G722 implementation of the AudioEncoderFactoryTemplate API
Now the templated AudioEncoderFactory can create G722 encoders!
BUG=webrtc:7833
Review-Url: https://codereview.webrtc.org/2934833002
Cr-Commit-Position: refs/heads/master@{#18644}
diff --git a/webrtc/api/audio_codecs/g722/BUILD.gn b/webrtc/api/audio_codecs/g722/BUILD.gn
index 78708f5..d2470a2 100644
--- a/webrtc/api/audio_codecs/g722/BUILD.gn
+++ b/webrtc/api/audio_codecs/g722/BUILD.gn
@@ -12,6 +12,25 @@
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 0000000..7f82b9c
--- /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 <memory>
+#include <vector>
+
+#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<AudioEncoderG722Config> AudioEncoderG722::SdpToConfig(
+ const SdpAudioFormat& format) {
+ return AudioEncoderG722Impl::SdpToConfig(format);
+}
+
+void AudioEncoderG722::AppendSupportedEncoders(
+ std::vector<AudioCodecSpec>* 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<size_t>(config.num_channels),
+ 64000 * config.num_channels};
+}
+
+std::unique_ptr<AudioEncoder> AudioEncoderG722::MakeAudioEncoder(
+ const AudioEncoderG722Config& config,
+ int payload_type) {
+ RTC_DCHECK(config.IsOk());
+ return rtc::MakeUnique<AudioEncoderG722Impl>(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 0000000..369ebad
--- /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 <memory>
+#include <vector>
+
+#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<AudioEncoderG722Config> SdpToConfig(
+ const SdpAudioFormat& audio_format);
+ static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs);
+ static AudioCodecInfo QueryAudioEncoder(const AudioEncoderG722Config& config);
+ static std::unique_ptr<AudioEncoder> 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 0000000..fa26942
--- /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 914acf4..08d527d 100644
--- a/webrtc/api/audio_codecs/test/BUILD.gn
+++ b/webrtc/api/audio_codecs/test/BUILD.gn
@@ -25,6 +25,7 @@
"../../../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 15097b9..abca968 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 @@
EXPECT_EQ(16000, enc2->SampleRateHz());
}
+TEST(AudioEncoderFactoryTemplateTest, G722) {
+ auto factory = CreateAudioEncoderFactory<AudioEncoderG722>();
+ EXPECT_THAT(factory->GetSupportedEncoders(),
+ testing::ElementsAre(
+ AudioCodecSpec{{"g722", 8000, 1}, {16000, 1, 64000}}));
+ EXPECT_EQ(rtc::Optional<AudioCodecInfo>(),
+ factory->QueryAudioEncoder({"foo", 8000, 1}));
+ EXPECT_EQ(rtc::Optional<AudioCodecInfo>({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 dc107b6..afd2720 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -279,6 +279,7 @@
":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 b353b38..79491b8 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 @@
#endif
#ifdef WEBRTC_CODEC_G722
if (STR_CASE_CMP(speech_inst.plname, "g722") == 0)
- return std::unique_ptr<AudioEncoder>(new AudioEncoderG722(speech_inst));
+ return std::unique_ptr<AudioEncoder>(new AudioEncoderG722Impl(speech_inst));
#endif
LOG_F(LS_ERROR) << "Could not create encoder of type " << speech_inst.plname;
return std::unique_ptr<AudioEncoder>();
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 32d2553..3f75cc8 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 @@
NamedEncoderFactory encoder_factories[] = {
#ifdef WEBRTC_CODEC_G722
- NamedEncoderFactory::ForEncoder<AudioEncoderG722>(),
+ NamedEncoderFactory::ForEncoder<AudioEncoderG722Impl>(),
#endif
#ifdef WEBRTC_CODEC_ILBC
NamedEncoderFactory::ForEncoder<AudioEncoderIlbc>(),
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 d5cf616..8d254b8 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 @@
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<int>(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<AudioEncoderG722Config> AudioEncoderG722Impl::SdpToConfig(
+ const SdpAudioFormat& format) {
+ if (STR_CASE_CMP(format.name.c_str(), "g722") != 0 ||
+ format.clockrate_hz != 8000) {
+ return rtc::Optional<AudioEncoderG722Config>();
+ }
+
+ AudioEncoderG722Config config;
+ config.num_channels = rtc::dchecked_cast<int>(format.num_channels);
auto ptime_iter = format.parameters.find("ptime");
if (ptime_iter != format.parameters.end()) {
auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
@@ -46,19 +51,14 @@
config.frame_size_ms = std::max(10, std::min(whole_packets * 10, 60));
}
}
- return config;
+ return config.IsOk() ? rtc::Optional<AudioEncoderG722Config>(config)
+ : rtc::Optional<AudioEncoderG722Config>();
}
-} // 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<size_t>(config.frame_size_ms / 10)),
num_10ms_frames_buffered_(0),
@@ -75,61 +75,63 @@
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<AudioCodecInfo> AudioEncoderG722::QueryAudioEncoder(
+rtc::Optional<AudioCodecInfo> 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<AudioCodecInfo>(
- {rtc::dchecked_cast<int>(kSampleRateHz), config.num_channels, 64000});
+ {rtc::dchecked_cast<int>(kSampleRateHz),
+ rtc::dchecked_cast<size_t>(config_opt->num_channels), 64000});
}
}
return rtc::Optional<AudioCodecInfo>();
}
-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<int>(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<const int16_t> audio,
rtc::Buffer* encoded) {
@@ -185,15 +187,15 @@
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 9f37fe6..ce87b2c 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 @@
struct CodecInst;
-class AudioEncoderG722 final : public AudioEncoder {
+class AudioEncoderG722Impl final : public AudioEncoder {
public:
- struct Config {
- bool IsOk() const;
+ static rtc::Optional<AudioEncoderG722Config> 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<AudioCodecInfo> QueryAudioEncoder(
@@ -74,7 +70,7 @@
uint32_t first_timestamp_in_buffer_;
const std::unique_ptr<EncoderState[]> 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 b1a07ed..8dcb416 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 @@
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 @@
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_));
}
};