| OLD | NEW |
| (Empty) |
| 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/main/acm2/codec_manager.h" | |
| 12 | |
| 13 #include "webrtc/base/checks.h" | |
| 14 #include "webrtc/engine_configurations.h" | |
| 15 #include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" | |
| 16 #include "webrtc/system_wrappers/include/trace.h" | |
| 17 | |
| 18 namespace webrtc { | |
| 19 namespace acm2 { | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 // Check if the given codec is a valid to be registered as send codec. | |
| 24 int IsValidSendCodec(const CodecInst& send_codec) { | |
| 25 int dummy_id = 0; | |
| 26 if ((send_codec.channels != 1) && (send_codec.channels != 2)) { | |
| 27 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
| 28 "Wrong number of channels (%d, only mono and stereo are " | |
| 29 "supported)", | |
| 30 send_codec.channels); | |
| 31 return -1; | |
| 32 } | |
| 33 | |
| 34 auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec); | |
| 35 if (!maybe_codec_id) { | |
| 36 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
| 37 "Invalid codec setting for the send codec."); | |
| 38 return -1; | |
| 39 } | |
| 40 | |
| 41 // Telephone-event cannot be a send codec. | |
| 42 if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { | |
| 43 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
| 44 "telephone-event cannot be a send codec"); | |
| 45 return -1; | |
| 46 } | |
| 47 | |
| 48 if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels) | |
| 49 .value_or(false)) { | |
| 50 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
| 51 "%d number of channels not supportedn for %s.", | |
| 52 send_codec.channels, send_codec.plname); | |
| 53 return -1; | |
| 54 } | |
| 55 return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1); | |
| 56 } | |
| 57 | |
| 58 bool IsIsac(const CodecInst& codec) { | |
| 59 return | |
| 60 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) | |
| 61 !STR_CASE_CMP(codec.plname, "isac") || | |
| 62 #endif | |
| 63 false; | |
| 64 } | |
| 65 | |
| 66 bool IsOpus(const CodecInst& codec) { | |
| 67 return | |
| 68 #ifdef WEBRTC_CODEC_OPUS | |
| 69 !STR_CASE_CMP(codec.plname, "opus") || | |
| 70 #endif | |
| 71 false; | |
| 72 } | |
| 73 | |
| 74 bool IsPcmU(const CodecInst& codec) { | |
| 75 return !STR_CASE_CMP(codec.plname, "pcmu"); | |
| 76 } | |
| 77 | |
| 78 bool IsPcmA(const CodecInst& codec) { | |
| 79 return !STR_CASE_CMP(codec.plname, "pcma"); | |
| 80 } | |
| 81 | |
| 82 bool IsPcm16B(const CodecInst& codec) { | |
| 83 return !STR_CASE_CMP(codec.plname, "l16"); | |
| 84 } | |
| 85 | |
| 86 bool IsIlbc(const CodecInst& codec) { | |
| 87 return | |
| 88 #ifdef WEBRTC_CODEC_ILBC | |
| 89 !STR_CASE_CMP(codec.plname, "ilbc") || | |
| 90 #endif | |
| 91 false; | |
| 92 } | |
| 93 | |
| 94 bool IsG722(const CodecInst& codec) { | |
| 95 return | |
| 96 #ifdef WEBRTC_CODEC_G722 | |
| 97 !STR_CASE_CMP(codec.plname, "g722") || | |
| 98 #endif | |
| 99 false; | |
| 100 } | |
| 101 | |
| 102 bool CodecSupported(const CodecInst& codec) { | |
| 103 return IsOpus(codec) || IsPcmU(codec) || IsPcmA(codec) || IsPcm16B(codec) || | |
| 104 IsIlbc(codec) || IsG722(codec) || IsIsac(codec); | |
| 105 } | |
| 106 | |
| 107 const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0}; | |
| 108 } // namespace | |
| 109 | |
| 110 CodecManager::CodecManager() | |
| 111 : send_codec_inst_(kEmptyCodecInst), encoder_is_opus_(false) { | |
| 112 thread_checker_.DetachFromThread(); | |
| 113 } | |
| 114 | |
| 115 CodecManager::~CodecManager() = default; | |
| 116 | |
| 117 int CodecManager::RegisterEncoder(const CodecInst& send_codec) { | |
| 118 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 119 int codec_id = IsValidSendCodec(send_codec); | |
| 120 | |
| 121 // Check for reported errors from function IsValidSendCodec(). | |
| 122 if (codec_id < 0) { | |
| 123 return -1; | |
| 124 } | |
| 125 | |
| 126 int dummy_id = 0; | |
| 127 switch (RentACodec::RegisterRedPayloadType( | |
| 128 &codec_stack_params_.red_payload_types, send_codec)) { | |
| 129 case RentACodec::RegistrationResult::kOk: | |
| 130 return 0; | |
| 131 case RentACodec::RegistrationResult::kBadFreq: | |
| 132 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
| 133 "RegisterSendCodec() failed, invalid frequency for RED" | |
| 134 " registration"); | |
| 135 return -1; | |
| 136 case RentACodec::RegistrationResult::kSkip: | |
| 137 break; | |
| 138 } | |
| 139 switch (RentACodec::RegisterCngPayloadType( | |
| 140 &codec_stack_params_.cng_payload_types, send_codec)) { | |
| 141 case RentACodec::RegistrationResult::kOk: | |
| 142 return 0; | |
| 143 case RentACodec::RegistrationResult::kBadFreq: | |
| 144 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
| 145 "RegisterSendCodec() failed, invalid frequency for CNG" | |
| 146 " registration"); | |
| 147 return -1; | |
| 148 case RentACodec::RegistrationResult::kSkip: | |
| 149 break; | |
| 150 } | |
| 151 | |
| 152 // Check if the codec is already registered as send codec. | |
| 153 bool new_codec = true; | |
| 154 if (CurrentEncoder()) { | |
| 155 auto new_codec_id = RentACodec::CodecIdByInst(send_codec_inst_); | |
| 156 RTC_DCHECK(new_codec_id); | |
| 157 auto old_codec_id = RentACodec::CodecIdFromIndex(codec_id); | |
| 158 new_codec = !old_codec_id || *new_codec_id != *old_codec_id; | |
| 159 } | |
| 160 | |
| 161 encoder_is_opus_ = IsOpus(send_codec); | |
| 162 | |
| 163 if (new_codec) { | |
| 164 // This is a new codec. Register it and return. | |
| 165 RTC_DCHECK(CodecSupported(send_codec)); | |
| 166 if (IsOpus(send_codec)) { | |
| 167 // VAD/DTX not supported. | |
| 168 codec_stack_params_.use_cng = false; | |
| 169 } | |
| 170 AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec); | |
| 171 if (!enc) | |
| 172 return -1; | |
| 173 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_); | |
| 174 RTC_DCHECK(CurrentEncoder()); | |
| 175 | |
| 176 send_codec_inst_ = send_codec; | |
| 177 return 0; | |
| 178 } | |
| 179 | |
| 180 // This is an existing codec; re-create it if any parameters have changed. | |
| 181 if (send_codec_inst_.plfreq != send_codec.plfreq || | |
| 182 send_codec_inst_.pacsize != send_codec.pacsize || | |
| 183 send_codec_inst_.channels != send_codec.channels) { | |
| 184 AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec); | |
| 185 if (!enc) | |
| 186 return -1; | |
| 187 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_); | |
| 188 RTC_DCHECK(CurrentEncoder()); | |
| 189 } | |
| 190 send_codec_inst_.plfreq = send_codec.plfreq; | |
| 191 send_codec_inst_.pacsize = send_codec.pacsize; | |
| 192 send_codec_inst_.channels = send_codec.channels; | |
| 193 send_codec_inst_.pltype = send_codec.pltype; | |
| 194 | |
| 195 // Check if a change in Rate is required. | |
| 196 if (send_codec.rate != send_codec_inst_.rate) { | |
| 197 CurrentEncoder()->SetTargetBitrate(send_codec.rate); | |
| 198 send_codec_inst_.rate = send_codec.rate; | |
| 199 } | |
| 200 | |
| 201 return 0; | |
| 202 } | |
| 203 | |
| 204 void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) { | |
| 205 // Make up a CodecInst. | |
| 206 send_codec_inst_.channels = external_speech_encoder->NumChannels(); | |
| 207 send_codec_inst_.plfreq = external_speech_encoder->SampleRateHz(); | |
| 208 send_codec_inst_.pacsize = rtc::CheckedDivExact( | |
| 209 static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() * | |
| 210 send_codec_inst_.plfreq), | |
| 211 100); | |
| 212 send_codec_inst_.pltype = -1; // Not valid. | |
| 213 send_codec_inst_.rate = -1; // Not valid. | |
| 214 static const char kName[] = "external"; | |
| 215 memcpy(send_codec_inst_.plname, kName, sizeof(kName)); | |
| 216 | |
| 217 rent_a_codec_.RentEncoderStack(external_speech_encoder, &codec_stack_params_); | |
| 218 } | |
| 219 | |
| 220 rtc::Optional<CodecInst> CodecManager::GetCodecInst() const { | |
| 221 int dummy_id = 0; | |
| 222 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, | |
| 223 "SendCodec()"); | |
| 224 | |
| 225 if (!CurrentEncoder()) { | |
| 226 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, | |
| 227 "SendCodec Failed, no codec is registered"); | |
| 228 return rtc::Optional<CodecInst>(); | |
| 229 } | |
| 230 return rtc::Optional<CodecInst>(send_codec_inst_); | |
| 231 } | |
| 232 | |
| 233 bool CodecManager::SetCopyRed(bool enable) { | |
| 234 if (enable && codec_stack_params_.use_codec_fec) { | |
| 235 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, | |
| 236 "Codec internal FEC and RED cannot be co-enabled."); | |
| 237 return false; | |
| 238 } | |
| 239 if (enable && | |
| 240 codec_stack_params_.red_payload_types.count(send_codec_inst_.plfreq) < | |
| 241 1) { | |
| 242 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, | |
| 243 "Cannot enable RED at %i Hz.", send_codec_inst_.plfreq); | |
| 244 return false; | |
| 245 } | |
| 246 if (codec_stack_params_.use_red != enable) { | |
| 247 codec_stack_params_.use_red = enable; | |
| 248 if (CurrentEncoder()) | |
| 249 rent_a_codec_.RentEncoderStack(rent_a_codec_.GetEncoder(), | |
| 250 &codec_stack_params_); | |
| 251 } | |
| 252 return true; | |
| 253 } | |
| 254 | |
| 255 int CodecManager::SetVAD(bool enable, ACMVADMode mode) { | |
| 256 // Sanity check of the mode. | |
| 257 RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr || | |
| 258 mode == VADVeryAggr); | |
| 259 | |
| 260 // Check that the send codec is mono. We don't support VAD/DTX for stereo | |
| 261 // sending. | |
| 262 auto* enc = rent_a_codec_.GetEncoder(); | |
| 263 const bool stereo_send = enc ? (enc->NumChannels() != 1) : false; | |
| 264 if (enable && stereo_send) { | |
| 265 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, | |
| 266 "VAD/DTX not supported for stereo sending"); | |
| 267 codec_stack_params_.use_cng = false; | |
| 268 return -1; | |
| 269 } | |
| 270 | |
| 271 // If a send codec is registered, set VAD/DTX for the codec. | |
| 272 if (IsOpus(send_codec_inst_)) { | |
| 273 // VAD/DTX not supported. | |
| 274 codec_stack_params_.use_cng = false; | |
| 275 return 0; | |
| 276 } | |
| 277 | |
| 278 if (codec_stack_params_.use_cng != enable || | |
| 279 codec_stack_params_.vad_mode != mode) { | |
| 280 codec_stack_params_.use_cng = enable; | |
| 281 codec_stack_params_.vad_mode = mode; | |
| 282 if (enc) | |
| 283 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_); | |
| 284 } | |
| 285 return 0; | |
| 286 } | |
| 287 | |
| 288 void CodecManager::VAD(bool* dtx_enabled, | |
| 289 bool* vad_enabled, | |
| 290 ACMVADMode* mode) const { | |
| 291 *dtx_enabled = *vad_enabled = codec_stack_params_.use_cng; | |
| 292 *mode = codec_stack_params_.vad_mode; | |
| 293 } | |
| 294 | |
| 295 int CodecManager::SetCodecFEC(bool enable_codec_fec) { | |
| 296 if (enable_codec_fec && codec_stack_params_.use_red) { | |
| 297 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, | |
| 298 "Codec internal FEC and RED cannot be co-enabled."); | |
| 299 return -1; | |
| 300 } | |
| 301 | |
| 302 RTC_CHECK(CurrentEncoder()); | |
| 303 codec_stack_params_.use_codec_fec = | |
| 304 CurrentEncoder()->SetFec(enable_codec_fec) && enable_codec_fec; | |
| 305 return codec_stack_params_.use_codec_fec == enable_codec_fec ? 0 : -1; | |
| 306 } | |
| 307 | |
| 308 AudioDecoder* CodecManager::GetAudioDecoder(const CodecInst& codec) { | |
| 309 return IsIsac(codec) ? rent_a_codec_.RentIsacDecoder() : nullptr; | |
| 310 } | |
| 311 | |
| 312 } // namespace acm2 | |
| 313 } // namespace webrtc | |
| OLD | NEW |