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/rent_a_codec.h" 12 13 #include <utility> 14 15 #include "webrtc/base/logging.h" 16 #include "webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h" 17 #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h" 18 #ifdef WEBRTC_CODEC_G722 19 #include "webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h" 20 #endif 21 #ifdef WEBRTC_CODEC_ILBC 22 #include "webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h" 23 #endif 24 #ifdef WEBRTC_CODEC_ISACFX 25 #include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_decoder_isacfix.h" 26 #include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h" 27 #endif 28 #ifdef WEBRTC_CODEC_ISAC 29 #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" 30 #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" 31 #endif 32 #ifdef WEBRTC_CODEC_OPUS 33 #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" 34 #endif 35 #include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" 36 #ifdef WEBRTC_CODEC_RED 37 #include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h" 38 #endif 39 #include "webrtc/modules/audio_coding/acm2/acm_codec_database.h" 40 #include "webrtc/modules/audio_coding/acm2/acm_common_defs.h" 41 42 namespace webrtc { 43 namespace acm2 { 44 45 rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByParams( 46 const char* payload_name, 47 int sampling_freq_hz, 48 size_t channels) { 49 return CodecIdFromIndex( 50 ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels)); 51 } 52 53 rtc::Optional<CodecInst> RentACodec::CodecInstById(CodecId codec_id) { 54 rtc::Optional<int> mi = CodecIndexFromId(codec_id); 55 return mi ? rtc::Optional<CodecInst>(Database()[*mi]) 56 : rtc::Optional<CodecInst>(); 57 } 58 59 rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByInst( 60 const CodecInst& codec_inst) { 61 return CodecIdFromIndex(ACMCodecDB::CodecNumber(codec_inst)); 62 } 63 64 rtc::Optional<CodecInst> RentACodec::CodecInstByParams(const char* payload_name, 65 int sampling_freq_hz, 66 size_t channels) { 67 rtc::Optional<CodecId> codec_id = 68 CodecIdByParams(payload_name, sampling_freq_hz, channels); 69 if (!codec_id) 70 return rtc::Optional<CodecInst>(); 71 rtc::Optional<CodecInst> ci = CodecInstById(*codec_id); 72 RTC_DCHECK(ci); 73 74 // Keep the number of channels from the function call. For most codecs it 75 // will be the same value as in default codec settings, but not for all. 76 ci->channels = channels; 77 78 return ci; 79 } 80 81 bool RentACodec::IsCodecValid(const CodecInst& codec_inst) { 82 return ACMCodecDB::CodecNumber(codec_inst) >= 0; 83 } 84 85 rtc::Optional<bool> RentACodec::IsSupportedNumChannels(CodecId codec_id, 86 size_t num_channels) { 87 auto i = CodecIndexFromId(codec_id); 88 return i ? rtc::Optional<bool>( 89 ACMCodecDB::codec_settings_[*i].channel_support >= 90 num_channels) 91 : rtc::Optional<bool>(); 92 } 93 94 rtc::ArrayView<const CodecInst> RentACodec::Database() { 95 return rtc::ArrayView<const CodecInst>(ACMCodecDB::database_, 96 NumberOfCodecs()); 97 } 98 99 rtc::Optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId( 100 CodecId codec_id, 101 size_t num_channels) { 102 rtc::Optional<int> i = CodecIndexFromId(codec_id); 103 if (!i) 104 return rtc::Optional<NetEqDecoder>(); 105 const NetEqDecoder ned = ACMCodecDB::neteq_decoders_[*i]; 106 return rtc::Optional<NetEqDecoder>( 107 (ned == NetEqDecoder::kDecoderOpus && num_channels == 2) 108 ? NetEqDecoder::kDecoderOpus_2ch 109 : ned); 110 } 111 112 RentACodec::RegistrationResult RentACodec::RegisterCngPayloadType( 113 std::map<int, int>* pt_map, 114 const CodecInst& codec_inst) { 115 if (STR_CASE_CMP(codec_inst.plname, "CN") != 0) 116 return RegistrationResult::kSkip; 117 switch (codec_inst.plfreq) { 118 case 8000: 119 case 16000: 120 case 32000: 121 case 48000: 122 (*pt_map)[codec_inst.plfreq] = codec_inst.pltype; 123 return RegistrationResult::kOk; 124 default: 125 return RegistrationResult::kBadFreq; 126 } 127 } 128 129 RentACodec::RegistrationResult RentACodec::RegisterRedPayloadType( 130 std::map<int, int>* pt_map, 131 const CodecInst& codec_inst) { 132 if (STR_CASE_CMP(codec_inst.plname, "RED") != 0) 133 return RegistrationResult::kSkip; 134 switch (codec_inst.plfreq) { 135 case 8000: 136 (*pt_map)[codec_inst.plfreq] = codec_inst.pltype; 137 return RegistrationResult::kOk; 138 default: 139 return RegistrationResult::kBadFreq; 140 } 141 } 142 143 namespace { 144 145 // Returns a new speech encoder, or null on error. 146 // TODO(kwiberg): Don't handle errors here (bug 5033) 147 rtc::scoped_ptr<AudioEncoder> CreateEncoder( 148 const CodecInst& speech_inst, 149 LockedIsacBandwidthInfo* bwinfo) { 150 #if defined(WEBRTC_CODEC_ISACFX) 151 if (STR_CASE_CMP(speech_inst.plname, "isac") == 0) 152 return rtc_make_scoped_ptr(new AudioEncoderIsacFix(speech_inst, bwinfo)); 153 #endif 154 #if defined(WEBRTC_CODEC_ISAC) 155 if (STR_CASE_CMP(speech_inst.plname, "isac") == 0) 156 return rtc_make_scoped_ptr(new AudioEncoderIsac(speech_inst, bwinfo)); 157 #endif 158 #ifdef WEBRTC_CODEC_OPUS 159 if (STR_CASE_CMP(speech_inst.plname, "opus") == 0) 160 return rtc_make_scoped_ptr(new AudioEncoderOpus(speech_inst)); 161 #endif 162 if (STR_CASE_CMP(speech_inst.plname, "pcmu") == 0) 163 return rtc_make_scoped_ptr(new AudioEncoderPcmU(speech_inst)); 164 if (STR_CASE_CMP(speech_inst.plname, "pcma") == 0) 165 return rtc_make_scoped_ptr(new AudioEncoderPcmA(speech_inst)); 166 if (STR_CASE_CMP(speech_inst.plname, "l16") == 0) 167 return rtc_make_scoped_ptr(new AudioEncoderPcm16B(speech_inst)); 168 #ifdef WEBRTC_CODEC_ILBC 169 if (STR_CASE_CMP(speech_inst.plname, "ilbc") == 0) 170 return rtc_make_scoped_ptr(new AudioEncoderIlbc(speech_inst)); 171 #endif 172 #ifdef WEBRTC_CODEC_G722 173 if (STR_CASE_CMP(speech_inst.plname, "g722") == 0) 174 return rtc_make_scoped_ptr(new AudioEncoderG722(speech_inst)); 175 #endif 176 LOG_F(LS_ERROR) << "Could not create encoder of type " << speech_inst.plname; 177 return rtc::scoped_ptr<AudioEncoder>(); 178 } 179 180 rtc::scoped_ptr<AudioEncoder> CreateRedEncoder(AudioEncoder* encoder, 181 int red_payload_type) { 182 #ifdef WEBRTC_CODEC_RED 183 AudioEncoderCopyRed::Config config; 184 config.payload_type = red_payload_type; 185 config.speech_encoder = encoder; 186 return rtc::scoped_ptr<AudioEncoder>(new AudioEncoderCopyRed(config)); 187 #else 188 return rtc::scoped_ptr<AudioEncoder>(); 189 #endif 190 } 191 192 rtc::scoped_ptr<AudioEncoder> CreateCngEncoder(AudioEncoder* encoder, 193 int payload_type, 194 ACMVADMode vad_mode) { 195 AudioEncoderCng::Config config; 196 config.num_channels = encoder->NumChannels(); 197 config.payload_type = payload_type; 198 config.speech_encoder = encoder; 199 switch (vad_mode) { 200 case VADNormal: 201 config.vad_mode = Vad::kVadNormal; 202 break; 203 case VADLowBitrate: 204 config.vad_mode = Vad::kVadLowBitrate; 205 break; 206 case VADAggr: 207 config.vad_mode = Vad::kVadAggressive; 208 break; 209 case VADVeryAggr: 210 config.vad_mode = Vad::kVadVeryAggressive; 211 break; 212 default: 213 FATAL(); 214 } 215 return rtc::scoped_ptr<AudioEncoder>(new AudioEncoderCng(config)); 216 } 217 218 rtc::scoped_ptr<AudioDecoder> CreateIsacDecoder( 219 LockedIsacBandwidthInfo* bwinfo) { 220 #if defined(WEBRTC_CODEC_ISACFX) 221 return rtc_make_scoped_ptr(new AudioDecoderIsacFix(bwinfo)); 222 #elif defined(WEBRTC_CODEC_ISAC) 223 return rtc_make_scoped_ptr(new AudioDecoderIsac(bwinfo)); 224 #else 225 FATAL() << "iSAC is not supported."; 226 return rtc::scoped_ptr<AudioDecoder>(); 227 #endif 228 } 229 230 } // namespace 231 232 RentACodec::RentACodec() = default; 233 RentACodec::~RentACodec() = default; 234 235 AudioEncoder* RentACodec::RentEncoder(const CodecInst& codec_inst) { 236 rtc::scoped_ptr<AudioEncoder> enc = 237 CreateEncoder(codec_inst, &isac_bandwidth_info_); 238 if (!enc) 239 return nullptr; 240 speech_encoder_ = std::move(enc); 241 return speech_encoder_.get(); 242 } 243 244 RentACodec::StackParameters::StackParameters() { 245 // Register the default payload types for RED and CNG. 246 for (const CodecInst& ci : RentACodec::Database()) { 247 RentACodec::RegisterCngPayloadType(&cng_payload_types, ci); 248 RentACodec::RegisterRedPayloadType(&red_payload_types, ci); 249 } 250 } 251 252 RentACodec::StackParameters::~StackParameters() = default; 253 254 AudioEncoder* RentACodec::RentEncoderStack(StackParameters* param) { 255 RTC_DCHECK(param->speech_encoder); 256 257 if (param->use_codec_fec) { 258 // Switch FEC on. On failure, remember that FEC is off. 259 if (!param->speech_encoder->SetFec(true)) 260 param->use_codec_fec = false; 261 } else { 262 // Switch FEC off. This shouldn't fail. 263 const bool success = param->speech_encoder->SetFec(false); 264 RTC_DCHECK(success); 265 } 266 267 auto pt = [¶m](const std::map<int, int>& m) { 268 auto it = m.find(param->speech_encoder->SampleRateHz()); 269 return it == m.end() ? rtc::Optional<int>() 270 : rtc::Optional<int>(it->second); 271 }; 272 auto cng_pt = pt(param->cng_payload_types); 273 param->use_cng = 274 param->use_cng && cng_pt && param->speech_encoder->NumChannels() == 1; 275 auto red_pt = pt(param->red_payload_types); 276 param->use_red = param->use_red && red_pt; 277 278 if (param->use_cng || param->use_red) { 279 // The RED and CNG encoders need to be in sync with the speech encoder, so 280 // reset the latter to ensure its buffer is empty. 281 param->speech_encoder->Reset(); 282 } 283 encoder_stack_ = param->speech_encoder; 284 if (param->use_red) { 285 red_encoder_ = CreateRedEncoder(encoder_stack_, *red_pt); 286 if (red_encoder_) 287 encoder_stack_ = red_encoder_.get(); 288 } else { 289 red_encoder_.reset(); 290 } 291 if (param->use_cng) { 292 cng_encoder_ = CreateCngEncoder(encoder_stack_, *cng_pt, param->vad_mode); 293 encoder_stack_ = cng_encoder_.get(); 294 } else { 295 cng_encoder_.reset(); 296 } 297 return encoder_stack_; 298 } 299 300 AudioDecoder* RentACodec::RentIsacDecoder() { 301 if (!isac_decoder_) 302 isac_decoder_ = CreateIsacDecoder(&isac_bandwidth_info_); 303 return isac_decoder_.get(); 304 } 305 306 } // namespace acm2 307 } // namespace webrtc 308