blob: e4030201940c6fcf697adc15a572d5fe24cf8da2 [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>
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000014#include <limits>
niklase@google.com470e71d2011-07-07 08:21:25 +000015
16#ifdef WIN32
17# include <Winsock2.h>
18#else
19# include <arpa/inet.h>
20#endif
21
22#include "audio_coding_module.h"
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000023#include "engine_configurations.h"
andresp@webrtc.org86e1e482015-01-14 09:30:52 +000024#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
kjellander@webrtc.org3c0aae12014-09-04 09:55:40 +000025// TODO(tlegrand): Consider removing usage of gtest.
26#include "testing/gtest/include/gtest/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000028namespace webrtc {
29
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000030void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo,
31 const uint8_t* rtpHeader) {
32 rtpInfo->header.payloadType = rtpHeader[1];
33 rtpInfo->header.sequenceNumber = (static_cast<uint16_t>(rtpHeader[2]) << 8) |
34 rtpHeader[3];
35 rtpInfo->header.timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
36 (static_cast<uint32_t>(rtpHeader[5]) << 16) |
37 (static_cast<uint32_t>(rtpHeader[6]) << 8) | rtpHeader[7];
38 rtpInfo->header.ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) |
39 (static_cast<uint32_t>(rtpHeader[9]) << 16) |
40 (static_cast<uint32_t>(rtpHeader[10]) << 8) | rtpHeader[11];
niklase@google.com470e71d2011-07-07 08:21:25 +000041}
42
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000043void RTPStream::MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
44 int16_t seqNo, uint32_t timeStamp,
45 uint32_t ssrc) {
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);
niklase@google.com470e71d2011-07-07 08:21:25 +000052
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000053 rtpHeader[6] = (unsigned char) ((timeStamp >> 8) & 0xFF);
54 rtpHeader[7] = (unsigned char) (timeStamp & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000055
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000056 rtpHeader[8] = (unsigned char) ((ssrc >> 24) & 0xFF);
57 rtpHeader[9] = (unsigned char) ((ssrc >> 16) & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000058
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000059 rtpHeader[10] = (unsigned char) ((ssrc >> 8) & 0xFF);
60 rtpHeader[11] = (unsigned char) (ssrc & 0xFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000061}
62
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000063RTPPacket::RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000064 const uint8_t* payloadData, size_t payloadSize,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000065 uint32_t frequency)
66 : payloadType(payloadType),
67 timeStamp(timeStamp),
68 seqNo(seqNo),
69 payloadSize(payloadSize),
70 frequency(frequency) {
71 if (payloadSize > 0) {
72 this->payloadData = new uint8_t[payloadSize];
73 memcpy(this->payloadData, payloadData, payloadSize);
74 }
niklase@google.com470e71d2011-07-07 08:21:25 +000075}
76
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000077RTPPacket::~RTPPacket() {
78 delete[] payloadData;
niklase@google.com470e71d2011-07-07 08:21:25 +000079}
80
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000081RTPBuffer::RTPBuffer() {
82 _queueRWLock = RWLockWrapper::CreateRWLock();
niklase@google.com470e71d2011-07-07 08:21:25 +000083}
84
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000085RTPBuffer::~RTPBuffer() {
86 delete _queueRWLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000087}
88
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000089void RTPBuffer::Write(const uint8_t payloadType, const uint32_t timeStamp,
90 const int16_t seqNo, const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000091 const size_t payloadSize, uint32_t frequency) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000092 RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
93 payloadSize, frequency);
94 _queueRWLock->AcquireLockExclusive();
95 _rtpQueue.push(packet);
96 _queueRWLock->ReleaseLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +000097}
98
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000099size_t RTPBuffer::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
100 size_t payloadSize, uint32_t* offset) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000101 _queueRWLock->AcquireLockShared();
102 RTPPacket *packet = _rtpQueue.front();
103 _rtpQueue.pop();
104 _queueRWLock->ReleaseLockShared();
105 rtpInfo->header.markerBit = 1;
106 rtpInfo->header.payloadType = packet->payloadType;
107 rtpInfo->header.sequenceNumber = packet->seqNo;
108 rtpInfo->header.ssrc = 0;
109 rtpInfo->header.timestamp = packet->timeStamp;
110 if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
111 memcpy(payloadData, packet->payloadData, packet->payloadSize);
112 } else {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000113 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000114 }
115 *offset = (packet->timeStamp / (packet->frequency / 1000));
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000116
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000117 return packet->payloadSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000118}
119
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000120bool RTPBuffer::EndOfFile() const {
121 _queueRWLock->AcquireLockShared();
122 bool eof = _rtpQueue.empty();
123 _queueRWLock->ReleaseLockShared();
124 return eof;
niklase@google.com470e71d2011-07-07 08:21:25 +0000125}
126
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000127void RTPFile::Open(const char *filename, const char *mode) {
128 if ((_rtpFile = fopen(filename, mode)) == NULL) {
129 printf("Cannot write file %s.\n", filename);
130 ADD_FAILURE() << "Unable to write file";
131 exit(1);
132 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000133}
134
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000135void RTPFile::Close() {
136 if (_rtpFile != NULL) {
137 fclose(_rtpFile);
138 _rtpFile = NULL;
139 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000140}
141
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000142void RTPFile::WriteHeader() {
143 // Write data in a format that NetEQ and RTP Play can parse
144 fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
145 uint32_t dummy_variable = 0;
146 // should be converted to network endian format, but does not matter when 0
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000147 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
148 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
149 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
150 EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
151 EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000152 fflush(_rtpFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000153}
154
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000155void RTPFile::ReadHeader() {
156 uint32_t start_sec, start_usec, source;
157 uint16_t port, padding;
158 char fileHeader[40];
159 EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
160 EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
161 start_sec = ntohl(start_sec);
162 EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
163 start_usec = ntohl(start_usec);
164 EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
165 source = ntohl(source);
166 EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
167 port = ntohs(port);
168 EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
169 padding = ntohs(padding);
niklase@google.com470e71d2011-07-07 08:21:25 +0000170}
171
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000172void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
173 const int16_t seqNo, const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000174 const size_t payloadSize, uint32_t frequency) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000175 /* write RTP packet to file */
176 uint8_t rtpHeader[12];
177 MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000178 ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max());
179 uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8));
180 uint16_t plen = htons(static_cast<u_short>(12 + payloadSize));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000181 uint32_t offsetMs;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000182
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000183 offsetMs = (timeStamp / (frequency / 1000));
184 offsetMs = htonl(offsetMs);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000185 EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile));
186 EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile));
187 EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile));
188 EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile));
189 EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000190}
191
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000192size_t RTPFile::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
193 size_t payloadSize, uint32_t* offset) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000194 uint16_t lengthBytes;
195 uint16_t plen;
196 uint8_t rtpHeader[12];
197 size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
198 /* Check if we have reached end of file. */
199 if ((read_len == 0) && feof(_rtpFile)) {
200 _rtpEOF = true;
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000201 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000202 }
203 EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
204 EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
205 lengthBytes = ntohs(lengthBytes);
206 plen = ntohs(plen);
207 *offset = ntohl(*offset);
208 EXPECT_GT(plen, 11);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000209
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000210 EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
211 ParseRTPHeader(rtpInfo, rtpHeader);
212 rtpInfo->type.Audio.isCNG = false;
213 rtpInfo->type.Audio.channel = 1;
214 EXPECT_EQ(lengthBytes, plen + 8);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000215
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000216 if (plen == 0) {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000217 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000218 }
219 if (lengthBytes < 20) {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000220 return 0;
221 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000222 if (payloadSize < static_cast<size_t>((lengthBytes - 20))) {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000223 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000224 }
225 lengthBytes -= 20;
226 EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
227 return lengthBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228}
229
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000230} // namespace webrtc