blob: b886bde0b3f673d511a08331fcd5fed62cd01310 [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
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000028void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo,
29 const uint8_t* rtpHeader) {
30 rtpInfo->header.payloadType = rtpHeader[1];
31 rtpInfo->header.sequenceNumber = (static_cast<uint16_t>(rtpHeader[2]) << 8) |
32 rtpHeader[3];
33 rtpInfo->header.timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
34 (static_cast<uint32_t>(rtpHeader[5]) << 16) |
35 (static_cast<uint32_t>(rtpHeader[6]) << 8) | rtpHeader[7];
36 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) | rtpHeader[11];
niklase@google.com470e71d2011-07-07 08:21:25 +000039}
40
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000041void RTPStream::MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
42 int16_t seqNo, uint32_t timeStamp,
43 uint32_t ssrc) {
44 rtpHeader[0] = (unsigned char) 0x80;
45 rtpHeader[1] = (unsigned char) (payloadType & 0xFF);
46 rtpHeader[2] = (unsigned char) ((seqNo >> 8) & 0xFF);
47 rtpHeader[3] = (unsigned char) ((seqNo) & 0xFF);
48 rtpHeader[4] = (unsigned char) ((timeStamp >> 24) & 0xFF);
49 rtpHeader[5] = (unsigned char) ((timeStamp >> 16) & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000050
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000051 rtpHeader[6] = (unsigned char) ((timeStamp >> 8) & 0xFF);
52 rtpHeader[7] = (unsigned char) (timeStamp & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000053
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000054 rtpHeader[8] = (unsigned char) ((ssrc >> 24) & 0xFF);
55 rtpHeader[9] = (unsigned char) ((ssrc >> 16) & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000056
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000057 rtpHeader[10] = (unsigned char) ((ssrc >> 8) & 0xFF);
58 rtpHeader[11] = (unsigned char) (ssrc & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000061RTPPacket::RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
62 const uint8_t* payloadData, uint16_t payloadSize,
63 uint32_t frequency)
64 : payloadType(payloadType),
65 timeStamp(timeStamp),
66 seqNo(seqNo),
67 payloadSize(payloadSize),
68 frequency(frequency) {
69 if (payloadSize > 0) {
70 this->payloadData = new uint8_t[payloadSize];
71 memcpy(this->payloadData, payloadData, payloadSize);
72 }
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000075RTPPacket::~RTPPacket() {
76 delete[] payloadData;
niklase@google.com470e71d2011-07-07 08:21:25 +000077}
78
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000079RTPBuffer::RTPBuffer() {
80 _queueRWLock = RWLockWrapper::CreateRWLock();
niklase@google.com470e71d2011-07-07 08:21:25 +000081}
82
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000083RTPBuffer::~RTPBuffer() {
84 delete _queueRWLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000085}
86
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000087void RTPBuffer::Write(const uint8_t payloadType, const uint32_t timeStamp,
88 const int16_t seqNo, const uint8_t* payloadData,
89 const uint16_t payloadSize, uint32_t frequency) {
90 RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
91 payloadSize, frequency);
92 _queueRWLock->AcquireLockExclusive();
93 _rtpQueue.push(packet);
94 _queueRWLock->ReleaseLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +000095}
96
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000097uint16_t RTPBuffer::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
98 uint16_t payloadSize, uint32_t* offset) {
99 _queueRWLock->AcquireLockShared();
100 RTPPacket *packet = _rtpQueue.front();
101 _rtpQueue.pop();
102 _queueRWLock->ReleaseLockShared();
103 rtpInfo->header.markerBit = 1;
104 rtpInfo->header.payloadType = packet->payloadType;
105 rtpInfo->header.sequenceNumber = packet->seqNo;
106 rtpInfo->header.ssrc = 0;
107 rtpInfo->header.timestamp = packet->timeStamp;
108 if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
109 memcpy(payloadData, packet->payloadData, packet->payloadSize);
110 } else {
111 return 0;
112 }
113 *offset = (packet->timeStamp / (packet->frequency / 1000));
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000114
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000115 return packet->payloadSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000118bool RTPBuffer::EndOfFile() const {
119 _queueRWLock->AcquireLockShared();
120 bool eof = _rtpQueue.empty();
121 _queueRWLock->ReleaseLockShared();
122 return eof;
niklase@google.com470e71d2011-07-07 08:21:25 +0000123}
124
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000125void RTPFile::Open(const char *filename, const char *mode) {
126 if ((_rtpFile = fopen(filename, mode)) == NULL) {
127 printf("Cannot write file %s.\n", filename);
128 ADD_FAILURE() << "Unable to write file";
129 exit(1);
130 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000131}
132
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000133void RTPFile::Close() {
134 if (_rtpFile != NULL) {
135 fclose(_rtpFile);
136 _rtpFile = NULL;
137 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000138}
139
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000140void RTPFile::WriteHeader() {
141 // Write data in a format that NetEQ and RTP Play can parse
142 fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
143 uint32_t dummy_variable = 0;
144 // should be converted to network endian format, but does not matter when 0
145 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
146 return;
147 }
148 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
149 return;
150 }
151 if (fwrite(&dummy_variable, 4, 1, _rtpFile) != 1) {
152 return;
153 }
154 if (fwrite(&dummy_variable, 2, 1, _rtpFile) != 1) {
155 return;
156 }
157 if (fwrite(&dummy_variable, 2, 1, _rtpFile) != 1) {
158 return;
159 }
160 fflush(_rtpFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000161}
162
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000163void RTPFile::ReadHeader() {
164 uint32_t start_sec, start_usec, source;
165 uint16_t port, padding;
166 char fileHeader[40];
167 EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
168 EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
169 start_sec = ntohl(start_sec);
170 EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
171 start_usec = ntohl(start_usec);
172 EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
173 source = ntohl(source);
174 EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
175 port = ntohs(port);
176 EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
177 padding = ntohs(padding);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178}
179
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000180void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
181 const int16_t seqNo, const uint8_t* payloadData,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000182 const uint16_t payloadSize, uint32_t frequency) {
183 /* write RTP packet to file */
184 uint8_t rtpHeader[12];
185 MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
186 uint16_t lengthBytes = htons(12 + payloadSize + 8);
187 uint16_t plen = htons(12 + payloadSize);
188 uint32_t offsetMs;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000189
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000190 offsetMs = (timeStamp / (frequency / 1000));
191 offsetMs = htonl(offsetMs);
192 if (fwrite(&lengthBytes, 2, 1, _rtpFile) != 1) {
193 return;
194 }
195 if (fwrite(&plen, 2, 1, _rtpFile) != 1) {
196 return;
197 }
198 if (fwrite(&offsetMs, 4, 1, _rtpFile) != 1) {
199 return;
200 }
201 if (fwrite(rtpHeader, 12, 1, _rtpFile) != 1) {
202 return;
203 }
204 if (fwrite(payloadData, 1, payloadSize, _rtpFile) != payloadSize) {
205 return;
206 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000207}
208
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000209uint16_t RTPFile::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
210 uint16_t payloadSize, uint32_t* offset) {
211 uint16_t lengthBytes;
212 uint16_t plen;
213 uint8_t rtpHeader[12];
214 size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
215 /* Check if we have reached end of file. */
216 if ((read_len == 0) && feof(_rtpFile)) {
217 _rtpEOF = true;
218 return 0;
219 }
220 EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
221 EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
222 lengthBytes = ntohs(lengthBytes);
223 plen = ntohs(plen);
224 *offset = ntohl(*offset);
225 EXPECT_GT(plen, 11);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000226
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000227 EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
228 ParseRTPHeader(rtpInfo, rtpHeader);
229 rtpInfo->type.Audio.isCNG = false;
230 rtpInfo->type.Audio.channel = 1;
231 EXPECT_EQ(lengthBytes, plen + 8);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000232
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000233 if (plen == 0) {
234 return 0;
235 }
236 if (payloadSize < (lengthBytes - 20)) {
henrike@webrtc.org6ac22e62014-08-11 21:06:30 +0000237 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000238 }
239 if (lengthBytes < 20) {
henrike@webrtc.org6ac22e62014-08-11 21:06:30 +0000240 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000241 }
242 lengthBytes -= 20;
243 EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
244 return lengthBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245}
246
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000247} // namespace webrtc