Added SetBitRate function to VoE API to allow changing the audio bitrate.

If the requested bitrate is not valid for the codec, the codec will decide on
an appropriate value.
Updated VoE command line tool to use new SetBitRate function.
Includes unittests for SetBitRate function.

BUG=
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kwiberg@webrtc.org, pbos@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/50789004

Cr-Commit-Position: refs/heads/master@{#9115}
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index c394d0c..328ef2b 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -540,6 +540,7 @@
     codec = channels_[channel]->send_codec;
     return 0;
   }
+  WEBRTC_STUB(SetBitRate, (int channel, int bitrate_bps));
   WEBRTC_FUNC(GetRecCodec, (int channel, webrtc::CodecInst& codec)) {
     WEBRTC_CHECK_CHANNEL(channel);
     const Channel* c = channels_[channel];
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
index c852d8b..83febd0 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc
@@ -386,10 +386,9 @@
   return num_channels == 1 || enable_dtx ? kVoip : kAudio;
 }
 
-int16_t ACMGenericCodec::SetBitRate(const int32_t bitrate_bps) {
+void ACMGenericCodec::SetBitRate(const int bitrate_bps) {
   encoder_->SetTargetBitrate(bitrate_bps);
   bitrate_bps_ = bitrate_bps;
-  return 0;
 }
 
 int16_t ACMGenericCodec::SetVAD(bool* enable_dtx,
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
index d775434..69161bd 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h
@@ -162,18 +162,14 @@
   void ResetNoMissedSamples();
 
   ///////////////////////////////////////////////////////////////////////////
-  // int16_t SetBitRate()
-  // The function is called to set the encoding rate.
+  // void SetBitRate()
+  // The function is called to set the encoding rate. If the value is not
+  // supported by the codec, another appropriate value is used.
   //
   // Input:
   //   -bitrate_bps        : encoding rate in bits per second
   //
-  // Return value:
-  //   -1 if failed to set the rate, due to invalid input or given
-  //      codec is not rate-adjustable.
-  //    0 if the rate is adjusted successfully
-  //
-  int16_t SetBitRate(const int32_t bitrate_bps);
+  void SetBitRate(const int bitrate_bps);
 
   ///////////////////////////////////////////////////////////////////////////
   // uint32_t EarliestTimestamp()
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
index 4918d21..18570d0 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
@@ -287,6 +287,14 @@
   return encoder_param.codec_inst.rate;
 }
 
+void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) {
+  CriticalSectionScoped lock(acm_crit_sect_);
+
+  if (codec_manager_.current_encoder()) {
+    codec_manager_.current_encoder()->SetBitRate(bitrate_bps);
+  }
+}
+
 // Set available bandwidth, inform the encoder about the estimated bandwidth
 // received from the remote party.
 // TODO(henrik.lundin): Remove; not used.
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
index d307cda..08e10ae 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h
@@ -60,6 +60,11 @@
   // codecs return there long-term average or their fixed rate.
   int SendBitrate() const override;
 
+  // Sets the bitrate to the specified value in bits/sec. In case the codec does
+  // not support the requested value it will choose an appropriate value
+  // instead.
+  void SetBitRate(int bitrate_bps) override;
+
   // Set available bandwidth, inform the encoder about the
   // estimated bandwidth received from the remote party.
   int SetReceivedEstimatedBandwidth(int bw) override;
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
index 81ae8aa..d2e7cdd 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest_oldapi.cc
@@ -1169,6 +1169,192 @@
       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 {
+ protected:
+  static const int kTestDurationMs = 1000;
+
+  // Sets up the test::AcmSendTest object. Returns true on success, otherwise
+  // false.
+  bool SetUpSender() {
+    const std::string input_file_name =
+        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+    // Note that |audio_source_| will loop forever. The test duration is set
+    // explicitly by |kTestDurationMs|.
+    audio_source_.reset(new test::InputAudioFile(input_file_name));
+    static const int kSourceRateHz = 32000;
+    send_test_.reset(new test::AcmSendTestOldApi(
+        audio_source_.get(), kSourceRateHz, kTestDurationMs));
+    return send_test_.get();
+  }
+
+  // Registers a send codec in the test::AcmSendTest object. Returns true on
+  // success, false on failure.
+  virtual bool RegisterSendCodec(const char* payload_name,
+                                 int sampling_freq_hz,
+                                 int channels,
+                                 int payload_type,
+                                 int frame_size_samples,
+                                 int frame_size_rtp_timestamps) {
+    return send_test_->RegisterCodec(payload_name, sampling_freq_hz, channels,
+                                     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);
+    int nr_bytes = 0;
+    while (test::Packet* next_packet = send_test_->NextPacket()) {
+      nr_bytes += next_packet->payload_length_bytes();
+      delete next_packet;
+    }
+    EXPECT_EQ(expected_total_bits, nr_bytes * 8);
+  }
+
+  void SetUpTest(const char* codec_name,
+                 int codec_sample_rate_hz,
+                 int channels,
+                 int payload_type,
+                 int codec_frame_size_samples,
+                 int codec_frame_size_rtp_timestamps) {
+    ASSERT_TRUE(SetUpSender());
+    ASSERT_TRUE(RegisterSendCodec(codec_name, codec_sample_rate_hz, channels,
+                                  payload_type, codec_frame_size_samples,
+                                  codec_frame_size_rtp_timestamps));
+  }
+
+  rtc::scoped_ptr<test::AcmSendTestOldApi> send_test_;
+  rtc::scoped_ptr<test::InputAudioFile> audio_source_;
+};
+
+TEST_F(AcmSetBitRateOldApi, Opus_48khz_20ms_10kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
+#if defined(WEBRTC_ANDROID)
+  Run(10000, 9328);
+#else
+  Run(10000, 9072);
+#endif // WEBRTC_ANDROID
+
+}
+
+TEST_F(AcmSetBitRateOldApi, Opus_48khz_20ms_50kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
+#if defined(WEBRTC_ANDROID)
+  Run(50000, 47952);
+#else
+  Run(50000, 49600);
+#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.
+TEST_F(AcmSetBitRateOldApi, DISABLED_ON_ANDROID(Opus_48khz_20ms_100kbps)) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
+  Run(100000, 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));
+  Run(8000, 128000);
+}
+
+TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_32kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
+  Run(32000, 128000);
+}
+
+// This test is for verifying the SetBitRate function. The bitrate is changed
+// in the middle, and the number of generated bytes are before and after the
+// change are checked.
+class AcmChangeBitRateOldApi : public AcmSetBitRateOldApi {
+ protected:
+  AcmChangeBitRateOldApi() : sampling_freq_hz_(0), frame_size_samples_(0) {}
+
+  // Registers a send codec in the test::AcmSendTest object. Returns true on
+  // success, false on failure.
+  bool RegisterSendCodec(const char* payload_name,
+                         int sampling_freq_hz,
+                         int channels,
+                         int payload_type,
+                         int frame_size_samples,
+                         int frame_size_rtp_timestamps) override {
+    frame_size_samples_ = frame_size_samples;
+    sampling_freq_hz_ = sampling_freq_hz;
+    return AcmSetBitRateOldApi::RegisterSendCodec(
+        payload_name, sampling_freq_hz, channels, payload_type,
+        frame_size_samples, frame_size_rtp_timestamps);
+  }
+
+  // Runs the test. SetUpSender() and RegisterSendCodec() must have been called
+  // before calling this method.
+  void Run(int target_bitrate_bps,
+           int expected_before_switch_bits,
+           int expected_after_switch_bits) {
+    ASSERT_TRUE(send_test_->acm());
+    int nr_packets =
+        sampling_freq_hz_ * kTestDurationMs / (frame_size_samples_ * 1000);
+    int nr_bytes_before = 0, nr_bytes_after = 0;
+    int packet_counter = 0;
+    while (test::Packet* next_packet = send_test_->NextPacket()) {
+      if (packet_counter == nr_packets / 2)
+        send_test_->acm()->SetBitRate(target_bitrate_bps);
+      if (packet_counter < nr_packets / 2)
+        nr_bytes_before += next_packet->payload_length_bytes();
+      else
+        nr_bytes_after += next_packet->payload_length_bytes();
+      packet_counter++;
+      delete next_packet;
+    }
+    EXPECT_EQ(expected_before_switch_bits, nr_bytes_before * 8);
+    EXPECT_EQ(expected_after_switch_bits, nr_bytes_after * 8);
+  }
+
+  uint32_t sampling_freq_hz_;
+  uint32_t frame_size_samples_;
+};
+
+TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_10kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
+#if defined(WEBRTC_ANDROID)
+  Run(10000, 32200, 5496);
+#else
+  Run(10000, 32200, 5432);
+#endif // WEBRTC_ANDROID
+}
+
+TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_50kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
+#if defined(WEBRTC_ANDROID)
+  Run(50000, 32200, 24912);
+#else
+  Run(50000, 32200, 24792);
+#endif // WEBRTC_ANDROID
+}
+
+TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_100kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
+#if defined(WEBRTC_ANDROID)
+  Run(100000, 32200, 51480);
+#else
+  Run(100000, 32200, 50584);
+#endif // WEBRTC_ANDROID
+}
+
+// These next 2 tests ensure that the SetBitRate function has no effect on PCM
+TEST_F(AcmChangeBitRateOldApi, Pcm16_8khz_10ms_8kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
+  Run(8000, 64000, 64000);
+}
+
+TEST_F(AcmChangeBitRateOldApi, Pcm16_8khz_10ms_32kbps) {
+  ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
+  Run(32000, 64000, 64000);
+}
+
 // This test fixture is implemented to run ACM and change the desired output
 // frequency during the call. The input packets are simply PCM16b-wb encoded
 // payloads with a constant value of |kSampleValue|. The test fixture itself
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
index 6e80be8..d04f280 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
@@ -365,11 +365,7 @@
 
     // Check if a change in Rate is required.
     if (send_codec.rate != send_codec_inst_.rate) {
-      if (current_encoder_->SetBitRate(send_codec.rate) < 0) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
-                     "Could not change the codec rate.");
-        return -1;
-      }
+      current_encoder_->SetBitRate(send_codec.rate);
       send_codec_inst_.rate = send_codec.rate;
     }
 
diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
index 0a14788..4d4a6f3 100644
--- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
+++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h
@@ -264,6 +264,11 @@
   virtual int32_t SendBitrate() const = 0;
 
   ///////////////////////////////////////////////////////////////////////////
+  // Sets the bitrate to the specified value in bits/sec. If the value is not
+  // supported by the codec, it will choose another appropriate value.
+  virtual void SetBitRate(int bitrate_bps) = 0;
+
+  ///////////////////////////////////////////////////////////////////////////
   // int32_t SetReceivedEstimatedBandwidth()
   // Set available bandwidth [bits/sec] of the up-link channel.
   // This information is used for traffic shaping, and is currently only
diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc
index 472ed8b..40a974b 100644
--- a/webrtc/voice_engine/channel.cc
+++ b/webrtc/voice_engine/channel.cc
@@ -1342,6 +1342,12 @@
     return 0;
 }
 
+void Channel::SetBitRate(int bitrate_bps) {
+  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
+               "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
+  audio_coding_->SetBitRate(bitrate_bps);
+}
+
 void Channel::OnIncomingFractionLoss(int fraction_lost) {
   network_predictor_->UpdatePacketLossRate(fraction_lost);
   uint8_t average_fraction_loss = network_predictor_->GetLossRate();
diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h
index e197af8..83924f3 100644
--- a/webrtc/voice_engine/channel.h
+++ b/webrtc/voice_engine/channel.h
@@ -202,6 +202,7 @@
     int32_t GetSendCodec(CodecInst& codec);
     int32_t GetRecCodec(CodecInst& codec);
     int32_t SetSendCodec(const CodecInst& codec);
+    void SetBitRate(int bitrate_bps);
     int32_t SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX);
     int32_t GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX);
     int32_t SetRecPayloadType(const CodecInst& codec);
diff --git a/webrtc/voice_engine/include/voe_codec.h b/webrtc/voice_engine/include/voe_codec.h
index 4b9f939..1e7b97f 100644
--- a/webrtc/voice_engine/include/voe_codec.h
+++ b/webrtc/voice_engine/include/voe_codec.h
@@ -64,6 +64,12 @@
     // |channel|.
     virtual int GetSendCodec(int channel, CodecInst& codec) = 0;
 
+    // Sets the bitrate on a specified |channel| to the specified value
+    // (in bits/sec). If the value is not supported by the codec, the codec will
+    // choose an appropriate value.
+    // Returns -1 on failure and 0 on success.
+    virtual int SetBitRate(int channel, int bitrate_bps) = 0;
+
     // Gets the currently received |codec| for a specific |channel|.
     virtual int GetRecCodec(int channel, CodecInst& codec) = 0;
 
diff --git a/webrtc/voice_engine/test/cmd_test/voe_cmd_test.cc b/webrtc/voice_engine/test/cmd_test/voe_cmd_test.cc
index 419ba55..9133a07 100644
--- a/webrtc/voice_engine/test/cmd_test/voe_cmd_test.cc
+++ b/webrtc/voice_engine/test/cmd_test/voe_cmd_test.cc
@@ -784,8 +784,9 @@
         res = codec->GetSendCodec(chan, cinst);
         VALIDATE;
         printf("Current bit rate is %i bps, set to: ", cinst.rate);
-        ASSERT_EQ(1, scanf("%i", &cinst.rate));
-        res = codec->SetSendCodec(chan, cinst);
+        int new_bitrate_bps;
+        ASSERT_EQ(1, scanf("%i", &new_bitrate_bps));
+        res = codec->SetBitRate(chan, new_bitrate_bps);
         VALIDATE;
       } else if (option_selection == option_index++) {
         const char* kDebugFileName = "audio.aecdump";
diff --git a/webrtc/voice_engine/voe_codec_impl.cc b/webrtc/voice_engine/voe_codec_impl.cc
index 2b0141f..d628fc5 100644
--- a/webrtc/voice_engine/voe_codec_impl.cc
+++ b/webrtc/voice_engine/voe_codec_impl.cc
@@ -180,6 +180,18 @@
     return 0;
 }
 
+int VoECodecImpl::SetBitRate(int channel, int bitrate_bps) {
+  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
+               "SetBitRate(bitrate_bps=%d)", bitrate_bps);
+  if (!_shared->statistics().Initialized()) {
+    _shared->SetLastError(VE_NOT_INITED, kTraceError);
+    return -1;
+  }
+  _shared->channel_manager().GetChannel(channel).channel()->SetBitRate(
+      bitrate_bps);
+  return 0;
+}
+
 int VoECodecImpl::GetRecCodec(int channel, CodecInst& codec)
 {
     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
diff --git a/webrtc/voice_engine/voe_codec_impl.h b/webrtc/voice_engine/voe_codec_impl.h
index dad808d..8e8ac38 100644
--- a/webrtc/voice_engine/voe_codec_impl.h
+++ b/webrtc/voice_engine/voe_codec_impl.h
@@ -29,6 +29,8 @@
 
     virtual int GetSendCodec(int channel, CodecInst& codec);
 
+    int SetBitRate(int channel, int bitrate_bps) override;
+
     virtual int GetRecCodec(int channel, CodecInst& codec);
 
     virtual int SetSendCNPayloadType(