webrtc/modules/audio_coding/acm2/rent_a_codec.cc
Karl Wiberg 7275e18439 Hide the internal AudioEncoderOpus class by giving it an "Impl" suffix
We've done this previously with the other audio encoders, but Opus had
to wait until all external users had been updated.

BUG=webrtc:7847

Change-Id: I70422d7b6c715f32a43bee88febcf6b6155e18b3
Reviewed-on: https://webrtc-review.googlesource.com/8000
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Oskar Sundbom <ossu@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20424}
2017-10-25 10:19:06 +00:00

314 lines
11 KiB
C++

/*
* Copyright (c) 2015 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 "modules/audio_coding/acm2/rent_a_codec.h"
#include <memory>
#include <utility>
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
#include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
#include "rtc_base/logging.h"
#ifdef WEBRTC_CODEC_G722
#include "modules/audio_coding/codecs/g722/audio_encoder_g722.h"
#endif
#ifdef WEBRTC_CODEC_ILBC
#include "modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h"
#endif
#ifdef WEBRTC_CODEC_ISACFX
#include "modules/audio_coding/codecs/isac/fix/include/audio_decoder_isacfix.h" // nogncheck
#include "modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h" // nogncheck
#endif
#ifdef WEBRTC_CODEC_ISAC
#include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" // nogncheck
#include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" // nogncheck
#endif
#ifdef WEBRTC_CODEC_OPUS
#include "modules/audio_coding/codecs/opus/audio_encoder_opus.h"
#endif
#include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
#ifdef WEBRTC_CODEC_RED
#include "modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
#endif
#include "modules/audio_coding/acm2/acm_codec_database.h"
#if defined(WEBRTC_CODEC_ISACFX) || defined(WEBRTC_CODEC_ISAC)
#include "modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
#endif
namespace webrtc {
namespace acm2 {
rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByParams(
const char* payload_name,
int sampling_freq_hz,
size_t channels) {
return CodecIdFromIndex(
ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels));
}
rtc::Optional<CodecInst> RentACodec::CodecInstById(CodecId codec_id) {
rtc::Optional<int> mi = CodecIndexFromId(codec_id);
return mi ? rtc::Optional<CodecInst>(Database()[*mi])
: rtc::Optional<CodecInst>();
}
rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByInst(
const CodecInst& codec_inst) {
return CodecIdFromIndex(ACMCodecDB::CodecNumber(codec_inst));
}
rtc::Optional<CodecInst> RentACodec::CodecInstByParams(const char* payload_name,
int sampling_freq_hz,
size_t channels) {
rtc::Optional<CodecId> codec_id =
CodecIdByParams(payload_name, sampling_freq_hz, channels);
if (!codec_id)
return rtc::Optional<CodecInst>();
rtc::Optional<CodecInst> ci = CodecInstById(*codec_id);
RTC_DCHECK(ci);
// Keep the number of channels from the function call. For most codecs it
// will be the same value as in default codec settings, but not for all.
ci->channels = channels;
return ci;
}
bool RentACodec::IsCodecValid(const CodecInst& codec_inst) {
return ACMCodecDB::CodecNumber(codec_inst) >= 0;
}
rtc::Optional<bool> RentACodec::IsSupportedNumChannels(CodecId codec_id,
size_t num_channels) {
auto i = CodecIndexFromId(codec_id);
return i ? rtc::Optional<bool>(
ACMCodecDB::codec_settings_[*i].channel_support >=
num_channels)
: rtc::Optional<bool>();
}
rtc::ArrayView<const CodecInst> RentACodec::Database() {
return rtc::ArrayView<const CodecInst>(ACMCodecDB::database_,
NumberOfCodecs());
}
rtc::Optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId(
CodecId codec_id,
size_t num_channels) {
rtc::Optional<int> i = CodecIndexFromId(codec_id);
if (!i)
return rtc::Optional<NetEqDecoder>();
const NetEqDecoder ned = ACMCodecDB::neteq_decoders_[*i];
return rtc::Optional<NetEqDecoder>(
(ned == NetEqDecoder::kDecoderOpus && num_channels == 2)
? NetEqDecoder::kDecoderOpus_2ch
: ned);
}
RentACodec::RegistrationResult RentACodec::RegisterCngPayloadType(
std::map<int, int>* pt_map,
const CodecInst& codec_inst) {
if (STR_CASE_CMP(codec_inst.plname, "CN") != 0)
return RegistrationResult::kSkip;
switch (codec_inst.plfreq) {
case 8000:
case 16000:
case 32000:
case 48000:
(*pt_map)[codec_inst.plfreq] = codec_inst.pltype;
return RegistrationResult::kOk;
default:
return RegistrationResult::kBadFreq;
}
}
RentACodec::RegistrationResult RentACodec::RegisterRedPayloadType(
std::map<int, int>* pt_map,
const CodecInst& codec_inst) {
if (STR_CASE_CMP(codec_inst.plname, "RED") != 0)
return RegistrationResult::kSkip;
switch (codec_inst.plfreq) {
case 8000:
(*pt_map)[codec_inst.plfreq] = codec_inst.pltype;
return RegistrationResult::kOk;
default:
return RegistrationResult::kBadFreq;
}
}
namespace {
// Returns a new speech encoder, or null on error.
// TODO(kwiberg): Don't handle errors here (bug 5033)
std::unique_ptr<AudioEncoder> CreateEncoder(
const CodecInst& speech_inst,
const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo) {
#if defined(WEBRTC_CODEC_ISACFX)
if (STR_CASE_CMP(speech_inst.plname, "isac") == 0)
return std::unique_ptr<AudioEncoder>(
new AudioEncoderIsacFixImpl(speech_inst, bwinfo));
#endif
#if defined(WEBRTC_CODEC_ISAC)
if (STR_CASE_CMP(speech_inst.plname, "isac") == 0)
return std::unique_ptr<AudioEncoder>(
new AudioEncoderIsacFloatImpl(speech_inst, bwinfo));
#endif
#ifdef WEBRTC_CODEC_OPUS
if (STR_CASE_CMP(speech_inst.plname, "opus") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderOpusImpl(speech_inst));
#endif
if (STR_CASE_CMP(speech_inst.plname, "pcmu") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcmU(speech_inst));
if (STR_CASE_CMP(speech_inst.plname, "pcma") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcmA(speech_inst));
if (STR_CASE_CMP(speech_inst.plname, "l16") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcm16B(speech_inst));
#ifdef WEBRTC_CODEC_ILBC
if (STR_CASE_CMP(speech_inst.plname, "ilbc") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderIlbcImpl(speech_inst));
#endif
#ifdef WEBRTC_CODEC_G722
if (STR_CASE_CMP(speech_inst.plname, "g722") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderG722Impl(speech_inst));
#endif
LOG_F(LS_ERROR) << "Could not create encoder of type " << speech_inst.plname;
return std::unique_ptr<AudioEncoder>();
}
std::unique_ptr<AudioEncoder> CreateRedEncoder(
std::unique_ptr<AudioEncoder> encoder,
int red_payload_type) {
#ifdef WEBRTC_CODEC_RED
AudioEncoderCopyRed::Config config;
config.payload_type = red_payload_type;
config.speech_encoder = std::move(encoder);
return std::unique_ptr<AudioEncoder>(
new AudioEncoderCopyRed(std::move(config)));
#else
return std::unique_ptr<AudioEncoder>();
#endif
}
std::unique_ptr<AudioEncoder> CreateCngEncoder(
std::unique_ptr<AudioEncoder> encoder,
int payload_type,
ACMVADMode vad_mode) {
AudioEncoderCng::Config config;
config.num_channels = encoder->NumChannels();
config.payload_type = payload_type;
config.speech_encoder = std::move(encoder);
switch (vad_mode) {
case VADNormal:
config.vad_mode = Vad::kVadNormal;
break;
case VADLowBitrate:
config.vad_mode = Vad::kVadLowBitrate;
break;
case VADAggr:
config.vad_mode = Vad::kVadAggressive;
break;
case VADVeryAggr:
config.vad_mode = Vad::kVadVeryAggressive;
break;
default:
FATAL();
}
return std::unique_ptr<AudioEncoder>(new AudioEncoderCng(std::move(config)));
}
std::unique_ptr<AudioDecoder> CreateIsacDecoder(
int sample_rate_hz,
const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo) {
#if defined(WEBRTC_CODEC_ISACFX)
return std::unique_ptr<AudioDecoder>(
new AudioDecoderIsacFixImpl(sample_rate_hz, bwinfo));
#elif defined(WEBRTC_CODEC_ISAC)
return std::unique_ptr<AudioDecoder>(
new AudioDecoderIsacFloatImpl(sample_rate_hz, bwinfo));
#else
FATAL() << "iSAC is not supported.";
return std::unique_ptr<AudioDecoder>();
#endif
}
} // namespace
RentACodec::RentACodec() {
#if defined(WEBRTC_CODEC_ISACFX) || defined(WEBRTC_CODEC_ISAC)
isac_bandwidth_info_ = new LockedIsacBandwidthInfo;
#endif
}
RentACodec::~RentACodec() = default;
std::unique_ptr<AudioEncoder> RentACodec::RentEncoder(
const CodecInst& codec_inst) {
return CreateEncoder(codec_inst, isac_bandwidth_info_);
}
RentACodec::StackParameters::StackParameters() {
// Register the default payload types for RED and CNG.
for (const CodecInst& ci : RentACodec::Database()) {
RentACodec::RegisterCngPayloadType(&cng_payload_types, ci);
RentACodec::RegisterRedPayloadType(&red_payload_types, ci);
}
}
RentACodec::StackParameters::~StackParameters() = default;
std::unique_ptr<AudioEncoder> RentACodec::RentEncoderStack(
StackParameters* param) {
if (!param->speech_encoder)
return nullptr;
if (param->use_codec_fec) {
// Switch FEC on. On failure, remember that FEC is off.
if (!param->speech_encoder->SetFec(true))
param->use_codec_fec = false;
} else {
// Switch FEC off. This shouldn't fail.
const bool success = param->speech_encoder->SetFec(false);
RTC_DCHECK(success);
}
auto pt = [&param](const std::map<int, int>& m) {
auto it = m.find(param->speech_encoder->SampleRateHz());
return it == m.end() ? rtc::Optional<int>()
: rtc::Optional<int>(it->second);
};
auto cng_pt = pt(param->cng_payload_types);
param->use_cng =
param->use_cng && cng_pt && param->speech_encoder->NumChannels() == 1;
auto red_pt = pt(param->red_payload_types);
param->use_red = param->use_red && red_pt;
if (param->use_cng || param->use_red) {
// The RED and CNG encoders need to be in sync with the speech encoder, so
// reset the latter to ensure its buffer is empty.
param->speech_encoder->Reset();
}
std::unique_ptr<AudioEncoder> encoder_stack =
std::move(param->speech_encoder);
if (param->use_red) {
encoder_stack = CreateRedEncoder(std::move(encoder_stack), *red_pt);
}
if (param->use_cng) {
encoder_stack =
CreateCngEncoder(std::move(encoder_stack), *cng_pt, param->vad_mode);
}
return encoder_stack;
}
std::unique_ptr<AudioDecoder> RentACodec::RentIsacDecoder(int sample_rate_hz) {
return CreateIsacDecoder(sample_rate_hz, isac_bandwidth_info_);
}
} // namespace acm2
} // namespace webrtc