blob: 47850ae4fb3c610f1ca8d99710c85de4436fcccf [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
tina.legrand@webrtc.org16b6b902012-04-12 11:02:38 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "RTPFile.h"
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <stdlib.h>
14
15#ifdef WIN32
16# include <Winsock2.h>
17#else
18# include <arpa/inet.h>
19#endif
20
21#include "audio_coding_module.h"
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000022#include "engine_configurations.h"
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000023#include "gtest/gtest.h" // TODO (tlegrand): Consider removing usage of gtest.
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000024#include "rw_lock_wrapper.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000025
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000026namespace webrtc {
27
pbos@webrtc.org0946a562013-04-09 00:28:06 +000028void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo, const uint8_t* rtpHeader)
niklase@google.com470e71d2011-07-07 08:21:25 +000029{
30 rtpInfo->header.payloadType = rtpHeader[1];
pbos@webrtc.org0946a562013-04-09 00:28:06 +000031 rtpInfo->header.sequenceNumber = (static_cast<uint16_t>(rtpHeader[2])<<8) | rtpHeader[3];
32 rtpInfo->header.timestamp = (static_cast<uint32_t>(rtpHeader[4])<<24) |
33 (static_cast<uint32_t>(rtpHeader[5])<<16) |
34 (static_cast<uint32_t>(rtpHeader[6])<<8) |
niklase@google.com470e71d2011-07-07 08:21:25 +000035 rtpHeader[7];
pbos@webrtc.org0946a562013-04-09 00:28:06 +000036 rtpInfo->header.ssrc = (static_cast<uint32_t>(rtpHeader[8])<<24) |
37 (static_cast<uint32_t>(rtpHeader[9])<<16) |
38 (static_cast<uint32_t>(rtpHeader[10])<<8) |
niklase@google.com470e71d2011-07-07 08:21:25 +000039 rtpHeader[11];
40}
41
pbos@webrtc.org0946a562013-04-09 00:28:06 +000042void RTPStream::MakeRTPheader(uint8_t* rtpHeader,
43 uint8_t payloadType, int16_t seqNo,
44 uint32_t timeStamp, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +000045{
46 rtpHeader[0]=(unsigned char)0x80;
47 rtpHeader[1]=(unsigned char)(payloadType & 0xFF);
48 rtpHeader[2]=(unsigned char)((seqNo>>8)&0xFF);
49 rtpHeader[3]=(unsigned char)((seqNo)&0xFF);
50 rtpHeader[4]=(unsigned char)((timeStamp>>24)&0xFF);
51 rtpHeader[5]=(unsigned char)((timeStamp>>16)&0xFF);
52
53 rtpHeader[6]=(unsigned char)((timeStamp>>8)&0xFF);
54 rtpHeader[7]=(unsigned char)(timeStamp & 0xFF);
55
56 rtpHeader[8]=(unsigned char)((ssrc>>24)&0xFF);
57 rtpHeader[9]=(unsigned char)((ssrc>>16)&0xFF);
58
59 rtpHeader[10]=(unsigned char)((ssrc>>8)&0xFF);
60 rtpHeader[11]=(unsigned char)(ssrc & 0xFF);
61}
62
63
pbos@webrtc.org0946a562013-04-09 00:28:06 +000064RTPPacket::RTPPacket(uint8_t payloadType, uint32_t timeStamp,
65 int16_t seqNo, const uint8_t* payloadData,
66 uint16_t payloadSize, uint32_t frequency)
niklase@google.com470e71d2011-07-07 08:21:25 +000067 :
68payloadType(payloadType),
69timeStamp(timeStamp),
70seqNo(seqNo),
71payloadSize(payloadSize),
72frequency(frequency)
73{
74 if (payloadSize > 0)
75 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +000076 this->payloadData = new uint8_t[payloadSize];
niklase@google.com470e71d2011-07-07 08:21:25 +000077 memcpy(this->payloadData, payloadData, payloadSize);
78 }
79}
80
81RTPPacket::~RTPPacket()
82{
83 delete [] payloadData;
84}
85
86RTPBuffer::RTPBuffer()
87{
88 _queueRWLock = RWLockWrapper::CreateRWLock();
89}
90
91RTPBuffer::~RTPBuffer()
92{
93 delete _queueRWLock;
94}
95
96void
pbos@webrtc.org0946a562013-04-09 00:28:06 +000097RTPBuffer::Write(const uint8_t payloadType, const uint32_t timeStamp,
98 const int16_t seqNo, const uint8_t* payloadData,
99 const uint16_t payloadSize, uint32_t frequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000100{
101 RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData, payloadSize, frequency);
102 _queueRWLock->AcquireLockExclusive();
103 _rtpQueue.push(packet);
104 _queueRWLock->ReleaseLockExclusive();
105}
106
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000107uint16_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000108RTPBuffer::Read(WebRtcRTPHeader* rtpInfo,
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000109 uint8_t* payloadData,
110 uint16_t payloadSize,
111 uint32_t* offset)
niklase@google.com470e71d2011-07-07 08:21:25 +0000112{
113 _queueRWLock->AcquireLockShared();
114 RTPPacket *packet = _rtpQueue.front();
115 _rtpQueue.pop();
116 _queueRWLock->ReleaseLockShared();
117 rtpInfo->header.markerBit = 1;
118 rtpInfo->header.payloadType = packet->payloadType;
119 rtpInfo->header.sequenceNumber = packet->seqNo;
120 rtpInfo->header.ssrc = 0;
121 rtpInfo->header.timestamp = packet->timeStamp;
122 if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize)
123 {
124 memcpy(payloadData, packet->payloadData, packet->payloadSize);
125 }
126 else
127 {
andrew@webrtc.org975e4a32012-01-17 19:27:33 +0000128 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 }
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000130 *offset = (packet->timeStamp/(packet->frequency/1000));
131
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 return packet->payloadSize;
133}
134
135bool
136RTPBuffer::EndOfFile() const
137{
138 _queueRWLock->AcquireLockShared();
139 bool eof = _rtpQueue.empty();
140 _queueRWLock->ReleaseLockShared();
141 return eof;
142}
143
kjellander@webrtc.org5490c712011-12-21 13:34:18 +0000144void RTPFile::Open(const char *filename, const char *mode)
niklase@google.com470e71d2011-07-07 08:21:25 +0000145{
146 if ((_rtpFile = fopen(filename, mode)) == NULL)
147 {
148 printf("Cannot write file %s.\n", filename);
kjellander@webrtc.org5490c712011-12-21 13:34:18 +0000149 ADD_FAILURE() << "Unable to write file";
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 exit(1);
151 }
152}
153
154void RTPFile::Close()
155{
156 if (_rtpFile != NULL)
157 {
158 fclose(_rtpFile);
159 _rtpFile = NULL;
160 }
161}
162
163
164void RTPFile::WriteHeader()
165{
166 // Write data in a format that NetEQ and RTP Play can parse
167 fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000168 uint32_t dummy_variable = 0;
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000169 // should be converted to network endian format, but does not matter when 0
170 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
171 return;
172 }
173 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
174 return;
175 }
176 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
177 return;
178 }
179 if (fwrite(&dummy_variable, 2, 1, _rtpFile) != 1) {
180 return;
181 }
182 if (fwrite(&dummy_variable, 2, 1, _rtpFile) != 1) {
183 return;
184 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 fflush(_rtpFile);
186}
187
188void RTPFile::ReadHeader()
189{
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000190 uint32_t start_sec, start_usec, source;
191 uint16_t port, padding;
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 char fileHeader[40];
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +0000193 EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000194 EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 start_sec=ntohl(start_sec);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000196 EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 start_usec=ntohl(start_usec);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000198 EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 source=ntohl(source);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000200 EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 port=ntohs(port);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000202 EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 padding=ntohs(padding);
204}
205
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000206void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
207 const int16_t seqNo, const uint8_t* payloadData,
208 const uint16_t payloadSize, uint32_t frequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000209{
210 /* write RTP packet to file */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000211 uint8_t rtpHeader[12];
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000213 uint16_t lengthBytes = htons(12 + payloadSize + 8);
214 uint16_t plen = htons(12 + payloadSize);
215 uint32_t offsetMs;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000216
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 offsetMs = (timeStamp/(frequency/1000));
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 offsetMs = htonl(offsetMs);
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000219 if (fwrite(&lengthBytes, 2, 1, _rtpFile) != 1) {
220 return;
221 }
222 if (fwrite(&plen, 2, 1, _rtpFile) != 1) {
223 return;
224 }
225 if (fwrite(&offsetMs, 4, 1, _rtpFile) != 1) {
226 return;
227 }
228 if (fwrite(rtpHeader, 12, 1, _rtpFile) != 1) {
229 return;
230 }
231 if (fwrite(payloadData, 1, payloadSize, _rtpFile) != payloadSize) {
232 return;
233 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000234}
235
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000236uint16_t RTPFile::Read(WebRtcRTPHeader* rtpInfo,
237 uint8_t* payloadData,
238 uint16_t payloadSize,
239 uint32_t* offset)
niklase@google.com470e71d2011-07-07 08:21:25 +0000240{
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000241 uint16_t lengthBytes;
242 uint16_t plen;
243 uint8_t rtpHeader[12];
tina.legrand@webrtc.org9775a302011-12-16 11:15:46 +0000244 size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000245 /* Check if we have reached end of file. */
tina.legrand@webrtc.org9775a302011-12-16 11:15:46 +0000246 if ((read_len == 0) && feof(_rtpFile))
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 {
248 _rtpEOF = true;
249 return 0;
250 }
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000251 EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
252 EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 lengthBytes = ntohs(lengthBytes);
254 plen = ntohs(plen);
255 *offset = ntohl(*offset);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000256 EXPECT_GT(plen, 11);
257
258 EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000259 ParseRTPHeader(rtpInfo, rtpHeader);
260 rtpInfo->type.Audio.isCNG = false;
261 rtpInfo->type.Audio.channel = 1;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000262 EXPECT_EQ(lengthBytes, plen + 8);
263
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 if (plen == 0)
265 {
266 return 0;
267 }
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000268 if (payloadSize < (lengthBytes - 20))
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 {
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000270 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 }
andrew@webrtc.org975e4a32012-01-17 19:27:33 +0000272 if (lengthBytes < 20)
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 {
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000274 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 }
andrew@webrtc.org975e4a32012-01-17 19:27:33 +0000276 lengthBytes -= 20;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000277 EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 return lengthBytes;
279}
280
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000281} // namespace webrtc