From 0040a6ef97236053d9698470b9d4c095e8019f1c Mon Sep 17 00:00:00 2001 From: "minyue@webrtc.org" Date: Mon, 4 Aug 2014 14:41:57 +0000 Subject: [PATCH] This is a setup to solve https://code.google.com/p/webrtc/issues/detail?id=1906 In particular, we add an API to call Opus's set maximum bandwidth to prevent the encoder from coding audio content beyond this bandwidth so as to increase computation and transmission efficiency (without affecting sampling rate). BUG= R=henrik.lundin@webrtc.org, turaj@webrtc.org Review URL: https://webrtc-codereview.appspot.com/13099004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6817 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../codecs/opus/interface/opus_interface.h | 21 ++++++++++ .../audio_coding/codecs/opus/opus.gypi | 1 + .../audio_coding/codecs/opus/opus_inst.h | 28 +++++++++++++ .../audio_coding/codecs/opus/opus_interface.c | 35 ++++++++++------ .../audio_coding/codecs/opus/opus_unittest.cc | 41 +++++++++++++++++-- 5 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 webrtc/modules/audio_coding/codecs/opus/opus_inst.h diff --git a/webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h b/webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h index 7998fdbdeb..3bc7d0e891 100644 --- a/webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h +++ b/webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h @@ -72,6 +72,27 @@ int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate); */ int16_t WebRtcOpus_SetPacketLossRate(OpusEncInst* inst, int32_t loss_rate); +/**************************************************************************** + * WebRtcOpus_SetMaxBandwidth(...) + * + * Configures the maximum bandwidth for encoding. This can be taken as a hint + * about the maximum output bandwidth that the receiver is capable to render, + * due to hardware limitations. Sending signals with higher audio bandwidth + * results in higher than necessary network usage and encoding complexity. + * + * Input: + * - inst : Encoder context + * - bandwidth : Maximum encoding bandwidth in Hz. + * This parameter can take any value, but values + * other than Opus typical bandwidths: 4000, 6000, + * 8000, 12000, and 20000 will be rounded up (values + * greater than 20000 will be rounded down) to + * these values. + * Return value : 0 - Success + * -1 - Error + */ +int16_t WebRtcOpus_SetMaxBandwidth(OpusEncInst* inst, int32_t bandwidth); + /* TODO(minyue): Check whether an API to check the FEC and the packet loss rate * is needed. It might not be very useful since there are not many use cases and * the caller can always maintain the states. */ diff --git a/webrtc/modules/audio_coding/codecs/opus/opus.gypi b/webrtc/modules/audio_coding/codecs/opus/opus.gypi index b1dedd7d4a..89f0a54a76 100644 --- a/webrtc/modules/audio_coding/codecs/opus/opus.gypi +++ b/webrtc/modules/audio_coding/codecs/opus/opus.gypi @@ -28,6 +28,7 @@ ], 'sources': [ 'interface/opus_interface.h', + 'opus_inst.h', 'opus_interface.c', ], }, diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_inst.h b/webrtc/modules/audio_coding/codecs/opus/opus_inst.h new file mode 100644 index 0000000000..50caf8373f --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/opus/opus_inst.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 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_OPUS_OPUS_INST_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INST_H_ + +#include "opus.h" + +struct WebRtcOpusEncInst { + OpusEncoder* encoder; +}; + +struct WebRtcOpusDecInst { + OpusDecoder* decoder_left; + OpusDecoder* decoder_right; + int prev_decoded_samples; + int channels; +}; + + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INST_H_ diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_interface.c b/webrtc/modules/audio_coding/codecs/opus/opus_interface.c index ea535ea97a..94ad1bd92b 100644 --- a/webrtc/modules/audio_coding/codecs/opus/opus_interface.c +++ b/webrtc/modules/audio_coding/codecs/opus/opus_interface.c @@ -9,12 +9,11 @@ */ #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" +#include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h" #include #include -#include "opus.h" - enum { /* Maximum supported frame size in WebRTC is 60 ms. */ kWebRtcOpusMaxEncodeFrameSizeMs = 60, @@ -32,10 +31,6 @@ enum { kWebRtcOpusDefaultFrameSize = 960, }; -struct WebRtcOpusEncInst { - OpusEncoder* encoder; -}; - int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, int32_t channels) { OpusEncInst* state; if (inst != NULL) { @@ -104,6 +99,27 @@ int16_t WebRtcOpus_SetPacketLossRate(OpusEncInst* inst, int32_t loss_rate) { } } +int16_t WebRtcOpus_SetMaxBandwidth(OpusEncInst* inst, int32_t bandwidth) { + opus_int32 set_bandwidth; + + if (!inst) + return -1; + + if (bandwidth <= 4000) { + set_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if (bandwidth <= 6000) { + set_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if (bandwidth <= 8000) { + set_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } else if (bandwidth <= 12000) { + set_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + set_bandwidth = OPUS_BANDWIDTH_FULLBAND; + } + return opus_encoder_ctl(inst->encoder, + OPUS_SET_MAX_BANDWIDTH(set_bandwidth)); +} + int16_t WebRtcOpus_EnableFec(OpusEncInst* inst) { if (inst) { return opus_encoder_ctl(inst->encoder, OPUS_SET_INBAND_FEC(1)); @@ -128,13 +144,6 @@ int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity) { } } -struct WebRtcOpusDecInst { - OpusDecoder* decoder_left; - OpusDecoder* decoder_right; - int prev_decoded_samples; - int channels; -}; - int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, int channels) { int error_l; int error_r; diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc index 2ec77a5366..582bb735ef 100644 --- a/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc @@ -11,11 +11,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" +#include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h" #include "webrtc/test/testsupport/fileutils.h" -struct WebRtcOpusEncInst; -struct WebRtcOpusDecInst; - namespace webrtc { // Number of samples in a 60 ms stereo frame, sampled at 48 kHz. @@ -32,6 +30,8 @@ class OpusTest : public ::testing::Test { OpusTest(); virtual void SetUp(); + void TestSetMaxBandwidth(opus_int32 expect, int32_t set); + WebRtcOpusEncInst* opus_mono_encoder_; WebRtcOpusEncInst* opus_stereo_encoder_; WebRtcOpusDecInst* opus_mono_decoder_; @@ -66,6 +66,20 @@ void OpusTest::SetUp() { input_file = NULL; } +void OpusTest::TestSetMaxBandwidth(opus_int32 expect, int32_t set) { + opus_int32 bandwidth; + // Test mono encoder. + EXPECT_EQ(0, WebRtcOpus_SetMaxBandwidth(opus_mono_encoder_, set)); + opus_encoder_ctl(opus_mono_encoder_->encoder, + OPUS_GET_MAX_BANDWIDTH(&bandwidth)); + EXPECT_EQ(expect, bandwidth); + // Test stereo encoder. + EXPECT_EQ(0, WebRtcOpus_SetMaxBandwidth(opus_stereo_encoder_, set)); + opus_encoder_ctl(opus_stereo_encoder_->encoder, + OPUS_GET_MAX_BANDWIDTH(&bandwidth)); + EXPECT_EQ(expect, bandwidth); +} + // Test failing Create. TEST_F(OpusTest, OpusCreateFail) { // Test to see that an invalid pointer is caught. @@ -341,6 +355,27 @@ TEST_F(OpusTest, OpusSetPacketLossRate) { EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_stereo_encoder_)); } +TEST_F(OpusTest, OpusSetMaxBandwidth) { + // Test without creating encoder memory. + EXPECT_EQ(-1, WebRtcOpus_SetMaxBandwidth(opus_mono_encoder_, 20000)); + EXPECT_EQ(-1, WebRtcOpus_SetMaxBandwidth(opus_stereo_encoder_, 20000)); + + // Create encoder memory, try with different bitrates. + EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1)); + EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2)); + + TestSetMaxBandwidth(OPUS_BANDWIDTH_FULLBAND, 24000); + TestSetMaxBandwidth(OPUS_BANDWIDTH_FULLBAND, 14000); + TestSetMaxBandwidth(OPUS_BANDWIDTH_SUPERWIDEBAND, 10000); + TestSetMaxBandwidth(OPUS_BANDWIDTH_WIDEBAND, 7000); + TestSetMaxBandwidth(OPUS_BANDWIDTH_MEDIUMBAND, 6000); + TestSetMaxBandwidth(OPUS_BANDWIDTH_NARROWBAND, 4000); + TestSetMaxBandwidth(OPUS_BANDWIDTH_NARROWBAND, 3000); + + // Free memory. + EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_mono_encoder_)); + EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_stereo_encoder_)); +} // PLC in mono mode. TEST_F(OpusTest, OpusDecodePlcMono) {