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
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 7998fdb..3bc7d0e 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_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 b1dedd7..89f0a54 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 0000000..50caf83
--- /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 ea535ea..94ad1bd 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 <stdlib.h>
 #include <string.h>
 
-#include "opus.h"
-
 enum {
   /* Maximum supported frame size in WebRTC is 60 ms. */
   kWebRtcOpusMaxEncodeFrameSizeMs = 60,
@@ -32,10 +31,6 @@
   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_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 @@
   }
 }
 
-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 2ec77a5..582bb73 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 @@
   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 @@
   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 @@
   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) {