diff --git a/libcelt/opus_defines.h b/libcelt/opus_defines.h index ac1c4662..4445be7b 100644 --- a/libcelt/opus_defines.h +++ b/libcelt/opus_defines.h @@ -103,6 +103,8 @@ extern "C" { #define OPUS_SET_DTX_REQUEST 4016 #define OPUS_GET_DTX_REQUEST 4017 #define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_SET_RESTRICTED_LOWDELAY_REQUEST 4032 +#define OPUS_GET_RESTRICTED_LOWDELAY_REQUEST 4033 /* Macros to trigger compilation errors when the wrong types are provided to a CTL */ #define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) @@ -117,14 +119,11 @@ extern "C" { /** \cond DOXYGEN_EXCLUDE */ /* Values for the varrious encoder CTLs */ #define OPUS_AUTO -1000 /**int: 0 (default); 1 (forced mono) + * \param[in] x int: OPUS_AUTO (default); 1 (forced mono); 2 (forced stereo) * @hideinitializer */ #define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) -/** Gets the encoder's forced mono configuration, @see [OPUS_SET_FORCE_MONO] - * \param[out] x int*: 0; 1 +/** Gets the encoder's forced channel configuration, @see [OPUS_SET_FORCE_CHANNELS] + * \param[out] x int*: OPUS_AUTO; 0; 1 * @hideinitializer */ #define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) @@ -337,6 +336,19 @@ extern "C" { * * @hideinitializer */ #define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Configures low-delay mode that disables the speech-optimized mode in exchange for slightly reduced delay. + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * The setting can only be changed right after initialization or after a reset. + * \param[in] x int: 0 (default); 1 (lowdelay) + * @hideinitializer */ +#define OPUS_SET_RESTRICTED_LOWDELAY(x) OPUS_SET_RESTRICTED_LOWDELAY_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration, @see [OPUS_SET_RESTRICTED_LOWDELAY] + * \param[out] x int*: 0; 1 + * @hideinitializer */ +#define OPUS_GET_RESTRICTED_LOWDELAY(x) OPUS_GET_RESTRICTED_LOWDELAY_REQUEST, __opus_check_int_ptr(x) + + /**@}*/ /** \defgroup libinfo Opus library information functions diff --git a/src/opus_encoder.c b/src/opus_encoder.c index e5a94754..7987e31d 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -67,6 +67,7 @@ struct OpusEncoder { int vbr_constraint; int bitrate_bps; int user_bitrate_bps; + int lowdelay; int encoder_buffer; #define OPUS_ENCODER_RESET_START stream_channels @@ -374,6 +375,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, int cutoff_Hz, hp_freq_smth1; int voice_est; opus_int32 equiv_rate; + int delay_compensation; ALLOC_STACK; st->rangeFinal = 0; @@ -386,6 +388,11 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, silk_enc = (char*)st+st->silk_enc_offset; celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + if (st->lowdelay) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + if (st->user_bitrate_bps==OPUS_AUTO) st->bitrate_bps = 60*st->Fs/frame_size + st->Fs*st->channels; else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) @@ -446,7 +453,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, } #else /* Mode selection depending on application and signal type */ - if (st->user_forced_mode == OPUS_AUTO) + if (st->lowdelay) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) { int chan; opus_int32 mode_voice, mode_music; @@ -578,9 +588,9 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, ec_enc_init(&enc, data, max_data_bytes-1); - ALLOC(pcm_buf, (st->delay_compensation+frame_size)*st->channels, opus_val16); - for (i=0;idelay_compensation*st->channels;i++) - pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i]; + ALLOC(pcm_buf, (delay_compensation+frame_size)*st->channels, opus_val16); + for (i=0;ichannels;i++) + pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-delay_compensation)*st->channels+i]; if (st->mode == MODE_CELT_ONLY) hp_freq_smth1 = SKP_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); @@ -595,10 +605,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, if (st->application == OPUS_APPLICATION_VOIP) { - hp_cutoff(pcm, cutoff_Hz, &pcm_buf[st->delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); } else { for (i=0;ichannels;i++) - pcm_buf[st->delay_compensation*st->channels + i] = pcm[i]; + pcm_buf[delay_compensation*st->channels + i] = pcm[i]; } /* SILK processing */ @@ -671,10 +681,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, } #ifdef FIXED_POINT - pcm_silk = pcm_buf+st->delay_compensation*st->channels; + pcm_silk = pcm_buf+delay_compensation*st->channels; #else for (i=0;ichannels;i++) - pcm_silk[i] = FLOAT2INT16(pcm_buf[st->delay_compensation*st->channels + i]); + pcm_silk[i] = FLOAT2INT16(pcm_buf[delay_compensation*st->channels + i]); #endif ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 ); if( ret ) { @@ -736,7 +746,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); /* TODO: This wastes CPU a bit compared to just prefilling the buffer */ - celt_encode_with_ec(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10, NULL); + celt_encode_with_ec(celt_enc, &st->delay_buffer[(st->encoder_buffer-delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10, NULL); } else { celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2)); } @@ -768,10 +778,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, nb_compr_bytes = 0; } - for (i=0;ichannels*(st->encoder_buffer-(frame_size+st->delay_compensation));i++) + for (i=0;ichannels*(st->encoder_buffer-(frame_size+delay_compensation));i++) st->delay_buffer[i] = st->delay_buffer[i+st->channels*frame_size]; for (;iencoder_buffer*st->channels;i++) - st->delay_buffer[i] = pcm_buf[(frame_size+st->delay_compensation-st->encoder_buffer)*st->channels+i]; + st->delay_buffer[i] = pcm_buf[(frame_size+delay_compensation-st->encoder_buffer)*st->channels+i]; if( st->mode == MODE_HYBRID && st->stream_channels == 2 ) { @@ -1117,7 +1127,9 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) case OPUS_GET_LOOKAHEAD_REQUEST: { opus_int32 *value = va_arg(ap, opus_int32*); - *value = st->delay_compensation+st->Fs/400; + *value = st->Fs/400; + if (!st->lowdelay) + *value += st->delay_compensation; } break; case OPUS_GET_FINAL_RANGE_REQUEST: @@ -1154,6 +1166,23 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) st->user_forced_mode = value; } break; + case OPUS_SET_RESTRICTED_LOWDELAY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (!st->first && st->lowdelay != !!value) + { + ret = OPUS_BAD_ARG; + break; + } + st->lowdelay = !!value; + } + break; + case OPUS_GET_RESTRICTED_LOWDELAY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->lowdelay; + } + break; default: /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ ret = OPUS_UNIMPLEMENTED; diff --git a/src/test_opus.c b/src/test_opus.c index cd597582..be208cc6 100644 --- a/src/test_opus.c +++ b/src/test_opus.c @@ -118,6 +118,7 @@ int main(int argc, char *argv[]) int max_frame_size = 960*6; int curr_read=0; int sweep_bps = 0; + int lowdelay = 0; if (argc < 7 ) { @@ -216,6 +217,9 @@ int main(int argc, char *argv[]) } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-forcemono" ) == 0 ) { forcechannels = 1; args++; + } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-lowdelay" ) == 0 ) { + lowdelay = 1; + args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cvbr" ) == 0 ) { cvbr = 1; args++; @@ -295,11 +299,9 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels)); opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx)); opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); + opus_encoder_ctl(enc, OPUS_SET_RESTRICTED_LOWDELAY(lowdelay)); - skip = 5*sampling_rate/1000; - /* When SILK resamples, add 18 samples delay */ - /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000) - skip += 18;*/ + opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); switch(bandwidth) {