/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/audio_coding/main/acm2/codec_owner.h" #include "webrtc/base/checks.h" #include "webrtc/engine_configurations.h" #include "webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h" #include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h" #include "webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h" #include "webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h" #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_isacfix.h" #include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_isac.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h" #include "webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h" #include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h" namespace webrtc { namespace acm2 { namespace { bool IsIsac(const CodecInst& codec) { return #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) !STR_CASE_CMP(codec.plname, "isac") || #endif false; } bool IsOpus(const CodecInst& codec) { return #ifdef WEBRTC_CODEC_OPUS !STR_CASE_CMP(codec.plname, "opus") || #endif false; } bool IsPcmU(const CodecInst& codec) { return !STR_CASE_CMP(codec.plname, "pcmu"); } bool IsPcmA(const CodecInst& codec) { return !STR_CASE_CMP(codec.plname, "pcma"); } bool IsPcm16B(const CodecInst& codec) { return #ifdef WEBRTC_CODEC_PCM16 !STR_CASE_CMP(codec.plname, "l16") || #endif false; } bool IsIlbc(const CodecInst& codec) { return #ifdef WEBRTC_CODEC_ILBC !STR_CASE_CMP(codec.plname, "ilbc") || #endif false; } bool IsG722(const CodecInst& codec) { return #ifdef WEBRTC_CODEC_G722 !STR_CASE_CMP(codec.plname, "g722") || #endif false; } } // namespace CodecOwner::CodecOwner() : isac_is_encoder_(false), external_speech_encoder_(nullptr) { } CodecOwner::~CodecOwner() = default; namespace { AudioEncoderDecoderMutableIsac* CreateIsacCodec(const CodecInst& speech_inst) { #if defined(WEBRTC_CODEC_ISACFX) return new AudioEncoderDecoderMutableIsacFix(speech_inst); #elif defined(WEBRTC_CODEC_ISAC) return new AudioEncoderDecoderMutableIsacFloat(speech_inst); #else FATAL() << "iSAC is not supported."; return nullptr; #endif } void CreateSpeechEncoder( const CodecInst& speech_inst, rtc::scoped_ptr* speech_encoder, rtc::scoped_ptr* isac_codec, bool* isac_is_encoder) { if (IsIsac(speech_inst)) { if (*isac_codec) { (*isac_codec)->UpdateSettings(speech_inst); } else { isac_codec->reset(CreateIsacCodec(speech_inst)); } *isac_is_encoder = true; speech_encoder->reset(); return; } if (IsOpus(speech_inst)) { speech_encoder->reset(new AudioEncoderMutableOpus(speech_inst)); } else if (IsPcmU(speech_inst)) { speech_encoder->reset(new AudioEncoderMutablePcmU(speech_inst)); } else if (IsPcmA(speech_inst)) { speech_encoder->reset(new AudioEncoderMutablePcmA(speech_inst)); } else if (IsPcm16B(speech_inst)) { speech_encoder->reset(new AudioEncoderMutablePcm16B(speech_inst)); } else if (IsIlbc(speech_inst)) { speech_encoder->reset(new AudioEncoderMutableIlbc(speech_inst)); } else if (IsG722(speech_inst)) { speech_encoder->reset(new AudioEncoderMutableG722(speech_inst)); } else { FATAL(); } *isac_is_encoder = false; } AudioEncoder* CreateRedEncoder(int red_payload_type, AudioEncoder* encoder, rtc::scoped_ptr* red_encoder) { if (red_payload_type == -1) { red_encoder->reset(); return encoder; } AudioEncoderCopyRed::Config config; config.payload_type = red_payload_type; config.speech_encoder = encoder; red_encoder->reset(new AudioEncoderCopyRed(config)); return red_encoder->get(); } void CreateCngEncoder(int cng_payload_type, ACMVADMode vad_mode, AudioEncoder* encoder, rtc::scoped_ptr* cng_encoder) { if (cng_payload_type == -1) { cng_encoder->reset(); return; } AudioEncoderCng::Config config; config.num_channels = encoder->NumChannels(); config.payload_type = cng_payload_type; config.speech_encoder = encoder; switch (vad_mode) { case VADNormal: config.vad_mode = Vad::kVadNormal; break; case VADLowBitrate: config.vad_mode = Vad::kVadLowBitrate; break; case VADAggr: config.vad_mode = Vad::kVadAggressive; break; case VADVeryAggr: config.vad_mode = Vad::kVadVeryAggressive; break; default: FATAL(); } cng_encoder->reset(new AudioEncoderCng(config)); } } // namespace void CodecOwner::SetEncoders(const CodecInst& speech_inst, int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { CreateSpeechEncoder(speech_inst, &speech_encoder_, &isac_codec_, &isac_is_encoder_); external_speech_encoder_ = nullptr; ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type); } void CodecOwner::SetEncoders(AudioEncoderMutable* external_speech_encoder, int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { external_speech_encoder_ = external_speech_encoder; speech_encoder_.reset(); isac_is_encoder_ = false; ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type); } void CodecOwner::ChangeCngAndRed(int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { AudioEncoderMutable* speech_encoder = SpeechEncoder(); if (cng_payload_type != -1 || red_payload_type != -1) { // The RED and CNG encoders need to be in sync with the speech encoder, so // reset the latter to ensure its buffer is empty. speech_encoder->Reset(); } AudioEncoder* encoder = CreateRedEncoder(red_payload_type, speech_encoder, &red_encoder_); CreateCngEncoder(cng_payload_type, vad_mode, encoder, &cng_encoder_); int num_true = !!speech_encoder_ + !!external_speech_encoder_ + isac_is_encoder_; DCHECK_EQ(num_true, 1); DCHECK(!isac_is_encoder_ || isac_codec_); } AudioDecoder* CodecOwner::GetIsacDecoder() { if (!isac_codec_) { DCHECK(!isac_is_encoder_); // None of the parameter values in |speech_inst| matter when the codec is // used only as a decoder. CodecInst speech_inst; speech_inst.plfreq = 16000; speech_inst.rate = -1; speech_inst.pacsize = 480; isac_codec_.reset(CreateIsacCodec(speech_inst)); } return isac_codec_.get(); } AudioEncoder* CodecOwner::Encoder() { const auto& const_this = *this; return const_cast(const_this.Encoder()); } const AudioEncoder* CodecOwner::Encoder() const { if (cng_encoder_) return cng_encoder_.get(); if (red_encoder_) return red_encoder_.get(); return SpeechEncoder(); } AudioEncoderMutable* CodecOwner::SpeechEncoder() { const auto& const_this = *this; return const_cast(const_this.SpeechEncoder()); } const AudioEncoderMutable* CodecOwner::SpeechEncoder() const { int num_true = !!speech_encoder_ + !!external_speech_encoder_ + isac_is_encoder_; DCHECK_GE(num_true, 0); DCHECK_LE(num_true, 1); if (external_speech_encoder_) return external_speech_encoder_; if (speech_encoder_) return speech_encoder_.get(); return isac_is_encoder_ ? isac_codec_.get() : nullptr; } } // namespace acm2 } // namespace webrtc