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}
This commit is contained in:
@ -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",
|
||||
|
||||
48
webrtc/api/audio_codecs/g722/audio_encoder_g722.cc
Normal file
48
webrtc/api/audio_codecs/g722/audio_encoder_g722.cc
Normal file
@ -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
|
||||
40
webrtc/api/audio_codecs/g722/audio_encoder_g722.h
Normal file
40
webrtc/api/audio_codecs/g722/audio_encoder_g722.h
Normal file
@ -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_
|
||||
27
webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h
Normal file
27
webrtc/api/audio_codecs/g722/audio_encoder_g722_config.h
Normal file
@ -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_
|
||||
@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
@ -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<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
|
||||
|
||||
@ -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 = [
|
||||
|
||||
@ -177,7 +177,7 @@ std::unique_ptr<AudioEncoder> CreateEncoder(
|
||||
#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>();
|
||||
|
||||
@ -62,7 +62,7 @@ struct NamedEncoderFactory {
|
||||
|
||||
NamedEncoderFactory encoder_factories[] = {
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
NamedEncoderFactory::ForEncoder<AudioEncoderG722>(),
|
||||
NamedEncoderFactory::ForEncoder<AudioEncoderG722Impl>(),
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
NamedEncoderFactory::ForEncoder<AudioEncoderIlbc>(),
|
||||
|
||||
@ -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<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 @@ 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<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 @@ 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<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 @@ 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_;
|
||||
}
|
||||
|
||||
|
||||
@ -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<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 @@ class AudioEncoderG722 final : public AudioEncoder {
|
||||
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
|
||||
|
||||
@ -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_));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user