diff options
Diffstat (limited to 'webrtc/modules/audio_coding/acm2/codec_manager.cc')
-rw-r--r-- | webrtc/modules/audio_coding/acm2/codec_manager.cc | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/webrtc/modules/audio_coding/acm2/codec_manager.cc b/webrtc/modules/audio_coding/acm2/codec_manager.cc new file mode 100644 index 0000000000..ad67377d42 --- /dev/null +++ b/webrtc/modules/audio_coding/acm2/codec_manager.cc @@ -0,0 +1,194 @@ +/* + * 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/acm2/codec_manager.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/format_macros.h" +#include "webrtc/engine_configurations.h" +#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h" +#include "webrtc/system_wrappers/include/trace.h" + +namespace webrtc { +namespace acm2 { + +namespace { + +// Check if the given codec is a valid to be registered as send codec. +int IsValidSendCodec(const CodecInst& send_codec) { + int dummy_id = 0; + if ((send_codec.channels != 1) && (send_codec.channels != 2)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Wrong number of channels (%" PRIuS ", only mono and stereo " + "are supported)", + send_codec.channels); + return -1; + } + + auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec); + if (!maybe_codec_id) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Invalid codec setting for the send codec."); + return -1; + } + + // Telephone-event cannot be a send codec. + if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "telephone-event cannot be a send codec"); + return -1; + } + + if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels) + .value_or(false)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "%" PRIuS " number of channels not supportedn for %s.", + send_codec.channels, send_codec.plname); + return -1; + } + return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1); +} + +bool IsOpus(const CodecInst& codec) { + return +#ifdef WEBRTC_CODEC_OPUS + !STR_CASE_CMP(codec.plname, "opus") || +#endif + false; +} + +} // namespace + +CodecManager::CodecManager() { + thread_checker_.DetachFromThread(); +} + +CodecManager::~CodecManager() = default; + +bool CodecManager::RegisterEncoder(const CodecInst& send_codec) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + int codec_id = IsValidSendCodec(send_codec); + + // Check for reported errors from function IsValidSendCodec(). + if (codec_id < 0) { + return false; + } + + int dummy_id = 0; + switch (RentACodec::RegisterRedPayloadType( + &codec_stack_params_.red_payload_types, send_codec)) { + case RentACodec::RegistrationResult::kOk: + return true; + case RentACodec::RegistrationResult::kBadFreq: + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "RegisterSendCodec() failed, invalid frequency for RED" + " registration"); + return false; + case RentACodec::RegistrationResult::kSkip: + break; + } + switch (RentACodec::RegisterCngPayloadType( + &codec_stack_params_.cng_payload_types, send_codec)) { + case RentACodec::RegistrationResult::kOk: + return true; + case RentACodec::RegistrationResult::kBadFreq: + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "RegisterSendCodec() failed, invalid frequency for CNG" + " registration"); + return false; + case RentACodec::RegistrationResult::kSkip: + break; + } + + if (IsOpus(send_codec)) { + // VAD/DTX not supported. + codec_stack_params_.use_cng = false; + } + + send_codec_inst_ = rtc::Optional<CodecInst>(send_codec); + codec_stack_params_.speech_encoder = nullptr; // Caller must recreate it. + return true; +} + +CodecInst CodecManager::ForgeCodecInst( + const AudioEncoder* external_speech_encoder) { + CodecInst ci; + ci.channels = external_speech_encoder->NumChannels(); + ci.plfreq = external_speech_encoder->SampleRateHz(); + ci.pacsize = rtc::CheckedDivExact( + static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() * + ci.plfreq), + 100); + ci.pltype = -1; // Not valid. + ci.rate = -1; // Not valid. + static const char kName[] = "external"; + memcpy(ci.plname, kName, sizeof(kName)); + return ci; +} + +bool CodecManager::SetCopyRed(bool enable) { + if (enable && codec_stack_params_.use_codec_fec) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, + "Codec internal FEC and RED cannot be co-enabled."); + return false; + } + if (enable && send_codec_inst_ && + codec_stack_params_.red_payload_types.count(send_codec_inst_->plfreq) < + 1) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, + "Cannot enable RED at %i Hz.", send_codec_inst_->plfreq); + return false; + } + codec_stack_params_.use_red = enable; + return true; +} + +bool CodecManager::SetVAD(bool enable, ACMVADMode mode) { + // Sanity check of the mode. + RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr || + mode == VADVeryAggr); + + // Check that the send codec is mono. We don't support VAD/DTX for stereo + // sending. + const bool stereo_send = + codec_stack_params_.speech_encoder + ? (codec_stack_params_.speech_encoder->NumChannels() != 1) + : false; + if (enable && stereo_send) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "VAD/DTX not supported for stereo sending"); + return false; + } + + // TODO(kwiberg): This doesn't protect Opus when injected as an external + // encoder. + if (send_codec_inst_ && IsOpus(*send_codec_inst_)) { + // VAD/DTX not supported, but don't fail. + enable = false; + } + + codec_stack_params_.use_cng = enable; + codec_stack_params_.vad_mode = mode; + return true; +} + +bool CodecManager::SetCodecFEC(bool enable_codec_fec) { + if (enable_codec_fec && codec_stack_params_.use_red) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, + "Codec internal FEC and RED cannot be co-enabled."); + return false; + } + + codec_stack_params_.use_codec_fec = enable_codec_fec; + return true; +} + +} // namespace acm2 +} // namespace webrtc |