AudioCodingModule: Remove support for creating encoders
After this CL, all audio encoders have to be injected by the caller. This means that there is no special "built-in" set of codecs, and users won't have to pay the binary size and security costs of codecs they aren't using. Bug: webrtc:8396 Change-Id: Idb0959ce395940c8bb3bbb49256cdcd84fc87bb6 Reviewed-on: https://webrtc-review.googlesource.com/c/103821 Commit-Queue: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Ivo Creusen <ivoc@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25600}
This commit is contained in:
@ -14,31 +14,6 @@ if (!build_with_mozilla) {
|
||||
|
||||
visibility = [ ":*" ]
|
||||
|
||||
audio_codec_deps = [
|
||||
":g711",
|
||||
":pcm16b",
|
||||
]
|
||||
if (rtc_include_ilbc) {
|
||||
audio_codec_deps += [ ":ilbc" ]
|
||||
}
|
||||
if (rtc_include_opus) {
|
||||
audio_codec_deps += [ ":webrtc_opus" ]
|
||||
}
|
||||
if (current_cpu == "arm") {
|
||||
audio_codec_deps += [ ":isac_fix" ]
|
||||
} else {
|
||||
audio_codec_deps += [ ":isac" ]
|
||||
}
|
||||
audio_codec_deps += [ ":g722" ]
|
||||
if (!build_with_mozilla && !build_with_chromium) {
|
||||
audio_codec_deps += [ ":red" ]
|
||||
}
|
||||
audio_coding_deps = audio_codec_deps + [
|
||||
"../..:webrtc_common",
|
||||
"../../common_audio",
|
||||
"../../system_wrappers",
|
||||
]
|
||||
|
||||
rtc_static_library("audio_format_conversion") {
|
||||
visibility += webrtc_default_visibility
|
||||
sources = [
|
||||
@ -63,7 +38,6 @@ rtc_static_library("rent_a_codec") {
|
||||
# TODO(bugs.webrtc.org/9808): Move to private visibility as soon as that
|
||||
# client code gets updated.
|
||||
visibility += [ "*" ]
|
||||
allow_poison = [ "audio_codecs" ]
|
||||
|
||||
sources = [
|
||||
"acm2/acm_codec_database.cc",
|
||||
@ -72,22 +46,18 @@ rtc_static_library("rent_a_codec") {
|
||||
"acm2/rent_a_codec.h",
|
||||
]
|
||||
deps = [
|
||||
"../../rtc_base:checks",
|
||||
"../../api:array_view",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
"../../api/audio_codecs:audio_codecs_api",
|
||||
":audio_coding_module_typedefs",
|
||||
":neteq_decoder_enum",
|
||||
"../..:webrtc_common",
|
||||
"../../api:array_view",
|
||||
"../../api/audio_codecs:audio_codecs_api",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:protobuf_utils",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../system_wrappers",
|
||||
":audio_coding_module_typedefs",
|
||||
":isac_common",
|
||||
":isac_fix_c",
|
||||
":audio_encoder_cng",
|
||||
":neteq_decoder_enum",
|
||||
] + audio_codec_deps
|
||||
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
defines = audio_codec_defines
|
||||
}
|
||||
|
||||
@ -102,7 +72,6 @@ rtc_source_set("audio_coding_module_typedefs") {
|
||||
|
||||
rtc_static_library("audio_coding") {
|
||||
visibility += [ "*" ]
|
||||
allow_poison = [ "audio_codecs" ] # TODO(bugs.webrtc.org/8396): Remove.
|
||||
sources = [
|
||||
"acm2/acm_receiver.cc",
|
||||
"acm2/acm_receiver.h",
|
||||
@ -111,40 +80,34 @@ rtc_static_library("audio_coding") {
|
||||
"acm2/audio_coding_module.cc",
|
||||
"acm2/call_statistics.cc",
|
||||
"acm2/call_statistics.h",
|
||||
"acm2/codec_manager.cc",
|
||||
"acm2/codec_manager.h",
|
||||
"include/audio_coding_module.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
||||
if (rtc_include_opus) {
|
||||
public_deps = [
|
||||
":webrtc_opus",
|
||||
]
|
||||
}
|
||||
|
||||
deps = audio_coding_deps + [
|
||||
"../../system_wrappers:metrics",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"..:module_api",
|
||||
"..:module_api_public",
|
||||
"../../common_audio:common_audio_c",
|
||||
"../../rtc_base:deprecation",
|
||||
"../../rtc_base:checks",
|
||||
"../../api:array_view",
|
||||
"../../api/audio_codecs:audio_codecs_api",
|
||||
deps = [
|
||||
":audio_coding_module_typedefs",
|
||||
":neteq",
|
||||
":neteq_decoder_enum",
|
||||
":rent_a_codec",
|
||||
"..:module_api",
|
||||
"..:module_api_public",
|
||||
"../..:webrtc_common",
|
||||
"../../api:array_view",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../api/audio_codecs:audio_codecs_api",
|
||||
"../../common_audio:common_audio",
|
||||
"../../common_audio:common_audio_c",
|
||||
"../../logging:rtc_event_log_api",
|
||||
"../../rtc_base:audio_format_to_string",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:deprecation",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../system_wrappers",
|
||||
"../../system_wrappers:metrics",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
"../../logging:rtc_event_log_api",
|
||||
]
|
||||
defines = audio_coding_defines
|
||||
}
|
||||
|
||||
rtc_static_library("legacy_encoded_audio_frame") {
|
||||
@ -1280,6 +1243,30 @@ if (rtc_enable_protobuf) {
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
audio_coding_deps = [
|
||||
"../../common_audio",
|
||||
"../../system_wrappers",
|
||||
"../..:webrtc_common",
|
||||
":audio_encoder_cng",
|
||||
":g711",
|
||||
":g722",
|
||||
":pcm16b",
|
||||
]
|
||||
if (rtc_include_ilbc) {
|
||||
audio_coding_deps += [ ":ilbc" ]
|
||||
}
|
||||
if (rtc_include_opus) {
|
||||
audio_coding_deps += [ ":webrtc_opus" ]
|
||||
}
|
||||
if (current_cpu == "arm") {
|
||||
audio_coding_deps += [ ":isac_fix" ]
|
||||
} else {
|
||||
audio_coding_deps += [ ":isac" ]
|
||||
}
|
||||
if (!build_with_mozilla && !build_with_chromium) {
|
||||
audio_coding_deps += [ ":red" ]
|
||||
}
|
||||
|
||||
rtc_source_set("mocks") {
|
||||
testonly = true
|
||||
sources = [
|
||||
@ -1368,6 +1355,7 @@ if (rtc_include_tests) {
|
||||
":audio_format_conversion",
|
||||
":pcm16b_c",
|
||||
":red",
|
||||
":webrtc_opus_c",
|
||||
"..:module_api",
|
||||
"../..:webrtc_common",
|
||||
"../../api/audio:audio_frame_api",
|
||||
@ -2007,8 +1995,6 @@ if (rtc_include_tests) {
|
||||
"acm2/acm_receiver_unittest.cc",
|
||||
"acm2/audio_coding_module_unittest.cc",
|
||||
"acm2/call_statistics_unittest.cc",
|
||||
"acm2/codec_manager_unittest.cc",
|
||||
"acm2/rent_a_codec_unittest.cc",
|
||||
"audio_network_adaptor/audio_network_adaptor_impl_unittest.cc",
|
||||
"audio_network_adaptor/bitrate_controller_unittest.cc",
|
||||
"audio_network_adaptor/channel_controller_unittest.cc",
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include "api/array_view.h"
|
||||
#include "modules/audio_coding/acm2/acm_receiver.h"
|
||||
#include "modules/audio_coding/acm2/acm_resampler.h"
|
||||
#include "modules/audio_coding/acm2/codec_manager.h"
|
||||
#include "modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "modules/include/module_common_types.h"
|
||||
#include "modules/include/module_common_types_public.h"
|
||||
@ -34,12 +33,6 @@ namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
struct EncoderFactory {
|
||||
AudioEncoder* external_speech_encoder = nullptr;
|
||||
acm2::CodecManager codec_manager;
|
||||
acm2::RentACodec rent_a_codec;
|
||||
};
|
||||
|
||||
class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
public:
|
||||
explicit AudioCodingModuleImpl(const AudioCodingModule::Config& config);
|
||||
@ -49,12 +42,6 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
// Sender
|
||||
//
|
||||
|
||||
// Can be called multiple times for Codec, CNG, RED.
|
||||
int RegisterSendCodec(const CodecInst& send_codec) override;
|
||||
|
||||
void RegisterExternalSendCodec(
|
||||
AudioEncoder* external_speech_encoder) override;
|
||||
|
||||
void ModifyEncoder(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)>
|
||||
modifier) override;
|
||||
|
||||
@ -73,26 +60,10 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
// Add 10 ms of raw (PCM) audio data to the encoder.
|
||||
int Add10MsData(const AudioFrame& audio_frame) override;
|
||||
|
||||
/////////////////////////////////////////
|
||||
// (RED) Redundant Coding
|
||||
//
|
||||
|
||||
// Configure RED status i.e. on/off.
|
||||
int SetREDStatus(bool enable_red) override;
|
||||
|
||||
// Get RED status.
|
||||
bool REDStatus() const override;
|
||||
|
||||
/////////////////////////////////////////
|
||||
// (FEC) Forward Error Correction (codec internal)
|
||||
//
|
||||
|
||||
// Configure FEC status i.e. on/off.
|
||||
int SetCodecFEC(bool enabled_codec_fec) override;
|
||||
|
||||
// Get FEC status.
|
||||
bool CodecFEC() const override;
|
||||
|
||||
// Set target packet loss rate
|
||||
int SetPacketLossRate(int loss_rate) override;
|
||||
|
||||
@ -102,14 +73,6 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
// (CNG) Comfort Noise Generation
|
||||
//
|
||||
|
||||
int SetVAD(bool enable_dtx = true,
|
||||
bool enable_vad = false,
|
||||
ACMVADMode mode = VADNormal) override;
|
||||
|
||||
int VAD(bool* dtx_enabled,
|
||||
bool* vad_enabled,
|
||||
ACMVADMode* mode) const override;
|
||||
|
||||
int RegisterVADCallback(ACMVADCallback* vad_callback) override;
|
||||
|
||||
/////////////////////////////////////////
|
||||
@ -130,11 +93,6 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
bool RegisterReceiveCodec(int rtp_payload_type,
|
||||
const SdpAudioFormat& audio_format) override;
|
||||
|
||||
int RegisterReceiveCodec(const CodecInst& receive_codec) override;
|
||||
int RegisterReceiveCodec(
|
||||
const CodecInst& receive_codec,
|
||||
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) override;
|
||||
|
||||
int RegisterExternalReceiveCodec(int rtp_payload_type,
|
||||
AudioDecoder* external_decoder,
|
||||
int sample_rate_hz,
|
||||
@ -222,11 +180,6 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
const std::string histogram_name_;
|
||||
};
|
||||
|
||||
int RegisterReceiveCodecUnlocked(
|
||||
const CodecInst& codec,
|
||||
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
|
||||
|
||||
int Add10MsDataInternal(const AudioFrame& audio_frame, InputData* input_data)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
|
||||
int Encode(const InputData& input_data)
|
||||
@ -264,12 +217,7 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
||||
acm2::AcmReceiver receiver_; // AcmReceiver has it's own internal lock.
|
||||
ChangeLogger bitrate_logger_ RTC_GUARDED_BY(acm_crit_sect_);
|
||||
|
||||
std::unique_ptr<EncoderFactory> encoder_factory_
|
||||
RTC_GUARDED_BY(acm_crit_sect_);
|
||||
|
||||
// Current encoder stack, either obtained from
|
||||
// encoder_factory_->rent_a_codec.RentEncoderStack or provided by a call to
|
||||
// RegisterEncoder.
|
||||
// Current encoder stack, provided by a call to RegisterEncoder.
|
||||
std::unique_ptr<AudioEncoder> encoder_stack_ RTC_GUARDED_BY(acm_crit_sect_);
|
||||
|
||||
std::unique_ptr<AudioDecoder> isac_decoder_16k_
|
||||
@ -405,28 +353,6 @@ class RawAudioEncoderWrapper final : public AudioEncoder {
|
||||
AudioEncoder* enc_;
|
||||
};
|
||||
|
||||
// Return false on error.
|
||||
bool CreateSpeechEncoderIfNecessary(EncoderFactory* ef) {
|
||||
auto* sp = ef->codec_manager.GetStackParams();
|
||||
if (sp->speech_encoder) {
|
||||
// Do nothing; we already have a speech encoder.
|
||||
} else if (ef->codec_manager.GetCodecInst()) {
|
||||
RTC_DCHECK(!ef->external_speech_encoder);
|
||||
// We have no speech encoder, but we have a specification for making one.
|
||||
std::unique_ptr<AudioEncoder> enc =
|
||||
ef->rent_a_codec.RentEncoder(*ef->codec_manager.GetCodecInst());
|
||||
if (!enc)
|
||||
return false; // Encoder spec was bad.
|
||||
sp->speech_encoder = std::move(enc);
|
||||
} else if (ef->external_speech_encoder) {
|
||||
RTC_DCHECK(!ef->codec_manager.GetCodecInst());
|
||||
// We have an external speech encoder.
|
||||
sp->speech_encoder = std::unique_ptr<AudioEncoder>(
|
||||
new RawAudioEncoderWrapper(ef->external_speech_encoder));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioCodingModuleImpl::ChangeLogger::MaybeLog(int value) {
|
||||
if (value != last_value_ || first_time_) {
|
||||
first_time_ = false;
|
||||
@ -441,7 +367,6 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(
|
||||
expected_in_ts_(0xD87F3F9F),
|
||||
receiver_(config),
|
||||
bitrate_logger_("WebRTC.Audio.TargetBitrateInKbps"),
|
||||
encoder_factory_(new EncoderFactory),
|
||||
encoder_stack_(nullptr),
|
||||
previous_pltype_(255),
|
||||
receiver_initialized_(false),
|
||||
@ -549,69 +474,29 @@ int32_t AudioCodingModuleImpl::Encode(const InputData& input_data) {
|
||||
// Sender
|
||||
//
|
||||
|
||||
// Can be called multiple times for Codec, CNG, RED.
|
||||
int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
if (!encoder_factory_->codec_manager.RegisterEncoder(send_codec)) {
|
||||
return -1;
|
||||
}
|
||||
if (encoder_factory_->codec_manager.GetCodecInst()) {
|
||||
encoder_factory_->external_speech_encoder = nullptr;
|
||||
}
|
||||
if (!CreateSpeechEncoderIfNecessary(encoder_factory_.get())) {
|
||||
return -1;
|
||||
}
|
||||
auto* sp = encoder_factory_->codec_manager.GetStackParams();
|
||||
if (sp->speech_encoder)
|
||||
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AudioCodingModuleImpl::RegisterExternalSendCodec(
|
||||
AudioEncoder* external_speech_encoder) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
encoder_factory_->codec_manager.UnsetCodecInst();
|
||||
encoder_factory_->external_speech_encoder = external_speech_encoder;
|
||||
RTC_CHECK(CreateSpeechEncoderIfNecessary(encoder_factory_.get()));
|
||||
auto* sp = encoder_factory_->codec_manager.GetStackParams();
|
||||
RTC_CHECK(sp->speech_encoder);
|
||||
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp);
|
||||
}
|
||||
|
||||
void AudioCodingModuleImpl::ModifyEncoder(
|
||||
rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
|
||||
// Wipe the encoder factory, so that everything that relies on it will fail.
|
||||
// We don't want the complexity of supporting swapping back and forth.
|
||||
if (encoder_factory_) {
|
||||
encoder_factory_.reset();
|
||||
RTC_CHECK(!encoder_stack_); // Ensure we hadn't started using the factory.
|
||||
}
|
||||
|
||||
modifier(&encoder_stack_);
|
||||
}
|
||||
|
||||
// Get current send codec.
|
||||
absl::optional<CodecInst> AudioCodingModuleImpl::SendCodec() const {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
if (encoder_factory_) {
|
||||
auto* ci = encoder_factory_->codec_manager.GetCodecInst();
|
||||
if (ci) {
|
||||
return *ci;
|
||||
}
|
||||
CreateSpeechEncoderIfNecessary(encoder_factory_.get());
|
||||
const std::unique_ptr<AudioEncoder>& enc =
|
||||
encoder_factory_->codec_manager.GetStackParams()->speech_encoder;
|
||||
if (enc) {
|
||||
return acm2::CodecManager::ForgeCodecInst(enc.get());
|
||||
}
|
||||
return absl::nullopt;
|
||||
if (encoder_stack_) {
|
||||
CodecInst ci;
|
||||
ci.channels = encoder_stack_->NumChannels();
|
||||
ci.plfreq = encoder_stack_->SampleRateHz();
|
||||
ci.pacsize = rtc::CheckedDivExact(
|
||||
static_cast<int>(encoder_stack_->Max10MsFramesInAPacket() * ci.plfreq),
|
||||
100);
|
||||
ci.pltype = -1; // Not valid.
|
||||
ci.rate = -1; // Not valid.
|
||||
static const char kName[] = "external";
|
||||
memcpy(ci.plname, kName, sizeof(kName));
|
||||
return ci;
|
||||
} else {
|
||||
return encoder_stack_
|
||||
? absl::optional<CodecInst>(
|
||||
acm2::CodecManager::ForgeCodecInst(encoder_stack_.get()))
|
||||
: absl::nullopt;
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -808,59 +693,10 @@ int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// (RED) Redundant Coding
|
||||
//
|
||||
|
||||
bool AudioCodingModuleImpl::REDStatus() const {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
return encoder_factory_->codec_manager.GetStackParams()->use_red;
|
||||
}
|
||||
|
||||
// Configure RED status i.e on/off.
|
||||
int AudioCodingModuleImpl::SetREDStatus(bool enable_red) {
|
||||
#ifdef WEBRTC_CODEC_RED
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
CreateSpeechEncoderIfNecessary(encoder_factory_.get());
|
||||
if (!encoder_factory_->codec_manager.SetCopyRed(enable_red)) {
|
||||
return -1;
|
||||
}
|
||||
auto* sp = encoder_factory_->codec_manager.GetStackParams();
|
||||
if (sp->speech_encoder)
|
||||
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp);
|
||||
return 0;
|
||||
#else
|
||||
RTC_LOG(LS_WARNING) << " WEBRTC_CODEC_RED is undefined";
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// (FEC) Forward Error Correction (codec internal)
|
||||
//
|
||||
|
||||
bool AudioCodingModuleImpl::CodecFEC() const {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
return encoder_factory_->codec_manager.GetStackParams()->use_codec_fec;
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
CreateSpeechEncoderIfNecessary(encoder_factory_.get());
|
||||
if (!encoder_factory_->codec_manager.SetCodecFEC(enable_codec_fec)) {
|
||||
return -1;
|
||||
}
|
||||
auto* sp = encoder_factory_->codec_manager.GetStackParams();
|
||||
if (sp->speech_encoder)
|
||||
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp);
|
||||
if (enable_codec_fec) {
|
||||
return sp->use_codec_fec ? 0 : -1;
|
||||
} else {
|
||||
RTC_DCHECK(!sp->use_codec_fec);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
if (HaveValidEncoder("SetPacketLossRate")) {
|
||||
@ -869,36 +705,6 @@ int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// (VAD) Voice Activity Detection
|
||||
//
|
||||
int AudioCodingModuleImpl::SetVAD(bool enable_dtx,
|
||||
bool enable_vad,
|
||||
ACMVADMode mode) {
|
||||
// Note: |enable_vad| is not used; VAD is enabled based on the DTX setting.
|
||||
RTC_DCHECK_EQ(enable_dtx, enable_vad);
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
CreateSpeechEncoderIfNecessary(encoder_factory_.get());
|
||||
if (!encoder_factory_->codec_manager.SetVAD(enable_dtx, mode)) {
|
||||
return -1;
|
||||
}
|
||||
auto* sp = encoder_factory_->codec_manager.GetStackParams();
|
||||
if (sp->speech_encoder)
|
||||
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get VAD/DTX settings.
|
||||
int AudioCodingModuleImpl::VAD(bool* dtx_enabled,
|
||||
bool* vad_enabled,
|
||||
ACMVADMode* mode) const {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
const auto* sp = encoder_factory_->codec_manager.GetStackParams();
|
||||
*dtx_enabled = *vad_enabled = sp->use_cng;
|
||||
*mode = sp->vad_mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Receiver
|
||||
//
|
||||
@ -957,59 +763,6 @@ bool AudioCodingModuleImpl::RegisterReceiveCodec(
|
||||
return receiver_.AddCodec(rtp_payload_type, audio_format);
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
auto* ef = encoder_factory_.get();
|
||||
return RegisterReceiveCodecUnlocked(
|
||||
codec, [&] { return ef->rent_a_codec.RentIsacDecoder(codec.plfreq); });
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::RegisterReceiveCodec(
|
||||
const CodecInst& codec,
|
||||
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) {
|
||||
rtc::CritScope lock(&acm_crit_sect_);
|
||||
return RegisterReceiveCodecUnlocked(codec, isac_factory);
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::RegisterReceiveCodecUnlocked(
|
||||
const CodecInst& codec,
|
||||
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) {
|
||||
RTC_DCHECK(receiver_initialized_);
|
||||
if (codec.channels > 2) {
|
||||
RTC_LOG_F(LS_ERROR) << "Unsupported number of channels: " << codec.channels;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto codec_id = acm2::RentACodec::CodecIdByParams(codec.plname, codec.plfreq,
|
||||
codec.channels);
|
||||
if (!codec_id) {
|
||||
RTC_LOG_F(LS_ERROR)
|
||||
<< "Wrong codec params to be registered as receive codec";
|
||||
return -1;
|
||||
}
|
||||
auto codec_index = acm2::RentACodec::CodecIndexFromId(*codec_id);
|
||||
RTC_CHECK(codec_index) << "Invalid codec ID: " << static_cast<int>(*codec_id);
|
||||
|
||||
// Check if the payload-type is valid.
|
||||
if (!acm2::RentACodec::IsPayloadTypeValid(codec.pltype)) {
|
||||
RTC_LOG_F(LS_ERROR) << "Invalid payload type " << codec.pltype << " for "
|
||||
<< codec.plname;
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioDecoder* isac_decoder = nullptr;
|
||||
if (absl::EqualsIgnoreCase(codec.plname, "isac")) {
|
||||
std::unique_ptr<AudioDecoder>& saved_isac_decoder =
|
||||
codec.plfreq == 16000 ? isac_decoder_16k_ : isac_decoder_32k_;
|
||||
if (!saved_isac_decoder) {
|
||||
saved_isac_decoder = isac_factory();
|
||||
}
|
||||
isac_decoder = saved_isac_decoder.get();
|
||||
}
|
||||
return receiver_.AddCodec(*codec_index, codec.pltype, codec.channels,
|
||||
codec.plfreq, isac_decoder, codec.plname);
|
||||
}
|
||||
|
||||
int AudioCodingModuleImpl::RegisterExternalReceiveCodec(
|
||||
int rtp_payload_type,
|
||||
AudioDecoder* external_decoder,
|
||||
|
||||
@ -1,253 +0,0 @@
|
||||
/*
|
||||
* 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/codec_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "api/array_view.h"
|
||||
#include "api/audio_codecs/audio_encoder.h"
|
||||
#include "modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace acm2 {
|
||||
|
||||
namespace {
|
||||
|
||||
// Check if the given codec is a valid to be registered as send codec.
|
||||
int IsValidSendCodec(const CodecInst& send_codec) {
|
||||
if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
|
||||
RTC_LOG(LS_ERROR) << "Wrong number of channels (" << send_codec.channels
|
||||
<< "), only mono and stereo are supported)";
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto maybe_codec_id = RentACodec::CodecIdByInst(send_codec);
|
||||
if (!maybe_codec_id) {
|
||||
RTC_LOG(LS_ERROR) << "Invalid codec setting for the send codec.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Telephone-event cannot be a send codec.
|
||||
if (absl::EqualsIgnoreCase(send_codec.plname, "telephone-event")) {
|
||||
RTC_LOG(LS_ERROR) << "telephone-event cannot be a send codec";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!RentACodec::IsSupportedNumChannels(*maybe_codec_id, send_codec.channels)
|
||||
.value_or(false)) {
|
||||
RTC_LOG(LS_ERROR) << send_codec.channels
|
||||
<< " number of channels not supported for "
|
||||
<< send_codec.plname << ".";
|
||||
return -1;
|
||||
}
|
||||
return RentACodec::CodecIndexFromId(*maybe_codec_id).value_or(-1);
|
||||
}
|
||||
|
||||
bool IsOpus(const CodecInst& codec) {
|
||||
return
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
absl::EqualsIgnoreCase(codec.plname, "opus") ||
|
||||
#endif
|
||||
false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CodecManager::CodecManager() {
|
||||
thread_checker_.DetachFromThread();
|
||||
}
|
||||
|
||||
CodecManager::~CodecManager() = default;
|
||||
|
||||
bool CodecManager::RegisterEncoder(const CodecInst& send_codec) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
int codec_id = IsValidSendCodec(send_codec);
|
||||
|
||||
// Check for reported errors from function IsValidSendCodec().
|
||||
if (codec_id < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (RentACodec::RegisterRedPayloadType(
|
||||
&codec_stack_params_.red_payload_types, send_codec)) {
|
||||
case RentACodec::RegistrationResult::kOk:
|
||||
return true;
|
||||
case RentACodec::RegistrationResult::kBadFreq:
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "RegisterSendCodec() failed, invalid frequency for RED"
|
||||
" registration";
|
||||
return false;
|
||||
case RentACodec::RegistrationResult::kSkip:
|
||||
break;
|
||||
}
|
||||
switch (RentACodec::RegisterCngPayloadType(
|
||||
&codec_stack_params_.cng_payload_types, send_codec)) {
|
||||
case RentACodec::RegistrationResult::kOk:
|
||||
return true;
|
||||
case RentACodec::RegistrationResult::kBadFreq:
|
||||
RTC_LOG(LS_ERROR)
|
||||
<< "RegisterSendCodec() failed, invalid frequency for CNG"
|
||||
" registration";
|
||||
return false;
|
||||
case RentACodec::RegistrationResult::kSkip:
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsOpus(send_codec)) {
|
||||
// VAD/DTX not supported.
|
||||
codec_stack_params_.use_cng = false;
|
||||
}
|
||||
|
||||
send_codec_inst_ = send_codec;
|
||||
recreate_encoder_ = true; // Caller must recreate it.
|
||||
return true;
|
||||
}
|
||||
|
||||
CodecInst CodecManager::ForgeCodecInst(
|
||||
const AudioEncoder* external_speech_encoder) {
|
||||
CodecInst ci;
|
||||
ci.channels = external_speech_encoder->NumChannels();
|
||||
ci.plfreq = external_speech_encoder->SampleRateHz();
|
||||
ci.pacsize = rtc::CheckedDivExact(
|
||||
static_cast<int>(external_speech_encoder->Max10MsFramesInAPacket() *
|
||||
ci.plfreq),
|
||||
100);
|
||||
ci.pltype = -1; // Not valid.
|
||||
ci.rate = -1; // Not valid.
|
||||
static const char kName[] = "external";
|
||||
memcpy(ci.plname, kName, sizeof(kName));
|
||||
return ci;
|
||||
}
|
||||
|
||||
bool CodecManager::SetCopyRed(bool enable) {
|
||||
if (enable && codec_stack_params_.use_codec_fec) {
|
||||
RTC_LOG(LS_WARNING) << "Codec internal FEC and RED cannot be co-enabled.";
|
||||
return false;
|
||||
}
|
||||
if (enable && send_codec_inst_ &&
|
||||
codec_stack_params_.red_payload_types.count(send_codec_inst_->plfreq) <
|
||||
1) {
|
||||
RTC_LOG(LS_WARNING) << "Cannot enable RED at " << send_codec_inst_->plfreq
|
||||
<< " Hz.";
|
||||
return false;
|
||||
}
|
||||
codec_stack_params_.use_red = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodecManager::SetVAD(bool enable, ACMVADMode mode) {
|
||||
// Sanity check of the mode.
|
||||
RTC_DCHECK(mode == VADNormal || mode == VADLowBitrate || mode == VADAggr ||
|
||||
mode == VADVeryAggr);
|
||||
|
||||
// Check that the send codec is mono. We don't support VAD/DTX for stereo
|
||||
// sending.
|
||||
const bool stereo_send =
|
||||
codec_stack_params_.speech_encoder
|
||||
? (codec_stack_params_.speech_encoder->NumChannels() != 1)
|
||||
: false;
|
||||
if (enable && stereo_send) {
|
||||
RTC_LOG(LS_ERROR) << "VAD/DTX not supported for stereo sending";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(kwiberg): This doesn't protect Opus when injected as an external
|
||||
// encoder.
|
||||
if (send_codec_inst_ && IsOpus(*send_codec_inst_)) {
|
||||
// VAD/DTX not supported, but don't fail.
|
||||
enable = false;
|
||||
}
|
||||
|
||||
codec_stack_params_.use_cng = enable;
|
||||
codec_stack_params_.vad_mode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodecManager::SetCodecFEC(bool enable_codec_fec) {
|
||||
if (enable_codec_fec && codec_stack_params_.use_red) {
|
||||
RTC_LOG(LS_WARNING) << "Codec internal FEC and RED cannot be co-enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
codec_stack_params_.use_codec_fec = enable_codec_fec;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodecManager::MakeEncoder(RentACodec* rac, AudioCodingModule* acm) {
|
||||
RTC_DCHECK(rac);
|
||||
RTC_DCHECK(acm);
|
||||
|
||||
if (!recreate_encoder_) {
|
||||
bool error = false;
|
||||
// Try to re-use the speech encoder we've given to the ACM.
|
||||
acm->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
|
||||
if (!*encoder) {
|
||||
// There is no existing encoder.
|
||||
recreate_encoder_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the speech encoder from the ACM.
|
||||
std::unique_ptr<AudioEncoder> enc = std::move(*encoder);
|
||||
while (true) {
|
||||
auto sub_enc = enc->ReclaimContainedEncoders();
|
||||
if (sub_enc.empty()) {
|
||||
break;
|
||||
}
|
||||
RTC_CHECK_EQ(1, sub_enc.size());
|
||||
|
||||
// Replace enc with its sub encoder. We need to put the sub encoder in
|
||||
// a temporary first, since otherwise the old value of enc would be
|
||||
// destroyed before the new value got assigned, which would be bad
|
||||
// since the new value is a part of the old value.
|
||||
auto tmp_enc = std::move(sub_enc[0]);
|
||||
enc = std::move(tmp_enc);
|
||||
}
|
||||
|
||||
// Wrap it in a new encoder stack and put it back.
|
||||
codec_stack_params_.speech_encoder = std::move(enc);
|
||||
*encoder = rac->RentEncoderStack(&codec_stack_params_);
|
||||
if (!*encoder) {
|
||||
error = true;
|
||||
}
|
||||
});
|
||||
if (error) {
|
||||
return false;
|
||||
}
|
||||
if (!recreate_encoder_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!send_codec_inst_) {
|
||||
// We don't have the information we need to create a new speech encoder.
|
||||
// (This is not an error.)
|
||||
return true;
|
||||
}
|
||||
|
||||
codec_stack_params_.speech_encoder = rac->RentEncoder(*send_codec_inst_);
|
||||
auto stack = rac->RentEncoderStack(&codec_stack_params_);
|
||||
if (!stack) {
|
||||
return false;
|
||||
}
|
||||
acm->SetEncoder(std::move(stack));
|
||||
recreate_encoder_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace acm2
|
||||
} // namespace webrtc
|
||||
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_CODING_ACM2_CODEC_MANAGER_H_
|
||||
#define MODULES_AUDIO_CODING_ACM2_CODEC_MANAGER_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
#include "modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "rtc_base/constructormagic.h"
|
||||
#include "rtc_base/thread_checker.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class AudioEncoder;
|
||||
|
||||
namespace acm2 {
|
||||
|
||||
class CodecManager final {
|
||||
public:
|
||||
CodecManager();
|
||||
~CodecManager();
|
||||
|
||||
// Parses the given specification. On success, returns true and updates the
|
||||
// stored CodecInst and stack parameters; on error, returns false.
|
||||
bool RegisterEncoder(const CodecInst& send_codec);
|
||||
|
||||
static CodecInst ForgeCodecInst(const AudioEncoder* external_speech_encoder);
|
||||
|
||||
const CodecInst* GetCodecInst() const {
|
||||
return send_codec_inst_ ? &*send_codec_inst_ : nullptr;
|
||||
}
|
||||
|
||||
void UnsetCodecInst() { send_codec_inst_ = absl::nullopt; }
|
||||
|
||||
const RentACodec::StackParameters* GetStackParams() const {
|
||||
return &codec_stack_params_;
|
||||
}
|
||||
RentACodec::StackParameters* GetStackParams() { return &codec_stack_params_; }
|
||||
|
||||
bool SetCopyRed(bool enable);
|
||||
|
||||
bool SetVAD(bool enable, ACMVADMode mode);
|
||||
|
||||
bool SetCodecFEC(bool enable_codec_fec);
|
||||
|
||||
// Uses the provided Rent-A-Codec to create a new encoder stack, if we have a
|
||||
// complete specification; if so, it is then passed to set_encoder. On error,
|
||||
// returns false.
|
||||
bool MakeEncoder(RentACodec* rac, AudioCodingModule* acm);
|
||||
|
||||
private:
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
absl::optional<CodecInst> send_codec_inst_;
|
||||
RentACodec::StackParameters codec_stack_params_;
|
||||
bool recreate_encoder_ = true; // Need to recreate encoder?
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(CodecManager);
|
||||
};
|
||||
|
||||
} // namespace acm2
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_AUDIO_CODING_ACM2_CODEC_MANAGER_H_
|
||||
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
|
||||
#include "modules/audio_coding/acm2/codec_manager.h"
|
||||
#include "modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "test/gtest.h"
|
||||
#include "test/mock_audio_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace acm2 {
|
||||
|
||||
using ::testing::Return;
|
||||
|
||||
namespace {
|
||||
|
||||
// Create a MockAudioEncoder with some reasonable default behavior.
|
||||
std::unique_ptr<MockAudioEncoder> CreateMockEncoder() {
|
||||
auto enc = std::unique_ptr<MockAudioEncoder>(new MockAudioEncoder);
|
||||
EXPECT_CALL(*enc, SampleRateHz()).WillRepeatedly(Return(8000));
|
||||
EXPECT_CALL(*enc, NumChannels()).WillRepeatedly(Return(1));
|
||||
EXPECT_CALL(*enc, Max10MsFramesInAPacket()).WillRepeatedly(Return(1));
|
||||
return enc;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(CodecManagerTest, ExternalEncoderFec) {
|
||||
auto enc0 = CreateMockEncoder();
|
||||
auto enc1 = CreateMockEncoder();
|
||||
auto enc2 = CreateMockEncoder();
|
||||
{
|
||||
::testing::InSequence s;
|
||||
EXPECT_CALL(*enc0, SetFec(false)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*enc1, SetFec(true)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*enc2, SetFec(true)).WillOnce(Return(false));
|
||||
}
|
||||
|
||||
CodecManager cm;
|
||||
RentACodec rac;
|
||||
|
||||
// use_codec_fec starts out false.
|
||||
EXPECT_FALSE(cm.GetStackParams()->use_codec_fec);
|
||||
cm.GetStackParams()->speech_encoder = std::move(enc0);
|
||||
EXPECT_TRUE(rac.RentEncoderStack(cm.GetStackParams()));
|
||||
EXPECT_FALSE(cm.GetStackParams()->use_codec_fec);
|
||||
|
||||
// Set it to true.
|
||||
EXPECT_EQ(true, cm.SetCodecFEC(true));
|
||||
EXPECT_TRUE(cm.GetStackParams()->use_codec_fec);
|
||||
cm.GetStackParams()->speech_encoder = std::move(enc1);
|
||||
EXPECT_TRUE(rac.RentEncoderStack(cm.GetStackParams()));
|
||||
EXPECT_TRUE(cm.GetStackParams()->use_codec_fec);
|
||||
|
||||
// Switch to a codec that doesn't support it.
|
||||
cm.GetStackParams()->speech_encoder = std::move(enc2);
|
||||
EXPECT_TRUE(rac.RentEncoderStack(cm.GetStackParams()));
|
||||
EXPECT_FALSE(cm.GetStackParams()->use_codec_fec);
|
||||
}
|
||||
|
||||
} // namespace acm2
|
||||
} // namespace webrtc
|
||||
@ -13,35 +13,9 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
|
||||
#include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
|
||||
#include "modules/audio_coding/codecs/g722/audio_encoder_g722.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
#include "modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h" // nogncheck
|
||||
#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" // nogncheck
|
||||
#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 {
|
||||
|
||||
@ -107,200 +81,5 @@ absl::optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId(
|
||||
: ned;
|
||||
}
|
||||
|
||||
RentACodec::RegistrationResult RentACodec::RegisterCngPayloadType(
|
||||
std::map<int, int>* pt_map,
|
||||
const CodecInst& codec_inst) {
|
||||
if (!absl::EqualsIgnoreCase(codec_inst.plname, "CN"))
|
||||
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 (!absl::EqualsIgnoreCase(codec_inst.plname, "RED"))
|
||||
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 (absl::EqualsIgnoreCase(speech_inst.plname, "isac"))
|
||||
return std::unique_ptr<AudioEncoder>(
|
||||
new AudioEncoderIsacFixImpl(speech_inst, bwinfo));
|
||||
#endif
|
||||
#if defined(WEBRTC_CODEC_ISAC)
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "isac"))
|
||||
return std::unique_ptr<AudioEncoder>(
|
||||
new AudioEncoderIsacFloatImpl(speech_inst, bwinfo));
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "opus"))
|
||||
return std::unique_ptr<AudioEncoder>(new AudioEncoderOpusImpl(speech_inst));
|
||||
#endif
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "pcmu"))
|
||||
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcmU(speech_inst));
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "pcma"))
|
||||
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcmA(speech_inst));
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "l16"))
|
||||
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcm16B(speech_inst));
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "ilbc"))
|
||||
return std::unique_ptr<AudioEncoder>(new AudioEncoderIlbcImpl(speech_inst));
|
||||
#endif
|
||||
if (absl::EqualsIgnoreCase(speech_inst.plname, "g722"))
|
||||
return std::unique_ptr<AudioEncoder>(new AudioEncoderG722Impl(speech_inst));
|
||||
RTC_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) {
|
||||
AudioEncoderCngConfig 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 CreateComfortNoiseEncoder(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 = [¶m](const std::map<int, int>& m) {
|
||||
auto it = m.find(param->speech_encoder->SampleRateHz());
|
||||
return it == m.end() ? absl::nullopt : absl::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
|
||||
|
||||
@ -31,8 +31,7 @@ class LockedIsacBandwidthInfo;
|
||||
|
||||
namespace acm2 {
|
||||
|
||||
class RentACodec {
|
||||
public:
|
||||
struct RentACodec {
|
||||
enum class CodecId {
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
kISAC,
|
||||
@ -141,56 +140,6 @@ class RentACodec {
|
||||
static absl::optional<NetEqDecoder> NetEqDecoderFromCodecId(
|
||||
CodecId codec_id,
|
||||
size_t num_channels);
|
||||
|
||||
// Parse codec_inst and extract payload types. If the given CodecInst was for
|
||||
// the wrong sort of codec, return kSkip; otherwise, if the rate was illegal,
|
||||
// return kBadFreq; otherwise, update the given RTP timestamp rate (Hz) ->
|
||||
// payload type map and return kOk.
|
||||
enum class RegistrationResult { kOk, kSkip, kBadFreq };
|
||||
static RegistrationResult RegisterCngPayloadType(std::map<int, int>* pt_map,
|
||||
const CodecInst& codec_inst);
|
||||
static RegistrationResult RegisterRedPayloadType(std::map<int, int>* pt_map,
|
||||
const CodecInst& codec_inst);
|
||||
|
||||
RentACodec();
|
||||
~RentACodec();
|
||||
|
||||
// Creates and returns an audio encoder built to the given specification.
|
||||
// Returns null in case of error.
|
||||
std::unique_ptr<AudioEncoder> RentEncoder(const CodecInst& codec_inst);
|
||||
|
||||
struct StackParameters {
|
||||
StackParameters();
|
||||
~StackParameters();
|
||||
|
||||
std::unique_ptr<AudioEncoder> speech_encoder;
|
||||
|
||||
bool use_codec_fec = false;
|
||||
bool use_red = false;
|
||||
bool use_cng = false;
|
||||
ACMVADMode vad_mode = VADNormal;
|
||||
|
||||
// Maps from RTP timestamp rate (in Hz) to payload type.
|
||||
std::map<int, int> cng_payload_types;
|
||||
std::map<int, int> red_payload_types;
|
||||
};
|
||||
|
||||
// Creates and returns an audio encoder stack constructed to the given
|
||||
// specification. If the specification isn't compatible with the encoder, it
|
||||
// will be changed to match (things will be switched off). The speech encoder
|
||||
// will be stolen. If the specification isn't complete, returns nullptr.
|
||||
std::unique_ptr<AudioEncoder> RentEncoderStack(StackParameters* param);
|
||||
|
||||
// Creates and returns an iSAC decoder.
|
||||
std::unique_ptr<AudioDecoder> RentIsacDecoder(int sample_rate_hz);
|
||||
|
||||
private:
|
||||
std::unique_ptr<AudioEncoder> speech_encoder_;
|
||||
std::unique_ptr<AudioEncoder> cng_encoder_;
|
||||
std::unique_ptr<AudioEncoder> red_encoder_;
|
||||
rtc::scoped_refptr<LockedIsacBandwidthInfo> isac_bandwidth_info_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RentACodec);
|
||||
};
|
||||
|
||||
} // namespace acm2
|
||||
|
||||
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
|
||||
#include "common_types.h"
|
||||
#include "modules/audio_coding/acm2/rent_a_codec.h"
|
||||
#include "rtc_base/arraysize.h"
|
||||
#include "test/gtest.h"
|
||||
#include "test/mock_audio_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace acm2 {
|
||||
|
||||
using ::testing::Return;
|
||||
|
||||
namespace {
|
||||
|
||||
const int kDataLengthSamples = 80;
|
||||
const int kPacketSizeSamples = 2 * kDataLengthSamples;
|
||||
const int16_t kZeroData[kDataLengthSamples] = {0};
|
||||
const CodecInst kDefaultCodecInst = {0, "pcmu", 8000, kPacketSizeSamples,
|
||||
1, 64000};
|
||||
const int kCngPt = 13;
|
||||
|
||||
class Marker final {
|
||||
public:
|
||||
MOCK_METHOD1(Mark, void(std::string desc));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class RentACodecTestF : public ::testing::Test {
|
||||
protected:
|
||||
void CreateCodec() {
|
||||
auto speech_encoder = rent_a_codec_.RentEncoder(kDefaultCodecInst);
|
||||
ASSERT_TRUE(speech_encoder);
|
||||
RentACodec::StackParameters param;
|
||||
param.use_cng = true;
|
||||
param.speech_encoder = std::move(speech_encoder);
|
||||
encoder_ = rent_a_codec_.RentEncoderStack(¶m);
|
||||
}
|
||||
|
||||
void EncodeAndVerify(size_t expected_out_length,
|
||||
uint32_t expected_timestamp,
|
||||
int expected_payload_type,
|
||||
int expected_send_even_if_empty) {
|
||||
rtc::Buffer out;
|
||||
AudioEncoder::EncodedInfo encoded_info;
|
||||
encoded_info = encoder_->Encode(timestamp_, kZeroData, &out);
|
||||
timestamp_ += kDataLengthSamples;
|
||||
EXPECT_TRUE(encoded_info.redundant.empty());
|
||||
EXPECT_EQ(expected_out_length, encoded_info.encoded_bytes);
|
||||
EXPECT_EQ(expected_timestamp, encoded_info.encoded_timestamp);
|
||||
if (expected_payload_type >= 0)
|
||||
EXPECT_EQ(expected_payload_type, encoded_info.payload_type);
|
||||
if (expected_send_even_if_empty >= 0)
|
||||
EXPECT_EQ(static_cast<bool>(expected_send_even_if_empty),
|
||||
encoded_info.send_even_if_empty);
|
||||
}
|
||||
|
||||
RentACodec rent_a_codec_;
|
||||
std::unique_ptr<AudioEncoder> encoder_;
|
||||
uint32_t timestamp_ = 0;
|
||||
};
|
||||
|
||||
// This test verifies that CNG frames are delivered as expected. Since the frame
|
||||
// size is set to 20 ms, we expect the first encode call to produce no output
|
||||
// (which is signaled as 0 bytes output of type kNoEncoding). The next encode
|
||||
// call should produce one SID frame of 9 bytes. The third call should not
|
||||
// result in any output (just like the first one). The fourth and final encode
|
||||
// call should produce an "empty frame", which is like no output, but with
|
||||
// AudioEncoder::EncodedInfo::send_even_if_empty set to true. (The reason to
|
||||
// produce an empty frame is to drive sending of DTMF packets in the RTP/RTCP
|
||||
// module.)
|
||||
TEST_F(RentACodecTestF, VerifyCngFrames) {
|
||||
CreateCodec();
|
||||
uint32_t expected_timestamp = timestamp_;
|
||||
// Verify no frame.
|
||||
{
|
||||
SCOPED_TRACE("First encoding");
|
||||
EncodeAndVerify(0, expected_timestamp, -1, -1);
|
||||
}
|
||||
|
||||
// Verify SID frame delivered.
|
||||
{
|
||||
SCOPED_TRACE("Second encoding");
|
||||
EncodeAndVerify(9, expected_timestamp, kCngPt, 1);
|
||||
}
|
||||
|
||||
// Verify no frame.
|
||||
{
|
||||
SCOPED_TRACE("Third encoding");
|
||||
EncodeAndVerify(0, expected_timestamp, -1, -1);
|
||||
}
|
||||
|
||||
// Verify NoEncoding.
|
||||
expected_timestamp += 2 * kDataLengthSamples;
|
||||
{
|
||||
SCOPED_TRACE("Fourth encoding");
|
||||
EncodeAndVerify(0, expected_timestamp, kCngPt, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, ExternalEncoder) {
|
||||
const int kSampleRateHz = 8000;
|
||||
auto* external_encoder = new MockAudioEncoder;
|
||||
EXPECT_CALL(*external_encoder, SampleRateHz())
|
||||
.WillRepeatedly(Return(kSampleRateHz));
|
||||
EXPECT_CALL(*external_encoder, NumChannels()).WillRepeatedly(Return(1));
|
||||
EXPECT_CALL(*external_encoder, SetFec(false)).WillRepeatedly(Return(true));
|
||||
|
||||
RentACodec rac;
|
||||
RentACodec::StackParameters param;
|
||||
param.speech_encoder = std::unique_ptr<AudioEncoder>(external_encoder);
|
||||
std::unique_ptr<AudioEncoder> encoder_stack = rac.RentEncoderStack(¶m);
|
||||
EXPECT_EQ(external_encoder, encoder_stack.get());
|
||||
const int kPacketSizeSamples = kSampleRateHz / 100;
|
||||
int16_t audio[kPacketSizeSamples] = {0};
|
||||
rtc::Buffer encoded;
|
||||
AudioEncoder::EncodedInfo info;
|
||||
|
||||
Marker marker;
|
||||
{
|
||||
::testing::InSequence s;
|
||||
info.encoded_timestamp = 0;
|
||||
EXPECT_CALL(*external_encoder,
|
||||
EncodeImpl(0, rtc::ArrayView<const int16_t>(audio), &encoded))
|
||||
.WillOnce(Return(info));
|
||||
EXPECT_CALL(marker, Mark("A"));
|
||||
EXPECT_CALL(marker, Mark("B"));
|
||||
EXPECT_CALL(marker, Mark("C"));
|
||||
}
|
||||
|
||||
info = encoder_stack->Encode(0, audio, &encoded);
|
||||
EXPECT_EQ(0u, info.encoded_timestamp);
|
||||
marker.Mark("A");
|
||||
|
||||
// Change to internal encoder.
|
||||
CodecInst codec_inst = kDefaultCodecInst;
|
||||
codec_inst.pacsize = kPacketSizeSamples;
|
||||
param.speech_encoder = rac.RentEncoder(codec_inst);
|
||||
ASSERT_TRUE(param.speech_encoder);
|
||||
AudioEncoder* enc = param.speech_encoder.get();
|
||||
std::unique_ptr<AudioEncoder> stack = rac.RentEncoderStack(¶m);
|
||||
EXPECT_EQ(enc, stack.get());
|
||||
|
||||
// Don't expect any more calls to the external encoder.
|
||||
info = stack->Encode(1, audio, &encoded);
|
||||
marker.Mark("B");
|
||||
encoder_stack.reset();
|
||||
marker.Mark("C");
|
||||
}
|
||||
|
||||
// Verify that the speech encoder's Reset method is called when CNG or RED
|
||||
// (or both) are switched on, but not when they're switched off.
|
||||
void TestCngAndRedResetSpeechEncoder(bool use_cng, bool use_red) {
|
||||
auto make_enc = [] {
|
||||
auto speech_encoder =
|
||||
std::unique_ptr<MockAudioEncoder>(new MockAudioEncoder);
|
||||
EXPECT_CALL(*speech_encoder, NumChannels()).WillRepeatedly(Return(1));
|
||||
EXPECT_CALL(*speech_encoder, Max10MsFramesInAPacket())
|
||||
.WillRepeatedly(Return(2));
|
||||
EXPECT_CALL(*speech_encoder, SampleRateHz()).WillRepeatedly(Return(8000));
|
||||
EXPECT_CALL(*speech_encoder, SetFec(false)).WillRepeatedly(Return(true));
|
||||
return speech_encoder;
|
||||
};
|
||||
auto speech_encoder1 = make_enc();
|
||||
auto speech_encoder2 = make_enc();
|
||||
Marker marker;
|
||||
{
|
||||
::testing::InSequence s;
|
||||
EXPECT_CALL(marker, Mark("disabled"));
|
||||
EXPECT_CALL(marker, Mark("enabled"));
|
||||
if (use_cng || use_red)
|
||||
EXPECT_CALL(*speech_encoder2, Reset());
|
||||
}
|
||||
|
||||
RentACodec::StackParameters param1, param2;
|
||||
param1.speech_encoder = std::move(speech_encoder1);
|
||||
param2.speech_encoder = std::move(speech_encoder2);
|
||||
param2.use_cng = use_cng;
|
||||
param2.use_red = use_red;
|
||||
marker.Mark("disabled");
|
||||
RentACodec rac;
|
||||
rac.RentEncoderStack(¶m1);
|
||||
marker.Mark("enabled");
|
||||
rac.RentEncoderStack(¶m2);
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, CngResetsSpeechEncoder) {
|
||||
TestCngAndRedResetSpeechEncoder(true, false);
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, RedResetsSpeechEncoder) {
|
||||
TestCngAndRedResetSpeechEncoder(false, true);
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, CngAndRedResetsSpeechEncoder) {
|
||||
TestCngAndRedResetSpeechEncoder(true, true);
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, NoCngAndRedNoSpeechEncoderReset) {
|
||||
TestCngAndRedResetSpeechEncoder(false, false);
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, RentEncoderError) {
|
||||
const CodecInst codec_inst = {
|
||||
0, "Robert'); DROP TABLE Students;", 8000, 160, 1, 64000};
|
||||
RentACodec rent_a_codec;
|
||||
EXPECT_FALSE(rent_a_codec.RentEncoder(codec_inst));
|
||||
}
|
||||
|
||||
TEST(RentACodecTest, RentEncoderStackWithoutSpeechEncoder) {
|
||||
RentACodec::StackParameters sp;
|
||||
EXPECT_EQ(nullptr, sp.speech_encoder);
|
||||
EXPECT_EQ(nullptr, RentACodec().RentEncoderStack(&sp));
|
||||
}
|
||||
|
||||
} // namespace acm2
|
||||
} // namespace webrtc
|
||||
@ -154,40 +154,6 @@ class AudioCodingModule {
|
||||
// Sender
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t RegisterSendCodec()
|
||||
// Registers a codec, specified by |send_codec|, as sending codec.
|
||||
// This API can be called multiple of times to register Codec. The last codec
|
||||
// registered overwrites the previous ones.
|
||||
// The API can also be used to change payload type for CNG and RED, which are
|
||||
// registered by default to default payload types.
|
||||
// Note that registering CNG and RED won't overwrite speech codecs.
|
||||
// This API can be called to set/change the send payload-type, frame-size
|
||||
// or encoding rate (if applicable for the codec).
|
||||
//
|
||||
// Note: If a stereo codec is registered as send codec, VAD/DTX will
|
||||
// automatically be turned off, since it is not supported for stereo sending.
|
||||
//
|
||||
// Note: If a secondary encoder is already registered, and the new send-codec
|
||||
// has a sampling rate that does not match the secondary encoder, the
|
||||
// secondary encoder will be unregistered.
|
||||
//
|
||||
// Input:
|
||||
// -send_codec : Parameters of the codec to be registered, c.f.
|
||||
// common_types.h for the definition of
|
||||
// CodecInst.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if failed to initialize,
|
||||
// 0 if succeeded.
|
||||
//
|
||||
virtual int32_t RegisterSendCodec(const CodecInst& send_codec) = 0;
|
||||
|
||||
// Registers |external_speech_encoder| as encoder. The new encoder will
|
||||
// replace any previously registered speech encoder (internal or external).
|
||||
virtual void RegisterExternalSendCodec(
|
||||
AudioEncoder* external_speech_encoder) = 0;
|
||||
|
||||
// |modifier| is called exactly once with one argument: a pointer to the
|
||||
// unique_ptr that holds the current encoder (which is null if there is no
|
||||
// current encoder). For the duration of the call, |modifier| has exclusive
|
||||
@ -257,71 +223,6 @@ class AudioCodingModule {
|
||||
//
|
||||
virtual int32_t Add10MsData(const AudioFrame& audio_frame) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// (RED) Redundant Coding
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t SetREDStatus()
|
||||
// configure RED status i.e. on/off.
|
||||
//
|
||||
// RFC 2198 describes a solution which has a single payload type which
|
||||
// signifies a packet with redundancy. That packet then becomes a container,
|
||||
// encapsulating multiple payloads into a single RTP packet.
|
||||
// Such a scheme is flexible, since any amount of redundancy may be
|
||||
// encapsulated within a single packet. There is, however, a small overhead
|
||||
// since each encapsulated payload must be preceded by a header indicating
|
||||
// the type of data enclosed.
|
||||
//
|
||||
// Input:
|
||||
// -enable_red : if true RED is enabled, otherwise RED is
|
||||
// disabled.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if failed to set RED status,
|
||||
// 0 if succeeded.
|
||||
//
|
||||
virtual int32_t SetREDStatus(bool enable_red) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// bool REDStatus()
|
||||
// Get RED status
|
||||
//
|
||||
// Return value:
|
||||
// true if RED is enabled,
|
||||
// false if RED is disabled.
|
||||
//
|
||||
virtual bool REDStatus() const = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// (FEC) Forward Error Correction (codec internal)
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t SetCodecFEC()
|
||||
// Configures codec internal FEC status i.e. on/off. No effects on codecs that
|
||||
// do not provide internal FEC.
|
||||
//
|
||||
// Input:
|
||||
// -enable_fec : if true FEC will be enabled otherwise the FEC is
|
||||
// disabled.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if failed, or the codec does not support FEC
|
||||
// 0 if succeeded.
|
||||
//
|
||||
virtual int SetCodecFEC(bool enable_codec_fec) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// bool CodecFEC()
|
||||
// Gets status of codec internal FEC.
|
||||
//
|
||||
// Return value:
|
||||
// true if FEC is enabled,
|
||||
// false if FEC is disabled.
|
||||
//
|
||||
virtual bool CodecFEC() const = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int SetPacketLossRate()
|
||||
// Sets expected packet loss rate for encoding. Some encoders provide packet
|
||||
@ -343,55 +244,6 @@ class AudioCodingModule {
|
||||
// (VAD) Voice Activity Detection
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t SetVAD()
|
||||
// If DTX is enabled & the codec does not have internal DTX/VAD
|
||||
// WebRtc VAD will be automatically enabled and |enable_vad| is ignored.
|
||||
//
|
||||
// If DTX is disabled but VAD is enabled no DTX packets are send,
|
||||
// regardless of whether the codec has internal DTX/VAD or not. In this
|
||||
// case, WebRtc VAD is running to label frames as active/in-active.
|
||||
//
|
||||
// NOTE! VAD/DTX is not supported when sending stereo.
|
||||
//
|
||||
// Inputs:
|
||||
// -enable_dtx : if true DTX is enabled,
|
||||
// otherwise DTX is disabled.
|
||||
// -enable_vad : if true VAD is enabled,
|
||||
// otherwise VAD is disabled.
|
||||
// -vad_mode : determines the aggressiveness of VAD. A more
|
||||
// aggressive mode results in more frames labeled
|
||||
// as in-active, c.f. definition of
|
||||
// ACMVADMode in audio_coding_module_typedefs.h
|
||||
// for valid values.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if failed to set up VAD/DTX,
|
||||
// 0 if succeeded.
|
||||
//
|
||||
virtual int32_t SetVAD(const bool enable_dtx = true,
|
||||
const bool enable_vad = false,
|
||||
const ACMVADMode vad_mode = VADNormal) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t VAD()
|
||||
// Get VAD status.
|
||||
//
|
||||
// Outputs:
|
||||
// -dtx_enabled : is set to true if DTX is enabled, otherwise
|
||||
// is set to false.
|
||||
// -vad_enabled : is set to true if VAD is enabled, otherwise
|
||||
// is set to false.
|
||||
// -vad_mode : is set to the current aggressiveness of VAD.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if fails to retrieve the setting of DTX/VAD,
|
||||
// 0 if succeeded.
|
||||
//
|
||||
virtual int32_t VAD(bool* dtx_enabled,
|
||||
bool* vad_enabled,
|
||||
ACMVADMode* vad_mode) const = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t RegisterVADCallback()
|
||||
// Call this method to register a callback function which is called
|
||||
@ -455,29 +307,6 @@ class AudioCodingModule {
|
||||
virtual bool RegisterReceiveCodec(int rtp_payload_type,
|
||||
const SdpAudioFormat& audio_format) = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// int32_t RegisterReceiveCodec()
|
||||
// Register possible decoders, can be called multiple times for
|
||||
// codecs, CNG-NB, CNG-WB, CNG-SWB, AVT and RED.
|
||||
//
|
||||
// Input:
|
||||
// -receive_codec : parameters of the codec to be registered, c.f.
|
||||
// common_types.h for the definition of
|
||||
// CodecInst.
|
||||
//
|
||||
// Return value:
|
||||
// -1 if failed to register the codec
|
||||
// 0 if the codec registered successfully.
|
||||
//
|
||||
virtual int RegisterReceiveCodec(const CodecInst& receive_codec) = 0;
|
||||
|
||||
// Register a decoder; call repeatedly to register multiple decoders. |df| is
|
||||
// a decoder factory that returns an iSAC decoder; it will be called once if
|
||||
// the decoder being registered is iSAC.
|
||||
virtual int RegisterReceiveCodec(
|
||||
const CodecInst& receive_codec,
|
||||
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) = 0;
|
||||
|
||||
// Registers an external decoder. The name is only used to provide information
|
||||
// back to the caller about the decoder. Hence, the name is arbitrary, and may
|
||||
// be empty.
|
||||
|
||||
Reference in New Issue
Block a user