1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/modules/audio_coding/acm2/codec_manager.h" 12 13 #include "webrtc/base/checks.h" 14 #include "webrtc/base/format_macros.h" 15 #include "webrtc/engine_configurations.h" 16 #include "webrtc/modules/audio_coding/acm2/rent_a_codec.h" 17 #include "webrtc/system_wrappers/include/trace.h" 18 19 namespace webrtc { 20 namespace acm2 { 21 22 namespace { 23 24 // Check if the given codec is a valid to be registered as send codec. 25 int IsValidSendCodec(const CodecInst& send_codec) { 26 int dummy_id = 0; 27 if ((send_codec.channels != 1) && (send_codec.channels != 2)) { 28 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, 29 "Wrong number of channels (%" PRIuS ", only mono and stereo " 30 "are supported)", 31 send_codec.channels); 32 return -1; 33 } 34 35 auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec); 36 if (!maybe_codec_id) { 37 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, 38 "Invalid codec setting for the send codec."); 39 return -1; 40 } 41 42 // Telephone-event cannot be a send codec. 43 if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { 44 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, 45 "telephone-event cannot be a send codec"); 46 return -1; 47 } 48 49 if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels) 50 .value_or(false)) { 51 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, 52 "%" PRIuS " number of channels not supportedn for %s.", 53 send_codec.channels, send_codec.plname); 54 return -1; 55 } 56 return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1); 57 } 58 59 bool IsOpus(const CodecInst& codec) { 60 return 61 #ifdef WEBRTC_CODEC_OPUS 62 !STR_CASE_CMP(codec.plname, "opus") || 63 #endif 64 false; 65 } 66 67 } // namespace 68 69 CodecManager::CodecManager() { 70 thread_checker_.DetachFromThread(); 71 } 72 73 CodecManager::~CodecManager() = default; 74 75 bool CodecManager::RegisterEncoder(const CodecInst& send_codec) { 76 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 77 int codec_id = IsValidSendCodec(send_codec); 78 79 // Check for reported errors from function IsValidSendCodec(). 80 if (codec_id < 0) { 81 return false; 82 } 83 84 int dummy_id = 0; 85 switch (RentACodec::RegisterRedPayloadType( 86 &codec_stack_params_.red_payload_types, send_codec)) { 87 case RentACodec::RegistrationResult::kOk: 88 return true; 89 case RentACodec::RegistrationResult::kBadFreq: 90 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, 91 "RegisterSendCodec() failed, invalid frequency for RED" 92 " registration"); 93 return false; 94 case RentACodec::RegistrationResult::kSkip: 95 break; 96 } 97 switch (RentACodec::RegisterCngPayloadType( 98 &codec_stack_params_.cng_payload_types, send_codec)) { 99 case RentACodec::RegistrationResult::kOk: 100 return true; 101 case RentACodec::RegistrationResult::kBadFreq: 102 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, 103 "RegisterSendCodec() failed, invalid frequency for CNG" 104 " registration"); 105 return false; 106 case RentACodec::RegistrationResult::kSkip: 107 break; 108 } 109 110 if (IsOpus(send_codec)) { 111 // VAD/DTX not supported. 112 codec_stack_params_.use_cng = false; 113 } 114 115 send_codec_inst_ = rtc::Optional<CodecInst>(send_codec); 116 codec_stack_params_.speech_encoder = nullptr; // Caller must recreate it. 117 return true; 118 } 119 120 CodecInst CodecManager::ForgeCodecInst( 121 const AudioEncoder* external_speech_encoder) { 122 CodecInst ci; 123 ci.channels = external_speech_encoder->NumChannels(); 124 ci.plfreq = external_speech_encoder->SampleRateHz(); 125 ci.pacsize = rtc::CheckedDivExact( 126 static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() * 127 ci.plfreq), 128 100); 129 ci.pltype = -1; // Not valid. 130 ci.rate = -1; // Not valid. 131 static const char kName[] = "external"; 132 memcpy(ci.plname, kName, sizeof(kName)); 133 return ci; 134 } 135 136 bool CodecManager::SetCopyRed(bool enable) { 137 if (enable && codec_stack_params_.use_codec_fec) { 138 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, 139 "Codec internal FEC and RED cannot be co-enabled."); 140 return false; 141 } 142 if (enable && send_codec_inst_ && 143 codec_stack_params_.red_payload_types.count(send_codec_inst_->plfreq) < 144 1) { 145 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, 146 "Cannot enable RED at %i Hz.", send_codec_inst_->plfreq); 147 return false; 148 } 149 codec_stack_params_.use_red = enable; 150 return true; 151 } 152 153 bool CodecManager::SetVAD(bool enable, ACMVADMode mode) { 154 // Sanity check of the mode. 155 RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr || 156 mode == VADVeryAggr); 157 158 // Check that the send codec is mono. We don't support VAD/DTX for stereo 159 // sending. 160 const bool stereo_send = 161 codec_stack_params_.speech_encoder 162 ? (codec_stack_params_.speech_encoder->NumChannels() != 1) 163 : false; 164 if (enable && stereo_send) { 165 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, 166 "VAD/DTX not supported for stereo sending"); 167 return false; 168 } 169 170 // TODO(kwiberg): This doesn't protect Opus when injected as an external 171 // encoder. 172 if (send_codec_inst_ && IsOpus(*send_codec_inst_)) { 173 // VAD/DTX not supported, but don't fail. 174 enable = false; 175 } 176 177 codec_stack_params_.use_cng = enable; 178 codec_stack_params_.vad_mode = mode; 179 return true; 180 } 181 182 bool CodecManager::SetCodecFEC(bool enable_codec_fec) { 183 if (enable_codec_fec && codec_stack_params_.use_red) { 184 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, 185 "Codec internal FEC and RED cannot be co-enabled."); 186 return false; 187 } 188 189 codec_stack_params_.use_codec_fec = enable_codec_fec; 190 return true; 191 } 192 193 } // namespace acm2 194 } // namespace webrtc 195