blob: 6f470be106a6fb85a0a0f48a626d56cd8ab8d421 [file] [log] [blame]
/*
* 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/main/interface/audio_coding_module.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/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)
{
#ifndef WEBRTC_VOICE_ENGINE_CODEC_API
return NULL;
#else
if (NULL == voiceEngine)
{
return NULL;
}
VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
s->AddRef();
return s;
#endif
}
#ifdef WEBRTC_VOICE_ENGINE_CODEC_API
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()
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"NumOfCodecs()");
// Number of supported codecs in the ACM
uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_shared->instance_id(), -1),
"NumOfCodecs() => %u", nSupportedCodecs);
return (nSupportedCodecs);
}
int VoECodecImpl::GetCodec(int index, CodecInst& codec)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetCodec(index=%d, codec=?)", index);
CodecInst acmCodec;
if (AudioCodingModule::Codec(index, &acmCodec)
== -1)
{
_shared->SetLastError(VE_INVALID_LISTNR, kTraceError,
"GetCodec() invalid index");
return -1;
}
ACMToExternalCodecRepresentation(codec, acmCodec);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_shared->instance_id(), -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(_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=%d, 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(copyCodec.plname, "L16") == 0) &&
(copyCodec.pacsize >= 960))
{
_shared->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"))
{
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetSendCodec() invalid codec name");
return -1;
}
if ((copyCodec.channels != 1) && (copyCodec.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(
(CodecInst&) copyCodec))
{
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetSendCodec() invalid codec");
return -1;
}
if (channelPtr->SetSendCodec(copyCodec) != 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)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetSendCodec(channel=%d, codec=?)", 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,
"GetSendCodec() failed to locate channel");
return -1;
}
CodecInst acmCodec;
if (channelPtr->GetSendCodec(acmCodec) != 0)
{
_shared->SetLastError(VE_CANNOT_GET_SEND_CODEC, kTraceError,
"GetSendCodec() failed to get send codec");
return -1;
}
ACMToExternalCodecRepresentation(codec, acmCodec);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_shared->instance_id(), -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(_shared->instance_id(), -1),
"GetRecCodec(channel=%d, codec=?)", 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,
"GetRecCodec() failed to locate channel");
return -1;
}
CodecInst acmCodec;
if (channelPtr->GetRecCodec(acmCodec) != 0)
{
_shared->SetLastError(VE_CANNOT_GET_REC_CODEC, kTraceError,
"GetRecCodec() failed to get received codec");
return -1;
}
ACMToExternalCodecRepresentation(codec, acmCodec);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_shared->instance_id(), -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::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=%u, "
"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)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetRecPayloadType(channel=%d, codec)", 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,
"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) {
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetCodecFECStatus(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,
"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)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetVADStatus(channel=%i)", 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,
"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);
}
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;
}
}
}
}
int VoECodecImpl::SetSecondarySendCodec(int channel, const CodecInst& codec,
int red_payload_type) {
CodecInst copy_codec;
ExternalToACMCodecRepresentation(copy_codec, codec);
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"SetSecondarySendCodec(channel=%d, codec)", channel);
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -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 (!_shared->statistics().Initialized()) {
_shared->SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
// External sanity checks performed outside the ACM
if ((STR_CASE_CMP(copy_codec.plname, "L16") == 0) &&
(copy_codec.pacsize >= 960)) {
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetSecondarySendCodec() invalid L16 packet size");
return -1;
}
// None of the following codecs can be registered as the secondary encoder.
if (!STR_CASE_CMP(copy_codec.plname, "CN") ||
!STR_CASE_CMP(copy_codec.plname, "TELEPHONE-EVENT") ||
!STR_CASE_CMP(copy_codec.plname, "RED")) {
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetSecondarySendCodec() invalid codec name");
return -1;
}
// Only mono and stereo are supported.
if ((copy_codec.channels != 1) && (copy_codec.channels != 2)) {
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetSecondarySendCodec() 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,
"SetSecondarySendCodec() failed to locate channel");
return -1;
}
if (!AudioCodingModule::IsCodecValid(copy_codec)) {
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
"SetSecondarySendCodec() invalid codec");
return -1;
}
if (channelPtr->SetSecondarySendCodec(copy_codec, red_payload_type) != 0) {
_shared->SetLastError(VE_CANNOT_SET_SECONDARY_SEND_CODEC, kTraceError,
"SetSecondarySendCodec() failed to set secondary "
"send codec");
return -1;
}
return 0;
}
int VoECodecImpl::GetSecondarySendCodec(int channel, CodecInst& codec) {
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"GetSecondarySendCodec(channel=%d, codec=?)", 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,
"GetSecondarySendCodec() failed to locate channel");
return -1;
}
CodecInst acm_codec;
if (channelPtr->GetSecondarySendCodec(&acm_codec) != 0) {
_shared->SetLastError(VE_CANNOT_GET_SECONDARY_SEND_CODEC, kTraceError,
"GetSecondarySendCodec() failed to get secondary "
"send codec");
return -1;
}
ACMToExternalCodecRepresentation(codec, acm_codec);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_shared->instance_id(), -1),
"GetSecondarySendCodec() => plname=%s, pacsize=%d, plfreq=%d, "
"channels=%d, rate=%d", codec.plname, codec.pacsize,
codec.plfreq, codec.channels, codec.rate);
return 0;
}
int VoECodecImpl::RemoveSecondarySendCodec(int channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
"RemoveSecondarySendCodec(channel=%d)", channel);
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
voe::Channel* channelPtr = ch.channel();
if (channelPtr == NULL) {
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
"RemoveSecondarySendCodec() failed to locate "
"channel");
return -1;
}
channelPtr->RemoveSecondarySendCodec();
return 0;
}
#endif // WEBRTC_VOICE_ENGINE_CODEC_API
} // namespace webrtc