blob: 561d744f0fdb8906489a27098e81017ef128e1fa [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"
Karl Wibergbd1bc472015-05-18 12:18:54 +020014#include "webrtc/engine_configurations.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"
Henrik Lundin45c64492015-03-30 19:00:44 +020017
18namespace webrtc {
19namespace acm2 {
20
21namespace {
Henrik Lundin45c64492015-03-30 19:00:44 +020022
Henrik Lundin45c64492015-03-30 19:00:44 +020023// Check if the given codec is a valid to be registered as send codec.
kwiberg223692a2015-11-18 08:27:51 -080024int IsValidSendCodec(const CodecInst& send_codec) {
Henrik Lundin45c64492015-03-30 19:00:44 +020025 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 "
kwiberg223692a2015-11-18 08:27:51 -080029 "supported)",
30 send_codec.channels);
Henrik Lundin45c64492015-03-30 19:00:44 +020031 return -1;
32 }
33
kwibergd6c0f8c2015-11-06 14:28:00 -080034 auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec);
35 if (!maybe_codec_id) {
Henrik Lundin45c64492015-03-30 19:00:44 +020036 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
37 "Invalid codec setting for the send codec.");
38 return -1;
39 }
40
Henrik Lundin45c64492015-03-30 19:00:44 +020041 // 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");
Henrik Lundin45c64492015-03-30 19:00:44 +020045 return -1;
46 }
47
kwibergd6c0f8c2015-11-06 14:28:00 -080048 if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels)
49 .value_or(false)) {
Henrik Lundin45c64492015-03-30 19:00:44 +020050 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
51 "%d number of channels not supportedn for %s.",
52 send_codec.channels, send_codec.plname);
Henrik Lundin45c64492015-03-30 19:00:44 +020053 return -1;
54 }
kwibergd6c0f8c2015-11-06 14:28:00 -080055 return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1);
Henrik Lundin45c64492015-03-30 19:00:44 +020056}
57
Henrik Lundin93ef1d82015-04-13 09:31:16 +020058bool IsIsac(const CodecInst& codec) {
Karl Wiberg2ea71c32015-05-07 15:49:23 +020059 return
60#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
61 !STR_CASE_CMP(codec.plname, "isac") ||
62#endif
63 false;
64}
65
66bool IsOpus(const CodecInst& codec) {
67 return
68#ifdef WEBRTC_CODEC_OPUS
69 !STR_CASE_CMP(codec.plname, "opus") ||
70#endif
71 false;
72}
73
74bool IsPcmU(const CodecInst& codec) {
75 return !STR_CASE_CMP(codec.plname, "pcmu");
76}
77
78bool IsPcmA(const CodecInst& codec) {
79 return !STR_CASE_CMP(codec.plname, "pcma");
80}
81
82bool IsPcm16B(const CodecInst& codec) {
kwiberg844a9102015-09-16 09:42:18 -070083 return !STR_CASE_CMP(codec.plname, "l16");
Karl Wiberg2ea71c32015-05-07 15:49:23 +020084}
85
86bool IsIlbc(const CodecInst& codec) {
87 return
88#ifdef WEBRTC_CODEC_ILBC
89 !STR_CASE_CMP(codec.plname, "ilbc") ||
90#endif
91 false;
92}
93
94bool IsG722(const CodecInst& codec) {
95 return
96#ifdef WEBRTC_CODEC_G722
97 !STR_CASE_CMP(codec.plname, "g722") ||
98#endif
99 false;
100}
101
102bool CodecSupported(const CodecInst& codec) {
103 return IsOpus(codec) || IsPcmU(codec) || IsPcmA(codec) || IsPcm16B(codec) ||
104 IsIlbc(codec) || IsG722(codec) || IsIsac(codec);
Henrik Lundin93ef1d82015-04-13 09:31:16 +0200105}
106
Henrik Lundin45c64492015-03-30 19:00:44 +0200107const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0};
108} // namespace
109
Karl Wibergbd1bc472015-05-18 12:18:54 +0200110CodecManager::CodecManager()
kwiberg1379f1f2015-11-23 04:30:52 -0800111 : send_codec_inst_(kEmptyCodecInst), encoder_is_opus_(false) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200112 thread_checker_.DetachFromThread();
113}
114
Henrik Lundin93ef1d82015-04-13 09:31:16 +0200115CodecManager::~CodecManager() = default;
Henrik Lundin45c64492015-03-30 19:00:44 +0200116
Karl Wiberg7e0c7d42015-05-18 14:52:29 +0200117int CodecManager::RegisterEncoder(const CodecInst& send_codec) {
henrikg91d6ede2015-09-17 00:24:34 -0700118 RTC_DCHECK(thread_checker_.CalledOnValidThread());
kwiberg223692a2015-11-18 08:27:51 -0800119 int codec_id = IsValidSendCodec(send_codec);
Henrik Lundin45c64492015-03-30 19:00:44 +0200120
121 // Check for reported errors from function IsValidSendCodec().
122 if (codec_id < 0) {
123 return -1;
124 }
125
126 int dummy_id = 0;
kwiberg1379f1f2015-11-23 04:30:52 -0800127 switch (RentACodec::RegisterRedPayloadType(
128 &codec_stack_params_.red_payload_types, send_codec)) {
kwiberge1a27d42015-11-18 07:32:49 -0800129 case RentACodec::RegistrationResult::kOk:
130 return 0;
131 case RentACodec::RegistrationResult::kBadFreq:
Henrik Lundin45c64492015-03-30 19:00:44 +0200132 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
kwiberge1a27d42015-11-18 07:32:49 -0800133 "RegisterSendCodec() failed, invalid frequency for RED"
134 " registration");
Henrik Lundin45c64492015-03-30 19:00:44 +0200135 return -1;
kwiberge1a27d42015-11-18 07:32:49 -0800136 case RentACodec::RegistrationResult::kSkip:
137 break;
Henrik Lundin45c64492015-03-30 19:00:44 +0200138 }
kwiberg1379f1f2015-11-23 04:30:52 -0800139 switch (RentACodec::RegisterCngPayloadType(
140 &codec_stack_params_.cng_payload_types, send_codec)) {
kwiberge1a27d42015-11-18 07:32:49 -0800141 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;
Henrik Lundin45c64492015-03-30 19:00:44 +0200150 }
151
kwiberg12cfc9b2015-09-08 05:57:53 -0700152 encoder_is_opus_ = IsOpus(send_codec);
kwibergdfbb3a42015-12-01 04:45:04 -0800153 if (encoder_is_opus_) {
154 // VAD/DTX not supported.
155 codec_stack_params_.use_cng = false;
Henrik Lundin45c64492015-03-30 19:00:44 +0200156 }
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200157
kwibergdfbb3a42015-12-01 04:45:04 -0800158 // Recreate the encoder if anything except the send bitrate has changed.
159 if (!CurrentEncoder() || send_codec_inst_.pltype != send_codec.pltype ||
160 STR_CASE_CMP(send_codec_inst_.plname, send_codec.plname) != 0 ||
161 send_codec_inst_.plfreq != send_codec.plfreq ||
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200162 send_codec_inst_.pacsize != send_codec.pacsize ||
163 send_codec_inst_.channels != send_codec.channels) {
kwibergdfbb3a42015-12-01 04:45:04 -0800164 RTC_DCHECK(CodecSupported(send_codec));
kwibergc95c3662015-11-10 06:35:21 -0800165 AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec);
166 if (!enc)
kwiberg574d5da2015-09-24 22:53:55 -0700167 return -1;
kwiberg1379f1f2015-11-23 04:30:52 -0800168 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
kwiberge155ae62015-11-16 04:49:54 -0800169 RTC_DCHECK(CurrentEncoder());
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200170 }
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200171
kwibergdfbb3a42015-12-01 04:45:04 -0800172 send_codec_inst_ = send_codec;
173 CurrentEncoder()->SetTargetBitrate(send_codec_inst_.rate);
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200174 return 0;
Henrik Lundin45c64492015-03-30 19:00:44 +0200175}
176
kwiberg12cfc9b2015-09-08 05:57:53 -0700177void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) {
Karl Wiberg7e0c7d42015-05-18 14:52:29 +0200178 // Make up a CodecInst.
179 send_codec_inst_.channels = external_speech_encoder->NumChannels();
180 send_codec_inst_.plfreq = external_speech_encoder->SampleRateHz();
Peter Kastingdce40cf2015-08-24 14:52:23 -0700181 send_codec_inst_.pacsize = rtc::CheckedDivExact(
182 static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() *
183 send_codec_inst_.plfreq),
184 100);
Karl Wiberg7e0c7d42015-05-18 14:52:29 +0200185 send_codec_inst_.pltype = -1; // Not valid.
186 send_codec_inst_.rate = -1; // Not valid.
187 static const char kName[] = "external";
188 memcpy(send_codec_inst_.plname, kName, sizeof(kName));
189
kwiberg1379f1f2015-11-23 04:30:52 -0800190 rent_a_codec_.RentEncoderStack(external_speech_encoder, &codec_stack_params_);
Karl Wiberg7e0c7d42015-05-18 14:52:29 +0200191}
192
Karl Wibergbe579832015-11-10 22:34:18 +0100193rtc::Optional<CodecInst> CodecManager::GetCodecInst() const {
Henrik Lundin45c64492015-03-30 19:00:44 +0200194 int dummy_id = 0;
195 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id,
196 "SendCodec()");
197
kwiberge155ae62015-11-16 04:49:54 -0800198 if (!CurrentEncoder()) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200199 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id,
200 "SendCodec Failed, no codec is registered");
Karl Wibergbe579832015-11-10 22:34:18 +0100201 return rtc::Optional<CodecInst>();
Henrik Lundin45c64492015-03-30 19:00:44 +0200202 }
Karl Wibergbe579832015-11-10 22:34:18 +0100203 return rtc::Optional<CodecInst>(send_codec_inst_);
Henrik Lundin45c64492015-03-30 19:00:44 +0200204}
205
Henrik Lundin45c64492015-03-30 19:00:44 +0200206bool CodecManager::SetCopyRed(bool enable) {
kwiberg1379f1f2015-11-23 04:30:52 -0800207 if (enable && codec_stack_params_.use_codec_fec) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200208 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
209 "Codec internal FEC and RED cannot be co-enabled.");
210 return false;
211 }
kwiberg1379f1f2015-11-23 04:30:52 -0800212 if (enable &&
213 codec_stack_params_.red_payload_types.count(send_codec_inst_.plfreq) <
214 1) {
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200215 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
216 "Cannot enable RED at %i Hz.", send_codec_inst_.plfreq);
Henrik Lundin45c64492015-03-30 19:00:44 +0200217 return false;
218 }
kwiberg1379f1f2015-11-23 04:30:52 -0800219 if (codec_stack_params_.use_red != enable) {
220 codec_stack_params_.use_red = enable;
kwiberge155ae62015-11-16 04:49:54 -0800221 if (CurrentEncoder())
kwiberg1379f1f2015-11-23 04:30:52 -0800222 rent_a_codec_.RentEncoderStack(rent_a_codec_.GetEncoder(),
223 &codec_stack_params_);
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200224 }
Henrik Lundin45c64492015-03-30 19:00:44 +0200225 return true;
226}
227
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200228int CodecManager::SetVAD(bool enable, ACMVADMode mode) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200229 // Sanity check of the mode.
henrikg91d6ede2015-09-17 00:24:34 -0700230 RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr ||
231 mode == VADVeryAggr);
Henrik Lundin45c64492015-03-30 19:00:44 +0200232
233 // Check that the send codec is mono. We don't support VAD/DTX for stereo
234 // sending.
kwiberge155ae62015-11-16 04:49:54 -0800235 auto* enc = rent_a_codec_.GetEncoder();
kwiberged8275a2015-11-10 09:47:36 -0800236 const bool stereo_send = enc ? (enc->NumChannels() != 1) : false;
237 if (enable && stereo_send) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200238 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
239 "VAD/DTX not supported for stereo sending");
kwiberg1379f1f2015-11-23 04:30:52 -0800240 codec_stack_params_.use_cng = false;
Henrik Lundin45c64492015-03-30 19:00:44 +0200241 return -1;
242 }
243
Henrik Lundin45c64492015-03-30 19:00:44 +0200244 // If a send codec is registered, set VAD/DTX for the codec.
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200245 if (IsOpus(send_codec_inst_)) {
246 // VAD/DTX not supported.
kwiberg1379f1f2015-11-23 04:30:52 -0800247 codec_stack_params_.use_cng = false;
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200248 return 0;
249 }
250
kwiberg1379f1f2015-11-23 04:30:52 -0800251 if (codec_stack_params_.use_cng != enable ||
252 codec_stack_params_.vad_mode != mode) {
253 codec_stack_params_.use_cng = enable;
254 codec_stack_params_.vad_mode = mode;
kwiberge155ae62015-11-16 04:49:54 -0800255 if (enc)
kwiberg1379f1f2015-11-23 04:30:52 -0800256 rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
Henrik Lundin45c64492015-03-30 19:00:44 +0200257 }
258 return 0;
259}
260
261void CodecManager::VAD(bool* dtx_enabled,
262 bool* vad_enabled,
263 ACMVADMode* mode) const {
kwiberg1379f1f2015-11-23 04:30:52 -0800264 *dtx_enabled = *vad_enabled = codec_stack_params_.use_cng;
265 *mode = codec_stack_params_.vad_mode;
Henrik Lundin45c64492015-03-30 19:00:44 +0200266}
267
268int CodecManager::SetCodecFEC(bool enable_codec_fec) {
kwiberg1379f1f2015-11-23 04:30:52 -0800269 if (enable_codec_fec && codec_stack_params_.use_red) {
Henrik Lundin45c64492015-03-30 19:00:44 +0200270 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
271 "Codec internal FEC and RED cannot be co-enabled.");
272 return -1;
273 }
274
kwiberge155ae62015-11-16 04:49:54 -0800275 RTC_CHECK(CurrentEncoder());
kwiberg1379f1f2015-11-23 04:30:52 -0800276 codec_stack_params_.use_codec_fec =
kwiberge155ae62015-11-16 04:49:54 -0800277 CurrentEncoder()->SetFec(enable_codec_fec) && enable_codec_fec;
kwiberg1379f1f2015-11-23 04:30:52 -0800278 return codec_stack_params_.use_codec_fec == enable_codec_fec ? 0 : -1;
Henrik Lundin45c64492015-03-30 19:00:44 +0200279}
280
Karl Wiberg2ea71c32015-05-07 15:49:23 +0200281AudioDecoder* CodecManager::GetAudioDecoder(const CodecInst& codec) {
kwibergc95c3662015-11-10 06:35:21 -0800282 return IsIsac(codec) ? rent_a_codec_.RentIsacDecoder() : nullptr;
Henrik Lundin45c64492015-03-30 19:00:44 +0200283}
284
Henrik Lundin45c64492015-03-30 19:00:44 +0200285} // namespace acm2
286} // namespace webrtc