blob: aa9e6cdf40b63cc1e3be360b872f6cd0f7d19e22 [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
turaj@webrtc.orga305e962013-06-06 19:00:09 +000011#include "webrtc/modules/audio_coding/main/test/Channel.h"
12
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <assert.h>
14#include <iostream>
15
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000016#include "webrtc/base/format_macros.h"
turaj@webrtc.orga305e962013-06-06 19:00:09 +000017#include "webrtc/system_wrappers/interface/tick_util.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000020namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000021
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000022int32_t Channel::SendData(FrameType frameType,
23 uint8_t payloadType,
24 uint32_t timeStamp,
25 const uint8_t* payloadData,
26 size_t payloadSize,
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000027 const RTPFragmentationHeader* fragmentation) {
28 WebRtcRTPHeader rtpInfo;
29 int32_t status;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000030 size_t payloadDataSize = payloadSize;
niklase@google.com470e71d2011-07-07 08:21:25 +000031
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000032 rtpInfo.header.markerBit = false;
33 rtpInfo.header.ssrc = 0;
turaj@webrtc.orga305e962013-06-06 19:00:09 +000034 rtpInfo.header.sequenceNumber = (external_sequence_number_ < 0) ?
35 _seqNo++ : static_cast<uint16_t>(external_sequence_number_);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000036 rtpInfo.header.payloadType = payloadType;
turaj@webrtc.orga305e962013-06-06 19:00:09 +000037 rtpInfo.header.timestamp = (external_send_timestamp_ < 0) ? timeStamp :
38 static_cast<uint32_t>(external_send_timestamp_);
39
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000040 if (frameType == kAudioFrameCN) {
41 rtpInfo.type.Audio.isCNG = true;
42 } else {
43 rtpInfo.type.Audio.isCNG = false;
44 }
45 if (frameType == kFrameEmpty) {
46 // Skip this frame
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 rtpInfo.type.Audio.channel = 1;
51 // Treat fragmentation separately
52 if (fragmentation != NULL) {
53 // If silence for too long, send only new data.
54 if ((fragmentation->fragmentationTimeDiff[1] <= 0x3fff) &&
55 (fragmentation->fragmentationVectorSize == 2)) {
56 // only 0x80 if we have multiple blocks
57 _payloadData[0] = 0x80 + fragmentation->fragmentationPlType[1];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000058 size_t REDheader = (fragmentation->fragmentationTimeDiff[1] << 10) +
59 fragmentation->fragmentationLength[1];
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000060 _payloadData[1] = uint8_t((REDheader >> 16) & 0x000000FF);
61 _payloadData[2] = uint8_t((REDheader >> 8) & 0x000000FF);
62 _payloadData[3] = uint8_t(REDheader & 0x000000FF);
63
64 _payloadData[4] = fragmentation->fragmentationPlType[0];
65 // copy the RED data
66 memcpy(_payloadData + 5,
67 payloadData + fragmentation->fragmentationOffset[1],
68 fragmentation->fragmentationLength[1]);
69 // copy the normal data
70 memcpy(_payloadData + 5 + fragmentation->fragmentationLength[1],
71 payloadData + fragmentation->fragmentationOffset[0],
72 fragmentation->fragmentationLength[0]);
73 payloadDataSize += 5;
74 } else {
75 // single block (newest one)
76 memcpy(_payloadData, payloadData + fragmentation->fragmentationOffset[0],
77 fragmentation->fragmentationLength[0]);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000078 payloadDataSize = fragmentation->fragmentationLength[0];
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000079 rtpInfo.header.payloadType = fragmentation->fragmentationPlType[0];
niklase@google.com470e71d2011-07-07 08:21:25 +000080 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000081 } else {
82 memcpy(_payloadData, payloadData, payloadDataSize);
83 if (_isStereo) {
84 if (_leftChannel) {
85 memcpy(&_rtpInfo, &rtpInfo, sizeof(WebRtcRTPHeader));
86 _leftChannel = false;
87 rtpInfo.type.Audio.channel = 1;
88 } else {
89 memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcRTPHeader));
90 _leftChannel = true;
91 rtpInfo.type.Audio.channel = 2;
92 }
niklase@google.com470e71d2011-07-07 08:21:25 +000093 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000094 }
niklase@google.com470e71d2011-07-07 08:21:25 +000095
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000096 _channelCritSect->Enter();
97 if (_saveBitStream) {
98 //fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
99 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000101 if (!_isStereo) {
102 CalcStatistics(rtpInfo, payloadSize);
103 }
104 _lastInTimestamp = timeStamp;
105 _totalBytes += payloadDataSize;
106 _channelCritSect->Leave();
niklase@google.com470e71d2011-07-07 08:21:25 +0000107
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000108 if (_useFECTestWithPacketLoss) {
109 _packetLoss += 1;
110 if (_packetLoss == 3) {
111 _packetLoss = 0;
112 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000114 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000116 if (num_packets_to_drop_ > 0) {
117 num_packets_to_drop_--;
118 return 0;
119 }
120
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000121 status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtpInfo);
122
123 return status;
124}
125
turaj@webrtc.orgc2d69d32014-02-19 20:31:17 +0000126// TODO(turajs): rewite this method.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000127void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000128 int n;
129 if ((rtpInfo.header.payloadType != _lastPayloadType)
130 && (_lastPayloadType != -1)) {
131 // payload-type is changed.
132 // we have to terminate the calculations on the previous payload type
133 // we ignore the last packet in that payload type just to make things
134 // easier.
135 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
136 if (_lastPayloadType == _payloadStats[n].payloadType) {
137 _payloadStats[n].newPacket = true;
138 break;
139 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000141 }
142 _lastPayloadType = rtpInfo.header.payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000143
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000144 bool newPayload = true;
145 ACMTestPayloadStats* currentPayloadStr = NULL;
146 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
147 if (rtpInfo.header.payloadType == _payloadStats[n].payloadType) {
148 newPayload = false;
149 currentPayloadStr = &_payloadStats[n];
150 break;
151 }
152 }
153
154 if (!newPayload) {
155 if (!currentPayloadStr->newPacket) {
156 uint32_t lastFrameSizeSample = (uint32_t)(
157 (uint32_t) rtpInfo.header.timestamp
158 - (uint32_t) currentPayloadStr->lastTimestamp);
159 assert(lastFrameSizeSample > 0);
160 int k = 0;
161 while ((currentPayloadStr->frameSizeStats[k].frameSizeSample
162 != lastFrameSizeSample)
163 && (currentPayloadStr->frameSizeStats[k].frameSizeSample != 0)) {
164 k++;
165 }
166 ACMTestFrameSizeStats* currentFrameSizeStats = &(currentPayloadStr
167 ->frameSizeStats[k]);
168 currentFrameSizeStats->frameSizeSample = (int16_t) lastFrameSizeSample;
169
170 // increment the number of encoded samples.
171 currentFrameSizeStats->totalEncodedSamples += lastFrameSizeSample;
172 // increment the number of recveived packets
173 currentFrameSizeStats->numPackets++;
174 // increment the total number of bytes (this is based on
175 // the previous payload we don't know the frame-size of
176 // the current payload.
177 currentFrameSizeStats->totalPayloadLenByte += currentPayloadStr
178 ->lastPayloadLenByte;
179 // store the maximum payload-size (this is based on
180 // the previous payload we don't know the frame-size of
181 // the current payload.
182 if (currentFrameSizeStats->maxPayloadLen
183 < currentPayloadStr->lastPayloadLenByte) {
184 currentFrameSizeStats->maxPayloadLen = currentPayloadStr
185 ->lastPayloadLenByte;
186 }
187 // store the current values for the next time
188 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
189 currentPayloadStr->lastPayloadLenByte = payloadSize;
190 } else {
191 currentPayloadStr->newPacket = false;
192 currentPayloadStr->lastPayloadLenByte = payloadSize;
193 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
194 currentPayloadStr->payloadType = rtpInfo.header.payloadType;
turaj@webrtc.org78f0db42014-02-19 23:07:31 +0000195 memset(currentPayloadStr->frameSizeStats, 0, MAX_NUM_FRAMESIZES *
196 sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000197 }
198 } else {
199 n = 0;
200 while (_payloadStats[n].payloadType != -1) {
201 n++;
202 }
203 // first packet
204 _payloadStats[n].newPacket = false;
205 _payloadStats[n].lastPayloadLenByte = payloadSize;
206 _payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
207 _payloadStats[n].payloadType = rtpInfo.header.payloadType;
turaj@webrtc.org78f0db42014-02-19 23:07:31 +0000208 memset(_payloadStats[n].frameSizeStats, 0, MAX_NUM_FRAMESIZES *
209 sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000210 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000211}
212
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000213Channel::Channel(int16_t chID)
214 : _receiverACM(NULL),
215 _seqNo(0),
216 _channelCritSect(CriticalSectionWrapper::CreateCriticalSection()),
217 _bitStreamFile(NULL),
218 _saveBitStream(false),
219 _lastPayloadType(-1),
220 _isStereo(false),
221 _leftChannel(true),
222 _lastInTimestamp(0),
223 _packetLoss(0),
224 _useFECTestWithPacketLoss(false),
225 _beginTime(TickTime::MillisecondTimestamp()),
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000226 _totalBytes(0),
227 external_send_timestamp_(-1),
228 external_sequence_number_(-1),
229 num_packets_to_drop_(0) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000230 int n;
231 int k;
232 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
233 _payloadStats[n].payloadType = -1;
234 _payloadStats[n].newPacket = true;
235 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
236 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
237 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
238 _payloadStats[n].frameSizeStats[k].numPackets = 0;
239 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
240 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
241 }
242 }
243 if (chID >= 0) {
244 _saveBitStream = true;
245 char bitStreamFileName[500];
246 sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
247 _bitStreamFile = fopen(bitStreamFileName, "wb");
248 } else {
249 _saveBitStream = false;
250 }
251}
252
253Channel::~Channel() {
254 delete _channelCritSect;
255}
256
257void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
258 _receiverACM = acm;
259 return;
260}
261
262void Channel::ResetStats() {
263 int n;
264 int k;
265 _channelCritSect->Enter();
266 _lastPayloadType = -1;
267 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
268 _payloadStats[n].payloadType = -1;
269 _payloadStats[n].newPacket = true;
270 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
271 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
272 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
273 _payloadStats[n].frameSizeStats[k].numPackets = 0;
274 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
275 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
276 }
277 }
278 _beginTime = TickTime::MillisecondTimestamp();
279 _totalBytes = 0;
280 _channelCritSect->Leave();
281}
282
283int16_t Channel::Stats(CodecInst& codecInst,
284 ACMTestPayloadStats& payloadStats) {
285 _channelCritSect->Enter();
286 int n;
287 payloadStats.payloadType = -1;
288 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
289 if (_payloadStats[n].payloadType == codecInst.pltype) {
290 memcpy(&payloadStats, &_payloadStats[n], sizeof(ACMTestPayloadStats));
291 break;
292 }
293 }
294 if (payloadStats.payloadType == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 _channelCritSect->Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000296 return -1;
297 }
298 for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
299 if (payloadStats.frameSizeStats[n].frameSizeSample == 0) {
300 _channelCritSect->Leave();
301 return 0;
302 }
303 payloadStats.frameSizeStats[n].usageLenSec = (double) payloadStats
304 .frameSizeStats[n].totalEncodedSamples / (double) codecInst.plfreq;
305
306 payloadStats.frameSizeStats[n].rateBitPerSec =
307 payloadStats.frameSizeStats[n].totalPayloadLenByte * 8
308 / payloadStats.frameSizeStats[n].usageLenSec;
309
310 }
311 _channelCritSect->Leave();
312 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000313}
314
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000315void Channel::Stats(uint32_t* numPackets) {
316 _channelCritSect->Enter();
317 int k;
318 int n;
319 memset(numPackets, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
320 for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
321 if (_payloadStats[k].payloadType == -1) {
322 break;
323 }
324 numPackets[k] = 0;
325 for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
326 if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
327 break;
328 }
329 numPackets[k] += _payloadStats[k].frameSizeStats[n].numPackets;
330 }
331 }
332 _channelCritSect->Leave();
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000333}
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000334
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000335void Channel::Stats(uint8_t* payloadType, uint32_t* payloadLenByte) {
336 _channelCritSect->Enter();
337
338 int k;
339 int n;
340 memset(payloadLenByte, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
341 for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
342 if (_payloadStats[k].payloadType == -1) {
343 break;
344 }
345 payloadType[k] = (uint8_t) _payloadStats[k].payloadType;
346 payloadLenByte[k] = 0;
347 for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
348 if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
349 break;
350 }
351 payloadLenByte[k] += (uint16_t) _payloadStats[k].frameSizeStats[n]
352 .totalPayloadLenByte;
353 }
354 }
355
356 _channelCritSect->Leave();
357}
358
359void Channel::PrintStats(CodecInst& codecInst) {
360 ACMTestPayloadStats payloadStats;
361 Stats(codecInst, payloadStats);
362 printf("%s %d kHz\n", codecInst.plname, codecInst.plfreq / 1000);
363 printf("=====================================================\n");
364 if (payloadStats.payloadType == -1) {
365 printf("No Packets are sent with payload-type %d (%s)\n\n",
366 codecInst.pltype, codecInst.plname);
367 return;
368 }
369 for (int k = 0; k < MAX_NUM_FRAMESIZES; k++) {
370 if (payloadStats.frameSizeStats[k].frameSizeSample == 0) {
371 break;
372 }
373 printf("Frame-size.................... %d samples\n",
374 payloadStats.frameSizeStats[k].frameSizeSample);
375 printf("Average Rate.................. %.0f bits/sec\n",
376 payloadStats.frameSizeStats[k].rateBitPerSec);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000377 printf("Maximum Payload-Size.......... %" PRIuS " Bytes\n",
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000378 payloadStats.frameSizeStats[k].maxPayloadLen);
379 printf(
380 "Maximum Instantaneous Rate.... %.0f bits/sec\n",
381 ((double) payloadStats.frameSizeStats[k].maxPayloadLen * 8.0
382 * (double) codecInst.plfreq)
383 / (double) payloadStats.frameSizeStats[k].frameSizeSample);
384 printf("Number of Packets............. %u\n",
385 (unsigned int) payloadStats.frameSizeStats[k].numPackets);
386 printf("Duration...................... %0.3f sec\n\n",
387 payloadStats.frameSizeStats[k].usageLenSec);
388
389 }
390
391}
392
393uint32_t Channel::LastInTimestamp() {
394 uint32_t timestamp;
395 _channelCritSect->Enter();
396 timestamp = _lastInTimestamp;
397 _channelCritSect->Leave();
398 return timestamp;
399}
400
401double Channel::BitRate() {
402 double rate;
403 uint64_t currTime = TickTime::MillisecondTimestamp();
404 _channelCritSect->Enter();
405 rate = ((double) _totalBytes * 8.0) / (double) (currTime - _beginTime);
406 _channelCritSect->Leave();
407 return rate;
408}
409
410} // namespace webrtc