diff --git a/webrtc/api/audio_codecs/g722/BUILD.gn b/webrtc/api/audio_codecs/g722/BUILD.gn index 78708f5194..d2470a26e4 100644 --- a/webrtc/api/audio_codecs/g722/BUILD.gn +++ b/webrtc/api/audio_codecs/g722/BUILD.gn @@ -12,6 +12,25 @@ if (is_android) { import("//build/config/android/rules.gni") } +rtc_source_set("audio_encoder_g722_config") { + sources = [ + "audio_encoder_g722_config.h", + ] +} + +rtc_static_library("audio_encoder_g722") { + sources = [ + "audio_encoder_g722.cc", + "audio_encoder_g722.h", + ] + deps = [ + ":audio_encoder_g722_config", + "..:audio_codecs_api", + "../../../base:rtc_base_approved", + "../../../modules/audio_coding:g722", + ] +} + rtc_static_library("audio_decoder_g722") { sources = [ "audio_decoder_g722.cc", diff --git a/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc b/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc new file mode 100644 index 0000000000..7f82b9c04b --- /dev/null +++ b/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc @@ -0,0 +1,48 @@ +/* + * 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/g722/audio_encoder_g722.h" + +#include +#include + +#include "webrtc/base/ptr_util.h" +#include "webrtc/base/safe_conversions.h" +#include "webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h" + +namespace webrtc { + +rtc::Optional AudioEncoderG722::SdpToConfig( + const SdpAudioFormat& format) { + return AudioEncoderG722Impl::SdpToConfig(format); +} + +void AudioEncoderG722::AppendSupportedEncoders( + std::vector* specs) { + const SdpAudioFormat fmt = {"g722", 8000, 1}; + const AudioCodecInfo info = QueryAudioEncoder(*SdpToConfig(fmt)); + specs->push_back({fmt, info}); +} + +AudioCodecInfo AudioEncoderG722::QueryAudioEncoder( + const AudioEncoderG722Config& config) { + RTC_DCHECK(config.IsOk()); + return {16000, rtc::dchecked_cast(config.num_channels), + 64000 * config.num_channels}; +} + +std::unique_ptr AudioEncoderG722::MakeAudioEncoder( + const AudioEncoderG722Config& config, + int payload_type) { + RTC_DCHECK(config.IsOk()); + return rtc::MakeUnique(config, payload_type); +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/g722/audio_encoder_g722.h b/webrtc/api/audio_codecs/g722/audio_encoder_g722.h new file mode 100644 index 0000000000..369ebadef7 --- /dev/null +++ b/webrtc/api/audio_codecs/g722/audio_encoder_g722.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_G722_AUDIO_ENCODER_G722_H_ +#define WEBRTC_API_AUDIO_CODECS_G722_AUDIO_ENCODER_G722_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_encoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h" +#include "webrtc/base/optional.h" + +namespace webrtc { + +// G722 encoder API for use as a template parameter to +// CreateAudioEncoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderG722 { + static rtc::Optional SdpToConfig( + const SdpAudioFormat& audio_format); + static void AppendSupportedEncoders(std::vector* specs); + static AudioCodecInfo QueryAudioEncoder(const AudioEncoderG722Config& config); + static std::unique_ptr MakeAudioEncoder( + const AudioEncoderG722Config& config, + int payload_type); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_G722_AUDIO_ENCODER_G722_H_ diff --git a/webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h b/webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h new file mode 100644 index 0000000000..fa26942976 --- /dev/null +++ b/webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h @@ -0,0 +1,27 @@ +/* + * 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_G722_AUDIO_ENCODER_G722_CONFIG_H_ +#define WEBRTC_API_AUDIO_CODECS_G722_AUDIO_ENCODER_G722_CONFIG_H_ + +namespace webrtc { + +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderG722Config { + bool IsOk() const { + return frame_size_ms > 0 && frame_size_ms % 10 == 0 && num_channels >= 1; + } + int frame_size_ms = 20; + int num_channels = 1; +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_G722_AUDIO_ENCODER_G722_CONFIG_H_ diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn index 914acf46a4..08d527d2b0 100644 --- a/webrtc/api/audio_codecs/test/BUILD.gn +++ b/webrtc/api/audio_codecs/test/BUILD.gn @@ -25,6 +25,7 @@ if (rtc_include_tests) { "../../../test:audio_codec_mocks", "../../../test:test_support", "../g722:audio_decoder_g722", + "../g722:audio_encoder_g722", "//testing/gmock", ] } 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 15097b9318..abca96852b 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 @@ -9,6 +9,7 @@ */ #include "webrtc/api/audio_codecs/audio_encoder_factory_template.h" +#include "webrtc/api/audio_codecs/g722/audio_encoder_g722.h" #include "webrtc/base/ptr_util.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" @@ -117,4 +118,19 @@ TEST(AudioEncoderFactoryTemplateTest, TwoEncoderTypes) { EXPECT_EQ(16000, enc2->SampleRateHz()); } +TEST(AudioEncoderFactoryTemplateTest, G722) { + auto factory = CreateAudioEncoderFactory(); + EXPECT_THAT(factory->GetSupportedEncoders(), + testing::ElementsAre( + AudioCodecSpec{{"g722", 8000, 1}, {16000, 1, 64000}})); + EXPECT_EQ(rtc::Optional(), + factory->QueryAudioEncoder({"foo", 8000, 1})); + EXPECT_EQ(rtc::Optional({16000, 1, 64000}), + factory->QueryAudioEncoder({"g722", 8000, 1})); + EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); + auto enc = factory->MakeAudioEncoder(17, {"g722", 8000, 1}); + ASSERT_NE(nullptr, enc); + EXPECT_EQ(16000, enc->SampleRateHz()); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index dc107b6cf5..afd2720f39 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -279,6 +279,7 @@ rtc_static_library("g722") { ":legacy_encoded_audio_frame", "../..:webrtc_common", "../../api/audio_codecs:audio_codecs_api", + "../../api/audio_codecs/g722:audio_encoder_g722_config", "../../base:rtc_base_approved", ] public_deps = [ diff --git a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc index b353b38201..79491b83a6 100644 --- a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc +++ b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc @@ -177,7 +177,7 @@ std::unique_ptr CreateEncoder( #endif #ifdef WEBRTC_CODEC_G722 if (STR_CASE_CMP(speech_inst.plname, "g722") == 0) - return std::unique_ptr(new AudioEncoderG722(speech_inst)); + return std::unique_ptr(new AudioEncoderG722Impl(speech_inst)); #endif LOG_F(LS_ERROR) << "Could not create encoder of type " << speech_inst.plname; return std::unique_ptr(); 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 32d255308c..3f75cc8624 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 @@ -62,7 +62,7 @@ struct NamedEncoderFactory { NamedEncoderFactory encoder_factories[] = { #ifdef WEBRTC_CODEC_G722 - NamedEncoderFactory::ForEncoder(), + NamedEncoderFactory::ForEncoder(), #endif #ifdef WEBRTC_CODEC_ILBC NamedEncoderFactory::ForEncoder(), diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc index d5cf616313..8d254b83cc 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc +++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc @@ -25,19 +25,24 @@ namespace { const size_t kSampleRateHz = 16000; -AudioEncoderG722::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderG722::Config config; - config.num_channels = codec_inst.channels; +AudioEncoderG722Config CreateConfig(const CodecInst& codec_inst) { + AudioEncoderG722Config config; + config.num_channels = rtc::dchecked_cast(codec_inst.channels); config.frame_size_ms = codec_inst.pacsize / 16; - config.payload_type = codec_inst.pltype; return config; } -AudioEncoderG722::Config CreateConfig(int payload_type, - const SdpAudioFormat& format) { - AudioEncoderG722::Config config; - config.payload_type = payload_type; - config.num_channels = format.num_channels; +} // namespace + +rtc::Optional AudioEncoderG722Impl::SdpToConfig( + const SdpAudioFormat& format) { + if (STR_CASE_CMP(format.name.c_str(), "g722") != 0 || + format.clockrate_hz != 8000) { + return rtc::Optional(); + } + + AudioEncoderG722Config config; + config.num_channels = rtc::dchecked_cast(format.num_channels); auto ptime_iter = format.parameters.find("ptime"); if (ptime_iter != format.parameters.end()) { auto ptime = rtc::StringToNumber(ptime_iter->second); @@ -46,19 +51,14 @@ AudioEncoderG722::Config CreateConfig(int payload_type, config.frame_size_ms = std::max(10, std::min(whole_packets * 10, 60)); } } - return config; + return config.IsOk() ? rtc::Optional(config) + : rtc::Optional(); } -} // namespace - -bool AudioEncoderG722::Config::IsOk() const { - return (frame_size_ms > 0) && (frame_size_ms % 10 == 0) && - (num_channels >= 1); -} - -AudioEncoderG722::AudioEncoderG722(const Config& config) +AudioEncoderG722Impl::AudioEncoderG722Impl(const AudioEncoderG722Config& config, + int payload_type) : num_channels_(config.num_channels), - payload_type_(config.payload_type), + payload_type_(payload_type), num_10ms_frames_per_packet_( static_cast(config.frame_size_ms / 10)), num_10ms_frames_buffered_(0), @@ -75,61 +75,63 @@ AudioEncoderG722::AudioEncoderG722(const Config& config) Reset(); } -AudioEncoderG722::AudioEncoderG722(const CodecInst& codec_inst) - : AudioEncoderG722(CreateConfig(codec_inst)) {} +AudioEncoderG722Impl::AudioEncoderG722Impl(const CodecInst& codec_inst) + : AudioEncoderG722Impl(CreateConfig(codec_inst), codec_inst.pltype) {} -AudioEncoderG722::AudioEncoderG722(int payload_type, - const SdpAudioFormat& format) - : AudioEncoderG722(CreateConfig(payload_type, format)) {} +AudioEncoderG722Impl::AudioEncoderG722Impl(int payload_type, + const SdpAudioFormat& format) + : AudioEncoderG722Impl(*SdpToConfig(format), payload_type) {} -AudioEncoderG722::~AudioEncoderG722() = default; +AudioEncoderG722Impl::~AudioEncoderG722Impl() = default; -rtc::Optional AudioEncoderG722::QueryAudioEncoder( +rtc::Optional AudioEncoderG722Impl::QueryAudioEncoder( const SdpAudioFormat& format) { if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0) { - Config config = CreateConfig(0, format); - if (format.clockrate_hz == 8000 && config.IsOk()) { + const auto config_opt = SdpToConfig(format); + if (format.clockrate_hz == 8000 && config_opt) { + RTC_DCHECK(config_opt->IsOk()); return rtc::Optional( - {rtc::dchecked_cast(kSampleRateHz), config.num_channels, 64000}); + {rtc::dchecked_cast(kSampleRateHz), + rtc::dchecked_cast(config_opt->num_channels), 64000}); } } return rtc::Optional(); } -int AudioEncoderG722::SampleRateHz() const { +int AudioEncoderG722Impl::SampleRateHz() const { return kSampleRateHz; } -size_t AudioEncoderG722::NumChannels() const { +size_t AudioEncoderG722Impl::NumChannels() const { return num_channels_; } -int AudioEncoderG722::RtpTimestampRateHz() const { +int AudioEncoderG722Impl::RtpTimestampRateHz() const { // The RTP timestamp rate for G.722 is 8000 Hz, even though it is a 16 kHz // codec. return kSampleRateHz / 2; } -size_t AudioEncoderG722::Num10MsFramesInNextPacket() const { +size_t AudioEncoderG722Impl::Num10MsFramesInNextPacket() const { return num_10ms_frames_per_packet_; } -size_t AudioEncoderG722::Max10MsFramesInAPacket() const { +size_t AudioEncoderG722Impl::Max10MsFramesInAPacket() const { return num_10ms_frames_per_packet_; } -int AudioEncoderG722::GetTargetBitrate() const { +int AudioEncoderG722Impl::GetTargetBitrate() const { // 4 bits/sample, 16000 samples/s/channel. return static_cast(64000 * NumChannels()); } -void AudioEncoderG722::Reset() { +void AudioEncoderG722Impl::Reset() { num_10ms_frames_buffered_ = 0; for (size_t i = 0; i < num_channels_; ++i) RTC_CHECK_EQ(0, WebRtcG722_EncoderInit(encoders_[i].encoder)); } -AudioEncoder::EncodedInfo AudioEncoderG722::EncodeImpl( +AudioEncoder::EncodedInfo AudioEncoderG722Impl::EncodeImpl( uint32_t rtp_timestamp, rtc::ArrayView audio, rtc::Buffer* encoded) { @@ -185,15 +187,15 @@ AudioEncoder::EncodedInfo AudioEncoderG722::EncodeImpl( return info; } -AudioEncoderG722::EncoderState::EncoderState() { +AudioEncoderG722Impl::EncoderState::EncoderState() { RTC_CHECK_EQ(0, WebRtcG722_CreateEncoder(&encoder)); } -AudioEncoderG722::EncoderState::~EncoderState() { +AudioEncoderG722Impl::EncoderState::~EncoderState() { RTC_CHECK_EQ(0, WebRtcG722_FreeEncoder(encoder)); } -size_t AudioEncoderG722::SamplesPerChannel() const { +size_t AudioEncoderG722Impl::SamplesPerChannel() const { return kSampleRateHz / 100 * num_10ms_frames_per_packet_; } diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h index 9f37fe6dd0..ce87b2cdd3 100644 --- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h +++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h @@ -15,6 +15,7 @@ #include "webrtc/api/audio_codecs/audio_encoder.h" #include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h" #include "webrtc/base/buffer.h" #include "webrtc/base/constructormagic.h" #include "webrtc/modules/audio_coding/codecs/g722/g722_interface.h" @@ -23,20 +24,15 @@ namespace webrtc { struct CodecInst; -class AudioEncoderG722 final : public AudioEncoder { +class AudioEncoderG722Impl final : public AudioEncoder { public: - struct Config { - bool IsOk() const; + static rtc::Optional SdpToConfig( + const SdpAudioFormat& format); - int payload_type = 9; - int frame_size_ms = 20; - size_t num_channels = 1; - }; - - explicit AudioEncoderG722(const Config& config); - explicit AudioEncoderG722(const CodecInst& codec_inst); - AudioEncoderG722(int payload_type, const SdpAudioFormat& format); - ~AudioEncoderG722() override; + AudioEncoderG722Impl(const AudioEncoderG722Config& config, int payload_type); + explicit AudioEncoderG722Impl(const CodecInst& codec_inst); + AudioEncoderG722Impl(int payload_type, const SdpAudioFormat& format); + ~AudioEncoderG722Impl() override; static constexpr const char* GetPayloadName() { return "G722"; } static rtc::Optional QueryAudioEncoder( @@ -74,7 +70,7 @@ class AudioEncoderG722 final : public AudioEncoder { uint32_t first_timestamp_in_buffer_; const std::unique_ptr encoders_; rtc::Buffer interleave_buffer_; - RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderG722); + RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderG722Impl); }; } // namespace webrtc diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc index b1a07edf14..8dcb416217 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -404,11 +404,10 @@ class AudioDecoderG722Test : public AudioDecoderTest { data_length_ = 10 * frame_size_; decoder_ = new AudioDecoderG722Impl; assert(decoder_); - AudioEncoderG722::Config config; + AudioEncoderG722Config config; config.frame_size_ms = 10; - config.payload_type = payload_type_; config.num_channels = 1; - audio_encoder_.reset(new AudioEncoderG722(config)); + audio_encoder_.reset(new AudioEncoderG722Impl(config, payload_type_)); } }; @@ -421,11 +420,10 @@ class AudioDecoderG722StereoTest : public AudioDecoderTest { data_length_ = 10 * frame_size_; decoder_ = new AudioDecoderG722Stereo; assert(decoder_); - AudioEncoderG722::Config config; + AudioEncoderG722Config config; config.frame_size_ms = 10; - config.payload_type = payload_type_; config.num_channels = 2; - audio_encoder_.reset(new AudioEncoderG722(config)); + audio_encoder_.reset(new AudioEncoderG722Impl(config, payload_type_)); } };