| /* | 
 |  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "webrtc/voice_engine/voe_codec_impl.h" | 
 |  | 
 | #include "webrtc/modules/audio_coding/include/audio_coding_module.h" | 
 | #include "webrtc/rtc_base/format_macros.h" | 
 | #include "webrtc/system_wrappers/include/trace.h" | 
 | #include "webrtc/voice_engine/channel.h" | 
 | #include "webrtc/voice_engine/include/voe_errors.h" | 
 | #include "webrtc/voice_engine/voice_engine_impl.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | VoECodec* VoECodec::GetInterface(VoiceEngine* voiceEngine) { | 
 |   if (NULL == voiceEngine) { | 
 |     return NULL; | 
 |   } | 
 |   VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); | 
 |   s->AddRef(); | 
 |   return s; | 
 | } | 
 |  | 
 | VoECodecImpl::VoECodecImpl(voe::SharedData* shared) : _shared(shared) { | 
 |   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "VoECodecImpl() - ctor"); | 
 | } | 
 |  | 
 | VoECodecImpl::~VoECodecImpl() { | 
 |   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "~VoECodecImpl() - dtor"); | 
 | } | 
 |  | 
 | int VoECodecImpl::NumOfCodecs() { | 
 |   // Number of supported codecs in the ACM | 
 |   uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs(); | 
 |   return (nSupportedCodecs); | 
 | } | 
 |  | 
 | int VoECodecImpl::GetCodec(int index, CodecInst& codec) { | 
 |   if (AudioCodingModule::Codec(index, &codec) == -1) { | 
 |     _shared->SetLastError(VE_INVALID_LISTNR, kTraceError, | 
 |                           "GetCodec() invalid index"); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int VoECodecImpl::SetSendCodec(int channel, const CodecInst& codec) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetSendCodec(channel=%d, codec)", channel); | 
 |   WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "codec: plname=%s, pacsize=%d, plfreq=%d, pltype=%d, " | 
 |                "channels=%" PRIuS ", rate=%d", | 
 |                codec.plname, codec.pacsize, codec.plfreq, codec.pltype, | 
 |                codec.channels, codec.rate); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   // External sanity checks performed outside the ACM | 
 |   if ((STR_CASE_CMP(codec.plname, "L16") == 0) && (codec.pacsize >= 960)) { | 
 |     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, | 
 |                           "SetSendCodec() invalid L16 packet size"); | 
 |     return -1; | 
 |   } | 
 |   if (!STR_CASE_CMP(codec.plname, "CN") || | 
 |       !STR_CASE_CMP(codec.plname, "TELEPHONE-EVENT") || | 
 |       !STR_CASE_CMP(codec.plname, "RED")) { | 
 |     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, | 
 |                           "SetSendCodec() invalid codec name"); | 
 |     return -1; | 
 |   } | 
 |   if ((codec.channels != 1) && (codec.channels != 2)) { | 
 |     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, | 
 |                           "SetSendCodec() invalid number of channels"); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetSendCodec() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   if (!AudioCodingModule::IsCodecValid(codec)) { | 
 |     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, | 
 |                           "SetSendCodec() invalid codec"); | 
 |     return -1; | 
 |   } | 
 |   if (channelPtr->SetSendCodec(codec) != 0) { | 
 |     _shared->SetLastError(VE_CANNOT_SET_SEND_CODEC, kTraceError, | 
 |                           "SetSendCodec() failed to set send codec"); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | int VoECodecImpl::GetSendCodec(int channel, CodecInst& codec) { | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetSendCodec() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   if (channelPtr->GetSendCodec(codec) != 0) { | 
 |     _shared->SetLastError(VE_CANNOT_GET_SEND_CODEC, kTraceError, | 
 |                           "GetSendCodec() failed to get send codec"); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int VoECodecImpl::SetBitRate(int channel, int bitrate_bps) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetBitRate(bitrate_bps=%d)", bitrate_bps); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   constexpr int64_t kDefaultProbingIntervalMs = 3000; | 
 |   _shared->channel_manager().GetChannel(channel).channel()->SetBitRate( | 
 |       bitrate_bps, kDefaultProbingIntervalMs); | 
 |   return 0; | 
 | } | 
 |  | 
 | int VoECodecImpl::GetRecCodec(int channel, CodecInst& codec) { | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetRecCodec() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->GetRecCodec(codec); | 
 | } | 
 |  | 
 | int VoECodecImpl::SetRecPayloadType(int channel, const CodecInst& codec) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetRecPayloadType(channel=%d, codec)", channel); | 
 |   WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "codec: plname=%s, plfreq=%d, pltype=%d, channels=%" PRIuS ", " | 
 |                "pacsize=%d, rate=%d", | 
 |                codec.plname, codec.plfreq, codec.pltype, codec.channels, | 
 |                codec.pacsize, codec.rate); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetRecPayloadType() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->SetRecPayloadType(codec); | 
 | } | 
 |  | 
 | int VoECodecImpl::GetRecPayloadType(int channel, CodecInst& codec) { | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetRecPayloadType() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->GetRecPayloadType(codec); | 
 | } | 
 |  | 
 | int VoECodecImpl::SetSendCNPayloadType(int channel, | 
 |                                        int type, | 
 |                                        PayloadFrequencies frequency) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetSendCNPayloadType(channel=%d, type=%d, frequency=%d)", | 
 |                channel, type, frequency); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   if (type < 96 || type > 127) { | 
 |     // Only allow dynamic range: 96 to 127 | 
 |     _shared->SetLastError(VE_INVALID_PLTYPE, kTraceError, | 
 |                           "SetSendCNPayloadType() invalid payload type"); | 
 |     return -1; | 
 |   } | 
 |   if ((frequency != kFreq16000Hz) && (frequency != kFreq32000Hz)) { | 
 |     // It is not possible to modify the payload type for CN/8000. | 
 |     // We only allow modification of the CN payload type for CN/16000 | 
 |     // and CN/32000. | 
 |     _shared->SetLastError(VE_INVALID_PLFREQ, kTraceError, | 
 |                           "SetSendCNPayloadType() invalid payload frequency"); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "SetSendCNPayloadType() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->SetSendCNPayloadType(type, frequency); | 
 | } | 
 |  | 
 | int VoECodecImpl::SetFECStatus(int channel, bool enable) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetCodecFECStatus(channel=%d, enable=%d)", channel, enable); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "SetCodecFECStatus() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->SetCodecFECStatus(enable); | 
 | } | 
 |  | 
 | int VoECodecImpl::GetFECStatus(int channel, bool& enabled) { | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetFECStatus() failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   enabled = channelPtr->GetCodecFECStatus(); | 
 |   return 0; | 
 | } | 
 |  | 
 | int VoECodecImpl::SetVADStatus(int channel, | 
 |                                bool enable, | 
 |                                VadModes mode, | 
 |                                bool disableDTX) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetVADStatus(channel=%i, enable=%i, mode=%i, disableDTX=%i)", | 
 |                channel, enable, mode, disableDTX); | 
 |  | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "SetVADStatus failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   ACMVADMode vadMode(VADNormal); | 
 |   switch (mode) { | 
 |     case kVadConventional: | 
 |       vadMode = VADNormal; | 
 |       break; | 
 |     case kVadAggressiveLow: | 
 |       vadMode = VADLowBitrate; | 
 |       break; | 
 |     case kVadAggressiveMid: | 
 |       vadMode = VADAggr; | 
 |       break; | 
 |     case kVadAggressiveHigh: | 
 |       vadMode = VADVeryAggr; | 
 |       break; | 
 |   } | 
 |   return channelPtr->SetVADStatus(enable, vadMode, disableDTX); | 
 | } | 
 |  | 
 | int VoECodecImpl::GetVADStatus(int channel, | 
 |                                bool& enabled, | 
 |                                VadModes& mode, | 
 |                                bool& disabledDTX) { | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetVADStatus failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   ACMVADMode vadMode; | 
 |   int ret = channelPtr->GetVADStatus(enabled, vadMode, disabledDTX); | 
 |  | 
 |   if (ret != 0) { | 
 |     _shared->SetLastError(VE_INVALID_OPERATION, kTraceError, | 
 |                           "GetVADStatus failed to get VAD mode"); | 
 |     return -1; | 
 |   } | 
 |   switch (vadMode) { | 
 |     case VADNormal: | 
 |       mode = kVadConventional; | 
 |       break; | 
 |     case VADLowBitrate: | 
 |       mode = kVadAggressiveLow; | 
 |       break; | 
 |     case VADAggr: | 
 |       mode = kVadAggressiveMid; | 
 |       break; | 
 |     case VADVeryAggr: | 
 |       mode = kVadAggressiveHigh; | 
 |       break; | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | int VoECodecImpl::SetOpusMaxPlaybackRate(int channel, int frequency_hz) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetOpusMaxPlaybackRate(channel=%d, frequency_hz=%d)", channel, | 
 |                frequency_hz); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "SetOpusMaxPlaybackRate failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->SetOpusMaxPlaybackRate(frequency_hz); | 
 | } | 
 |  | 
 | int VoECodecImpl::SetOpusDtx(int channel, bool enable_dtx) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "SetOpusDtx(channel=%d, enable_dtx=%d)", channel, enable_dtx); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "SetOpusDtx failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->SetOpusDtx(enable_dtx); | 
 | } | 
 |  | 
 | int VoECodecImpl::GetOpusDtxStatus(int channel, bool* enabled) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | 
 |                "GetOpusDtx(channel=%d)", channel); | 
 |   if (!_shared->statistics().Initialized()) { | 
 |     _shared->SetLastError(VE_NOT_INITED, kTraceError); | 
 |     return -1; | 
 |   } | 
 |   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); | 
 |   voe::Channel* channelPtr = ch.channel(); | 
 |   if (channelPtr == NULL) { | 
 |     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, | 
 |                           "GetOpusDtx failed to locate channel"); | 
 |     return -1; | 
 |   } | 
 |   return channelPtr->GetOpusDtx(enabled); | 
 | } | 
 |  | 
 | }  // namespace webrtc |