Generalize the C-language Opus interface.

Switch to explicit channel mappings (RFC 7845) when creating
multi-stream Opus en/de-coders. The responsibility of setting up the
channel mappings will shift from WebRTC to the WebRTC user.

See https://webrtc-review.googlesource.com/c/src/+/121764 for the
current vision. See also the first child CL
https://webrtc-review.googlesource.com/c/src/+/129768
that sets up the Decoder to use this code.

Bug: webrtc:8649
Change-Id: I55959a293d54bb4c982eff68ec107c5ef8666c5c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/129767
Commit-Queue: Alex Loiko <aleloi@webrtc.org>
Reviewed-by: Oskar Sundbom <ossu@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27452}
This commit is contained in:
Alex Loiko
2019-04-03 15:12:01 +02:00
committed by Commit Bot
parent 21f6fd79ad
commit 50b8c399c9
5 changed files with 311 additions and 165 deletions

View File

@ -1510,7 +1510,9 @@ TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms) {
test::AcmReceiveTestOldApi::kStereoOutput); test::AcmReceiveTestOldApi::kStereoOutput);
} }
TEST_F(AcmSenderBitExactnessNewApi, OpusManyChannels) { // TODO(webrtc:8649): Disabled until the Encoder counterpart of
// https://webrtc-review.googlesource.com/c/src/+/129768 lands.
TEST_F(AcmSenderBitExactnessNewApi, DISABLED_OpusManyChannels) {
constexpr int kNumChannels = 4; constexpr int kNumChannels = 4;
constexpr int kOpusPayloadType = 120; constexpr int kOpusPayloadType = 120;
constexpr int kBitrateBps = 128000; constexpr int kBitrateBps = 128000;

View File

@ -21,19 +21,15 @@ RTC_PUSH_IGNORING_WUNDEF()
RTC_POP_IGNORING_WUNDEF() RTC_POP_IGNORING_WUNDEF()
struct WebRtcOpusEncInst { struct WebRtcOpusEncInst {
union { OpusEncoder* encoder;
OpusEncoder* encoder; OpusMSEncoder* multistream_encoder;
OpusMSEncoder* multistream_encoder;
} encoder;
size_t channels; size_t channels;
int in_dtx_mode; int in_dtx_mode;
}; };
struct WebRtcOpusDecInst { struct WebRtcOpusDecInst {
union { OpusDecoder* decoder;
OpusDecoder* decoder; OpusMSDecoder* multistream_decoder;
OpusMSDecoder* multistream_decoder;
} decoder;
int prev_decoded_samples; int prev_decoded_samples;
size_t channels; size_t channels;
int in_dtx_mode; int in_dtx_mode;

View File

@ -37,40 +37,6 @@ enum {
kWebRtcOpusDefaultFrameSize = 960, kWebRtcOpusDefaultFrameSize = 960,
}; };
int16_t GetSurroundParameters(int channels,
int *streams,
int *coupled_streams,
unsigned char *mapping) {
int opus_error;
int ret = 0;
// Use 'surround encoder create' to get values for 'coupled_streams',
// 'streams' and 'mapping'.
OpusMSEncoder* ms_encoder_ptr = opus_multistream_surround_encoder_create(
48000,
channels,
/* mapping family */ channels <= 2 ? 0 : 1,
streams,
coupled_streams,
mapping,
OPUS_APPLICATION_VOIP, // Application type shouldn't affect
// streams/mapping values.
&opus_error);
// This shouldn't fail; if it fails,
// signal an error and return invalid values.
if (opus_error != OPUS_OK || ms_encoder_ptr == NULL) {
ret = -1;
*streams = -1;
*coupled_streams = -1;
}
// We don't need the encoder.
if (ms_encoder_ptr != NULL) {
opus_multistream_encoder_destroy(ms_encoder_ptr);
}
return ret;
}
int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
size_t channels, size_t channels,
int32_t application) { int32_t application) {
@ -93,30 +59,60 @@ int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
RTC_DCHECK(state); RTC_DCHECK(state);
int error; int error;
if (channels <= 2) { state->encoder = opus_encoder_create(48000, (int)channels, opus_app,
state->encoder.encoder = opus_encoder_create(48000, (int)channels, opus_app, &error);
&error);
} else { if (error != OPUS_OK || (!state->encoder &&
unsigned char mapping[255]; !state->multistream_encoder)) {
memset(mapping, 0, 255); WebRtcOpus_EncoderFree(state);
int streams = -1; return -1;
int coupled_streams = -1;
state->encoder.multistream_encoder =
opus_multistream_surround_encoder_create(
48000,
channels,
/* mapping family */ 1,
&streams,
&coupled_streams,
mapping,
opus_app,
&error);
} }
if (error != OPUS_OK || (!state->encoder.encoder && state->in_dtx_mode = 0;
!state->encoder.multistream_encoder)) { state->channels = channels;
*inst = state;
return 0;
}
int16_t WebRtcOpus_MultistreamEncoderCreate(
OpusEncInst** inst,
size_t channels,
int32_t application,
size_t coupled_streams,
const unsigned char *channel_mapping) {
int opus_app;
if (!inst)
return -1;
switch (application) {
case 0:
opus_app = OPUS_APPLICATION_VOIP;
break;
case 1:
opus_app = OPUS_APPLICATION_AUDIO;
break;
default:
return -1;
}
OpusEncInst* state = (OpusEncInst*)calloc(1, sizeof(OpusEncInst));
RTC_DCHECK(state);
int streams = channels - coupled_streams;
int error;
state->multistream_encoder =
opus_multistream_encoder_create(
48000,
channels,
streams,
coupled_streams,
channel_mapping,
opus_app,
&error);
if (error != OPUS_OK || (!state->encoder &&
!state->multistream_encoder)) {
WebRtcOpus_EncoderFree(state); WebRtcOpus_EncoderFree(state);
return -1; return -1;
} }
@ -130,10 +126,10 @@ int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) { int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) {
if (inst) { if (inst) {
if (inst->channels <= 2) { if (inst->encoder) {
opus_encoder_destroy(inst->encoder.encoder); opus_encoder_destroy(inst->encoder);
} else { } else {
opus_multistream_encoder_destroy(inst->encoder.multistream_encoder); opus_multistream_encoder_destroy(inst->multistream_encoder);
} }
free(inst); free(inst);
return 0; return 0;
@ -153,14 +149,14 @@ int WebRtcOpus_Encode(OpusEncInst* inst,
return -1; return -1;
} }
if (inst->channels <= 2) { if (inst->encoder) {
res = opus_encode(inst->encoder.encoder, res = opus_encode(inst->encoder,
(const opus_int16*)audio_in, (const opus_int16*)audio_in,
(int)samples, (int)samples,
encoded, encoded,
(opus_int32)length_encoded_buffer); (opus_int32)length_encoded_buffer);
} else { } else {
res = opus_multistream_encode(inst->encoder.multistream_encoder, res = opus_multistream_encode(inst->multistream_encoder,
(const opus_int16*)audio_in, (const opus_int16*)audio_in,
(int)samples, (int)samples,
encoded, encoded,
@ -187,10 +183,10 @@ int WebRtcOpus_Encode(OpusEncInst* inst,
return res; return res;
} }
#define ENCODER_CTL(inst, vargs) ( \ #define ENCODER_CTL(inst, vargs) ( \
inst->channels <= 2 ? \ inst->encoder ? \
opus_encoder_ctl(inst->encoder.encoder, vargs) \ opus_encoder_ctl(inst->encoder, vargs) \
: opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs)) : opus_multistream_encoder_ctl(inst->multistream_encoder, vargs))
int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate) { int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate) {
@ -231,9 +227,9 @@ int16_t WebRtcOpus_SetMaxPlaybackRate(OpusEncInst* inst, int32_t frequency_hz) {
int16_t WebRtcOpus_GetMaxPlaybackRate(OpusEncInst* const inst, int16_t WebRtcOpus_GetMaxPlaybackRate(OpusEncInst* const inst,
int32_t* result_hz) { int32_t* result_hz) {
if (inst->channels <= 2) { if (inst->encoder) {
if (opus_encoder_ctl( if (opus_encoder_ctl(
inst->encoder.encoder, inst->encoder,
OPUS_GET_MAX_BANDWIDTH(result_hz)) == OPUS_OK) { OPUS_GET_MAX_BANDWIDTH(result_hz)) == OPUS_OK) {
return 0; return 0;
} }
@ -388,30 +384,10 @@ int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels) {
return -1; return -1;
} }
if (channels <= 2) { // Create new memory, always at 48000 Hz.
state->decoder.decoder = opus_decoder_create(48000, state->decoder = opus_decoder_create(48000,
(int)channels, &error); (int)channels, &error);
} else { if (error == OPUS_OK && state->decoder) {
unsigned char mapping[255];
memset(mapping, 0, 255);
int streams = -1;
int coupled_streams = -1;
if (GetSurroundParameters(channels, &streams,
&coupled_streams, mapping) != 0) {
free(state);
return -1;
}
// Create new memory, always at 48000 Hz.
state->decoder.multistream_decoder = opus_multistream_decoder_create(
48000, (int)channels,
/* streams = */ streams,
/* coupled streams = */ coupled_streams,
mapping,
&error);
}
if (error == OPUS_OK && (state->decoder.decoder ||
state->decoder.multistream_decoder)) {
// Creation of memory all ok. // Creation of memory all ok.
state->channels = channels; state->channels = channels;
state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize; state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize;
@ -421,23 +397,60 @@ int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels) {
} }
// If memory allocation was unsuccessful, free the entire state. // If memory allocation was unsuccessful, free the entire state.
if (state->decoder.decoder) { if (state->decoder) {
opus_decoder_destroy(state->decoder.decoder); opus_decoder_destroy(state->decoder);
} else if (state->decoder.multistream_decoder) {
opus_multistream_decoder_destroy(state->decoder.multistream_decoder);
} }
free(state); free(state);
} }
return -1; return -1;
} }
int16_t WebRtcOpus_MultistreamDecoderCreate(
OpusDecInst** inst, size_t channels,
size_t coupled_streams,
const unsigned char* channel_mapping) {
int error;
OpusDecInst* state;
if (inst != NULL) {
// Create Opus decoder state.
state = (OpusDecInst*) calloc(1, sizeof(OpusDecInst));
if (state == NULL) {
return -1;
}
int streams = channels - coupled_streams;
// Create new memory, always at 48000 Hz.
state->multistream_decoder = opus_multistream_decoder_create(
48000, (int)channels,
streams,
coupled_streams,
channel_mapping,
&error);
if (error == OPUS_OK && state->multistream_decoder) {
// Creation of memory all ok.
state->channels = channels;
state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize;
state->in_dtx_mode = 0;
*inst = state;
return 0;
}
// If memory allocation was unsuccessful, free the entire state.
opus_multistream_decoder_destroy(state->multistream_decoder);
free(state);
}
return -1;
}
int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst) { int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst) {
if (inst) { if (inst) {
if (inst->channels <= 2) { if (inst->decoder) {
opus_decoder_destroy(inst->decoder.decoder); opus_decoder_destroy(inst->decoder);
} else if (inst->channels > 2) { } else if (inst->multistream_decoder) {
opus_multistream_decoder_destroy(inst->decoder.multistream_decoder); opus_multistream_decoder_destroy(inst->multistream_decoder);
} }
free(inst); free(inst);
return 0; return 0;
@ -451,10 +464,10 @@ size_t WebRtcOpus_DecoderChannels(OpusDecInst* inst) {
} }
void WebRtcOpus_DecoderInit(OpusDecInst* inst) { void WebRtcOpus_DecoderInit(OpusDecInst* inst) {
if (inst->channels <= 2) { if (inst->decoder) {
opus_decoder_ctl(inst->decoder.decoder, OPUS_RESET_STATE); opus_decoder_ctl(inst->decoder, OPUS_RESET_STATE);
} else { } else {
opus_multistream_decoder_ctl(inst->decoder.multistream_decoder, opus_multistream_decoder_ctl(inst->multistream_decoder,
OPUS_RESET_STATE); OPUS_RESET_STATE);
} }
inst->in_dtx_mode = 0; inst->in_dtx_mode = 0;
@ -490,12 +503,12 @@ static int DecodeNative(OpusDecInst* inst, const uint8_t* encoded,
size_t encoded_bytes, int frame_size, size_t encoded_bytes, int frame_size,
int16_t* decoded, int16_t* audio_type, int decode_fec) { int16_t* decoded, int16_t* audio_type, int decode_fec) {
int res = -1; int res = -1;
if (inst->channels <= 2) { if (inst->decoder) {
res = opus_decode(inst->decoder.decoder, encoded, (opus_int32)encoded_bytes, res = opus_decode(inst->decoder, encoded, (opus_int32)encoded_bytes,
(opus_int16*)decoded, frame_size, decode_fec); (opus_int16*)decoded, frame_size, decode_fec);
} else { } else {
res = opus_multistream_decode( res = opus_multistream_decode(
inst->decoder.multistream_decoder, encoded, (opus_int32)encoded_bytes, inst->multistream_decoder, encoded, (opus_int32)encoded_bytes,
(opus_int16*)decoded, frame_size, decode_fec); (opus_int16*)decoded, frame_size, decode_fec);
} }

View File

@ -27,10 +27,10 @@ typedef struct WebRtcOpusDecInst OpusDecInst;
/**************************************************************************** /****************************************************************************
* WebRtcOpus_EncoderCreate(...) * WebRtcOpus_EncoderCreate(...)
* *
* This function create an Opus encoder. * This function creates an Opus encoder that encodes mono or stereo.
* *
* Input: * Input:
* - channels : number of channels. * - channels : number of channels; 1 or 2.
* - application : 0 - VOIP applications. * - application : 0 - VOIP applications.
* Favor speech intelligibility. * Favor speech intelligibility.
* 1 - Audio applications. * 1 - Audio applications.
@ -47,6 +47,36 @@ int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
size_t channels, size_t channels,
int32_t application); int32_t application);
/****************************************************************************
* WebRtcOpus_MultistreamEncoderCreate(...)
*
* This function creates an Opus encoder with any supported channel count.
*
* Input:
* - channels : number of channels.
* - application : 0 - VOIP applications.
* Favor speech intelligibility.
* 1 - Audio applications.
* Favor faithfulness to the original input.
* - coupled_streams : number of coupled streams, as described in
* RFC 7845.
* - channel_mapping : the channel mapping; pointer to array of
* `channel` bytes, as described in RFC 7845.
*
* Output:
* - inst : a pointer to Encoder context that is created
* if success.
*
* Return value : 0 - Success
* -1 - Error
*/
int16_t WebRtcOpus_MultistreamEncoderCreate(
OpusEncInst** inst,
size_t channels,
int32_t application,
size_t coupled_streams,
const unsigned char* channel_mapping);
int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst); int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst);
/**************************************************************************** /****************************************************************************
@ -295,6 +325,32 @@ int16_t WebRtcOpus_SetBandwidth(OpusEncInst* inst, int32_t bandwidth);
int16_t WebRtcOpus_SetForceChannels(OpusEncInst* inst, size_t num_channels); int16_t WebRtcOpus_SetForceChannels(OpusEncInst* inst, size_t num_channels);
int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels); int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels);
/****************************************************************************
* WebRtcOpus_MultistreamDecoderCreate(...)
*
* This function creates an Opus decoder with any supported channel count.
*
* Input:
* - channels : number of channels.
* - coupled_streams : number of coupled streams, as described in
* RFC 7845.
* - channel_mapping : the channel mapping; pointer to array of
* `channel` bytes, as described in RFC 7845.
*
* Output:
* - inst : a pointer to a Decoder context that is created
* if success.
*
* Return value : 0 - Success
* -1 - Error
*/
int16_t WebRtcOpus_MultistreamDecoderCreate(
OpusDecInst** inst,
size_t channels,
size_t coupled_streams,
const unsigned char* channel_mapping);
int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst); int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst);
/**************************************************************************** /****************************************************************************

View File

@ -21,6 +21,64 @@
namespace webrtc { namespace webrtc {
namespace {
// Equivalent to SDP params
// {{"channel_mapping", "0,1,2,3"}, {"coupled_streams", "2"}}.
constexpr unsigned char kQuadChannelMapping[] = {0, 1, 2, 3};
constexpr int kQuadCoupledStreams = 2;
constexpr unsigned char kStereoChannelMapping[] = {0, 1};
constexpr int kStereoCoupledStreams = 1;
constexpr unsigned char kMonoChannelMapping[] = {0};
constexpr int kMonoCoupledStreams = 0;
void CreateSingleOrMultiStreamEncoder(WebRtcOpusEncInst** opus_encoder,
int channels,
int application,
bool force_multistream = false) {
if (!force_multistream && (channels == 1 || channels == 2)) {
EXPECT_EQ(0, WebRtcOpus_EncoderCreate(opus_encoder, channels, application));
} else if (force_multistream && channels == 1) {
EXPECT_EQ(0, WebRtcOpus_MultistreamEncoderCreate(
opus_encoder, channels, application, kMonoCoupledStreams,
kMonoChannelMapping));
} else if (force_multistream && channels == 2) {
EXPECT_EQ(0, WebRtcOpus_MultistreamEncoderCreate(
opus_encoder, channels, application, kStereoCoupledStreams,
kStereoChannelMapping));
} else if (channels == 4) {
EXPECT_EQ(0, WebRtcOpus_MultistreamEncoderCreate(
opus_encoder, channels, application, kQuadCoupledStreams,
kQuadChannelMapping));
} else {
EXPECT_TRUE(false) << channels;
}
}
void CreateSingleOrMultiStreamDecoder(WebRtcOpusDecInst** opus_decoder,
int channels,
bool force_multistream = false) {
if (!force_multistream && (channels == 1 || channels == 2)) {
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(opus_decoder, channels));
} else if (channels == 1) {
EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(opus_decoder, channels,
kMonoCoupledStreams,
kMonoChannelMapping));
} else if (channels == 2) {
EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(opus_decoder, channels,
kStereoCoupledStreams,
kStereoChannelMapping));
} else if (channels == 4) {
EXPECT_EQ(0, WebRtcOpus_MultistreamDecoderCreate(opus_decoder, channels,
kQuadCoupledStreams,
kQuadChannelMapping));
} else {
EXPECT_TRUE(false) << channels;
}
}
} // namespace
using test::AudioLoop; using test::AudioLoop;
using ::testing::TestWithParam; using ::testing::TestWithParam;
using ::testing::Values; using ::testing::Values;
@ -35,7 +93,7 @@ const size_t kOpus20msFrameSamples = kOpusRateKhz * 20;
// Number of samples-per-channel in a 10 ms frame, sampled at 48 kHz. // Number of samples-per-channel in a 10 ms frame, sampled at 48 kHz.
const size_t kOpus10msFrameSamples = kOpusRateKhz * 10; const size_t kOpus10msFrameSamples = kOpusRateKhz * 10;
class OpusTest : public TestWithParam<::testing::tuple<int, int>> { class OpusTest : public TestWithParam<::testing::tuple<int, int, bool>> {
protected: protected:
OpusTest(); OpusTest();
@ -74,6 +132,7 @@ class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
size_t encoded_bytes_; size_t encoded_bytes_;
size_t channels_; size_t channels_;
int application_; int application_;
bool force_multistream_;
}; };
OpusTest::OpusTest() OpusTest::OpusTest()
@ -81,7 +140,8 @@ OpusTest::OpusTest()
opus_decoder_(NULL), opus_decoder_(NULL),
encoded_bytes_(0), encoded_bytes_(0),
channels_(static_cast<size_t>(::testing::get<0>(GetParam()))), channels_(static_cast<size_t>(::testing::get<0>(GetParam()))),
application_(::testing::get<1>(GetParam())) {} application_(::testing::get<1>(GetParam())),
force_multistream_(::testing::get<2>(GetParam())) {}
void OpusTest::PrepareSpeechData(size_t channel, void OpusTest::PrepareSpeechData(size_t channel,
int block_length_ms, int block_length_ms,
@ -148,9 +208,10 @@ void OpusTest::TestDtxEffect(bool dtx, int block_length_ms) {
const size_t samples = kOpusRateKhz * block_length_ms; const size_t samples = kOpusRateKhz * block_length_ms;
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate. // Set bitrate.
EXPECT_EQ( EXPECT_EQ(
@ -313,9 +374,10 @@ void OpusTest::TestCbrEffect(bool cbr, int block_length_ms) {
int32_t prev_pkt_size = 0; int32_t prev_pkt_size = 0;
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate. // Set bitrate.
EXPECT_EQ( EXPECT_EQ(
@ -376,9 +438,10 @@ TEST(OpusTest, OpusFreeFail) {
// Test normal Create and Free. // Test normal Create and Free.
TEST_P(OpusTest, OpusCreateFree) { TEST_P(OpusTest, OpusCreateFree) {
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
EXPECT_TRUE(opus_encoder_ != NULL); EXPECT_TRUE(opus_encoder_ != NULL);
EXPECT_TRUE(opus_decoder_ != NULL); EXPECT_TRUE(opus_decoder_ != NULL);
// Free encoder and decoder memory. // Free encoder and decoder memory.
@ -386,18 +449,19 @@ TEST_P(OpusTest, OpusCreateFree) {
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_)); EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
} }
#define ENCODER_CTL(inst, vargs) \ #define ENCODER_CTL(inst, vargs) \
inst->channels <= 2 \ inst->encoder \
? opus_encoder_ctl(inst->encoder.encoder, vargs) \ ? opus_encoder_ctl(inst->encoder, vargs) \
: opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs) : opus_multistream_encoder_ctl(inst->multistream_encoder, vargs)
TEST_P(OpusTest, OpusEncodeDecode) { TEST_P(OpusTest, OpusEncodeDecode) {
PrepareSpeechData(channels_, 20, 20); PrepareSpeechData(channels_, 20, 20);
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate. // Set bitrate.
EXPECT_EQ( EXPECT_EQ(
@ -431,8 +495,8 @@ TEST_P(OpusTest, OpusSetBitRate) {
EXPECT_EQ(-1, WebRtcOpus_SetBitRate(opus_encoder_, 60000)); EXPECT_EQ(-1, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
// Create encoder memory, try with different bitrates. // Create encoder memory, try with different bitrates.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 30000)); EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 30000));
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 60000)); EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 300000)); EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 300000));
@ -447,8 +511,8 @@ TEST_P(OpusTest, OpusSetComplexity) {
EXPECT_EQ(-1, WebRtcOpus_SetComplexity(opus_encoder_, 9)); EXPECT_EQ(-1, WebRtcOpus_SetComplexity(opus_encoder_, 9));
// Create encoder memory, try with different complexities. // Create encoder memory, try with different complexities.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 0)); EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 0));
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 10)); EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 10));
@ -476,9 +540,10 @@ TEST_P(OpusTest, OpusSetBandwidth) {
EXPECT_EQ(-1, WebRtcOpus_GetBandwidth(opus_encoder_)); EXPECT_EQ(-1, WebRtcOpus_GetBandwidth(opus_encoder_));
// Create encoder memory, try with different bandwidths. // Create encoder memory, try with different bandwidths.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
EXPECT_EQ(-1, WebRtcOpus_SetBandwidth(opus_encoder_, EXPECT_EQ(-1, WebRtcOpus_SetBandwidth(opus_encoder_,
OPUS_BANDWIDTH_NARROWBAND - 1)); OPUS_BANDWIDTH_NARROWBAND - 1));
@ -506,8 +571,9 @@ TEST_P(OpusTest, OpusForceChannels) {
// Test without creating encoder memory. // Test without creating encoder memory.
EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 1)); EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 1));
ASSERT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
ASSERT_NE(nullptr, opus_encoder_);
if (channels_ >= 2) { if (channels_ >= 2) {
EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 3)); EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 3));
@ -529,9 +595,10 @@ TEST_P(OpusTest, OpusDecodeInit) {
PrepareSpeechData(channels_, 20, 20); PrepareSpeechData(channels_, 20, 20);
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Encode & decode. // Encode & decode.
int16_t audio_type; int16_t audio_type;
@ -560,8 +627,8 @@ TEST_P(OpusTest, OpusEnableDisableFec) {
EXPECT_EQ(-1, WebRtcOpus_DisableFec(opus_encoder_)); EXPECT_EQ(-1, WebRtcOpus_DisableFec(opus_encoder_));
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_)); EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_)); EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_));
@ -576,8 +643,8 @@ TEST_P(OpusTest, OpusEnableDisableDtx) {
EXPECT_EQ(-1, WebRtcOpus_DisableDtx(opus_encoder_)); EXPECT_EQ(-1, WebRtcOpus_DisableDtx(opus_encoder_));
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
opus_int32 dtx; opus_int32 dtx;
@ -633,8 +700,8 @@ TEST_P(OpusTest, OpusSetPacketLossRate) {
EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50)); EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50)); EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, -1)); EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, -1));
@ -649,8 +716,8 @@ TEST_P(OpusTest, OpusSetMaxPlaybackRate) {
EXPECT_EQ(-1, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, 20000)); EXPECT_EQ(-1, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, 20000));
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 48000); SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 48000);
SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 24001); SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 24001);
@ -672,9 +739,10 @@ TEST_P(OpusTest, OpusDecodePlc) {
PrepareSpeechData(channels_, 20, 20); PrepareSpeechData(channels_, 20, 20);
// Create encoder memory. // Create encoder memory.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate. // Set bitrate.
EXPECT_EQ( EXPECT_EQ(
@ -708,9 +776,10 @@ TEST_P(OpusTest, OpusDurationEstimation) {
PrepareSpeechData(channels_, 20, 20); PrepareSpeechData(channels_, 20, 20);
// Create. // Create.
EXPECT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// 10 ms. We use only first 10 ms of a 20 ms block. // 10 ms. We use only first 10 ms of a 20 ms block.
auto speech_block = speech_data_.GetNextBlock(); auto speech_block = speech_data_.GetNextBlock();
@ -753,9 +822,12 @@ TEST_P(OpusTest, OpusDecodeRepacketized) {
PrepareSpeechData(channels_, 20, 20 * kPackets); PrepareSpeechData(channels_, 20, 20 * kPackets);
// Create encoder memory. // Create encoder memory.
ASSERT_EQ(0, CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); force_multistream_);
ASSERT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_)); ASSERT_NE(nullptr, opus_encoder_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
ASSERT_NE(nullptr, opus_decoder_);
// Set bitrate. // Set bitrate.
EXPECT_EQ( EXPECT_EQ(
@ -812,6 +884,13 @@ TEST_P(OpusTest, OpusDecodeRepacketized) {
INSTANTIATE_TEST_SUITE_P(VariousMode, INSTANTIATE_TEST_SUITE_P(VariousMode,
OpusTest, OpusTest,
Combine(Values(1, 2, 4), Values(0, 1))); ::testing::ValuesIn({
std::make_tuple(1, 0, true),
std::make_tuple(1, 1, true),
std::make_tuple(2, 0, false),
std::make_tuple(4, 0, false),
std::make_tuple(1, 1, false),
std::make_tuple(4, 1, false),
}));
} // namespace webrtc } // namespace webrtc