1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/test/Channel.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <iostream>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
16*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
17*d9f75844SAndroid Build Coastguard Worker
18*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
19*d9f75844SAndroid Build Coastguard Worker
SendData(AudioFrameType frameType,uint8_t payloadType,uint32_t timeStamp,const uint8_t * payloadData,size_t payloadSize,int64_t absolute_capture_timestamp_ms)20*d9f75844SAndroid Build Coastguard Worker int32_t Channel::SendData(AudioFrameType frameType,
21*d9f75844SAndroid Build Coastguard Worker uint8_t payloadType,
22*d9f75844SAndroid Build Coastguard Worker uint32_t timeStamp,
23*d9f75844SAndroid Build Coastguard Worker const uint8_t* payloadData,
24*d9f75844SAndroid Build Coastguard Worker size_t payloadSize,
25*d9f75844SAndroid Build Coastguard Worker int64_t absolute_capture_timestamp_ms) {
26*d9f75844SAndroid Build Coastguard Worker RTPHeader rtp_header;
27*d9f75844SAndroid Build Coastguard Worker int32_t status;
28*d9f75844SAndroid Build Coastguard Worker size_t payloadDataSize = payloadSize;
29*d9f75844SAndroid Build Coastguard Worker
30*d9f75844SAndroid Build Coastguard Worker rtp_header.markerBit = false;
31*d9f75844SAndroid Build Coastguard Worker rtp_header.ssrc = 0;
32*d9f75844SAndroid Build Coastguard Worker rtp_header.sequenceNumber =
33*d9f75844SAndroid Build Coastguard Worker (external_sequence_number_ < 0)
34*d9f75844SAndroid Build Coastguard Worker ? _seqNo++
35*d9f75844SAndroid Build Coastguard Worker : static_cast<uint16_t>(external_sequence_number_);
36*d9f75844SAndroid Build Coastguard Worker rtp_header.payloadType = payloadType;
37*d9f75844SAndroid Build Coastguard Worker rtp_header.timestamp = (external_send_timestamp_ < 0)
38*d9f75844SAndroid Build Coastguard Worker ? timeStamp
39*d9f75844SAndroid Build Coastguard Worker : static_cast<uint32_t>(external_send_timestamp_);
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker if (frameType == AudioFrameType::kEmptyFrame) {
42*d9f75844SAndroid Build Coastguard Worker // When frame is empty, we should not transmit it. The frame size of the
43*d9f75844SAndroid Build Coastguard Worker // next non-empty frame will be based on the previous frame size.
44*d9f75844SAndroid Build Coastguard Worker _useLastFrameSize = _lastFrameSizeSample > 0;
45*d9f75844SAndroid Build Coastguard Worker return 0;
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker
48*d9f75844SAndroid Build Coastguard Worker memcpy(_payloadData, payloadData, payloadDataSize);
49*d9f75844SAndroid Build Coastguard Worker if (_isStereo) {
50*d9f75844SAndroid Build Coastguard Worker if (_leftChannel) {
51*d9f75844SAndroid Build Coastguard Worker _rtp_header = rtp_header;
52*d9f75844SAndroid Build Coastguard Worker _leftChannel = false;
53*d9f75844SAndroid Build Coastguard Worker } else {
54*d9f75844SAndroid Build Coastguard Worker rtp_header = _rtp_header;
55*d9f75844SAndroid Build Coastguard Worker _leftChannel = true;
56*d9f75844SAndroid Build Coastguard Worker }
57*d9f75844SAndroid Build Coastguard Worker }
58*d9f75844SAndroid Build Coastguard Worker
59*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Lock();
60*d9f75844SAndroid Build Coastguard Worker if (_saveBitStream) {
61*d9f75844SAndroid Build Coastguard Worker // fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker
64*d9f75844SAndroid Build Coastguard Worker if (!_isStereo) {
65*d9f75844SAndroid Build Coastguard Worker CalcStatistics(rtp_header, payloadSize);
66*d9f75844SAndroid Build Coastguard Worker }
67*d9f75844SAndroid Build Coastguard Worker _useLastFrameSize = false;
68*d9f75844SAndroid Build Coastguard Worker _lastInTimestamp = timeStamp;
69*d9f75844SAndroid Build Coastguard Worker _totalBytes += payloadDataSize;
70*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Unlock();
71*d9f75844SAndroid Build Coastguard Worker
72*d9f75844SAndroid Build Coastguard Worker if (_useFECTestWithPacketLoss) {
73*d9f75844SAndroid Build Coastguard Worker _packetLoss += 1;
74*d9f75844SAndroid Build Coastguard Worker if (_packetLoss == 3) {
75*d9f75844SAndroid Build Coastguard Worker _packetLoss = 0;
76*d9f75844SAndroid Build Coastguard Worker return 0;
77*d9f75844SAndroid Build Coastguard Worker }
78*d9f75844SAndroid Build Coastguard Worker }
79*d9f75844SAndroid Build Coastguard Worker
80*d9f75844SAndroid Build Coastguard Worker if (num_packets_to_drop_ > 0) {
81*d9f75844SAndroid Build Coastguard Worker num_packets_to_drop_--;
82*d9f75844SAndroid Build Coastguard Worker return 0;
83*d9f75844SAndroid Build Coastguard Worker }
84*d9f75844SAndroid Build Coastguard Worker
85*d9f75844SAndroid Build Coastguard Worker status =
86*d9f75844SAndroid Build Coastguard Worker _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtp_header);
87*d9f75844SAndroid Build Coastguard Worker
88*d9f75844SAndroid Build Coastguard Worker return status;
89*d9f75844SAndroid Build Coastguard Worker }
90*d9f75844SAndroid Build Coastguard Worker
91*d9f75844SAndroid Build Coastguard Worker // TODO(turajs): rewite this method.
CalcStatistics(const RTPHeader & rtp_header,size_t payloadSize)92*d9f75844SAndroid Build Coastguard Worker void Channel::CalcStatistics(const RTPHeader& rtp_header, size_t payloadSize) {
93*d9f75844SAndroid Build Coastguard Worker int n;
94*d9f75844SAndroid Build Coastguard Worker if ((rtp_header.payloadType != _lastPayloadType) &&
95*d9f75844SAndroid Build Coastguard Worker (_lastPayloadType != -1)) {
96*d9f75844SAndroid Build Coastguard Worker // payload-type is changed.
97*d9f75844SAndroid Build Coastguard Worker // we have to terminate the calculations on the previous payload type
98*d9f75844SAndroid Build Coastguard Worker // we ignore the last packet in that payload type just to make things
99*d9f75844SAndroid Build Coastguard Worker // easier.
100*d9f75844SAndroid Build Coastguard Worker for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
101*d9f75844SAndroid Build Coastguard Worker if (_lastPayloadType == _payloadStats[n].payloadType) {
102*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].newPacket = true;
103*d9f75844SAndroid Build Coastguard Worker break;
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker }
107*d9f75844SAndroid Build Coastguard Worker _lastPayloadType = rtp_header.payloadType;
108*d9f75844SAndroid Build Coastguard Worker
109*d9f75844SAndroid Build Coastguard Worker bool newPayload = true;
110*d9f75844SAndroid Build Coastguard Worker ACMTestPayloadStats* currentPayloadStr = NULL;
111*d9f75844SAndroid Build Coastguard Worker for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
112*d9f75844SAndroid Build Coastguard Worker if (rtp_header.payloadType == _payloadStats[n].payloadType) {
113*d9f75844SAndroid Build Coastguard Worker newPayload = false;
114*d9f75844SAndroid Build Coastguard Worker currentPayloadStr = &_payloadStats[n];
115*d9f75844SAndroid Build Coastguard Worker break;
116*d9f75844SAndroid Build Coastguard Worker }
117*d9f75844SAndroid Build Coastguard Worker }
118*d9f75844SAndroid Build Coastguard Worker
119*d9f75844SAndroid Build Coastguard Worker if (!newPayload) {
120*d9f75844SAndroid Build Coastguard Worker if (!currentPayloadStr->newPacket) {
121*d9f75844SAndroid Build Coastguard Worker if (!_useLastFrameSize) {
122*d9f75844SAndroid Build Coastguard Worker _lastFrameSizeSample =
123*d9f75844SAndroid Build Coastguard Worker (uint32_t)((uint32_t)rtp_header.timestamp -
124*d9f75844SAndroid Build Coastguard Worker (uint32_t)currentPayloadStr->lastTimestamp);
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(_lastFrameSizeSample, 0);
127*d9f75844SAndroid Build Coastguard Worker int k = 0;
128*d9f75844SAndroid Build Coastguard Worker for (; k < MAX_NUM_FRAMESIZES; ++k) {
129*d9f75844SAndroid Build Coastguard Worker if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
130*d9f75844SAndroid Build Coastguard Worker _lastFrameSizeSample) ||
131*d9f75844SAndroid Build Coastguard Worker (currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
132*d9f75844SAndroid Build Coastguard Worker break;
133*d9f75844SAndroid Build Coastguard Worker }
134*d9f75844SAndroid Build Coastguard Worker }
135*d9f75844SAndroid Build Coastguard Worker if (k == MAX_NUM_FRAMESIZES) {
136*d9f75844SAndroid Build Coastguard Worker // New frame size found but no space to count statistics on it. Skip it.
137*d9f75844SAndroid Build Coastguard Worker printf("No memory to store statistics for payload %d : frame size %d\n",
138*d9f75844SAndroid Build Coastguard Worker _lastPayloadType, _lastFrameSizeSample);
139*d9f75844SAndroid Build Coastguard Worker return;
140*d9f75844SAndroid Build Coastguard Worker }
141*d9f75844SAndroid Build Coastguard Worker ACMTestFrameSizeStats* currentFrameSizeStats =
142*d9f75844SAndroid Build Coastguard Worker &(currentPayloadStr->frameSizeStats[k]);
143*d9f75844SAndroid Build Coastguard Worker currentFrameSizeStats->frameSizeSample = (int16_t)_lastFrameSizeSample;
144*d9f75844SAndroid Build Coastguard Worker
145*d9f75844SAndroid Build Coastguard Worker // increment the number of encoded samples.
146*d9f75844SAndroid Build Coastguard Worker currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
147*d9f75844SAndroid Build Coastguard Worker // increment the number of recveived packets
148*d9f75844SAndroid Build Coastguard Worker currentFrameSizeStats->numPackets++;
149*d9f75844SAndroid Build Coastguard Worker // increment the total number of bytes (this is based on
150*d9f75844SAndroid Build Coastguard Worker // the previous payload we don't know the frame-size of
151*d9f75844SAndroid Build Coastguard Worker // the current payload.
152*d9f75844SAndroid Build Coastguard Worker currentFrameSizeStats->totalPayloadLenByte +=
153*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastPayloadLenByte;
154*d9f75844SAndroid Build Coastguard Worker // store the maximum payload-size (this is based on
155*d9f75844SAndroid Build Coastguard Worker // the previous payload we don't know the frame-size of
156*d9f75844SAndroid Build Coastguard Worker // the current payload.
157*d9f75844SAndroid Build Coastguard Worker if (currentFrameSizeStats->maxPayloadLen <
158*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastPayloadLenByte) {
159*d9f75844SAndroid Build Coastguard Worker currentFrameSizeStats->maxPayloadLen =
160*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastPayloadLenByte;
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker // store the current values for the next time
163*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastTimestamp = rtp_header.timestamp;
164*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastPayloadLenByte = payloadSize;
165*d9f75844SAndroid Build Coastguard Worker } else {
166*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->newPacket = false;
167*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastPayloadLenByte = payloadSize;
168*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->lastTimestamp = rtp_header.timestamp;
169*d9f75844SAndroid Build Coastguard Worker currentPayloadStr->payloadType = rtp_header.payloadType;
170*d9f75844SAndroid Build Coastguard Worker memset(currentPayloadStr->frameSizeStats, 0,
171*d9f75844SAndroid Build Coastguard Worker MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker } else {
174*d9f75844SAndroid Build Coastguard Worker n = 0;
175*d9f75844SAndroid Build Coastguard Worker while (_payloadStats[n].payloadType != -1) {
176*d9f75844SAndroid Build Coastguard Worker n++;
177*d9f75844SAndroid Build Coastguard Worker }
178*d9f75844SAndroid Build Coastguard Worker // first packet
179*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].newPacket = false;
180*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].lastPayloadLenByte = payloadSize;
181*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].lastTimestamp = rtp_header.timestamp;
182*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].payloadType = rtp_header.payloadType;
183*d9f75844SAndroid Build Coastguard Worker memset(_payloadStats[n].frameSizeStats, 0,
184*d9f75844SAndroid Build Coastguard Worker MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
185*d9f75844SAndroid Build Coastguard Worker }
186*d9f75844SAndroid Build Coastguard Worker }
187*d9f75844SAndroid Build Coastguard Worker
Channel(int16_t chID)188*d9f75844SAndroid Build Coastguard Worker Channel::Channel(int16_t chID)
189*d9f75844SAndroid Build Coastguard Worker : _receiverACM(NULL),
190*d9f75844SAndroid Build Coastguard Worker _seqNo(0),
191*d9f75844SAndroid Build Coastguard Worker _bitStreamFile(NULL),
192*d9f75844SAndroid Build Coastguard Worker _saveBitStream(false),
193*d9f75844SAndroid Build Coastguard Worker _lastPayloadType(-1),
194*d9f75844SAndroid Build Coastguard Worker _isStereo(false),
195*d9f75844SAndroid Build Coastguard Worker _leftChannel(true),
196*d9f75844SAndroid Build Coastguard Worker _lastInTimestamp(0),
197*d9f75844SAndroid Build Coastguard Worker _useLastFrameSize(false),
198*d9f75844SAndroid Build Coastguard Worker _lastFrameSizeSample(0),
199*d9f75844SAndroid Build Coastguard Worker _packetLoss(0),
200*d9f75844SAndroid Build Coastguard Worker _useFECTestWithPacketLoss(false),
201*d9f75844SAndroid Build Coastguard Worker _beginTime(rtc::TimeMillis()),
202*d9f75844SAndroid Build Coastguard Worker _totalBytes(0),
203*d9f75844SAndroid Build Coastguard Worker external_send_timestamp_(-1),
204*d9f75844SAndroid Build Coastguard Worker external_sequence_number_(-1),
205*d9f75844SAndroid Build Coastguard Worker num_packets_to_drop_(0) {
206*d9f75844SAndroid Build Coastguard Worker int n;
207*d9f75844SAndroid Build Coastguard Worker int k;
208*d9f75844SAndroid Build Coastguard Worker for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
209*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].payloadType = -1;
210*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].newPacket = true;
211*d9f75844SAndroid Build Coastguard Worker for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
212*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
213*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
214*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].numPackets = 0;
215*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
216*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
217*d9f75844SAndroid Build Coastguard Worker }
218*d9f75844SAndroid Build Coastguard Worker }
219*d9f75844SAndroid Build Coastguard Worker if (chID >= 0) {
220*d9f75844SAndroid Build Coastguard Worker _saveBitStream = true;
221*d9f75844SAndroid Build Coastguard Worker rtc::StringBuilder ss;
222*d9f75844SAndroid Build Coastguard Worker ss.AppendFormat("bitStream_%d.dat", chID);
223*d9f75844SAndroid Build Coastguard Worker _bitStreamFile = fopen(ss.str().c_str(), "wb");
224*d9f75844SAndroid Build Coastguard Worker } else {
225*d9f75844SAndroid Build Coastguard Worker _saveBitStream = false;
226*d9f75844SAndroid Build Coastguard Worker }
227*d9f75844SAndroid Build Coastguard Worker }
228*d9f75844SAndroid Build Coastguard Worker
~Channel()229*d9f75844SAndroid Build Coastguard Worker Channel::~Channel() {}
230*d9f75844SAndroid Build Coastguard Worker
RegisterReceiverACM(AudioCodingModule * acm)231*d9f75844SAndroid Build Coastguard Worker void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
232*d9f75844SAndroid Build Coastguard Worker _receiverACM = acm;
233*d9f75844SAndroid Build Coastguard Worker return;
234*d9f75844SAndroid Build Coastguard Worker }
235*d9f75844SAndroid Build Coastguard Worker
ResetStats()236*d9f75844SAndroid Build Coastguard Worker void Channel::ResetStats() {
237*d9f75844SAndroid Build Coastguard Worker int n;
238*d9f75844SAndroid Build Coastguard Worker int k;
239*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Lock();
240*d9f75844SAndroid Build Coastguard Worker _lastPayloadType = -1;
241*d9f75844SAndroid Build Coastguard Worker for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
242*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].payloadType = -1;
243*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].newPacket = true;
244*d9f75844SAndroid Build Coastguard Worker for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
245*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
246*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
247*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].numPackets = 0;
248*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
249*d9f75844SAndroid Build Coastguard Worker _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
250*d9f75844SAndroid Build Coastguard Worker }
251*d9f75844SAndroid Build Coastguard Worker }
252*d9f75844SAndroid Build Coastguard Worker _beginTime = rtc::TimeMillis();
253*d9f75844SAndroid Build Coastguard Worker _totalBytes = 0;
254*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Unlock();
255*d9f75844SAndroid Build Coastguard Worker }
256*d9f75844SAndroid Build Coastguard Worker
LastInTimestamp()257*d9f75844SAndroid Build Coastguard Worker uint32_t Channel::LastInTimestamp() {
258*d9f75844SAndroid Build Coastguard Worker uint32_t timestamp;
259*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Lock();
260*d9f75844SAndroid Build Coastguard Worker timestamp = _lastInTimestamp;
261*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Unlock();
262*d9f75844SAndroid Build Coastguard Worker return timestamp;
263*d9f75844SAndroid Build Coastguard Worker }
264*d9f75844SAndroid Build Coastguard Worker
BitRate()265*d9f75844SAndroid Build Coastguard Worker double Channel::BitRate() {
266*d9f75844SAndroid Build Coastguard Worker double rate;
267*d9f75844SAndroid Build Coastguard Worker uint64_t currTime = rtc::TimeMillis();
268*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Lock();
269*d9f75844SAndroid Build Coastguard Worker rate = ((double)_totalBytes * 8.0) / (double)(currTime - _beginTime);
270*d9f75844SAndroid Build Coastguard Worker _channelCritSect.Unlock();
271*d9f75844SAndroid Build Coastguard Worker return rate;
272*d9f75844SAndroid Build Coastguard Worker }
273*d9f75844SAndroid Build Coastguard Worker
274*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
275