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:
@ -37,40 +37,6 @@ enum {
|
||||
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,
|
||||
size_t channels,
|
||||
int32_t application) {
|
||||
@ -93,30 +59,60 @@ int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
|
||||
RTC_DCHECK(state);
|
||||
|
||||
int error;
|
||||
if (channels <= 2) {
|
||||
state->encoder.encoder = opus_encoder_create(48000, (int)channels, opus_app,
|
||||
&error);
|
||||
state->encoder = opus_encoder_create(48000, (int)channels, opus_app,
|
||||
&error);
|
||||
|
||||
} else {
|
||||
unsigned char mapping[255];
|
||||
memset(mapping, 0, 255);
|
||||
int streams = -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 &&
|
||||
!state->multistream_encoder)) {
|
||||
WebRtcOpus_EncoderFree(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (error != OPUS_OK || (!state->encoder.encoder &&
|
||||
!state->encoder.multistream_encoder)) {
|
||||
state->in_dtx_mode = 0;
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
@ -130,10 +126,10 @@ int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
|
||||
|
||||
int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) {
|
||||
if (inst) {
|
||||
if (inst->channels <= 2) {
|
||||
opus_encoder_destroy(inst->encoder.encoder);
|
||||
if (inst->encoder) {
|
||||
opus_encoder_destroy(inst->encoder);
|
||||
} else {
|
||||
opus_multistream_encoder_destroy(inst->encoder.multistream_encoder);
|
||||
opus_multistream_encoder_destroy(inst->multistream_encoder);
|
||||
}
|
||||
free(inst);
|
||||
return 0;
|
||||
@ -153,14 +149,14 @@ int WebRtcOpus_Encode(OpusEncInst* inst,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inst->channels <= 2) {
|
||||
res = opus_encode(inst->encoder.encoder,
|
||||
if (inst->encoder) {
|
||||
res = opus_encode(inst->encoder,
|
||||
(const opus_int16*)audio_in,
|
||||
(int)samples,
|
||||
encoded,
|
||||
(opus_int32)length_encoded_buffer);
|
||||
} else {
|
||||
res = opus_multistream_encode(inst->encoder.multistream_encoder,
|
||||
res = opus_multistream_encode(inst->multistream_encoder,
|
||||
(const opus_int16*)audio_in,
|
||||
(int)samples,
|
||||
encoded,
|
||||
@ -187,10 +183,10 @@ int WebRtcOpus_Encode(OpusEncInst* inst,
|
||||
return res;
|
||||
}
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
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,
|
||||
int32_t* result_hz) {
|
||||
if (inst->channels <= 2) {
|
||||
if (inst->encoder) {
|
||||
if (opus_encoder_ctl(
|
||||
inst->encoder.encoder,
|
||||
inst->encoder,
|
||||
OPUS_GET_MAX_BANDWIDTH(result_hz)) == OPUS_OK) {
|
||||
return 0;
|
||||
}
|
||||
@ -388,30 +384,10 @@ int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channels <= 2) {
|
||||
state->decoder.decoder = opus_decoder_create(48000,
|
||||
(int)channels, &error);
|
||||
} else {
|
||||
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)) {
|
||||
// Create new memory, always at 48000 Hz.
|
||||
state->decoder = opus_decoder_create(48000,
|
||||
(int)channels, &error);
|
||||
if (error == OPUS_OK && state->decoder) {
|
||||
// Creation of memory all ok.
|
||||
state->channels = channels;
|
||||
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 (state->decoder.decoder) {
|
||||
opus_decoder_destroy(state->decoder.decoder);
|
||||
|
||||
} else if (state->decoder.multistream_decoder) {
|
||||
opus_multistream_decoder_destroy(state->decoder.multistream_decoder);
|
||||
if (state->decoder) {
|
||||
opus_decoder_destroy(state->decoder);
|
||||
}
|
||||
free(state);
|
||||
}
|
||||
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) {
|
||||
if (inst) {
|
||||
if (inst->channels <= 2) {
|
||||
opus_decoder_destroy(inst->decoder.decoder);
|
||||
} else if (inst->channels > 2) {
|
||||
opus_multistream_decoder_destroy(inst->decoder.multistream_decoder);
|
||||
if (inst->decoder) {
|
||||
opus_decoder_destroy(inst->decoder);
|
||||
} else if (inst->multistream_decoder) {
|
||||
opus_multistream_decoder_destroy(inst->multistream_decoder);
|
||||
}
|
||||
free(inst);
|
||||
return 0;
|
||||
@ -451,10 +464,10 @@ size_t WebRtcOpus_DecoderChannels(OpusDecInst* inst) {
|
||||
}
|
||||
|
||||
void WebRtcOpus_DecoderInit(OpusDecInst* inst) {
|
||||
if (inst->channels <= 2) {
|
||||
opus_decoder_ctl(inst->decoder.decoder, OPUS_RESET_STATE);
|
||||
if (inst->decoder) {
|
||||
opus_decoder_ctl(inst->decoder, OPUS_RESET_STATE);
|
||||
} else {
|
||||
opus_multistream_decoder_ctl(inst->decoder.multistream_decoder,
|
||||
opus_multistream_decoder_ctl(inst->multistream_decoder,
|
||||
OPUS_RESET_STATE);
|
||||
}
|
||||
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,
|
||||
int16_t* decoded, int16_t* audio_type, int decode_fec) {
|
||||
int res = -1;
|
||||
if (inst->channels <= 2) {
|
||||
res = opus_decode(inst->decoder.decoder, encoded, (opus_int32)encoded_bytes,
|
||||
if (inst->decoder) {
|
||||
res = opus_decode(inst->decoder, encoded, (opus_int32)encoded_bytes,
|
||||
(opus_int16*)decoded, frame_size, decode_fec);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user