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 |