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 = [¶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
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