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}
This commit is contained in:
@@ -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];
|
||||
|
@@ -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,
|
||||
|
@@ -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()
|
||||
|
@@ -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.
|
||||
|
@@ -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;
|
||||
|
@@ -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<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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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";
|
||||
|
@@ -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),
|
||||
|
@@ -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(
|
||||
|
Reference in New Issue
Block a user