2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h"
17 #include "webrtc/engine_configurations.h"
18 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
19 #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
20 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
21 #include "webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h"
22 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h"
23 #include "webrtc/modules/audio_coding/main/acm2/call_statistics.h"
24 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
25 #include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
26 #include "webrtc/system_wrappers/interface/trace.h"
27 #include "webrtc/typedefs.h"
37 // Maximum number of bytes in one packet (PCM16B, 20 ms packets, stereo).
42 // Maximum number of payloads that can be packed in one RED packet. For
43 // regular RED, we only pack two payloads. In case of dual-streaming, in worst
44 // case we might pack 3 payloads in one RED packet.
46 kNumRedFragmentationVectors = 2,
47 kMaxNumFragmentationVectors = 3
50 // If packet N is arrived all packets prior to N - |kNackThresholdPackets| which
51 // are not received are considered as lost, and appear in NACK list.
53 kNackThresholdPackets = 2
58 // TODO(turajs): the same functionality is used in NetEq. If both classes
59 // need them, make it a static function in ACMCodecDB.
60 bool IsCodecRED(const CodecInst* codec) {
61 return (STR_CASE_CMP(codec->plname, "RED") == 0);
64 bool IsCodecRED(int index) {
65 return (IsCodecRED(&ACMCodecDB::database_[index]));
68 bool IsCodecCN(const CodecInst* codec) {
69 return (STR_CASE_CMP(codec->plname, "CN") == 0);
72 bool IsCodecCN(int index) {
73 return (IsCodecCN(&ACMCodecDB::database_[index]));
76 // Stereo-to-mono can be used as in-place.
77 int DownMix(const AudioFrame& frame, int length_out_buff, int16_t* out_buff) {
78 if (length_out_buff < frame.samples_per_channel_) {
81 for (int n = 0; n < frame.samples_per_channel_; ++n)
82 out_buff[n] = (frame.data_[2 * n] + frame.data_[2 * n + 1]) >> 1;
86 // Mono-to-stereo can be used as in-place.
87 int UpMix(const AudioFrame& frame, int length_out_buff, int16_t* out_buff) {
88 if (length_out_buff < frame.samples_per_channel_) {
91 for (int n = frame.samples_per_channel_ - 1; n >= 0; --n) {
92 out_buff[2 * n + 1] = frame.data_[n];
93 out_buff[2 * n] = frame.data_[n];
98 // Return 1 if timestamp t1 is less than timestamp t2, while compensating for
100 static int TimestampLessThan(uint32_t t1, uint32_t t2) {
101 uint32_t kHalfFullRange = static_cast<uint32_t>(0xFFFFFFFF) / 2;
104 } else if (t1 < t2) {
105 if (t2 - t1 < kHalfFullRange)
109 if (t1 - t2 < kHalfFullRange)
117 AudioCodingModuleImpl::AudioCodingModuleImpl(
118 const AudioCodingModule::Config& config)
119 : acm_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
121 expected_codec_ts_(0xD87F3F9F),
122 expected_in_ts_(0xD87F3F9F),
126 cng_swb_pltype_(255),
131 vad_mode_(VADNormal),
133 current_send_codec_idx_(-1),
134 send_codec_registered_(false),
138 last_red_timestamp_(0),
139 codec_fec_enabled_(false),
140 previous_pltype_(255),
141 aux_rtp_header_(NULL),
142 receiver_initialized_(false),
143 secondary_send_codec_inst_(),
144 codec_timestamp_(expected_codec_ts_),
145 first_10ms_data_(false),
146 callback_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
147 packetization_callback_(NULL),
148 vad_callback_(NULL) {
150 // Nullify send codec memory, set payload type and set codec name to
152 const char no_name[] = "noCodecRegistered";
153 strncpy(send_codec_inst_.plname, no_name, RTP_PAYLOAD_NAME_SIZE - 1);
154 send_codec_inst_.pltype = -1;
156 strncpy(secondary_send_codec_inst_.plname, no_name,
157 RTP_PAYLOAD_NAME_SIZE - 1);
158 secondary_send_codec_inst_.pltype = -1;
160 for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
162 mirror_codec_idx_[i] = -1;
165 // Allocate memory for RED.
166 red_buffer_ = new uint8_t[MAX_PAYLOAD_SIZE_BYTE];
168 // TODO(turajs): This might not be exactly how this class is supposed to work.
169 // The external usage might be that |fragmentationVectorSize| has to match
170 // the allocated space for the member-arrays, while here, we allocate
171 // according to the maximum number of fragmentations and change
172 // |fragmentationVectorSize| on-the-fly based on actual number of
173 // fragmentations. However, due to copying to local variable before calling
174 // SendData, the RTP module receives a "valid" fragmentation, where allocated
175 // space matches |fragmentationVectorSize|, therefore, this should not cause
176 // any problem. A better approach is not using RTPFragmentationHeader as
177 // member variable, instead, use an ACM-specific structure to hold RED-related
178 // data. See module_common_type.h for the definition of
179 // RTPFragmentationHeader.
180 fragmentation_.VerifyAndAllocateFragmentationHeader(
181 kMaxNumFragmentationVectors);
183 // Register the default payload type for RED and for CNG at sampling rates of
184 // 8, 16, 32 and 48 kHz.
185 for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) {
187 red_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
188 } else if (IsCodecCN(i)) {
189 if (ACMCodecDB::database_[i].plfreq == 8000) {
190 cng_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
191 } else if (ACMCodecDB::database_[i].plfreq == 16000) {
192 cng_wb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
193 } else if (ACMCodecDB::database_[i].plfreq == 32000) {
194 cng_swb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
195 } else if (ACMCodecDB::database_[i].plfreq == 48000) {
196 cng_fb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
201 if (InitializeReceiverSafe() < 0) {
202 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
203 "Cannot initialize receiver");
205 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, id_, "Created");
208 AudioCodingModuleImpl::~AudioCodingModuleImpl() {
210 CriticalSectionScoped lock(acm_crit_sect_);
211 current_send_codec_idx_ = -1;
213 for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
214 if (codecs_[i] != NULL) {
215 // Mirror index holds the address of the codec memory.
216 assert(mirror_codec_idx_[i] > -1);
217 if (codecs_[mirror_codec_idx_[i]] != NULL) {
218 delete codecs_[mirror_codec_idx_[i]];
219 codecs_[mirror_codec_idx_[i]] = NULL;
226 if (red_buffer_ != NULL) {
227 delete[] red_buffer_;
232 if (aux_rtp_header_ != NULL) {
233 delete aux_rtp_header_;
234 aux_rtp_header_ = NULL;
237 delete callback_crit_sect_;
238 callback_crit_sect_ = NULL;
240 delete acm_crit_sect_;
241 acm_crit_sect_ = NULL;
242 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, id_,
246 int32_t AudioCodingModuleImpl::ChangeUniqueId(const int32_t id) {
248 CriticalSectionScoped lock(acm_crit_sect_);
251 for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
252 if (codecs_[i] != NULL) {
253 codecs_[i]->SetUniqueID(id);
258 receiver_.set_id(id_);
262 // Returns the number of milliseconds until the module want a
263 // worker thread to call Process.
264 int32_t AudioCodingModuleImpl::TimeUntilNextProcess() {
265 CriticalSectionScoped lock(acm_crit_sect_);
267 if (!HaveValidEncoder("TimeUntilNextProcess")) {
270 return codecs_[current_send_codec_idx_]->SamplesLeftToEncode() /
271 (send_codec_inst_.plfreq / 1000);
274 int32_t AudioCodingModuleImpl::Process() {
277 CriticalSectionScoped lock(acm_crit_sect_);
278 dual_stream = (secondary_encoder_.get() != NULL);
281 return ProcessDualStream();
283 return ProcessSingleStream();
286 int AudioCodingModuleImpl::EncodeFragmentation(int fragmentation_index,
288 uint32_t current_timestamp,
289 ACMGenericCodec* encoder,
291 int16_t len_bytes = MAX_PAYLOAD_SIZE_BYTE;
292 uint32_t rtp_timestamp;
293 WebRtcACMEncodingType encoding_type;
294 if (encoder->Encode(stream, &len_bytes, &rtp_timestamp, &encoding_type) < 0) {
297 assert(encoding_type == kActiveNormalEncoded);
298 assert(len_bytes > 0);
300 fragmentation_.fragmentationLength[fragmentation_index] = len_bytes;
301 fragmentation_.fragmentationPlType[fragmentation_index] = payload_type;
302 fragmentation_.fragmentationTimeDiff[fragmentation_index] =
303 static_cast<uint16_t>(current_timestamp - rtp_timestamp);
304 fragmentation_.fragmentationVectorSize++;
308 // Primary payloads are sent immediately, whereas a single secondary payload is
309 // buffered to be combined with "the next payload."
310 // Normally "the next payload" would be a primary payload. In case two
311 // consecutive secondary payloads are generated with no primary payload in
312 // between, then two secondary payloads are packed in one RED.
313 int AudioCodingModuleImpl::ProcessDualStream() {
314 uint8_t stream[kMaxNumFragmentationVectors * MAX_PAYLOAD_SIZE_BYTE];
315 uint32_t current_timestamp;
316 int16_t length_bytes = 0;
317 RTPFragmentationHeader my_fragmentation;
319 uint8_t my_red_payload_type;
322 CriticalSectionScoped lock(acm_crit_sect_);
323 // Check if there is an encoder before.
324 if (!HaveValidEncoder("ProcessDualStream") ||
325 secondary_encoder_.get() == NULL) {
328 ACMGenericCodec* primary_encoder = codecs_[current_send_codec_idx_];
329 // If primary encoder has a full frame of audio to generate payload.
330 bool primary_ready_to_encode = primary_encoder->HasFrameToEncode();
331 // If the secondary encoder has a frame of audio to generate a payload.
332 bool secondary_ready_to_encode = secondary_encoder_->HasFrameToEncode();
334 if (!primary_ready_to_encode && !secondary_ready_to_encode) {
338 int len_bytes_previous_secondary = static_cast<int>(
339 fragmentation_.fragmentationLength[2]);
340 assert(len_bytes_previous_secondary <= MAX_PAYLOAD_SIZE_BYTE);
341 bool has_previous_payload = len_bytes_previous_secondary > 0;
343 uint32_t primary_timestamp = primary_encoder->EarliestTimestamp();
344 uint32_t secondary_timestamp = secondary_encoder_->EarliestTimestamp();
346 if (!has_previous_payload && !primary_ready_to_encode &&
347 secondary_ready_to_encode) {
348 // Secondary payload will be the ONLY bit-stream. Encode by secondary
349 // encoder, store the payload, and return. No packet is sent.
350 int16_t len_bytes = MAX_PAYLOAD_SIZE_BYTE;
351 WebRtcACMEncodingType encoding_type;
352 if (secondary_encoder_->Encode(red_buffer_, &len_bytes,
353 &last_red_timestamp_,
354 &encoding_type) < 0) {
355 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
356 "ProcessDual(): Encoding of secondary encoder Failed");
359 assert(len_bytes > 0);
360 assert(encoding_type == kActiveNormalEncoded);
361 assert(len_bytes <= MAX_PAYLOAD_SIZE_BYTE);
362 fragmentation_.fragmentationLength[2] = len_bytes;
366 // Initialize with invalid but different values, so later can have sanity
367 // check if they are different.
368 int index_primary = -1;
369 int index_secondary = -2;
370 int index_previous_secondary = -3;
372 if (primary_ready_to_encode) {
373 index_primary = secondary_ready_to_encode ?
374 TimestampLessThan(primary_timestamp, secondary_timestamp) : 0;
375 index_primary += has_previous_payload ?
376 TimestampLessThan(primary_timestamp, last_red_timestamp_) : 0;
379 if (secondary_ready_to_encode) {
380 // Timestamp of secondary payload can only be less than primary payload,
381 // but is always larger than the timestamp of previous secondary payload.
382 index_secondary = primary_ready_to_encode ?
383 (1 - TimestampLessThan(primary_timestamp, secondary_timestamp)) : 0;
386 if (has_previous_payload) {
387 index_previous_secondary = primary_ready_to_encode ?
388 (1 - TimestampLessThan(primary_timestamp, last_red_timestamp_)) : 0;
389 // If secondary is ready it always have a timestamp larger than previous
390 // secondary. So the index is either 0 or 1.
391 index_previous_secondary += secondary_ready_to_encode ? 1 : 0;
394 // Indices must not be equal.
395 assert(index_primary != index_secondary);
396 assert(index_primary != index_previous_secondary);
397 assert(index_secondary != index_previous_secondary);
399 // One of the payloads has to be at position zero.
400 assert(index_primary == 0 || index_secondary == 0 ||
401 index_previous_secondary == 0);
403 // Timestamp of the RED payload.
404 if (index_primary == 0) {
405 current_timestamp = primary_timestamp;
406 } else if (index_secondary == 0) {
407 current_timestamp = secondary_timestamp;
409 current_timestamp = last_red_timestamp_;
412 fragmentation_.fragmentationVectorSize = 0;
413 if (has_previous_payload) {
414 assert(index_previous_secondary >= 0 &&
415 index_previous_secondary < kMaxNumFragmentationVectors);
416 assert(len_bytes_previous_secondary <= MAX_PAYLOAD_SIZE_BYTE);
417 memcpy(&stream[index_previous_secondary * MAX_PAYLOAD_SIZE_BYTE],
418 red_buffer_, sizeof(stream[0]) * len_bytes_previous_secondary);
419 fragmentation_.fragmentationLength[index_previous_secondary] =
420 len_bytes_previous_secondary;
421 fragmentation_.fragmentationPlType[index_previous_secondary] =
422 secondary_send_codec_inst_.pltype;
423 fragmentation_.fragmentationTimeDiff[index_previous_secondary] =
424 static_cast<uint16_t>(current_timestamp - last_red_timestamp_);
425 fragmentation_.fragmentationVectorSize++;
428 if (primary_ready_to_encode) {
429 assert(index_primary >= 0 && index_primary < kMaxNumFragmentationVectors);
430 int i = index_primary * MAX_PAYLOAD_SIZE_BYTE;
431 if (EncodeFragmentation(index_primary, send_codec_inst_.pltype,
432 current_timestamp, primary_encoder,
434 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
435 "ProcessDualStream(): Encoding of primary encoder Failed");
440 if (secondary_ready_to_encode) {
441 assert(index_secondary >= 0 &&
442 index_secondary < kMaxNumFragmentationVectors - 1);
443 int i = index_secondary * MAX_PAYLOAD_SIZE_BYTE;
444 if (EncodeFragmentation(index_secondary,
445 secondary_send_codec_inst_.pltype,
446 current_timestamp, secondary_encoder_.get(),
448 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
449 "ProcessDualStream(): Encoding of secondary encoder "
454 // Copy to local variable, as it will be used outside the ACM lock.
455 my_fragmentation.CopyFrom(fragmentation_);
456 my_red_payload_type = red_pltype_;
458 for (int n = 0; n < fragmentation_.fragmentationVectorSize; n++) {
459 length_bytes += fragmentation_.fragmentationLength[n];
464 CriticalSectionScoped lock(callback_crit_sect_);
465 if (packetization_callback_ != NULL) {
466 // Callback with payload data, including redundant data (RED).
467 if (packetization_callback_->SendData(kAudioFrameSpeech,
469 current_timestamp, stream,
471 &my_fragmentation) < 0) {
478 CriticalSectionScoped lock(acm_crit_sect_);
479 // Now that data is sent, clean up fragmentation.
480 ResetFragmentation(0);
485 // Process any pending tasks such as timeouts.
486 int AudioCodingModuleImpl::ProcessSingleStream() {
487 // Make room for 1 RED payload.
488 uint8_t stream[2 * MAX_PAYLOAD_SIZE_BYTE];
489 // TODO(turajs): |length_bytes| & |red_length_bytes| can be of type int if
490 // ACMGenericCodec::Encode() & ACMGenericCodec::GetRedPayload() allows.
491 int16_t length_bytes = 2 * MAX_PAYLOAD_SIZE_BYTE;
492 int16_t red_length_bytes = length_bytes;
493 uint32_t rtp_timestamp;
495 WebRtcACMEncodingType encoding_type;
496 FrameType frame_type = kAudioFrameSpeech;
497 uint8_t current_payload_type = 0;
498 bool has_data_to_send = false;
499 bool red_active = false;
500 RTPFragmentationHeader my_fragmentation;
502 // Keep the scope of the ACM critical section limited.
504 CriticalSectionScoped lock(acm_crit_sect_);
505 // Check if there is an encoder before.
506 if (!HaveValidEncoder("ProcessSingleStream")) {
509 status = codecs_[current_send_codec_idx_]->Encode(stream, &length_bytes,
514 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
515 "ProcessSingleStream(): Encoding Failed");
518 } else if (status == 0) {
522 switch (encoding_type) {
524 current_payload_type = previous_pltype_;
525 frame_type = kFrameEmpty;
529 case kActiveNormalEncoded:
530 case kPassiveNormalEncoded: {
531 current_payload_type = static_cast<uint8_t>(send_codec_inst_.pltype);
532 frame_type = kAudioFrameSpeech;
535 case kPassiveDTXNB: {
536 current_payload_type = cng_nb_pltype_;
537 frame_type = kAudioFrameCN;
538 is_first_red_ = true;
541 case kPassiveDTXWB: {
542 current_payload_type = cng_wb_pltype_;
543 frame_type = kAudioFrameCN;
544 is_first_red_ = true;
547 case kPassiveDTXSWB: {
548 current_payload_type = cng_swb_pltype_;
549 frame_type = kAudioFrameCN;
550 is_first_red_ = true;
553 case kPassiveDTXFB: {
554 current_payload_type = cng_fb_pltype_;
555 frame_type = kAudioFrameCN;
556 is_first_red_ = true;
560 has_data_to_send = true;
561 previous_pltype_ = current_payload_type;
563 // Redundancy encode is done here. The two bitstreams packetized into
564 // one RTP packet and the fragmentation points are set.
565 // Only apply RED on speech data.
566 if ((red_enabled_) &&
567 ((encoding_type == kActiveNormalEncoded) ||
568 (encoding_type == kPassiveNormalEncoded))) {
569 // RED is enabled within this scope.
571 // Note that, a special solution exists for iSAC since it is the only
572 // codec for which GetRedPayload has a non-empty implementation.
574 // Summary of the RED scheme below (use iSAC as example):
576 // 1st (is_first_red_ is true) encoded iSAC frame (primary #1) =>
577 // - call GetRedPayload() and store redundancy for packet #1 in
578 // second fragment of RED buffer (old data)
579 // - drop the primary iSAC frame
580 // - don't call SendData
581 // 2nd (is_first_red_ is false) encoded iSAC frame (primary #2) =>
582 // - store primary #2 in 1st fragment of RED buffer and send the
584 // - the transmitted packet contains primary #2 (new) and
585 // redundancy for packet #1 (old)
586 // - call GetRed_Payload() and store redundancy for packet #2 in
587 // second fragment of RED buffer
591 // Nth encoded iSAC frame (primary #N) =>
592 // - store primary #N in 1st fragment of RED buffer and send the
594 // - the transmitted packet contains primary #N (new) and
595 // reduncancy for packet #(N-1) (old)
596 // - call GetRedPayload() and store redundancy for packet #N in
597 // second fragment of RED buffer
599 // For all other codecs, GetRedPayload does nothing and returns -1 =>
600 // redundant data is only a copy.
602 // First combined packet contains : #2 (new) and #1 (old)
603 // Second combined packet contains: #3 (new) and #2 (old)
604 // Third combined packet contains : #4 (new) and #3 (old)
606 // Hence, even if every second packet is dropped, perfect
607 // reconstruction is possible.
610 has_data_to_send = false;
611 // Skip the following part for the first packet in a RED session.
612 if (!is_first_red_) {
613 // Rearrange stream such that RED packets are included.
614 // Replace stream now that we have stored current stream.
615 memcpy(stream + fragmentation_.fragmentationOffset[1], red_buffer_,
616 fragmentation_.fragmentationLength[1]);
617 // Update the fragmentation time difference vector, in number of
619 uint16_t time_since_last = static_cast<uint16_t>(
620 rtp_timestamp - last_red_timestamp_);
622 // Update fragmentation vectors.
623 fragmentation_.fragmentationPlType[1] =
624 fragmentation_.fragmentationPlType[0];
625 fragmentation_.fragmentationTimeDiff[1] = time_since_last;
626 has_data_to_send = true;
629 // Insert new packet length.
630 fragmentation_.fragmentationLength[0] = length_bytes;
632 // Insert new packet payload type.
633 fragmentation_.fragmentationPlType[0] = current_payload_type;
634 last_red_timestamp_ = rtp_timestamp;
636 // Can be modified by the GetRedPayload() call if iSAC is utilized.
637 red_length_bytes = length_bytes;
639 // A fragmentation header is provided => packetization according to
640 // RFC 2198 (RTP Payload for Redundant Audio Data) will be used.
641 // First fragment is the current data (new).
642 // Second fragment is the previous data (old).
643 length_bytes = static_cast<int16_t>(
644 fragmentation_.fragmentationLength[0] +
645 fragmentation_.fragmentationLength[1]);
647 // Get, and store, redundant data from the encoder based on the recently
649 // NOTE - only iSAC contains an implementation; all other codecs does
650 // nothing and returns -1.
651 if (codecs_[current_send_codec_idx_]->GetRedPayload(
652 red_buffer_, &red_length_bytes) == -1) {
653 // The codec was not iSAC => use current encoder output as redundant
654 // data instead (trivial RED scheme).
655 memcpy(red_buffer_, stream, red_length_bytes);
658 is_first_red_ = false;
659 // Update payload type with RED payload type.
660 current_payload_type = red_pltype_;
661 // We have packed 2 payloads.
662 fragmentation_.fragmentationVectorSize = kNumRedFragmentationVectors;
664 // Copy to local variable, as it will be used outside ACM lock.
665 my_fragmentation.CopyFrom(fragmentation_);
667 fragmentation_.fragmentationLength[1] = red_length_bytes;
672 if (has_data_to_send) {
673 CriticalSectionScoped lock(callback_crit_sect_);
675 if (packetization_callback_ != NULL) {
677 // Callback with payload data, including redundant data (RED).
678 packetization_callback_->SendData(frame_type, current_payload_type,
679 rtp_timestamp, stream, length_bytes,
682 // Callback with payload data.
683 packetization_callback_->SendData(frame_type, current_payload_type,
684 rtp_timestamp, stream, length_bytes,
689 if (vad_callback_ != NULL) {
690 // Callback with VAD decision.
691 vad_callback_->InFrameType(static_cast<int16_t>(encoding_type));
697 /////////////////////////////////////////
701 // Initialize send codec.
702 int AudioCodingModuleImpl::InitializeSender() {
703 CriticalSectionScoped lock(acm_crit_sect_);
705 // Start with invalid values.
706 send_codec_registered_ = false;
707 current_send_codec_idx_ = -1;
708 send_codec_inst_.plname[0] = '\0';
710 // Delete all encoders to start fresh.
711 for (int id = 0; id < ACMCodecDB::kMaxNumCodecs; id++) {
712 if (codecs_[id] != NULL) {
713 codecs_[id]->DestructEncoder();
718 is_first_red_ = true;
719 if (red_enabled_ || secondary_encoder_.get() != NULL) {
720 if (red_buffer_ != NULL) {
721 memset(red_buffer_, 0, MAX_PAYLOAD_SIZE_BYTE);
724 ResetFragmentation(kNumRedFragmentationVectors);
726 ResetFragmentation(0);
733 int AudioCodingModuleImpl::ResetEncoder() {
734 CriticalSectionScoped lock(acm_crit_sect_);
735 if (!HaveValidEncoder("ResetEncoder")) {
738 return codecs_[current_send_codec_idx_]->ResetEncoder();
741 ACMGenericCodec* AudioCodingModuleImpl::CreateCodec(const CodecInst& codec) {
742 ACMGenericCodec* my_codec = NULL;
744 my_codec = ACMCodecDB::CreateCodecInstance(codec);
745 if (my_codec == NULL) {
746 // Error, could not create the codec.
747 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
748 "ACMCodecDB::CreateCodecInstance() failed in CreateCodec()");
751 my_codec->SetUniqueID(id_);
756 // Check if the given codec is a valid to be registered as send codec.
757 static int IsValidSendCodec(const CodecInst& send_codec,
758 bool is_primary_encoder,
761 if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
762 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
763 "Wrong number of channels (%d, only mono and stereo are "
764 "supported) for %s encoder", send_codec.channels,
765 is_primary_encoder ? "primary" : "secondary");
769 int codec_id = ACMCodecDB::CodecNumber(send_codec, mirror_id);
771 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
772 "Invalid codec setting for the send codec.");
776 // TODO(tlegrand): Remove this check. Already taken care of in
777 // ACMCodecDB::CodecNumber().
778 // Check if the payload-type is valid
779 if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
780 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
781 "Invalid payload-type %d for %s.", send_codec.pltype,
786 // Telephone-event cannot be a send codec.
787 if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) {
788 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
789 "telephone-event cannot be a send codec");
794 if (ACMCodecDB::codec_settings_[codec_id].channel_support
795 < send_codec.channels) {
796 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
797 "%d number of channels not supportedn for %s.",
798 send_codec.channels, send_codec.plname);
803 if (!is_primary_encoder) {
804 // If registering the secondary encoder, then RED and CN are not valid
805 // choices as encoder.
806 if (IsCodecRED(&send_codec)) {
807 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
808 "RED cannot be secondary codec");
813 if (IsCodecCN(&send_codec)) {
814 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id,
815 "DTX cannot be secondary codec");
823 int AudioCodingModuleImpl::RegisterSecondarySendCodec(
824 const CodecInst& send_codec) {
825 CriticalSectionScoped lock(acm_crit_sect_);
826 if (!send_codec_registered_) {
829 // Primary and Secondary codecs should have the same sampling rates.
830 if (send_codec.plfreq != send_codec_inst_.plfreq) {
834 int codec_id = IsValidSendCodec(send_codec, false, id_, &mirror_id);
838 ACMGenericCodec* encoder = CreateCodec(send_codec);
839 WebRtcACMCodecParams codec_params;
840 // Initialize the codec before registering. For secondary codec VAD & DTX are
842 memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
843 codec_params.enable_vad = false;
844 codec_params.enable_dtx = false;
845 codec_params.vad_mode = VADNormal;
846 // Force initialization.
847 if (encoder->InitEncoder(&codec_params, true) < 0) {
848 // Could not initialize, therefore cannot be registered.
852 secondary_encoder_.reset(encoder);
853 memcpy(&secondary_send_codec_inst_, &send_codec, sizeof(send_codec));
855 // Disable VAD & DTX.
856 SetVADSafe(false, false, VADNormal);
860 memset(red_buffer_, 0, MAX_PAYLOAD_SIZE_BYTE);
862 ResetFragmentation(0);
866 void AudioCodingModuleImpl::UnregisterSecondarySendCodec() {
867 CriticalSectionScoped lock(acm_crit_sect_);
868 if (secondary_encoder_.get() == NULL) {
871 secondary_encoder_.reset();
872 ResetFragmentation(0);
875 int AudioCodingModuleImpl::SecondarySendCodec(
876 CodecInst* secondary_codec) const {
877 CriticalSectionScoped lock(acm_crit_sect_);
878 if (secondary_encoder_.get() == NULL) {
881 memcpy(secondary_codec, &secondary_send_codec_inst_,
882 sizeof(secondary_send_codec_inst_));
886 // Can be called multiple times for Codec, CNG, RED.
887 int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
889 int codec_id = IsValidSendCodec(send_codec, true, id_, &mirror_id);
891 CriticalSectionScoped lock(acm_crit_sect_);
893 // Check for reported errors from function IsValidSendCodec().
895 if (!send_codec_registered_) {
896 // This values has to be NULL if there is no codec registered.
897 current_send_codec_idx_ = -1;
902 // RED can be registered with other payload type. If not registered a default
903 // payload type is used.
904 if (IsCodecRED(&send_codec)) {
905 // TODO(tlegrand): Remove this check. Already taken care of in
906 // ACMCodecDB::CodecNumber().
907 // Check if the payload-type is valid
908 if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
909 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
910 "Invalid payload-type %d for %s.", send_codec.pltype,
914 // Set RED payload type.
915 red_pltype_ = static_cast<uint8_t>(send_codec.pltype);
919 // CNG can be registered with other payload type. If not registered the
920 // default payload types from codec database will be used.
921 if (IsCodecCN(&send_codec)) {
922 // CNG is registered.
923 switch (send_codec.plfreq) {
925 cng_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
929 cng_wb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
933 cng_swb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
937 cng_fb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
941 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
942 "RegisterSendCodec() failed, invalid frequency for CNG "
950 // Set Stereo, and make sure VAD and DTX is turned off.
951 if (send_codec.channels == 2) {
953 if (vad_enabled_ || dtx_enabled_) {
954 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
955 "VAD/DTX is turned off, not supported when sending stereo.");
957 vad_enabled_ = false;
958 dtx_enabled_ = false;
960 stereo_send_ = false;
963 // Check if the codec is already registered as send codec.
965 if (send_codec_registered_) {
966 int send_codec_mirror_id;
967 int send_codec_id = ACMCodecDB::CodecNumber(send_codec_inst_,
968 &send_codec_mirror_id);
969 assert(send_codec_id >= 0);
970 is_send_codec = (send_codec_id == codec_id) ||
971 (mirror_id == send_codec_mirror_id);
973 is_send_codec = false;
976 // If there is secondary codec registered and the new send codec has a
977 // sampling rate different than that of secondary codec, then unregister the
979 if (secondary_encoder_.get() != NULL &&
980 secondary_send_codec_inst_.plfreq != send_codec.plfreq) {
981 secondary_encoder_.reset();
982 ResetFragmentation(0);
985 // If new codec, or new settings, register.
986 if (!is_send_codec) {
987 if (codecs_[mirror_id] == NULL) {
988 codecs_[mirror_id] = CreateCodec(send_codec);
989 if (codecs_[mirror_id] == NULL) {
990 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
991 "Cannot Create the codec");
994 mirror_codec_idx_[mirror_id] = mirror_id;
997 if (mirror_id != codec_id) {
998 codecs_[codec_id] = codecs_[mirror_id];
999 mirror_codec_idx_[codec_id] = mirror_id;
1002 ACMGenericCodec* codec_ptr = codecs_[codec_id];
1003 WebRtcACMCodecParams codec_params;
1005 memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
1006 codec_params.enable_vad = vad_enabled_;
1007 codec_params.enable_dtx = dtx_enabled_;
1008 codec_params.vad_mode = vad_mode_;
1009 // Force initialization.
1010 if (codec_ptr->InitEncoder(&codec_params, true) < 0) {
1011 // Could not initialize the encoder.
1013 // Check if already have a registered codec.
1014 // Depending on that different messages are logged.
1015 if (!send_codec_registered_) {
1016 current_send_codec_idx_ = -1;
1017 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1018 "Cannot Initialize the encoder No Encoder is registered");
1020 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1021 "Cannot Initialize the encoder, continue encoding with "
1022 "the previously registered codec");
1028 dtx_enabled_ = codec_params.enable_dtx;
1029 vad_enabled_ = codec_params.enable_vad;
1030 vad_mode_ = codec_params.vad_mode;
1032 // Everything is fine so we can replace the previous codec with this one.
1033 if (send_codec_registered_) {
1034 // If we change codec we start fresh with RED.
1035 // This is not strictly required by the standard.
1036 is_first_red_ = true;
1037 codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
1039 if (!codec_ptr->HasInternalFEC()) {
1040 codec_fec_enabled_ = false;
1042 if (codec_ptr->SetFEC(codec_fec_enabled_) < 0) {
1043 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1044 "Cannot set codec FEC");
1050 current_send_codec_idx_ = codec_id;
1051 send_codec_registered_ = true;
1052 memcpy(&send_codec_inst_, &send_codec, sizeof(CodecInst));
1053 previous_pltype_ = send_codec_inst_.pltype;
1056 // If codec is the same as already registered check if any parameters
1057 // has changed compared to the current values.
1058 // If any parameter is valid then apply it and record.
1059 bool force_init = false;
1061 if (mirror_id != codec_id) {
1062 codecs_[codec_id] = codecs_[mirror_id];
1063 mirror_codec_idx_[codec_id] = mirror_id;
1066 // Check the payload type.
1067 if (send_codec.pltype != send_codec_inst_.pltype) {
1068 // At this point check if the given payload type is valid.
1069 // Record it later when the sampling frequency is changed
1071 if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) {
1072 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1073 "Out of range payload type");
1078 // If there is a codec that ONE instance of codec supports multiple
1079 // sampling frequencies, then we need to take care of it here.
1080 // one such a codec is iSAC. Both WB and SWB are encoded and decoded
1081 // with one iSAC instance. Therefore, we need to update the encoder
1082 // frequency if required.
1083 if (send_codec_inst_.plfreq != send_codec.plfreq) {
1086 // If sampling frequency is changed we have to start fresh with RED.
1087 is_first_red_ = true;
1090 // If packet size or number of channels has changed, we need to
1091 // re-initialize the encoder.
1092 if (send_codec_inst_.pacsize != send_codec.pacsize) {
1095 if (send_codec_inst_.channels != send_codec.channels) {
1100 WebRtcACMCodecParams codec_params;
1102 memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
1103 codec_params.enable_vad = vad_enabled_;
1104 codec_params.enable_dtx = dtx_enabled_;
1105 codec_params.vad_mode = vad_mode_;
1107 // Force initialization.
1108 if (codecs_[current_send_codec_idx_]->InitEncoder(&codec_params,
1110 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1111 "Could not change the codec packet-size.");
1115 send_codec_inst_.plfreq = send_codec.plfreq;
1116 send_codec_inst_.pacsize = send_codec.pacsize;
1117 send_codec_inst_.channels = send_codec.channels;
1120 // If the change of sampling frequency has been successful then
1121 // we store the payload-type.
1122 send_codec_inst_.pltype = send_codec.pltype;
1124 // Check if a change in Rate is required.
1125 if (send_codec.rate != send_codec_inst_.rate) {
1126 if (codecs_[codec_id]->SetBitRate(send_codec.rate) < 0) {
1127 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1128 "Could not change the codec rate.");
1131 send_codec_inst_.rate = send_codec.rate;
1134 if (!codecs_[codec_id]->HasInternalFEC()) {
1135 codec_fec_enabled_ = false;
1137 if (codecs_[codec_id]->SetFEC(codec_fec_enabled_) < 0) {
1138 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1139 "Cannot set codec FEC");
1144 previous_pltype_ = send_codec_inst_.pltype;
1149 // Get current send codec.
1150 int AudioCodingModuleImpl::SendCodec(
1151 CodecInst* current_codec) const {
1152 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1154 CriticalSectionScoped lock(acm_crit_sect_);
1156 if (!send_codec_registered_) {
1157 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1158 "SendCodec Failed, no codec is registered");
1161 WebRtcACMCodecParams encoder_param;
1162 codecs_[current_send_codec_idx_]->EncoderParams(&encoder_param);
1163 encoder_param.codec_inst.pltype = send_codec_inst_.pltype;
1164 memcpy(current_codec, &(encoder_param.codec_inst), sizeof(CodecInst));
1169 // Get current send frequency.
1170 int AudioCodingModuleImpl::SendFrequency() const {
1171 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1173 CriticalSectionScoped lock(acm_crit_sect_);
1175 if (!send_codec_registered_) {
1176 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1177 "SendFrequency Failed, no codec is registered");
1181 return send_codec_inst_.plfreq;
1184 // Get encode bitrate.
1185 // Adaptive rate codecs return their current encode target rate, while other
1186 // codecs return there longterm avarage or their fixed rate.
1187 int AudioCodingModuleImpl::SendBitrate() const {
1188 CriticalSectionScoped lock(acm_crit_sect_);
1190 if (!send_codec_registered_) {
1191 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1192 "SendBitrate Failed, no codec is registered");
1196 WebRtcACMCodecParams encoder_param;
1197 codecs_[current_send_codec_idx_]->EncoderParams(&encoder_param);
1199 return encoder_param.codec_inst.rate;
1202 // Set available bandwidth, inform the encoder about the estimated bandwidth
1203 // received from the remote party.
1204 int AudioCodingModuleImpl::SetReceivedEstimatedBandwidth(int bw) {
1205 CriticalSectionScoped lock(acm_crit_sect_);
1206 return codecs_[current_send_codec_idx_]->SetEstimatedBandwidth(bw);
1209 // Register a transport callback which will be called to deliver
1210 // the encoded buffers.
1211 int AudioCodingModuleImpl::RegisterTransportCallback(
1212 AudioPacketizationCallback* transport) {
1213 CriticalSectionScoped lock(callback_crit_sect_);
1214 packetization_callback_ = transport;
1218 // Add 10MS of raw (PCM) audio data to the encoder.
1219 int AudioCodingModuleImpl::Add10MsData(
1220 const AudioFrame& audio_frame) {
1221 if (audio_frame.samples_per_channel_ <= 0) {
1223 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1224 "Cannot Add 10 ms audio, payload length is negative or "
1229 if (audio_frame.sample_rate_hz_ > 48000) {
1231 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1232 "Cannot Add 10 ms audio, input frequency not valid");
1236 // If the length and frequency matches. We currently just support raw PCM.
1237 if ((audio_frame.sample_rate_hz_ / 100)
1238 != audio_frame.samples_per_channel_) {
1239 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1240 "Cannot Add 10 ms audio, input frequency and length doesn't"
1245 if (audio_frame.num_channels_ != 1 && audio_frame.num_channels_ != 2) {
1246 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1247 "Cannot Add 10 ms audio, invalid number of channels.");
1251 CriticalSectionScoped lock(acm_crit_sect_);
1252 // Do we have a codec registered?
1253 if (!HaveValidEncoder("Add10MsData")) {
1257 const AudioFrame* ptr_frame;
1258 // Perform a resampling, also down-mix if it is required and can be
1259 // performed before resampling (a down mix prior to resampling will take
1260 // place if both primary and secondary encoders are mono and input is in
1262 if (PreprocessToAddData(audio_frame, &ptr_frame) < 0) {
1266 // Check whether we need an up-mix or down-mix?
1267 bool remix = ptr_frame->num_channels_ != send_codec_inst_.channels;
1268 if (secondary_encoder_.get() != NULL) {
1270 (ptr_frame->num_channels_ != secondary_send_codec_inst_.channels);
1273 // If a re-mix is required (up or down), this buffer will store re-mixed
1274 // version of the input.
1275 int16_t buffer[WEBRTC_10MS_PCM_AUDIO];
1277 if (ptr_frame->num_channels_ == 1) {
1278 if (UpMix(*ptr_frame, WEBRTC_10MS_PCM_AUDIO, buffer) < 0)
1281 if (DownMix(*ptr_frame, WEBRTC_10MS_PCM_AUDIO, buffer) < 0)
1286 // When adding data to encoders this pointer is pointing to an audio buffer
1287 // with correct number of channels.
1288 const int16_t* ptr_audio = ptr_frame->data_;
1290 // For pushing data to primary, point the |ptr_audio| to correct buffer.
1291 if (send_codec_inst_.channels != ptr_frame->num_channels_)
1294 if (codecs_[current_send_codec_idx_]->Add10MsData(
1295 ptr_frame->timestamp_, ptr_audio, ptr_frame->samples_per_channel_,
1296 send_codec_inst_.channels) < 0)
1299 if (secondary_encoder_.get() != NULL) {
1300 // For pushing data to secondary, point the |ptr_audio| to correct buffer.
1301 ptr_audio = ptr_frame->data_;
1302 if (secondary_send_codec_inst_.channels != ptr_frame->num_channels_)
1305 if (secondary_encoder_->Add10MsData(
1306 ptr_frame->timestamp_, ptr_audio, ptr_frame->samples_per_channel_,
1307 secondary_send_codec_inst_.channels) < 0)
1314 // Perform a resampling and down-mix if required. We down-mix only if
1315 // encoder is mono and input is stereo. In case of dual-streaming, both
1316 // encoders has to be mono for down-mix to take place.
1317 // |*ptr_out| will point to the pre-processed audio-frame. If no pre-processing
1318 // is required, |*ptr_out| points to |in_frame|.
1319 int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame,
1320 const AudioFrame** ptr_out) {
1321 // Primary and secondary (if exists) should have the same sampling rate.
1322 assert((secondary_encoder_.get() != NULL) ?
1323 secondary_send_codec_inst_.plfreq == send_codec_inst_.plfreq : true);
1325 bool resample = (in_frame.sample_rate_hz_ != send_codec_inst_.plfreq);
1327 // This variable is true if primary codec and secondary codec (if exists)
1328 // are both mono and input is stereo.
1330 if (secondary_encoder_.get() != NULL) {
1331 down_mix = (in_frame.num_channels_ == 2) &&
1332 (send_codec_inst_.channels == 1) &&
1333 (secondary_send_codec_inst_.channels == 1);
1335 down_mix = (in_frame.num_channels_ == 2) &&
1336 (send_codec_inst_.channels == 1);
1339 if (!first_10ms_data_) {
1340 expected_in_ts_ = in_frame.timestamp_;
1341 expected_codec_ts_ = in_frame.timestamp_;
1342 first_10ms_data_ = true;
1343 } else if (in_frame.timestamp_ != expected_in_ts_) {
1344 // TODO(turajs): Do we need a warning here.
1345 expected_codec_ts_ += (in_frame.timestamp_ - expected_in_ts_) *
1346 static_cast<uint32_t>((static_cast<double>(send_codec_inst_.plfreq) /
1347 static_cast<double>(in_frame.sample_rate_hz_)));
1348 expected_in_ts_ = in_frame.timestamp_;
1352 if (!down_mix && !resample) {
1353 // No pre-processing is required.
1354 expected_in_ts_ += in_frame.samples_per_channel_;
1355 expected_codec_ts_ += in_frame.samples_per_channel_;
1356 *ptr_out = &in_frame;
1360 *ptr_out = &preprocess_frame_;
1361 preprocess_frame_.num_channels_ = in_frame.num_channels_;
1362 int16_t audio[WEBRTC_10MS_PCM_AUDIO];
1363 const int16_t* src_ptr_audio = in_frame.data_;
1364 int16_t* dest_ptr_audio = preprocess_frame_.data_;
1366 // If a resampling is required the output of a down-mix is written into a
1367 // local buffer, otherwise, it will be written to the output frame.
1369 dest_ptr_audio = audio;
1370 if (DownMix(in_frame, WEBRTC_10MS_PCM_AUDIO, dest_ptr_audio) < 0)
1372 preprocess_frame_.num_channels_ = 1;
1373 // Set the input of the resampler is the down-mixed signal.
1374 src_ptr_audio = audio;
1377 preprocess_frame_.timestamp_ = expected_codec_ts_;
1378 preprocess_frame_.samples_per_channel_ = in_frame.samples_per_channel_;
1379 preprocess_frame_.sample_rate_hz_ = in_frame.sample_rate_hz_;
1380 // If it is required, we have to do a resampling.
1382 // The result of the resampler is written to output frame.
1383 dest_ptr_audio = preprocess_frame_.data_;
1385 preprocess_frame_.samples_per_channel_ =
1386 resampler_.Resample10Msec(src_ptr_audio,
1387 in_frame.sample_rate_hz_,
1388 send_codec_inst_.plfreq,
1389 preprocess_frame_.num_channels_,
1390 AudioFrame::kMaxDataSizeSamples,
1393 if (preprocess_frame_.samples_per_channel_ < 0) {
1394 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1395 "Cannot add 10 ms audio, resampling failed");
1398 preprocess_frame_.sample_rate_hz_ = send_codec_inst_.plfreq;
1401 expected_codec_ts_ += preprocess_frame_.samples_per_channel_;
1402 expected_in_ts_ += in_frame.samples_per_channel_;
1407 /////////////////////////////////////////
1408 // (RED) Redundant Coding
1411 bool AudioCodingModuleImpl::REDStatus() const {
1412 CriticalSectionScoped lock(acm_crit_sect_);
1414 return red_enabled_;
1417 // Configure RED status i.e on/off.
1418 int AudioCodingModuleImpl::SetREDStatus(
1419 #ifdef WEBRTC_CODEC_RED
1421 CriticalSectionScoped lock(acm_crit_sect_);
1423 if (enable_red == true && codec_fec_enabled_ == true) {
1424 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
1425 "Codec internal FEC and RED cannot be co-enabled.");
1429 if (red_enabled_ != enable_red) {
1430 // Reset the RED buffer.
1431 memset(red_buffer_, 0, MAX_PAYLOAD_SIZE_BYTE);
1433 // Reset fragmentation buffers.
1434 ResetFragmentation(kNumRedFragmentationVectors);
1435 // Set red_enabled_.
1436 red_enabled_ = enable_red;
1438 is_first_red_ = true; // Make sure we restart RED.
1441 bool /* enable_red */) {
1442 red_enabled_ = false;
1443 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
1444 " WEBRTC_CODEC_RED is undefined => red_enabled_ = %d",
1450 /////////////////////////////////////////
1451 // (FEC) Forward Error Correction (codec internal)
1454 bool AudioCodingModuleImpl::CodecFEC() const {
1455 CriticalSectionScoped lock(acm_crit_sect_);
1456 return codec_fec_enabled_;
1459 int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) {
1460 CriticalSectionScoped lock(acm_crit_sect_);
1462 if (enable_codec_fec == true && red_enabled_ == true) {
1463 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
1464 "Codec internal FEC and RED cannot be co-enabled.");
1469 if (HaveValidEncoder("SetCodecFEC") &&
1470 codecs_[current_send_codec_idx_]->SetFEC(enable_codec_fec) < 0) {
1471 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1472 "Set codec internal FEC failed.");
1475 codec_fec_enabled_ = enable_codec_fec;
1479 int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) {
1480 CriticalSectionScoped lock(acm_crit_sect_);
1481 if (HaveValidEncoder("SetPacketLossRate") &&
1482 codecs_[current_send_codec_idx_]->SetPacketLossRate(loss_rate) < 0) {
1483 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1484 "Set packet loss rate failed.");
1490 /////////////////////////////////////////
1491 // (VAD) Voice Activity Detection
1493 int AudioCodingModuleImpl::SetVAD(bool enable_dtx,
1496 CriticalSectionScoped lock(acm_crit_sect_);
1497 return SetVADSafe(enable_dtx, enable_vad, mode);
1500 int AudioCodingModuleImpl::SetVADSafe(bool enable_dtx,
1503 // Sanity check of the mode.
1504 if ((mode != VADNormal) && (mode != VADLowBitrate)
1505 && (mode != VADAggr) && (mode != VADVeryAggr)) {
1506 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1507 "Invalid VAD Mode %d, no change is made to VAD/DTX status",
1512 // Check that the send codec is mono. We don't support VAD/DTX for stereo
1514 if ((enable_dtx || enable_vad) && stereo_send_) {
1515 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1516 "VAD/DTX not supported for stereo sending");
1517 dtx_enabled_ = false;
1518 vad_enabled_ = false;
1523 // We don't support VAD/DTX when dual-streaming is enabled, i.e.
1524 // secondary-encoder is registered.
1525 if ((enable_dtx || enable_vad) && secondary_encoder_.get() != NULL) {
1526 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1527 "VAD/DTX not supported when dual-streaming is enabled.");
1528 dtx_enabled_ = false;
1529 vad_enabled_ = false;
1534 // Store VAD/DTX settings. Values can be changed in the call to "SetVAD"
1536 dtx_enabled_ = enable_dtx;
1537 vad_enabled_ = enable_vad;
1540 // If a send codec is registered, set VAD/DTX for the codec.
1541 if (HaveValidEncoder("SetVAD") && codecs_[current_send_codec_idx_]->SetVAD(
1542 &dtx_enabled_, &vad_enabled_, &vad_mode_) < 0) {
1544 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1546 vad_enabled_ = false;
1547 dtx_enabled_ = false;
1553 // Get VAD/DTX settings.
1554 int AudioCodingModuleImpl::VAD(bool* dtx_enabled, bool* vad_enabled,
1555 ACMVADMode* mode) const {
1556 CriticalSectionScoped lock(acm_crit_sect_);
1558 *dtx_enabled = dtx_enabled_;
1559 *vad_enabled = vad_enabled_;
1565 /////////////////////////////////////////
1569 int AudioCodingModuleImpl::InitializeReceiver() {
1570 CriticalSectionScoped lock(acm_crit_sect_);
1571 return InitializeReceiverSafe();
1574 // Initialize receiver, resets codec database etc.
1575 int AudioCodingModuleImpl::InitializeReceiverSafe() {
1576 // If the receiver is already initialized then we want to destroy any
1577 // existing decoders. After a call to this function, we should have a clean
1579 if (receiver_initialized_) {
1580 if (receiver_.RemoveAllCodecs() < 0)
1583 receiver_.set_id(id_);
1584 receiver_.ResetInitialDelay();
1585 receiver_.SetMinimumDelay(0);
1586 receiver_.SetMaximumDelay(0);
1587 receiver_.FlushBuffers();
1589 // Register RED and CN.
1590 for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) {
1591 if (IsCodecRED(i) || IsCodecCN(i)) {
1592 uint8_t pl_type = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
1593 if (receiver_.AddCodec(i, pl_type, 1, NULL) < 0) {
1594 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1595 "Cannot register master codec.");
1600 receiver_initialized_ = true;
1604 // TODO(turajs): If NetEq opens an API for reseting the state of decoders then
1605 // implement this method. Otherwise it should be removed. I might be that by
1606 // removing and registering a decoder we can achieve the effect of resetting.
1607 // Reset the decoder state.
1608 int AudioCodingModuleImpl::ResetDecoder() {
1612 // Get current receive frequency.
1613 int AudioCodingModuleImpl::ReceiveFrequency() const {
1614 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1615 "ReceiveFrequency()");
1617 CriticalSectionScoped lock(acm_crit_sect_);
1619 int codec_id = receiver_.last_audio_codec_id();
1621 return codec_id < 0 ? receiver_.current_sample_rate_hz() :
1622 ACMCodecDB::database_[codec_id].plfreq;
1625 // Get current playout frequency.
1626 int AudioCodingModuleImpl::PlayoutFrequency() const {
1627 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
1628 "PlayoutFrequency()");
1630 CriticalSectionScoped lock(acm_crit_sect_);
1632 return receiver_.current_sample_rate_hz();
1635 // Register possible receive codecs, can be called multiple times,
1636 // for codecs, CNG (NB, WB and SWB), DTMF, RED.
1637 int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) {
1638 CriticalSectionScoped lock(acm_crit_sect_);
1640 if (codec.channels > 2 || codec.channels < 0) {
1641 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1642 "Unsupported number of channels, %d.", codec.channels);
1646 // TODO(turajs) do we need this for NetEq 4?
1647 if (!receiver_initialized_) {
1648 if (InitializeReceiverSafe() < 0) {
1649 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1650 "Cannot initialize receiver, failed registering codec.");
1656 int codec_id = ACMCodecDB::ReceiverCodecNumber(codec, &mirror_id);
1658 if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) {
1659 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1660 "Wrong codec params to be registered as receive codec");
1664 // Check if the payload-type is valid.
1665 if (!ACMCodecDB::ValidPayloadType(codec.pltype)) {
1666 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1667 "Invalid payload-type %d for %s.", codec.pltype,
1672 AudioDecoder* decoder = NULL;
1673 // Get |decoder| associated with |codec|. |decoder| can be NULL if |codec|
1674 // does not own its decoder.
1675 if (GetAudioDecoder(codec, codec_id, mirror_id, &decoder) < 0) {
1676 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1677 "Wrong codec params to be registered as receive codec");
1680 uint8_t payload_type = static_cast<uint8_t>(codec.pltype);
1681 return receiver_.AddCodec(codec_id, payload_type, codec.channels, decoder);
1684 // Get current received codec.
1685 int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const {
1686 return receiver_.LastAudioCodec(current_codec);
1689 // Incoming packet from network parsed and ready for decode.
1690 int AudioCodingModuleImpl::IncomingPacket(const uint8_t* incoming_payload,
1691 const int payload_length,
1692 const WebRtcRTPHeader& rtp_header) {
1693 if (payload_length < 0) {
1694 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1695 "IncomingPacket() Error, payload-length cannot be negative");
1698 int last_audio_pltype = receiver_.last_audio_payload_type();
1699 if (receiver_.InsertPacket(rtp_header, incoming_payload, payload_length) <
1703 if (receiver_.last_audio_payload_type() != last_audio_pltype) {
1704 int index = receiver_.last_audio_codec_id();
1706 CriticalSectionScoped lock(acm_crit_sect_);
1708 // |codec_[index]| might not be even created, simply because it is not
1709 // yet registered as send codec. Even if it is registered, unless the
1710 // codec shares same instance for encoder and decoder, this call is
1712 if (codecs_[index] != NULL)
1713 codecs_[index]->UpdateDecoderSampFreq(index);
1718 // Minimum playout delay (Used for lip-sync).
1719 int AudioCodingModuleImpl::SetMinimumPlayoutDelay(int time_ms) {
1720 if ((time_ms < 0) || (time_ms > 10000)) {
1721 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1722 "Delay must be in the range of 0-1000 milliseconds.");
1725 return receiver_.SetMinimumDelay(time_ms);
1728 int AudioCodingModuleImpl::SetMaximumPlayoutDelay(int time_ms) {
1729 if ((time_ms < 0) || (time_ms > 10000)) {
1730 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1731 "Delay must be in the range of 0-1000 milliseconds.");
1734 return receiver_.SetMaximumDelay(time_ms);
1737 // Estimate the Bandwidth based on the incoming stream, needed for one way
1738 // audio where the RTCP send the BW estimate.
1739 // This is also done in the RTP module.
1740 int AudioCodingModuleImpl::DecoderEstimatedBandwidth() const {
1741 // We can estimate far-end to near-end bandwidth if the iSAC are sent. Check
1742 // if the last received packets were iSAC packet then retrieve the bandwidth.
1743 int last_audio_codec_id = receiver_.last_audio_codec_id();
1744 if (last_audio_codec_id >= 0 &&
1745 STR_CASE_CMP("ISAC", ACMCodecDB::database_[last_audio_codec_id].plname)) {
1746 CriticalSectionScoped lock(acm_crit_sect_);
1747 return codecs_[last_audio_codec_id]->GetEstimatedBandwidth();
1752 // Set playout mode for: voice, fax, streaming or off.
1753 int AudioCodingModuleImpl::SetPlayoutMode(AudioPlayoutMode mode) {
1754 receiver_.SetPlayoutMode(mode);
1755 return 0; // TODO(turajs): return value is for backward compatibility.
1758 // Get playout mode voice, fax, streaming or off.
1759 AudioPlayoutMode AudioCodingModuleImpl::PlayoutMode() const {
1760 return receiver_.PlayoutMode();
1763 // Get 10 milliseconds of raw audio data to play out.
1764 // Automatic resample to the requested frequency.
1765 int AudioCodingModuleImpl::PlayoutData10Ms(int desired_freq_hz,
1766 AudioFrame* audio_frame) {
1767 // GetAudio always returns 10 ms, at the requested sample rate.
1768 if (receiver_.GetAudio(desired_freq_hz, audio_frame) != 0) {
1769 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1770 "PlayoutData failed, RecOut Failed");
1774 audio_frame->id_ = id_;
1778 /////////////////////////////////////////
1782 // TODO(turajs) change the return value to void. Also change the corresponding
1784 int AudioCodingModuleImpl::NetworkStatistics(ACMNetworkStatistics* statistics) {
1785 receiver_.NetworkStatistics(statistics);
1789 void AudioCodingModuleImpl::DestructEncoderInst(void* inst) {
1790 CriticalSectionScoped lock(acm_crit_sect_);
1791 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, id_,
1792 "DestructEncoderInst()");
1793 if (!HaveValidEncoder("DestructEncoderInst"))
1795 codecs_[current_send_codec_idx_]->DestructEncoderInst(inst);
1798 int AudioCodingModuleImpl::RegisterVADCallback(ACMVADCallback* vad_callback) {
1799 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, id_,
1800 "RegisterVADCallback()");
1801 CriticalSectionScoped lock(callback_crit_sect_);
1802 vad_callback_ = vad_callback;
1806 // TODO(tlegrand): Modify this function to work for stereo, and add tests.
1807 int AudioCodingModuleImpl::IncomingPayload(const uint8_t* incoming_payload,
1809 uint8_t payload_type,
1810 uint32_t timestamp) {
1811 if (payload_length < 0) {
1812 // Log error in trace file.
1813 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1814 "IncomingPacket() Error, payload-length cannot be negative");
1818 // We are not acquiring any lock when interacting with |aux_rtp_header_| no
1819 // other method uses this member variable.
1820 if (aux_rtp_header_ == NULL) {
1821 // This is the first time that we are using |dummy_rtp_header_|
1822 // so we have to create it.
1823 aux_rtp_header_ = new WebRtcRTPHeader;
1824 aux_rtp_header_->header.payloadType = payload_type;
1825 // Don't matter in this case.
1826 aux_rtp_header_->header.ssrc = 0;
1827 aux_rtp_header_->header.markerBit = false;
1828 // Start with random numbers.
1829 aux_rtp_header_->header.sequenceNumber = 0x1234; // Arbitrary.
1830 aux_rtp_header_->type.Audio.channel = 1;
1833 aux_rtp_header_->header.timestamp = timestamp;
1834 IncomingPacket(incoming_payload, payload_length, *aux_rtp_header_);
1835 // Get ready for the next payload.
1836 aux_rtp_header_->header.sequenceNumber++;
1840 int AudioCodingModuleImpl::ReplaceInternalDTXWithWebRtc(bool use_webrtc_dtx) {
1841 CriticalSectionScoped lock(acm_crit_sect_);
1843 if (!HaveValidEncoder("ReplaceInternalDTXWithWebRtc")) {
1845 webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1846 "Cannot replace codec internal DTX when no send codec is registered.");
1850 int res = codecs_[current_send_codec_idx_]->ReplaceInternalDTX(
1852 // Check if VAD is turned on, or if there is any error.
1854 vad_enabled_ = true;
1855 } else if (res < 0) {
1856 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1857 "Failed to set ReplaceInternalDTXWithWebRtc(%d)",
1865 int AudioCodingModuleImpl::IsInternalDTXReplacedWithWebRtc(
1866 bool* uses_webrtc_dtx) {
1867 CriticalSectionScoped lock(acm_crit_sect_);
1869 if (!HaveValidEncoder("IsInternalDTXReplacedWithWebRtc")) {
1872 if (codecs_[current_send_codec_idx_]->IsInternalDTXReplaced(uses_webrtc_dtx)
1879 int AudioCodingModuleImpl::SetISACMaxRate(int max_bit_per_sec) {
1880 CriticalSectionScoped lock(acm_crit_sect_);
1882 if (!HaveValidEncoder("SetISACMaxRate")) {
1886 return codecs_[current_send_codec_idx_]->SetISACMaxRate(max_bit_per_sec);
1889 int AudioCodingModuleImpl::SetISACMaxPayloadSize(int max_size_bytes) {
1890 CriticalSectionScoped lock(acm_crit_sect_);
1892 if (!HaveValidEncoder("SetISACMaxPayloadSize")) {
1896 return codecs_[current_send_codec_idx_]->SetISACMaxPayloadSize(
1900 int AudioCodingModuleImpl::ConfigISACBandwidthEstimator(
1902 int rate_bit_per_sec,
1903 bool enforce_frame_size) {
1904 CriticalSectionScoped lock(acm_crit_sect_);
1906 if (!HaveValidEncoder("ConfigISACBandwidthEstimator")) {
1910 return codecs_[current_send_codec_idx_]->ConfigISACBandwidthEstimator(
1911 frame_size_ms, rate_bit_per_sec, enforce_frame_size);
1914 // Informs Opus encoder about the maximum audio bandwidth needs to be encoded.
1915 int AudioCodingModuleImpl::SetOpusMaxBandwidth(int bandwidth_hz) {
1916 CriticalSectionScoped lock(acm_crit_sect_);
1917 if (!HaveValidEncoder("SetOpusMaxBandwidth")) {
1920 return codecs_[current_send_codec_idx_]->SetOpusMaxBandwidth(bandwidth_hz);
1923 int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
1924 return receiver_.GetPlayoutTimestamp(timestamp) ? 0 : -1;
1927 bool AudioCodingModuleImpl::HaveValidEncoder(const char* caller_name) const {
1928 if ((!send_codec_registered_) || (current_send_codec_idx_ < 0) ||
1929 (current_send_codec_idx_ >= ACMCodecDB::kNumCodecs)) {
1930 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1931 "%s failed: No send codec is registered.", caller_name);
1934 if ((current_send_codec_idx_ < 0) ||
1935 (current_send_codec_idx_ >= ACMCodecDB::kNumCodecs)) {
1936 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1937 "%s failed: Send codec index out of range.", caller_name);
1940 if (codecs_[current_send_codec_idx_] == NULL) {
1941 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1942 "%s failed: Send codec is NULL pointer.", caller_name);
1948 int AudioCodingModuleImpl::UnregisterReceiveCodec(uint8_t payload_type) {
1949 return receiver_.RemoveCodec(payload_type);
1952 // TODO(turajs): correct the type of |length_bytes| when it is corrected in
1954 int AudioCodingModuleImpl::REDPayloadISAC(int isac_rate,
1955 int isac_bw_estimate,
1957 int16_t* length_bytes) {
1958 CriticalSectionScoped lock(acm_crit_sect_);
1959 if (!HaveValidEncoder("EncodeData")) {
1963 status = codecs_[current_send_codec_idx_]->REDPayloadISAC(isac_rate,
1970 void AudioCodingModuleImpl::ResetFragmentation(int vector_size) {
1971 for (int n = 0; n < kMaxNumFragmentationVectors; n++) {
1972 fragmentation_.fragmentationOffset[n] = n * MAX_PAYLOAD_SIZE_BYTE;
1974 memset(fragmentation_.fragmentationLength, 0, kMaxNumFragmentationVectors *
1975 sizeof(fragmentation_.fragmentationLength[0]));
1976 memset(fragmentation_.fragmentationTimeDiff, 0, kMaxNumFragmentationVectors *
1977 sizeof(fragmentation_.fragmentationTimeDiff[0]));
1978 memset(fragmentation_.fragmentationPlType,
1980 kMaxNumFragmentationVectors *
1981 sizeof(fragmentation_.fragmentationPlType[0]));
1982 fragmentation_.fragmentationVectorSize = static_cast<uint16_t>(vector_size);
1985 int AudioCodingModuleImpl::GetAudioDecoder(const CodecInst& codec, int codec_id,
1987 AudioDecoder** decoder) {
1988 if (ACMCodecDB::OwnsDecoder(codec_id)) {
1989 // This codec has to own its own decoder. Therefore, it should create the
1990 // corresponding AudioDecoder class and insert it into NetEq. If the codec
1991 // does not exist create it.
1993 // TODO(turajs): this part of the code is common with RegisterSendCodec(),
1994 // make a method for it.
1995 if (codecs_[mirror_id] == NULL) {
1996 codecs_[mirror_id] = CreateCodec(codec);
1997 if (codecs_[mirror_id] == NULL) {
1998 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
1999 "Cannot Create the codec");
2002 mirror_codec_idx_[mirror_id] = mirror_id;
2005 if (mirror_id != codec_id) {
2006 codecs_[codec_id] = codecs_[mirror_id];
2007 mirror_codec_idx_[codec_id] = mirror_id;
2009 *decoder = codecs_[codec_id]->Decoder(codec_id);
2021 int AudioCodingModuleImpl::SetInitialPlayoutDelay(int delay_ms) {
2023 CriticalSectionScoped lock(acm_crit_sect_);
2024 // Initialize receiver, if it is not initialized. Otherwise, initial delay
2025 // is reset upon initialization of the receiver.
2026 if (!receiver_initialized_)
2027 InitializeReceiverSafe();
2029 return receiver_.SetInitialDelay(delay_ms);
2032 int AudioCodingModuleImpl::EnableNack(size_t max_nack_list_size) {
2033 return receiver_.EnableNack(max_nack_list_size);
2036 void AudioCodingModuleImpl::DisableNack() {
2037 receiver_.DisableNack();
2040 std::vector<uint16_t> AudioCodingModuleImpl::GetNackList(
2041 int round_trip_time_ms) const {
2042 return receiver_.GetNackList(round_trip_time_ms);
2045 int AudioCodingModuleImpl::LeastRequiredDelayMs() const {
2046 return receiver_.LeastRequiredDelayMs();
2049 void AudioCodingModuleImpl::GetDecodingCallStatistics(
2050 AudioDecodingCallStats* call_stats) const {
2051 receiver_.GetDecodingCallStatistics(call_stats);
2056 } // namespace webrtc