blob: e54a29aca81e9d76da418e8fb0c5ad77011591c4 [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
Niels Möllerafb5dbb2019-02-15 15:21:47 +0100119 status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize,
120 rtpInfo.header);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000121
122 return status;
123}
124
turaj@webrtc.orgc2d69d32014-02-19 20:31:17 +0000125// TODO(turajs): rewite this method.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000126void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000127 int n;
Yves Gerey665174f2018-06-19 15:03:05 +0200128 if ((rtpInfo.header.payloadType != _lastPayloadType) &&
129 (_lastPayloadType != -1)) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000130 // payload-type is changed.
131 // we have to terminate the calculations on the previous payload type
132 // we ignore the last packet in that payload type just to make things
133 // easier.
134 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
135 if (_lastPayloadType == _payloadStats[n].payloadType) {
136 _payloadStats[n].newPacket = true;
137 break;
138 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000140 }
141 _lastPayloadType = rtpInfo.header.payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000142
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000143 bool newPayload = true;
144 ACMTestPayloadStats* currentPayloadStr = NULL;
145 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
146 if (rtpInfo.header.payloadType == _payloadStats[n].payloadType) {
147 newPayload = false;
148 currentPayloadStr = &_payloadStats[n];
149 break;
150 }
151 }
152
153 if (!newPayload) {
154 if (!currentPayloadStr->newPacket) {
minyue@webrtc.org05617162015-03-03 12:02:30 +0000155 if (!_useLastFrameSize) {
Yves Gerey665174f2018-06-19 15:03:05 +0200156 _lastFrameSizeSample =
157 (uint32_t)((uint32_t)rtpInfo.header.timestamp -
158 (uint32_t)currentPayloadStr->lastTimestamp);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000159 }
160 assert(_lastFrameSizeSample > 0);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000161 int k = 0;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000162 for (; k < MAX_NUM_FRAMESIZES; ++k) {
163 if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
Yves Gerey665174f2018-06-19 15:03:05 +0200164 _lastFrameSizeSample) ||
minyue@webrtc.org05617162015-03-03 12:02:30 +0000165 (currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
166 break;
167 }
168 }
169 if (k == MAX_NUM_FRAMESIZES) {
170 // New frame size found but no space to count statistics on it. Skip it.
171 printf("No memory to store statistics for payload %d : frame size %d\n",
172 _lastPayloadType, _lastFrameSizeSample);
173 return;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000174 }
Yves Gerey665174f2018-06-19 15:03:05 +0200175 ACMTestFrameSizeStats* currentFrameSizeStats =
176 &(currentPayloadStr->frameSizeStats[k]);
177 currentFrameSizeStats->frameSizeSample = (int16_t)_lastFrameSizeSample;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000178
179 // increment the number of encoded samples.
minyue@webrtc.org05617162015-03-03 12:02:30 +0000180 currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000181 // increment the number of recveived packets
182 currentFrameSizeStats->numPackets++;
183 // increment the total number of bytes (this is based on
184 // the previous payload we don't know the frame-size of
185 // the current payload.
Yves Gerey665174f2018-06-19 15:03:05 +0200186 currentFrameSizeStats->totalPayloadLenByte +=
187 currentPayloadStr->lastPayloadLenByte;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000188 // store the maximum payload-size (this is based on
189 // the previous payload we don't know the frame-size of
190 // the current payload.
Yves Gerey665174f2018-06-19 15:03:05 +0200191 if (currentFrameSizeStats->maxPayloadLen <
192 currentPayloadStr->lastPayloadLenByte) {
193 currentFrameSizeStats->maxPayloadLen =
194 currentPayloadStr->lastPayloadLenByte;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000195 }
196 // store the current values for the next time
197 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
198 currentPayloadStr->lastPayloadLenByte = payloadSize;
199 } else {
200 currentPayloadStr->newPacket = false;
201 currentPayloadStr->lastPayloadLenByte = payloadSize;
202 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
203 currentPayloadStr->payloadType = rtpInfo.header.payloadType;
Yves Gerey665174f2018-06-19 15:03:05 +0200204 memset(currentPayloadStr->frameSizeStats, 0,
205 MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000206 }
207 } else {
208 n = 0;
209 while (_payloadStats[n].payloadType != -1) {
210 n++;
211 }
212 // first packet
213 _payloadStats[n].newPacket = false;
214 _payloadStats[n].lastPayloadLenByte = payloadSize;
215 _payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
216 _payloadStats[n].payloadType = rtpInfo.header.payloadType;
Yves Gerey665174f2018-06-19 15:03:05 +0200217 memset(_payloadStats[n].frameSizeStats, 0,
218 MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000219 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000220}
221
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000222Channel::Channel(int16_t chID)
223 : _receiverACM(NULL),
224 _seqNo(0),
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000225 _bitStreamFile(NULL),
226 _saveBitStream(false),
227 _lastPayloadType(-1),
228 _isStereo(false),
229 _leftChannel(true),
230 _lastInTimestamp(0),
minyue@webrtc.org05617162015-03-03 12:02:30 +0000231 _useLastFrameSize(false),
232 _lastFrameSizeSample(0),
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000233 _packetLoss(0),
234 _useFECTestWithPacketLoss(false),
Niels Möllerd28db7f2016-05-10 16:31:47 +0200235 _beginTime(rtc::TimeMillis()),
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000236 _totalBytes(0),
237 external_send_timestamp_(-1),
238 external_sequence_number_(-1),
239 num_packets_to_drop_(0) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000240 int n;
241 int k;
242 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
243 _payloadStats[n].payloadType = -1;
244 _payloadStats[n].newPacket = true;
245 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
246 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
247 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
248 _payloadStats[n].frameSizeStats[k].numPackets = 0;
249 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
250 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
251 }
252 }
253 if (chID >= 0) {
254 _saveBitStream = true;
255 char bitStreamFileName[500];
256 sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
257 _bitStreamFile = fopen(bitStreamFileName, "wb");
258 } else {
259 _saveBitStream = false;
260 }
261}
262
Yves Gerey665174f2018-06-19 15:03:05 +0200263Channel::~Channel() {}
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000264
265void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
266 _receiverACM = acm;
267 return;
268}
269
270void Channel::ResetStats() {
271 int n;
272 int k;
Tommi9090e0b2016-01-20 13:39:36 +0100273 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000274 _lastPayloadType = -1;
275 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
276 _payloadStats[n].payloadType = -1;
277 _payloadStats[n].newPacket = true;
278 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
279 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
280 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
281 _payloadStats[n].frameSizeStats[k].numPackets = 0;
282 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
283 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
284 }
285 }
Niels Möllerd28db7f2016-05-10 16:31:47 +0200286 _beginTime = rtc::TimeMillis();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000287 _totalBytes = 0;
Tommi9090e0b2016-01-20 13:39:36 +0100288 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000289}
290
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000291uint32_t Channel::LastInTimestamp() {
292 uint32_t timestamp;
Tommi9090e0b2016-01-20 13:39:36 +0100293 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000294 timestamp = _lastInTimestamp;
Tommi9090e0b2016-01-20 13:39:36 +0100295 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000296 return timestamp;
297}
298
299double Channel::BitRate() {
300 double rate;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200301 uint64_t currTime = rtc::TimeMillis();
Tommi9090e0b2016-01-20 13:39:36 +0100302 _channelCritSect.Enter();
Yves Gerey665174f2018-06-19 15:03:05 +0200303 rate = ((double)_totalBytes * 8.0) / (double)(currTime - _beginTime);
Tommi9090e0b2016-01-20 13:39:36 +0100304 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000305 return rate;
306}
307
308} // namespace webrtc