Expose ILBC codec in webrtc/api/audio_codecs/

BUG=webrtc:7834, webrtc:7840

Review-Url: https://codereview.webrtc.org/2951873002
Cr-Commit-Position: refs/heads/master@{#18803}
This commit is contained in:
solenberg
2017-06-28 02:05:04 -07:00
committed by Commit Bot
parent cd9dd458d0
commit db3c9b0f72
21 changed files with 390 additions and 110 deletions

View File

@ -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",
]
}

View 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.
*/
#include "webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h"
#include <memory>
#include <vector>
#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::Config> 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>(Config())
: rtc::Optional<Config>();
}
void AudioDecoderIlbc::AppendSupportedDecoders(
std::vector<AudioCodecSpec>* specs) {
specs->push_back({{"ILBC", 8000, 1}, {8000, 1, 13300}});
}
std::unique_ptr<AudioDecoder> AudioDecoderIlbc::MakeAudioDecoder(
Config config) {
return rtc::MakeUnique<AudioDecoderIlbcImpl>();
}
} // namespace webrtc

View File

@ -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 <memory>
#include <vector>
#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<Config> SdpToConfig(const SdpAudioFormat& audio_format);
static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs);
static std::unique_ptr<AudioDecoder> MakeAudioDecoder(Config config);
};
} // namespace webrtc
#endif // WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_DECODER_ILBC_H_

View File

@ -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 <memory>
#include <vector>
#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<AudioEncoderIlbcConfig> AudioEncoderIlbc::SdpToConfig(
const SdpAudioFormat& format) {
return AudioEncoderIlbcImpl::SdpToConfig(format);
}
void AudioEncoderIlbc::AppendSupportedEncoders(
std::vector<AudioCodecSpec>* 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<AudioEncoder> AudioEncoderIlbc::MakeAudioEncoder(
const AudioEncoderIlbcConfig& config,
int payload_type) {
RTC_DCHECK(config.IsOk());
return rtc::MakeUnique<AudioEncoderIlbcImpl>(config, payload_type);
}
} // namespace webrtc

View 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_ILBC_AUDIO_ENCODER_ILBC_H_
#define WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_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/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<AudioEncoderIlbcConfig> SdpToConfig(
const SdpAudioFormat& audio_format);
static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs);
static AudioCodecInfo QueryAudioEncoder(const AudioEncoderIlbcConfig& config);
static std::unique_ptr<AudioEncoder> MakeAudioEncoder(
const AudioEncoderIlbcConfig& config,
int payload_type);
};
} // namespace webrtc
#endif // WEBRTC_API_AUDIO_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_

View File

@ -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_

View File

@ -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",
]
}

View File

@ -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<AudioDecoderIlbc>();
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

View File

@ -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<AudioEncoderIlbc>();
EXPECT_THAT(factory->GetSupportedEncoders(),
testing::ElementsAre(
AudioCodecSpec{{"ILBC", 8000, 1}, {8000, 1, 13333}}));
EXPECT_EQ(rtc::Optional<AudioCodecInfo>(),
factory->QueryAudioEncoder({"foo", 8000, 1}));
EXPECT_EQ(rtc::Optional<AudioCodecInfo>({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

View File

@ -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",
]

View File

@ -173,7 +173,7 @@ std::unique_ptr<AudioEncoder> CreateEncoder(
return std::unique_ptr<AudioEncoder>(new AudioEncoderPcm16B(speech_inst));
#ifdef WEBRTC_CODEC_ILBC
if (STR_CASE_CMP(speech_inst.plname, "ilbc") == 0)
return std::unique_ptr<AudioEncoder>(new AudioEncoderIlbc(speech_inst));
return std::unique_ptr<AudioEncoder>(new AudioEncoderIlbcImpl(speech_inst));
#endif
#ifdef WEBRTC_CODEC_G722
if (STR_CASE_CMP(speech_inst.plname, "g722") == 0)

View File

@ -78,7 +78,7 @@ NamedDecoderConstructor decoder_constructors[] = {
[](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
if (format.clockrate_hz == 8000 && format.num_channels == 1) {
if (out) {
out->reset(new AudioDecoderIlbc);
out->reset(new AudioDecoderIlbcImpl);
}
return true;
} else {

View File

@ -65,7 +65,7 @@ NamedEncoderFactory encoder_factories[] = {
NamedEncoderFactory::ForEncoder<AudioEncoderG722Impl>(),
#endif
#ifdef WEBRTC_CODEC_ILBC
NamedEncoderFactory::ForEncoder<AudioEncoderIlbc>(),
NamedEncoderFactory::ForEncoder<AudioEncoderIlbcImpl>(),
#endif
#if defined(WEBRTC_CODEC_ISACFX)
NamedEncoderFactory::ForEncoder<AudioEncoderIsacFix>(),

View File

@ -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<AudioDecoder::ParseResult> AudioDecoderIlbc::ParsePayload(
std::vector<AudioDecoder::ParseResult> AudioDecoderIlbcImpl::ParsePayload(
rtc::Buffer&& payload,
uint32_t timestamp) {
std::vector<ParseResult> 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<AudioDecoder::ParseResult> 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<AudioDecoder::ParseResult> 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;
}

View File

@ -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

View File

@ -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<int>(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<AudioEncoderIlbcConfig> 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<AudioEncoderIlbcConfig>();
}
bool AudioEncoderIlbc::Config::IsOk() const {
return (frame_size_ms == 20 || frame_size_ms == 30 || frame_size_ms == 40 ||
frame_size_ms == 60) &&
static_cast<size_t>(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<int>(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<AudioEncoderIlbcConfig>(config)
: rtc::Optional<AudioEncoderIlbcConfig>();
}
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<size_t>(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<AudioCodecInfo> 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<AudioCodecInfo>(
{kSampleRateHz, 1, GetIlbcBitrate(config.frame_size_ms)});
}
}
return rtc::Optional<AudioCodecInfo>();
}
AudioEncoderIlbc::~AudioEncoderIlbc() {
AudioEncoderIlbcImpl::~AudioEncoderIlbcImpl() {
RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
}
int AudioEncoderIlbc::SampleRateHz() const {
rtc::Optional<AudioCodecInfo> 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<AudioCodecInfo>(
{rtc::dchecked_cast<int>(kSampleRateHz), 1,
GetIlbcBitrate(config_opt->frame_size_ms)});
}
}
return rtc::Optional<AudioCodecInfo>();
}
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<int>(num_10ms_frames_per_packet_) *
10);
}
AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeImpl(
AudioEncoder::EncodedInfo AudioEncoderIlbcImpl::EncodeImpl(
uint32_t rtp_timestamp,
rtc::ArrayView<const int16_t> 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;

View File

@ -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<AudioEncoderIlbcConfig> 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<AudioCodecInfo> 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

View File

@ -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<int16_t> 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<int16_t> 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<std::pair<int, int> > {
};
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);

View File

@ -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

View File

@ -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<AudioEncoderIlbc> encoder_;
std::unique_ptr<AudioEncoderIlbcImpl> encoder_;
};
TEST_F(NetEqIlbcQualityTest, Test) {

View File

@ -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];