diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index c394d0cf7..328ef2b6c 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -540,6 +540,7 @@ class FakeWebRtcVoiceEngine 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 c852d8b3e..83febd086 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 @@ OpusApplicationMode ACMGenericCodec::GetOpusApplication( 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 d77543496..69161bdfc 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 @@ class ACMGenericCodec { 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 4918d2149..18570d0d7 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 @@ int AudioCodingModuleImpl::SendBitrate() const { 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 d307cda01..08e10ae9c 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 @@ class AudioCodingModuleImpl : public AudioCodingModule { // 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 81ae8aad1..d2e7cdd94 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_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms_voip) { 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 send_test_; + rtc::scoped_ptr 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 6e80be85b..d04f280d2 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 @@ int CodecManager::RegisterSendCodec(const CodecInst& send_codec) { // 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 0a147885b..4d4a6f325 100644 --- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h +++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h @@ -263,6 +263,11 @@ class AudioCodingModule { // 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. diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index 472ed8b7f..40a974bd3 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -1342,6 +1342,12 @@ Channel::SetSendCodec(const CodecInst& codec) 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 e197af872..83924f3b1 100644 --- a/webrtc/voice_engine/channel.h +++ b/webrtc/voice_engine/channel.h @@ -202,6 +202,7 @@ public: 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 4b9f939ce..1e7b97f01 100644 --- a/webrtc/voice_engine/include/voe_codec.h +++ b/webrtc/voice_engine/include/voe_codec.h @@ -64,6 +64,12 @@ public: // |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 419ba55d7..9133a0796 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 @@ void RunTest(std::string out_path) { 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 2b0141fa8..d628fc5e7 100644 --- a/webrtc/voice_engine/voe_codec_impl.cc +++ b/webrtc/voice_engine/voe_codec_impl.cc @@ -180,6 +180,18 @@ int VoECodecImpl::GetSendCodec(int channel, CodecInst& codec) 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 dad808dbb..8e8ac38cc 100644 --- a/webrtc/voice_engine/voe_codec_impl.h +++ b/webrtc/voice_engine/voe_codec_impl.h @@ -29,6 +29,8 @@ public: 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(