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/codec_manager.h" | |
12 | |
13 #include "webrtc/base/checks.h" | |
14 #include "webrtc/engine_configurations.h" | |
15 #include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" | |
16 #include "webrtc/system_wrappers/include/trace.h" | |
17 | |
18 namespace webrtc { | |
19 namespace acm2 { | |
20 | |
21 namespace { | |
22 | |
23 // Check if the given codec is a valid to be registered as send codec. | |
24 int IsValidSendCodec(const CodecInst& send_codec) { | |
25 int dummy_id = 0; | |
26 if ((send_codec.channels != 1) && (send_codec.channels != 2)) { | |
27 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
28 "Wrong number of channels (%d, only mono and stereo are " | |
29 "supported)", | |
30 send_codec.channels); | |
31 return -1; | |
32 } | |
33 | |
34 auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec); | |
35 if (!maybe_codec_id) { | |
36 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
37 "Invalid codec setting for the send codec."); | |
38 return -1; | |
39 } | |
40 | |
41 // Telephone-event cannot be a send codec. | |
42 if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { | |
43 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
44 "telephone-event cannot be a send codec"); | |
45 return -1; | |
46 } | |
47 | |
48 if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels) | |
49 .value_or(false)) { | |
50 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
51 "%d number of channels not supportedn for %s.", | |
52 send_codec.channels, send_codec.plname); | |
53 return -1; | |
54 } | |
55 return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1); | |
56 } | |
57 | |
58 bool IsIsac(const CodecInst& codec) { | |
59 return | |
60 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) | |
61 !STR_CASE_CMP(codec.plname, "isac") || | |
62 #endif | |
63 false; | |
64 } | |
65 | |
66 bool IsOpus(const CodecInst& codec) { | |
67 return | |
68 #ifdef WEBRTC_CODEC_OPUS | |
69 !STR_CASE_CMP(codec.plname, "opus") || | |
70 #endif | |
71 false; | |
72 } | |
73 | |
74 bool IsPcmU(const CodecInst& codec) { | |
75 return !STR_CASE_CMP(codec.plname, "pcmu"); | |
76 } | |
77 | |
78 bool IsPcmA(const CodecInst& codec) { | |
79 return !STR_CASE_CMP(codec.plname, "pcma"); | |
80 } | |
81 | |
82 bool IsPcm16B(const CodecInst& codec) { | |
83 return !STR_CASE_CMP(codec.plname, "l16"); | |
84 } | |
85 | |
86 bool IsIlbc(const CodecInst& codec) { | |
87 return | |
88 #ifdef WEBRTC_CODEC_ILBC | |
89 !STR_CASE_CMP(codec.plname, "ilbc") || | |
90 #endif | |
91 false; | |
92 } | |
93 | |
94 bool IsG722(const CodecInst& codec) { | |
95 return | |
96 #ifdef WEBRTC_CODEC_G722 | |
97 !STR_CASE_CMP(codec.plname, "g722") || | |
98 #endif | |
99 false; | |
100 } | |
101 | |
102 bool CodecSupported(const CodecInst& codec) { | |
103 return IsOpus(codec) || IsPcmU(codec) || IsPcmA(codec) || IsPcm16B(codec) || | |
104 IsIlbc(codec) || IsG722(codec) || IsIsac(codec); | |
105 } | |
106 | |
107 const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0}; | |
108 } // namespace | |
109 | |
110 CodecManager::CodecManager() | |
111 : send_codec_inst_(kEmptyCodecInst), encoder_is_opus_(false) { | |
112 thread_checker_.DetachFromThread(); | |
113 } | |
114 | |
115 CodecManager::~CodecManager() = default; | |
116 | |
117 int CodecManager::RegisterEncoder(const CodecInst& send_codec) { | |
118 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
119 int codec_id = IsValidSendCodec(send_codec); | |
120 | |
121 // Check for reported errors from function IsValidSendCodec(). | |
122 if (codec_id < 0) { | |
123 return -1; | |
124 } | |
125 | |
126 int dummy_id = 0; | |
127 switch (RentACodec::RegisterRedPayloadType( | |
128 &codec_stack_params_.red_payload_types, send_codec)) { | |
129 case RentACodec::RegistrationResult::kOk: | |
130 return 0; | |
131 case RentACodec::RegistrationResult::kBadFreq: | |
132 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
133 "RegisterSendCodec() failed, invalid frequency for RED" | |
134 " registration"); | |
135 return -1; | |
136 case RentACodec::RegistrationResult::kSkip: | |
137 break; | |
138 } | |
139 switch (RentACodec::RegisterCngPayloadType( | |
140 &codec_stack_params_.cng_payload_types, send_codec)) { | |
141 case RentACodec::RegistrationResult::kOk: | |
142 return 0; | |
143 case RentACodec::RegistrationResult::kBadFreq: | |
144 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, | |
145 "RegisterSendCodec() failed, invalid frequency for CNG" | |
146 " registration"); | |
147 return -1; | |
148 case RentACodec::RegistrationResult::kSkip: | |
149 break; | |
150 } | |
151 | |
152 // Check if the codec is already registered as send codec. | |
153 bool new_codec = true; | |
154 if (CurrentEncoder()) { | |
155 auto new_codec_id = RentACodec::CodecIdByInst(send_codec_inst_); | |
156 RTC_DCHECK(new_codec_id); | |
157 auto old_codec_id = RentACodec::CodecIdFromIndex(codec_id); | |
158 new_codec = !old_codec_id || *new_codec_id != *old_codec_id; | |
159 } | |
160 | |
161 encoder_is_opus_ = IsOpus(send_codec); | |
162 | |
163 if (new_codec) { | |
164 // This is a new codec. Register it and return. | |
165 RTC_DCHECK(CodecSupported(send_codec)); | |
166 if (IsOpus(send_codec)) { | |
167 // VAD/DTX not supported. | |
168 codec_stack_params_.use_cng = false; | |
169 } | |
170 AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec); | |
171 if (!enc) | |
172 return -1; | |
173 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_); | |
174 RTC_DCHECK(CurrentEncoder()); | |
175 | |
176 send_codec_inst_ = send_codec; | |
177 return 0; | |
178 } | |
179 | |
180 // This is an existing codec; re-create it if any parameters have changed. | |
181 if (send_codec_inst_.plfreq != send_codec.plfreq || | |
182 send_codec_inst_.pacsize != send_codec.pacsize || | |
183 send_codec_inst_.channels != send_codec.channels) { | |
184 AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec); | |
185 if (!enc) | |
186 return -1; | |
187 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_); | |
188 RTC_DCHECK(CurrentEncoder()); | |
189 } | |
190 send_codec_inst_.plfreq = send_codec.plfreq; | |
191 send_codec_inst_.pacsize = send_codec.pacsize; | |
192 send_codec_inst_.channels = send_codec.channels; | |
193 send_codec_inst_.pltype = send_codec.pltype; | |
194 | |
195 // Check if a change in Rate is required. | |
196 if (send_codec.rate != send_codec_inst_.rate) { | |
197 CurrentEncoder()->SetTargetBitrate(send_codec.rate); | |
198 send_codec_inst_.rate = send_codec.rate; | |
199 } | |
200 | |
201 return 0; | |
202 } | |
203 | |
204 void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) { | |
205 // Make up a CodecInst. | |
206 send_codec_inst_.channels = external_speech_encoder->NumChannels(); | |
207 send_codec_inst_.plfreq = external_speech_encoder->SampleRateHz(); | |
208 send_codec_inst_.pacsize = rtc::CheckedDivExact( | |
209 static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() * | |
210 send_codec_inst_.plfreq), | |
211 100); | |
212 send_codec_inst_.pltype = -1; // Not valid. | |
213 send_codec_inst_.rate = -1; // Not valid. | |
214 static const char kName[] = "external"; | |
215 memcpy(send_codec_inst_.plname, kName, sizeof(kName)); | |
216 | |
217 rent_a_codec_.RentEncoderStack(external_speech_encoder, &codec_stack_params_); | |
218 } | |
219 | |
220 rtc::Optional<CodecInst> CodecManager::GetCodecInst() const { | |
221 int dummy_id = 0; | |
222 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, | |
223 "SendCodec()"); | |
224 | |
225 if (!CurrentEncoder()) { | |
226 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, | |
227 "SendCodec Failed, no codec is registered"); | |
228 return rtc::Optional<CodecInst>(); | |
229 } | |
230 return rtc::Optional<CodecInst>(send_codec_inst_); | |
231 } | |
232 | |
233 bool CodecManager::SetCopyRed(bool enable) { | |
234 if (enable && codec_stack_params_.use_codec_fec) { | |
235 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, | |
236 "Codec internal FEC and RED cannot be co-enabled."); | |
237 return false; | |
238 } | |
239 if (enable && | |
240 codec_stack_params_.red_payload_types.count(send_codec_inst_.plfreq) < | |
241 1) { | |
242 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, | |
243 "Cannot enable RED at %i Hz.", send_codec_inst_.plfreq); | |
244 return false; | |
245 } | |
246 if (codec_stack_params_.use_red != enable) { | |
247 codec_stack_params_.use_red = enable; | |
248 if (CurrentEncoder()) | |
249 rent_a_codec_.RentEncoderStack(rent_a_codec_.GetEncoder(), | |
250 &codec_stack_params_); | |
251 } | |
252 return true; | |
253 } | |
254 | |
255 int CodecManager::SetVAD(bool enable, ACMVADMode mode) { | |
256 // Sanity check of the mode. | |
257 RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr || | |
258 mode == VADVeryAggr); | |
259 | |
260 // Check that the send codec is mono. We don't support VAD/DTX for stereo | |
261 // sending. | |
262 auto* enc = rent_a_codec_.GetEncoder(); | |
263 const bool stereo_send = enc ? (enc->NumChannels() != 1) : false; | |
264 if (enable && stereo_send) { | |
265 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, | |
266 "VAD/DTX not supported for stereo sending"); | |
267 codec_stack_params_.use_cng = false; | |
268 return -1; | |
269 } | |
270 | |
271 // If a send codec is registered, set VAD/DTX for the codec. | |
272 if (IsOpus(send_codec_inst_)) { | |
273 // VAD/DTX not supported. | |
274 codec_stack_params_.use_cng = false; | |
275 return 0; | |
276 } | |
277 | |
278 if (codec_stack_params_.use_cng != enable || | |
279 codec_stack_params_.vad_mode != mode) { | |
280 codec_stack_params_.use_cng = enable; | |
281 codec_stack_params_.vad_mode = mode; | |
282 if (enc) | |
283 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_); | |
284 } | |
285 return 0; | |
286 } | |
287 | |
288 void CodecManager::VAD(bool* dtx_enabled, | |
289 bool* vad_enabled, | |
290 ACMVADMode* mode) const { | |
291 *dtx_enabled = *vad_enabled = codec_stack_params_.use_cng; | |
292 *mode = codec_stack_params_.vad_mode; | |
293 } | |
294 | |
295 int CodecManager::SetCodecFEC(bool enable_codec_fec) { | |
296 if (enable_codec_fec && codec_stack_params_.use_red) { | |
297 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, | |
298 "Codec internal FEC and RED cannot be co-enabled."); | |
299 return -1; | |
300 } | |
301 | |
302 RTC_CHECK(CurrentEncoder()); | |
303 codec_stack_params_.use_codec_fec = | |
304 CurrentEncoder()->SetFec(enable_codec_fec) && enable_codec_fec; | |
305 return codec_stack_params_.use_codec_fec == enable_codec_fec ? 0 : -1; | |
306 } | |
307 | |
308 AudioDecoder* CodecManager::GetAudioDecoder(const CodecInst& codec) { | |
309 return IsIsac(codec) ? rent_a_codec_.RentIsacDecoder() : nullptr; | |
310 } | |
311 | |
312 } // namespace acm2 | |
313 } // namespace webrtc | |
OLD | NEW |