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