1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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"
12
13#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"
22#include "engine_configurations.h"
23#include "rw_lock_wrapper.h"
24// TODO(tlegrand): Consider removing usage of gtest.
25#include "testing/gtest/include/gtest/gtest.h"
26
27namespace webrtc {
28
29void 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];
40}
41
42void 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);
51
52  rtpHeader[6] = (unsigned char) ((timeStamp >> 8) & 0xFF);
53  rtpHeader[7] = (unsigned char) (timeStamp & 0xFF);
54
55  rtpHeader[8] = (unsigned char) ((ssrc >> 24) & 0xFF);
56  rtpHeader[9] = (unsigned char) ((ssrc >> 16) & 0xFF);
57
58  rtpHeader[10] = (unsigned char) ((ssrc >> 8) & 0xFF);
59  rtpHeader[11] = (unsigned char) (ssrc & 0xFF);
60}
61
62RTPPacket::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  }
74}
75
76RTPPacket::~RTPPacket() {
77  delete[] payloadData;
78}
79
80RTPBuffer::RTPBuffer() {
81  _queueRWLock = RWLockWrapper::CreateRWLock();
82}
83
84RTPBuffer::~RTPBuffer() {
85  delete _queueRWLock;
86}
87
88void 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();
96}
97
98uint16_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));
115
116  return packet->payloadSize;
117}
118
119bool RTPBuffer::EndOfFile() const {
120  _queueRWLock->AcquireLockShared();
121  bool eof = _rtpQueue.empty();
122  _queueRWLock->ReleaseLockShared();
123  return eof;
124}
125
126void 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  }
132}
133
134void RTPFile::Close() {
135  if (_rtpFile != NULL) {
136    fclose(_rtpFile);
137    _rtpFile = NULL;
138  }
139}
140
141void 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);
162}
163
164void 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);
179}
180
181void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
182                    const int16_t seqNo, const uint8_t* payloadData,
183                    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;
190
191  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  }
208}
209
210uint16_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);
227
228  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);
233
234  if (plen == 0) {
235    return 0;
236  }
237  if (lengthBytes < 20) {
238    return 0;
239  }
240  if (payloadSize < (lengthBytes - 20)) {
241    return 0;
242  }
243  lengthBytes -= 20;
244  EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
245  return lengthBytes;
246}
247
248}  // namespace webrtc
249