blob: 46c398b1b758617f05305bd19e5d92b392f82573 [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
kjellander3e6db232015-11-26 04:44:54 -080011#include "webrtc/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
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000016#include "webrtc/base/format_macros.h"
Niels Möllerd28db7f2016-05-10 16:31:47 +020017#include "webrtc/base/timeutils.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;
turaj@webrtc.orga305e962013-06-06 19:00:09 +000033 rtpInfo.header.sequenceNumber = (external_sequence_number_ < 0) ?
34 _seqNo++ : static_cast<uint16_t>(external_sequence_number_);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000035 rtpInfo.header.payloadType = payloadType;
turaj@webrtc.orga305e962013-06-06 19:00:09 +000036 rtpInfo.header.timestamp = (external_send_timestamp_ < 0) ? timeStamp :
37 static_cast<uint32_t>(external_send_timestamp_);
38
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000039 if (frameType == kAudioFrameCN) {
40 rtpInfo.type.Audio.isCNG = true;
41 } else {
42 rtpInfo.type.Audio.isCNG = false;
43 }
pbos22993e12015-10-19 02:39:06 -070044 if (frameType == kEmptyFrame) {
minyue@webrtc.org05617162015-03-03 12:02:30 +000045 // When frame is empty, we should not transmit it. The frame size of the
46 // next non-empty frame will be based on the previous frame size.
47 _useLastFrameSize = _lastFrameSizeSample > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000048 return 0;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000049 }
niklase@google.com470e71d2011-07-07 08:21:25 +000050
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000051 rtpInfo.type.Audio.channel = 1;
52 // Treat fragmentation separately
53 if (fragmentation != NULL) {
54 // If silence for too long, send only new data.
henrik.lundin@webrtc.org05db3522015-01-30 13:03:45 +000055 if ((fragmentation->fragmentationVectorSize == 2) &&
56 (fragmentation->fragmentationTimeDiff[1] <= 0x3fff)) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000057 // only 0x80 if we have multiple blocks
58 _payloadData[0] = 0x80 + fragmentation->fragmentationPlType[1];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000059 size_t REDheader = (fragmentation->fragmentationTimeDiff[1] << 10) +
60 fragmentation->fragmentationLength[1];
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000061 _payloadData[1] = uint8_t((REDheader >> 16) & 0x000000FF);
62 _payloadData[2] = uint8_t((REDheader >> 8) & 0x000000FF);
63 _payloadData[3] = uint8_t(REDheader & 0x000000FF);
64
65 _payloadData[4] = fragmentation->fragmentationPlType[0];
66 // copy the RED data
67 memcpy(_payloadData + 5,
68 payloadData + fragmentation->fragmentationOffset[1],
69 fragmentation->fragmentationLength[1]);
70 // copy the normal data
71 memcpy(_payloadData + 5 + fragmentation->fragmentationLength[1],
72 payloadData + fragmentation->fragmentationOffset[0],
73 fragmentation->fragmentationLength[0]);
74 payloadDataSize += 5;
75 } else {
76 // single block (newest one)
77 memcpy(_payloadData, payloadData + fragmentation->fragmentationOffset[0],
78 fragmentation->fragmentationLength[0]);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000079 payloadDataSize = fragmentation->fragmentationLength[0];
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000080 rtpInfo.header.payloadType = fragmentation->fragmentationPlType[0];
niklase@google.com470e71d2011-07-07 08:21:25 +000081 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000082 } else {
83 memcpy(_payloadData, payloadData, payloadDataSize);
84 if (_isStereo) {
85 if (_leftChannel) {
86 memcpy(&_rtpInfo, &rtpInfo, sizeof(WebRtcRTPHeader));
87 _leftChannel = false;
88 rtpInfo.type.Audio.channel = 1;
89 } else {
90 memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcRTPHeader));
91 _leftChannel = true;
92 rtpInfo.type.Audio.channel = 2;
93 }
niklase@google.com470e71d2011-07-07 08:21:25 +000094 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000095 }
niklase@google.com470e71d2011-07-07 08:21:25 +000096
Tommi9090e0b2016-01-20 13:39:36 +010097 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000098 if (_saveBitStream) {
99 //fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
100 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000102 if (!_isStereo) {
103 CalcStatistics(rtpInfo, payloadSize);
104 }
minyue@webrtc.org05617162015-03-03 12:02:30 +0000105 _useLastFrameSize = false;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000106 _lastInTimestamp = timeStamp;
107 _totalBytes += payloadDataSize;
Tommi9090e0b2016-01-20 13:39:36 +0100108 _channelCritSect.Leave();
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000110 if (_useFECTestWithPacketLoss) {
111 _packetLoss += 1;
112 if (_packetLoss == 3) {
113 _packetLoss = 0;
114 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000115 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000116 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000117
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000118 if (num_packets_to_drop_ > 0) {
119 num_packets_to_drop_--;
120 return 0;
121 }
122
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000123 status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtpInfo);
124
125 return status;
126}
127
turaj@webrtc.orgc2d69d32014-02-19 20:31:17 +0000128// TODO(turajs): rewite this method.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000129void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000130 int n;
131 if ((rtpInfo.header.payloadType != _lastPayloadType)
132 && (_lastPayloadType != -1)) {
133 // payload-type is changed.
134 // we have to terminate the calculations on the previous payload type
135 // we ignore the last packet in that payload type just to make things
136 // easier.
137 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
138 if (_lastPayloadType == _payloadStats[n].payloadType) {
139 _payloadStats[n].newPacket = true;
140 break;
141 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000142 }
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000143 }
144 _lastPayloadType = rtpInfo.header.payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000145
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000146 bool newPayload = true;
147 ACMTestPayloadStats* currentPayloadStr = NULL;
148 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
149 if (rtpInfo.header.payloadType == _payloadStats[n].payloadType) {
150 newPayload = false;
151 currentPayloadStr = &_payloadStats[n];
152 break;
153 }
154 }
155
156 if (!newPayload) {
157 if (!currentPayloadStr->newPacket) {
minyue@webrtc.org05617162015-03-03 12:02:30 +0000158 if (!_useLastFrameSize) {
159 _lastFrameSizeSample = (uint32_t) ((uint32_t) rtpInfo.header.timestamp -
160 (uint32_t) currentPayloadStr->lastTimestamp);
161 }
162 assert(_lastFrameSizeSample > 0);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000163 int k = 0;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000164 for (; k < MAX_NUM_FRAMESIZES; ++k) {
165 if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
166 _lastFrameSizeSample) ||
167 (currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
168 break;
169 }
170 }
171 if (k == MAX_NUM_FRAMESIZES) {
172 // New frame size found but no space to count statistics on it. Skip it.
173 printf("No memory to store statistics for payload %d : frame size %d\n",
174 _lastPayloadType, _lastFrameSizeSample);
175 return;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000176 }
177 ACMTestFrameSizeStats* currentFrameSizeStats = &(currentPayloadStr
178 ->frameSizeStats[k]);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000179 currentFrameSizeStats->frameSizeSample = (int16_t) _lastFrameSizeSample;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000180
181 // increment the number of encoded samples.
minyue@webrtc.org05617162015-03-03 12:02:30 +0000182 currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000183 // increment the number of recveived packets
184 currentFrameSizeStats->numPackets++;
185 // increment the total number of bytes (this is based on
186 // the previous payload we don't know the frame-size of
187 // the current payload.
188 currentFrameSizeStats->totalPayloadLenByte += currentPayloadStr
189 ->lastPayloadLenByte;
190 // store the maximum payload-size (this is based on
191 // the previous payload we don't know the frame-size of
192 // the current payload.
193 if (currentFrameSizeStats->maxPayloadLen
194 < currentPayloadStr->lastPayloadLenByte) {
195 currentFrameSizeStats->maxPayloadLen = currentPayloadStr
196 ->lastPayloadLenByte;
197 }
198 // store the current values for the next time
199 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
200 currentPayloadStr->lastPayloadLenByte = payloadSize;
201 } else {
202 currentPayloadStr->newPacket = false;
203 currentPayloadStr->lastPayloadLenByte = payloadSize;
204 currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
205 currentPayloadStr->payloadType = rtpInfo.header.payloadType;
turaj@webrtc.org78f0db42014-02-19 23:07:31 +0000206 memset(currentPayloadStr->frameSizeStats, 0, MAX_NUM_FRAMESIZES *
207 sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000208 }
209 } else {
210 n = 0;
211 while (_payloadStats[n].payloadType != -1) {
212 n++;
213 }
214 // first packet
215 _payloadStats[n].newPacket = false;
216 _payloadStats[n].lastPayloadLenByte = payloadSize;
217 _payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
218 _payloadStats[n].payloadType = rtpInfo.header.payloadType;
turaj@webrtc.org78f0db42014-02-19 23:07:31 +0000219 memset(_payloadStats[n].frameSizeStats, 0, MAX_NUM_FRAMESIZES *
220 sizeof(ACMTestFrameSizeStats));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000221 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000222}
223
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000224Channel::Channel(int16_t chID)
225 : _receiverACM(NULL),
226 _seqNo(0),
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000227 _bitStreamFile(NULL),
228 _saveBitStream(false),
229 _lastPayloadType(-1),
230 _isStereo(false),
231 _leftChannel(true),
232 _lastInTimestamp(0),
minyue@webrtc.org05617162015-03-03 12:02:30 +0000233 _useLastFrameSize(false),
234 _lastFrameSizeSample(0),
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000235 _packetLoss(0),
236 _useFECTestWithPacketLoss(false),
Niels Möllerd28db7f2016-05-10 16:31:47 +0200237 _beginTime(rtc::TimeMillis()),
turaj@webrtc.orga305e962013-06-06 19:00:09 +0000238 _totalBytes(0),
239 external_send_timestamp_(-1),
240 external_sequence_number_(-1),
241 num_packets_to_drop_(0) {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000242 int n;
243 int k;
244 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
245 _payloadStats[n].payloadType = -1;
246 _payloadStats[n].newPacket = true;
247 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
248 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
249 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
250 _payloadStats[n].frameSizeStats[k].numPackets = 0;
251 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
252 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
253 }
254 }
255 if (chID >= 0) {
256 _saveBitStream = true;
257 char bitStreamFileName[500];
258 sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
259 _bitStreamFile = fopen(bitStreamFileName, "wb");
260 } else {
261 _saveBitStream = false;
262 }
263}
264
265Channel::~Channel() {
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000266}
267
268void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
269 _receiverACM = acm;
270 return;
271}
272
273void Channel::ResetStats() {
274 int n;
275 int k;
Tommi9090e0b2016-01-20 13:39:36 +0100276 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000277 _lastPayloadType = -1;
278 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
279 _payloadStats[n].payloadType = -1;
280 _payloadStats[n].newPacket = true;
281 for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
282 _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
283 _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
284 _payloadStats[n].frameSizeStats[k].numPackets = 0;
285 _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
286 _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
287 }
288 }
Niels Möllerd28db7f2016-05-10 16:31:47 +0200289 _beginTime = rtc::TimeMillis();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000290 _totalBytes = 0;
Tommi9090e0b2016-01-20 13:39:36 +0100291 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000292}
293
294int16_t Channel::Stats(CodecInst& codecInst,
295 ACMTestPayloadStats& payloadStats) {
Tommi9090e0b2016-01-20 13:39:36 +0100296 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000297 int n;
298 payloadStats.payloadType = -1;
299 for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
300 if (_payloadStats[n].payloadType == codecInst.pltype) {
301 memcpy(&payloadStats, &_payloadStats[n], sizeof(ACMTestPayloadStats));
302 break;
303 }
304 }
305 if (payloadStats.payloadType == -1) {
Tommi9090e0b2016-01-20 13:39:36 +0100306 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000307 return -1;
308 }
309 for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
310 if (payloadStats.frameSizeStats[n].frameSizeSample == 0) {
Tommi9090e0b2016-01-20 13:39:36 +0100311 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000312 return 0;
313 }
314 payloadStats.frameSizeStats[n].usageLenSec = (double) payloadStats
315 .frameSizeStats[n].totalEncodedSamples / (double) codecInst.plfreq;
316
317 payloadStats.frameSizeStats[n].rateBitPerSec =
318 payloadStats.frameSizeStats[n].totalPayloadLenByte * 8
319 / payloadStats.frameSizeStats[n].usageLenSec;
320
321 }
Tommi9090e0b2016-01-20 13:39:36 +0100322 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000323 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000324}
325
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000326void Channel::Stats(uint32_t* numPackets) {
Tommi9090e0b2016-01-20 13:39:36 +0100327 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000328 int k;
329 int n;
330 memset(numPackets, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
331 for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
332 if (_payloadStats[k].payloadType == -1) {
333 break;
334 }
335 numPackets[k] = 0;
336 for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
337 if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
338 break;
339 }
340 numPackets[k] += _payloadStats[k].frameSizeStats[n].numPackets;
341 }
342 }
Tommi9090e0b2016-01-20 13:39:36 +0100343 _channelCritSect.Leave();
andrew@webrtc.orgd7a71d02012-08-01 01:40:02 +0000344}
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000345
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000346void Channel::Stats(uint8_t* payloadType, uint32_t* payloadLenByte) {
Tommi9090e0b2016-01-20 13:39:36 +0100347 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000348
349 int k;
350 int n;
351 memset(payloadLenByte, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
352 for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
353 if (_payloadStats[k].payloadType == -1) {
354 break;
355 }
356 payloadType[k] = (uint8_t) _payloadStats[k].payloadType;
357 payloadLenByte[k] = 0;
358 for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
359 if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
360 break;
361 }
362 payloadLenByte[k] += (uint16_t) _payloadStats[k].frameSizeStats[n]
363 .totalPayloadLenByte;
364 }
365 }
366
Tommi9090e0b2016-01-20 13:39:36 +0100367 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000368}
369
370void Channel::PrintStats(CodecInst& codecInst) {
371 ACMTestPayloadStats payloadStats;
372 Stats(codecInst, payloadStats);
373 printf("%s %d kHz\n", codecInst.plname, codecInst.plfreq / 1000);
374 printf("=====================================================\n");
375 if (payloadStats.payloadType == -1) {
376 printf("No Packets are sent with payload-type %d (%s)\n\n",
377 codecInst.pltype, codecInst.plname);
378 return;
379 }
380 for (int k = 0; k < MAX_NUM_FRAMESIZES; k++) {
381 if (payloadStats.frameSizeStats[k].frameSizeSample == 0) {
382 break;
383 }
384 printf("Frame-size.................... %d samples\n",
385 payloadStats.frameSizeStats[k].frameSizeSample);
386 printf("Average Rate.................. %.0f bits/sec\n",
387 payloadStats.frameSizeStats[k].rateBitPerSec);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000388 printf("Maximum Payload-Size.......... %" PRIuS " Bytes\n",
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000389 payloadStats.frameSizeStats[k].maxPayloadLen);
390 printf(
391 "Maximum Instantaneous Rate.... %.0f bits/sec\n",
392 ((double) payloadStats.frameSizeStats[k].maxPayloadLen * 8.0
393 * (double) codecInst.plfreq)
394 / (double) payloadStats.frameSizeStats[k].frameSizeSample);
395 printf("Number of Packets............. %u\n",
396 (unsigned int) payloadStats.frameSizeStats[k].numPackets);
397 printf("Duration...................... %0.3f sec\n\n",
398 payloadStats.frameSizeStats[k].usageLenSec);
399
400 }
401
402}
403
404uint32_t Channel::LastInTimestamp() {
405 uint32_t timestamp;
Tommi9090e0b2016-01-20 13:39:36 +0100406 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000407 timestamp = _lastInTimestamp;
Tommi9090e0b2016-01-20 13:39:36 +0100408 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000409 return timestamp;
410}
411
412double Channel::BitRate() {
413 double rate;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200414 uint64_t currTime = rtc::TimeMillis();
Tommi9090e0b2016-01-20 13:39:36 +0100415 _channelCritSect.Enter();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000416 rate = ((double) _totalBytes * 8.0) / (double) (currTime - _beginTime);
Tommi9090e0b2016-01-20 13:39:36 +0100417 _channelCritSect.Leave();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000418 return rate;
419}
420
421} // namespace webrtc