Injectable audio encoders: BuiltinAudioEncoderFactory
This CL contains all the changes made to audio_coding while making
audio encoders injectable. Apart from some small changes to
webrtcvoiceengine, nothing here is hooked up to the outside
world. Those changes will be added to a follow-up CL.
BUG=webrtc:5806
Review-Url: https://codereview.webrtc.org/2695243005
Cr-Commit-Position: refs/heads/master@{#17569}
diff --git a/webrtc/api/DEPS b/webrtc/api/DEPS
index 0b3778b..245c31c 100644
--- a/webrtc/api/DEPS
+++ b/webrtc/api/DEPS
@@ -12,6 +12,13 @@
"+webrtc/voice_engine",
],
+ # TODO(ossu): Remove this exception when {builtin_,}audio_encoder_factory.h
+ # has moved to api/.
+ "peerconnectioninterface\.h": [
+ "+webrtc/modules/audio_coding/codecs/audio_encoder_factory.h",
+ "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
+ ],
+
# We allow .cc files in webrtc/api/ to #include a bunch of stuff
# that's off-limits for the .h files. That's because .h files leak
# their #includes to whoever's #including them, but .cc files do not
diff --git a/webrtc/api/audio_codecs/audio_format.cc b/webrtc/api/audio_codecs/audio_format.cc
index b0a86e2..3a1d0a9 100644
--- a/webrtc/api/audio_codecs/audio_format.cc
+++ b/webrtc/api/audio_codecs/audio_format.cc
@@ -19,17 +19,17 @@
SdpAudioFormat::SdpAudioFormat(const char* name,
int clockrate_hz,
- int num_channels)
+ size_t num_channels)
: name(name), clockrate_hz(clockrate_hz), num_channels(num_channels) {}
SdpAudioFormat::SdpAudioFormat(const std::string& name,
int clockrate_hz,
- int num_channels)
+ size_t num_channels)
: name(name), clockrate_hz(clockrate_hz), num_channels(num_channels) {}
SdpAudioFormat::SdpAudioFormat(const char* name,
int clockrate_hz,
- int num_channels,
+ size_t num_channels,
const Parameters& param)
: name(name),
clockrate_hz(clockrate_hz),
@@ -38,7 +38,7 @@
SdpAudioFormat::SdpAudioFormat(const std::string& name,
int clockrate_hz,
- int num_channels,
+ size_t num_channels,
const Parameters& param)
: name(name),
clockrate_hz(clockrate_hz),
@@ -77,9 +77,30 @@
return os;
}
-AudioCodecSpec::AudioCodecSpec(const SdpAudioFormat& format) : format(format) {}
+AudioCodecInfo::AudioCodecInfo(int sample_rate_hz,
+ size_t num_channels,
+ int bitrate_bps)
+ : AudioCodecInfo(sample_rate_hz,
+ num_channels,
+ bitrate_bps,
+ bitrate_bps,
+ bitrate_bps) {}
-AudioCodecSpec::AudioCodecSpec(SdpAudioFormat&& format)
- : format(std::move(format)) {}
+AudioCodecInfo::AudioCodecInfo(int sample_rate_hz,
+ size_t num_channels,
+ int default_bitrate_bps,
+ int min_bitrate_bps,
+ int max_bitrate_bps)
+ : sample_rate_hz(sample_rate_hz),
+ num_channels(num_channels),
+ default_bitrate_bps(default_bitrate_bps),
+ min_bitrate_bps(min_bitrate_bps),
+ max_bitrate_bps(max_bitrate_bps) {
+ RTC_DCHECK_GT(sample_rate_hz, 0);
+ RTC_DCHECK_GT(num_channels, 0);
+ RTC_DCHECK_GE(min_bitrate_bps, 0);
+ RTC_DCHECK_LE(min_bitrate_bps, default_bitrate_bps);
+ RTC_DCHECK_GE(max_bitrate_bps, default_bitrate_bps);
+}
} // namespace webrtc
diff --git a/webrtc/api/audio_codecs/audio_format.h b/webrtc/api/audio_codecs/audio_format.h
index db3990f..8814a3d 100644
--- a/webrtc/api/audio_codecs/audio_format.h
+++ b/webrtc/api/audio_codecs/audio_format.h
@@ -16,6 +16,8 @@
#include <string>
#include <utility>
+#include "webrtc/base/optional.h"
+
namespace webrtc {
// SDP specification for a single audio codec.
@@ -25,15 +27,17 @@
SdpAudioFormat(const SdpAudioFormat&);
SdpAudioFormat(SdpAudioFormat&&);
- SdpAudioFormat(const char* name, int clockrate_hz, int num_channels);
- SdpAudioFormat(const std::string& name, int clockrate_hz, int num_channels);
+ SdpAudioFormat(const char* name, int clockrate_hz, size_t num_channels);
+ SdpAudioFormat(const std::string& name,
+ int clockrate_hz,
+ size_t num_channels);
SdpAudioFormat(const char* name,
int clockrate_hz,
- int num_channels,
+ size_t num_channels,
const Parameters& param);
SdpAudioFormat(const std::string& name,
int clockrate_hz,
- int num_channels,
+ size_t num_channels,
const Parameters& param);
~SdpAudioFormat();
@@ -47,35 +51,83 @@
std::string name;
int clockrate_hz;
- int num_channels;
+ size_t num_channels;
Parameters parameters;
};
void swap(SdpAudioFormat& a, SdpAudioFormat& b);
std::ostream& operator<<(std::ostream& os, const SdpAudioFormat& saf);
-// To avoid API breakage, and make the code clearer, AudioCodecSpec should not
+// Information about how an audio format is treated by the codec implementation.
+// Contains basic information, such as sample rate and number of channels, which
+// isn't uniformly presented by SDP. Also contains flags indicating support for
+// integrating with other parts of WebRTC, like external VAD and comfort noise
+// level calculation.
+//
+// To avoid API breakage, and make the code clearer, AudioCodecInfo should not
// be directly initializable with any flags indicating optional support. If it
// were, these initializers would break any time a new flag was added. It's also
// more difficult to understand:
-// AudioCodecSpec spec{{"format", 8000, 1}, true, false, false, true, true};
+// AudioCodecInfo info{16000, 1, 32000, true, false, false, true, true};
// than
-// AudioCodecSpec spec({"format", 8000, 1});
-// spec.allow_comfort_noise = true;
-// spec.future_flag_b = true;
-// spec.future_flag_c = true;
-struct AudioCodecSpec {
- explicit AudioCodecSpec(const SdpAudioFormat& format);
- explicit AudioCodecSpec(SdpAudioFormat&& format);
- ~AudioCodecSpec() = default;
+// AudioCodecInfo info(16000, 1, 32000);
+// info.allow_comfort_noise = true;
+// info.future_flag_b = true;
+// info.future_flag_c = true;
+struct AudioCodecInfo {
+ AudioCodecInfo(int sample_rate_hz, size_t num_channels, int bitrate_bps);
+ AudioCodecInfo(int sample_rate_hz,
+ size_t num_channels,
+ int default_bitrate_bps,
+ int min_bitrate_bps,
+ int max_bitrate_bps);
+ AudioCodecInfo(const AudioCodecInfo& b) = default;
+ ~AudioCodecInfo() = default;
- SdpAudioFormat format;
+ bool operator==(const AudioCodecInfo& b) const {
+ return sample_rate_hz == b.sample_rate_hz &&
+ num_channels == b.num_channels &&
+ default_bitrate_bps == b.default_bitrate_bps &&
+ min_bitrate_bps == b.min_bitrate_bps &&
+ max_bitrate_bps == b.max_bitrate_bps &&
+ allow_comfort_noise == b.allow_comfort_noise &&
+ supports_network_adaption == b.supports_network_adaption;
+ }
+
+ bool operator!=(const AudioCodecInfo& b) const { return !(*this == b); }
+
+ bool HasFixedBitrate() const {
+ RTC_DCHECK_GE(min_bitrate_bps, 0);
+ RTC_DCHECK_LE(min_bitrate_bps, default_bitrate_bps);
+ RTC_DCHECK_GE(max_bitrate_bps, default_bitrate_bps);
+ return min_bitrate_bps == max_bitrate_bps;
+ }
+
+ int sample_rate_hz;
+ size_t num_channels;
+ int default_bitrate_bps;
+ int min_bitrate_bps;
+ int max_bitrate_bps;
+
bool allow_comfort_noise = true; // This codec can be used with an external
// comfort noise generator.
bool supports_network_adaption = false; // This codec can adapt to varying
// network conditions.
};
+// AudioCodecSpec ties an audio format to specific information about the codec
+// and its implementation.
+struct AudioCodecSpec {
+ bool operator==(const AudioCodecSpec& b) const {
+ return format == b.format && info == b.info;
+ }
+
+ bool operator!=(const AudioCodecSpec& b) const { return !(*this == b); }
+
+ SdpAudioFormat format;
+ AudioCodecInfo info;
+};
+
} // namespace webrtc
#endif // WEBRTC_API_AUDIO_CODECS_AUDIO_FORMAT_H_
diff --git a/webrtc/api/peerconnectioninterface.h b/webrtc/api/peerconnectioninterface.h
index e965457..d30834d 100644
--- a/webrtc/api/peerconnectioninterface.h
+++ b/webrtc/api/peerconnectioninterface.h
@@ -91,6 +91,9 @@
#include "webrtc/base/sslstreamadapter.h"
#include "webrtc/media/base/mediachannel.h"
#include "webrtc/media/base/videocapturer.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder_factory.h"
+// TODO(ossu): Remove this once downstream projects have been updated.
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
#include "webrtc/p2p/base/portallocator.h"
namespace rtc {
@@ -986,14 +989,6 @@
~PeerConnectionFactoryInterface() {} // NOLINT
};
-// TODO(ossu): Remove these and define a real builtin audio encoder factory
-// instead.
-class AudioEncoderFactory : public rtc::RefCountInterface {};
-inline rtc::scoped_refptr<AudioEncoderFactory>
-CreateBuiltinAudioEncoderFactory() {
- return nullptr;
-}
-
// Create a new instance of PeerConnectionFactoryInterface.
//
// This method relies on the thread it's called on as the "signaling thread"
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc
index 8fcda89..d3a928b 100644
--- a/webrtc/media/engine/webrtcvoiceengine.cc
+++ b/webrtc/media/engine/webrtcvoiceengine.cc
@@ -1091,12 +1091,12 @@
rtc::Optional<AudioCodec> opt_codec = map_format(spec.format, nullptr);
if (opt_codec) {
AudioCodec& codec = *opt_codec;
- if (spec.supports_network_adaption) {
+ if (spec.info.supports_network_adaption) {
codec.AddFeedbackParam(
FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
}
- if (spec.allow_comfort_noise) {
+ if (spec.info.allow_comfort_noise) {
// Generate a CN entry if the decoder allows it and we support the
// clockrate.
auto cn = generate_cn.find(spec.format.clockrate_hz);
diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
index 44003ec..5da1d8a 100644
--- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc
+++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
@@ -3781,18 +3781,21 @@
TEST(WebRtcVoiceEngineTest, CollectRecvCodecs) {
std::vector<webrtc::AudioCodecSpec> specs;
- webrtc::AudioCodecSpec spec1({"codec1", 48000, 2, {{"param1", "value1"}}});
- spec1.allow_comfort_noise = false;
- spec1.supports_network_adaption = true;
+ webrtc::AudioCodecSpec spec1{{"codec1", 48000, 2, {{"param1", "value1"}}},
+ {48000, 2, 16000, 10000, 20000}};
+ spec1.info.allow_comfort_noise = false;
+ spec1.info.supports_network_adaption = true;
specs.push_back(spec1);
- webrtc::AudioCodecSpec spec2({"codec2", 32000, 1});
- spec2.allow_comfort_noise = false;
+ webrtc::AudioCodecSpec spec2{{"codec2", 32000, 1}, {32000, 1, 32000}};
+ spec2.info.allow_comfort_noise = false;
specs.push_back(spec2);
- specs.push_back(webrtc::AudioCodecSpec({"codec3", 16000, 1,
- {{"param1", "value1b"},
- {"param2", "value2"}}}));
- specs.push_back(webrtc::AudioCodecSpec({"codec4", 8000, 1}));
- specs.push_back(webrtc::AudioCodecSpec({"codec5", 8000, 2}));
+ specs.push_back(webrtc::AudioCodecSpec{
+ {"codec3", 16000, 1, {{"param1", "value1b"}, {"param2", "value2"}}},
+ {16000, 1, 13300}});
+ specs.push_back(
+ webrtc::AudioCodecSpec{{"codec4", 8000, 1}, {8000, 1, 64000}});
+ specs.push_back(
+ webrtc::AudioCodecSpec{{"codec5", 8000, 2}, {8000, 1, 64000}});
rtc::scoped_refptr<webrtc::MockAudioDecoderFactory> mock_factory =
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>;
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index ea3a1b7..5ae3164 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -51,6 +51,33 @@
]
}
+rtc_source_set("audio_encoder_factory_interface") {
+ sources = [
+ "codecs/audio_encoder_factory.h",
+ ]
+ deps = [
+ ":audio_encoder_interface",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../base:rtc_base_approved",
+ ]
+}
+
+rtc_static_library("builtin_audio_encoder_factory") {
+ # TODO(kjellander): Remove (bugs.webrtc.org/6828)
+ # Errors on cyclic dependency with :isac_fix if enabled.
+ check_includes = false
+ sources = [
+ "codecs/builtin_audio_encoder_factory.cc",
+ "codecs/builtin_audio_encoder_factory.h",
+ ]
+ deps = [
+ "../..:webrtc_common",
+ "../../base:rtc_base_approved",
+ ":audio_encoder_factory_interface",
+ ] + audio_codec_deps
+ defines = audio_codec_defines
+}
+
rtc_static_library("builtin_audio_decoder_factory_internal") {
sources = [
"codecs/builtin_audio_decoder_factory_internal.cc",
@@ -491,6 +518,7 @@
deps = [
":audio_encoder_interface",
"../..:webrtc_common",
+ "../../api/audio_codecs:audio_codecs_api",
"../../base:rtc_base_approved",
]
}
@@ -1998,6 +2026,7 @@
"audio_network_adaptor/mock/mock_controller_manager.h",
"audio_network_adaptor/util/threshold_curve_unittest.cc",
"codecs/builtin_audio_decoder_factory_unittest.cc",
+ "codecs/builtin_audio_encoder_factory_unittest.cc",
"codecs/cng/audio_encoder_cng_unittest.cc",
"codecs/cng/cng_unittest.cc",
"codecs/ilbc/ilbc_unittest.cc",
@@ -2065,6 +2094,7 @@
":audio_encoder_interface",
":audio_format_conversion",
":audio_network_adaptor",
+ ":builtin_audio_encoder_factory",
":cng",
":g711",
":ilbc",
diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
index 7515903..98569a6 100644
--- a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
+++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -26,6 +26,7 @@
#include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
#include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h"
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/neteq/audio_decoder_impl.h"
@@ -1266,6 +1267,8 @@
rtc::Md5Digest payload_checksum_;
};
+class AcmSenderBitExactnessNewApi : public AcmSenderBitExactnessOldApi {};
+
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 480, 480));
@@ -1460,8 +1463,10 @@
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
#define MAYBE_Opus_stereo_20ms DISABLED_Opus_stereo_20ms
+#define MAYBE_OpusFromFormat_stereo_20ms DISABLED_OpusFromFormat_stereo_20ms
#else
#define MAYBE_Opus_stereo_20ms Opus_stereo_20ms
+#define MAYBE_OpusFromFormat_stereo_20ms OpusFromFormat_stereo_20ms
#endif
TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960));
@@ -1478,10 +1483,30 @@
50, test::AcmReceiveTestOldApi::kStereoOutput);
}
+TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms) {
+ const SdpAudioFormat kOpusFormat("opus", 48000, 2, {{"stereo", "1"}});
+ AudioEncoderOpus encoder(120, kOpusFormat);
+ ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(&encoder, 120));
+ Run(AcmReceiverBitExactnessOldApi::PlatformChecksum(
+ "855041f2490b887302bce9d544731849",
+ "855041f2490b887302bce9d544731849",
+ "9692eede45638eb425e0daf9c75b5c7a",
+ "86d3552bb3492247f965cdd0e88a1c82"),
+ AcmReceiverBitExactnessOldApi::PlatformChecksum(
+ "d781cce1ab986b618d0da87226cdde30",
+ "d781cce1ab986b618d0da87226cdde30",
+ "8d6782b905c3230d4b0e3e83e1fc3439",
+ "798347a685fac7d0c2d8f748ffe66881"),
+ 50, test::AcmReceiveTestOldApi::kStereoOutput);
+}
+
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
#define MAYBE_Opus_stereo_20ms_voip DISABLED_Opus_stereo_20ms_voip
+#define MAYBE_OpusFromFormat_stereo_20ms_voip \
+ DISABLED_OpusFromFormat_stereo_20ms_voip
#else
#define MAYBE_Opus_stereo_20ms_voip Opus_stereo_20ms_voip
+#define MAYBE_OpusFromFormat_stereo_20ms_voip OpusFromFormat_stereo_20ms_voip
#endif
TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms_voip) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960));
@@ -1500,9 +1525,28 @@
50, test::AcmReceiveTestOldApi::kStereoOutput);
}
+TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms_voip) {
+ const SdpAudioFormat kOpusFormat("opus", 48000, 2, {{"stereo", "1"}});
+ AudioEncoderOpus encoder(120, kOpusFormat);
+ ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder(&encoder, 120));
+ // If not set, default will be kAudio in case of stereo.
+ EXPECT_EQ(0, send_test_->acm()->SetOpusApplication(kVoip));
+ Run(AcmReceiverBitExactnessOldApi::PlatformChecksum(
+ "9b9e12bc3cc793740966e11cbfa8b35b",
+ "9b9e12bc3cc793740966e11cbfa8b35b",
+ "0de6249018fdd316c21086db84e10610",
+ "9c4cb69db77b85841a5f8225bb8f508b"),
+ AcmReceiverBitExactnessOldApi::PlatformChecksum(
+ "c7340b1189652ab6b5e80dade7390cb4",
+ "c7340b1189652ab6b5e80dade7390cb4",
+ "95612864c954ee63e28cc6eebad56626",
+ "ae33ea2e43407cf9ebdabbbd6ca912a3"),
+ 50, test::AcmReceiveTestOldApi::kStereoOutput);
+}
+
// This test is for verifying the SetBitRate function. The bitrate is changed at
// the beginning, and the number of generated bytes are checked.
-class AcmSetBitRateOldApi : public ::testing::Test {
+class AcmSetBitRateTest : public ::testing::Test {
protected:
static const int kTestDurationMs = 1000;
@@ -1532,11 +1576,12 @@
payload_type, frame_size_samples);
}
- // Runs the test. SetUpSender() and RegisterSendCodec() must have been called
- // before calling this method.
- void Run(int target_bitrate_bps, int expected_total_bits) {
- ASSERT_TRUE(send_test_->acm());
- send_test_->acm()->SetBitRate(target_bitrate_bps);
+ bool RegisterExternalSendCodec(AudioEncoder* external_speech_encoder,
+ int payload_type) {
+ return send_test_->RegisterExternalCodec(external_speech_encoder);
+ }
+
+ void RunInner(int expected_total_bits) {
int nr_bytes = 0;
while (std::unique_ptr<test::Packet> next_packet =
send_test_->NextPacket()) {
@@ -1561,10 +1606,31 @@
std::unique_ptr<test::InputAudioFile> audio_source_;
};
+class AcmSetBitRateOldApi : public AcmSetBitRateTest {
+ protected:
+ // Runs the test. SetUpSender() must have been called and a codec must be set
+ // up before calling this method.
+ void Run(int target_bitrate_bps, int expected_total_bits) {
+ ASSERT_TRUE(send_test_->acm());
+ send_test_->acm()->SetBitRate(target_bitrate_bps);
+ RunInner(expected_total_bits);
+ }
+};
+
+class AcmSetBitRateNewApi : public AcmSetBitRateTest {
+ protected:
+ // Runs the test. SetUpSender() must have been called and a codec must be set
+ // up before calling this method.
+ void Run(int expected_total_bits) { RunInner(expected_total_bits); }
+};
+
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
#define MAYBE_Opus_48khz_20ms_10kbps DISABLED_Opus_48khz_20ms_10kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_10kbps \
+ DISABLED_OpusFromFormat_48khz_20ms_10kbps
#else
#define MAYBE_Opus_48khz_20ms_10kbps Opus_48khz_20ms_10kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_10kbps OpusFromFormat_48khz_20ms_10kbps
#endif
TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_10kbps) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
@@ -1575,10 +1641,25 @@
#endif // WEBRTC_ANDROID
}
+TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_10kbps) {
+ AudioEncoderOpus encoder(
+ 107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "10000"}}));
+ ASSERT_TRUE(SetUpSender());
+ ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107));
+#if defined(WEBRTC_ANDROID)
+ RunInner(9288);
+#else
+ RunInner(9024);
+#endif // WEBRTC_ANDROID
+}
+
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
#define MAYBE_Opus_48khz_20ms_50kbps DISABLED_Opus_48khz_20ms_50kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_50kbps \
+ DISABLED_OpusFromFormat_48khz_20ms_50kbps
#else
#define MAYBE_Opus_48khz_20ms_50kbps Opus_48khz_20ms_50kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_50kbps OpusFromFormat_48khz_20ms_50kbps
#endif
TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_50kbps) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
@@ -1589,18 +1670,42 @@
#endif // WEBRTC_ANDROID
}
+TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_50kbps) {
+ AudioEncoderOpus encoder(
+ 107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "50000"}}));
+ ASSERT_TRUE(SetUpSender());
+ ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107));
+#if defined(WEBRTC_ANDROID)
+ RunInner(47960);
+#else
+ RunInner(49544);
+#endif // WEBRTC_ANDROID
+}
+
// The result on the Android platforms is inconsistent for this test case.
// On android_rel the result is different from android and android arm64 rel.
#if defined(WEBRTC_ANDROID) || WEBRTC_OPUS_SUPPORT_120MS_PTIME
#define MAYBE_Opus_48khz_20ms_100kbps DISABLED_Opus_48khz_20ms_100kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_100kbps \
+ DISABLED_OpusFromFormat_48khz_20ms_100kbps
#else
#define MAYBE_Opus_48khz_20ms_100kbps Opus_48khz_20ms_100kbps
+#define MAYBE_OpusFromFormat_48khz_20ms_100kbps \
+ OpusFromFormat_48khz_20ms_100kbps
#endif
TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_100kbps) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
Run(100000, 100888);
}
+TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_100kbps) {
+ AudioEncoderOpus encoder(
+ 107, SdpAudioFormat("opus", 48000, 2, {{"maxaveragebitrate", "100000"}}));
+ ASSERT_TRUE(SetUpSender());
+ ASSERT_TRUE(RegisterExternalSendCodec(&encoder, 107));
+ RunInner(100888);
+}
+
// These next 2 tests ensure that the SetBitRate function has no effect on PCM
TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_8kbps) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder_factory.h b/webrtc/modules/audio_coding/codecs/audio_encoder_factory.h
new file mode 100644
index 0000000..eebb615
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder_factory.h
@@ -0,0 +1,46 @@
+/*
+ * 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_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_FACTORY_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "webrtc/api/audio_codecs/audio_format.h"
+#include "webrtc/base/refcount.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+
+namespace webrtc {
+
+// A factory that creates AudioEncoders.
+// NOTE: This class is still under development and may change without notice.
+class AudioEncoderFactory : public rtc::RefCountInterface {
+ public:
+ // Returns a prioritized list of audio codecs, to use for signaling etc.
+ virtual std::vector<AudioCodecSpec> GetSupportedEncoders() = 0;
+
+ // Returns information about how this format would be encoded, provided it's
+ // supported. More format and format variations may be supported than those
+ // returned by GetSupportedEncoders().
+ virtual rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format) = 0;
+
+ // Creates an AudioEncoder for the specified format. The encoder will tags its
+ // payloads with the specified payload type.
+ // TODO(ossu): Try to avoid audio encoders having to know their payload type.
+ virtual std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+ int payload_type,
+ const SdpAudioFormat& format) = 0;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_FACTORY_H_
diff --git a/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc b/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
index 5a69ae4..a858053 100644
--- a/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
@@ -25,7 +25,7 @@
CodecInst MakeCodecInst(int payload_type,
const char* name,
int sample_rate,
- int num_channels) {
+ size_t num_channels) {
// Create a CodecInst with some fields set. The remaining fields are zeroed,
// but we tell MSan to consider them uninitialized.
CodecInst ci = {0};
@@ -34,7 +34,7 @@
strncpy(ci.plname, name, sizeof(ci.plname));
ci.plname[sizeof(ci.plname) - 1] = '\0';
ci.plfreq = sample_rate;
- ci.channels = rtc::dchecked_cast<size_t>(num_channels);
+ ci.channels = num_channels;
return ci;
}
@@ -44,7 +44,7 @@
if (STR_CASE_CMP(ci.plname, "g722") == 0) {
RTC_CHECK_EQ(16000, ci.plfreq);
RTC_CHECK(ci.channels == 1 || ci.channels == 2);
- return {"g722", 8000, static_cast<int>(ci.channels)};
+ return {"g722", 8000, ci.channels};
} else if (STR_CASE_CMP(ci.plname, "opus") == 0) {
RTC_CHECK_EQ(48000, ci.plfreq);
RTC_CHECK(ci.channels == 1 || ci.channels == 2);
@@ -52,7 +52,7 @@
? SdpAudioFormat("opus", 48000, 2)
: SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}});
} else {
- return {ci.plname, ci.plfreq, rtc::checked_cast<int>(ci.channels)};
+ return {ci.plname, ci.plfreq, ci.channels};
}
}
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 8ec08e4..549fef4 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
@@ -180,30 +180,37 @@
static std::vector<AudioCodecSpec> specs = [] {
std::vector<AudioCodecSpec> specs;
#ifdef WEBRTC_CODEC_OPUS
+ AudioCodecInfo opus_info{48000, 1, 64000, 6000, 510000};
+ opus_info.allow_comfort_noise = false;
+ opus_info.supports_network_adaption = true;
// clang-format off
- AudioCodecSpec opus({"opus", 48000, 2, {
- {"minptime", "10"},
- {"useinbandfec", "1"}
- }});
+ SdpAudioFormat opus_format({"opus", 48000, 2, {
+ {"minptime", "10"},
+ {"useinbandfec", "1"}
+ }});
// clang-format on
- opus.allow_comfort_noise = false;
- opus.supports_network_adaption = true;
- specs.push_back(opus);
+ specs.push_back({std::move(opus_format), opus_info});
#endif
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
- specs.push_back(AudioCodecSpec({"isac", 16000, 1}));
+ specs.push_back(AudioCodecSpec{{"isac", 16000, 1},
+ {16000, 1, 32000, 10000, 56000}});
#endif
#if (defined(WEBRTC_CODEC_ISAC))
- specs.push_back(AudioCodecSpec({"isac", 32000, 1}));
+ specs.push_back(AudioCodecSpec{{"isac", 32000, 1},
+ {32000, 1, 56000, 10000, 56000}});
#endif
#ifdef WEBRTC_CODEC_G722
- specs.push_back(AudioCodecSpec({"G722", 8000, 1}));
+ specs.push_back(AudioCodecSpec{{"G722", 8000, 1},
+ {16000, 1, 64000}});
#endif
#ifdef WEBRTC_CODEC_ILBC
- specs.push_back(AudioCodecSpec({"iLBC", 8000, 1}));
+ specs.push_back(AudioCodecSpec{{"iLBC", 8000, 1},
+ {8000, 1, 13300}});
#endif
- specs.push_back(AudioCodecSpec({"PCMU", 8000, 1}));
- specs.push_back(AudioCodecSpec({"PCMA", 8000, 1}));
+ specs.push_back(AudioCodecSpec{{"PCMU", 8000, 1},
+ {8000, 1, 64000}});
+ specs.push_back(AudioCodecSpec{{"PCMA", 8000, 1},
+ {8000, 1, 64000}});
return specs;
}();
return specs;
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.cc
new file mode 100644
index 0000000..54345fd
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.cc
@@ -0,0 +1,143 @@
+/*
+ * 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/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
+
+#include <memory>
+#include <vector>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/optional.h"
+#include "webrtc/common_types.h"
+#include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
+#ifdef WEBRTC_CODEC_G722
+#include "webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h"
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+#include "webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h"
+#endif
+#ifdef WEBRTC_CODEC_ISACFX
+#include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h"
+#endif
+#ifdef WEBRTC_CODEC_ISAC
+#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
+#endif
+#include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
+
+namespace webrtc {
+
+namespace {
+
+struct NamedEncoderFactory {
+ const char* name;
+ rtc::Optional<AudioCodecInfo> (*QueryAudioEncoder)(
+ const SdpAudioFormat& format);
+ std::unique_ptr<AudioEncoder> (
+ *MakeAudioEncoder)(int payload_type, const SdpAudioFormat& format);
+
+ template <typename T>
+ static NamedEncoderFactory ForEncoder() {
+ auto constructor = [](int payload_type, const SdpAudioFormat& format) {
+ auto opt_info = T::QueryAudioEncoder(format);
+ if (opt_info) {
+ return std::unique_ptr<AudioEncoder>(new T(payload_type, format));
+ }
+ return std::unique_ptr<AudioEncoder>();
+ };
+
+ return {T::GetPayloadName(), T::QueryAudioEncoder, constructor};
+ }
+};
+
+NamedEncoderFactory encoder_factories[] = {
+#ifdef WEBRTC_CODEC_G722
+ NamedEncoderFactory::ForEncoder<AudioEncoderG722>(),
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+ NamedEncoderFactory::ForEncoder<AudioEncoderIlbc>(),
+#endif
+#if defined(WEBRTC_CODEC_ISACFX)
+ NamedEncoderFactory::ForEncoder<AudioEncoderIsacFix>(),
+#elif defined(WEBRTC_CODEC_ISAC)
+ NamedEncoderFactory::ForEncoder<AudioEncoderIsac>(),
+#endif
+
+#ifdef WEBRTC_CODEC_OPUS
+ NamedEncoderFactory::ForEncoder<AudioEncoderOpus>(),
+#endif
+ NamedEncoderFactory::ForEncoder<AudioEncoderPcm16B>(),
+ NamedEncoderFactory::ForEncoder<AudioEncoderPcmA>(),
+ NamedEncoderFactory::ForEncoder<AudioEncoderPcmU>(),
+};
+} // namespace
+
+class BuiltinAudioEncoderFactory : public AudioEncoderFactory {
+ public:
+ std::vector<AudioCodecSpec> GetSupportedEncoders() override {
+ static const SdpAudioFormat desired_encoders[] = {
+ {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
+ {"isac", 16000, 1},
+ {"isac", 32000, 1},
+ {"G722", 8000, 1},
+ {"iLBC", 8000, 1},
+ {"PCMU", 8000, 1},
+ {"PCMA", 8000, 1},
+ };
+
+ // Initialize thread-safely, once, on first use.
+ static const std::vector<AudioCodecSpec> specs = [] {
+ std::vector<AudioCodecSpec> specs;
+ for (const auto& format : desired_encoders) {
+ for (const auto& ef : encoder_factories) {
+ if (STR_CASE_CMP(format.name.c_str(), ef.name) == 0) {
+ auto opt_info = ef.QueryAudioEncoder(format);
+ if (opt_info) {
+ specs.push_back({format, *opt_info});
+ }
+ }
+ }
+ }
+ return specs;
+ }();
+ return specs;
+ }
+
+ rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format) override {
+ for (const auto& ef : encoder_factories) {
+ if (STR_CASE_CMP(format.name.c_str(), ef.name) == 0) {
+ return ef.QueryAudioEncoder(format);
+ }
+ }
+ return rtc::Optional<AudioCodecInfo>();
+ }
+
+ std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+ int payload_type,
+ const SdpAudioFormat& format) override {
+ for (const auto& ef : encoder_factories) {
+ if (STR_CASE_CMP(format.name.c_str(), ef.name) == 0) {
+ return ef.MakeAudioEncoder(payload_type, format);
+ }
+ }
+ return nullptr;
+ }
+};
+
+rtc::scoped_refptr<AudioEncoderFactory> CreateBuiltinAudioEncoderFactory() {
+ return rtc::scoped_refptr<AudioEncoderFactory>(
+ new rtc::RefCountedObject<BuiltinAudioEncoderFactory>());
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h
new file mode 100644
index 0000000..150a76c
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h
@@ -0,0 +1,25 @@
+/*
+ * 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_MODULES_AUDIO_CODING_CODECS_BUILTIN_AUDIO_ENCODER_FACTORY_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_BUILTIN_AUDIO_ENCODER_FACTORY_H_
+
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/modules/audio_coding/codecs/audio_encoder_factory.h"
+
+namespace webrtc {
+
+// Creates a new factory that can create the built-in types of audio encoders.
+// NOTE: This function is still under development and may change without notice.
+rtc::scoped_refptr<AudioEncoderFactory> CreateBuiltinAudioEncoderFactory();
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_BUILTIN_AUDIO_ENCODER_FACTORY_H_
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
new file mode 100644
index 0000000..0d3ce52
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
@@ -0,0 +1,145 @@
+/*
+ * 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 <limits>
+#include <memory>
+#include <vector>
+
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
+#include "webrtc/test/gmock.h"
+#include "webrtc/test/gtest.h"
+
+namespace webrtc {
+
+class AudioEncoderFactoryTest
+ : public ::testing::TestWithParam<rtc::scoped_refptr<AudioEncoderFactory>> {
+};
+
+TEST_P(AudioEncoderFactoryTest, SupportsAtLeastOneFormat) {
+ auto factory = GetParam();
+ auto supported_encoders = factory->GetSupportedEncoders();
+ EXPECT_FALSE(supported_encoders.empty());
+}
+
+TEST_P(AudioEncoderFactoryTest, CanQueryAllSupportedFormats) {
+ auto factory = GetParam();
+ auto supported_encoders = factory->GetSupportedEncoders();
+ for (const auto& spec : supported_encoders) {
+ auto info = factory->QueryAudioEncoder(spec.format);
+ EXPECT_TRUE(info);
+ }
+}
+
+TEST_P(AudioEncoderFactoryTest, CanConstructAllSupportedEncoders) {
+ auto factory = GetParam();
+ auto supported_encoders = factory->GetSupportedEncoders();
+ for (const auto& spec : supported_encoders) {
+ auto info = factory->QueryAudioEncoder(spec.format);
+ auto encoder = factory->MakeAudioEncoder(127, spec.format);
+ EXPECT_TRUE(encoder);
+ EXPECT_EQ(encoder->SampleRateHz(), info->sample_rate_hz);
+ EXPECT_EQ(encoder->NumChannels(), info->num_channels);
+ EXPECT_EQ(encoder->RtpTimestampRateHz(), spec.format.clockrate_hz);
+ }
+}
+
+TEST_P(AudioEncoderFactoryTest, CanRunAllSupportedEncoders) {
+ constexpr int kTestPayloadType = 127;
+ auto factory = GetParam();
+ auto supported_encoders = factory->GetSupportedEncoders();
+ for (const auto& spec : supported_encoders) {
+ auto encoder = factory->MakeAudioEncoder(kTestPayloadType, spec.format);
+ EXPECT_TRUE(encoder);
+ encoder->Reset();
+ const int num_samples =
+ encoder->SampleRateHz() * encoder->NumChannels() / 100;
+ rtc::Buffer out;
+ rtc::BufferT<int16_t> audio;
+ audio.SetData(num_samples, [](rtc::ArrayView<int16_t> audio) {
+ for (size_t i = 0; i != audio.size(); ++i) {
+ // Just put some numbers in there, ensure they're within range.
+ audio[i] =
+ static_cast<int16_t>(i & std::numeric_limits<int16_t>::max());
+ }
+ return audio.size();
+ });
+ // This is here to stop the test going forever with a broken encoder.
+ constexpr int kMaxEncodeCalls = 100;
+ int blocks = 0;
+ for (; blocks < kMaxEncodeCalls; ++blocks) {
+ AudioEncoder::EncodedInfo info = encoder->Encode(
+ blocks * encoder->RtpTimestampRateHz() / 100, audio, &out);
+ EXPECT_EQ(info.encoded_bytes, out.size());
+ if (info.encoded_bytes > 0) {
+ EXPECT_EQ(0u, info.encoded_timestamp);
+ EXPECT_EQ(kTestPayloadType, info.payload_type);
+ break;
+ }
+ }
+ ASSERT_LT(blocks, kMaxEncodeCalls);
+ const unsigned int next_timestamp =
+ blocks * encoder->RtpTimestampRateHz() / 100;
+ out.Clear();
+ for (; blocks < kMaxEncodeCalls; ++blocks) {
+ AudioEncoder::EncodedInfo info = encoder->Encode(
+ blocks * encoder->RtpTimestampRateHz() / 100, audio, &out);
+ EXPECT_EQ(info.encoded_bytes, out.size());
+ if (info.encoded_bytes > 0) {
+ EXPECT_EQ(next_timestamp, info.encoded_timestamp);
+ EXPECT_EQ(kTestPayloadType, info.payload_type);
+ break;
+ }
+ }
+ ASSERT_LT(blocks, kMaxEncodeCalls);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(BuiltinAudioEncoderFactoryTest,
+ AudioEncoderFactoryTest,
+ ::testing::Values(CreateBuiltinAudioEncoderFactory()));
+
+TEST(BuiltinAudioEncoderFactoryTest, SupportsTheExpectedFormats) {
+ using ::testing::ElementsAreArray;
+ // Check that we claim to support the formats we expect from build flags, and
+ // we've ordered them correctly.
+ auto factory = CreateBuiltinAudioEncoderFactory();
+ auto specs = factory->GetSupportedEncoders();
+
+ const std::vector<SdpAudioFormat> supported_formats = [&specs] {
+ std::vector<SdpAudioFormat> formats;
+ for (const auto& spec : specs) {
+ formats.push_back(spec.format);
+ }
+ return formats;
+ }();
+
+ const std::vector<SdpAudioFormat> expected_formats = {
+#ifdef WEBRTC_CODEC_OPUS
+ {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
+#endif
+#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
+ {"isac", 16000, 1},
+#endif
+#ifdef WEBRTC_CODEC_ISAC
+ {"isac", 32000, 1},
+#endif
+#ifdef WEBRTC_CODEC_G722
+ {"G722", 8000, 1},
+#endif
+#ifdef WEBRTC_CODEC_ILBC
+ {"ilbc", 8000, 1},
+#endif
+ {"pcmu", 8000, 1},
+ {"pcma", 8000, 1}
+ };
+
+ ASSERT_THAT(supported_formats, ElementsAreArray(expected_formats));
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
index baa5d38..113fb63 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -10,9 +10,11 @@
#include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
+#include <algorithm>
#include <limits>
#include "webrtc/base/checks.h"
+#include "webrtc/base/string_to_number.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/codecs/g711/g711_interface.h"
@@ -29,6 +31,35 @@
return config;
}
+template <typename T>
+typename T::Config CreateConfig(int payload_type,
+ const SdpAudioFormat& format) {
+ typename T::Config config;
+ config.frame_size_ms = 20;
+ 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(10, std::min(whole_packets * 10, 60));
+ }
+ }
+ config.num_channels = format.num_channels;
+ config.payload_type = payload_type;
+ return config;
+}
+
+template <typename T>
+rtc::Optional<AudioCodecInfo> QueryAudioEncoderImpl(
+ const SdpAudioFormat& format) {
+ if (STR_CASE_CMP(format.name.c_str(), T::GetPayloadName()) == 0 &&
+ format.clockrate_hz == 8000 && format.num_channels >= 1 &&
+ CreateConfig<T>(0, format).IsOk()) {
+ return rtc::Optional<AudioCodecInfo>({8000, format.num_channels, 64000});
+ }
+ return rtc::Optional<AudioCodecInfo>();
+}
+
} // namespace
bool AudioEncoderPcm::Config::IsOk() const {
@@ -107,6 +138,15 @@
AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst)
: AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(codec_inst)) {}
+AudioEncoderPcmA::AudioEncoderPcmA(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderPcmA::QueryAudioEncoder(
+ const SdpAudioFormat& format) {
+ return QueryAudioEncoderImpl<AudioEncoderPcmA>(format);
+}
+
size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio,
size_t input_len,
uint8_t* encoded) {
@@ -124,6 +164,15 @@
AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst)
: AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(codec_inst)) {}
+AudioEncoderPcmU::AudioEncoderPcmU(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderPcmU::QueryAudioEncoder(
+ const SdpAudioFormat& format) {
+ return QueryAudioEncoderImpl<AudioEncoderPcmU>(format);
+}
+
size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio,
size_t input_len,
uint8_t* encoded) {
diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
index 7213445..a98d2da 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
@@ -13,6 +13,7 @@
#include <vector>
+#include "webrtc/api/audio_codecs/audio_format.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
@@ -80,6 +81,11 @@
explicit AudioEncoderPcmA(const Config& config)
: AudioEncoderPcm(config, kSampleRateHz) {}
explicit AudioEncoderPcmA(const CodecInst& codec_inst);
+ AudioEncoderPcmA(int payload_type, const SdpAudioFormat& format);
+
+ static constexpr const char* GetPayloadName() { return "pcma"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
protected:
size_t EncodeCall(const int16_t* audio,
@@ -104,6 +110,11 @@
explicit AudioEncoderPcmU(const Config& config)
: AudioEncoderPcm(config, kSampleRateHz) {}
explicit AudioEncoderPcmU(const CodecInst& codec_inst);
+ AudioEncoderPcmU(int payload_type, const SdpAudioFormat& format);
+
+ static constexpr const char* GetPayloadName() { return "pcmu"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
protected:
size_t EncodeCall(const int16_t* audio,
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 1f3936c..d5cf616 100644
--- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
+++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -10,8 +10,12 @@
#include "webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h"
+#include <algorithm>
+
#include <limits>
#include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/codecs/g722/g722_interface.h"
@@ -29,6 +33,22 @@
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;
+ 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(10, std::min(whole_packets * 10, 60));
+ }
+ }
+ return config;
+}
+
} // namespace
bool AudioEncoderG722::Config::IsOk() const {
@@ -58,8 +78,24 @@
AudioEncoderG722::AudioEncoderG722(const CodecInst& codec_inst)
: AudioEncoderG722(CreateConfig(codec_inst)) {}
+AudioEncoderG722::AudioEncoderG722(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderG722(CreateConfig(payload_type, format)) {}
+
AudioEncoderG722::~AudioEncoderG722() = default;
+rtc::Optional<AudioCodecInfo> AudioEncoderG722::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()) {
+ return rtc::Optional<AudioCodecInfo>(
+ {rtc::dchecked_cast<int>(kSampleRateHz), config.num_channels, 64000});
+ }
+ }
+ return rtc::Optional<AudioCodecInfo>();
+}
+
int AudioEncoderG722::SampleRateHz() const {
return kSampleRateHz;
}
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 ad49a86..cc3e7e5 100644
--- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h
+++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.h
@@ -13,6 +13,7 @@
#include <memory>
+#include "webrtc/api/audio_codecs/audio_format.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
@@ -34,8 +35,13 @@
explicit AudioEncoderG722(const Config& config);
explicit AudioEncoderG722(const CodecInst& codec_inst);
+ AudioEncoderG722(int payload_type, const SdpAudioFormat& format);
~AudioEncoderG722() override;
+ static constexpr const char* GetPayloadName() { return "G722"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
+
int SampleRateHz() const override;
size_t NumChannels() const override;
int RtpTimestampRateHz() const override;
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 ca11587..6ed445a 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
+++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -13,6 +13,8 @@
#include <algorithm>
#include <limits>
#include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/codecs/ilbc/ilbc.h"
@@ -29,6 +31,34 @@
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:
+ // 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
// static
@@ -52,6 +82,24 @@
AudioEncoderIlbc::AudioEncoderIlbc(const CodecInst& codec_inst)
: AudioEncoderIlbc(CreateConfig(codec_inst)) {}
+AudioEncoderIlbc::AudioEncoderIlbc(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderIlbc(CreateConfig(payload_type, format)) {}
+
+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() {
RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
}
@@ -73,16 +121,8 @@
}
int AudioEncoderIlbc::GetTargetBitrate() const {
- switch (num_10ms_frames_per_packet_) {
- case 2: case 4:
- // 38 bytes per frame of 20 ms => 15200 bits/s.
- return 15200;
- case 3: case 6:
- // 50 bytes per frame of 30 ms => (approx) 13333 bits/s.
- return 13333;
- default:
- FATAL();
- }
+ return GetIlbcBitrate(rtc::dchecked_cast<int>(num_10ms_frames_per_packet_) *
+ 10);
}
AudioEncoder::EncodedInfo AudioEncoderIlbc::EncodeImpl(
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 6363986..467caee 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
@@ -11,6 +11,7 @@
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ILBC_AUDIO_ENCODER_ILBC_H_
+#include "webrtc/api/audio_codecs/audio_format.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
#include "webrtc/modules/audio_coding/codecs/ilbc/ilbc.h"
@@ -32,8 +33,13 @@
explicit AudioEncoderIlbc(const Config& config);
explicit AudioEncoderIlbc(const CodecInst& codec_inst);
+ AudioEncoderIlbc(int payload_type, const SdpAudioFormat& format);
~AudioEncoderIlbc() override;
+ static constexpr const char* GetPayloadName() { return "ilbc"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
+
int SampleRateHz() const override;
size_t NumChannels() const override;
size_t Num10MsFramesInNextPacket() const override;
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
index f1f2714..64d6384 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -13,6 +13,7 @@
#include <vector>
+#include "webrtc/api/audio_codecs/audio_format.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
@@ -55,8 +56,13 @@
explicit AudioEncoderIsacT(
const CodecInst& codec_inst,
const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo);
+ AudioEncoderIsacT(int payload_type, const SdpAudioFormat& format);
~AudioEncoderIsacT() override;
+ static constexpr const char* GetPayloadName() { return "isac"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
+
int SampleRateHz() const override;
size_t NumChannels() const override;
size_t Num10MsFramesInNextPacket() const override;
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
index e4d58ae..ebe4d6a 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -12,9 +12,15 @@
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
#include "webrtc/base/checks.h"
+#include "webrtc/base/string_to_number.h"
#include "webrtc/common_types.h"
namespace webrtc {
+namespace { // NOLINT (not a "regular" header file)
+int GetIsacMaxBitrate(int clockrate_hz) {
+ return (clockrate_hz == 32000) ? 56000 : 32000;
+}
+} // namespace
template <typename T>
typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
@@ -33,6 +39,33 @@
}
template <typename T>
+typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
+ int payload_type,
+ const SdpAudioFormat& format) {
+ typename AudioEncoderIsacT<T>::Config config;
+ config.payload_type = payload_type;
+ config.sample_rate_hz = format.clockrate_hz;
+
+ // We only support different frame sizes at 16000 Hz.
+ if (config.sample_rate_hz == 16000) {
+ auto ptime_iter = format.parameters.find("ptime");
+ if (ptime_iter != format.parameters.end()) {
+ auto ptime = rtc::StringToNumber<int>(ptime_iter->second);
+ if (ptime && *ptime >= 60) {
+ config.frame_size_ms = 60;
+ } else {
+ config.frame_size_ms = 30;
+ }
+ }
+ }
+
+ // Set the default bitrate for ISAC to the maximum bitrate allowed at this
+ // clockrate. At this point, adaptive mode is not used by WebRTC.
+ config.bit_rate = GetIsacMaxBitrate(format.clockrate_hz);
+ return config;
+}
+
+template <typename T>
bool AudioEncoderIsacT<T>::Config::IsOk() const {
if (max_bit_rate < 32000 && max_bit_rate != -1)
return false;
@@ -73,6 +106,25 @@
: AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
template <typename T>
+AudioEncoderIsacT<T>::AudioEncoderIsacT(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderIsacT(CreateIsacConfig<T>(payload_type, format)) {}
+
+template <typename T>
+rtc::Optional<AudioCodecInfo> AudioEncoderIsacT<T>::QueryAudioEncoder(
+ const SdpAudioFormat& format) {
+ if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0) {
+ Config config = CreateIsacConfig<T>(0, format);
+ if (config.IsOk()) {
+ return rtc::Optional<AudioCodecInfo>(
+ {config.sample_rate_hz, 1, config.bit_rate, 10000,
+ GetIsacMaxBitrate(format.clockrate_hz)});
+ }
+ }
+ return rtc::Optional<AudioCodecInfo>();
+}
+
+template <typename T>
AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
RTC_CHECK_EQ(0, T::Free(isac_state_));
}
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index 103ec9b..aaf2647 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -12,11 +12,14 @@
#include <algorithm>
#include <iterator>
+#include <utility>
+#include "webrtc/base/arraysize.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/numerics/exp_filter.h"
#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h"
@@ -28,39 +31,42 @@
namespace {
-constexpr int kSampleRateHz = 48000;
+// Codec parameters for Opus.
+// draft-spittka-payload-rtp-opus-03
+
+// Recommended bitrates:
+// 8-12 kb/s for NB speech,
+// 16-20 kb/s for WB speech,
+// 28-40 kb/s for FB speech,
+// 48-64 kb/s for FB mono music, and
+// 64-128 kb/s for FB stereo music.
+// The current implementation applies the following values to mono signals,
+// and multiplies them by 2 for stereo.
+constexpr int kOpusBitrateNbBps = 12000;
+constexpr int kOpusBitrateWbBps = 20000;
+constexpr int kOpusBitrateFbBps = 32000;
// Opus API allows a min bitrate of 500bps, but Opus documentation suggests
-// a minimum bitrate of 6kbps.
-constexpr int kMinBitrateBps = 6000;
+// bitrate should be in the range of 6000 to 510000, inclusive.
+constexpr int kOpusMinBitrateBps = 6000;
+constexpr int kOpusMaxBitrateBps = 510000;
-constexpr int kMaxBitrateBps = 512000;
+constexpr int kSampleRateHz = 48000;
+constexpr int kDefaultMaxPlaybackRate = 48000;
+// These two lists must be sorted from low to high
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
-constexpr int kSupportedFrameLengths[] = {20, 60, 120};
+constexpr int kANASupportedFrameLengths[] = {20, 60, 120};
+constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60, 120};
#else
-constexpr int kSupportedFrameLengths[] = {20, 60};
+constexpr int kANASupportedFrameLengths[] = {20, 60};
+constexpr int kOpusSupportedFrameLengths[] = {10, 20, 40, 60};
#endif
// PacketLossFractionSmoother uses an exponential filter with a time constant
// of -1.0 / ln(0.9999) = 10000 ms.
constexpr float kAlphaForPacketLossFractionSmoother = 0.9999f;
-AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) {
- AudioEncoderOpus::Config config;
- config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
- config.num_channels = codec_inst.channels;
- config.bitrate_bps = rtc::Optional<int>(codec_inst.rate);
- config.payload_type = codec_inst.pltype;
- config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
- : AudioEncoderOpus::kAudio;
- config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
-#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
- config.low_rate_complexity = 9;
-#endif
- return config;
-}
-
// Optimize the loss rate to configure Opus. Basically, optimized loss rate is
// the input loss rate rounded down to various levels, because a robustly good
// audio quality is achieved by lowering the packet loss down.
@@ -101,8 +107,180 @@
}
}
+rtc::Optional<std::string> GetFormatParameter(const SdpAudioFormat& format,
+ const std::string& param) {
+ auto it = format.parameters.find(param);
+ return (it == format.parameters.end())
+ ? rtc::Optional<std::string>()
+ : rtc::Optional<std::string>(it->second);
+}
+
+template <typename T>
+rtc::Optional<T> GetFormatParameter(const SdpAudioFormat& format,
+ const std::string& param) {
+ return rtc::StringToNumber<T>(GetFormatParameter(format, param).value_or(""));
+}
+
+int CalculateDefaultBitrate(int max_playback_rate, size_t num_channels) {
+ const int bitrate = [&] {
+ if (max_playback_rate <= 8000) {
+ return kOpusBitrateNbBps * rtc::dchecked_cast<int>(num_channels);
+ } else if (max_playback_rate <= 16000) {
+ return kOpusBitrateWbBps * rtc::dchecked_cast<int>(num_channels);
+ } else {
+ return kOpusBitrateFbBps * rtc::dchecked_cast<int>(num_channels);
+ }
+ }();
+ RTC_DCHECK_GE(bitrate, kOpusMinBitrateBps);
+ RTC_DCHECK_LE(bitrate, kOpusMaxBitrateBps);
+ return bitrate;
+}
+
+// Get the maxaveragebitrate parameter in string-form, so we can properly figure
+// out how invalid it is and accurately log invalid values.
+int CalculateBitrate(int max_playback_rate_hz,
+ size_t num_channels,
+ rtc::Optional<std::string> bitrate_param) {
+ const int default_bitrate =
+ CalculateDefaultBitrate(max_playback_rate_hz, num_channels);
+
+ if (bitrate_param) {
+ const auto bitrate = rtc::StringToNumber<int>(*bitrate_param);
+ if (bitrate) {
+ const int chosen_bitrate =
+ std::max(kOpusMinBitrateBps, std::min(*bitrate, kOpusMaxBitrateBps));
+ if (bitrate != chosen_bitrate) {
+ LOG(LS_WARNING) << "Invalid maxaveragebitrate " << *bitrate
+ << " clamped to " << chosen_bitrate;
+ }
+ return chosen_bitrate;
+ }
+ LOG(LS_WARNING) << "Invalid maxaveragebitrate \"" << *bitrate_param
+ << "\" replaced by default bitrate " << default_bitrate;
+ }
+
+ return default_bitrate;
+}
+
+int GetChannelCount(const SdpAudioFormat& format) {
+ const auto param = GetFormatParameter(format, "stereo");
+ if (param == "1") {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+int GetMaxPlaybackRate(const SdpAudioFormat& format) {
+ const auto param = GetFormatParameter<int>(format, "maxplaybackrate");
+ if (param && *param >= 8000) {
+ return std::min(*param, kDefaultMaxPlaybackRate);
+ }
+ return kDefaultMaxPlaybackRate;
+}
+
+int GetFrameSizeMs(const SdpAudioFormat& format) {
+ const auto ptime = GetFormatParameter<int>(format, "ptime");
+ if (ptime) {
+ // Pick the next highest supported frame length from
+ // kOpusSupportedFrameLengths.
+ for (const int supported_frame_length : kOpusSupportedFrameLengths) {
+ if (supported_frame_length >= *ptime) {
+ return supported_frame_length;
+ }
+ }
+ // If none was found, return the largest supported frame length.
+ return *(std::end(kOpusSupportedFrameLengths) - 1);
+ }
+
+ return AudioEncoderOpus::Config::kDefaultFrameSizeMs;
+}
+
+void FindSupportedFrameLengths(int min_frame_length_ms,
+ int max_frame_length_ms,
+ std::vector<int>* out) {
+ out->clear();
+ std::copy_if(std::begin(kANASupportedFrameLengths),
+ std::end(kANASupportedFrameLengths), std::back_inserter(*out),
+ [&](int frame_length_ms) {
+ return frame_length_ms >= min_frame_length_ms &&
+ frame_length_ms <= max_frame_length_ms;
+ });
+ RTC_DCHECK(std::is_sorted(out->begin(), out->end()));
+}
+
} // namespace
+rtc::Optional<AudioCodecInfo> AudioEncoderOpus::QueryAudioEncoder(
+ const SdpAudioFormat& format) {
+ if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
+ format.clockrate_hz == 48000 && format.num_channels == 2) {
+ const size_t num_channels = GetChannelCount(format);
+ const int bitrate =
+ CalculateBitrate(GetMaxPlaybackRate(format), num_channels,
+ GetFormatParameter(format, "maxaveragebitrate"));
+ AudioCodecInfo info(48000, num_channels, bitrate, kOpusMinBitrateBps,
+ kOpusMaxBitrateBps);
+ info.allow_comfort_noise = false;
+ info.supports_network_adaption = true;
+
+ return rtc::Optional<AudioCodecInfo>(info);
+ }
+ return rtc::Optional<AudioCodecInfo>();
+}
+
+AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig(
+ const CodecInst& codec_inst) {
+ AudioEncoderOpus::Config config;
+ config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48);
+ config.num_channels = codec_inst.channels;
+ config.bitrate_bps = rtc::Optional<int>(codec_inst.rate);
+ config.payload_type = codec_inst.pltype;
+ config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
+ : AudioEncoderOpus::kAudio;
+ config.supported_frame_lengths_ms.push_back(config.frame_size_ms);
+#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
+ config.low_rate_complexity = 9;
+#endif
+ return config;
+}
+
+AudioEncoderOpus::Config AudioEncoderOpus::CreateConfig(
+ int payload_type,
+ const SdpAudioFormat& format) {
+ AudioEncoderOpus::Config config;
+
+ config.num_channels = GetChannelCount(format);
+ config.frame_size_ms = GetFrameSizeMs(format);
+ config.max_playback_rate_hz = GetMaxPlaybackRate(format);
+ config.fec_enabled = (GetFormatParameter(format, "useinbandfec") == "1");
+ config.dtx_enabled = (GetFormatParameter(format, "usedtx") == "1");
+ config.bitrate_bps = rtc::Optional<int>(
+ CalculateBitrate(config.max_playback_rate_hz, config.num_channels,
+ GetFormatParameter(format, "maxaveragebitrate")));
+ config.payload_type = payload_type;
+ config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip
+ : AudioEncoderOpus::kAudio;
+#if WEBRTC_OPUS_VARIABLE_COMPLEXITY
+ config.low_rate_complexity = 9;
+#endif
+
+ constexpr int kMinANAFrameLength = kANASupportedFrameLengths[0];
+ constexpr int kMaxANAFrameLength =
+ kANASupportedFrameLengths[arraysize(kANASupportedFrameLengths) - 1];
+ // For now, minptime and maxptime are only used with ANA. If ptime is outside
+ // of this range, it will get adjusted once ANA takes hold. Ideally, we'd know
+ // if ANA was to be used when setting up the config, and adjust accordingly.
+ const int min_frame_length_ms =
+ GetFormatParameter<int>(format, "minptime").value_or(kMinANAFrameLength);
+ const int max_frame_length_ms =
+ GetFormatParameter<int>(format, "maxptime").value_or(kMaxANAFrameLength);
+
+ FindSupportedFrameLengths(min_frame_length_ms, max_frame_length_ms,
+ &config.supported_frame_lengths_ms);
+ return config;
+}
+
class AudioEncoderOpus::PacketLossFractionSmoother {
public:
explicit PacketLossFractionSmoother(const Clock* clock)
@@ -147,7 +325,7 @@
if (num_channels != 1 && num_channels != 2)
return false;
if (bitrate_bps &&
- (*bitrate_bps < kMinBitrateBps || *bitrate_bps > kMaxBitrateBps))
+ (*bitrate_bps < kOpusMinBitrateBps || *bitrate_bps > kOpusMaxBitrateBps))
return false;
if (complexity < 0 || complexity > 10)
return false;
@@ -208,6 +386,10 @@
AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst)
: AudioEncoderOpus(CreateConfig(codec_inst), nullptr) {}
+AudioEncoderOpus::AudioEncoderOpus(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderOpus(CreateConfig(payload_type, format), nullptr) {}
+
AudioEncoderOpus::~AudioEncoderOpus() {
RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_));
}
@@ -344,8 +526,8 @@
const int overhead_bps = static_cast<int>(
*overhead_bytes_per_packet_ * 8 * 100 / Num10MsFramesInNextPacket());
SetTargetBitrate(std::min(
- kMaxBitrateBps,
- std::max(kMinBitrateBps, target_audio_bitrate_bps - overhead_bps)));
+ kOpusMaxBitrateBps,
+ std::max(kOpusMinBitrateBps, target_audio_bitrate_bps - overhead_bps)));
} else {
SetTargetBitrate(target_audio_bitrate_bps);
}
@@ -374,17 +556,8 @@
// |EnableAudioNetworkAdaptor|, otherwise we need to recreate
// |audio_network_adaptor_|, which is not a needed use case.
RTC_DCHECK(!audio_network_adaptor_);
-
- config_.supported_frame_lengths_ms.clear();
- std::copy_if(std::begin(kSupportedFrameLengths),
- std::end(kSupportedFrameLengths),
- std::back_inserter(config_.supported_frame_lengths_ms),
- [&](int frame_length_ms) {
- return frame_length_ms >= min_frame_length_ms &&
- frame_length_ms <= max_frame_length_ms;
- });
- RTC_DCHECK(std::is_sorted(config_.supported_frame_lengths_ms.begin(),
- config_.supported_frame_lengths_ms.end()));
+ FindSupportedFrameLengths(min_frame_length_ms, max_frame_length_ms,
+ &config_.supported_frame_lengths_ms);
}
AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl(
@@ -516,8 +689,8 @@
}
void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
- config_.bitrate_bps = rtc::Optional<int>(
- std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps));
+ config_.bitrate_bps = rtc::Optional<int>(std::max(
+ std::min(bits_per_second, kOpusMaxBitrateBps), kOpusMinBitrateBps));
RTC_DCHECK(config_.IsOk());
RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps()));
const auto new_complexity = config_.GetNewComplexity();
@@ -558,7 +731,7 @@
config,
ControllerManagerImpl::Create(
config_string, NumChannels(), supported_frame_lengths_ms(),
- kMinBitrateBps, num_channels_to_encode_, next_frame_length_ms_,
+ kOpusMinBitrateBps, num_channels_to_encode_, next_frame_length_ms_,
GetTargetBitrate(), config_.fec_enabled, GetDtx(), clock)));
}
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
index 8f5bba6..3d3597b 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -16,12 +16,13 @@
#include <string>
#include <vector>
+#include "webrtc/api/audio_codecs/audio_format.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/optional.h"
#include "webrtc/common_audio/smoothing_filter.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
-#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
namespace webrtc {
@@ -50,7 +51,8 @@
// current bitrate is above or below complexity_threshold_bps.
rtc::Optional<int> GetNewComplexity() const;
- int frame_size_ms = 20;
+ static constexpr int kDefaultFrameSizeMs = 20;
+ int frame_size_ms = kDefaultFrameSizeMs;
size_t num_channels = 1;
int payload_type = 120;
ApplicationMode application = kVoip;
@@ -79,6 +81,9 @@
#endif
};
+ static Config CreateConfig(int payload_type, const SdpAudioFormat& format);
+ static Config CreateConfig(const CodecInst& codec_inst);
+
using AudioNetworkAdaptorCreator =
std::function<std::unique_ptr<AudioNetworkAdaptor>(const std::string&,
RtcEventLog*,
@@ -89,9 +94,14 @@
std::unique_ptr<SmoothingFilter> bitrate_smoother = nullptr);
explicit AudioEncoderOpus(const CodecInst& codec_inst);
-
+ AudioEncoderOpus(int payload_type, const SdpAudioFormat& format);
~AudioEncoderOpus() override;
+ // Static interface for use by BuiltinAudioEncoderFactory.
+ static constexpr const char* GetPayloadName() { return "opus"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
+
int SampleRateHz() const override;
size_t NumChannels() const override;
size_t Num10MsFramesInNextPacket() const override;
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
index 04c0cf1..55d3c92 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
@@ -10,6 +10,7 @@
#include <array>
#include <memory>
+#include <utility>
#include "webrtc/base/checks.h"
#include "webrtc/base/fakeclock.h"
@@ -45,6 +46,12 @@
return config;
}
+AudioEncoderOpus::Config CreateConfigWithParameters(
+ const SdpAudioFormat::Parameters& params) {
+ SdpAudioFormat format("opus", 48000, 2, params);
+ return AudioEncoderOpus::CreateConfig(0, format);
+}
+
struct AudioEncoderOpusStates {
std::shared_ptr<MockAudioNetworkAdaptor*> mock_audio_network_adaptor;
MockSmoothingFilter* mock_bitrate_smoother;
@@ -186,7 +193,7 @@
auto states = CreateCodec(1);
// Constants are replicated from audio_states.encoderopus.cc.
const int kMinBitrateBps = 6000;
- const int kMaxBitrateBps = 512000;
+ const int kMaxBitrateBps = 510000;
// Set a too low bitrate.
states.encoder->OnReceivedUplinkBandwidth(kMinBitrateBps - 1,
rtc::Optional<int64_t>());
@@ -417,7 +424,7 @@
"WebRTC-SendSideBwe-WithOverhead/Enabled/");
constexpr int kMinBitrateBps = 6000;
- constexpr int kMaxBitrateBps = 512000;
+ constexpr int kMaxBitrateBps = 510000;
auto states = CreateCodec(2);
@@ -545,4 +552,199 @@
}
}
+TEST(AudioEncoderOpusTest, TestConfigDefaults) {
+ const AudioEncoderOpus::Config config =
+ AudioEncoderOpus::CreateConfig(0, {"opus", 48000, 2});
+
+ EXPECT_EQ(48000, config.max_playback_rate_hz);
+ EXPECT_EQ(1u, config.num_channels);
+ EXPECT_FALSE(config.fec_enabled);
+ EXPECT_FALSE(config.dtx_enabled);
+ EXPECT_EQ(20, config.frame_size_ms);
+}
+
+TEST(AudioEncoderOpusTest, TestConfigFromParams) {
+ AudioEncoderOpus::Config config;
+
+ config = CreateConfigWithParameters({{"stereo", "0"}});
+ EXPECT_EQ(1U, config.num_channels);
+
+ config = CreateConfigWithParameters({{"stereo", "1"}});
+ EXPECT_EQ(2U, config.num_channels);
+
+ config = CreateConfigWithParameters({{"useinbandfec", "0"}});
+ EXPECT_FALSE(config.fec_enabled);
+
+ config = CreateConfigWithParameters({{"useinbandfec", "1"}});
+ EXPECT_TRUE(config.fec_enabled);
+
+ config = CreateConfigWithParameters({{"usedtx", "0"}});
+ EXPECT_FALSE(config.dtx_enabled);
+
+ config = CreateConfigWithParameters({{"usedtx", "1"}});
+ EXPECT_TRUE(config.dtx_enabled);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "12345"}});
+ EXPECT_EQ(12345, config.max_playback_rate_hz);
+
+ config = CreateConfigWithParameters({{"maxaveragebitrate", "96000"}});
+ EXPECT_EQ(96000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxptime", "40"}});
+ for (int frame_length : config.supported_frame_lengths_ms) {
+ EXPECT_LE(frame_length, 40);
+ }
+
+ config = CreateConfigWithParameters({{"minptime", "40"}});
+ for (int frame_length : config.supported_frame_lengths_ms) {
+ EXPECT_GE(frame_length, 40);
+ }
+
+ config = CreateConfigWithParameters({{"ptime", "40"}});
+ EXPECT_EQ(40, config.frame_size_ms);
+
+ constexpr int kMinSupportedFrameLength = 10;
+ constexpr int kMaxSupportedFrameLength =
+ WEBRTC_OPUS_SUPPORT_120MS_PTIME ? 120 : 60;
+
+ config = CreateConfigWithParameters({{"ptime", "1"}});
+ EXPECT_EQ(kMinSupportedFrameLength, config.frame_size_ms);
+
+ config = CreateConfigWithParameters({{"ptime", "2000"}});
+ EXPECT_EQ(kMaxSupportedFrameLength, config.frame_size_ms);
+}
+
+TEST(AudioEncoderOpusTest, TestConfigFromInvalidParams) {
+ const webrtc::SdpAudioFormat format("opus", 48000, 2);
+ const AudioEncoderOpus::Config default_config =
+ AudioEncoderOpus::CreateConfig(0, format);
+#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
+ const std::vector<int> default_supported_frame_lengths_ms({20, 60, 120});
+#else
+ const std::vector<int> default_supported_frame_lengths_ms({20, 60});
+#endif
+
+ AudioEncoderOpus::Config config;
+ config = CreateConfigWithParameters({{"stereo", "invalid"}});
+ EXPECT_EQ(default_config.num_channels, config.num_channels);
+
+ config = CreateConfigWithParameters({{"useinbandfec", "invalid"}});
+ EXPECT_EQ(default_config.fec_enabled, config.fec_enabled);
+
+ config = CreateConfigWithParameters({{"usedtx", "invalid"}});
+ EXPECT_EQ(default_config.dtx_enabled, config.dtx_enabled);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "0"}});
+ EXPECT_EQ(default_config.max_playback_rate_hz, config.max_playback_rate_hz);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "-23"}});
+ EXPECT_EQ(default_config.max_playback_rate_hz, config.max_playback_rate_hz);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "not a number!"}});
+ EXPECT_EQ(default_config.max_playback_rate_hz, config.max_playback_rate_hz);
+
+ config = CreateConfigWithParameters({{"maxaveragebitrate", "0"}});
+ EXPECT_EQ(6000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxaveragebitrate", "-1000"}});
+ EXPECT_EQ(6000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxaveragebitrate", "1024000"}});
+ EXPECT_EQ(510000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxaveragebitrate", "not a number!"}});
+ EXPECT_EQ(default_config.bitrate_bps, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxptime", "invalid"}});
+ EXPECT_EQ(default_supported_frame_lengths_ms,
+ config.supported_frame_lengths_ms);
+
+ config = CreateConfigWithParameters({{"minptime", "invalid"}});
+ EXPECT_EQ(default_supported_frame_lengths_ms,
+ config.supported_frame_lengths_ms);
+
+ config = CreateConfigWithParameters({{"ptime", "invalid"}});
+ EXPECT_EQ(default_supported_frame_lengths_ms,
+ config.supported_frame_lengths_ms);
+}
+
+// Test that bitrate will be overridden by the "maxaveragebitrate" parameter.
+// Also test that the "maxaveragebitrate" can't be set to values outside the
+// range of 6000 and 510000
+TEST(AudioEncoderOpusTest, SetSendCodecOpusMaxAverageBitrate) {
+ // Ignore if less than 6000.
+ const AudioEncoderOpus::Config config1 = AudioEncoderOpus::CreateConfig(
+ 0, {"opus", 48000, 2, {{"maxaveragebitrate", "5999"}}});
+ EXPECT_EQ(6000, config1.bitrate_bps);
+
+ // Ignore if larger than 510000.
+ const AudioEncoderOpus::Config config2 = AudioEncoderOpus::CreateConfig(
+ 0, {"opus", 48000, 2, {{"maxaveragebitrate", "510001"}}});
+ EXPECT_EQ(510000, config2.bitrate_bps);
+
+ const AudioEncoderOpus::Config config3 = AudioEncoderOpus::CreateConfig(
+ 0, {"opus", 48000, 2, {{"maxaveragebitrate", "200000"}}});
+ EXPECT_EQ(200000, config3.bitrate_bps);
+}
+
+// Test maxplaybackrate <= 8000 triggers Opus narrow band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateNb) {
+ auto config = CreateConfigWithParameters({{"maxplaybackrate", "8000"}});
+ EXPECT_EQ(8000, config.max_playback_rate_hz);
+ EXPECT_EQ(12000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "8000"},
+ {"stereo", "1"}});
+ EXPECT_EQ(8000, config.max_playback_rate_hz);
+ EXPECT_EQ(24000, config.bitrate_bps);
+}
+
+// Test 8000 < maxplaybackrate <= 12000 triggers Opus medium band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateMb) {
+ auto config = CreateConfigWithParameters({{"maxplaybackrate", "8001"}});
+ EXPECT_EQ(8001, config.max_playback_rate_hz);
+ EXPECT_EQ(20000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "8001"},
+ {"stereo", "1"}});
+ EXPECT_EQ(8001, config.max_playback_rate_hz);
+ EXPECT_EQ(40000, config.bitrate_bps);
+}
+
+// Test 12000 < maxplaybackrate <= 16000 triggers Opus wide band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateWb) {
+ auto config = CreateConfigWithParameters({{"maxplaybackrate", "12001"}});
+ EXPECT_EQ(12001, config.max_playback_rate_hz);
+ EXPECT_EQ(20000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "12001"},
+ {"stereo", "1"}});
+ EXPECT_EQ(12001, config.max_playback_rate_hz);
+ EXPECT_EQ(40000, config.bitrate_bps);
+}
+
+// Test 16000 < maxplaybackrate <= 24000 triggers Opus super wide band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateSwb) {
+ auto config = CreateConfigWithParameters({{"maxplaybackrate", "16001"}});
+ EXPECT_EQ(16001, config.max_playback_rate_hz);
+ EXPECT_EQ(32000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "16001"},
+ {"stereo", "1"}});
+ EXPECT_EQ(16001, config.max_playback_rate_hz);
+ EXPECT_EQ(64000, config.bitrate_bps);
+}
+
+// Test 24000 < maxplaybackrate triggers Opus full band mode.
+TEST(AudioEncoderOpusTest, SetMaxPlaybackRateFb) {
+ auto config = CreateConfigWithParameters({{"maxplaybackrate", "24001"}});
+ EXPECT_EQ(24001, config.max_playback_rate_hz);
+ EXPECT_EQ(32000, config.bitrate_bps);
+
+ config = CreateConfigWithParameters({{"maxplaybackrate", "24001"},
+ {"stereo", "1"}});
+ EXPECT_EQ(24001, config.max_playback_rate_hz);
+ EXPECT_EQ(64000, config.bitrate_bps);
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
index cafd3e8..442ea66 100644
--- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
+++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
@@ -10,7 +10,11 @@
#include "webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
+#include <algorithm>
+
#include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/string_to_number.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h"
@@ -40,6 +44,24 @@
config.payload_type = codec_inst.pltype;
return config;
}
+
+AudioEncoderPcm16B::Config CreateConfig(int payload_type,
+ const SdpAudioFormat& format) {
+ AudioEncoderPcm16B::Config config;
+ config.num_channels = format.num_channels;
+ config.sample_rate_hz = format.clockrate_hz;
+ config.frame_size_ms = 10;
+ 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(10, std::min(whole_packets * 10, 60));
+ }
+ }
+ config.payload_type = payload_type;
+ return config;
+}
} // namespace
bool AudioEncoderPcm16B::Config::IsOk() const {
@@ -52,4 +74,23 @@
AudioEncoderPcm16B::AudioEncoderPcm16B(const CodecInst& codec_inst)
: AudioEncoderPcm16B(CreateConfig(codec_inst)) {}
+AudioEncoderPcm16B::AudioEncoderPcm16B(int payload_type,
+ const SdpAudioFormat& format)
+ : AudioEncoderPcm16B(CreateConfig(payload_type, format)) {}
+
+rtc::Optional<AudioCodecInfo> AudioEncoderPcm16B::QueryAudioEncoder(
+ const SdpAudioFormat& format) {
+ if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
+ format.num_channels >= 1) {
+ Config config = CreateConfig(0, format);
+ if (config.IsOk()) {
+ return rtc::Optional<AudioCodecInfo>(
+ {config.sample_rate_hz, config.num_channels,
+ config.sample_rate_hz * 2 *
+ rtc::dchecked_cast<int>(config.num_channels)});
+ }
+ }
+ return rtc::Optional<AudioCodecInfo>();
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
index bdc27a6..deb0e1e 100644
--- a/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
+++ b/webrtc/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
@@ -31,6 +31,11 @@
explicit AudioEncoderPcm16B(const Config& config)
: AudioEncoderPcm(config, config.sample_rate_hz) {}
explicit AudioEncoderPcm16B(const CodecInst& codec_inst);
+ AudioEncoderPcm16B(int payload_type, const SdpAudioFormat& format);
+
+ static constexpr const char* GetPayloadName() { return "L16"; }
+ static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+ const SdpAudioFormat& format);
protected:
size_t EncodeCall(const int16_t* audio,
diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 1ee92a1..4a4e62b 100644
--- a/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -611,8 +611,8 @@
EXPECT_EQ(6000, SetAndGetTargetBitrate(audio_encoder, 5999));
EXPECT_EQ(6000, SetAndGetTargetBitrate(audio_encoder, 6000));
EXPECT_EQ(32000, SetAndGetTargetBitrate(audio_encoder, 32000));
- EXPECT_EQ(512000, SetAndGetTargetBitrate(audio_encoder, 512000));
- EXPECT_EQ(512000, SetAndGetTargetBitrate(audio_encoder, 513000));
+ EXPECT_EQ(510000, SetAndGetTargetBitrate(audio_encoder, 510000));
+ EXPECT_EQ(510000, SetAndGetTargetBitrate(audio_encoder, 511000));
}
} // namespace
diff --git a/webrtc/pc/DEPS b/webrtc/pc/DEPS
index 5b8f955..4468e6b 100644
--- a/webrtc/pc/DEPS
+++ b/webrtc/pc/DEPS
@@ -24,12 +24,12 @@
"+crypto",
],
- # TODO(kwiberg): Remove these exceptions when audio_decoder_factory.h
+ # TODO(ossu): Remove these exceptions when audio_encoder_factory.h
# has moved to api/.
"peerconnectionfactory\.cc": [
- "+webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h",
+ "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
],
"peerconnectioninterface_unittest\.cc": [
- "+webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h",
+ "+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
],
}
diff --git a/webrtc/pc/peerconnectionfactory.cc b/webrtc/pc/peerconnectionfactory.cc
index 74a693d..8269a1a 100644
--- a/webrtc/pc/peerconnectionfactory.cc
+++ b/webrtc/pc/peerconnectionfactory.cc
@@ -24,6 +24,7 @@
#include "webrtc/media/engine/webrtcmediaengine.h"
#include "webrtc/media/engine/webrtcvideodecoderfactory.h"
#include "webrtc/media/engine/webrtcvideoencoderfactory.h"
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
#include "webrtc/modules/audio_device/include/audio_device.h"
#include "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/client/basicportallocator.h"
diff --git a/webrtc/pc/peerconnectioninterface_unittest.cc b/webrtc/pc/peerconnectioninterface_unittest.cc
index 05d53ad..e7636e0 100644
--- a/webrtc/pc/peerconnectioninterface_unittest.cc
+++ b/webrtc/pc/peerconnectioninterface_unittest.cc
@@ -27,6 +27,7 @@
#include "webrtc/base/thread.h"
#include "webrtc/media/base/fakevideocapturer.h"
#include "webrtc/media/sctp/sctptransportinternal.h"
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h"
#include "webrtc/p2p/base/fakeportallocator.h"
#include "webrtc/pc/audiotrack.h"
#include "webrtc/pc/mediasession.h"
diff --git a/webrtc/voice_engine/BUILD.gn b/webrtc/voice_engine/BUILD.gn
index 8d0f249..ba79b2d 100644
--- a/webrtc/voice_engine/BUILD.gn
+++ b/webrtc/voice_engine/BUILD.gn
@@ -17,7 +17,9 @@
"..:webrtc_common",
"../api/audio_codecs:builtin_audio_decoder_factory",
"../modules/audio_coding",
+ "../modules/audio_coding:audio_encoder_factory_interface",
"../modules/audio_coding:audio_format_conversion",
+ "../modules/audio_coding:builtin_audio_encoder_factory",
"../modules/audio_coding:rent_a_codec",
]