diff --git a/webrtc/api/audio_codecs/ilbc/BUILD.gn b/webrtc/api/audio_codecs/ilbc/BUILD.gn new file mode 100644 index 0000000000..bba2662ad6 --- /dev/null +++ b/webrtc/api/audio_codecs/ilbc/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2017 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. + +import("../../../webrtc.gni") +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +rtc_source_set("audio_encoder_ilbc_config") { + sources = [ + "audio_encoder_ilbc_config.h", + ] +} + +rtc_static_library("audio_encoder_ilbc") { + sources = [ + "audio_encoder_ilbc.cc", + "audio_encoder_ilbc.h", + ] + deps = [ + ":audio_encoder_ilbc_config", + "..:audio_codecs_api", + "../../../base:rtc_base_approved", + "../../../modules/audio_coding:ilbc", + ] +} + +rtc_static_library("audio_decoder_ilbc") { + sources = [ + "audio_decoder_ilbc.cc", + "audio_decoder_ilbc.h", + ] + deps = [ + "..:audio_codecs_api", + "../../..:webrtc_common", + "../../../base:rtc_base_approved", + "../../../modules/audio_coding:ilbc", + ] +} diff --git a/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc b/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc new file mode 100644 index 0000000000..da290afeaf --- /dev/null +++ b/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 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/api/audio_codecs/ilbc/audio_decoder_ilbc.h" + +#include +#include + +#include "webrtc/base/ptr_util.h" +#include "webrtc/common_types.h" +#include "webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h" + +namespace webrtc { + +rtc::Optional AudioDecoderIlbc::SdpToConfig( + const SdpAudioFormat& format) { + return STR_CASE_CMP(format.name.c_str(), "ilbc") == 0 && + format.clockrate_hz == 8000 && format.num_channels == 1 + ? rtc::Optional(Config()) + : rtc::Optional(); +} + +void AudioDecoderIlbc::AppendSupportedDecoders( + std::vector* specs) { + specs->push_back({{"ILBC", 8000, 1}, {8000, 1, 13300}}); +} + +std::unique_ptr AudioDecoderIlbc::MakeAudioDecoder( + Config config) { + return rtc::MakeUnique(); +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h b/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h new file mode 100644 index 0000000000..1d58810047 --- /dev/null +++ b/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 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 WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_DECODER_ILBC_H_ +#define WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_DECODER_ILBC_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_decoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/base/optional.h" + +namespace webrtc { + +// ILBC decoder API for use as a template parameter to +// CreateAudioDecoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioDecoderIlbc { + struct Config {}; // Empty---no config values needed! + static rtc::Optional SdpToConfig(const SdpAudioFormat& audio_format); + static void AppendSupportedDecoders(std::vector* specs); + static std::unique_ptr MakeAudioDecoder(Config config); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_DECODER_ILBC_H_ diff --git a/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc b/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc new file mode 100644 index 0000000000..a4b3a388b0 --- /dev/null +++ b/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 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/api/audio_codecs/ilbc/audio_encoder_ilbc.h" + +#include +#include + +#include "webrtc/base/ptr_util.h" +#include "webrtc/base/safe_conversions.h" +#include "webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h" + +namespace webrtc { +namespace { +int GetIlbcBitrate(int ptime) { + switch (ptime) { + case 20: + case 40: + // 38 bytes per frame of 20 ms => 15200 bits/s. + return 15200; + case 30: + case 60: + // 50 bytes per frame of 30 ms => (approx) 13333 bits/s. + return 13333; + default: + FATAL(); + } +} +} // namespace + +rtc::Optional AudioEncoderIlbc::SdpToConfig( + const SdpAudioFormat& format) { + return AudioEncoderIlbcImpl::SdpToConfig(format); +} + +void AudioEncoderIlbc::AppendSupportedEncoders( + std::vector* specs) { + const SdpAudioFormat fmt = {"ILBC", 8000, 1}; + const AudioCodecInfo info = QueryAudioEncoder(*SdpToConfig(fmt)); + specs->push_back({fmt, info}); +} + +AudioCodecInfo AudioEncoderIlbc::QueryAudioEncoder( + const AudioEncoderIlbcConfig& config) { + RTC_DCHECK(config.IsOk()); + return {8000, 1, GetIlbcBitrate(config.frame_size_ms)}; +} + +std::unique_ptr AudioEncoderIlbc::MakeAudioEncoder( + const AudioEncoderIlbcConfig& config, + int payload_type) { + RTC_DCHECK(config.IsOk()); + return rtc::MakeUnique(config, payload_type); +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h b/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h new file mode 100644 index 0000000000..42010354a3 --- /dev/null +++ b/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 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 WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_ +#define WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_encoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc_config.h" +#include "webrtc/base/optional.h" + +namespace webrtc { + +// ILBC encoder API for use as a template parameter to +// CreateAudioEncoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderIlbc { + static rtc::Optional SdpToConfig( + const SdpAudioFormat& audio_format); + static void AppendSupportedEncoders(std::vector* specs); + static AudioCodecInfo QueryAudioEncoder(const AudioEncoderIlbcConfig& config); + static std::unique_ptr MakeAudioEncoder( + const AudioEncoderIlbcConfig& config, + int payload_type); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_ diff --git a/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc_config.h b/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc_config.h new file mode 100644 index 0000000000..429ac8112d --- /dev/null +++ b/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc_config.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017 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 WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_CONFIG_H_ +#define WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_CONFIG_H_ + +namespace webrtc { + +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderIlbcConfig { + bool IsOk() const { + return (frame_size_ms == 20 || frame_size_ms == 30 || frame_size_ms == 40 || + frame_size_ms == 60); + } + int frame_size_ms = 30; // Valid values are 20, 30, 40, and 60 ms. + // Note that frame size 40 ms produces encodings with two 20 ms frames in + // them, and frame size 60 ms consists of two 30 ms frames. +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_CONFIG_H_ diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn index 08d527d2b0..38ca736e1a 100644 --- a/webrtc/api/audio_codecs/test/BUILD.gn +++ b/webrtc/api/audio_codecs/test/BUILD.gn @@ -26,6 +26,8 @@ if (rtc_include_tests) { "../../../test:test_support", "../g722:audio_decoder_g722", "../g722:audio_encoder_g722", + "../ilbc:audio_decoder_ilbc", + "../ilbc:audio_encoder_ilbc", "//testing/gmock", ] } diff --git a/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc index c05fcd6e2f..283a5f5e67 100644 --- a/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc +++ b/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc @@ -10,6 +10,7 @@ #include "webrtc/api/audio_codecs/audio_decoder_factory_template.h" #include "webrtc/api/audio_codecs/g722/audio_decoder_g722.h" +#include "webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h" #include "webrtc/base/ptr_util.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" @@ -131,4 +132,17 @@ TEST(AudioDecoderFactoryTemplateTest, G722) { ASSERT_EQ(nullptr, dec3); } +TEST(AudioDecoderFactoryTemplateTest, Ilbc) { + auto factory = CreateAudioDecoderFactory(); + EXPECT_THAT(factory->GetSupportedDecoders(), + testing::ElementsAre( + AudioCodecSpec{{"ILBC", 8000, 1}, {8000, 1, 13300}})); + EXPECT_FALSE(factory->IsSupportedDecoder({"foo", 8000, 1})); + EXPECT_TRUE(factory->IsSupportedDecoder({"ilbc", 8000, 1})); + EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 8000, 1})); + auto dec = factory->MakeAudioDecoder({"ilbc", 8000, 1}); + ASSERT_NE(nullptr, dec); + EXPECT_EQ(8000, dec->SampleRateHz()); +} + } // namespace webrtc diff --git a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc index abca96852b..c3c07c65ee 100644 --- a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc +++ b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc @@ -10,6 +10,7 @@ #include "webrtc/api/audio_codecs/audio_encoder_factory_template.h" #include "webrtc/api/audio_codecs/g722/audio_encoder_g722.h" +#include "webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h" #include "webrtc/base/ptr_util.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" @@ -133,4 +134,19 @@ TEST(AudioEncoderFactoryTemplateTest, G722) { EXPECT_EQ(16000, enc->SampleRateHz()); } +TEST(AudioEncoderFactoryTemplateTest, Ilbc) { + auto factory = CreateAudioEncoderFactory(); + EXPECT_THAT(factory->GetSupportedEncoders(), + testing::ElementsAre( + AudioCodecSpec{{"ILBC", 8000, 1}, {8000, 1, 13333}})); + EXPECT_EQ(rtc::Optional(), + factory->QueryAudioEncoder({"foo", 8000, 1})); + EXPECT_EQ(rtc::Optional({8000, 1, 13333}), + factory->QueryAudioEncoder({"ilbc", 8000, 1})); + EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 8000, 1})); + auto enc = factory->MakeAudioEncoder(17, {"ilbc", 8000, 1}); + ASSERT_NE(nullptr, enc); + EXPECT_EQ(8000, enc->SampleRateHz()); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index afd2720f39..30460ba203 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -322,6 +322,7 @@ rtc_static_library("ilbc") { ":legacy_encoded_audio_frame", "../..:webrtc_common", "../../api/audio_codecs:audio_codecs_api", + "../../api/audio_codecs/ilbc:audio_encoder_ilbc_config", "../../base:rtc_base_approved", "../../common_audio", ] diff --git a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc index 79491b83a6..8456285e49 100644 --- a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc +++ b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc @@ -173,7 +173,7 @@ std::unique_ptr CreateEncoder( return std::unique_ptr(new AudioEncoderPcm16B(speech_inst)); #ifdef WEBRTC_CODEC_ILBC if (STR_CASE_CMP(speech_inst.plname, "ilbc") == 0) - return std::unique_ptr(new AudioEncoderIlbc(speech_inst)); + return std::unique_ptr(new AudioEncoderIlbcImpl(speech_inst)); #endif #ifdef WEBRTC_CODEC_G722 if (STR_CASE_CMP(speech_inst.plname, "g722") == 0) diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc index 332ad06e26..ce7ec3d8f5 100644 --- a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc +++ b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory_internal.cc @@ -78,7 +78,7 @@ NamedDecoderConstructor decoder_constructors[] = { [](const SdpAudioFormat& format, std::unique_ptr* out) { if (format.clockrate_hz == 8000 && format.num_channels == 1) { if (out) { - out->reset(new AudioDecoderIlbc); + out->reset(new AudioDecoderIlbcImpl); } return true; } else { diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc index 3f75cc8624..3c8c03065a 100644 --- a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc +++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_internal.cc @@ -65,7 +65,7 @@ NamedEncoderFactory encoder_factories[] = { NamedEncoderFactory::ForEncoder(), #endif #ifdef WEBRTC_CODEC_ILBC - NamedEncoderFactory::ForEncoder(), + NamedEncoderFactory::ForEncoder(), #endif #if defined(WEBRTC_CODEC_ISACFX) NamedEncoderFactory::ForEncoder(), diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc index a0fc02bb59..a95c7d5a17 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc @@ -19,20 +19,20 @@ namespace webrtc { -AudioDecoderIlbc::AudioDecoderIlbc() { +AudioDecoderIlbcImpl::AudioDecoderIlbcImpl() { WebRtcIlbcfix_DecoderCreate(&dec_state_); WebRtcIlbcfix_Decoderinit30Ms(dec_state_); } -AudioDecoderIlbc::~AudioDecoderIlbc() { +AudioDecoderIlbcImpl::~AudioDecoderIlbcImpl() { WebRtcIlbcfix_DecoderFree(dec_state_); } -bool AudioDecoderIlbc::HasDecodePlc() const { +bool AudioDecoderIlbcImpl::HasDecodePlc() const { return true; } -int AudioDecoderIlbc::DecodeInternal(const uint8_t* encoded, +int AudioDecoderIlbcImpl::DecodeInternal(const uint8_t* encoded, size_t encoded_len, int sample_rate_hz, int16_t* decoded, @@ -45,22 +45,22 @@ int AudioDecoderIlbc::DecodeInternal(const uint8_t* encoded, return ret; } -size_t AudioDecoderIlbc::DecodePlc(size_t num_frames, int16_t* decoded) { +size_t AudioDecoderIlbcImpl::DecodePlc(size_t num_frames, int16_t* decoded) { return WebRtcIlbcfix_NetEqPlc(dec_state_, decoded, num_frames); } -void AudioDecoderIlbc::Reset() { +void AudioDecoderIlbcImpl::Reset() { WebRtcIlbcfix_Decoderinit30Ms(dec_state_); } -std::vector AudioDecoderIlbc::ParsePayload( +std::vector AudioDecoderIlbcImpl::ParsePayload( rtc::Buffer&& payload, uint32_t timestamp) { std::vector results; size_t bytes_per_frame; int timestamps_per_frame; if (payload.size() >= 950) { - LOG(LS_WARNING) << "AudioDecoderIlbc::ParsePayload: Payload too large"; + LOG(LS_WARNING) << "AudioDecoderIlbcImpl::ParsePayload: Payload too large"; return results; } if (payload.size() % 38 == 0) { @@ -72,7 +72,7 @@ std::vector AudioDecoderIlbc::ParsePayload( bytes_per_frame = 50; timestamps_per_frame = 240; } else { - LOG(LS_WARNING) << "AudioDecoderIlbc::ParsePayload: Invalid payload"; + LOG(LS_WARNING) << "AudioDecoderIlbcImpl::ParsePayload: Invalid payload"; return results; } @@ -97,11 +97,11 @@ std::vector AudioDecoderIlbc::ParsePayload( return results; } -int AudioDecoderIlbc::SampleRateHz() const { +int AudioDecoderIlbcImpl::SampleRateHz() const { return 8000; } -size_t AudioDecoderIlbc::Channels() const { +size_t AudioDecoderIlbcImpl::Channels() const { return 1; } diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h index bc01a5de7d..5269f4d456 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h @@ -18,10 +18,10 @@ typedef struct iLBC_decinst_t_ IlbcDecoderInstance; namespace webrtc { -class AudioDecoderIlbc final : public AudioDecoder { +class AudioDecoderIlbcImpl final : public AudioDecoder { public: - AudioDecoderIlbc(); - ~AudioDecoderIlbc() override; + AudioDecoderIlbcImpl(); + ~AudioDecoderIlbcImpl() override; bool HasDecodePlc() const override; size_t DecodePlc(size_t num_frames, int16_t* decoded) override; void Reset() override; @@ -39,7 +39,7 @@ class AudioDecoderIlbc final : public AudioDecoder { private: IlbcDecoderInstance* dec_state_; - RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIlbc); + RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIlbcImpl); }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc index 6ed445a97e..0dc9bb4d1c 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc @@ -24,34 +24,20 @@ namespace { const int kSampleRateHz = 8000; -AudioEncoderIlbc::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderIlbc::Config config; +AudioEncoderIlbcConfig CreateConfig(const CodecInst& codec_inst) { + AudioEncoderIlbcConfig config; config.frame_size_ms = codec_inst.pacsize / 8; - config.payload_type = codec_inst.pltype; - return config; -} - -AudioEncoderIlbc::Config CreateConfig(int payload_type, - const SdpAudioFormat& format) { - AudioEncoderIlbc::Config config; - config.payload_type = payload_type; - auto ptime_iter = format.parameters.find("ptime"); - if (ptime_iter != format.parameters.end()) { - auto ptime = rtc::StringToNumber(ptime_iter->second); - if (ptime && *ptime > 0) { - const int whole_packets = *ptime / 10; - config.frame_size_ms = std::max(20, std::min(whole_packets * 10, 60)); - } - } return config; } int GetIlbcBitrate(int ptime) { switch (ptime) { - case 20: case 40: + case 20: + case 40: // 38 bytes per frame of 20 ms => 15200 bits/s. return 15200; - case 30: case 60: + case 30: + case 60: // 50 bytes per frame of 30 ms => (approx) 13333 bits/s. return 13333; default: @@ -61,71 +47,85 @@ int GetIlbcBitrate(int ptime) { } // namespace -// static -const size_t AudioEncoderIlbc::kMaxSamplesPerPacket; +rtc::Optional AudioEncoderIlbcImpl::SdpToConfig( + const SdpAudioFormat& format) { + if (STR_CASE_CMP(format.name.c_str(), "ilbc") != 0 || + format.clockrate_hz != 8000 || format.num_channels != 1) { + return rtc::Optional(); + } -bool AudioEncoderIlbc::Config::IsOk() const { - return (frame_size_ms == 20 || frame_size_ms == 30 || frame_size_ms == 40 || - frame_size_ms == 60) && - static_cast(kSampleRateHz / 100 * (frame_size_ms / 10)) <= - kMaxSamplesPerPacket; + AudioEncoderIlbcConfig config; + auto ptime_iter = format.parameters.find("ptime"); + if (ptime_iter != format.parameters.end()) { + auto ptime = rtc::StringToNumber(ptime_iter->second); + if (ptime && *ptime > 0) { + const int whole_packets = *ptime / 10; + config.frame_size_ms = std::max(20, std::min(whole_packets * 10, 60)); + } + } + return config.IsOk() ? rtc::Optional(config) + : rtc::Optional(); } -AudioEncoderIlbc::AudioEncoderIlbc(const Config& config) - : config_(config), +AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(const AudioEncoderIlbcConfig& config, + int payload_type) + : frame_size_ms_(config.frame_size_ms), + payload_type_(payload_type), num_10ms_frames_per_packet_( static_cast(config.frame_size_ms / 10)), encoder_(nullptr) { + RTC_CHECK(config.IsOk()); Reset(); } -AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst) - : AudioEncoderIlbc(CreateConfig(codec_inst)) {} +AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(const CodecInst& codec_inst) + : AudioEncoderIlbcImpl(CreateConfig(codec_inst), codec_inst.pltype) {} -AudioEncoderIlbc::AudioEncoderIlbc(int payload_type, - const SdpAudioFormat& format) - : AudioEncoderIlbc(CreateConfig(payload_type, format)) {} +AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(int payload_type, + const SdpAudioFormat& format) + : AudioEncoderIlbcImpl(*SdpToConfig(format), payload_type) {} -rtc::Optional AudioEncoderIlbc::QueryAudioEncoder( - const SdpAudioFormat& format) { - if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 && - format.clockrate_hz == 8000 && format.num_channels == 1) { - Config config = CreateConfig(0, format); - if (config.IsOk()) { - return rtc::Optional( - {kSampleRateHz, 1, GetIlbcBitrate(config.frame_size_ms)}); - } - } - - return rtc::Optional(); -} - -AudioEncoderIlbc::~AudioEncoderIlbc() { +AudioEncoderIlbcImpl::~AudioEncoderIlbcImpl() { RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_)); } -int AudioEncoderIlbc::SampleRateHz() const { +rtc::Optional AudioEncoderIlbcImpl::QueryAudioEncoder( + const SdpAudioFormat& format) { + if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0) { + const auto config_opt = SdpToConfig(format); + if (format.clockrate_hz == 8000 && format.num_channels == 1 && + config_opt) { + RTC_DCHECK(config_opt->IsOk()); + return rtc::Optional( + {rtc::dchecked_cast(kSampleRateHz), 1, + GetIlbcBitrate(config_opt->frame_size_ms)}); + } + } + return rtc::Optional(); +} + +int AudioEncoderIlbcImpl::SampleRateHz() const { return kSampleRateHz; } -size_t AudioEncoderIlbc::NumChannels() const { +size_t AudioEncoderIlbcImpl::NumChannels() const { return 1; } -size_t AudioEncoderIlbc::Num10MsFramesInNextPacket() const { +size_t AudioEncoderIlbcImpl::Num10MsFramesInNextPacket() const { return num_10ms_frames_per_packet_; } -size_t AudioEncoderIlbc::Max10MsFramesInAPacket() const { +size_t AudioEncoderIlbcImpl::Max10MsFramesInAPacket() const { return num_10ms_frames_per_packet_; } -int AudioEncoderIlbc::GetTargetBitrate() const { +int AudioEncoderIlbcImpl::GetTargetBitrate() const { return GetIlbcBitrate(rtc::dchecked_cast(num_10ms_frames_per_packet_) * 10); } -AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeImpl( +AudioEncoder::EncodedInfo AudioEncoderIlbcImpl::EncodeImpl( uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) { @@ -166,24 +166,23 @@ AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeImpl( EncodedInfo info; info.encoded_bytes = encoded_bytes; info.encoded_timestamp = first_timestamp_in_buffer_; - info.payload_type = config_.payload_type; + info.payload_type = payload_type_; info.encoder_type = CodecType::kIlbc; return info; } -void AudioEncoderIlbc::Reset() { +void AudioEncoderIlbcImpl::Reset() { if (encoder_) RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_)); - RTC_CHECK(config_.IsOk()); RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_)); - const int encoder_frame_size_ms = config_.frame_size_ms > 30 - ? config_.frame_size_ms / 2 - : config_.frame_size_ms; + const int encoder_frame_size_ms = frame_size_ms_ > 30 + ? frame_size_ms_ / 2 + : frame_size_ms_; RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms)); num_10ms_frames_buffered_ = 0; } -size_t AudioEncoderIlbc::RequiredOutputSizeBytes() const { +size_t AudioEncoderIlbcImpl::RequiredOutputSizeBytes() const { switch (num_10ms_frames_per_packet_) { case 2: return 38; case 3: return 50; diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h index 6d3d102cba..0d9b366747 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h +++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h @@ -13,6 +13,7 @@ #include "webrtc/api/audio_codecs/audio_encoder.h" #include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc_config.h" #include "webrtc/base/constructormagic.h" #include "webrtc/modules/audio_coding/codecs/ilbc/ilbc.h" @@ -20,21 +21,15 @@ namespace webrtc { struct CodecInst; -class AudioEncoderIlbc final : public AudioEncoder { +class AudioEncoderIlbcImpl final : public AudioEncoder { public: - struct Config { - bool IsOk() const; + static rtc::Optional SdpToConfig( + const SdpAudioFormat& format); - int payload_type = 102; - int frame_size_ms = 30; // Valid values are 20, 30, 40, and 60 ms. - // Note that frame size 40 ms produces encodings with two 20 ms frames in - // them, and frame size 60 ms consists of two 30 ms frames. - }; - - explicit AudioEncoderIlbc(const Config& config); - explicit AudioEncoderIlbc(const CodecInst& codec_inst); - AudioEncoderIlbc(int payload_type, const SdpAudioFormat& format); - ~AudioEncoderIlbc() override; + AudioEncoderIlbcImpl(const AudioEncoderIlbcConfig& config, int payload_type); + explicit AudioEncoderIlbcImpl(const CodecInst& codec_inst); + AudioEncoderIlbcImpl(int payload_type, const SdpAudioFormat& format); + ~AudioEncoderIlbcImpl() override; static constexpr const char* GetPayloadName() { return "ILBC"; } static rtc::Optional QueryAudioEncoder( @@ -53,14 +48,15 @@ class AudioEncoderIlbc final : public AudioEncoder { private: size_t RequiredOutputSizeBytes() const; - static const size_t kMaxSamplesPerPacket = 480; - const Config config_; + static constexpr size_t kMaxSamplesPerPacket = 480; + const int frame_size_ms_; + const int payload_type_; const size_t num_10ms_frames_per_packet_; size_t num_10ms_frames_buffered_; uint32_t first_timestamp_in_buffer_; int16_t input_buffer_[kMaxSamplesPerPacket]; IlbcEncoderInstance* encoder_; - RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIlbc); + RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIlbcImpl); }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc b/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc index dbd5c07763..69e218188b 100644 --- a/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc @@ -17,11 +17,11 @@ namespace webrtc { TEST(IlbcTest, BadPacket) { // Get a good packet. - AudioEncoderIlbc::Config config; + AudioEncoderIlbcConfig config; config.frame_size_ms = 20; // We need 20 ms rather than the default 30 ms; // otherwise, all possible values of cb_index[2] // are valid. - AudioEncoderIlbc encoder(config); + AudioEncoderIlbcImpl encoder(config, 102); std::vector samples(encoder.SampleRateHz() / 100, 4711); rtc::Buffer packet; int num_10ms_chunks = 0; @@ -39,7 +39,7 @@ TEST(IlbcTest, BadPacket) { bad_packet[30] |= 0x80; // Bit 0. // Decode the bad packet. We expect the decoder to respond by returning -1. - AudioDecoderIlbc decoder; + AudioDecoderIlbcImpl decoder; std::vector decoded_samples(num_10ms_chunks * samples.size()); AudioDecoder::SpeechType speech_type; EXPECT_EQ(-1, decoder.Decode(bad_packet.data(), bad_packet.size(), @@ -69,7 +69,7 @@ class SplitIlbcTest : public ::testing::TestWithParam > { }; TEST_P(SplitIlbcTest, NumFrames) { - AudioDecoderIlbc decoder; + AudioDecoderIlbcImpl decoder; const size_t frame_length_samples = frame_length_ms_ * 8; const auto generate_payload = [] (size_t payload_length_bytes) { rtc::Buffer payload(payload_length_bytes); @@ -120,7 +120,7 @@ INSTANTIATE_TEST_CASE_P( // Test too large payload size. TEST(IlbcTest, SplitTooLargePayload) { - AudioDecoderIlbc decoder; + AudioDecoderIlbcImpl decoder; constexpr size_t kPayloadLengthBytes = 950; const auto results = decoder.ParsePayload(rtc::Buffer(kPayloadLengthBytes), 0); @@ -129,7 +129,7 @@ TEST(IlbcTest, SplitTooLargePayload) { // Payload not an integer number of frames. TEST(IlbcTest, SplitUnevenPayload) { - AudioDecoderIlbc decoder; + AudioDecoderIlbcImpl decoder; constexpr size_t kPayloadLengthBytes = 39; // Not an even number of frames. const auto results = decoder.ParsePayload(rtc::Buffer(kPayloadLengthBytes), 0); diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index 6d71b85941..15a89e9bc0 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -315,12 +315,11 @@ class AudioDecoderIlbcTest : public AudioDecoderTest { codec_input_rate_hz_ = 8000; frame_size_ = 240; data_length_ = 10 * frame_size_; - decoder_ = new AudioDecoderIlbc; + decoder_ = new AudioDecoderIlbcImpl; assert(decoder_); - AudioEncoderIlbc::Config config; + AudioEncoderIlbcConfig config; config.frame_size_ms = 30; - config.payload_type = payload_type_; - audio_encoder_.reset(new AudioEncoderIlbc(config)); + audio_encoder_.reset(new AudioEncoderIlbcImpl(config, payload_type_)); } // Overload the default test since iLBC's function WebRtcIlbcfix_NetEqPlc does diff --git a/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc b/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc index 1c6d2ca797..b3524a3a6d 100644 --- a/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc +++ b/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc @@ -51,9 +51,9 @@ class NetEqIlbcQualityTest : public NetEqQualityTest { void SetUp() override { ASSERT_EQ(1u, channels_) << "iLBC supports only mono audio."; - AudioEncoderIlbc::Config config; + AudioEncoderIlbcConfig config; config.frame_size_ms = FLAGS_frame_size_ms; - encoder_.reset(new AudioEncoderIlbc(config)); + encoder_.reset(new AudioEncoderIlbcImpl(config, 102)); NetEqQualityTest::SetUp(); } @@ -75,7 +75,7 @@ class NetEqIlbcQualityTest : public NetEqQualityTest { } private: - std::unique_ptr encoder_; + std::unique_ptr encoder_; }; TEST_F(NetEqIlbcQualityTest, Test) { diff --git a/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc b/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc index b3bc4349d1..fbc9d66e8c 100644 --- a/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc +++ b/webrtc/test/fuzzers/audio_decoder_ilbc_fuzzer.cc @@ -13,7 +13,7 @@ namespace webrtc { void FuzzOneInput(const uint8_t* data, size_t size) { - AudioDecoderIlbc dec; + AudioDecoderIlbcImpl dec; static const int kSampleRateHz = 8000; static const size_t kAllocatedOuputSizeSamples = kSampleRateHz / 10; int16_t output[kAllocatedOuputSizeSamples];