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 
CodecIdByParams(const char * payload_name,int sampling_freq_hz,size_t channels)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 
CodecInstById(CodecId codec_id)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 
CodecIdByInst(const CodecInst & codec_inst)59 rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByInst(
60     const CodecInst& codec_inst) {
61   return CodecIdFromIndex(ACMCodecDB::CodecNumber(codec_inst));
62 }
63 
CodecInstByParams(const char * payload_name,int sampling_freq_hz,size_t channels)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 
IsCodecValid(const CodecInst & codec_inst)81 bool RentACodec::IsCodecValid(const CodecInst& codec_inst) {
82   return ACMCodecDB::CodecNumber(codec_inst) >= 0;
83 }
84 
IsSupportedNumChannels(CodecId codec_id,size_t num_channels)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 
Database()94 rtc::ArrayView<const CodecInst> RentACodec::Database() {
95   return rtc::ArrayView<const CodecInst>(ACMCodecDB::database_,
96                                          NumberOfCodecs());
97 }
98 
NetEqDecoderFromCodecId(CodecId codec_id,size_t num_channels)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 
RegisterCngPayloadType(std::map<int,int> * pt_map,const CodecInst & codec_inst)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 
RegisterRedPayloadType(std::map<int,int> * pt_map,const CodecInst & codec_inst)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)
CreateEncoder(const CodecInst & speech_inst,LockedIsacBandwidthInfo * bwinfo)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 
CreateRedEncoder(AudioEncoder * encoder,int red_payload_type)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 
CreateCngEncoder(AudioEncoder * encoder,int payload_type,ACMVADMode vad_mode)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 
CreateIsacDecoder(LockedIsacBandwidthInfo * bwinfo)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 
RentEncoder(const CodecInst & codec_inst)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 
StackParameters()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 
RentEncoderStack(StackParameters * param)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 
RentIsacDecoder()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