blob: db4e0f3fcd810978a346957859de3cb4eda381c0 [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>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000015#include <limits>
niklase@google.com470e71d2011-07-07 08:21:25 +000016
17#ifdef WIN32
Yves Gerey665174f2018-06-19 15:03:05 +020018#include <Winsock2.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000019#else
Yves Gerey665174f2018-06-19 15:03:05 +020020#include <arpa/inet.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000021#endif
22
Fredrik Solenbergbbf21a32018-04-12 22:44:09 +020023#include "modules/include/module_common_types.h"
kjellander@webrtc.org3c0aae12014-09-04 09:55:40 +000024// TODO(tlegrand): Consider removing usage of gtest.
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000027namespace webrtc {
28
Niels Möllerbf474952019-02-18 12:00:06 +010029void RTPStream::ParseRTPHeader(RTPHeader* rtp_header,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000030 const uint8_t* rtpHeader) {
Niels Möllerbf474952019-02-18 12:00:06 +010031 rtp_header->payloadType = rtpHeader[1];
32 rtp_header->sequenceNumber =
Yves Gerey665174f2018-06-19 15:03:05 +020033 (static_cast<uint16_t>(rtpHeader[2]) << 8) | rtpHeader[3];
Niels Möllerbf474952019-02-18 12:00:06 +010034 rtp_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) |
37 rtpHeader[7];
38 rtp_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) |
41 rtpHeader[11];
niklase@google.com470e71d2011-07-07 08:21:25 +000042}
43
Yves Gerey665174f2018-06-19 15:03:05 +020044void RTPStream::MakeRTPheader(uint8_t* rtpHeader,
45 uint8_t payloadType,
46 int16_t seqNo,
47 uint32_t timeStamp,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000048 uint32_t ssrc) {
pkasting@chromium.orgd3245462015-02-23 21:28:22 +000049 rtpHeader[0] = 0x80;
50 rtpHeader[1] = payloadType;
51 rtpHeader[2] = (seqNo >> 8) & 0xFF;
52 rtpHeader[3] = seqNo & 0xFF;
53 rtpHeader[4] = timeStamp >> 24;
54 rtpHeader[5] = (timeStamp >> 16) & 0xFF;
55 rtpHeader[6] = (timeStamp >> 8) & 0xFF;
56 rtpHeader[7] = timeStamp & 0xFF;
57 rtpHeader[8] = ssrc >> 24;
58 rtpHeader[9] = (ssrc >> 16) & 0xFF;
59 rtpHeader[10] = (ssrc >> 8) & 0xFF;
60 rtpHeader[11] = ssrc & 0xFF;
niklase@google.com470e71d2011-07-07 08:21:25 +000061}
62
Yves Gerey665174f2018-06-19 15:03:05 +020063RTPPacket::RTPPacket(uint8_t payloadType,
64 uint32_t timeStamp,
65 int16_t seqNo,
66 const uint8_t* payloadData,
67 size_t payloadSize,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000068 uint32_t frequency)
69 : payloadType(payloadType),
70 timeStamp(timeStamp),
71 seqNo(seqNo),
72 payloadSize(payloadSize),
73 frequency(frequency) {
74 if (payloadSize > 0) {
75 this->payloadData = new uint8_t[payloadSize];
76 memcpy(this->payloadData, payloadData, payloadSize);
77 }
niklase@google.com470e71d2011-07-07 08:21:25 +000078}
79
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000080RTPPacket::~RTPPacket() {
81 delete[] payloadData;
niklase@google.com470e71d2011-07-07 08:21:25 +000082}
83
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000084RTPBuffer::RTPBuffer() {
85 _queueRWLock = RWLockWrapper::CreateRWLock();
niklase@google.com470e71d2011-07-07 08:21:25 +000086}
87
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000088RTPBuffer::~RTPBuffer() {
89 delete _queueRWLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000090}
91
Yves Gerey665174f2018-06-19 15:03:05 +020092void RTPBuffer::Write(const uint8_t payloadType,
93 const uint32_t timeStamp,
94 const int16_t seqNo,
95 const uint8_t* payloadData,
96 const size_t payloadSize,
97 uint32_t frequency) {
98 RTPPacket* packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000099 payloadSize, frequency);
100 _queueRWLock->AcquireLockExclusive();
101 _rtpQueue.push(packet);
102 _queueRWLock->ReleaseLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +0000103}
104
Niels Möllerbf474952019-02-18 12:00:06 +0100105size_t RTPBuffer::Read(RTPHeader* rtp_header,
Yves Gerey665174f2018-06-19 15:03:05 +0200106 uint8_t* payloadData,
107 size_t payloadSize,
108 uint32_t* offset) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000109 _queueRWLock->AcquireLockShared();
Yves Gerey665174f2018-06-19 15:03:05 +0200110 RTPPacket* packet = _rtpQueue.front();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000111 _rtpQueue.pop();
112 _queueRWLock->ReleaseLockShared();
Niels Möllerbf474952019-02-18 12:00:06 +0100113 rtp_header->markerBit = 1;
114 rtp_header->payloadType = packet->payloadType;
115 rtp_header->sequenceNumber = packet->seqNo;
116 rtp_header->ssrc = 0;
117 rtp_header->timestamp = packet->timeStamp;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000118 if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
119 memcpy(payloadData, packet->payloadData, packet->payloadSize);
120 } else {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000121 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000122 }
123 *offset = (packet->timeStamp / (packet->frequency / 1000));
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000124
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000125 return packet->payloadSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126}
127
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000128bool RTPBuffer::EndOfFile() const {
129 _queueRWLock->AcquireLockShared();
130 bool eof = _rtpQueue.empty();
131 _queueRWLock->ReleaseLockShared();
132 return eof;
niklase@google.com470e71d2011-07-07 08:21:25 +0000133}
134
Yves Gerey665174f2018-06-19 15:03:05 +0200135void RTPFile::Open(const char* filename, const char* mode) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000136 if ((_rtpFile = fopen(filename, mode)) == NULL) {
137 printf("Cannot write file %s.\n", filename);
138 ADD_FAILURE() << "Unable to write file";
139 exit(1);
140 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000141}
142
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000143void RTPFile::Close() {
144 if (_rtpFile != NULL) {
145 fclose(_rtpFile);
146 _rtpFile = NULL;
147 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000148}
149
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000150void RTPFile::WriteHeader() {
151 // Write data in a format that NetEQ and RTP Play can parse
152 fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
153 uint32_t dummy_variable = 0;
154 // should be converted to network endian format, but does not matter when 0
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000155 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
156 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
157 EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
158 EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
159 EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000160 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
Yves Gerey665174f2018-06-19 15:03:05 +0200180void RTPFile::Write(const uint8_t payloadType,
181 const uint32_t timeStamp,
182 const int16_t seqNo,
183 const uint8_t* payloadData,
184 const size_t payloadSize,
185 uint32_t frequency) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000186 /* write RTP packet to file */
187 uint8_t rtpHeader[12];
188 MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000189 ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max());
190 uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8));
191 uint16_t plen = htons(static_cast<u_short>(12 + payloadSize));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000192 uint32_t offsetMs;
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000193
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000194 offsetMs = (timeStamp / (frequency / 1000));
195 offsetMs = htonl(offsetMs);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000196 EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile));
197 EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile));
198 EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile));
199 EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile));
200 EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile));
niklase@google.com470e71d2011-07-07 08:21:25 +0000201}
202
Niels Möllerbf474952019-02-18 12:00:06 +0100203size_t RTPFile::Read(RTPHeader* rtp_header,
Yves Gerey665174f2018-06-19 15:03:05 +0200204 uint8_t* payloadData,
205 size_t payloadSize,
206 uint32_t* offset) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000207 uint16_t lengthBytes;
208 uint16_t plen;
209 uint8_t rtpHeader[12];
210 size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
211 /* Check if we have reached end of file. */
212 if ((read_len == 0) && feof(_rtpFile)) {
213 _rtpEOF = true;
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000214 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000215 }
216 EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
217 EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
218 lengthBytes = ntohs(lengthBytes);
219 plen = ntohs(plen);
220 *offset = ntohl(*offset);
221 EXPECT_GT(plen, 11);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000222
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000223 EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
Niels Möllerbf474952019-02-18 12:00:06 +0100224 ParseRTPHeader(rtp_header, rtpHeader);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000225 EXPECT_EQ(lengthBytes, plen + 8);
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000226
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000227 if (plen == 0) {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000228 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000229 }
230 if (lengthBytes < 20) {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000231 return 0;
232 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000233 if (payloadSize < static_cast<size_t>((lengthBytes - 20))) {
henrik.lundin@webrtc.org741711a2014-09-25 07:38:14 +0000234 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000235 }
236 lengthBytes -= 20;
237 EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
238 return lengthBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
240
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000241} // namespace webrtc