Opus implementation of the AudioEncoderFactoryTemplate API
This was previously reverted, because external projects were using the
internal webrtc::AudioEncoderOpus class and broke when it was renamed.
This re-land avoids renaming it immediately, to give those projects
time to adapt. It also has to revert some of the changes I had made to the
Config struct, since that was also used by the same external projects.
BUG=webrtc:7831
Review-Url: https://codereview.webrtc.org/2948483002
Cr-Commit-Position: refs/heads/master@{#18852}
diff --git a/webrtc/api/DEPS b/webrtc/api/DEPS
index e48b568..b0493fa 100644
--- a/webrtc/api/DEPS
+++ b/webrtc/api/DEPS
@@ -21,6 +21,13 @@
"+webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h",
],
+ # Needed because AudioEncoderOpus is in the wrong place for
+ # backwards compatibilty reasons. See
+ # https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+ "audio_encoder_opus\.h": [
+ "+webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.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/opus/BUILD.gn b/webrtc/api/audio_codecs/opus/BUILD.gn
new file mode 100644
index 0000000..b82f496
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/BUILD.gn
@@ -0,0 +1,42 @@
+# 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_static_library("audio_encoder_opus_config") {
+ sources = [
+ "audio_encoder_opus_config.cc",
+ "audio_encoder_opus_config.h",
+ ]
+ deps = [
+ "../../../base:rtc_base_approved",
+ ]
+ defines = []
+ if (rtc_opus_variable_complexity) {
+ defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=1" ]
+ } else {
+ defines += [ "WEBRTC_OPUS_VARIABLE_COMPLEXITY=0" ]
+ }
+}
+
+rtc_source_set("audio_encoder_opus") {
+ sources = [
+ "audio_encoder_opus.h",
+ ]
+ deps = [
+ ":audio_encoder_opus_config",
+ "..:audio_codecs_api",
+ "../../../base:protobuf_utils", # TODO(kwiberg): Why is this needed?
+ "../../../base:rtc_base_approved",
+ "../../../modules/audio_coding:webrtc_opus",
+ ]
+}
diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus.h b/webrtc/api/audio_codecs/opus/audio_encoder_opus.h
new file mode 100644
index 0000000..4763f44
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
+#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
+
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
+
+namespace webrtc {
+
+// Opus encoder API for use as a template parameter to
+// CreateAudioEncoderFactory<...>().
+//
+// NOTE: At the moment, this struct actually resides in another file. This is a
+// temporary backwards compatibility hack; see
+// https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+//
+// NOTE: This struct is still under development and may change without notice.
+/*
+struct AudioEncoderOpus {
+ static rtc::Optional<AudioEncoderOpusConfig> SdpToConfig(
+ const SdpAudioFormat& audio_format);
+ static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs);
+ static AudioCodecInfo QueryAudioEncoder(const AudioEncoderOpusConfig& config);
+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder(
+ const AudioEncoderOpusConfig&,
+ int payload_type);
+};
+*/
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc
new file mode 100644
index 0000000..7d29883
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.cc
@@ -0,0 +1,70 @@
+/*
+ * 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/opus/audio_encoder_opus_config.h"
+
+namespace webrtc {
+
+namespace {
+
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
+// If we are on Android, iOS and/or ARM, use a lower complexity setting by
+// default, to save encoder complexity.
+constexpr int kDefaultComplexity = 5;
+#else
+constexpr int kDefaultComplexity = 9;
+#endif
+
+constexpr int kDefaultLowRateComplexity =
+ WEBRTC_OPUS_VARIABLE_COMPLEXITY ? 9 : kDefaultComplexity;
+
+} // namespace
+
+constexpr int AudioEncoderOpusConfig::kDefaultFrameSizeMs;
+constexpr int AudioEncoderOpusConfig::kMinBitrateBps;
+constexpr int AudioEncoderOpusConfig::kMaxBitrateBps;
+
+AudioEncoderOpusConfig::AudioEncoderOpusConfig()
+ : frame_size_ms(kDefaultFrameSizeMs),
+ num_channels(1),
+ application(ApplicationMode::kVoip),
+ bitrate_bps(32000),
+ fec_enabled(false),
+ cbr_enabled(false),
+ max_playback_rate_hz(48000),
+ complexity(kDefaultComplexity),
+ low_rate_complexity(kDefaultLowRateComplexity),
+ complexity_threshold_bps(12500),
+ complexity_threshold_window_bps(1500),
+ dtx_enabled(false),
+ uplink_bandwidth_update_interval_ms(200),
+ payload_type(-1) {}
+AudioEncoderOpusConfig::AudioEncoderOpusConfig(const AudioEncoderOpusConfig&) =
+ default;
+AudioEncoderOpusConfig::~AudioEncoderOpusConfig() = default;
+AudioEncoderOpusConfig& AudioEncoderOpusConfig::operator=(
+ const AudioEncoderOpusConfig&) = default;
+
+bool AudioEncoderOpusConfig::IsOk() const {
+ if (frame_size_ms <= 0 || frame_size_ms % 10 != 0)
+ return false;
+ if (num_channels != 1 && num_channels != 2)
+ return false;
+ if (!bitrate_bps)
+ return false;
+ if (*bitrate_bps < kMinBitrateBps || *bitrate_bps > kMaxBitrateBps)
+ return false;
+ if (complexity < 0 || complexity > 10)
+ return false;
+ if (low_rate_complexity < 0 || low_rate_complexity > 10)
+ return false;
+ return true;
+}
+} // namespace webrtc
diff --git a/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h
new file mode 100644
index 0000000..bd25b54
--- /dev/null
+++ b/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h
@@ -0,0 +1,73 @@
+/*
+ * 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_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_
+#define WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "webrtc/base/optional.h"
+
+namespace webrtc {
+
+// NOTE: This struct is still under development and may change without notice.
+struct AudioEncoderOpusConfig {
+ static constexpr int kDefaultFrameSizeMs = 20;
+
+ // Opus API allows a min bitrate of 500bps, but Opus documentation suggests
+ // bitrate should be in the range of 6000 to 510000, inclusive.
+ static constexpr int kMinBitrateBps = 6000;
+ static constexpr int kMaxBitrateBps = 510000;
+
+ AudioEncoderOpusConfig();
+ AudioEncoderOpusConfig(const AudioEncoderOpusConfig&);
+ ~AudioEncoderOpusConfig();
+ AudioEncoderOpusConfig& operator=(const AudioEncoderOpusConfig&);
+
+ bool IsOk() const; // Checks if the values are currently OK.
+
+ int frame_size_ms;
+ size_t num_channels;
+ enum class ApplicationMode { kVoip, kAudio };
+ ApplicationMode application;
+
+ // NOTE: This member must always be set.
+ // TODO(kwiberg): Turn it into just an int.
+ rtc::Optional<int> bitrate_bps;
+
+ bool fec_enabled;
+ bool cbr_enabled;
+ int max_playback_rate_hz;
+
+ // |complexity| is used when the bitrate goes above
+ // |complexity_threshold_bps| + |complexity_threshold_window_bps|;
+ // |low_rate_complexity| is used when the bitrate falls below
+ // |complexity_threshold_bps| - |complexity_threshold_window_bps|. In the
+ // interval in the middle, we keep using the most recent of the two
+ // complexity settings.
+ int complexity;
+ int low_rate_complexity;
+ int complexity_threshold_bps;
+ int complexity_threshold_window_bps;
+
+ bool dtx_enabled;
+ std::vector<int> supported_frame_lengths_ms;
+ int uplink_bandwidth_update_interval_ms;
+
+ // NOTE: This member isn't necessary, and will soon go away. See
+ // https://bugs.chromium.org/p/webrtc/issues/detail?id=7847
+ int payload_type;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_API_AUDIO_CODECS_OPUS_AUDIO_ENCODER_OPUS_CONFIG_H_
diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn
index 38ca736..685726f 100644
--- a/webrtc/api/audio_codecs/test/BUILD.gn
+++ b/webrtc/api/audio_codecs/test/BUILD.gn
@@ -21,6 +21,7 @@
]
deps = [
"..:audio_codecs_api",
+ "../../../base:protobuf_utils", # TODO(kwiberg): Why is this needed?
"../../../base:rtc_base_approved",
"../../../test:audio_codec_mocks",
"../../../test:test_support",
@@ -28,6 +29,7 @@
"../g722:audio_encoder_g722",
"../ilbc:audio_decoder_ilbc",
"../ilbc:audio_encoder_ilbc",
+ "../opus:audio_encoder_opus",
"//testing/gmock",
]
}
diff --git a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc
index c3c07c6..d08e7aa 100644
--- a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc
+++ b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc
@@ -11,6 +11,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/api/audio_codecs/opus/audio_encoder_opus.h"
#include "webrtc/base/ptr_util.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
@@ -149,4 +150,26 @@
EXPECT_EQ(8000, enc->SampleRateHz());
}
+TEST(AudioEncoderFactoryTemplateTest, Opus) {
+ auto factory = CreateAudioEncoderFactory<AudioEncoderOpus>();
+ AudioCodecInfo info = {48000, 1, 32000, 6000, 510000};
+ info.allow_comfort_noise = false;
+ info.supports_network_adaption = true;
+ EXPECT_THAT(
+ factory->GetSupportedEncoders(),
+ testing::ElementsAre(AudioCodecSpec{
+ {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}},
+ info}));
+ EXPECT_EQ(rtc::Optional<AudioCodecInfo>(),
+ factory->QueryAudioEncoder({"foo", 8000, 1}));
+ EXPECT_EQ(
+ rtc::Optional<AudioCodecInfo>(info),
+ factory->QueryAudioEncoder(
+ {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}));
+ EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1}));
+ auto enc = factory->MakeAudioEncoder(17, {"opus", 48000, 2});
+ ASSERT_NE(nullptr, enc);
+ EXPECT_EQ(48000, enc->SampleRateHz());
+}
+
} // namespace webrtc