Line data Source code
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/acm2/codec_manager.h"
12 :
13 : #include "webrtc/base/checks.h"
14 : #include "webrtc/base/format_macros.h"
15 : #include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
16 : #include "webrtc/system_wrappers/include/trace.h"
17 : #include "webrtc/typedefs.h"
18 :
19 : namespace webrtc {
20 : namespace acm2 {
21 :
22 : namespace {
23 :
24 : // Check if the given codec is a valid to be registered as send codec.
25 0 : int IsValidSendCodec(const CodecInst& send_codec) {
26 0 : int dummy_id = 0;
27 0 : if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
28 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
29 : "Wrong number of channels (%" PRIuS ", only mono and stereo "
30 : "are supported)",
31 : send_codec.channels);
32 0 : return -1;
33 : }
34 :
35 0 : auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec);
36 0 : if (!maybe_codec_id) {
37 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
38 : "Invalid codec setting for the send codec.");
39 0 : return -1;
40 : }
41 :
42 : // Telephone-event cannot be a send codec.
43 0 : 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");
46 0 : return -1;
47 : }
48 :
49 0 : if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels)
50 0 : .value_or(false)) {
51 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
52 : "%" PRIuS " number of channels not supportedn for %s.",
53 : send_codec.channels, send_codec.plname);
54 0 : return -1;
55 : }
56 0 : return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1);
57 : }
58 :
59 0 : bool IsOpus(const CodecInst& codec) {
60 : return
61 : #ifdef WEBRTC_CODEC_OPUS
62 0 : !STR_CASE_CMP(codec.plname, "opus") ||
63 : #endif
64 0 : false;
65 : }
66 :
67 : } // namespace
68 :
69 0 : CodecManager::CodecManager() {
70 0 : thread_checker_.DetachFromThread();
71 0 : }
72 :
73 : CodecManager::~CodecManager() = default;
74 :
75 0 : bool CodecManager::RegisterEncoder(const CodecInst& send_codec) {
76 0 : RTC_DCHECK(thread_checker_.CalledOnValidThread());
77 0 : int codec_id = IsValidSendCodec(send_codec);
78 :
79 : // Check for reported errors from function IsValidSendCodec().
80 0 : if (codec_id < 0) {
81 0 : return false;
82 : }
83 :
84 0 : int dummy_id = 0;
85 0 : switch (RentACodec::RegisterRedPayloadType(
86 : &codec_stack_params_.red_payload_types, send_codec)) {
87 : case RentACodec::RegistrationResult::kOk:
88 0 : return true;
89 : case RentACodec::RegistrationResult::kBadFreq:
90 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
91 : "RegisterSendCodec() failed, invalid frequency for RED"
92 : " registration");
93 0 : return false;
94 : case RentACodec::RegistrationResult::kSkip:
95 0 : break;
96 : }
97 0 : switch (RentACodec::RegisterCngPayloadType(
98 : &codec_stack_params_.cng_payload_types, send_codec)) {
99 : case RentACodec::RegistrationResult::kOk:
100 0 : return true;
101 : case RentACodec::RegistrationResult::kBadFreq:
102 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
103 : "RegisterSendCodec() failed, invalid frequency for CNG"
104 : " registration");
105 0 : return false;
106 : case RentACodec::RegistrationResult::kSkip:
107 0 : break;
108 : }
109 :
110 0 : if (IsOpus(send_codec)) {
111 : // VAD/DTX not supported.
112 0 : codec_stack_params_.use_cng = false;
113 : }
114 :
115 0 : send_codec_inst_ = rtc::Optional<CodecInst>(send_codec);
116 0 : recreate_encoder_ = true; // Caller must recreate it.
117 0 : return true;
118 : }
119 :
120 0 : CodecInst CodecManager::ForgeCodecInst(
121 : const AudioEncoder* external_speech_encoder) {
122 : CodecInst ci;
123 0 : ci.channels = external_speech_encoder->NumChannels();
124 0 : ci.plfreq = external_speech_encoder->SampleRateHz();
125 0 : ci.pacsize = rtc::CheckedDivExact(
126 0 : static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() *
127 0 : ci.plfreq),
128 : 100);
129 0 : ci.pltype = -1; // Not valid.
130 0 : ci.rate = -1; // Not valid.
131 : static const char kName[] = "external";
132 0 : memcpy(ci.plname, kName, sizeof(kName));
133 0 : return ci;
134 : }
135 :
136 0 : bool CodecManager::SetCopyRed(bool enable) {
137 0 : if (enable && codec_stack_params_.use_codec_fec) {
138 : WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
139 : "Codec internal FEC and RED cannot be co-enabled.");
140 0 : return false;
141 : }
142 0 : if (enable && send_codec_inst_ &&
143 0 : codec_stack_params_.red_payload_types.count(send_codec_inst_->plfreq) <
144 : 1) {
145 : WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
146 : "Cannot enable RED at %i Hz.", send_codec_inst_->plfreq);
147 0 : return false;
148 : }
149 0 : codec_stack_params_.use_red = enable;
150 0 : return true;
151 : }
152 :
153 0 : bool CodecManager::SetVAD(bool enable, ACMVADMode mode) {
154 : // Sanity check of the mode.
155 0 : RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr ||
156 0 : mode == VADVeryAggr);
157 :
158 : // Check that the send codec is mono. We don't support VAD/DTX for stereo
159 : // sending.
160 : const bool stereo_send =
161 : codec_stack_params_.speech_encoder
162 0 : ? (codec_stack_params_.speech_encoder->NumChannels() != 1)
163 0 : : false;
164 0 : if (enable && stereo_send) {
165 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
166 : "VAD/DTX not supported for stereo sending");
167 0 : return false;
168 : }
169 :
170 : // TODO(kwiberg): This doesn't protect Opus when injected as an external
171 : // encoder.
172 0 : if (send_codec_inst_ && IsOpus(*send_codec_inst_)) {
173 : // VAD/DTX not supported, but don't fail.
174 0 : enable = false;
175 : }
176 :
177 0 : codec_stack_params_.use_cng = enable;
178 0 : codec_stack_params_.vad_mode = mode;
179 0 : return true;
180 : }
181 :
182 0 : bool CodecManager::SetCodecFEC(bool enable_codec_fec) {
183 0 : if (enable_codec_fec && codec_stack_params_.use_red) {
184 : WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
185 : "Codec internal FEC and RED cannot be co-enabled.");
186 0 : return false;
187 : }
188 :
189 0 : codec_stack_params_.use_codec_fec = enable_codec_fec;
190 0 : return true;
191 : }
192 :
193 0 : bool CodecManager::MakeEncoder(RentACodec* rac, AudioCodingModule* acm) {
194 0 : RTC_DCHECK(rac);
195 0 : RTC_DCHECK(acm);
196 :
197 0 : if (!recreate_encoder_) {
198 0 : bool error = false;
199 : // Try to re-use the speech encoder we've given to the ACM.
200 0 : acm->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
201 0 : if (!*encoder) {
202 : // There is no existing encoder.
203 0 : recreate_encoder_ = true;
204 0 : return;
205 : }
206 :
207 : // Extract the speech encoder from the ACM.
208 0 : std::unique_ptr<AudioEncoder> enc = std::move(*encoder);
209 : while (true) {
210 0 : auto sub_enc = enc->ReclaimContainedEncoders();
211 0 : if (sub_enc.empty()) {
212 0 : break;
213 : }
214 0 : RTC_CHECK_EQ(1, 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 0 : auto tmp_enc = std::move(sub_enc[0]);
221 0 : enc = std::move(tmp_enc);
222 0 : }
223 :
224 : // Wrap it in a new encoder stack and put it back.
225 0 : codec_stack_params_.speech_encoder = std::move(enc);
226 0 : *encoder = rac->RentEncoderStack(&codec_stack_params_);
227 0 : if (!*encoder) {
228 0 : error = true;
229 : }
230 0 : });
231 0 : if (error) {
232 0 : return false;
233 : }
234 0 : if (!recreate_encoder_) {
235 0 : return true;
236 : }
237 : }
238 :
239 0 : 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 0 : return true;
243 : }
244 :
245 0 : codec_stack_params_.speech_encoder = rac->RentEncoder(*send_codec_inst_);
246 0 : auto stack = rac->RentEncoderStack(&codec_stack_params_);
247 0 : if (!stack) {
248 0 : return false;
249 : }
250 0 : acm->SetEncoder(std::move(stack));
251 0 : recreate_encoder_ = false;
252 0 : return true;
253 : }
254 :
255 : } // namespace acm2
256 : } // namespace webrtc
|