xref: /aosp_15_r20/external/webrtc/modules/audio_coding/test/RTPFile.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "RTPFile.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <stdlib.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <limits>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #ifdef WIN32
20*d9f75844SAndroid Build Coastguard Worker #include <Winsock2.h>
21*d9f75844SAndroid Build Coastguard Worker #else
22*d9f75844SAndroid Build Coastguard Worker #include <arpa/inet.h>
23*d9f75844SAndroid Build Coastguard Worker #endif
24*d9f75844SAndroid Build Coastguard Worker 
25*d9f75844SAndroid Build Coastguard Worker // TODO(tlegrand): Consider removing usage of gtest.
26*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
27*d9f75844SAndroid Build Coastguard Worker 
28*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
29*d9f75844SAndroid Build Coastguard Worker 
ParseRTPHeader(RTPHeader * rtp_header,const uint8_t * rtpHeader)30*d9f75844SAndroid Build Coastguard Worker void RTPStream::ParseRTPHeader(RTPHeader* rtp_header,
31*d9f75844SAndroid Build Coastguard Worker                                const uint8_t* rtpHeader) {
32*d9f75844SAndroid Build Coastguard Worker   rtp_header->payloadType = rtpHeader[1];
33*d9f75844SAndroid Build Coastguard Worker   rtp_header->sequenceNumber =
34*d9f75844SAndroid Build Coastguard Worker       (static_cast<uint16_t>(rtpHeader[2]) << 8) | rtpHeader[3];
35*d9f75844SAndroid Build Coastguard Worker   rtp_header->timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
36*d9f75844SAndroid Build Coastguard Worker                           (static_cast<uint32_t>(rtpHeader[5]) << 16) |
37*d9f75844SAndroid Build Coastguard Worker                           (static_cast<uint32_t>(rtpHeader[6]) << 8) |
38*d9f75844SAndroid Build Coastguard Worker                           rtpHeader[7];
39*d9f75844SAndroid Build Coastguard Worker   rtp_header->ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) |
40*d9f75844SAndroid Build Coastguard Worker                      (static_cast<uint32_t>(rtpHeader[9]) << 16) |
41*d9f75844SAndroid Build Coastguard Worker                      (static_cast<uint32_t>(rtpHeader[10]) << 8) |
42*d9f75844SAndroid Build Coastguard Worker                      rtpHeader[11];
43*d9f75844SAndroid Build Coastguard Worker }
44*d9f75844SAndroid Build Coastguard Worker 
MakeRTPheader(uint8_t * rtpHeader,uint8_t payloadType,int16_t seqNo,uint32_t timeStamp,uint32_t ssrc)45*d9f75844SAndroid Build Coastguard Worker void RTPStream::MakeRTPheader(uint8_t* rtpHeader,
46*d9f75844SAndroid Build Coastguard Worker                               uint8_t payloadType,
47*d9f75844SAndroid Build Coastguard Worker                               int16_t seqNo,
48*d9f75844SAndroid Build Coastguard Worker                               uint32_t timeStamp,
49*d9f75844SAndroid Build Coastguard Worker                               uint32_t ssrc) {
50*d9f75844SAndroid Build Coastguard Worker   rtpHeader[0] = 0x80;
51*d9f75844SAndroid Build Coastguard Worker   rtpHeader[1] = payloadType;
52*d9f75844SAndroid Build Coastguard Worker   rtpHeader[2] = (seqNo >> 8) & 0xFF;
53*d9f75844SAndroid Build Coastguard Worker   rtpHeader[3] = seqNo & 0xFF;
54*d9f75844SAndroid Build Coastguard Worker   rtpHeader[4] = timeStamp >> 24;
55*d9f75844SAndroid Build Coastguard Worker   rtpHeader[5] = (timeStamp >> 16) & 0xFF;
56*d9f75844SAndroid Build Coastguard Worker   rtpHeader[6] = (timeStamp >> 8) & 0xFF;
57*d9f75844SAndroid Build Coastguard Worker   rtpHeader[7] = timeStamp & 0xFF;
58*d9f75844SAndroid Build Coastguard Worker   rtpHeader[8] = ssrc >> 24;
59*d9f75844SAndroid Build Coastguard Worker   rtpHeader[9] = (ssrc >> 16) & 0xFF;
60*d9f75844SAndroid Build Coastguard Worker   rtpHeader[10] = (ssrc >> 8) & 0xFF;
61*d9f75844SAndroid Build Coastguard Worker   rtpHeader[11] = ssrc & 0xFF;
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker 
RTPPacket(uint8_t payloadType,uint32_t timeStamp,int16_t seqNo,const uint8_t * payloadData,size_t payloadSize,uint32_t frequency)64*d9f75844SAndroid Build Coastguard Worker RTPPacket::RTPPacket(uint8_t payloadType,
65*d9f75844SAndroid Build Coastguard Worker                      uint32_t timeStamp,
66*d9f75844SAndroid Build Coastguard Worker                      int16_t seqNo,
67*d9f75844SAndroid Build Coastguard Worker                      const uint8_t* payloadData,
68*d9f75844SAndroid Build Coastguard Worker                      size_t payloadSize,
69*d9f75844SAndroid Build Coastguard Worker                      uint32_t frequency)
70*d9f75844SAndroid Build Coastguard Worker     : payloadType(payloadType),
71*d9f75844SAndroid Build Coastguard Worker       timeStamp(timeStamp),
72*d9f75844SAndroid Build Coastguard Worker       seqNo(seqNo),
73*d9f75844SAndroid Build Coastguard Worker       payloadSize(payloadSize),
74*d9f75844SAndroid Build Coastguard Worker       frequency(frequency) {
75*d9f75844SAndroid Build Coastguard Worker   if (payloadSize > 0) {
76*d9f75844SAndroid Build Coastguard Worker     this->payloadData = new uint8_t[payloadSize];
77*d9f75844SAndroid Build Coastguard Worker     memcpy(this->payloadData, payloadData, payloadSize);
78*d9f75844SAndroid Build Coastguard Worker   }
79*d9f75844SAndroid Build Coastguard Worker }
80*d9f75844SAndroid Build Coastguard Worker 
~RTPPacket()81*d9f75844SAndroid Build Coastguard Worker RTPPacket::~RTPPacket() {
82*d9f75844SAndroid Build Coastguard Worker   delete[] payloadData;
83*d9f75844SAndroid Build Coastguard Worker }
84*d9f75844SAndroid Build Coastguard Worker 
Write(const uint8_t payloadType,const uint32_t timeStamp,const int16_t seqNo,const uint8_t * payloadData,const size_t payloadSize,uint32_t frequency)85*d9f75844SAndroid Build Coastguard Worker void RTPBuffer::Write(const uint8_t payloadType,
86*d9f75844SAndroid Build Coastguard Worker                       const uint32_t timeStamp,
87*d9f75844SAndroid Build Coastguard Worker                       const int16_t seqNo,
88*d9f75844SAndroid Build Coastguard Worker                       const uint8_t* payloadData,
89*d9f75844SAndroid Build Coastguard Worker                       const size_t payloadSize,
90*d9f75844SAndroid Build Coastguard Worker                       uint32_t frequency) {
91*d9f75844SAndroid Build Coastguard Worker   RTPPacket* packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
92*d9f75844SAndroid Build Coastguard Worker                                     payloadSize, frequency);
93*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
94*d9f75844SAndroid Build Coastguard Worker   _rtpQueue.push(packet);
95*d9f75844SAndroid Build Coastguard Worker }
96*d9f75844SAndroid Build Coastguard Worker 
Read(RTPHeader * rtp_header,uint8_t * payloadData,size_t payloadSize,uint32_t * offset)97*d9f75844SAndroid Build Coastguard Worker size_t RTPBuffer::Read(RTPHeader* rtp_header,
98*d9f75844SAndroid Build Coastguard Worker                        uint8_t* payloadData,
99*d9f75844SAndroid Build Coastguard Worker                        size_t payloadSize,
100*d9f75844SAndroid Build Coastguard Worker                        uint32_t* offset) {
101*d9f75844SAndroid Build Coastguard Worker   RTPPacket* packet;
102*d9f75844SAndroid Build Coastguard Worker   {
103*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&mutex_);
104*d9f75844SAndroid Build Coastguard Worker     packet = _rtpQueue.front();
105*d9f75844SAndroid Build Coastguard Worker     _rtpQueue.pop();
106*d9f75844SAndroid Build Coastguard Worker   }
107*d9f75844SAndroid Build Coastguard Worker   rtp_header->markerBit = 1;
108*d9f75844SAndroid Build Coastguard Worker   rtp_header->payloadType = packet->payloadType;
109*d9f75844SAndroid Build Coastguard Worker   rtp_header->sequenceNumber = packet->seqNo;
110*d9f75844SAndroid Build Coastguard Worker   rtp_header->ssrc = 0;
111*d9f75844SAndroid Build Coastguard Worker   rtp_header->timestamp = packet->timeStamp;
112*d9f75844SAndroid Build Coastguard Worker   if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
113*d9f75844SAndroid Build Coastguard Worker     memcpy(payloadData, packet->payloadData, packet->payloadSize);
114*d9f75844SAndroid Build Coastguard Worker   } else {
115*d9f75844SAndroid Build Coastguard Worker     return 0;
116*d9f75844SAndroid Build Coastguard Worker   }
117*d9f75844SAndroid Build Coastguard Worker   *offset = (packet->timeStamp / (packet->frequency / 1000));
118*d9f75844SAndroid Build Coastguard Worker 
119*d9f75844SAndroid Build Coastguard Worker   return packet->payloadSize;
120*d9f75844SAndroid Build Coastguard Worker }
121*d9f75844SAndroid Build Coastguard Worker 
EndOfFile() const122*d9f75844SAndroid Build Coastguard Worker bool RTPBuffer::EndOfFile() const {
123*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
124*d9f75844SAndroid Build Coastguard Worker   return _rtpQueue.empty();
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker 
Open(absl::string_view filename,absl::string_view mode)127*d9f75844SAndroid Build Coastguard Worker void RTPFile::Open(absl::string_view filename, absl::string_view mode) {
128*d9f75844SAndroid Build Coastguard Worker   std::string filename_str = std::string(filename);
129*d9f75844SAndroid Build Coastguard Worker   if ((_rtpFile = fopen(filename_str.c_str(), std::string(mode).c_str())) ==
130*d9f75844SAndroid Build Coastguard Worker       NULL) {
131*d9f75844SAndroid Build Coastguard Worker     printf("Cannot write file %s.\n", filename_str.c_str());
132*d9f75844SAndroid Build Coastguard Worker     ADD_FAILURE() << "Unable to write file";
133*d9f75844SAndroid Build Coastguard Worker     exit(1);
134*d9f75844SAndroid Build Coastguard Worker   }
135*d9f75844SAndroid Build Coastguard Worker }
136*d9f75844SAndroid Build Coastguard Worker 
Close()137*d9f75844SAndroid Build Coastguard Worker void RTPFile::Close() {
138*d9f75844SAndroid Build Coastguard Worker   if (_rtpFile != NULL) {
139*d9f75844SAndroid Build Coastguard Worker     fclose(_rtpFile);
140*d9f75844SAndroid Build Coastguard Worker     _rtpFile = NULL;
141*d9f75844SAndroid Build Coastguard Worker   }
142*d9f75844SAndroid Build Coastguard Worker }
143*d9f75844SAndroid Build Coastguard Worker 
WriteHeader()144*d9f75844SAndroid Build Coastguard Worker void RTPFile::WriteHeader() {
145*d9f75844SAndroid Build Coastguard Worker   // Write data in a format that NetEQ and RTP Play can parse
146*d9f75844SAndroid Build Coastguard Worker   fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
147*d9f75844SAndroid Build Coastguard Worker   uint32_t dummy_variable = 0;
148*d9f75844SAndroid Build Coastguard Worker   // should be converted to network endian format, but does not matter when 0
149*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
150*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
151*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
152*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
153*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
154*d9f75844SAndroid Build Coastguard Worker   fflush(_rtpFile);
155*d9f75844SAndroid Build Coastguard Worker }
156*d9f75844SAndroid Build Coastguard Worker 
ReadHeader()157*d9f75844SAndroid Build Coastguard Worker void RTPFile::ReadHeader() {
158*d9f75844SAndroid Build Coastguard Worker   uint32_t start_sec, start_usec, source;
159*d9f75844SAndroid Build Coastguard Worker   uint16_t port, padding;
160*d9f75844SAndroid Build Coastguard Worker   char fileHeader[40];
161*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
162*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
163*d9f75844SAndroid Build Coastguard Worker   start_sec = ntohl(start_sec);
164*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
165*d9f75844SAndroid Build Coastguard Worker   start_usec = ntohl(start_usec);
166*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
167*d9f75844SAndroid Build Coastguard Worker   source = ntohl(source);
168*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
169*d9f75844SAndroid Build Coastguard Worker   port = ntohs(port);
170*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
171*d9f75844SAndroid Build Coastguard Worker   padding = ntohs(padding);
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker 
Write(const uint8_t payloadType,const uint32_t timeStamp,const int16_t seqNo,const uint8_t * payloadData,const size_t payloadSize,uint32_t frequency)174*d9f75844SAndroid Build Coastguard Worker void RTPFile::Write(const uint8_t payloadType,
175*d9f75844SAndroid Build Coastguard Worker                     const uint32_t timeStamp,
176*d9f75844SAndroid Build Coastguard Worker                     const int16_t seqNo,
177*d9f75844SAndroid Build Coastguard Worker                     const uint8_t* payloadData,
178*d9f75844SAndroid Build Coastguard Worker                     const size_t payloadSize,
179*d9f75844SAndroid Build Coastguard Worker                     uint32_t frequency) {
180*d9f75844SAndroid Build Coastguard Worker   /* write RTP packet to file */
181*d9f75844SAndroid Build Coastguard Worker   uint8_t rtpHeader[12];
182*d9f75844SAndroid Build Coastguard Worker   MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
183*d9f75844SAndroid Build Coastguard Worker   ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max());
184*d9f75844SAndroid Build Coastguard Worker   uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8));
185*d9f75844SAndroid Build Coastguard Worker   uint16_t plen = htons(static_cast<u_short>(12 + payloadSize));
186*d9f75844SAndroid Build Coastguard Worker   uint32_t offsetMs;
187*d9f75844SAndroid Build Coastguard Worker 
188*d9f75844SAndroid Build Coastguard Worker   offsetMs = (timeStamp / (frequency / 1000));
189*d9f75844SAndroid Build Coastguard Worker   offsetMs = htonl(offsetMs);
190*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile));
191*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile));
192*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile));
193*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile));
194*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile));
195*d9f75844SAndroid Build Coastguard Worker }
196*d9f75844SAndroid Build Coastguard Worker 
Read(RTPHeader * rtp_header,uint8_t * payloadData,size_t payloadSize,uint32_t * offset)197*d9f75844SAndroid Build Coastguard Worker size_t RTPFile::Read(RTPHeader* rtp_header,
198*d9f75844SAndroid Build Coastguard Worker                      uint8_t* payloadData,
199*d9f75844SAndroid Build Coastguard Worker                      size_t payloadSize,
200*d9f75844SAndroid Build Coastguard Worker                      uint32_t* offset) {
201*d9f75844SAndroid Build Coastguard Worker   uint16_t lengthBytes;
202*d9f75844SAndroid Build Coastguard Worker   uint16_t plen;
203*d9f75844SAndroid Build Coastguard Worker   uint8_t rtpHeader[12];
204*d9f75844SAndroid Build Coastguard Worker   size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
205*d9f75844SAndroid Build Coastguard Worker   /* Check if we have reached end of file. */
206*d9f75844SAndroid Build Coastguard Worker   if ((read_len == 0) && feof(_rtpFile)) {
207*d9f75844SAndroid Build Coastguard Worker     _rtpEOF = true;
208*d9f75844SAndroid Build Coastguard Worker     return 0;
209*d9f75844SAndroid Build Coastguard Worker   }
210*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
211*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
212*d9f75844SAndroid Build Coastguard Worker   lengthBytes = ntohs(lengthBytes);
213*d9f75844SAndroid Build Coastguard Worker   plen = ntohs(plen);
214*d9f75844SAndroid Build Coastguard Worker   *offset = ntohl(*offset);
215*d9f75844SAndroid Build Coastguard Worker   EXPECT_GT(plen, 11);
216*d9f75844SAndroid Build Coastguard Worker 
217*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
218*d9f75844SAndroid Build Coastguard Worker   ParseRTPHeader(rtp_header, rtpHeader);
219*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(lengthBytes, plen + 8);
220*d9f75844SAndroid Build Coastguard Worker 
221*d9f75844SAndroid Build Coastguard Worker   if (plen == 0) {
222*d9f75844SAndroid Build Coastguard Worker     return 0;
223*d9f75844SAndroid Build Coastguard Worker   }
224*d9f75844SAndroid Build Coastguard Worker   if (lengthBytes < 20) {
225*d9f75844SAndroid Build Coastguard Worker     return 0;
226*d9f75844SAndroid Build Coastguard Worker   }
227*d9f75844SAndroid Build Coastguard Worker   if (payloadSize < static_cast<size_t>((lengthBytes - 20))) {
228*d9f75844SAndroid Build Coastguard Worker     return 0;
229*d9f75844SAndroid Build Coastguard Worker   }
230*d9f75844SAndroid Build Coastguard Worker   lengthBytes -= 20;
231*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
232*d9f75844SAndroid Build Coastguard Worker   return lengthBytes;
233*d9f75844SAndroid Build Coastguard Worker }
234*d9f75844SAndroid Build Coastguard Worker 
235*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
236