OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 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/audio_coding_module_impl.h" | |
12 | |
13 #include <assert.h> | |
14 #include <stdlib.h> | |
15 #include <vector> | |
16 | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/base/safe_conversions.h" | |
19 #include "webrtc/engine_configurations.h" | |
20 #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs.
h" | |
21 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" | |
22 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h" | |
23 #include "webrtc/modules/audio_coding/main/acm2/call_statistics.h" | |
24 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
25 #include "webrtc/system_wrappers/include/logging.h" | |
26 #include "webrtc/system_wrappers/include/metrics.h" | |
27 #include "webrtc/system_wrappers/include/rw_lock_wrapper.h" | |
28 #include "webrtc/system_wrappers/include/trace.h" | |
29 #include "webrtc/typedefs.h" | |
30 | |
31 namespace webrtc { | |
32 | |
33 namespace acm2 { | |
34 | |
35 namespace { | |
36 | |
37 // TODO(turajs): the same functionality is used in NetEq. If both classes | |
38 // need them, make it a static function in ACMCodecDB. | |
39 bool IsCodecRED(const CodecInst& codec) { | |
40 return (STR_CASE_CMP(codec.plname, "RED") == 0); | |
41 } | |
42 | |
43 bool IsCodecCN(const CodecInst& codec) { | |
44 return (STR_CASE_CMP(codec.plname, "CN") == 0); | |
45 } | |
46 | |
47 // Stereo-to-mono can be used as in-place. | |
48 int DownMix(const AudioFrame& frame, | |
49 size_t length_out_buff, | |
50 int16_t* out_buff) { | |
51 if (length_out_buff < frame.samples_per_channel_) { | |
52 return -1; | |
53 } | |
54 for (size_t n = 0; n < frame.samples_per_channel_; ++n) | |
55 out_buff[n] = (frame.data_[2 * n] + frame.data_[2 * n + 1]) >> 1; | |
56 return 0; | |
57 } | |
58 | |
59 // Mono-to-stereo can be used as in-place. | |
60 int UpMix(const AudioFrame& frame, size_t length_out_buff, int16_t* out_buff) { | |
61 if (length_out_buff < frame.samples_per_channel_) { | |
62 return -1; | |
63 } | |
64 for (size_t n = frame.samples_per_channel_; n != 0; --n) { | |
65 size_t i = n - 1; | |
66 int16_t sample = frame.data_[i]; | |
67 out_buff[2 * i + 1] = sample; | |
68 out_buff[2 * i] = sample; | |
69 } | |
70 return 0; | |
71 } | |
72 | |
73 void ConvertEncodedInfoToFragmentationHeader( | |
74 const AudioEncoder::EncodedInfo& info, | |
75 RTPFragmentationHeader* frag) { | |
76 if (info.redundant.empty()) { | |
77 frag->fragmentationVectorSize = 0; | |
78 return; | |
79 } | |
80 | |
81 frag->VerifyAndAllocateFragmentationHeader( | |
82 static_cast<uint16_t>(info.redundant.size())); | |
83 frag->fragmentationVectorSize = static_cast<uint16_t>(info.redundant.size()); | |
84 size_t offset = 0; | |
85 for (size_t i = 0; i < info.redundant.size(); ++i) { | |
86 frag->fragmentationOffset[i] = offset; | |
87 offset += info.redundant[i].encoded_bytes; | |
88 frag->fragmentationLength[i] = info.redundant[i].encoded_bytes; | |
89 frag->fragmentationTimeDiff[i] = rtc::checked_cast<uint16_t>( | |
90 info.encoded_timestamp - info.redundant[i].encoded_timestamp); | |
91 frag->fragmentationPlType[i] = info.redundant[i].payload_type; | |
92 } | |
93 } | |
94 } // namespace | |
95 | |
96 void AudioCodingModuleImpl::ChangeLogger::MaybeLog(int value) { | |
97 if (value != last_value_ || first_time_) { | |
98 first_time_ = false; | |
99 last_value_ = value; | |
100 RTC_HISTOGRAM_COUNTS_100(histogram_name_, value); | |
101 } | |
102 } | |
103 | |
104 AudioCodingModuleImpl::AudioCodingModuleImpl( | |
105 const AudioCodingModule::Config& config) | |
106 : acm_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | |
107 id_(config.id), | |
108 expected_codec_ts_(0xD87F3F9F), | |
109 expected_in_ts_(0xD87F3F9F), | |
110 receiver_(config), | |
111 bitrate_logger_("WebRTC.Audio.TargetBitrateInKbps"), | |
112 previous_pltype_(255), | |
113 receiver_initialized_(false), | |
114 first_10ms_data_(false), | |
115 first_frame_(true), | |
116 callback_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | |
117 packetization_callback_(NULL), | |
118 vad_callback_(NULL) { | |
119 if (InitializeReceiverSafe() < 0) { | |
120 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
121 "Cannot initialize receiver"); | |
122 } | |
123 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, id_, "Created"); | |
124 } | |
125 | |
126 AudioCodingModuleImpl::~AudioCodingModuleImpl() = default; | |
127 | |
128 int32_t AudioCodingModuleImpl::Encode(const InputData& input_data) { | |
129 AudioEncoder::EncodedInfo encoded_info; | |
130 uint8_t previous_pltype; | |
131 | |
132 // Check if there is an encoder before. | |
133 if (!HaveValidEncoder("Process")) | |
134 return -1; | |
135 | |
136 AudioEncoder* audio_encoder = codec_manager_.CurrentEncoder(); | |
137 // Scale the timestamp to the codec's RTP timestamp rate. | |
138 uint32_t rtp_timestamp = | |
139 first_frame_ ? input_data.input_timestamp | |
140 : last_rtp_timestamp_ + | |
141 rtc::CheckedDivExact( | |
142 input_data.input_timestamp - last_timestamp_, | |
143 static_cast<uint32_t>(rtc::CheckedDivExact( | |
144 audio_encoder->SampleRateHz(), | |
145 audio_encoder->RtpTimestampRateHz()))); | |
146 last_timestamp_ = input_data.input_timestamp; | |
147 last_rtp_timestamp_ = rtp_timestamp; | |
148 first_frame_ = false; | |
149 | |
150 encode_buffer_.SetSize(audio_encoder->MaxEncodedBytes()); | |
151 encoded_info = audio_encoder->Encode( | |
152 rtp_timestamp, rtc::ArrayView<const int16_t>( | |
153 input_data.audio, input_data.audio_channel * | |
154 input_data.length_per_channel), | |
155 encode_buffer_.size(), encode_buffer_.data()); | |
156 encode_buffer_.SetSize(encoded_info.encoded_bytes); | |
157 bitrate_logger_.MaybeLog(audio_encoder->GetTargetBitrate() / 1000); | |
158 if (encode_buffer_.size() == 0 && !encoded_info.send_even_if_empty) { | |
159 // Not enough data. | |
160 return 0; | |
161 } | |
162 previous_pltype = previous_pltype_; // Read it while we have the critsect. | |
163 | |
164 RTPFragmentationHeader my_fragmentation; | |
165 ConvertEncodedInfoToFragmentationHeader(encoded_info, &my_fragmentation); | |
166 FrameType frame_type; | |
167 if (encode_buffer_.size() == 0 && encoded_info.send_even_if_empty) { | |
168 frame_type = kEmptyFrame; | |
169 encoded_info.payload_type = previous_pltype; | |
170 } else { | |
171 RTC_DCHECK_GT(encode_buffer_.size(), 0u); | |
172 frame_type = encoded_info.speech ? kAudioFrameSpeech : kAudioFrameCN; | |
173 } | |
174 | |
175 { | |
176 CriticalSectionScoped lock(callback_crit_sect_.get()); | |
177 if (packetization_callback_) { | |
178 packetization_callback_->SendData( | |
179 frame_type, encoded_info.payload_type, encoded_info.encoded_timestamp, | |
180 encode_buffer_.data(), encode_buffer_.size(), | |
181 my_fragmentation.fragmentationVectorSize > 0 ? &my_fragmentation | |
182 : nullptr); | |
183 } | |
184 | |
185 if (vad_callback_) { | |
186 // Callback with VAD decision. | |
187 vad_callback_->InFrameType(frame_type); | |
188 } | |
189 } | |
190 previous_pltype_ = encoded_info.payload_type; | |
191 return static_cast<int32_t>(encode_buffer_.size()); | |
192 } | |
193 | |
194 ///////////////////////////////////////// | |
195 // Sender | |
196 // | |
197 | |
198 // Can be called multiple times for Codec, CNG, RED. | |
199 int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) { | |
200 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
201 return codec_manager_.RegisterEncoder(send_codec); | |
202 } | |
203 | |
204 void AudioCodingModuleImpl::RegisterExternalSendCodec( | |
205 AudioEncoder* external_speech_encoder) { | |
206 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
207 codec_manager_.RegisterEncoder(external_speech_encoder); | |
208 } | |
209 | |
210 // Get current send codec. | |
211 rtc::Optional<CodecInst> AudioCodingModuleImpl::SendCodec() const { | |
212 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
213 return codec_manager_.GetCodecInst(); | |
214 } | |
215 | |
216 // Get current send frequency. | |
217 int AudioCodingModuleImpl::SendFrequency() const { | |
218 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, | |
219 "SendFrequency()"); | |
220 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
221 | |
222 if (!codec_manager_.CurrentEncoder()) { | |
223 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, | |
224 "SendFrequency Failed, no codec is registered"); | |
225 return -1; | |
226 } | |
227 | |
228 return codec_manager_.CurrentEncoder()->SampleRateHz(); | |
229 } | |
230 | |
231 void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) { | |
232 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
233 if (codec_manager_.CurrentEncoder()) { | |
234 codec_manager_.CurrentEncoder()->SetTargetBitrate(bitrate_bps); | |
235 } | |
236 } | |
237 | |
238 // Register a transport callback which will be called to deliver | |
239 // the encoded buffers. | |
240 int AudioCodingModuleImpl::RegisterTransportCallback( | |
241 AudioPacketizationCallback* transport) { | |
242 CriticalSectionScoped lock(callback_crit_sect_.get()); | |
243 packetization_callback_ = transport; | |
244 return 0; | |
245 } | |
246 | |
247 // Add 10MS of raw (PCM) audio data to the encoder. | |
248 int AudioCodingModuleImpl::Add10MsData(const AudioFrame& audio_frame) { | |
249 InputData input_data; | |
250 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
251 int r = Add10MsDataInternal(audio_frame, &input_data); | |
252 return r < 0 ? r : Encode(input_data); | |
253 } | |
254 | |
255 int AudioCodingModuleImpl::Add10MsDataInternal(const AudioFrame& audio_frame, | |
256 InputData* input_data) { | |
257 if (audio_frame.samples_per_channel_ == 0) { | |
258 assert(false); | |
259 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
260 "Cannot Add 10 ms audio, payload length is zero"); | |
261 return -1; | |
262 } | |
263 | |
264 if (audio_frame.sample_rate_hz_ > 48000) { | |
265 assert(false); | |
266 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
267 "Cannot Add 10 ms audio, input frequency not valid"); | |
268 return -1; | |
269 } | |
270 | |
271 // If the length and frequency matches. We currently just support raw PCM. | |
272 if (static_cast<size_t>(audio_frame.sample_rate_hz_ / 100) != | |
273 audio_frame.samples_per_channel_) { | |
274 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
275 "Cannot Add 10 ms audio, input frequency and length doesn't" | |
276 " match"); | |
277 return -1; | |
278 } | |
279 | |
280 if (audio_frame.num_channels_ != 1 && audio_frame.num_channels_ != 2) { | |
281 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
282 "Cannot Add 10 ms audio, invalid number of channels."); | |
283 return -1; | |
284 } | |
285 | |
286 // Do we have a codec registered? | |
287 if (!HaveValidEncoder("Add10MsData")) { | |
288 return -1; | |
289 } | |
290 | |
291 const AudioFrame* ptr_frame; | |
292 // Perform a resampling, also down-mix if it is required and can be | |
293 // performed before resampling (a down mix prior to resampling will take | |
294 // place if both primary and secondary encoders are mono and input is in | |
295 // stereo). | |
296 if (PreprocessToAddData(audio_frame, &ptr_frame) < 0) { | |
297 return -1; | |
298 } | |
299 | |
300 // Check whether we need an up-mix or down-mix? | |
301 bool remix = ptr_frame->num_channels_ != | |
302 codec_manager_.CurrentEncoder()->NumChannels(); | |
303 | |
304 if (remix) { | |
305 if (ptr_frame->num_channels_ == 1) { | |
306 if (UpMix(*ptr_frame, WEBRTC_10MS_PCM_AUDIO, input_data->buffer) < 0) | |
307 return -1; | |
308 } else { | |
309 if (DownMix(*ptr_frame, WEBRTC_10MS_PCM_AUDIO, input_data->buffer) < 0) | |
310 return -1; | |
311 } | |
312 } | |
313 | |
314 // When adding data to encoders this pointer is pointing to an audio buffer | |
315 // with correct number of channels. | |
316 const int16_t* ptr_audio = ptr_frame->data_; | |
317 | |
318 // For pushing data to primary, point the |ptr_audio| to correct buffer. | |
319 if (codec_manager_.CurrentEncoder()->NumChannels() != | |
320 ptr_frame->num_channels_) | |
321 ptr_audio = input_data->buffer; | |
322 | |
323 input_data->input_timestamp = ptr_frame->timestamp_; | |
324 input_data->audio = ptr_audio; | |
325 input_data->length_per_channel = ptr_frame->samples_per_channel_; | |
326 input_data->audio_channel = codec_manager_.CurrentEncoder()->NumChannels(); | |
327 | |
328 return 0; | |
329 } | |
330 | |
331 // Perform a resampling and down-mix if required. We down-mix only if | |
332 // encoder is mono and input is stereo. In case of dual-streaming, both | |
333 // encoders has to be mono for down-mix to take place. | |
334 // |*ptr_out| will point to the pre-processed audio-frame. If no pre-processing | |
335 // is required, |*ptr_out| points to |in_frame|. | |
336 int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame, | |
337 const AudioFrame** ptr_out) { | |
338 bool resample = (in_frame.sample_rate_hz_ != | |
339 codec_manager_.CurrentEncoder()->SampleRateHz()); | |
340 | |
341 // This variable is true if primary codec and secondary codec (if exists) | |
342 // are both mono and input is stereo. | |
343 bool down_mix = (in_frame.num_channels_ == 2) && | |
344 (codec_manager_.CurrentEncoder()->NumChannels() == 1); | |
345 | |
346 if (!first_10ms_data_) { | |
347 expected_in_ts_ = in_frame.timestamp_; | |
348 expected_codec_ts_ = in_frame.timestamp_; | |
349 first_10ms_data_ = true; | |
350 } else if (in_frame.timestamp_ != expected_in_ts_) { | |
351 // TODO(turajs): Do we need a warning here. | |
352 expected_codec_ts_ += | |
353 (in_frame.timestamp_ - expected_in_ts_) * | |
354 static_cast<uint32_t>( | |
355 (static_cast<double>( | |
356 codec_manager_.CurrentEncoder()->SampleRateHz()) / | |
357 static_cast<double>(in_frame.sample_rate_hz_))); | |
358 expected_in_ts_ = in_frame.timestamp_; | |
359 } | |
360 | |
361 | |
362 if (!down_mix && !resample) { | |
363 // No pre-processing is required. | |
364 expected_in_ts_ += static_cast<uint32_t>(in_frame.samples_per_channel_); | |
365 expected_codec_ts_ += static_cast<uint32_t>(in_frame.samples_per_channel_); | |
366 *ptr_out = &in_frame; | |
367 return 0; | |
368 } | |
369 | |
370 *ptr_out = &preprocess_frame_; | |
371 preprocess_frame_.num_channels_ = in_frame.num_channels_; | |
372 int16_t audio[WEBRTC_10MS_PCM_AUDIO]; | |
373 const int16_t* src_ptr_audio = in_frame.data_; | |
374 int16_t* dest_ptr_audio = preprocess_frame_.data_; | |
375 if (down_mix) { | |
376 // If a resampling is required the output of a down-mix is written into a | |
377 // local buffer, otherwise, it will be written to the output frame. | |
378 if (resample) | |
379 dest_ptr_audio = audio; | |
380 if (DownMix(in_frame, WEBRTC_10MS_PCM_AUDIO, dest_ptr_audio) < 0) | |
381 return -1; | |
382 preprocess_frame_.num_channels_ = 1; | |
383 // Set the input of the resampler is the down-mixed signal. | |
384 src_ptr_audio = audio; | |
385 } | |
386 | |
387 preprocess_frame_.timestamp_ = expected_codec_ts_; | |
388 preprocess_frame_.samples_per_channel_ = in_frame.samples_per_channel_; | |
389 preprocess_frame_.sample_rate_hz_ = in_frame.sample_rate_hz_; | |
390 // If it is required, we have to do a resampling. | |
391 if (resample) { | |
392 // The result of the resampler is written to output frame. | |
393 dest_ptr_audio = preprocess_frame_.data_; | |
394 | |
395 int samples_per_channel = resampler_.Resample10Msec( | |
396 src_ptr_audio, in_frame.sample_rate_hz_, | |
397 codec_manager_.CurrentEncoder()->SampleRateHz(), | |
398 preprocess_frame_.num_channels_, AudioFrame::kMaxDataSizeSamples, | |
399 dest_ptr_audio); | |
400 | |
401 if (samples_per_channel < 0) { | |
402 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
403 "Cannot add 10 ms audio, resampling failed"); | |
404 return -1; | |
405 } | |
406 preprocess_frame_.samples_per_channel_ = | |
407 static_cast<size_t>(samples_per_channel); | |
408 preprocess_frame_.sample_rate_hz_ = | |
409 codec_manager_.CurrentEncoder()->SampleRateHz(); | |
410 } | |
411 | |
412 expected_codec_ts_ += | |
413 static_cast<uint32_t>(preprocess_frame_.samples_per_channel_); | |
414 expected_in_ts_ += static_cast<uint32_t>(in_frame.samples_per_channel_); | |
415 | |
416 return 0; | |
417 } | |
418 | |
419 ///////////////////////////////////////// | |
420 // (RED) Redundant Coding | |
421 // | |
422 | |
423 bool AudioCodingModuleImpl::REDStatus() const { | |
424 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
425 return codec_manager_.red_enabled(); | |
426 } | |
427 | |
428 // Configure RED status i.e on/off. | |
429 int AudioCodingModuleImpl::SetREDStatus( | |
430 #ifdef WEBRTC_CODEC_RED | |
431 bool enable_red) { | |
432 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
433 return codec_manager_.SetCopyRed(enable_red) ? 0 : -1; | |
434 #else | |
435 bool /* enable_red */) { | |
436 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_, | |
437 " WEBRTC_CODEC_RED is undefined"); | |
438 return -1; | |
439 #endif | |
440 } | |
441 | |
442 ///////////////////////////////////////// | |
443 // (FEC) Forward Error Correction (codec internal) | |
444 // | |
445 | |
446 bool AudioCodingModuleImpl::CodecFEC() const { | |
447 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
448 return codec_manager_.codec_fec_enabled(); | |
449 } | |
450 | |
451 int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) { | |
452 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
453 return codec_manager_.SetCodecFEC(enable_codec_fec); | |
454 } | |
455 | |
456 int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) { | |
457 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
458 if (HaveValidEncoder("SetPacketLossRate")) { | |
459 codec_manager_.CurrentEncoder()->SetProjectedPacketLossRate(loss_rate / | |
460 100.0); | |
461 } | |
462 return 0; | |
463 } | |
464 | |
465 ///////////////////////////////////////// | |
466 // (VAD) Voice Activity Detection | |
467 // | |
468 int AudioCodingModuleImpl::SetVAD(bool enable_dtx, | |
469 bool enable_vad, | |
470 ACMVADMode mode) { | |
471 // Note: |enable_vad| is not used; VAD is enabled based on the DTX setting. | |
472 RTC_DCHECK_EQ(enable_dtx, enable_vad); | |
473 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
474 return codec_manager_.SetVAD(enable_dtx, mode); | |
475 } | |
476 | |
477 // Get VAD/DTX settings. | |
478 int AudioCodingModuleImpl::VAD(bool* dtx_enabled, bool* vad_enabled, | |
479 ACMVADMode* mode) const { | |
480 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
481 codec_manager_.VAD(dtx_enabled, vad_enabled, mode); | |
482 return 0; | |
483 } | |
484 | |
485 ///////////////////////////////////////// | |
486 // Receiver | |
487 // | |
488 | |
489 int AudioCodingModuleImpl::InitializeReceiver() { | |
490 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
491 return InitializeReceiverSafe(); | |
492 } | |
493 | |
494 // Initialize receiver, resets codec database etc. | |
495 int AudioCodingModuleImpl::InitializeReceiverSafe() { | |
496 // If the receiver is already initialized then we want to destroy any | |
497 // existing decoders. After a call to this function, we should have a clean | |
498 // start-up. | |
499 if (receiver_initialized_) { | |
500 if (receiver_.RemoveAllCodecs() < 0) | |
501 return -1; | |
502 } | |
503 receiver_.set_id(id_); | |
504 receiver_.ResetInitialDelay(); | |
505 receiver_.SetMinimumDelay(0); | |
506 receiver_.SetMaximumDelay(0); | |
507 receiver_.FlushBuffers(); | |
508 | |
509 // Register RED and CN. | |
510 auto db = RentACodec::Database(); | |
511 for (size_t i = 0; i < db.size(); i++) { | |
512 if (IsCodecRED(db[i]) || IsCodecCN(db[i])) { | |
513 if (receiver_.AddCodec(static_cast<int>(i), | |
514 static_cast<uint8_t>(db[i].pltype), 1, | |
515 db[i].plfreq, nullptr) < 0) { | |
516 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
517 "Cannot register master codec."); | |
518 return -1; | |
519 } | |
520 } | |
521 } | |
522 receiver_initialized_ = true; | |
523 return 0; | |
524 } | |
525 | |
526 // Get current receive frequency. | |
527 int AudioCodingModuleImpl::ReceiveFrequency() const { | |
528 const auto last_packet_sample_rate = receiver_.last_packet_sample_rate_hz(); | |
529 return last_packet_sample_rate ? *last_packet_sample_rate | |
530 : receiver_.last_output_sample_rate_hz(); | |
531 } | |
532 | |
533 // Get current playout frequency. | |
534 int AudioCodingModuleImpl::PlayoutFrequency() const { | |
535 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, | |
536 "PlayoutFrequency()"); | |
537 return receiver_.last_output_sample_rate_hz(); | |
538 } | |
539 | |
540 // Register possible receive codecs, can be called multiple times, | |
541 // for codecs, CNG (NB, WB and SWB), DTMF, RED. | |
542 int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) { | |
543 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
544 RTC_DCHECK(receiver_initialized_); | |
545 if (codec.channels > 2 || codec.channels < 0) { | |
546 LOG_F(LS_ERROR) << "Unsupported number of channels: " << codec.channels; | |
547 return -1; | |
548 } | |
549 | |
550 auto codec_id = | |
551 RentACodec::CodecIdByParams(codec.plname, codec.plfreq, codec.channels); | |
552 if (!codec_id) { | |
553 LOG_F(LS_ERROR) << "Wrong codec params to be registered as receive codec"; | |
554 return -1; | |
555 } | |
556 auto codec_index = RentACodec::CodecIndexFromId(*codec_id); | |
557 RTC_CHECK(codec_index) << "Invalid codec ID: " << static_cast<int>(*codec_id); | |
558 | |
559 // Check if the payload-type is valid. | |
560 if (!RentACodec::IsPayloadTypeValid(codec.pltype)) { | |
561 LOG_F(LS_ERROR) << "Invalid payload type " << codec.pltype << " for " | |
562 << codec.plname; | |
563 return -1; | |
564 } | |
565 | |
566 // Get |decoder| associated with |codec|. |decoder| is NULL if |codec| does | |
567 // not own its decoder. | |
568 return receiver_.AddCodec(*codec_index, codec.pltype, codec.channels, | |
569 codec.plfreq, | |
570 codec_manager_.GetAudioDecoder(codec)); | |
571 } | |
572 | |
573 int AudioCodingModuleImpl::RegisterExternalReceiveCodec( | |
574 int rtp_payload_type, | |
575 AudioDecoder* external_decoder, | |
576 int sample_rate_hz, | |
577 int num_channels) { | |
578 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
579 RTC_DCHECK(receiver_initialized_); | |
580 if (num_channels > 2 || num_channels < 0) { | |
581 LOG_F(LS_ERROR) << "Unsupported number of channels: " << num_channels; | |
582 return -1; | |
583 } | |
584 | |
585 // Check if the payload-type is valid. | |
586 if (!RentACodec::IsPayloadTypeValid(rtp_payload_type)) { | |
587 LOG_F(LS_ERROR) << "Invalid payload-type " << rtp_payload_type | |
588 << " for external decoder."; | |
589 return -1; | |
590 } | |
591 | |
592 return receiver_.AddCodec(-1 /* external */, rtp_payload_type, num_channels, | |
593 sample_rate_hz, external_decoder); | |
594 } | |
595 | |
596 // Get current received codec. | |
597 int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const { | |
598 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
599 return receiver_.LastAudioCodec(current_codec); | |
600 } | |
601 | |
602 // Incoming packet from network parsed and ready for decode. | |
603 int AudioCodingModuleImpl::IncomingPacket(const uint8_t* incoming_payload, | |
604 const size_t payload_length, | |
605 const WebRtcRTPHeader& rtp_header) { | |
606 return receiver_.InsertPacket( | |
607 rtp_header, | |
608 rtc::ArrayView<const uint8_t>(incoming_payload, payload_length)); | |
609 } | |
610 | |
611 // Minimum playout delay (Used for lip-sync). | |
612 int AudioCodingModuleImpl::SetMinimumPlayoutDelay(int time_ms) { | |
613 if ((time_ms < 0) || (time_ms > 10000)) { | |
614 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
615 "Delay must be in the range of 0-1000 milliseconds."); | |
616 return -1; | |
617 } | |
618 return receiver_.SetMinimumDelay(time_ms); | |
619 } | |
620 | |
621 int AudioCodingModuleImpl::SetMaximumPlayoutDelay(int time_ms) { | |
622 if ((time_ms < 0) || (time_ms > 10000)) { | |
623 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
624 "Delay must be in the range of 0-1000 milliseconds."); | |
625 return -1; | |
626 } | |
627 return receiver_.SetMaximumDelay(time_ms); | |
628 } | |
629 | |
630 // Get 10 milliseconds of raw audio data to play out. | |
631 // Automatic resample to the requested frequency. | |
632 int AudioCodingModuleImpl::PlayoutData10Ms(int desired_freq_hz, | |
633 AudioFrame* audio_frame) { | |
634 // GetAudio always returns 10 ms, at the requested sample rate. | |
635 if (receiver_.GetAudio(desired_freq_hz, audio_frame) != 0) { | |
636 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
637 "PlayoutData failed, RecOut Failed"); | |
638 return -1; | |
639 } | |
640 audio_frame->id_ = id_; | |
641 return 0; | |
642 } | |
643 | |
644 ///////////////////////////////////////// | |
645 // Statistics | |
646 // | |
647 | |
648 // TODO(turajs) change the return value to void. Also change the corresponding | |
649 // NetEq function. | |
650 int AudioCodingModuleImpl::GetNetworkStatistics(NetworkStatistics* statistics) { | |
651 receiver_.GetNetworkStatistics(statistics); | |
652 return 0; | |
653 } | |
654 | |
655 int AudioCodingModuleImpl::RegisterVADCallback(ACMVADCallback* vad_callback) { | |
656 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, id_, | |
657 "RegisterVADCallback()"); | |
658 CriticalSectionScoped lock(callback_crit_sect_.get()); | |
659 vad_callback_ = vad_callback; | |
660 return 0; | |
661 } | |
662 | |
663 // TODO(kwiberg): Remove this method, and have callers call IncomingPacket | |
664 // instead. The translation logic and state belong with them, not with | |
665 // AudioCodingModuleImpl. | |
666 int AudioCodingModuleImpl::IncomingPayload(const uint8_t* incoming_payload, | |
667 size_t payload_length, | |
668 uint8_t payload_type, | |
669 uint32_t timestamp) { | |
670 // We are not acquiring any lock when interacting with |aux_rtp_header_| no | |
671 // other method uses this member variable. | |
672 if (!aux_rtp_header_) { | |
673 // This is the first time that we are using |dummy_rtp_header_| | |
674 // so we have to create it. | |
675 aux_rtp_header_.reset(new WebRtcRTPHeader); | |
676 aux_rtp_header_->header.payloadType = payload_type; | |
677 // Don't matter in this case. | |
678 aux_rtp_header_->header.ssrc = 0; | |
679 aux_rtp_header_->header.markerBit = false; | |
680 // Start with random numbers. | |
681 aux_rtp_header_->header.sequenceNumber = 0x1234; // Arbitrary. | |
682 aux_rtp_header_->type.Audio.channel = 1; | |
683 } | |
684 | |
685 aux_rtp_header_->header.timestamp = timestamp; | |
686 IncomingPacket(incoming_payload, payload_length, *aux_rtp_header_); | |
687 // Get ready for the next payload. | |
688 aux_rtp_header_->header.sequenceNumber++; | |
689 return 0; | |
690 } | |
691 | |
692 int AudioCodingModuleImpl::SetOpusApplication(OpusApplicationMode application) { | |
693 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
694 if (!HaveValidEncoder("SetOpusApplication")) { | |
695 return -1; | |
696 } | |
697 if (!codec_manager_.CurrentEncoderIsOpus()) | |
698 return -1; | |
699 AudioEncoder::Application app; | |
700 switch (application) { | |
701 case kVoip: | |
702 app = AudioEncoder::Application::kSpeech; | |
703 break; | |
704 case kAudio: | |
705 app = AudioEncoder::Application::kAudio; | |
706 break; | |
707 default: | |
708 FATAL(); | |
709 return 0; | |
710 } | |
711 return codec_manager_.CurrentEncoder()->SetApplication(app) ? 0 : -1; | |
712 } | |
713 | |
714 // Informs Opus encoder of the maximum playback rate the receiver will render. | |
715 int AudioCodingModuleImpl::SetOpusMaxPlaybackRate(int frequency_hz) { | |
716 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
717 if (!HaveValidEncoder("SetOpusMaxPlaybackRate")) { | |
718 return -1; | |
719 } | |
720 if (!codec_manager_.CurrentEncoderIsOpus()) | |
721 return -1; | |
722 codec_manager_.CurrentEncoder()->SetMaxPlaybackRate(frequency_hz); | |
723 return 0; | |
724 } | |
725 | |
726 int AudioCodingModuleImpl::EnableOpusDtx() { | |
727 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
728 if (!HaveValidEncoder("EnableOpusDtx")) { | |
729 return -1; | |
730 } | |
731 if (!codec_manager_.CurrentEncoderIsOpus()) | |
732 return -1; | |
733 return codec_manager_.CurrentEncoder()->SetDtx(true) ? 0 : -1; | |
734 } | |
735 | |
736 int AudioCodingModuleImpl::DisableOpusDtx() { | |
737 CriticalSectionScoped lock(acm_crit_sect_.get()); | |
738 if (!HaveValidEncoder("DisableOpusDtx")) { | |
739 return -1; | |
740 } | |
741 if (!codec_manager_.CurrentEncoderIsOpus()) | |
742 return -1; | |
743 return codec_manager_.CurrentEncoder()->SetDtx(false) ? 0 : -1; | |
744 } | |
745 | |
746 int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) { | |
747 return receiver_.GetPlayoutTimestamp(timestamp) ? 0 : -1; | |
748 } | |
749 | |
750 bool AudioCodingModuleImpl::HaveValidEncoder(const char* caller_name) const { | |
751 if (!codec_manager_.CurrentEncoder()) { | |
752 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, | |
753 "%s failed: No send codec is registered.", caller_name); | |
754 return false; | |
755 } | |
756 return true; | |
757 } | |
758 | |
759 int AudioCodingModuleImpl::UnregisterReceiveCodec(uint8_t payload_type) { | |
760 return receiver_.RemoveCodec(payload_type); | |
761 } | |
762 | |
763 int AudioCodingModuleImpl::EnableNack(size_t max_nack_list_size) { | |
764 return receiver_.EnableNack(max_nack_list_size); | |
765 } | |
766 | |
767 void AudioCodingModuleImpl::DisableNack() { | |
768 receiver_.DisableNack(); | |
769 } | |
770 | |
771 std::vector<uint16_t> AudioCodingModuleImpl::GetNackList( | |
772 int64_t round_trip_time_ms) const { | |
773 return receiver_.GetNackList(round_trip_time_ms); | |
774 } | |
775 | |
776 int AudioCodingModuleImpl::LeastRequiredDelayMs() const { | |
777 return receiver_.LeastRequiredDelayMs(); | |
778 } | |
779 | |
780 void AudioCodingModuleImpl::GetDecodingCallStatistics( | |
781 AudioDecodingCallStats* call_stats) const { | |
782 receiver_.GetDecodingCallStatistics(call_stats); | |
783 } | |
784 | |
785 } // namespace acm2 | |
786 } // namespace webrtc | |
OLD | NEW |