/* * Copyright (c) 2011 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 "voe_codec_impl.h" #include "audio_coding_module.h" #include "channel.h" #include "critical_section_wrapper.h" #include "trace.h" #include "voe_errors.h" #include "voice_engine_impl.h" namespace webrtc { VoECodec* VoECodec::GetInterface(VoiceEngine* voiceEngine) { #ifndef WEBRTC_VOICE_ENGINE_CODEC_API return NULL; #else if (NULL == voiceEngine) { return NULL; } VoiceEngineImpl* s = reinterpret_cast (voiceEngine); VoECodecImpl* d = s; (*d)++; return (d); #endif } #ifdef WEBRTC_VOICE_ENGINE_CODEC_API VoECodecImpl::VoECodecImpl() { WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1), "VoECodecImpl() - ctor"); } VoECodecImpl::~VoECodecImpl() { WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1), "~VoECodecImpl() - dtor"); } int VoECodecImpl::Release() { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "VoECodecImpl::Release()"); (*this)--; int refCount = GetCount(); if (refCount < 0) { Reset(); _engineStatistics.SetLastError(VE_INTERFACE_NOT_FOUND, kTraceWarning); return (-1); } WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), "VoECodecImpl reference counter = %d", refCount); return (refCount); } int VoECodecImpl::NumOfCodecs() { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "NumOfCodecs()"); // Number of supported codecs in the ACM WebRtc_UWord8 nSupportedCodecs = AudioCodingModule::NumberOfCodecs(); WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), "NumOfCodecs() => %u", nSupportedCodecs); return (nSupportedCodecs); } int VoECodecImpl::GetCodec(int index, CodecInst& codec) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "GetCodec(index=%d, codec=?)", index); CodecInst acmCodec; if (AudioCodingModule::Codec(index, (CodecInst&) acmCodec) == -1) { _engineStatistics.SetLastError(VE_INVALID_LISTNR, kTraceError, "GetCodec() invalid index"); return -1; } ACMToExternalCodecRepresentation(codec, acmCodec); WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), "GetCodec() => plname=%s, pacsize=%d, plfreq=%d, pltype=%d, " "channels=%d, rate=%d", codec.plname, codec.pacsize, codec.plfreq, codec.pltype, codec.channels, codec.rate); return 0; } int VoECodecImpl::SetSendCodec(int channel, const CodecInst& codec) { CodecInst copyCodec; ExternalToACMCodecRepresentation(copyCodec, codec); WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetSendCodec(channel=%d, codec)", channel); WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), "codec: plname=%s, pacsize=%d, plfreq=%d, pltype=%d, " "channels=%d, rate=%d", codec.plname, codec.pacsize, codec.plfreq, codec.pltype, codec.channels, codec.rate); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } // External sanity checks performed outside the ACM if ((STR_CASE_CMP(copyCodec.plname, "L16") == 0) && (copyCodec.pacsize >= 960)) { _engineStatistics.SetLastError(VE_INVALID_ARGUMENT, kTraceError, "SetSendCodec() invalid L16 packet " "size"); return -1; } if (!STR_CASE_CMP(copyCodec.plname, "CN") || !STR_CASE_CMP(copyCodec.plname, "TELEPHONE-EVENT") || !STR_CASE_CMP(copyCodec.plname, "RED")) { _engineStatistics.SetLastError(VE_INVALID_ARGUMENT, kTraceError, "SetSendCodec() invalid codec name"); return -1; } if (copyCodec.channels != 1) { _engineStatistics.SetLastError(VE_INVALID_ARGUMENT, kTraceError, "SetSendCodec() invalid number of " "channels"); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "GetSendCodec() failed to locate " "channel"); return -1; } if (!AudioCodingModule::IsCodecValid( (CodecInst&) copyCodec)) { _engineStatistics.SetLastError(VE_INVALID_ARGUMENT, kTraceError, "SetSendCodec() invalid codec"); return -1; } if (channelPtr->SetSendCodec(copyCodec) != 0) { _engineStatistics.SetLastError(VE_CANNOT_SET_SEND_CODEC, kTraceError, "SetSendCodec() failed to set send " "codec"); return -1; } return 0; } int VoECodecImpl::GetSendCodec(int channel, CodecInst& codec) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "GetSendCodec(channel=%d, codec=?)", channel); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "GetSendCodec() failed to locate " "channel"); return -1; } CodecInst acmCodec; if (channelPtr->GetSendCodec(acmCodec) != 0) { _engineStatistics.SetLastError(VE_CANNOT_GET_SEND_CODEC, kTraceError, "GetSendCodec() failed to get send " "codec"); return -1; } ACMToExternalCodecRepresentation(codec, acmCodec); WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), "GetSendCodec() => plname=%s, pacsize=%d, plfreq=%d, " "channels=%d, rate=%d", codec.plname, codec.pacsize, codec.plfreq, codec.channels, codec.rate); return 0; } int VoECodecImpl::GetRecCodec(int channel, CodecInst& codec) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "GetRecCodec(channel=%d, codec=?)", channel); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "GetRecCodec() failed to locate " "channel"); return -1; } CodecInst acmCodec; if (channelPtr->GetRecCodec(acmCodec) != 0) { _engineStatistics.SetLastError(VE_CANNOT_GET_REC_CODEC, kTraceError, "GetRecCodec() failed to get received " "codec"); return -1; } ACMToExternalCodecRepresentation(codec, acmCodec); WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), "GetRecCodec() => plname=%s, pacsize=%d, plfreq=%d, " "channels=%d, rate=%d", codec.plname, codec.pacsize, codec.plfreq, codec.channels, codec.rate); return 0; } int VoECodecImpl::SetAMREncFormat(int channel, AmrMode mode) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetAMREncFormat(channel=%d, mode=%d)", channel, mode); #ifdef WEBRTC_CODEC_GSMAMR if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetAMREncFormat() failed to locate " "channel"); return -1; } return channelPtr->SetAMREncFormat(mode); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetAMREncFormat() AMR codec is not " "supported"); return -1; #endif } int VoECodecImpl::SetAMRDecFormat(int channel, AmrMode mode) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetAMRDecFormat(channel=%i, mode=%i)", channel, mode); #ifdef WEBRTC_CODEC_GSMAMR if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetAMRDecFormat() failed to locate " "channel"); return -1; } return channelPtr->SetAMRDecFormat(mode); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetAMRDecFormat() AMR codec is not " "supported"); return -1; #endif } int VoECodecImpl::SetAMRWbEncFormat(int channel, AmrMode mode) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetAMRWbEncFormat(channel=%d, mode=%d)", channel, mode); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); #ifdef WEBRTC_CODEC_GSMAMRWB if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetAMRWbEncFormat() failed to locate " "channel"); return -1; } return channelPtr->SetAMRWbEncFormat(mode); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetAMRWbEncFormat() AMR-wb codec is not " "supported"); return -1; #endif } int VoECodecImpl::SetAMRWbDecFormat(int channel, AmrMode mode) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetAMRWbDecFormat(channel=%i, mode=%i)", channel, mode); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); #ifdef WEBRTC_CODEC_GSMAMRWB if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetAMRWbDecFormat() failed to locate " "channel"); return -1; } return channelPtr->SetAMRWbDecFormat(mode); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetAMRWbDecFormat() AMR-wb codec is not " "supported"); return -1; #endif } int VoECodecImpl::SetRecPayloadType(int channel, const CodecInst& codec) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetRecPayloadType(channel=%d, codec)", channel); WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), "codec: plname=%s, plfreq=%d, pltype=%d, channels=%u, " "pacsize=%d, rate=%d", codec.plname, codec.plfreq, codec.pltype, codec.channels, codec.pacsize, codec.rate); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "GetRecPayloadType() failed to locate " "channel"); return -1; } return channelPtr->SetRecPayloadType(codec); } int VoECodecImpl::GetRecPayloadType(int channel, CodecInst& codec) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "GetRecPayloadType(channel=%d, codec)", channel); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.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(_instanceId, -1), "SetSendCNPayloadType(channel=%d, type=%d, frequency=%d)", channel, type, frequency); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } if (type < 96 || type > 127) { // Only allow dynamic range: 96 to 127 _engineStatistics.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. _engineStatistics.SetLastError(VE_INVALID_PLFREQ, kTraceError, "SetSendCNPayloadType() invalid payload" " frequency"); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetSendCNPayloadType() failed to " "locate channel"); return -1; } if (channelPtr->Sending()) { _engineStatistics.SetLastError(VE_SENDING, kTraceError, "SetSendCNPayloadType unable so set " "payload type while sending"); return -1; } return channelPtr->SetSendCNPayloadType(type, frequency); } int VoECodecImpl::SetISACInitTargetRate(int channel, int rateBps, bool useFixedFrameSize) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetISACInitTargetRate(channel=%d, rateBps=%d, " "useFixedFrameSize=%d)", channel, rateBps, useFixedFrameSize); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); #ifdef WEBRTC_CODEC_ISAC if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetISACInitTargetRate() failed to " "locate channel"); return -1; } return channelPtr->SetISACInitTargetRate(rateBps, useFixedFrameSize); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetISACInitTargetRate() iSAC codec is not " "supported"); return -1; #endif } int VoECodecImpl::SetISACMaxRate(int channel, int rateBps) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetISACMaxRate(channel=%d, rateBps=%d)", channel, rateBps); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); #ifdef WEBRTC_CODEC_ISAC if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetISACMaxRate() failed to locate " "channel"); return -1; } return channelPtr->SetISACMaxRate(rateBps); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetISACMaxRate() iSAC codec is not " "supported"); return -1; #endif } int VoECodecImpl::SetISACMaxPayloadSize(int channel, int sizeBytes) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetISACMaxPayloadSize(channel=%d, sizeBytes=%d)", channel, sizeBytes); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); #ifdef WEBRTC_CODEC_ISAC if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, "SetISACMaxPayloadSize() failed to " "locate channel"); return -1; } return channelPtr->SetISACMaxPayloadSize(sizeBytes); #else _engineStatistics.SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, "SetISACMaxPayloadSize() iSAC codec is not " "supported"); return -1; #endif return 0; } int VoECodecImpl::SetVADStatus(int channel, bool enable, VadModes mode, bool disableDTX) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "SetVADStatus(channel=%i, enable=%i, mode=%i, disableDTX=%i)", channel, enable, mode, disableDTX); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.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; default: _engineStatistics.SetLastError(VE_INVALID_ARGUMENT, kTraceError, "SetVADStatus() invalid VAD mode"); return -1; } return channelPtr->SetVADStatus(enable, vadMode, disableDTX); } int VoECodecImpl::GetVADStatus(int channel, bool& enabled, VadModes& mode, bool& disabledDTX) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), "GetVADStatus(channel=%i)", channel); if (!_engineStatistics.Initialized()) { _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; } voe::ScopedChannel sc(_channelManager, channel); voe::Channel* channelPtr = sc.ChannelPtr(); if (channelPtr == NULL) { _engineStatistics.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) { _engineStatistics.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; default: _engineStatistics.SetLastError(VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "GetVADStatus() invalid VAD mode"); return -1; } return 0; } void VoECodecImpl::ACMToExternalCodecRepresentation(CodecInst& toInst, const CodecInst& fromInst) { toInst = fromInst; if (STR_CASE_CMP(fromInst.plname,"SILK") == 0) { if (fromInst.plfreq == 12000) { if (fromInst.pacsize == 320) { toInst.pacsize = 240; } else if (fromInst.pacsize == 640) { toInst.pacsize = 480; } else if (fromInst.pacsize == 960) { toInst.pacsize = 720; } } else if (fromInst.plfreq == 24000) { if (fromInst.pacsize == 640) { toInst.pacsize = 480; } else if (fromInst.pacsize == 1280) { toInst.pacsize = 960; } else if (fromInst.pacsize == 1920) { toInst.pacsize = 1440; } } } } void VoECodecImpl::ExternalToACMCodecRepresentation(CodecInst& toInst, const CodecInst& fromInst) { toInst = fromInst; if (STR_CASE_CMP(fromInst.plname,"SILK") == 0) { if (fromInst.plfreq == 12000) { if (fromInst.pacsize == 240) { toInst.pacsize = 320; } else if (fromInst.pacsize == 480) { toInst.pacsize = 640; } else if (fromInst.pacsize == 720) { toInst.pacsize = 960; } } else if (fromInst.plfreq == 24000) { if (fromInst.pacsize == 480) { toInst.pacsize = 640; } else if (fromInst.pacsize == 960) { toInst.pacsize = 1280; } else if (fromInst.pacsize == 1440) { toInst.pacsize = 1920; } } } } #endif // WEBRTC_VOICE_ENGINE_CODEC_API } // namespace webrtc