From 3da099c19e2151589378ef61439e1a35ba78d506 Mon Sep 17 00:00:00 2001 From: hsd Date: Wed, 29 Apr 2026 09:29:47 +0200 Subject: [PATCH 1/2] basop port of float-1515-fix-isar-framing-in-rtp / 8a3d5bc80df7aec9fc349dcebf3c0ef81d1e7d5b / https://forge.3gpp.org/rep/ivas-codec-pc/ivas-codec/-/merge_requests/2608 --- apps/decoder.c | 9 +- apps/isar_post_rend.c | 15 ++ lib_com/options.h | 1 + lib_isar/isar_lc3plus_dec.c | 285 ++++++++++++++++++++++++++++++++++- lib_isar/lib_isar_pre_rend.c | 3 + 5 files changed, 309 insertions(+), 4 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index f019fc339..7b565207a 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3492,10 +3492,17 @@ static ivas_error decodeVoIP( } else if ( decodedGoodFrame ) { +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + srInfo.bitrateKbps = splitRendBits->bits_written * 1000 / splitRendBits->isar_frame_size_ms; +#else srInfo.bitrateKbps = splitRendBits->bits_written * 1000 / splitRendBits->codec_frame_size_ms; +#endif srInfo.codec = ( splitRendBits->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) ? IVAS_SR_TRANSPORT_LC3PLUS : IVAS_SR_TRANSPORT_LCLD; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + srInfo.codecFrameSizeMs = (uint32_t) splitRendBits->isar_frame_size_ms; +#else srInfo.codecFrameSizeMs = (uint32_t) splitRendBits->codec_frame_size_ms; - +#endif if ( ( error = IVAS_RTP_WriteNextFrame( &srRtp, splitRendBits->bits_buf, &srInfo, (int16_t) splitRendBits->bits_written, false, false ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError %s while pushing SR audio bitstream to RTP pack\n", ivas_error_to_string( error ) ); diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index c3fe556c8..06ba6b987 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -809,6 +809,13 @@ static ivas_error parseSRParamsFile( *codec = ( srInfo.codec == IVAS_SR_TRANSPORT_LCLD ) ? ISAR_SPLIT_REND_CODEC_LCLD : ISAR_SPLIT_REND_CODEC_LC3PLUS; *codec_frame_size_ms = (int16_t) srInfo.codecFrameSizeMs; *isar_frame_size_ms = *codec_frame_size_ms; /* for rtp force codec framesize as isar renderer frame size */ +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + if ( *codec == ISAR_SPLIT_REND_CODEC_LC3PLUS && *isar_frame_size_ms == 20 ) + { + /* For LC3plus, the codec frame size is limited to max 10 ms */ + *codec_frame_size_ms = 10; + } +#endif break; } } @@ -1198,7 +1205,11 @@ int main( bitsBuffer.config.bitsRead = 0; bitsBuffer.config.bitsWritten = 0; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + while ( frameMS < (int16_t) ( args.render_num_subframes * 5 ) ) +#else while ( frameMS < bitsBuffer.config.isar_frame_size_ms ) +#endif { error = IVAS_RTP_ReadNextFrame( &srRTP, bitBuffer, &auSizeBits, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &srInfo, &qBit ); if ( error != IVAS_ERR_OK ) @@ -1224,7 +1235,11 @@ int main( bitBuffer += ( auSizeBits + 7 ) / 8; bitsBuffer.config.bitsWritten += auSizeBits; bitsBuffer.config.codec = srInfo.codec == IVAS_SR_TRANSPORT_LC3PLUS ? ISAR_SPLIT_REND_CODEC_LC3PLUS : ISAR_SPLIT_REND_CODEC_LCLD; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + frameMS += bitsBuffer.config.isar_frame_size_ms; +#else frameMS += bitsBuffer.config.codec_frame_size_ms; +#endif } } else if ( ( hSplitRendFileReadWrite != NULL ) && splitBinNeedsNewFrame ) diff --git a/lib_com/options.h b/lib_com/options.h index 53bfa8a2e..e42218061 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -110,6 +110,7 @@ #define FIX_2095_REMOVE_UNUSED_ISAR_TABLES /* Dolby: remove unused ISAR */ #define FIX_BASOP_2560_STEREO_DFT_DEC_RESET /* FhG: BASOP issue 2560: align reset of hStereoDft->res_gains_ind_fx[][] between BASOP and float */ #define HARMONIZE_2539_cng_energy /* FhG: basop issue 2539: harmonize cng_energy with its ivas derivate */ +#define FIX_1515_ISAR_FRAME_SIZES_IN_RTP /* FhG: Fix ISAR frame sizes in RTP. This includes reconfiguration of the LC3plus decoder */ /* #################### End BE switches ################################## */ diff --git a/lib_isar/isar_lc3plus_dec.c b/lib_isar/isar_lc3plus_dec.c index 7f158cc04..aad5764be 100644 --- a/lib_isar/isar_lc3plus_dec.c +++ b/lib_isar/isar_lc3plus_dec.c @@ -30,6 +30,7 @@ *******************************************************************************************************/ +#include #include #include "options.h" #include "prot_fx.h" @@ -40,7 +41,212 @@ #include "ivas_error_utils.h" #include "wmc_auto.h" +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP /* "open" and "close" were refactored (mostly copy-paste) into separate steps of (de)allocate handle and (de)init handle */ +static ivas_error isar_lc3plus_dec_init_handle( + const LC3PLUS_CONFIG config, /* i : LC3plus decoder configuration */ + ISAR_LC3PLUS_DEC_HANDLE *handle /* o : decoder handle */ +) +{ + LC3PLUS_Error err; + int32_t decoder_size; + Word32 scratch_size; + int16_t i; + + if ( 0 == config.lc3plus_frame_duration_us ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid lc3plus_frame_duration_us (0)\n" ); + } + + if ( config.channels > ISAR_LC3PLUS_MAX_NUM_DECODERS ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INIT_ERROR, "Maximum number of channels exceeds ISAR_LC3PLUS_MAX_NUM_DECODERS\n" ); + } + + ( *handle )->num_decs = 0; + ( *handle )->pcm_conversion_buffer = NULL; + ( *handle )->handles = NULL; + ( *handle )->selective_decoding_states = NULL; + ( *handle )->bitstream_caches = NULL; + + if ( ( ( *handle )->handles = malloc( config.channels * sizeof( ISAR_LC3PLUS_DEC_HANDLE ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + + if ( ( ( *handle )->selective_decoding_states = malloc( config.channels * sizeof( ISAR_LC3PLUS_DEC_SELECTIVE_DECODING_STATE * ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + + for ( i = 0; i < config.channels; ++i ) + { + ( *handle )->handles[i] = NULL; + ( *handle )->selective_decoding_states[i] = NULL; + } + + if ( ( ( *handle )->bitstream_caches = malloc( config.channels * sizeof( ISAR_LC3PLUS_DEC_BITSTREAM_CACHE * ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + for ( i = 0; i < config.channels; ++i ) + { + ( *handle )->bitstream_caches[i] = NULL; + } + + ( *handle )->num_decs = config.channels; + for ( int32_t iCh = 0; iCh < config.channels; iCh++ ) + { + ( *handle )->selective_decoding_states[iCh] = NULL; + if ( NULL != ( *handle )->bitstream_caches ) + { + ( *handle )->bitstream_caches[iCh] = NULL; + } + /* allocate and configure LC3plus decoder */ + decoder_size = lc3plus_dec_get_size( config.samplerate, 1, LC3PLUS_PLC_ADVANCED); + if ( 0 == decoder_size ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "lc3plus_dec_get_size failed\n" ); + } + + if ( ( ( *handle )->handles[iCh] = malloc( decoder_size ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + + err = lc3plus_dec_init( ( *handle )->handles[iCh], config.samplerate, 1, LC3PLUS_PLC_ADVANCED, config.high_res_mode_enabled ); + + if ( LC3PLUS_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_dec_init failed\n" ); + } + + err = lc3plus_dec_set_frame_dms( ( *handle )->handles[iCh], IVAS_LC3PLUS_UsToLC3plusFrameDuration( config.lc3plus_frame_duration_us ) ); + if ( LC3PLUS_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_dec_set_frame_dms failed\n" ); + } + + /* allocate and configure per LC3plus decoder skip state */ + if ( ( ( *handle )->selective_decoding_states[iCh] = malloc( sizeof( ISAR_LC3PLUS_DEC_SELECTIVE_DECODING_STATE ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + + ( *handle )->selective_decoding_states[iCh]->has_skipped_a_frame = 0; + ( *handle )->selective_decoding_states[iCh]->shall_decode_cached_frame = 0; + ( *handle )->selective_decoding_states[iCh]->frame_action = DEC_ACTION_DECODE_AND_USE; + + /* allocate and configure per LC3plus decoder bitstream cache */ + if ( ( ( *handle )->bitstream_caches[iCh] = malloc( sizeof( ISAR_LC3PLUS_DEC_BITSTREAM_CACHE ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + + ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity = 400 /*LC3plus max non-HR octet count*/; + + if ( ( ( *handle )->bitstream_caches[iCh]->bitstream_cache = malloc( ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + ( *handle )->bitstream_caches[iCh]->bitstream_cache_size = 0; + } + + ( *handle )->config = config; + if ( config.isar_frame_duration_us < config.lc3plus_frame_duration_us || config.isar_frame_duration_us % config.lc3plus_frame_duration_us != 0 ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "Current pcm_conversion_buffer sizing requires that lc3plus uses a shorter or equal frame duration than ivas\n" ); + } + + if ( ( ( *handle )->pcm_conversion_buffer = malloc( sizeof( int16_t ) * config.samplerate * config.lc3plus_frame_duration_us / 1000000 ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder wrapper pcm_conversion_buffer\n" ); + } + + scratch_size = lc3plus_dec_get_scratch_size( ( *handle )->handles[0] ); + if ( ( ( *handle )->scratch = malloc( sizeof( uint8_t ) * scratch_size ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder wrapper scratch\n" ); + } + + return IVAS_ERR_OK; +} + +static void isar_lc3plus_dec_deinit_handle( + ISAR_LC3PLUS_DEC_HANDLE handle /* i/o: decoder handle */ +) +{ + if ( NULL == handle ) + { + return; + } + for ( uint32_t iDec = 0; iDec < handle->num_decs; iDec++ ) + { + if ( NULL != handle->handles && NULL != handle->handles[iDec] ) + { + free( handle->handles[iDec] ); + } + + if ( NULL != handle->selective_decoding_states && NULL != handle->selective_decoding_states[iDec] ) + { + free( handle->selective_decoding_states[iDec] ); + } + + if ( NULL != handle->bitstream_caches && NULL != handle->bitstream_caches[iDec] ) + { + free( handle->bitstream_caches[iDec]->bitstream_cache ); + free( handle->bitstream_caches[iDec] ); + } + } + + if ( NULL != handle->pcm_conversion_buffer ) + { + free( handle->pcm_conversion_buffer ); + } + free( handle->handles ); + + if ( NULL != handle->bitstream_caches ) + { + free( handle->bitstream_caches ); + } + free( handle->selective_decoding_states ); + + return; +} +/*------------------------------------------------------------------------- + * ISAR_LC3PLUS_DEC_Open() + * + * + *------------------------------------------------------------------------*/ + +ivas_error ISAR_LC3PLUS_DEC_Open( + const LC3PLUS_CONFIG config, /* i : LC3plus decoder configuration */ + ISAR_LC3PLUS_DEC_HANDLE *handle /* o : decoder handle */ +) +{ + if ( ( *handle = malloc( sizeof( struct ISAR_LC3PLUS_DEC_HANDLE ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + + return isar_lc3plus_dec_init_handle( config, handle ); +} +#else /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_Open() * @@ -193,7 +399,7 @@ ivas_error ISAR_LC3PLUS_DEC_Open( return IVAS_ERR_OK; } - +#endif /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_GetDelay() @@ -238,7 +444,28 @@ ivas_error ISAR_LC3PLUS_DEC_GetDelay( return IVAS_ERR_OK; } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP +/*------------------------------------------------------------------------- + * ISAR_LC3PLUS_DEC_Close() + * + * + *------------------------------------------------------------------------*/ + +void ISAR_LC3PLUS_DEC_Close( + ISAR_LC3PLUS_DEC_HANDLE *handle /* i/o: Pointer to LC3plus decoder handle */ +) +{ + if ( NULL == handle || NULL == *handle ) + { + return; + } + isar_lc3plus_dec_deinit_handle( *handle ); + free( *handle ); + *handle = NULL; + return; +} +#else /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_Close() * @@ -294,7 +521,7 @@ void ISAR_LC3PLUS_DEC_Close( return; } - +#endif /*------------------------------------------------------------------------- * decode_or_conceal_one_lc3plus_frame() @@ -353,7 +580,9 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( int32_t ivasSampleIndex; int16_t numSamplesPerLC3plusChannel; ivas_error err; - +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + bool reInitRequired = false; +#endif if ( NULL == handle ) { return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "LC3PLUS_Dec_Wrap_Handle is NULL\n" ); @@ -380,7 +609,9 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "isar_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); } +#ifndef FIX_1515_ISAR_FRAME_SIZES_IN_RTP config_num_media_times = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#endif if ( !badFrameIndicator ) { if ( LC3PLUS_RTP_payload_deserialize( &payload, bitstream_in, bitstream_in_size ) != LC3PLUS_RTP_ERR_NO_ERROR ) @@ -395,6 +626,50 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of channels) in bitstream is not supported\n" ); } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + if ( payload.frame_duration_us != handle->config.lc3plus_frame_duration_us ) + { + if ( payload.num_media_times * payload.frame_duration_us == handle->config.isar_frame_duration_us ) + { + reInitRequired = true; + } + else + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (frame duration) in bitstream is only supported when the ISAR frame duration stays the same\n" ); + } + } + if ( payload.high_resolution_enabled != handle->config.high_res_mode_enabled ) + { + reInitRequired = true; + } + if ( payload.num_media_times != handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us ) + { + if ( payload.num_media_times * payload.frame_duration_us == handle->config.isar_frame_duration_us ) + { + reInitRequired = true; + } + else + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of media times per frame data block) in bitstream is only supported when the ISAR frame duration stays the same\n" ); + } + } + if ( reInitRequired ) + { + isar_lc3plus_dec_deinit_handle( handle ); + LC3PLUS_CONFIG newConfig; + newConfig.channels = payload.num_channels; + newConfig.samplerate = payload.sampling_rate_hz; + newConfig.high_res_mode_enabled = payload.high_resolution_enabled; + newConfig.isar_frame_duration_us = (int16_t) ( payload.num_media_times * payload.frame_duration_us ); + newConfig.lc3plus_frame_duration_us = (int16_t) payload.frame_duration_us; + newConfig.samplerate = payload.sampling_rate_hz; + err = isar_lc3plus_dec_init_handle( newConfig, &handle ); + if ( err != IVAS_ERR_OK ) + { + return IVAS_ERROR( err, "ISAR_LC3PLUS_DEC_Open failed\n" ); + } + } +#else if ( payload.frame_duration_us != handle->config.lc3plus_frame_duration_us ) { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (frame duration) in bitstream is not supported\n" ); @@ -407,8 +682,12 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of media times per frame data block) in bitstream is not supported\n" ); } +#endif } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + config_num_media_times = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#endif numSamplesPerLC3plusChannel = (int16_t) ( handle->config.samplerate / ( 1000000 / handle->config.isar_frame_duration_us ) / config_num_media_times ); for ( iDec = 0; iDec < handle->num_decs; iDec++ ) { diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 910f5f423..fcb59a08a 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -399,6 +399,9 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( available_bits = L_shr( tmp_32, sub( 31, tmp_e ) ); // Q0 available_bits = L_sub( available_bits, pBits->bits_written ); pBits->codec_frame_size_ms = codec_frame_size_ms; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + pBits->isar_frame_size_ms = isar_frame_size_ms; +#endif q_final = sub( s_min( Q_buff_re, Q_buff_im ), 2 ); FOR( i = 0; i < hSplitBin->hSplitBinLCLDEnc->iChannels; i++ ) { -- GitLab From b56eeaff26444349a0ba38e76db059de74cfa8f4 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Wed, 29 Apr 2026 13:47:56 +0200 Subject: [PATCH 2/2] Fix formatting --- lib_isar/isar_lc3plus_dec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_isar/isar_lc3plus_dec.c b/lib_isar/isar_lc3plus_dec.c index aad5764be..3f3d2b17f 100644 --- a/lib_isar/isar_lc3plus_dec.c +++ b/lib_isar/isar_lc3plus_dec.c @@ -107,7 +107,7 @@ static ivas_error isar_lc3plus_dec_init_handle( ( *handle )->bitstream_caches[iCh] = NULL; } /* allocate and configure LC3plus decoder */ - decoder_size = lc3plus_dec_get_size( config.samplerate, 1, LC3PLUS_PLC_ADVANCED); + decoder_size = lc3plus_dec_get_size( config.samplerate, 1, LC3PLUS_PLC_ADVANCED ); if ( 0 == decoder_size ) { ISAR_LC3PLUS_DEC_Close( handle ); -- GitLab