blob: 4cb6c35cc51e5d7352690b5210989476865f506a [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/test/Channel.h"
turaj@webrtc.orga305e962013-06-06 19:00:09 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <assert.h>
14#include <iostream>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/format_macros.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/time_utils.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000019namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000020
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000021int32_t Channel::SendData(FrameType frameType,
22 uint8_t payloadType,
23 uint32_t timeStamp,
24 const uint8_t* payloadData,
25 size_t payloadSize,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000026 const RTPFragmentationHeader* fragmentation) {
27 WebRtcRTPHeader rtpInfo;
28 int32_t status;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000029 size_t payloadDataSize = payloadSize;
niklase@google.com470e71d2011-07-07 08:21:25 +000030
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000031 rtpInfo.header.markerBit = false;
32 rtpInfo.header.ssrc = 0;
Yves Gerey665174f2018-06-19 15:03:05 +020033 rtpInfo.header.sequenceNumber =
34 (external_sequence_number_ < 0)
35 ? _seqNo++
36 : static_cast<uint16_t>(external_sequence_number_);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000037 rtpInfo.header.payloadType = payloadType;
Yves Gerey665174f2018-06-19 15:03:05 +020038 rtpInfo.header.timestamp =
39 (external_send_timestamp_ < 0)
40 ? timeStamp
41 : static_cast<uint32_t>(external_send_timestamp_);
turaj@webrtc.orga305e962013-06-06 19:00:09 +000042
pbos22993e12015-10-19 02:39:06 -070043 if (frameType == kEmptyFrame) {
minyue@webrtc.org05617162015-03-03 12:02:30 +000044 // When frame is empty, we should not transmit it. The frame size of the
45 // next non-empty frame will be based on the previous frame size.
46 _useLastFrameSize = _lastFrameSizeSample > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000047 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000048 }
niklase@google.com470e71d2011-07-07 08:21:25 +000049
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000050 // Treat fragmentation separately
51 if (fragmentation != NULL) {
52 // If silence for too long, send only new data.
henrik.lundin@webrtc.org05db3522015-01-30 13:03:45 +000053 if ((fragmentation->fragmentationVectorSize == 2) &&
54 (fragmentation->fragmentationTimeDiff[1] <= 0x3fff)) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000055 // only 0x80 if we have multiple blocks
56 _payloadData[0] = 0x80 + fragmentation->fragmentationPlType[1];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000057 size_t REDheader = (fragmentation->fragmentationTimeDiff[1] << 10) +
Yves Gerey665174f2018-06-19 15:03:05 +020058 fragmentation->fragmentationLength[1];
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000059 _payloadData[1] = uint8_t((REDheader >> 16) & 0x000000FF);
60 _payloadData[2] = uint8_t((REDheader >> 8) & 0x000000FF);
61 _payloadData[3] = uint8_t(REDheader & 0x000000FF);
62
63 _payloadData[4] = fragmentation->fragmentationPlType[0];
64 // copy the RED data
65 memcpy(_payloadData + 5,
66 payloadData + fragmentation->fragmentationOffset[1],
67 fragmentation->fragmentationLength[1]);
68 // copy the normal data
69 memcpy(_payloadData + 5 + fragmentation->fragmentationLength[1],
70 payloadData + fragmentation->fragmentationOffset[0],
71 fragmentation->fragmentationLength[0]);
72 payloadDataSize += 5;
73 } else {
74 // single block (newest one)
75 memcpy(_payloadData, payloadData + fragmentation->fragmentationOffset[0],
76 fragmentation->fragmentationLength[0]);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000077 payloadDataSize = fragmentation->fragmentationLength[0];
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000078 rtpInfo.header.payloadType = fragmentation->fragmentationPlType[0];
niklase@google.com470e71d2011-07-07 08:21:25 +000079 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000080 } else {
81 memcpy(_payloadData, payloadData, payloadDataSize);
82 if (_isStereo) {
83 if (_leftChannel) {
84 memcpy(&_rtpInfo, &rtpInfo, sizeof(WebRtcRTPHeader));
85 _leftChannel = false;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000086 } else {
87 memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcRTPHeader));
88 _leftChannel = true;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000089 }
niklase@google.com470e71d2011-07-07 08:21:25 +000090 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000091 }
niklase@google.com470e71d2011-07-07 08:21:25 +000092
Tommi9090e0b2016-01-20 13:39:36 +010093 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000094 if (_saveBitStream) {
Yves Gerey665174f2018-06-19 15:03:05 +020095 // fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000096 }
niklase@google.com470e71d2011-07-07 08:21:25 +000097
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000098 if (!_isStereo) {
99 CalcStatistics(rtpInfo, payloadSize);
100 }
minyue@webrtc.org05617162015-03-03 12:02:30 +0000101 _useLastFrameSize = false;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000102 _lastInTimestamp = timeStamp;
103 _totalBytes += payloadDataSize;
Tommi9090e0b2016-01-20 13:39:36 +0100104 _channelCritSect.Leave();
niklase@google.com470e71d2011-07-07 08:21:25 +0000105
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000106 if (_useFECTestWithPacketLoss) {
107 _packetLoss += 1;
108 if (_packetLoss == 3) {
109 _packetLoss = 0;
110 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000111 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000112 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000114 if (num_packets_to_drop_ > 0) {
115 num_packets_to_drop_--;
116 return 0;
117 }
118
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000119 status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtpInfo);
120
121 return status;
122}
123
turaj@webrtc.orgc2d69d32014-02-19 20:31:17 +0000124// TODO(turajs): rewite this method.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000125void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000126 int n;
Yves Gerey665174f2018-06-19 15:03:05 +0200127 if ((rtpInfo.header.payloadType != _lastPayloadType) &&
128 (_lastPayloadType != -1)) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000129 // payload-type is changed.
130 // we have to terminate the calculations on the previous payload type
131 // we ignore the last packet in that payload type just to make things
132 // easier.
133 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
134 if (_lastPayloadType == _payloadStats[n].payloadType) {
135 _payloadStats[n].newPacket = true;
136 break;
137 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000139 }
140 _lastPayloadType = rtpInfo.header.payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000141
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000142 bool newPayload = true;
143 ACMTestPayloadStats* currentPayloadStr = NULL;
144 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
145 if (rtpInfo.header.payloadType == _payloadStats[n].payloadType) {
146 newPayload = false;
147 currentPayloadStr = &_payloadStats[n];
148 break;
149 }
150 }
151
152 if (!newPayload) {
153 if (!currentPayloadStr->newPacket) {
minyue@webrtc.org05617162015-03-03 12:02:30 +0000154 if (!_useLastFrameSize) {
Yves Gerey665174f2018-06-19 15:03:05 +0200155 _lastFrameSizeSample =
156 (uint32_t)((uint32_t)rtpInfo.header.timestamp -
157 (uint32_t)currentPayloadStr->lastTimestamp);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000158 }
159 assert(_lastFrameSizeSample > 0);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000160 int k = 0;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000161 for (; k < MAX_NUM_FRAMESIZES; ++k) {
162 if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
Yves Gerey665174f2018-06-19 15:03:05 +0200163 _lastFrameSizeSample) ||
minyue@webrtc.org05617162015-03-03 12:02:30 +0000164 (currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
165 break;
166 }
167 }
168 if (k == MAX_NUM_FRAMESIZES) {
169 // New frame size found but no space to count statistics on it. Skip it.
170 printf("No memory to store statistics for payload %d : frame size %d\n",
171 _lastPayloadType, _lastFrameSizeSample);
172 return;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000173 }
Yves Gerey665174f2018-06-19 15:03:05 +0200174 ACMTestFrameSizeStats* currentFrameSizeStats =
175 &(currentPayloadStr->frameSizeStats[k]);
176 currentFrameSizeStats->frameSizeSample = (int16_t)_lastFrameSizeSample;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000177
178 // increment the number of encoded samples.
minyue@webrtc.org05617162015-03-03 12:02:30 +0000179 currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000180 // increment the number of recveived packets
181 currentFrameSizeStats->numPackets++;
182 // increment the total number of bytes (this is based on
183 // the previous payload we don't know the frame-size of
184 // the current payload.
Yves Gerey665174f2018-06-19 15:03:05 +0200185 currentFrameSizeStats->totalPayloadLenByte +=
186 currentPayloadStr->lastPayloadLenByte;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000187 // store the maximum payload-size (this is based on
188 // the previous payload we don't know the frame-size of
189 // the current payload.
Yves Gerey665174f2018-06-19 15:03:05 +0200190 if (currentFrameSizeStats->maxPayloadLen <
191 currentPayloadStr->lastPayloadLenByte) {
192 currentFrameSizeStats->maxPayloadLen =
193 currentPayloadStr->lastPayloadLenByte;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000194 }
195 // store the current values for the next time
196 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
197 currentPayloadStr->lastPayloadLenByte = payloadSize;
198 } else {
199 currentPayloadStr->newPacket = false;
200 currentPayloadStr->lastPayloadLenByte = payloadSize;
201 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
202 currentPayloadStr->payloadType = rtpInfo.header.payloadType;
Yves Gerey665174f2018-06-19 15:03:05 +0200203 memset(currentPayloadStr->frameSizeStats, 0,
204 MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000205 }
206 } else {
207 n = 0;
208 while (_payloadStats[n].payloadType != -1) {
209 n++;
210 }
211 // first packet
212 _payloadStats[n].newPacket = false;
213 _payloadStats[n].lastPayloadLenByte = payloadSize;
214 _payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
215 _payloadStats[n].payloadType = rtpInfo.header.payloadType;
Yves Gerey665174f2018-06-19 15:03:05 +0200216 memset(_payloadStats[n].frameSizeStats, 0,
217 MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000218 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000219}
220
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000221Channel::Channel(int16_t chID)
222 : _receiverACM(NULL),
223 _seqNo(0),
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000224 _bitStreamFile(NULL),
225 _saveBitStream(false),
226 _lastPayloadType(-1),
227 _isStereo(false),
228 _leftChannel(true),
229 _lastInTimestamp(0),
minyue@webrtc.org05617162015-03-03 12:02:30 +0000230 _useLastFrameSize(false),
231 _lastFrameSizeSample(0),
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000232 _packetLoss(0),
233 _useFECTestWithPacketLoss(false),
Niels Möllerd28db7f2016-05-10 16:31:47 +0200234 _beginTime(rtc::TimeMillis()),
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000235 _totalBytes(0),
236 external_send_timestamp_(-1),
237 external_sequence_number_(-1),
238 num_packets_to_drop_(0) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000239 int n;
240 int k;
241 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
242 _payloadStats[n].payloadType = -1;
243 _payloadStats[n].newPacket = true;
244 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
245 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
246 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
247 _payloadStats[n].frameSizeStats[k].numPackets = 0;
248 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
249 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
250 }
251 }
252 if (chID >= 0) {
253 _saveBitStream = true;
254 char bitStreamFileName[500];
255 sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
256 _bitStreamFile = fopen(bitStreamFileName, "wb");
257 } else {
258 _saveBitStream = false;
259 }
260}
261
Yves Gerey665174f2018-06-19 15:03:05 +0200262Channel::~Channel() {}
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000263
264void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
265 _receiverACM = acm;
266 return;
267}
268
269void Channel::ResetStats() {
270 int n;
271 int k;
Tommi9090e0b2016-01-20 13:39:36 +0100272 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000273 _lastPayloadType = -1;
274 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
275 _payloadStats[n].payloadType = -1;
276 _payloadStats[n].newPacket = true;
277 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
278 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
279 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
280 _payloadStats[n].frameSizeStats[k].numPackets = 0;
281 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
282 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
283 }
284 }
Niels Möllerd28db7f2016-05-10 16:31:47 +0200285 _beginTime = rtc::TimeMillis();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000286 _totalBytes = 0;
Tommi9090e0b2016-01-20 13:39:36 +0100287 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000288}
289
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000290uint32_t Channel::LastInTimestamp() {
291 uint32_t timestamp;
Tommi9090e0b2016-01-20 13:39:36 +0100292 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000293 timestamp = _lastInTimestamp;
Tommi9090e0b2016-01-20 13:39:36 +0100294 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000295 return timestamp;
296}
297
298double Channel::BitRate() {
299 double rate;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200300 uint64_t currTime = rtc::TimeMillis();
Tommi9090e0b2016-01-20 13:39:36 +0100301 _channelCritSect.Enter();
Yves Gerey665174f2018-06-19 15:03:05 +0200302 rate = ((double)_totalBytes * 8.0) / (double)(currTime - _beginTime);
Tommi9090e0b2016-01-20 13:39:36 +0100303 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000304 return rate;
305}
306
307} // namespace webrtc