Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 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" |
Karl Wiberg | 5168ae6 | 2015-05-18 10:18:54 | [diff] [blame] | 14 | #include "webrtc/engine_configurations.h" |
| 15 | #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 16 | #include "webrtc/system_wrappers/interface/trace.h" |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 17 | |
| 18 | namespace webrtc { |
| 19 | namespace acm2 { |
| 20 | |
| 21 | namespace { |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 22 | bool IsCodecRED(const CodecInst& codec) { |
| 23 | return (STR_CASE_CMP(codec.plname, "RED") == 0); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 24 | } |
| 25 | |
| 26 | bool IsCodecRED(int index) { |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 27 | return (IsCodecRED(ACMCodecDB::database_[index])); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 28 | } |
| 29 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 30 | bool IsCodecCN(const CodecInst& codec) { |
| 31 | return (STR_CASE_CMP(codec.plname, "CN") == 0); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 32 | } |
| 33 | |
| 34 | bool IsCodecCN(int index) { |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 35 | return (IsCodecCN(ACMCodecDB::database_[index])); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | // Check if the given codec is a valid to be registered as send codec. |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 39 | int IsValidSendCodec(const CodecInst& send_codec, bool is_primary_encoder) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 40 | int dummy_id = 0; |
| 41 | if ((send_codec.channels != 1) && (send_codec.channels != 2)) { |
| 42 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 43 | "Wrong number of channels (%d, only mono and stereo are " |
| 44 | "supported) for %s encoder", |
| 45 | send_codec.channels, |
| 46 | is_primary_encoder ? "primary" : "secondary"); |
| 47 | return -1; |
| 48 | } |
| 49 | |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 50 | int codec_id = ACMCodecDB::CodecNumber(send_codec); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 51 | if (codec_id < 0) { |
| 52 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 53 | "Invalid codec setting for the send codec."); |
| 54 | return -1; |
| 55 | } |
| 56 | |
| 57 | // TODO(tlegrand): Remove this check. Already taken care of in |
| 58 | // ACMCodecDB::CodecNumber(). |
| 59 | // Check if the payload-type is valid |
| 60 | if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { |
| 61 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 62 | "Invalid payload-type %d for %s.", send_codec.pltype, |
| 63 | send_codec.plname); |
| 64 | return -1; |
| 65 | } |
| 66 | |
| 67 | // Telephone-event cannot be a send codec. |
| 68 | if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { |
| 69 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 70 | "telephone-event cannot be a send codec"); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 71 | return -1; |
| 72 | } |
| 73 | |
| 74 | if (ACMCodecDB::codec_settings_[codec_id].channel_support < |
| 75 | send_codec.channels) { |
| 76 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 77 | "%d number of channels not supportedn for %s.", |
| 78 | send_codec.channels, send_codec.plname); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 79 | return -1; |
| 80 | } |
| 81 | |
| 82 | if (!is_primary_encoder) { |
| 83 | // If registering the secondary encoder, then RED and CN are not valid |
| 84 | // choices as encoder. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 85 | if (IsCodecRED(send_codec)) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 86 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 87 | "RED cannot be secondary codec"); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 88 | return -1; |
| 89 | } |
| 90 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 91 | if (IsCodecCN(send_codec)) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 92 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 93 | "DTX cannot be secondary codec"); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 94 | return -1; |
| 95 | } |
| 96 | } |
| 97 | return codec_id; |
| 98 | } |
| 99 | |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 100 | bool IsIsac(const CodecInst& codec) { |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 101 | return |
| 102 | #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) |
| 103 | !STR_CASE_CMP(codec.plname, "isac") || |
| 104 | #endif |
| 105 | false; |
| 106 | } |
| 107 | |
| 108 | bool IsOpus(const CodecInst& codec) { |
| 109 | return |
| 110 | #ifdef WEBRTC_CODEC_OPUS |
| 111 | !STR_CASE_CMP(codec.plname, "opus") || |
| 112 | #endif |
| 113 | false; |
| 114 | } |
| 115 | |
| 116 | bool IsPcmU(const CodecInst& codec) { |
| 117 | return !STR_CASE_CMP(codec.plname, "pcmu"); |
| 118 | } |
| 119 | |
| 120 | bool IsPcmA(const CodecInst& codec) { |
| 121 | return !STR_CASE_CMP(codec.plname, "pcma"); |
| 122 | } |
| 123 | |
| 124 | bool IsPcm16B(const CodecInst& codec) { |
| 125 | return |
| 126 | #ifdef WEBRTC_CODEC_PCM16 |
| 127 | !STR_CASE_CMP(codec.plname, "l16") || |
| 128 | #endif |
| 129 | false; |
| 130 | } |
| 131 | |
| 132 | bool IsIlbc(const CodecInst& codec) { |
| 133 | return |
| 134 | #ifdef WEBRTC_CODEC_ILBC |
| 135 | !STR_CASE_CMP(codec.plname, "ilbc") || |
| 136 | #endif |
| 137 | false; |
| 138 | } |
| 139 | |
| 140 | bool IsG722(const CodecInst& codec) { |
| 141 | return |
| 142 | #ifdef WEBRTC_CODEC_G722 |
| 143 | !STR_CASE_CMP(codec.plname, "g722") || |
| 144 | #endif |
| 145 | false; |
| 146 | } |
| 147 | |
| 148 | bool CodecSupported(const CodecInst& codec) { |
| 149 | return IsOpus(codec) || IsPcmU(codec) || IsPcmA(codec) || IsPcm16B(codec) || |
| 150 | IsIlbc(codec) || IsG722(codec) || IsIsac(codec); |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 151 | } |
| 152 | |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 153 | const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0}; |
| 154 | } // namespace |
| 155 | |
Karl Wiberg | 5168ae6 | 2015-05-18 10:18:54 | [diff] [blame] | 156 | CodecManager::CodecManager() |
| 157 | : cng_nb_pltype_(255), |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 158 | cng_wb_pltype_(255), |
| 159 | cng_swb_pltype_(255), |
| 160 | cng_fb_pltype_(255), |
| 161 | red_nb_pltype_(255), |
| 162 | stereo_send_(false), |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 163 | dtx_enabled_(false), |
| 164 | vad_mode_(VADNormal), |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 165 | send_codec_inst_(kEmptyCodecInst), |
| 166 | red_enabled_(false), |
| 167 | codec_fec_enabled_(false) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 168 | // Register the default payload type for RED and for CNG at sampling rates of |
| 169 | // 8, 16, 32 and 48 kHz. |
| 170 | for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) { |
| 171 | if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) { |
| 172 | red_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype); |
| 173 | } else if (IsCodecCN(i)) { |
| 174 | if (ACMCodecDB::database_[i].plfreq == 8000) { |
| 175 | cng_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype); |
| 176 | } else if (ACMCodecDB::database_[i].plfreq == 16000) { |
| 177 | cng_wb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype); |
| 178 | } else if (ACMCodecDB::database_[i].plfreq == 32000) { |
| 179 | cng_swb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype); |
| 180 | } else if (ACMCodecDB::database_[i].plfreq == 48000) { |
| 181 | cng_fb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype); |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | thread_checker_.DetachFromThread(); |
| 186 | } |
| 187 | |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 188 | CodecManager::~CodecManager() = default; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 189 | |
Karl Wiberg | 48a57c6 | 2015-05-18 12:52:29 | [diff] [blame] | 190 | int CodecManager::RegisterEncoder(const CodecInst& send_codec) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 191 | DCHECK(thread_checker_.CalledOnValidThread()); |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 192 | int codec_id = IsValidSendCodec(send_codec, true); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 193 | |
| 194 | // Check for reported errors from function IsValidSendCodec(). |
| 195 | if (codec_id < 0) { |
| 196 | return -1; |
| 197 | } |
| 198 | |
| 199 | int dummy_id = 0; |
| 200 | // RED can be registered with other payload type. If not registered a default |
| 201 | // payload type is used. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 202 | if (IsCodecRED(send_codec)) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 203 | // TODO(tlegrand): Remove this check. Already taken care of in |
| 204 | // ACMCodecDB::CodecNumber(). |
| 205 | // Check if the payload-type is valid |
| 206 | if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { |
| 207 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 208 | "Invalid payload-type %d for %s.", send_codec.pltype, |
| 209 | send_codec.plname); |
| 210 | return -1; |
| 211 | } |
| 212 | // Set RED payload type. |
| 213 | if (send_codec.plfreq == 8000) { |
| 214 | red_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype); |
| 215 | } else { |
| 216 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 217 | "RegisterSendCodec() failed, invalid frequency for RED " |
| 218 | "registration"); |
| 219 | return -1; |
| 220 | } |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | // CNG can be registered with other payload type. If not registered the |
| 225 | // default payload types from codec database will be used. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 226 | if (IsCodecCN(send_codec)) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 227 | // CNG is registered. |
| 228 | switch (send_codec.plfreq) { |
| 229 | case 8000: { |
| 230 | cng_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype); |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 231 | return 0; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 232 | } |
| 233 | case 16000: { |
| 234 | cng_wb_pltype_ = static_cast<uint8_t>(send_codec.pltype); |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 235 | return 0; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 236 | } |
| 237 | case 32000: { |
| 238 | cng_swb_pltype_ = static_cast<uint8_t>(send_codec.pltype); |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 239 | return 0; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 240 | } |
| 241 | case 48000: { |
| 242 | cng_fb_pltype_ = static_cast<uint8_t>(send_codec.pltype); |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 243 | return 0; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 244 | } |
| 245 | default: { |
| 246 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, |
| 247 | "RegisterSendCodec() failed, invalid frequency for CNG " |
| 248 | "registration"); |
| 249 | return -1; |
| 250 | } |
| 251 | } |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | // Set Stereo, and make sure VAD and DTX is turned off. |
| 255 | if (send_codec.channels == 2) { |
| 256 | stereo_send_ = true; |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 257 | if (dtx_enabled_) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 258 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, dummy_id, |
| 259 | "VAD/DTX is turned off, not supported when sending stereo."); |
| 260 | } |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 261 | dtx_enabled_ = false; |
| 262 | } else { |
| 263 | stereo_send_ = false; |
| 264 | } |
| 265 | |
| 266 | // Check if the codec is already registered as send codec. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 267 | bool new_codec = true; |
| 268 | if (codec_owner_.Encoder()) { |
| 269 | int new_codec_id = ACMCodecDB::CodecNumber(send_codec_inst_); |
| 270 | DCHECK_GE(new_codec_id, 0); |
| 271 | new_codec = new_codec_id != codec_id; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 272 | } |
| 273 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 274 | if (RedPayloadType(send_codec.plfreq) == -1) { |
| 275 | red_enabled_ = false; |
| 276 | } |
| 277 | |
| 278 | if (new_codec) { |
| 279 | // This is a new codec. Register it and return. |
| 280 | DCHECK(CodecSupported(send_codec)); |
| 281 | if (IsOpus(send_codec)) { |
| 282 | // VAD/DTX not supported. |
| 283 | dtx_enabled_ = false; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 284 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 285 | codec_owner_.SetEncoders( |
| 286 | send_codec, dtx_enabled_ ? CngPayloadType(send_codec.plfreq) : -1, |
| 287 | vad_mode_, red_enabled_ ? RedPayloadType(send_codec.plfreq) : -1); |
| 288 | DCHECK(codec_owner_.Encoder()); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 289 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 290 | codec_fec_enabled_ = |
| 291 | codec_fec_enabled_ && |
| 292 | codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 293 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 294 | send_codec_inst_ = send_codec; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 295 | return 0; |
| 296 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 297 | |
| 298 | // This is an existing codec; re-create it if any parameters have changed. |
| 299 | if (send_codec_inst_.plfreq != send_codec.plfreq || |
| 300 | send_codec_inst_.pacsize != send_codec.pacsize || |
| 301 | send_codec_inst_.channels != send_codec.channels) { |
| 302 | codec_owner_.SetEncoders( |
| 303 | send_codec, dtx_enabled_ ? CngPayloadType(send_codec.plfreq) : -1, |
| 304 | vad_mode_, red_enabled_ ? RedPayloadType(send_codec.plfreq) : -1); |
| 305 | DCHECK(codec_owner_.Encoder()); |
| 306 | } |
| 307 | send_codec_inst_.plfreq = send_codec.plfreq; |
| 308 | send_codec_inst_.pacsize = send_codec.pacsize; |
| 309 | send_codec_inst_.channels = send_codec.channels; |
| 310 | send_codec_inst_.pltype = send_codec.pltype; |
| 311 | |
| 312 | // Check if a change in Rate is required. |
| 313 | if (send_codec.rate != send_codec_inst_.rate) { |
| 314 | codec_owner_.SpeechEncoder()->SetTargetBitrate(send_codec.rate); |
| 315 | send_codec_inst_.rate = send_codec.rate; |
| 316 | } |
| 317 | |
| 318 | codec_fec_enabled_ = codec_fec_enabled_ && |
| 319 | codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_); |
| 320 | |
| 321 | return 0; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 322 | } |
| 323 | |
Karl Wiberg | 48a57c6 | 2015-05-18 12:52:29 | [diff] [blame] | 324 | void CodecManager::RegisterEncoder( |
| 325 | AudioEncoderMutable* external_speech_encoder) { |
| 326 | // Make up a CodecInst. |
| 327 | send_codec_inst_.channels = external_speech_encoder->NumChannels(); |
| 328 | send_codec_inst_.plfreq = external_speech_encoder->SampleRateHz(); |
Peter Kasting | a0ad248 | 2015-08-24 21:52:23 | [diff] [blame^] | 329 | send_codec_inst_.pacsize = rtc::CheckedDivExact( |
| 330 | static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() * |
| 331 | send_codec_inst_.plfreq), |
| 332 | 100); |
Karl Wiberg | 48a57c6 | 2015-05-18 12:52:29 | [diff] [blame] | 333 | send_codec_inst_.pltype = -1; // Not valid. |
| 334 | send_codec_inst_.rate = -1; // Not valid. |
| 335 | static const char kName[] = "external"; |
| 336 | memcpy(send_codec_inst_.plname, kName, sizeof(kName)); |
| 337 | |
| 338 | if (stereo_send_) |
| 339 | dtx_enabled_ = false; |
| 340 | codec_fec_enabled_ = codec_fec_enabled_ && |
| 341 | codec_owner_.SpeechEncoder()->SetFec(codec_fec_enabled_); |
| 342 | int cng_pt = dtx_enabled_ |
| 343 | ? CngPayloadType(external_speech_encoder->SampleRateHz()) |
| 344 | : -1; |
| 345 | int red_pt = red_enabled_ ? RedPayloadType(send_codec_inst_.plfreq) : -1; |
| 346 | codec_owner_.SetEncoders(external_speech_encoder, cng_pt, vad_mode_, red_pt); |
| 347 | } |
| 348 | |
| 349 | int CodecManager::GetCodecInst(CodecInst* current_codec) const { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 350 | int dummy_id = 0; |
| 351 | WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, |
| 352 | "SendCodec()"); |
| 353 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 354 | if (!codec_owner_.Encoder()) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 355 | WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, |
| 356 | "SendCodec Failed, no codec is registered"); |
| 357 | return -1; |
| 358 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 359 | *current_codec = send_codec_inst_; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 360 | return 0; |
| 361 | } |
| 362 | |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 363 | bool CodecManager::SetCopyRed(bool enable) { |
| 364 | if (enable && codec_fec_enabled_) { |
| 365 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, |
| 366 | "Codec internal FEC and RED cannot be co-enabled."); |
| 367 | return false; |
| 368 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 369 | if (enable && RedPayloadType(send_codec_inst_.plfreq) == -1) { |
| 370 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, |
| 371 | "Cannot enable RED at %i Hz.", send_codec_inst_.plfreq); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 372 | return false; |
| 373 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 374 | if (red_enabled_ != enable) { |
| 375 | red_enabled_ = enable; |
Karl Wiberg | 48a57c6 | 2015-05-18 12:52:29 | [diff] [blame] | 376 | if (codec_owner_.Encoder()) { |
| 377 | int cng_pt = dtx_enabled_ ? CngPayloadType(send_codec_inst_.plfreq) : -1; |
| 378 | int red_pt = red_enabled_ ? RedPayloadType(send_codec_inst_.plfreq) : -1; |
| 379 | codec_owner_.ChangeCngAndRed(cng_pt, vad_mode_, red_pt); |
| 380 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 381 | } |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 382 | return true; |
| 383 | } |
| 384 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 385 | int CodecManager::SetVAD(bool enable, ACMVADMode mode) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 386 | // Sanity check of the mode. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 387 | DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr || |
| 388 | mode == VADVeryAggr); |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 389 | |
| 390 | // Check that the send codec is mono. We don't support VAD/DTX for stereo |
| 391 | // sending. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 392 | if (enable && stereo_send_) { |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 393 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, |
| 394 | "VAD/DTX not supported for stereo sending"); |
| 395 | dtx_enabled_ = false; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 396 | return -1; |
| 397 | } |
| 398 | |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 399 | // If a send codec is registered, set VAD/DTX for the codec. |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 400 | if (IsOpus(send_codec_inst_)) { |
| 401 | // VAD/DTX not supported. |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 402 | dtx_enabled_ = false; |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 403 | return 0; |
| 404 | } |
| 405 | |
| 406 | if (dtx_enabled_ != enable || vad_mode_ != mode) { |
| 407 | dtx_enabled_ = enable; |
| 408 | vad_mode_ = mode; |
Karl Wiberg | 48a57c6 | 2015-05-18 12:52:29 | [diff] [blame] | 409 | if (codec_owner_.Encoder()) { |
| 410 | int cng_pt = dtx_enabled_ ? CngPayloadType(send_codec_inst_.plfreq) : -1; |
| 411 | int red_pt = red_enabled_ ? RedPayloadType(send_codec_inst_.plfreq) : -1; |
| 412 | codec_owner_.ChangeCngAndRed(cng_pt, vad_mode_, red_pt); |
| 413 | } |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 414 | } |
| 415 | return 0; |
| 416 | } |
| 417 | |
| 418 | void CodecManager::VAD(bool* dtx_enabled, |
| 419 | bool* vad_enabled, |
| 420 | ACMVADMode* mode) const { |
| 421 | *dtx_enabled = dtx_enabled_; |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 422 | *vad_enabled = dtx_enabled_; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 423 | *mode = vad_mode_; |
| 424 | } |
| 425 | |
| 426 | int CodecManager::SetCodecFEC(bool enable_codec_fec) { |
| 427 | if (enable_codec_fec == true && red_enabled_ == true) { |
| 428 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, |
| 429 | "Codec internal FEC and RED cannot be co-enabled."); |
| 430 | return -1; |
| 431 | } |
| 432 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 433 | CHECK(codec_owner_.SpeechEncoder()); |
| 434 | codec_fec_enabled_ = codec_owner_.SpeechEncoder()->SetFec(enable_codec_fec) && |
| 435 | enable_codec_fec; |
| 436 | return codec_fec_enabled_ == enable_codec_fec ? 0 : -1; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 437 | } |
| 438 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 439 | AudioDecoder* CodecManager::GetAudioDecoder(const CodecInst& codec) { |
| 440 | return IsIsac(codec) ? codec_owner_.GetIsacDecoder() : nullptr; |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 441 | } |
| 442 | |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 443 | int CodecManager::CngPayloadType(int sample_rate_hz) const { |
| 444 | switch (sample_rate_hz) { |
| 445 | case 8000: |
| 446 | return cng_nb_pltype_; |
| 447 | case 16000: |
| 448 | return cng_wb_pltype_; |
| 449 | case 32000: |
| 450 | return cng_swb_pltype_; |
| 451 | case 48000: |
| 452 | return cng_fb_pltype_; |
| 453 | default: |
| 454 | FATAL() << sample_rate_hz << " Hz is not supported"; |
Henrik Lundin | dc04434 | 2015-04-13 07:31:16 | [diff] [blame] | 455 | return -1; |
| 456 | } |
Karl Wiberg | 6d216ed | 2015-05-07 13:49:23 | [diff] [blame] | 457 | } |
| 458 | |
| 459 | int CodecManager::RedPayloadType(int sample_rate_hz) const { |
| 460 | switch (sample_rate_hz) { |
| 461 | case 8000: |
| 462 | return red_nb_pltype_; |
| 463 | case 16000: |
| 464 | case 32000: |
| 465 | case 48000: |
| 466 | return -1; |
| 467 | default: |
| 468 | FATAL() << sample_rate_hz << " Hz is not supported"; |
| 469 | return -1; |
| 470 | } |
Henrik Lundin | 046319e | 2015-03-30 17:00:44 | [diff] [blame] | 471 | } |
| 472 | |
| 473 | } // namespace acm2 |
| 474 | } // namespace webrtc |