/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "RTPFile.h" #include "rw_lock_wrapper.h" #include "engine_configurations.h" #include #ifdef WIN32 # include #else # include #endif #include "audio_coding_module.h" void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo, const WebRtc_UWord8* rtpHeader) { rtpInfo->header.payloadType = rtpHeader[1]; rtpInfo->header.sequenceNumber = (static_cast(rtpHeader[2])<<8) | rtpHeader[3]; rtpInfo->header.timestamp = (static_cast(rtpHeader[4])<<24) | (static_cast(rtpHeader[5])<<16) | (static_cast(rtpHeader[6])<<8) | rtpHeader[7]; rtpInfo->header.ssrc = (static_cast(rtpHeader[8])<<24) | (static_cast(rtpHeader[9])<<16) | (static_cast(rtpHeader[10])<<8) | rtpHeader[11]; } void RTPStream::MakeRTPheader(WebRtc_UWord8* rtpHeader, WebRtc_UWord8 payloadType, WebRtc_Word16 seqNo, WebRtc_UWord32 timeStamp, WebRtc_UWord32 ssrc) { rtpHeader[0]=(unsigned char)0x80; rtpHeader[1]=(unsigned char)(payloadType & 0xFF); rtpHeader[2]=(unsigned char)((seqNo>>8)&0xFF); rtpHeader[3]=(unsigned char)((seqNo)&0xFF); rtpHeader[4]=(unsigned char)((timeStamp>>24)&0xFF); rtpHeader[5]=(unsigned char)((timeStamp>>16)&0xFF); rtpHeader[6]=(unsigned char)((timeStamp>>8)&0xFF); rtpHeader[7]=(unsigned char)(timeStamp & 0xFF); rtpHeader[8]=(unsigned char)((ssrc>>24)&0xFF); rtpHeader[9]=(unsigned char)((ssrc>>16)&0xFF); rtpHeader[10]=(unsigned char)((ssrc>>8)&0xFF); rtpHeader[11]=(unsigned char)(ssrc & 0xFF); } RTPPacket::RTPPacket(WebRtc_UWord8 payloadType, WebRtc_UWord32 timeStamp, WebRtc_Word16 seqNo, const WebRtc_UWord8* payloadData, WebRtc_UWord16 payloadSize, WebRtc_UWord32 frequency) : payloadType(payloadType), timeStamp(timeStamp), seqNo(seqNo), payloadSize(payloadSize), frequency(frequency) { if (payloadSize > 0) { this->payloadData = new WebRtc_UWord8[payloadSize]; memcpy(this->payloadData, payloadData, payloadSize); } } RTPPacket::~RTPPacket() { delete [] payloadData; } RTPBuffer::RTPBuffer() { _queueRWLock = RWLockWrapper::CreateRWLock(); } RTPBuffer::~RTPBuffer() { delete _queueRWLock; } void RTPBuffer::Write(const WebRtc_UWord8 payloadType, const WebRtc_UWord32 timeStamp, const WebRtc_Word16 seqNo, const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadSize, WebRtc_UWord32 frequency) { RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData, payloadSize, frequency); _queueRWLock->AcquireLockExclusive(); _rtpQueue.push(packet); _queueRWLock->ReleaseLockExclusive(); } WebRtc_UWord16 RTPBuffer::Read(WebRtcRTPHeader* rtpInfo, WebRtc_Word8* payloadData, WebRtc_UWord16 payloadSize, WebRtc_UWord32* offset) { _queueRWLock->AcquireLockShared(); RTPPacket *packet = _rtpQueue.front(); _rtpQueue.pop(); _queueRWLock->ReleaseLockShared(); rtpInfo->header.markerBit = 1; rtpInfo->header.payloadType = packet->payloadType; rtpInfo->header.sequenceNumber = packet->seqNo; rtpInfo->header.ssrc = 0; rtpInfo->header.timestamp = packet->timeStamp; if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) { memcpy(payloadData, packet->payloadData, packet->payloadSize); } else { throw "Payload buffer too small"; exit(1); } /*#ifdef WEBRTC_CODEC_G722 if(ACMCodecDB::_mycodecs[ACMCodecDB::g722].pltype == packet->payloadType) { *offset = (packet->timeStamp/(packet->frequency/1000))<<1; } else { #endif*/ *offset = (packet->timeStamp/(packet->frequency/1000)); /*#ifdef WEBRTC_CODEC_G722 } #endif*/ return packet->payloadSize; } bool RTPBuffer::EndOfFile() const { _queueRWLock->AcquireLockShared(); bool eof = _rtpQueue.empty(); _queueRWLock->ReleaseLockShared(); return eof; } void RTPFile::Open(char *filename, const char *mode) { if ((_rtpFile = fopen(filename, mode)) == NULL) { printf("Cannot write file %s.\n", filename); throw "Unable to write file"; exit(1); } } void RTPFile::Close() { if (_rtpFile != NULL) { fclose(_rtpFile); _rtpFile = NULL; } } void RTPFile::WriteHeader() { // Write data in a format that NetEQ and RTP Play can parse fprintf(_rtpFile, "#!RTPencode%s\n", "1.0"); WebRtc_UWord32 dummy_variable = 0; // should be converted to network endian format, but does not matter when 0 fwrite(&dummy_variable, 4, 1, _rtpFile); fwrite(&dummy_variable, 4, 1, _rtpFile); fwrite(&dummy_variable, 4, 1, _rtpFile); fwrite(&dummy_variable, 2, 1, _rtpFile); fwrite(&dummy_variable, 2, 1, _rtpFile); fflush(_rtpFile); } void RTPFile::ReadHeader() { WebRtc_UWord32 start_sec, start_usec, source; WebRtc_UWord16 port, padding; char fileHeader[40]; fgets(fileHeader, 40, _rtpFile); fread(&start_sec, 4, 1, _rtpFile); start_sec=ntohl(start_sec); fread(&start_usec, 4, 1, _rtpFile); start_usec=ntohl(start_usec); fread(&source, 4, 1, _rtpFile); source=ntohl(source); fread(&port, 2, 1, _rtpFile); port=ntohs(port); fread(&padding, 2, 1, _rtpFile); padding=ntohs(padding); } void RTPFile::Write(const WebRtc_UWord8 payloadType, const WebRtc_UWord32 timeStamp, const WebRtc_Word16 seqNo, const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadSize, WebRtc_UWord32 frequency) { /* write RTP packet to file */ WebRtc_UWord8 rtpHeader[12]; MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0); WebRtc_UWord16 lengthBytes = htons(12 + payloadSize + 8); WebRtc_UWord16 plen = htons(12 + payloadSize); WebRtc_UWord32 offsetMs; /*#ifdef WEBRTC_CODEC_G722 if(ACMCodecDB::_mycodecs[ACMCodecDB::g722].pltype == payloadType) { offsetMs = (timeStamp/(frequency/1000))<<1; } else { #endif*/ offsetMs = (timeStamp/(frequency/1000)); /*#ifdef WEBRTC_CODEC_G722 } #endif*/ offsetMs = htonl(offsetMs); fwrite(&lengthBytes, 2, 1, _rtpFile); fwrite(&plen, 2, 1, _rtpFile); fwrite(&offsetMs, 4, 1, _rtpFile); fwrite(rtpHeader, 12, 1, _rtpFile); fwrite(payloadData, 1, payloadSize, _rtpFile); } WebRtc_UWord16 RTPFile::Read(WebRtcRTPHeader* rtpInfo, WebRtc_Word8* payloadData, WebRtc_UWord16 payloadSize, WebRtc_UWord32* offset) { WebRtc_UWord16 lengthBytes; WebRtc_UWord16 plen; WebRtc_UWord8 rtpHeader[12]; fread(&lengthBytes, 2, 1, _rtpFile); if (feof(_rtpFile)) { _rtpEOF = true; return 0; } fread(&plen, 2, 1, _rtpFile); if (feof(_rtpFile)) { _rtpEOF = true; return 0; } fread(offset, 4, 1, _rtpFile); if (feof(_rtpFile)) { _rtpEOF = true; return 0; } lengthBytes = ntohs(lengthBytes); plen = ntohs(plen); *offset = ntohl(*offset); if (plen < 12) { throw "Unable to read RTP file"; exit(1); } fread(rtpHeader, 12, 1, _rtpFile); if (feof(_rtpFile)) { _rtpEOF = true; return 0; } ParseRTPHeader(rtpInfo, rtpHeader); rtpInfo->type.Audio.isCNG = false; rtpInfo->type.Audio.channel = 1; if (lengthBytes != plen + 8) { throw "Length parameters in RTP file doesn't match"; exit(1); } if (plen == 0) { return 0; } else if (lengthBytes - 20 > payloadSize) { throw "Payload buffer too small"; exit(1); } lengthBytes -= 20; fread(payloadData, 1, lengthBytes, _rtpFile); if (feof(_rtpFile)) { _rtpEOF = true; } return lengthBytes; }