blob: 789dc1dbc827a6f04bf3ab262512dbfc1d8442f6 [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"
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000023#include "rw_lock_wrapper.h"
kjellander@webrtc.org3c0aae12014-09-04 09:55:40 +000024// TODO(tlegrand): Consider removing usage of gtest.
25#include "testing/gtest/include/gtest/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000027namespace webrtc {
28
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000029void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo,
30 const uint8_t* rtpHeader) {
31 rtpInfo->header.payloadType = rtpHeader[1];
32 rtpInfo->header.sequenceNumber = (static_cast<uint16_t>(rtpHeader[2]) << 8) |
33 rtpHeader[3];
34 rtpInfo->header.timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
35 (static_cast<uint32_t>(rtpHeader[5]) << 16) |
36 (static_cast<uint32_t>(rtpHeader[6]) << 8) | rtpHeader[7];
37 rtpInfo->header.ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) |
38 (static_cast<uint32_t>(rtpHeader[9]) << 16) |
39 (static_cast<uint32_t>(rtpHeader[10]) << 8) | rtpHeader[11];
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000042void RTPStream::MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
43 int16_t seqNo, uint32_t timeStamp,
44 uint32_t ssrc) {
45 rtpHeader[0] = (unsigned char) 0x80;
46 rtpHeader[1] = (unsigned char) (payloadType & 0xFF);
47 rtpHeader[2] = (unsigned char) ((seqNo >> 8) & 0xFF);
48 rtpHeader[3] = (unsigned char) ((seqNo) & 0xFF);
49 rtpHeader[4] = (unsigned char) ((timeStamp >> 24) & 0xFF);
50 rtpHeader[5] = (unsigned char) ((timeStamp >> 16) & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000051
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000052 rtpHeader[6] = (unsigned char) ((timeStamp >> 8) & 0xFF);
53 rtpHeader[7] = (unsigned char) (timeStamp & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000054
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000055 rtpHeader[8] = (unsigned char) ((ssrc >> 24) & 0xFF);
56 rtpHeader[9] = (unsigned char) ((ssrc >> 16) & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000057
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000058 rtpHeader[10] = (unsigned char) ((ssrc >> 8) & 0xFF);
59 rtpHeader[11] = (unsigned char) (ssrc & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000060}
61
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000062RTPPacket::RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
63 const uint8_t* payloadData, uint16_t payloadSize,
64 uint32_t frequency)
65 : payloadType(payloadType),
66 timeStamp(timeStamp),
67 seqNo(seqNo),
68 payloadSize(payloadSize),
69 frequency(frequency) {
70 if (payloadSize > 0) {
71 this->payloadData = new uint8_t[payloadSize];
72 memcpy(this->payloadData, payloadData, payloadSize);
73 }
niklase@google.com470e71d2011-07-07 08:21:25 +000074}
75
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000076RTPPacket::~RTPPacket() {
77 delete[] payloadData;
niklase@google.com470e71d2011-07-07 08:21:25 +000078}
79
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000080RTPBuffer::RTPBuffer() {
81 _queueRWLock = RWLockWrapper::CreateRWLock();
niklase@google.com470e71d2011-07-07 08:21:25 +000082}
83
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000084RTPBuffer::~RTPBuffer() {
85 delete _queueRWLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000086}
87
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000088void RTPBuffer::Write(const uint8_t payloadType, const uint32_t timeStamp,
89 const int16_t seqNo, const uint8_t* payloadData,
90 const uint16_t payloadSize, uint32_t frequency) {
91 RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
92 payloadSize, frequency);
93 _queueRWLock->AcquireLockExclusive();
94 _rtpQueue.push(packet);
95 _queueRWLock->ReleaseLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +000096}
97
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000098uint16_t RTPBuffer::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
99 uint16_t payloadSize, uint32_t* offset) {
100 _queueRWLock->AcquireLockShared();
101 RTPPacket *packet = _rtpQueue.front();
102 _rtpQueue.pop();
103 _queueRWLock->ReleaseLockShared();
104 rtpInfo->header.markerBit = 1;
105 rtpInfo->header.payloadType = packet->payloadType;
106 rtpInfo->header.sequenceNumber = packet->seqNo;
107 rtpInfo->header.ssrc = 0;
108 rtpInfo->header.timestamp = packet->timeStamp;
109 if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
110 memcpy(payloadData, packet->payloadData, packet->payloadSize);
111 } else {
112 return 0;
113 }
114 *offset = (packet->timeStamp / (packet->frequency / 1000));
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000115
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000116 return packet->payloadSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000119bool RTPBuffer::EndOfFile() const {
120 _queueRWLock->AcquireLockShared();
121 bool eof = _rtpQueue.empty();
122 _queueRWLock->ReleaseLockShared();
123 return eof;
niklase@google.com470e71d2011-07-07 08:21:25 +0000124}
125
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000126void RTPFile::Open(const char *filename, const char *mode) {
127 if ((_rtpFile = fopen(filename, mode)) == NULL) {
128 printf("Cannot write file %s.\n", filename);
129 ADD_FAILURE() << "Unable to write file";
130 exit(1);
131 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000132}
133
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000134void RTPFile::Close() {
135 if (_rtpFile != NULL) {
136 fclose(_rtpFile);
137 _rtpFile = NULL;
138 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000141void RTPFile::WriteHeader() {
142 // Write data in a format that NetEQ and RTP Play can parse
143 fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
144 uint32_t dummy_variable = 0;
145 // should be converted to network endian format, but does not matter when 0
146 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
147 return;
148 }
149 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
150 return;
151 }
152 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
153 return;
154 }
155 if (fwrite(&dummy_variable, 2, 1, _rtpFile) != 1) {
156 return;
157 }
158 if (fwrite(&dummy_variable, 2, 1, _rtpFile) != 1) {
159 return;
160 }
161 fflush(_rtpFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162}
163
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000164void RTPFile::ReadHeader() {
165 uint32_t start_sec, start_usec, source;
166 uint16_t port, padding;
167 char fileHeader[40];
168 EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
169 EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
170 start_sec = ntohl(start_sec);
171 EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
172 start_usec = ntohl(start_usec);
173 EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
174 source = ntohl(source);
175 EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
176 port = ntohs(port);
177 EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
178 padding = ntohs(padding);
niklase@google.com470e71d2011-07-07 08:21:25 +0000179}
180
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000181void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
182 const int16_t seqNo, const uint8_t* payloadData,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000183 const uint16_t payloadSize, uint32_t frequency) {
184 /* write RTP packet to file */
185 uint8_t rtpHeader[12];
186 MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
187 uint16_t lengthBytes = htons(12 + payloadSize + 8);
188 uint16_t plen = htons(12 + payloadSize);
189 uint32_t offsetMs;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000190
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000191 offsetMs = (timeStamp / (frequency / 1000));
192 offsetMs = htonl(offsetMs);
193 if (fwrite(&lengthBytes, 2, 1, _rtpFile) != 1) {
194 return;
195 }
196 if (fwrite(&plen, 2, 1, _rtpFile) != 1) {
197 return;
198 }
199 if (fwrite(&offsetMs, 4, 1, _rtpFile) != 1) {
200 return;
201 }
202 if (fwrite(rtpHeader, 12, 1, _rtpFile) != 1) {
203 return;
204 }
205 if (fwrite(payloadData, 1, payloadSize, _rtpFile) != payloadSize) {
206 return;
207 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000208}
209
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000210uint16_t RTPFile::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
211 uint16_t payloadSize, uint32_t* offset) {
212 uint16_t lengthBytes;
213 uint16_t plen;
214 uint8_t rtpHeader[12];
215 size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
216 /* Check if we have reached end of file. */
217 if ((read_len == 0) && feof(_rtpFile)) {
218 _rtpEOF = true;
219 return 0;
220 }
221 EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
222 EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
223 lengthBytes = ntohs(lengthBytes);
224 plen = ntohs(plen);
225 *offset = ntohl(*offset);
226 EXPECT_GT(plen, 11);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000227
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000228 EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
229 ParseRTPHeader(rtpInfo, rtpHeader);
230 rtpInfo->type.Audio.isCNG = false;
231 rtpInfo->type.Audio.channel = 1;
232 EXPECT_EQ(lengthBytes, plen + 8);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000233
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000234 if (plen == 0) {
fbarchard@google.com9328f392014-09-03 23:05:07 +0000235 return static_cast<uint16_t>(0);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000236 }
237 if (payloadSize < (lengthBytes - 20)) {
fbarchard@google.com9328f392014-09-03 23:05:07 +0000238 return static_cast<uint16_t>(0);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000239 }
240 if (lengthBytes < 20) {
fbarchard@google.com9328f392014-09-03 23:05:07 +0000241 return static_cast<uint16_t>(0);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000242 }
243 lengthBytes -= 20;
244 EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
245 return lengthBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000246}
247
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000248} // namespace webrtc