blob: d8dcd792c4937b8ac933a53cd2ec1e47be3f4606 [file] [log] [blame]
Henrik Lundin45c64492015-03-30 19:00:44 +02001/*
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
kjellander3e6db232015-11-26 04:44:54 -080011#include "webrtc/modules/audio_coding/acm2/codec_manager.h"
Henrik Lundin45c64492015-03-30 19:00:44 +020012
13#include "webrtc/base/checks.h"
Peter Kasting69558702016-01-12 16:26:35 -080014#include "webrtc/base/format_macros.h"
kjellander3e6db232015-11-26 04:44:54 -080015#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010016#include "webrtc/system_wrappers/include/trace.h"
mflodman7056be92016-10-07 07:07:28 +020017#include "webrtc/voice_engine_configurations.h"
Henrik Lundin45c64492015-03-30 19:00:44 +020018
19namespace webrtc {
20namespace acm2 {
21
22namespace {
Henrik Lundin45c64492015-03-30 19:00:44 +020023
Henrik Lundin45c64492015-03-30 19:00:44 +020024// Check if the given codec is a valid to be registered as send codec.
kwiberg223692a2015-11-18 08:27:51 -080025int IsValidSendCodec(const CodecInst& send_codec) {
Henrik Lundin45c64492015-03-30 19:00:44 +020026 int dummy_id = 0;
27 if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
28 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
Peter Kasting69558702016-01-12 16:26:35 -080029 "Wrong number of channels (%" PRIuS ", only mono and stereo "
30 "are supported)",
kwiberg223692a2015-11-18 08:27:51 -080031 send_codec.channels);
Henrik Lundin45c64492015-03-30 19:00:44 +020032 return -1;
33 }
34
kwibergd6c0f8c2015-11-06 14:28:00 -080035 auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec);
36 if (!maybe_codec_id) {
Henrik Lundin45c64492015-03-30 19:00:44 +020037 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
38 "Invalid codec setting for the send codec.");
39 return -1;
40 }
41
Henrik Lundin45c64492015-03-30 19:00:44 +020042 // Telephone-event cannot be a send codec.
43 if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) {
44 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
45 "telephone-event cannot be a send codec");
Henrik Lundin45c64492015-03-30 19:00:44 +020046 return -1;
47 }
48
kwibergd6c0f8c2015-11-06 14:28:00 -080049 if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels)
50 .value_or(false)) {
Henrik Lundin45c64492015-03-30 19:00:44 +020051 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
Peter Kasting69558702016-01-12 16:26:35 -080052 "%" PRIuS " number of channels not supportedn for %s.",
Henrik Lundin45c64492015-03-30 19:00:44 +020053 send_codec.channels, send_codec.plname);
Henrik Lundin45c64492015-03-30 19:00:44 +020054 return -1;
55 }
kwibergd6c0f8c2015-11-06 14:28:00 -080056 return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1);
Henrik Lundin45c64492015-03-30 19:00:44 +020057}
58
Karl Wiberg2ea71c32015-05-07 15:49:23 +020059bool IsOpus(const CodecInst& codec) {
60 return
61#ifdef WEBRTC_CODEC_OPUS
62 !STR_CASE_CMP(codec.plname, "opus") ||
63#endif
64 false;
65}
66
Henrik Lundin45c64492015-03-30 19:00:44 +020067} // namespace
68
kwiberga6db4952015-12-16 04:19:08 -080069CodecManager::CodecManager() {
Henrik Lundin45c64492015-03-30 19:00:44 +020070 thread_checker_.DetachFromThread();
71}
72
Henrik Lundin93ef1d82015-04-13 09:31:16 +020073CodecManager::~CodecManager() = default;
Henrik Lundin45c64492015-03-30 19:00:44 +020074
kwiberga6db4952015-12-16 04:19:08 -080075bool CodecManager::RegisterEncoder(const CodecInst& send_codec) {
henrikg91d6ede2015-09-17 00:24:34 -070076 RTC_DCHECK(thread_checker_.CalledOnValidThread());
kwiberg223692a2015-11-18 08:27:51 -080077 int codec_id = IsValidSendCodec(send_codec);
Henrik Lundin45c64492015-03-30 19:00:44 +020078
79 // Check for reported errors from function IsValidSendCodec().
80 if (codec_id < 0) {
kwiberga6db4952015-12-16 04:19:08 -080081 return false;
Henrik Lundin45c64492015-03-30 19:00:44 +020082 }
83
84 int dummy_id = 0;
kwiberg1379f1f2015-11-23 04:30:52 -080085 switch (RentACodec::RegisterRedPayloadType(
86 &codec_stack_params_.red_payload_types, send_codec)) {
kwiberge1a27d42015-11-18 07:32:49 -080087 case RentACodec::RegistrationResult::kOk:
kwiberga6db4952015-12-16 04:19:08 -080088 return true;
kwiberge1a27d42015-11-18 07:32:49 -080089 case RentACodec::RegistrationResult::kBadFreq:
Henrik Lundin45c64492015-03-30 19:00:44 +020090 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
kwiberge1a27d42015-11-18 07:32:49 -080091 "RegisterSendCodec() failed, invalid frequency for RED"
92 " registration");
kwiberga6db4952015-12-16 04:19:08 -080093 return false;
kwiberge1a27d42015-11-18 07:32:49 -080094 case RentACodec::RegistrationResult::kSkip:
95 break;
Henrik Lundin45c64492015-03-30 19:00:44 +020096 }
kwiberg1379f1f2015-11-23 04:30:52 -080097 switch (RentACodec::RegisterCngPayloadType(
98 &codec_stack_params_.cng_payload_types, send_codec)) {
kwiberge1a27d42015-11-18 07:32:49 -080099 case RentACodec::RegistrationResult::kOk:
kwiberga6db4952015-12-16 04:19:08 -0800100 return true;
kwiberge1a27d42015-11-18 07:32:49 -0800101 case RentACodec::RegistrationResult::kBadFreq:
102 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
103 "RegisterSendCodec() failed, invalid frequency for CNG"
104 " registration");
kwiberga6db4952015-12-16 04:19:08 -0800105 return false;
kwiberge1a27d42015-11-18 07:32:49 -0800106 case RentACodec::RegistrationResult::kSkip:
107 break;
Henrik Lundin45c64492015-03-30 19:00:44 +0200108 }
109
kwiberga6db4952015-12-16 04:19:08 -0800110 if (IsOpus(send_codec)) {
kwibergdfbb3a42015-12-01 04:45:04 -0800111 // VAD/DTX not supported.
112 codec_stack_params_.use_cng = false;
Henrik Lundin45c64492015-03-30 19:00:44 +0200113 }
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200114
kwiberga6db4952015-12-16 04:19:08 -0800115 send_codec_inst_ = rtc::Optional<CodecInst>(send_codec);
kwiberg3f81fcd2016-06-23 03:58:36 -0700116 recreate_encoder_ = true; // Caller must recreate it.
kwiberga6db4952015-12-16 04:19:08 -0800117 return true;
Henrik Lundin45c64492015-03-30 19:00:44 +0200118}
119
kwiberga6db4952015-12-16 04:19:08 -0800120CodecInst CodecManager::ForgeCodecInst(
121 const AudioEncoder* external_speech_encoder) {
122 CodecInst ci;
123 ci.channels = external_speech_encoder->NumChannels();
124 ci.plfreq = external_speech_encoder->SampleRateHz();
125 ci.pacsize = rtc::CheckedDivExact(
Peter Kastingdce40cf2015-08-24 14:52:23 -0700126 static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() *
kwiberga6db4952015-12-16 04:19:08 -0800127 ci.plfreq),
Peter Kastingdce40cf2015-08-24 14:52:23 -0700128 100);
kwiberga6db4952015-12-16 04:19:08 -0800129 ci.pltype = -1; // Not valid.
130 ci.rate = -1; // Not valid.
Karl Wiberg7e0c7d42015-05-18 14:52:29 +0200131 static const char kName[] = "external";
kwiberga6db4952015-12-16 04:19:08 -0800132 memcpy(ci.plname, kName, sizeof(kName));
133 return ci;
Henrik Lundin45c64492015-03-30 19:00:44 +0200134}
135
Henrik Lundin45c64492015-03-30 19:00:44 +0200136bool CodecManager::SetCopyRed(bool enable) {
kwiberg1379f1f2015-11-23 04:30:52 -0800137 if (enable && codec_stack_params_.use_codec_fec) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200138 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
139 "Codec internal FEC and RED cannot be co-enabled.");
140 return false;
141 }
kwiberga6db4952015-12-16 04:19:08 -0800142 if (enable && send_codec_inst_ &&
143 codec_stack_params_.red_payload_types.count(send_codec_inst_->plfreq) <
kwiberg1379f1f2015-11-23 04:30:52 -0800144 1) {
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200145 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
kwiberga6db4952015-12-16 04:19:08 -0800146 "Cannot enable RED at %i Hz.", send_codec_inst_->plfreq);
Henrik Lundin45c64492015-03-30 19:00:44 +0200147 return false;
148 }
kwiberga6db4952015-12-16 04:19:08 -0800149 codec_stack_params_.use_red = enable;
Henrik Lundin45c64492015-03-30 19:00:44 +0200150 return true;
151}
152
kwiberga6db4952015-12-16 04:19:08 -0800153bool CodecManager::SetVAD(bool enable, ACMVADMode mode) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200154 // Sanity check of the mode.
henrikg91d6ede2015-09-17 00:24:34 -0700155 RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr ||
156 mode == VADVeryAggr);
Henrik Lundin45c64492015-03-30 19:00:44 +0200157
158 // Check that the send codec is mono. We don't support VAD/DTX for stereo
159 // sending.
kwiberg95d98512015-12-15 14:21:33 -0800160 const bool stereo_send =
161 codec_stack_params_.speech_encoder
162 ? (codec_stack_params_.speech_encoder->NumChannels() != 1)
163 : false;
kwiberged8275a2015-11-10 09:47:36 -0800164 if (enable && stereo_send) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200165 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
166 "VAD/DTX not supported for stereo sending");
kwiberga6db4952015-12-16 04:19:08 -0800167 return false;
Henrik Lundin45c64492015-03-30 19:00:44 +0200168 }
169
kwiberg44307632015-12-16 06:24:05 -0800170 // TODO(kwiberg): This doesn't protect Opus when injected as an external
171 // encoder.
172 if (send_codec_inst_ && IsOpus(*send_codec_inst_)) {
kwiberga6db4952015-12-16 04:19:08 -0800173 // VAD/DTX not supported, but don't fail.
174 enable = false;
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200175 }
176
kwiberga6db4952015-12-16 04:19:08 -0800177 codec_stack_params_.use_cng = enable;
178 codec_stack_params_.vad_mode = mode;
179 return true;
Henrik Lundin45c64492015-03-30 19:00:44 +0200180}
181
kwiberga6db4952015-12-16 04:19:08 -0800182bool CodecManager::SetCodecFEC(bool enable_codec_fec) {
kwiberg1379f1f2015-11-23 04:30:52 -0800183 if (enable_codec_fec && codec_stack_params_.use_red) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200184 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
185 "Codec internal FEC and RED cannot be co-enabled.");
kwiberga6db4952015-12-16 04:19:08 -0800186 return false;
Henrik Lundin45c64492015-03-30 19:00:44 +0200187 }
188
kwiberga6db4952015-12-16 04:19:08 -0800189 codec_stack_params_.use_codec_fec = enable_codec_fec;
190 return true;
Henrik Lundin45c64492015-03-30 19:00:44 +0200191}
192
kwiberg3f81fcd2016-06-23 03:58:36 -0700193bool CodecManager::MakeEncoder(RentACodec* rac, AudioCodingModule* acm) {
194 RTC_DCHECK(rac);
195 RTC_DCHECK(acm);
196
197 if (!recreate_encoder_) {
198 bool error = false;
199 // Try to re-use the speech encoder we've given to the ACM.
200 acm->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
201 if (!*encoder) {
202 // There is no existing encoder.
203 recreate_encoder_ = true;
204 return;
205 }
206
207 // Extract the speech encoder from the ACM.
208 std::unique_ptr<AudioEncoder> enc = std::move(*encoder);
209 while (true) {
210 auto sub_enc = enc->ReclaimContainedEncoders();
211 if (sub_enc.empty()) {
212 break;
213 }
214 RTC_CHECK_EQ(1u, sub_enc.size());
215
216 // Replace enc with its sub encoder. We need to put the sub encoder in
217 // a temporary first, since otherwise the old value of enc would be
218 // destroyed before the new value got assigned, which would be bad
219 // since the new value is a part of the old value.
220 auto tmp_enc = std::move(sub_enc[0]);
221 enc = std::move(tmp_enc);
222 }
223
224 // Wrap it in a new encoder stack and put it back.
225 codec_stack_params_.speech_encoder = std::move(enc);
226 *encoder = rac->RentEncoderStack(&codec_stack_params_);
227 if (!*encoder) {
228 error = true;
229 }
230 });
231 if (error) {
232 return false;
233 }
234 if (!recreate_encoder_) {
235 return true;
236 }
237 }
238
239 if (!send_codec_inst_) {
240 // We don't have the information we need to create a new speech encoder.
241 // (This is not an error.)
242 return true;
243 }
244
245 codec_stack_params_.speech_encoder = rac->RentEncoder(*send_codec_inst_);
246 auto stack = rac->RentEncoderStack(&codec_stack_params_);
247 if (!stack) {
248 return false;
249 }
250 acm->SetEncoder(std::move(stack));
251 recreate_encoder_ = false;
252 return true;
253}
254
Henrik Lundin45c64492015-03-30 19:00:44 +0200255} // namespace acm2
256} // namespace webrtc