blob: d7e387aca719e198f13625c90b676ff8191bb058 [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
11#include <assert.h>
12#include <iostream>
13
14#include "audio_coding_module.h"
15#include "Channel.h"
16#include "tick_util.h"
17#include "typedefs.h"
18#include "common_types.h"
19
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000020namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000021
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +000022WebRtc_Word32
niklase@google.com470e71d2011-07-07 08:21:25 +000023Channel::SendData(
24 const FrameType frameType,
25 const WebRtc_UWord8 payloadType,
26 const WebRtc_UWord32 timeStamp,
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +000027 const WebRtc_UWord8* payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +000028 const WebRtc_UWord16 payloadSize,
29 const RTPFragmentationHeader* fragmentation)
30{
31 WebRtcRTPHeader rtpInfo;
32 WebRtc_Word32 status;
33 WebRtc_UWord16 payloadDataSize = payloadSize;
34
35 rtpInfo.header.markerBit = false;
36 rtpInfo.header.ssrc = 0;
37 rtpInfo.header.sequenceNumber = _seqNo++;
38 rtpInfo.header.payloadType = payloadType;
39 rtpInfo.header.timestamp = timeStamp;
40 if(frameType == kAudioFrameCN)
41 {
42 rtpInfo.type.Audio.isCNG = true;
43 }
44 else
45 {
46 rtpInfo.type.Audio.isCNG = false;
47 }
48 if(frameType == kFrameEmpty)
49 {
50 // Skip this frame
51 return 0;
52 }
53
54 rtpInfo.type.Audio.channel = 1;
55 // Treat fragmentation separately
56 if(fragmentation != NULL)
57 {
58 if((fragmentation->fragmentationTimeDiff[1] <= 0x3fff) && // silence for too long send only new data
59 (fragmentation->fragmentationVectorSize == 2))
60 {
61 // only 0x80 if we have multiple blocks
62 _payloadData[0] = 0x80 + fragmentation->fragmentationPlType[1];
63 WebRtc_UWord32 REDheader = (((WebRtc_UWord32)fragmentation->fragmentationTimeDiff[1]) << 10) + fragmentation->fragmentationLength[1];
64 _payloadData[1] = WebRtc_UWord8((REDheader >> 16) & 0x000000FF);
65 _payloadData[2] = WebRtc_UWord8((REDheader >> 8) & 0x000000FF);
66 _payloadData[3] = WebRtc_UWord8(REDheader & 0x000000FF);
67
68 _payloadData[4] = fragmentation->fragmentationPlType[0];
69 // copy the RED data
70 memcpy(_payloadData + 5,
71 payloadData + fragmentation->fragmentationOffset[1],
72 fragmentation->fragmentationLength[1]);
73 // copy the normal data
74 memcpy(_payloadData + 5 + fragmentation->fragmentationLength[1],
75 payloadData + fragmentation->fragmentationOffset[0],
76 fragmentation->fragmentationLength[0]);
77 payloadDataSize += 5;
78 } else
79 {
80 // single block (newest one)
81 memcpy(_payloadData,
82 payloadData + fragmentation->fragmentationOffset[0],
83 fragmentation->fragmentationLength[0]);
84 payloadDataSize = WebRtc_UWord16(fragmentation->fragmentationLength[0]);
85 rtpInfo.header.payloadType = fragmentation->fragmentationPlType[0];
86 }
87 }
88 else
89 {
90 memcpy(_payloadData, payloadData, payloadDataSize);
91 if(_isStereo)
92 {
93 if(_leftChannel)
94 {
95 memcpy(&_rtpInfo, &rtpInfo, sizeof(WebRtcRTPHeader));
96 _leftChannel = false;
97 rtpInfo.type.Audio.channel = 1;
98 }
99 else
100 {
101 memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcRTPHeader));
102 _leftChannel = true;
103 rtpInfo.type.Audio.channel = 2;
104 }
105 }
106 }
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000107
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 _channelCritSect->Enter();
109 if(_saveBitStream)
110 {
111 //fwrite(payloadData, sizeof(WebRtc_UWord8), payloadSize, _bitStreamFile);
112 }
113
114 if(!_isStereo)
115 {
116 CalcStatistics(rtpInfo, payloadSize);
117 }
118 _lastInTimestamp = timeStamp;
119 _totalBytes += payloadDataSize;
120 _channelCritSect->Leave();
121
122 if(_useFECTestWithPacketLoss)
123 {
124 _packetLoss += 1;
125 if(_packetLoss == 3)
126 {
127 _packetLoss = 0;
128 return 0;
129 }
130 }
131
tina.legrand@webrtc.org16b6b902012-04-12 11:02:38 +0000132 status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize,
133 rtpInfo);
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
135 return status;
136}
137
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000138void
niklase@google.com470e71d2011-07-07 08:21:25 +0000139Channel::CalcStatistics(
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000140 WebRtcRTPHeader& rtpInfo,
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 WebRtc_UWord16 payloadSize)
142{
143 int n;
144 if((rtpInfo.header.payloadType != _lastPayloadType) &&
145 (_lastPayloadType != -1))
146 {
147 // payload-type is changed.
148 // we have to terminate the calculations on the previous payload type
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000149 // we ignore the last packet in that payload type just to make things
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 // easier.
151 for(n = 0; n < MAX_NUM_PAYLOADS; n++)
152 {
153 if(_lastPayloadType == _payloadStats[n].payloadType)
154 {
155 _payloadStats[n].newPacket = true;
156 break;
157 }
158 }
159 }
160 _lastPayloadType = rtpInfo.header.payloadType;
161
162 bool newPayload = true;
163 ACMTestPayloadStats* currentPayloadStr;
164 for(n = 0; n < MAX_NUM_PAYLOADS; n++)
165 {
166 if(rtpInfo.header.payloadType == _payloadStats[n].payloadType)
167 {
168 newPayload = false;
169 currentPayloadStr = &_payloadStats[n];
170 break;
171 }
172 }
173
174 if(!newPayload)
175 {
176 if(!currentPayloadStr->newPacket)
177 {
178 WebRtc_UWord32 lastFrameSizeSample = (WebRtc_UWord32)((WebRtc_UWord32)rtpInfo.header.timestamp -
179 (WebRtc_UWord32)currentPayloadStr->lastTimestamp);
180 assert(lastFrameSizeSample > 0);
181 int k = 0;
182 while((currentPayloadStr->frameSizeStats[k].frameSizeSample !=
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000183 lastFrameSizeSample) &&
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 (currentPayloadStr->frameSizeStats[k].frameSizeSample != 0))
185 {
186 k++;
187 }
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000188 ACMTestFrameSizeStats* currentFrameSizeStats =
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 &(currentPayloadStr->frameSizeStats[k]);
190 currentFrameSizeStats->frameSizeSample = (WebRtc_Word16)lastFrameSizeSample;
191
192 // increment the number of encoded samples.
193 currentFrameSizeStats->totalEncodedSamples +=
194 lastFrameSizeSample;
195 // increment the number of recveived packets
196 currentFrameSizeStats->numPackets++;
197 // increment the total number of bytes (this is based on
198 // the previous payload we don't know the frame-size of
199 // the current payload.
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000200 currentFrameSizeStats->totalPayloadLenByte +=
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 currentPayloadStr->lastPayloadLenByte;
202 // store the maximum payload-size (this is based on
203 // the previous payload we don't know the frame-size of
204 // the current payload.
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000205 if(currentFrameSizeStats->maxPayloadLen <
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 currentPayloadStr->lastPayloadLenByte)
207 {
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000208 currentFrameSizeStats->maxPayloadLen =
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 currentPayloadStr->lastPayloadLenByte;
210 }
211 // store the current values for the next time
212 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
213 currentPayloadStr->lastPayloadLenByte = payloadSize;
214 }
215 else
216 {
217 currentPayloadStr->newPacket = false;
218 currentPayloadStr->lastPayloadLenByte = payloadSize;
219 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
220 currentPayloadStr->payloadType = rtpInfo.header.payloadType;
221 }
222 }
223 else
224 {
225 n = 0;
226 while(_payloadStats[n].payloadType != -1)
227 {
228 n++;
229 }
230 // first packet
231 _payloadStats[n].newPacket = false;
232 _payloadStats[n].lastPayloadLenByte = payloadSize;
233 _payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
234 _payloadStats[n].payloadType = rtpInfo.header.payloadType;
235 }
236}
237
238Channel::Channel(WebRtc_Word16 chID) :
239_receiverACM(NULL),
240_seqNo(0),
241_channelCritSect(CriticalSectionWrapper::CreateCriticalSection()),
242_bitStreamFile(NULL),
243_saveBitStream(false),
244_lastPayloadType(-1),
245_isStereo(false),
246_leftChannel(true),
niklase@google.com470e71d2011-07-07 08:21:25 +0000247_lastInTimestamp(0),
tina.legrand@webrtc.org2e096922011-08-18 06:20:30 +0000248_packetLoss(0),
249_useFECTestWithPacketLoss(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000250_beginTime(TickTime::MillisecondTimestamp()),
251_totalBytes(0)
252{
253 int n;
254 int k;
255 for(n = 0; n < MAX_NUM_PAYLOADS; n++)
256 {
257 _payloadStats[n].payloadType = -1;
258 _payloadStats[n].newPacket = true;
259 for(k = 0; k < MAX_NUM_FRAMESIZES; k++)
260 {
261 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
262 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
263 _payloadStats[n].frameSizeStats[k].numPackets = 0;
264 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
265 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
266 }
267 }
268 if(chID >= 0)
269 {
270 _saveBitStream = true;
271 char bitStreamFileName[500];
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000272 sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 _bitStreamFile = fopen(bitStreamFileName, "wb");
274 }
275 else
276 {
277 _saveBitStream = false;
278 }
279}
280
281Channel::~Channel()
282{
283 delete _channelCritSect;
284}
285
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000286void
niklase@google.com470e71d2011-07-07 08:21:25 +0000287Channel::RegisterReceiverACM(AudioCodingModule* acm)
288{
289 _receiverACM = acm;
290 return;
291}
292
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000293void
niklase@google.com470e71d2011-07-07 08:21:25 +0000294Channel::ResetStats()
295{
296 int n;
297 int k;
298 _channelCritSect->Enter();
299 _lastPayloadType = -1;
300 for(n = 0; n < MAX_NUM_PAYLOADS; n++)
301 {
302 _payloadStats[n].payloadType = -1;
303 _payloadStats[n].newPacket = true;
304 for(k = 0; k < MAX_NUM_FRAMESIZES; k++)
305 {
306 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
307 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
308 _payloadStats[n].frameSizeStats[k].numPackets = 0;
309 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
310 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
311 }
312 }
313 _beginTime = TickTime::MillisecondTimestamp();
314 _totalBytes = 0;
315 _channelCritSect->Leave();
316}
317
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000318WebRtc_Word16
niklase@google.com470e71d2011-07-07 08:21:25 +0000319Channel::Stats(CodecInst& codecInst, ACMTestPayloadStats& payloadStats)
320{
321 _channelCritSect->Enter();
322 int n;
323 payloadStats.payloadType = -1;
324 for(n = 0; n < MAX_NUM_PAYLOADS; n++)
325 {
326 if(_payloadStats[n].payloadType == codecInst.pltype)
327 {
328 memcpy(&payloadStats, &_payloadStats[n], sizeof(ACMTestPayloadStats));
329 break;
330 }
331 }
332 if(payloadStats.payloadType == -1)
333 {
334 _channelCritSect->Leave();
335 return -1;
336 }
337 for(n = 0; n < MAX_NUM_FRAMESIZES; n++)
338 {
339 if(payloadStats.frameSizeStats[n].frameSizeSample == 0)
340 {
341 _channelCritSect->Leave();
342 return 0;
343 }
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000344 payloadStats.frameSizeStats[n].usageLenSec =
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 (double)payloadStats.frameSizeStats[n].totalEncodedSamples
346 / (double)codecInst.plfreq;
347
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000348 payloadStats.frameSizeStats[n].rateBitPerSec =
349 payloadStats.frameSizeStats[n].totalPayloadLenByte * 8 /
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 payloadStats.frameSizeStats[n].usageLenSec;
351
352 }
353 _channelCritSect->Leave();
354 return 0;
355}
356
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000357void
niklase@google.com470e71d2011-07-07 08:21:25 +0000358Channel::Stats(WebRtc_UWord32* numPackets)
359{
360 _channelCritSect->Enter();
361 int k;
362 int n;
363 memset(numPackets, 0, MAX_NUM_PAYLOADS * sizeof(WebRtc_UWord32));
364 for(k = 0; k < MAX_NUM_PAYLOADS; k++)
365 {
366 if(_payloadStats[k].payloadType == -1)
367 {
368 break;
369 }
370 numPackets[k] = 0;
371 for(n = 0; n < MAX_NUM_FRAMESIZES; n++)
372 {
373 if(_payloadStats[k].frameSizeStats[n].frameSizeSample == 0)
374 {
375 break;
376 }
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000377 numPackets[k] +=
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 _payloadStats[k].frameSizeStats[n].numPackets;
379 }
380 }
381 _channelCritSect->Leave();
382}
383
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000384void
niklase@google.com470e71d2011-07-07 08:21:25 +0000385Channel::Stats(WebRtc_UWord8* payloadType, WebRtc_UWord32* payloadLenByte)
386{
387 _channelCritSect->Enter();
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000388
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 int k;
390 int n;
391 memset(payloadLenByte, 0, MAX_NUM_PAYLOADS * sizeof(WebRtc_UWord32));
392 for(k = 0; k < MAX_NUM_PAYLOADS; k++)
393 {
394 if(_payloadStats[k].payloadType == -1)
395 {
396 break;
397 }
398 payloadType[k] = (WebRtc_UWord8)_payloadStats[k].payloadType;
399 payloadLenByte[k] = 0;
400 for(n = 0; n < MAX_NUM_FRAMESIZES; n++)
401 {
402 if(_payloadStats[k].frameSizeStats[n].frameSizeSample == 0)
403 {
404 break;
405 }
406 payloadLenByte[k] += (WebRtc_UWord16)
407 _payloadStats[k].frameSizeStats[n].totalPayloadLenByte;
408 }
409 }
410
411 _channelCritSect->Leave();
412}
413
414
415void
416Channel::PrintStats(CodecInst& codecInst)
417{
418 ACMTestPayloadStats payloadStats;
419 Stats(codecInst, payloadStats);
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000420 printf("%s %d kHz\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 codecInst.plname,
422 codecInst.plfreq / 1000);
423 printf("=====================================================\n");
424 if(payloadStats.payloadType == -1)
425 {
426 printf("No Packets are sent with payload-type %d (%s)\n\n",
427 codecInst.pltype,
428 codecInst.plname);
429 return;
430 }
431 for(int k = 0; k < MAX_NUM_FRAMESIZES; k++)
432 {
433 if(payloadStats.frameSizeStats[k].frameSizeSample == 0)
434 {
435 break;
436 }
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000437 printf("Frame-size.................... %d samples\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 payloadStats.frameSizeStats[k].frameSizeSample);
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000439 printf("Average Rate.................. %.0f bits/sec\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000440 payloadStats.frameSizeStats[k].rateBitPerSec);
441 printf("Maximum Payload-Size.......... %d Bytes\n",
442 payloadStats.frameSizeStats[k].maxPayloadLen);
443 printf("Maximum Instantaneous Rate.... %.0f bits/sec\n",
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000444 ((double)payloadStats.frameSizeStats[k].maxPayloadLen * 8.0 *
445 (double)codecInst.plfreq) /
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 (double)payloadStats.frameSizeStats[k].frameSizeSample);
447 printf("Number of Packets............. %u\n",
448 (unsigned int)payloadStats.frameSizeStats[k].numPackets);
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000449 printf("Duration...................... %0.3f sec\n\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000450 payloadStats.frameSizeStats[k].usageLenSec);
451
452 }
453
454}
455
456WebRtc_UWord32
457Channel::LastInTimestamp()
458{
459 WebRtc_UWord32 timestamp;
460 _channelCritSect->Enter();
461 timestamp = _lastInTimestamp;
462 _channelCritSect->Leave();
463 return timestamp;
464}
465
466double
467Channel::BitRate()
468{
469 double rate;
470 WebRtc_UWord64 currTime = TickTime::MillisecondTimestamp();
471 _channelCritSect->Enter();
472 rate = ((double)_totalBytes * 8.0)/ (double)(currTime - _beginTime);
473 _channelCritSect->Leave();
474 return rate;
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000475}
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000476
477} // namespace webrtc