Adding cbr support for Opus
BUG=webrtc:7394 Review-Url: https://codereview.webrtc.org/2772773002 Cr-Commit-Position: refs/heads/master@{#17564}
This commit is contained in:
1
AUTHORS
1
AUTHORS
@ -62,4 +62,5 @@ Telenor Digital AS <*@telenor.com>
|
|||||||
Temasys Communications <*@temasys.io>
|
Temasys Communications <*@temasys.io>
|
||||||
The Chromium Authors <*@chromium.org>
|
The Chromium Authors <*@chromium.org>
|
||||||
The WebRTC Authors <*@webrtc.org>
|
The WebRTC Authors <*@webrtc.org>
|
||||||
|
Wire Swiss GmbH <*@wire.com>
|
||||||
Vonage Holdings Corp. <*@vonage.com>
|
Vonage Holdings Corp. <*@vonage.com>
|
||||||
|
@ -56,6 +56,7 @@ class AudioEncoderOpus final : public AudioEncoder {
|
|||||||
ApplicationMode application = kVoip;
|
ApplicationMode application = kVoip;
|
||||||
rtc::Optional<int> bitrate_bps; // Unset means to use default value.
|
rtc::Optional<int> bitrate_bps; // Unset means to use default value.
|
||||||
bool fec_enabled = false;
|
bool fec_enabled = false;
|
||||||
|
bool cbr_enabled = false;
|
||||||
int max_playback_rate_hz = 48000;
|
int max_playback_rate_hz = 48000;
|
||||||
int complexity = kDefaultComplexity;
|
int complexity = kDefaultComplexity;
|
||||||
// This value may change in the struct's constructor.
|
// This value may change in the struct's constructor.
|
||||||
|
@ -205,6 +205,22 @@ int16_t WebRtcOpus_DisableDtx(OpusEncInst* inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16_t WebRtcOpus_EnableCbr(OpusEncInst* inst) {
|
||||||
|
if (inst) {
|
||||||
|
return opus_encoder_ctl(inst->encoder, OPUS_SET_VBR(0));
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t WebRtcOpus_DisableCbr(OpusEncInst* inst) {
|
||||||
|
if (inst) {
|
||||||
|
return opus_encoder_ctl(inst->encoder, OPUS_SET_VBR(1));
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity) {
|
int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity) {
|
||||||
if (inst) {
|
if (inst) {
|
||||||
return opus_encoder_ctl(inst->encoder, OPUS_SET_COMPLEXITY(complexity));
|
return opus_encoder_ctl(inst->encoder, OPUS_SET_COMPLEXITY(complexity));
|
||||||
|
@ -180,6 +180,32 @@ int16_t WebRtcOpus_EnableDtx(OpusEncInst* inst);
|
|||||||
*/
|
*/
|
||||||
int16_t WebRtcOpus_DisableDtx(OpusEncInst* inst);
|
int16_t WebRtcOpus_DisableDtx(OpusEncInst* inst);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* WebRtcOpus_EnableCbr()
|
||||||
|
*
|
||||||
|
* This function enables CBR for encoding.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* - inst : Encoder context
|
||||||
|
*
|
||||||
|
* Return value : 0 - Success
|
||||||
|
* -1 - Error
|
||||||
|
*/
|
||||||
|
int16_t WebRtcOpus_EnableCbr(OpusEncInst* inst);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* WebRtcOpus_DisableCbr()
|
||||||
|
*
|
||||||
|
* This function disables CBR for encoding.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* - inst : Encoder context
|
||||||
|
*
|
||||||
|
* Return value : 0 - Success
|
||||||
|
* -1 - Error
|
||||||
|
*/
|
||||||
|
int16_t WebRtcOpus_DisableCbr(OpusEncInst* inst);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WebRtcOpus_SetComplexity(...)
|
* WebRtcOpus_SetComplexity(...)
|
||||||
*
|
*
|
||||||
|
@ -40,6 +40,8 @@ class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
|
|||||||
|
|
||||||
void TestDtxEffect(bool dtx, int block_length_ms);
|
void TestDtxEffect(bool dtx, int block_length_ms);
|
||||||
|
|
||||||
|
void TestCbrEffect(bool dtx, int block_length_ms);
|
||||||
|
|
||||||
// Prepare |speech_data_| for encoding, read from a hard-coded file.
|
// Prepare |speech_data_| for encoding, read from a hard-coded file.
|
||||||
// After preparation, |speech_data_.GetNextBlock()| returns a pointer to a
|
// After preparation, |speech_data_.GetNextBlock()| returns a pointer to a
|
||||||
// block of |block_length_ms| milliseconds. The data is looped every
|
// block of |block_length_ms| milliseconds. The data is looped every
|
||||||
@ -300,6 +302,52 @@ void OpusTest::TestDtxEffect(bool dtx, int block_length_ms) {
|
|||||||
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
|
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test if CBR does what we expect.
|
||||||
|
void OpusTest::TestCbrEffect(bool cbr, int block_length_ms) {
|
||||||
|
PrepareSpeechData(channels_, block_length_ms, 2000);
|
||||||
|
const size_t samples = kOpusRateKhz * block_length_ms;
|
||||||
|
|
||||||
|
int32_t max_pkt_size_diff = 0;
|
||||||
|
int32_t prev_pkt_size = 0;
|
||||||
|
|
||||||
|
// Create encoder memory.
|
||||||
|
EXPECT_EQ(0,
|
||||||
|
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
|
||||||
|
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
|
||||||
|
|
||||||
|
// Set bitrate.
|
||||||
|
EXPECT_EQ(
|
||||||
|
0, WebRtcOpus_SetBitRate(opus_encoder_, channels_ == 1 ? 32000 : 64000));
|
||||||
|
|
||||||
|
// Setting CBR.
|
||||||
|
EXPECT_EQ(0, cbr ? WebRtcOpus_EnableCbr(opus_encoder_)
|
||||||
|
: WebRtcOpus_DisableCbr(opus_encoder_));
|
||||||
|
|
||||||
|
int16_t audio_type;
|
||||||
|
std::vector<int16_t> audio_out(samples * channels_);
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
EXPECT_EQ(samples, static_cast<size_t>(EncodeDecode(
|
||||||
|
opus_encoder_, speech_data_.GetNextBlock(),
|
||||||
|
opus_decoder_, audio_out.data(), &audio_type)));
|
||||||
|
|
||||||
|
if (prev_pkt_size > 0) {
|
||||||
|
int32_t diff = std::abs((int32_t)encoded_bytes_ - prev_pkt_size);
|
||||||
|
max_pkt_size_diff = std::max(max_pkt_size_diff, diff);
|
||||||
|
}
|
||||||
|
prev_pkt_size = encoded_bytes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbr) {
|
||||||
|
EXPECT_EQ(max_pkt_size_diff, 0);
|
||||||
|
} else {
|
||||||
|
EXPECT_GT(max_pkt_size_diff, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free memory.
|
||||||
|
EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
|
||||||
|
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
|
||||||
|
}
|
||||||
|
|
||||||
// Test failing Create.
|
// Test failing Create.
|
||||||
TEST(OpusTest, OpusCreateFail) {
|
TEST(OpusTest, OpusCreateFail) {
|
||||||
WebRtcOpusEncInst* opus_encoder;
|
WebRtcOpusEncInst* opus_encoder;
|
||||||
@ -525,6 +573,18 @@ TEST_P(OpusTest, OpusDtxOn) {
|
|||||||
TestDtxEffect(true, 40);
|
TestDtxEffect(true, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(OpusTest, OpusCbrOff) {
|
||||||
|
TestCbrEffect(false, 10);
|
||||||
|
TestCbrEffect(false, 20);
|
||||||
|
TestCbrEffect(false, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OpusTest, OpusCbrOn) {
|
||||||
|
TestCbrEffect(true, 10);
|
||||||
|
TestCbrEffect(true, 20);
|
||||||
|
TestCbrEffect(true, 40);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(OpusTest, OpusSetPacketLossRate) {
|
TEST_P(OpusTest, OpusSetPacketLossRate) {
|
||||||
// Test without creating encoder memory.
|
// Test without creating encoder memory.
|
||||||
EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
|
EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
|
||||||
|
Reference in New Issue
Block a user