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

@ -21,6 +21,64 @@
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 ::testing::TestWithParam;
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.
const size_t kOpus10msFrameSamples = kOpusRateKhz * 10;
class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
class OpusTest : public TestWithParam<::testing::tuple<int, int, bool>> {
protected:
OpusTest();
@ -74,6 +132,7 @@ class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
size_t encoded_bytes_;
size_t channels_;
int application_;
bool force_multistream_;
};
OpusTest::OpusTest()
@ -81,7 +140,8 @@ OpusTest::OpusTest()
opus_decoder_(NULL),
encoded_bytes_(0),
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,
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;
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate.
EXPECT_EQ(
@ -313,9 +374,10 @@ void OpusTest::TestCbrEffect(bool cbr, int block_length_ms) {
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_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate.
EXPECT_EQ(
@ -376,9 +438,10 @@ TEST(OpusTest, OpusFreeFail) {
// Test normal Create and Free.
TEST_P(OpusTest, OpusCreateFree) {
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
EXPECT_TRUE(opus_encoder_ != NULL);
EXPECT_TRUE(opus_decoder_ != NULL);
// Free encoder and decoder memory.
@ -386,18 +449,19 @@ TEST_P(OpusTest, OpusCreateFree) {
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
}
#define ENCODER_CTL(inst, vargs) \
inst->channels <= 2 \
? opus_encoder_ctl(inst->encoder.encoder, vargs) \
: opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs)
#define ENCODER_CTL(inst, vargs) \
inst->encoder \
? opus_encoder_ctl(inst->encoder, vargs) \
: opus_multistream_encoder_ctl(inst->multistream_encoder, vargs)
TEST_P(OpusTest, OpusEncodeDecode) {
PrepareSpeechData(channels_, 20, 20);
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate.
EXPECT_EQ(
@ -431,8 +495,8 @@ TEST_P(OpusTest, OpusSetBitRate) {
EXPECT_EQ(-1, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
// Create encoder memory, try with different bitrates.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 30000));
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 300000));
@ -447,8 +511,8 @@ TEST_P(OpusTest, OpusSetComplexity) {
EXPECT_EQ(-1, WebRtcOpus_SetComplexity(opus_encoder_, 9));
// Create encoder memory, try with different complexities.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 0));
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 10));
@ -476,9 +540,10 @@ TEST_P(OpusTest, OpusSetBandwidth) {
EXPECT_EQ(-1, WebRtcOpus_GetBandwidth(opus_encoder_));
// Create encoder memory, try with different bandwidths.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
EXPECT_EQ(-1, WebRtcOpus_SetBandwidth(opus_encoder_,
OPUS_BANDWIDTH_NARROWBAND - 1));
@ -506,8 +571,9 @@ TEST_P(OpusTest, OpusForceChannels) {
// Test without creating encoder memory.
EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 1));
ASSERT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
ASSERT_NE(nullptr, opus_encoder_);
if (channels_ >= 2) {
EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 3));
@ -529,9 +595,10 @@ TEST_P(OpusTest, OpusDecodeInit) {
PrepareSpeechData(channels_, 20, 20);
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Encode & decode.
int16_t audio_type;
@ -560,8 +627,8 @@ TEST_P(OpusTest, OpusEnableDisableFec) {
EXPECT_EQ(-1, WebRtcOpus_DisableFec(opus_encoder_));
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_));
@ -576,8 +643,8 @@ TEST_P(OpusTest, OpusEnableDisableDtx) {
EXPECT_EQ(-1, WebRtcOpus_DisableDtx(opus_encoder_));
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
opus_int32 dtx;
@ -633,8 +700,8 @@ TEST_P(OpusTest, OpusSetPacketLossRate) {
EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, -1));
@ -649,8 +716,8 @@ TEST_P(OpusTest, OpusSetMaxPlaybackRate) {
EXPECT_EQ(-1, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, 20000));
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 48000);
SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 24001);
@ -672,9 +739,10 @@ TEST_P(OpusTest, OpusDecodePlc) {
PrepareSpeechData(channels_, 20, 20);
// Create encoder memory.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// Set bitrate.
EXPECT_EQ(
@ -708,9 +776,10 @@ TEST_P(OpusTest, OpusDurationEstimation) {
PrepareSpeechData(channels_, 20, 20);
// Create.
EXPECT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
// 10 ms. We use only first 10 ms of a 20 ms block.
auto speech_block = speech_data_.GetNextBlock();
@ -753,9 +822,12 @@ TEST_P(OpusTest, OpusDecodeRepacketized) {
PrepareSpeechData(channels_, 20, 20 * kPackets);
// Create encoder memory.
ASSERT_EQ(0,
WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
ASSERT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
CreateSingleOrMultiStreamEncoder(&opus_encoder_, channels_, application_,
force_multistream_);
ASSERT_NE(nullptr, opus_encoder_);
CreateSingleOrMultiStreamDecoder(&opus_decoder_, channels_,
force_multistream_);
ASSERT_NE(nullptr, opus_decoder_);
// Set bitrate.
EXPECT_EQ(
@ -812,6 +884,13 @@ TEST_P(OpusTest, OpusDecodeRepacketized) {
INSTANTIATE_TEST_SUITE_P(VariousMode,
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