Home | History | Annotate | Download | only in acm2
      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 = [&param](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