diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ebc7588a4026452da86133780f62e9369dff4961..7bffc14cb5f748d0fb32420cc232752f17ecbe96 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -800,6 +800,18 @@ split-rendering-smoke-test: junit: - report-junit.xml +lc3-wrapper-unit-test: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-cmake"] + stage: test + script: + - *enable-split-rendering + - cmake -B cmake-build -G "Unix Makefiles" -DCOPY_EXECUTABLES_FROM_BUILD_DIR=true + - cmake --build cmake-build -- -j + - scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test + # compare split-rendering bitexactness between target and source branch split-rendering-pytest-on-merge-request: extends: diff --git a/Workspace_msvc/lib_isar.vcxproj b/Workspace_msvc/lib_isar.vcxproj index d50581fbee17aba89cfa3067805fa2bf7d62a68e..fceeb731ced2445a5434805d422d30654718782a 100644 --- a/Workspace_msvc/lib_isar.vcxproj +++ b/Workspace_msvc/lib_isar.vcxproj @@ -146,6 +146,7 @@ + @@ -169,6 +170,7 @@ + @@ -195,4 +197,4 @@ - \ No newline at end of file + diff --git a/apps/decoder.c b/apps/decoder.c index eeb2a19f20c1baba67e96b140f4beb1712e0a3ce..5a770f4d0a3a5549fa7f2769337cdc736ae3d92d 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -713,6 +713,13 @@ int main( } renderConfig.roomAcoustics.override = true; } +#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* ISAR frame size is set from command line, not renderer config file. + * This will be ignored if output format is not split rendering. */ + renderConfig.split_rend_config.isar_frame_size_ms = (int16_t) arg.renderFramesize /* given in number of 5ms subframes */ * 5; +#endif +#endif if ( ( error = IVAS_DEC_FeedRenderConfig( hIvasDec, renderConfig ) ) != IVAS_ERR_OK ) { @@ -1976,6 +1983,10 @@ static ivas_error initOnFirstGoodFrame( ISAR_SPLIT_REND_CODEC splitRendCodec; int16_t splitRendCodecFrameSizeMs; ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t splitRendIsarFrameSizeMs; + int16_t lc3plusHighRes; +#endif if ( ( error = IVAS_DEC_GetDelay( hIvasDec, delayNumSamples_temp, &delayTimeScale_temp ) ) != IVAS_ERR_OK ) { @@ -1983,7 +1994,18 @@ static ivas_error initOnFirstGoodFrame( return error; } - if ( ( error = IVAS_DEC_GetSplitRendBitstreamHeader( hIvasDec, &splitRendCodec, &poseCorrection, &splitRendCodecFrameSizeMs ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_GetSplitRendBitstreamHeader( hIvasDec, + &splitRendCodec, + &poseCorrection, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + &splitRendIsarFrameSizeMs, +#endif + &splitRendCodecFrameSizeMs +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + &lc3plusHighRes +#endif + ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nUnable to get split renderer bitstream header: %s\n", ivas_error_to_string( error ) ); return error; @@ -1991,7 +2013,20 @@ static ivas_error initOnFirstGoodFrame( if ( IVAS_DEC_is_split_rendering_coded_out( hIvasDec ) ) { - if ( ( error = split_rend_writer_open( splitRendWriter, arg.outputWavFilename, delayNumSamples_temp[0], delayTimeScale_temp, splitRendCodec, poseCorrection, splitRendCodecFrameSizeMs ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( splitRendWriter, + arg.outputWavFilename, + delayNumSamples_temp[0], + delayTimeScale_temp, + splitRendCodec, + poseCorrection, + splitRendCodecFrameSizeMs +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + splitRendIsarFrameSizeMs, + arg.output_Fs, + lc3plusHighRes +#endif + ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nUnable to open output split rendering metadata file %s\n", arg.outputWavFilename ); return error; @@ -2007,7 +2042,20 @@ static ivas_error initOnFirstGoodFrame( } #endif - if ( ( error = split_rend_writer_open( splitRendWriter, arg.outputMdFilename, delayNumSamples_temp[0], delayTimeScale_temp, splitRendCodec, poseCorrection, splitRendCodecFrameSizeMs ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( splitRendWriter, + arg.outputMdFilename, + delayNumSamples_temp[0], + delayTimeScale_temp, + splitRendCodec, + poseCorrection, + splitRendCodecFrameSizeMs +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + splitRendIsarFrameSizeMs, + arg.output_Fs, + lc3plusHighRes +#endif + ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nUnable to open output split rendering metadata file %s\n", arg.outputWavFilename ); return error; @@ -2043,7 +2091,12 @@ static ivas_error initOnFirstGoodFrame( splitRendBitsZero.buf_len = 0; splitRendBitsZero.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; splitRendBitsZero.pose_correction = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + splitRendBitsZero.codec_frame_size_ms = 0; + splitRendBitsZero.isar_frame_size_ms = 20; +#else splitRendBitsZero.codec_frame_size_ms = 20; +#endif if ( split_rend_write_bitstream_to_file( *splitRendWriter, splitRendBitsZero.bits_buf, &splitRendBitsZero.bits_read, &splitRendBitsZero.bits_written ) != IVAS_ERR_OK ) { diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index 9060ed9c4c73cfaf58b6c8f8a4ffcde3474443b5..4113ea494f59876b042cf7aa3e1a16f588f52adc 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -730,7 +730,13 @@ int main( bitsBuffer.config.bufLenInBytes = 0; bitsBuffer.config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; bitsBuffer.config.poseCorrection = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + bitsBuffer.config.codec_frame_size_ms = 5; + bitsBuffer.config.isar_frame_size_ms = 20; + bitsBuffer.config.lc3plusHighRes = 0; +#else bitsBuffer.config.codec_frame_size_ms = 20; +#endif CmdlnArgs args = parseCmdlnArgs( argc, argv ); @@ -754,11 +760,25 @@ int main( SplitRendBFIFileReader_open( args.splitRendBFIFilePath, &splitRendBFIReader ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t inFileSampleRate = 0; +#endif strncpy( audioFilePath, args.inputFilePath, FILENAME_MAX - 1 ); hSplitRendFileReadWrite = NULL; if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) { - error = split_rend_reader_open( &hSplitRendFileReadWrite, args.inMetadataFilePaths[0], &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms ); + error = split_rend_reader_open( &hSplitRendFileReadWrite, + args.inMetadataFilePaths[0], + &bitsBuffer.config.codec, + &bitsBuffer.config.poseCorrection, + &bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + &bitsBuffer.config.isar_frame_size_ms, + &inFileSampleRate, + &bitsBuffer.config.lc3plusHighRes +#endif + ); if ( error != IVAS_ERR_OK ) { fprintf( stderr, "Could not open split rend metadata file %s\n", args.inMetadataFilePaths[0] ); @@ -775,7 +795,18 @@ int main( /*if split renderer is running in post renderer mode*/ if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ) { - error = split_rend_reader_open( &hSplitRendFileReadWrite, args.inputFilePath, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms ); + error = split_rend_reader_open( &hSplitRendFileReadWrite, + args.inputFilePath, + &bitsBuffer.config.codec, + &bitsBuffer.config.poseCorrection, + &bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + &bitsBuffer.config.isar_frame_size_ms, + &inFileSampleRate, + &bitsBuffer.config.lc3plusHighRes +#endif + ); if ( error != IVAS_ERR_OK ) { fprintf( stderr, "Could not open split rend metadata file %s\n", args.inputFilePath ); @@ -784,12 +815,17 @@ int main( audioReader = NULL; } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS int32_t inFileSampleRate = 0; +#endif if ( audioReader != NULL ) { error = AudioFileReader_getSamplingRate( audioReader, &inFileSampleRate ); } else +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( hSplitRendFileReadWrite == NULL ) +#endif { inFileSampleRate = args.sampleRate; } @@ -797,7 +833,7 @@ int main( switch ( error ) { case IVAS_ERR_OK: - /* If sampling rate not given on command line, use the one from wav file */ + /* If sampling rate not given on command line, use the one from SR file */ if ( args.sampleRate == 0 ) { args.sampleRate = inFileSampleRate; @@ -848,8 +884,16 @@ int main( if ( args.inConfig.numBinBuses > 0 ) { - if ( ( error = ISAR_REND_SetSplitRendBitstreamHeader( hIsarPostRend, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, - bitsBuffer.config.codec_frame_size_ms ) ) != IVAS_ERR_OK ) + if ( ( error = ISAR_REND_SetSplitRendBitstreamHeader( hIsarPostRend, + bitsBuffer.config.codec, + bitsBuffer.config.poseCorrection, + bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + bitsBuffer.config.isar_frame_size_ms, + bitsBuffer.config.lc3plusHighRes +#endif + ) ) != IVAS_ERR_OK ) { fprintf( stderr, "Error in getting split renderer bitstream header: %s\n", ivas_error_to_string( error ) ); exit( -1 ); diff --git a/apps/renderer.c b/apps/renderer.c index d6123d53cabfd9ef6a5720310fce189c7292edbc..f8c53320d1ca65ed22823cf907f90b58445c0642 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -762,7 +762,13 @@ int main( bitsBuffer.config.bufLenInBytes = 0; bitsBuffer.config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; bitsBuffer.config.poseCorrection = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + bitsBuffer.config.codec_frame_size_ms = 5; + bitsBuffer.config.isar_frame_size_ms = 20; + bitsBuffer.config.lc3plus_highres = 0; +#else bitsBuffer.config.codec_frame_size_ms = 20; +#endif #endif for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i ) { @@ -1106,6 +1112,14 @@ int main( renderConfig.roomAcoustics.override = 1; } +#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* ISAR frame size is set from command line, not renderer config file. + * This will be ignored if output format is not split rendering. */ + renderConfig.split_rend_config.isar_frame_size_ms = (int16_t) args.render_framesize /* given in number of 5ms subframes */ * 5; +#endif +#endif + if ( ( error = IVAS_REND_FeedRenderConfig( hIvasRend, renderConfig ) ) != IVAS_ERR_OK ) { #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -1366,7 +1380,15 @@ int main( if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) { - IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms ); + IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, + &bitsBuffer.config.codec, + &bitsBuffer.config.poseCorrection, + &bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + &bitsBuffer.config.isar_frame_size_ms +#endif + ); if ( IVAS_REND_GetDelay( hIvasRend, &delayNumSamples_temp, &delayTimeScale_temp ) != IVAS_ERR_OK ) { @@ -1374,7 +1396,20 @@ int main( exit( -1 ); } - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outputFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, + args.outputFilePath, + delayNumSamples_temp, + delayTimeScale_temp, + bitsBuffer.config.codec, + bitsBuffer.config.poseCorrection, + bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + bitsBuffer.config.isar_frame_size_ms, + args.sampleRate, + bitsBuffer.config.lc3plus_highres +#endif + ) ) != IVAS_ERR_OK ) { fprintf( stderr, "Could not open split rend metadata file %s\n", args.outputFilePath ); exit( -1 ); @@ -1386,7 +1421,15 @@ int main( if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { - IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms ); + IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, + &bitsBuffer.config.codec, + &bitsBuffer.config.poseCorrection, + &bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + &bitsBuffer.config.isar_frame_size_ms +#endif + ); if ( IVAS_REND_GetDelay( hIvasRend, &delayNumSamples_temp, &delayTimeScale_temp ) != IVAS_ERR_OK ) { @@ -1394,7 +1437,20 @@ int main( exit( -1 ); } - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outMetadataFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, + args.outMetadataFilePath, + delayNumSamples_temp, + delayTimeScale_temp, + bitsBuffer.config.codec, + bitsBuffer.config.poseCorrection, + bitsBuffer.config.codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + bitsBuffer.config.isar_frame_size_ms, + args.sampleRate, + bitsBuffer.config.lc3plus_highres +#endif + ) ) != IVAS_ERR_OK ) { fprintf( stderr, "Could not open split rend metadata file %s\n", args.outMetadataFilePath ); exit( -1 ); diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index 1d4cde968052f087cd94d8e37f9d8269de822d2d..bb521f23ccc705c93eca47f4e4092c5b0caa476c 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -259,25 +259,35 @@ typedef struct _ISAR_SPLIT_REND_BITS_DATA int16_t codec_frame_size_ms; ISAR_SPLIT_REND_CODEC codec; ISAR_SPLIT_REND_POSE_CORRECTION_MODE pose_correction; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t isar_frame_size_ms; + int16_t lc3plus_highres; +#endif } ISAR_SPLIT_REND_BITS_DATA, *ISAR_SPLIT_REND_BITS_HANDLE; typedef struct _ISAR_SPLIT_REND_CONFIG { - int32_t splitRendBitRate; /*Bit rate for split rendering mode, if "pcm_out" is set then "splitRendBitRate" is used as a limit for MD bitrate */ - int16_t hq_mode; /*High quality 3DOF mode with additional side information. Requires more pre-renditions. */ - int16_t dof; /*flag to specify if pose correction is needed for 1, 2 or 3 degree of freedoms*/ - /*The axis can be set dynamically per frame based on a file input */ - /*possible values: - 1 - (1dof correction. By default YAW correction) - 2 - (2dof correction. By default YAW and PITCH correction) - 3 - (3dof correction. By default YAW, PITCH and ROLL correction) - */ - int16_t codec_delay_ms; /*PLACEHOLDER (currently being ignored) : look ahead delay of the codec that is used to code BIN signal output of pre-renderer*/ - int16_t codec_frame_size_ms; /*Codec frame size in milliseconds, only relevant with LC3plus */ + int32_t splitRendBitRate; /*Bit rate for split rendering mode, if "pcm_out" is set then "splitRendBitRate" is used as a limit for MD bitrate */ + int16_t hq_mode; /*High quality 3DOF mode with additional side information. Requires more pre-renditions. */ + int16_t dof; /*flag to specify if pose correction is needed for 1, 2 or 3 degree of freedoms*/ + /*The axis can be set dynamically per frame based on a file input */ + /*possible values: + 1 - (1dof correction. By default YAW correction) + 2 - (2dof correction. By default YAW and PITCH correction) + 3 - (3dof correction. By default YAW, PITCH and ROLL correction) + */ + int16_t codec_delay_ms; /*PLACEHOLDER (currently being ignored) : look ahead delay of the codec that is used to code BIN signal output of pre-renderer*/ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t isar_frame_size_ms; /* ISAR bit stream frame size in milliseconds */ +#endif + int16_t codec_frame_size_ms; /* Codec frame size in milliseconds, only relevant with LC3plus */ ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode; ISAR_SPLIT_REND_CODEC codec; ISAR_SPLIT_REND_RENDERER_SELECTION rendererSelection; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t lc3plus_highres; +#endif } ISAR_SPLIT_REND_CONFIG_DATA, *ISAR_SPLIT_REND_CONFIG_HANDLE; #endif diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index d9d6b31138b4ef29c80e63a0f7678749755bfa7f..a5fe2d93489bc23be1f379c829b9d7bd6f8f1a21 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -104,6 +104,12 @@ typedef enum * input data errors * *----------------------------------------*/ IVAS_ERR_INVALID_BITSTREAM = 0x2000, +#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + IVAS_ERR_UNEXPECTED_LC3PLUS_BITSTREAM, + IVAS_ERR_UNEXPECTED_LC3PLUS_BITSTREAM_CONFIG, +#endif +#endif /*----------------------------------------* * hardware errors * diff --git a/lib_com/ivas_error_utils.h b/lib_com/ivas_error_utils.h index ff0c96f624afa649d9d3f11e2c4e7dffc0aa5e4a..5bf677820f8bdf3af7e878b207ee6b709ea60c49 100644 --- a/lib_com/ivas_error_utils.h +++ b/lib_com/ivas_error_utils.h @@ -30,6 +30,9 @@ *******************************************************************************************************/ +#ifndef IVAS_ERROR_UTILS_H +#define IVAS_ERROR_UTILS_H + #include "options.h" #include @@ -42,9 +45,6 @@ #include #endif -#ifndef IVAS_ERROR_UTILS_H -#define IVAS_ERROR_UTILS_H - /* * Usage: * @@ -83,7 +83,6 @@ static inline ivas_error ivas_error_wrapper( const ivas_error error_code, const va_end( args ); fprintf( stderr, "\n\nIn function: %s(), %s:%d\n\n", function, file, line ); - // assert( 0 ); return error_code; } diff --git a/lib_com/options.h b/lib_com/options.h index 7dd0ba57d3ee910d474c827457a4edd6ea2fba2d..dd37e87f03ab866d3156194bb99d899df33d6ba4 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -155,6 +155,7 @@ /*#define FIX_I4_OL_PITCH*/ /* fix open-loop pitch used for EVS core switching */ #define SPLIT_REND_WITH_HEAD_ROT /* Dlb,FhG: Split Rendering contributions 21 and 35 */ +#define ISAR_BITSTREAM_UPDATE_LC3PLUS /* FhG: Multiple improvements to the ISAR bitstream when LC3plus is used. See MR 1456 for details. */ #define SPLIT_REND_POSE_CORRECTION_UNUSED_BITS #define FIX_NUM_SUBFRAME_UPDATE diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 71f89ea508d9baf17ccb9aa12ed166c08d0a94a2..33e820a9cf88ea2c378c0c1f3c1251f68e669687 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -271,6 +271,10 @@ static ivas_error isar_set_split_rend_setup( splitRendBits->codec = ISAR_SPLIT_REND_CODEC_DEFAULT; splitRendBits->pose_correction = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE; splitRendBits->codec_frame_size_ms = 0; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + splitRendBits->isar_frame_size_ms = 0; + splitRendBits->lc3plus_highres = 0; +#endif if ( ( hSplitBinRend->hMultiBinCldfbData = (ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA_HANDLE) malloc( sizeof( ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA ) ) ) == NULL ) { @@ -1230,6 +1234,9 @@ ivas_error IVAS_DEC_GetSplitBinauralBitstream( Quaternion, st_ivas->hRenderConfig->split_rend_config.splitRendBitRate, st_ivas->hRenderConfig->split_rend_config.codec, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + st_ivas->hRenderConfig->split_rend_config.isar_frame_size_ms, +#endif st_ivas->hRenderConfig->split_rend_config.codec_frame_size_ms, splitRendBits, Cldfb_RealBuffer_Binaural, @@ -2110,14 +2117,22 @@ static ivas_error copyRendererConfigStruct( mvr2r( hRCin->roomAcoustics.pAcoustic_dsr, hRCout->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX ); mvr2r( hRCin->directivity, hRCout->directivity, 3 * MAX_NUM_OBJECTS ); #ifdef SPLIT_REND_WITH_HEAD_ROT + /* TODO: This seems wrong. Why set default instead of copying from hRCin? + * Currently seems to work because we only ever copy from a default-initialized handle anyway */ hRCout->split_rend_config.splitRendBitRate = SPLIT_REND_768k; hRCout->split_rend_config.dof = 3; hRCout->split_rend_config.hq_mode = 0; hRCout->split_rend_config.codec_delay_ms = 0; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hRCout->split_rend_config.isar_frame_size_ms = 20; +#endif hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */ hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hRCout->split_rend_config.lc3plus_highres = hRCin->split_rend_config.lc3plus_highres; +#endif #endif hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er; hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity; @@ -3809,7 +3824,15 @@ ivas_error IVAS_DEC_GetSplitRendBitstreamHeader( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ ISAR_SPLIT_REND_CODEC *pCodec, /* o: pointer to codec setting */ ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o: pointer to pose correction mode */ - int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ ) +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t *pIsar_frame_size_ms, /* o: pointer to isar frame size setting */ +#endif + int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t *pLc3plusHighRes +#endif +) { if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) { @@ -3819,6 +3842,10 @@ ivas_error IVAS_DEC_GetSplitRendBitstreamHeader( *pCodec = hIvasDec->st_ivas->hRenderConfig->split_rend_config.codec; *pCodec_frame_size_ms = hIvasDec->st_ivas->hRenderConfig->split_rend_config.codec_frame_size_ms; *poseCorrection = hIvasDec->st_ivas->hRenderConfig->split_rend_config.poseCorrectionMode; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + *pIsar_frame_size_ms = hIvasDec->st_ivas->hRenderConfig->split_rend_config.isar_frame_size_ms; + *pLc3plusHighRes = hIvasDec->st_ivas->hRenderConfig->split_rend_config.lc3plus_highres; +#endif return IVAS_ERR_OK; } @@ -3907,8 +3934,10 @@ static void *pcm_buffer_offset( } break; default: - return NULL; + break; } + + return NULL; } diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 9a2b6d4b16929457cabad7a37dada51439003002..bafbf36dace0112580f621a01166171d6dccfc98 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -182,7 +182,14 @@ ivas_error IVAS_DEC_GetSplitRendBitstreamHeader( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ ISAR_SPLIT_REND_CODEC *pCodec, /* o: pointer to codec setting */ ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o: pointer to pose correction mode */ - int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t *pIsar_frame_size_ms, /* o: pointer to isar frame size setting */ +#endif + int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t *pLc3plusHighRes /* o: pointer to LC3plus High-Res setting */ +#endif ); /*! r: decoder error code */ diff --git a/lib_isar/isar_cnst.h b/lib_isar/isar_cnst.h index aa475a9c9a7506d80c801d0ebd334de6ba4ebfef..d93f9ae39f7b0f2fac02a21309086c42eb6273d6 100644 --- a/lib_isar/isar_cnst.h +++ b/lib_isar/isar_cnst.h @@ -115,6 +115,10 @@ typedef enum #define ISAR_SPLIT_REND_ROT_AXIS_BITS 3 #define ISAR_SPLIT_REND_RO_FLAG_BITS 1 +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#define IVAS_LC3PLUS_MAX_NUM_DECODERS 2 +#endif + /*----------------------------------------------------------------------------------* * Split rendering bitrate constants *----------------------------------------------------------------------------------*/ diff --git a/lib_isar/isar_lc3plus_common.c b/lib_isar/isar_lc3plus_common.c index e878b890cf2b683d617a8a40aee20cede88f69ca..7a9010335f2690c40b4931a374575113efcea973 100644 --- a/lib_isar/isar_lc3plus_common.c +++ b/lib_isar/isar_lc3plus_common.c @@ -57,4 +57,33 @@ ivas_error ISAR_LC3PLUS_LC3plusErrToIvasErr( return IVAS_ERR_INTERNAL; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +ivas_error IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( const LC3PLUS_RTP_ERR lc3PlusRtpError ) +{ + switch ( lc3PlusRtpError ) + { + case LC3PLUS_RTP_ERR_NO_ERROR: + return IVAS_ERR_OK; + case LC3PLUS_RTP_ERR_NULL_PTR: + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + case LC3PLUS_RTP_ERR_INVALID_PARAMETERS: + return IVAS_ERR_WRONG_PARAMS; + case LC3PLUS_RTP_ERR_NOT_IMPLEMENTED: + return IVAS_ERR_NOT_IMPLEMENTED; + case LC3PLUS_RTP_ERR_UNSUPPORTED_CONFIGURATION: + return IVAS_ERR_INTERNAL; + case LC3PLUS_RTP_ERR_INVALID_BITSTREAM: + return IVAS_ERR_UNEXPECTED_LC3PLUS_BITSTREAM; + case LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE: + return IVAS_ERR_INVALID_BUFFER_SIZE; + case LC3PLUS_RTP_ERR_NOT_ENOUGH_FTDS_ALLOCATED: + return IVAS_ERR_INTERNAL; + case LC3PLUS_RTP_ERR_GENERIC_ERROR: + default: + break; + } + + return IVAS_ERR_UNKNOWN; +} +#endif #endif diff --git a/lib_isar/isar_lc3plus_common.h b/lib_isar/isar_lc3plus_common.h index e350129499e2016a974b469cc6f5977cb76ab84d..13decaf944f66782242f51c8c09bed0b17da9806 100644 --- a/lib_isar/isar_lc3plus_common.h +++ b/lib_isar/isar_lc3plus_common.h @@ -35,25 +35,38 @@ #include +#include "options.h" #include "ivas_error.h" #ifdef SPLIT_REND_WITH_HEAD_ROT #include "lc3.h" +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#include "isar_lc3plus_payload.h" +#endif /*! common configuration parameters between encoder and decoder */ typedef struct LC3PLUS_CONFIG { /*! frame duration in microseconds [10000, 5000, 2500] */ - uint32_t lc3plus_frame_duration_us; - /*! ivas frame duration in microseconds [20000, 5000] */ - uint32_t ivas_frame_duration_us; + int16_t lc3plus_frame_duration_us; + /*! isar frame duration in microseconds [20000, 10000, 5000] */ + int16_t isar_frame_duration_us; /*! sampling rate*/ - uint32_t samplerate; + int32_t samplerate; /*! number of channels */ - uint16_t channels; + int16_t channels; +#if defined ISAR_BITSTREAM_UPDATE_LC3PLUS || defined ISAR_BITSTREAM_UPDATE_LC3PLUS + /*! high resolution mode enabled (1) or disabled (0)*/ + int16_t high_res_mode_enabled; +#endif } LC3PLUS_CONFIG; /*! utility function to convert LC3PLUS_Errors to the suitable ivas_error */ ivas_error ISAR_LC3PLUS_LC3plusErrToIvasErr( const LC3PLUS_Error lc3PlusError ); + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +/*! utility function to convert LC3PLUS_Errors to the suitable ivas_error */ +ivas_error IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( const LC3PLUS_RTP_ERR lc3PlusRtpError ); #endif -#endif /* IVAS_LC3PLUS_COM_H */ +#endif /* SPLIT_REND_WITH_HEAD_ROT */ +#endif /* ISAR_LC3PLUS_COM_H */ diff --git a/lib_isar/isar_lc3plus_dec.c b/lib_isar/isar_lc3plus_dec.c index 7ca5dda48eb0a08a0068b9a79d2db339c95fa34c..565f55e8cc5ee90cb679e1789b96684762001732 100644 --- a/lib_isar/isar_lc3plus_dec.c +++ b/lib_isar/isar_lc3plus_dec.c @@ -42,6 +42,7 @@ #ifdef SPLIT_REND_WITH_HEAD_ROT +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS /*------------------------------------------------------------------------- * isar_LC3PLUS_AllocateSubframeDecodingMatrix() * @@ -60,6 +61,7 @@ static void isar_LC3PLUS_DEC_FreeSubframeDecodingMatrix( return; } +#endif /*------------------------------------------------------------------------- @@ -75,20 +77,37 @@ ivas_error ISAR_LC3PLUS_DEC_Open( { LC3PLUS_Error err; int32_t decoder_size; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t i; + + if ( 0 == config.lc3plus_frame_duration_us ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid lc3plus_frame_duration_us (0)\n" ); + } +#else int16_t lc3plusFrameIdx; int16_t numLC3plusFramesPerIvasFrame; int16_t i; +#endif 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" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( config.channels > IVAS_LC3PLUS_MAX_NUM_DECODERS ) + { + return IVAS_ERROR( IVAS_ERR_INIT_ERROR, "Maximum number of channels exceeds IVAS_LC3PLUS_MAX_NUM_DECODERS\n" ); + } +#else + if ( 0 == config.lc3plus_frame_duration_us ) { return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid lc3plus_frame_duration_us (0)\n" ); } - numLC3plusFramesPerIvasFrame = (int16_t) ( config.ivas_frame_duration_us / config.lc3plus_frame_duration_us ); + numLC3plusFramesPerIvasFrame = (int16_t) ( config.isar_frame_duration_us / config.lc3plus_frame_duration_us ); +#endif ( *handle )->num_decs = 0; @@ -147,7 +166,11 @@ ivas_error ISAR_LC3PLUS_DEC_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + err = lc3plus_dec_init( ( *handle )->handles[iCh], config.samplerate, 1, LC3PLUS_PLC_ADVANCED, config.high_res_mode_enabled ); +#else err = lc3plus_dec_init( ( *handle )->handles[iCh], config.samplerate, 1, LC3PLUS_PLC_ADVANCED, 0 ); +#endif if ( LC3PLUS_OK != err ) { ISAR_LC3PLUS_DEC_Close( handle ); @@ -168,18 +191,24 @@ ivas_error ISAR_LC3PLUS_DEC_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS if ( ( ( *handle )->selective_decoding_states[iCh]->frame_actions = malloc( numLC3plusFramesPerIvasFrame * sizeof( SelectiveDecAction ) ) ) == NULL ) { ISAR_LC3PLUS_DEC_Close( handle ); return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); } +#endif ( *handle )->selective_decoding_states[iCh]->has_skipped_a_frame = 0; ( *handle )->selective_decoding_states[iCh]->shall_decode_cached_frame = 0; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ( *handle )->selective_decoding_states[iCh]->frame_action = DEC_ACTION_DECODE_AND_USE; +#else for ( lc3plusFrameIdx = 0; lc3plusFrameIdx < numLC3plusFramesPerIvasFrame; lc3plusFrameIdx++ ) { ( *handle )->selective_decoding_states[iCh]->frame_actions[lc3plusFrameIdx] = DEC_ACTION_DECODE_AND_USE; } +#endif /* allocate and configure per LC3plus decoder bitstream cache */ if ( ( ( *handle )->bitstream_caches[iCh] = malloc( sizeof( ISAR_LC3PLUS_DEC_BITSTREAM_CACHE ) ) ) == NULL ) @@ -187,7 +216,11 @@ ivas_error ISAR_LC3PLUS_DEC_Open( ISAR_LC3PLUS_DEC_Close( handle ); return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity = 400 /*LC3plus max non-HR octet count*/; +#else ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity = 400 /*LC3plus max non-HR octet count*/ * numLC3plusFramesPerIvasFrame; +#endif if ( ( ( *handle )->bitstream_caches[iCh]->bitstream_cache = malloc( ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity ) ) == NULL ) { ISAR_LC3PLUS_DEC_Close( handle ); @@ -197,7 +230,7 @@ ivas_error ISAR_LC3PLUS_DEC_Open( } ( *handle )->config = config; - if ( config.ivas_frame_duration_us < config.lc3plus_frame_duration_us || config.ivas_frame_duration_us % config.lc3plus_frame_duration_us != 0 ) + 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" ); @@ -212,7 +245,7 @@ ivas_error ISAR_LC3PLUS_DEC_Open( return IVAS_ERR_OK; } - +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix() * @@ -261,7 +294,7 @@ ivas_error ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( int16_t numIvasSubFramesPerLC3frame; uint32_t decIdx; int16_t ivasSubframeIdx; - int16_t effectiveIvasSubframeDuration; + int16_t effectiveIsarSubframeDuration; int16_t actual_num_spatial_subframes; if ( NULL == handle ) @@ -274,14 +307,14 @@ ivas_error ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "subframeChannelMatrix is NULL\n" ); } - if ( handle->config.lc3plus_frame_duration_us == 0 || handle->config.ivas_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) + if ( handle->config.lc3plus_frame_duration_us == 0 || handle->config.isar_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) { - return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "invalid ivas_frame_duration_us/lc3plus_frame_duration_us values\n" ); + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "invalid isar_frame_duration_us/lc3plus_frame_duration_us values\n" ); } - effectiveIvasSubframeDuration = (int16_t) ( handle->config.ivas_frame_duration_us == 20000 ? handle->config.ivas_frame_duration_us / MAX_PARAM_SPATIAL_SUBFRAMES : handle->config.ivas_frame_duration_us ); - numIvasSubFramesPerLC3frame = (int16_t) handle->config.lc3plus_frame_duration_us / effectiveIvasSubframeDuration; - actual_num_spatial_subframes = (int16_t) handle->config.ivas_frame_duration_us / effectiveIvasSubframeDuration; + effectiveIsarSubframeDuration = (int16_t) ( handle->config.isar_frame_duration_us == 20000 ? handle->config.isar_frame_duration_us / MAX_PARAM_SPATIAL_SUBFRAMES : handle->config.isar_frame_duration_us ); + numIvasSubFramesPerLC3frame = (int16_t) handle->config.lc3plus_frame_duration_us / effectiveIsarSubframeDuration; + actual_num_spatial_subframes = (int16_t) handle->config.isar_frame_duration_us / effectiveIsarSubframeDuration; /* 0.5(0) = 10ms lc3plus, 5ms subframe */ if ( numIvasSubFramesPerLC3frame != 1 ) { @@ -360,6 +393,7 @@ ivas_error ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( return IVAS_ERR_OK; } +#endif /*------------------------------------------------------------------------- @@ -430,7 +464,9 @@ void ISAR_LC3PLUS_DEC_Close( if ( NULL != ( *handle )->selective_decoding_states && NULL != ( *handle )->selective_decoding_states[iDec] ) { +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS free( ( *handle )->selective_decoding_states[iDec]->frame_actions ); +#endif free( ( *handle )->selective_decoding_states[iDec] ); } @@ -509,13 +545,20 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( ) { uint32_t iDec; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t config_num_media_times; + int32_t iMediaTime; + int32_t iFtd; + LC3PLUS_RTP_PAYLOAD payload; +#else int32_t iLc3plusFrame; int32_t lc3framesPerIvasFrame; + int32_t bitstreamOffsetPerCoder; + uint8_t *bitstream_in_iter = bitstream_in; +#endif int32_t ivasSampleIndex; int16_t numSamplesPerLC3plusChannel; - int32_t bitstreamOffsetPerCoder; ivas_error err; - uint8_t *bitstream_in_iter = bitstream_in; if ( NULL == handle ) { @@ -538,19 +581,59 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "bitstream_in_size must be positive\n" ); } - if ( handle->config.ivas_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) + if ( handle->config.isar_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) { - return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "ivas_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "isar_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); + } + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + config_num_media_times = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; + if ( !badFrameIndicator ) + { + if ( LC3PLUS_RTP_payload_deserialize( &payload, bitstream_in, bitstream_in_size ) != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "LC3PLUS_RTP_payload_deserialize failed\n" ); + } + if ( payload.sampling_rate_hz != handle->config.samplerate ) + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (samplerate) in bitstream is not supported\n" ); + } + if ( payload.num_channels != handle->config.channels ) + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of channels) in bitstream is not supported\n" ); + } + 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" ); + } + if ( payload.high_resolution_enabled != handle->config.high_res_mode_enabled ) + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (high resolution mode) in bitstream is not supported\n" ); + } + if ( payload.num_media_times != config_num_media_times ) + { + 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 - lc3framesPerIvasFrame = handle->config.ivas_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + 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++ ) + { + for ( iMediaTime = 0; iMediaTime < config_num_media_times; iMediaTime++ ) + { + iFtd = iDec + iMediaTime * handle->num_decs; +#else + lc3framesPerIvasFrame = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; - numSamplesPerLC3plusChannel = (int16_t) ( handle->config.samplerate / ( 1000000 / handle->config.ivas_frame_duration_us ) / lc3framesPerIvasFrame ); + numSamplesPerLC3plusChannel = (int16_t) ( handle->config.samplerate / ( 1000000 / handle->config.isar_frame_duration_us ) / lc3framesPerIvasFrame ); bitstreamOffsetPerCoder = bitstream_in_size / handle->num_decs / lc3framesPerIvasFrame; for ( iDec = 0; iDec < handle->num_decs; iDec++ ) { for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) { +#endif if ( handle->selective_decoding_states[iDec]->shall_decode_cached_frame ) { if ( 0 == handle->bitstream_caches[iDec]->bitstream_cache_size ) @@ -572,8 +655,14 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( { handle->bitstream_caches[iDec]->bitstream_cache_size = 0; } + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + switch ( handle->selective_decoding_states[iDec]->frame_action ) +#else switch ( handle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] ) +#endif { +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS case DEC_ACTION_DECODE_AND_DROP: { err = decode_or_conceal_one_lc3plus_frame( handle->handles[iDec], bitstream_in_iter, bitstreamOffsetPerCoder, &handle->pcm_conversion_buffer, badFrameIndicator ); @@ -584,8 +673,37 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( handle->selective_decoding_states[iDec]->has_skipped_a_frame = 0; break; } +#endif case DEC_ACTION_DECODE_AND_USE: { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( badFrameIndicator ) + { + err = decode_or_conceal_one_lc3plus_frame( handle->handles[iDec], bitstream_in, bitstream_in_size, &handle->pcm_conversion_buffer, badFrameIndicator ); + } + else if ( payload.ftds[iFtd].frame_data_length == LC3PLUS_RTP_FDL_SPEECH_BAD ) + { + return IVAS_ERR_NOT_IMPLEMENTED; + /* Untested therefore disabled. Would probably only need to call concealment, + * but the LC3plus API requires a non-NULL ptr for this which is not available here */ + } + else + { + err = decode_or_conceal_one_lc3plus_frame( handle->handles[iDec], payload.ftds[iFtd].frame_data, payload.ftds[iFtd].frame_data_length, &handle->pcm_conversion_buffer, badFrameIndicator ); + } + if ( err != IVAS_ERR_OK ) + { + return IVAS_ERROR( err, "lc3plus decoding failed\n" ); + } + + for ( int16_t iSampleInt16 = 0; iSampleInt16 < numSamplesPerLC3plusChannel; iSampleInt16++ ) + { + ivasSampleIndex = iSampleInt16 + iMediaTime * numSamplesPerLC3plusChannel; + pcm_out[iDec][ivasSampleIndex] = (float) handle->pcm_conversion_buffer[iSampleInt16]; + } + handle->selective_decoding_states[iDec]->has_skipped_a_frame = 0; + break; +#else err = decode_or_conceal_one_lc3plus_frame( handle->handles[iDec], bitstream_in_iter, bitstreamOffsetPerCoder, &handle->pcm_conversion_buffer, badFrameIndicator ); if ( err != IVAS_ERR_OK ) { @@ -599,15 +717,30 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( } handle->selective_decoding_states[iDec]->has_skipped_a_frame = 0; break; +#endif } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS case DEC_ACTION_SKIP: { /* log that this instance has skipped a frame and must decode twice once reactivated */ handle->selective_decoding_states[iDec]->has_skipped_a_frame = 1; break; } +#endif case DEC_ACTION_CACHE: { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( handle->bitstream_caches[iDec]->bitstream_cache_capacity < (int32_t) payload.ftds[iFtd].frame_data_length ) + { + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "bitstream_cache_capacity is too low for LC3plus frame size\n" ); + } + /* store bit rate of cached frame */ + mvc2c( payload.ftds[iFtd].frame_data, handle->bitstream_caches[iDec]->bitstream_cache, (int16_t) payload.ftds[iFtd].frame_data_length ); + handle->bitstream_caches[iDec]->bitstream_cache_size = payload.ftds[iFtd].frame_data_length; + /* log that this instance has skipped a frame and must decode twice once reactivated */ + handle->selective_decoding_states[iDec]->has_skipped_a_frame = 1; + break; +#else if ( handle->bitstream_caches[iDec]->bitstream_cache_capacity < bitstreamOffsetPerCoder ) { return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "bitstream_cache_capacity is too low for LC3plus frame size\n" ); @@ -618,11 +751,18 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( /* log that this instance has skipped a frame and must decode twice once reactivated */ handle->selective_decoding_states[iDec]->has_skipped_a_frame = 1; break; +#endif } case DEC_ACTION_NUM_ENUMS: default: return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "invalid LC3plus decoder state\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + } /* for each media time */ + /* reset skipping state, must be set by the user before each decode call*/ + handle->selective_decoding_states[iDec]->frame_action = DEC_ACTION_DECODE_AND_USE; + } /* for each dec/channel */ +#else bitstream_in_iter += bitstreamOffsetPerCoder; } @@ -634,6 +774,7 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( } } +#endif return IVAS_ERR_OK; } diff --git a/lib_isar/isar_lc3plus_dec.h b/lib_isar/isar_lc3plus_dec.h index 576c576959328c36b2f1beede10fa350a8b7f8d4..91af70cef2ef3f192883d2c72c462cd3d29fe451 100644 --- a/lib_isar/isar_lc3plus_dec.h +++ b/lib_isar/isar_lc3plus_dec.h @@ -44,9 +44,13 @@ typedef enum { +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS DEC_ACTION_DECODE_AND_DROP = 0, +#endif DEC_ACTION_DECODE_AND_USE, +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS DEC_ACTION_SKIP, +#endif DEC_ACTION_CACHE, DEC_ACTION_NUM_ENUMS } SelectiveDecAction; @@ -56,8 +60,13 @@ typedef struct ISAR_LC3PLUS_DEC_SELECTIVE_DECODING_STATE { /*! indicates that the decoder has skipped one or more frames. This means it must decode two frames to flush algorithmic delay when re-activated */ int16_t has_skipped_a_frame; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /*! action to execute for the next frame */ + SelectiveDecAction frame_action; +#else /*! if set to 1, decoder will skip decoding for the next frame */ SelectiveDecAction *frame_actions; +#endif /*! if set to 1, decoder will decode the cache before decoding any of current frames */ int16_t shall_decode_cached_frame; } ISAR_LC3PLUS_DEC_SELECTIVE_DECODING_STATE; @@ -94,11 +103,13 @@ void ISAR_LC3PLUS_DEC_Close( ISAR_LC3PLUS_DEC_HANDLE *handle /* i/o: pointer to decoder handle */ ); +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS /*! Sets a matrix[MAX_PARAM_SPATIAL_SUBFRAMES][numLC3plusDecoders] where all require subframes must be flagged with 1, frames that are not required with 0 */ ivas_error ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( ISAR_LC3PLUS_DEC_HANDLE handle, /* i : decoder handle */ int16_t *subframeChannelMatrix[MAX_PARAM_SPATIAL_SUBFRAMES] /* i : */ ); +#endif ivas_error ISAR_LC3PLUS_DEC_Decode( ISAR_LC3PLUS_DEC_HANDLE handle, /* i : decoder handle */ @@ -112,10 +123,13 @@ ivas_error ISAR_LC3PLUS_DEC_Conceal( float **pcm_out /* o : concealed samples */ ); +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS ivas_error ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( int16_t ***subframeChannelMatrix, const uint32_t num_decs ); +void ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( int16_t **subframeChannelMatrix ); #endif -#endif /* IVAS_LC3PLUS_DEC_H */ +#endif /* SPLIT_REND_WITH_HEAD_ROT */ +#endif /* ISAR_LC3PLUS_DEC_H */ diff --git a/lib_isar/isar_lc3plus_enc.c b/lib_isar/isar_lc3plus_enc.c index 4de75cc5265081fc2bf53a45c21df7f7c705556c..da2c1d48f047b8ecbe725b6d2e53430598d07f74 100644 --- a/lib_isar/isar_lc3plus_enc.c +++ b/lib_isar/isar_lc3plus_enc.c @@ -36,6 +36,50 @@ #include "ivas_error_utils.h" #include "prot.h" #include "wmc_auto.h" +#include "options.h" + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +static const LC3PLUS_RTP_FDL s_fdl_request = LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA; +#endif + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +static int32_t limit_per_channel_bitrate( LC3PLUS_CONFIG config, + int32_t per_channel_bitrate ) +{ + if ( config.high_res_mode_enabled ) + { + switch ( config.lc3plus_frame_duration_us ) + { + case 10000: + return min( per_channel_bitrate, 500000 ); + case 5000: + return min( per_channel_bitrate, 600000 ); + case 2500: + return min( per_channel_bitrate, 672000 ); + default: + assert( false && "unreachable" ); + } + } + + switch ( config.samplerate ) + { + case 48000: + case 32000: + return min( per_channel_bitrate, 320000 ); + case 24000: + return min( per_channel_bitrate, 314400 ); + case 16000: + return min( per_channel_bitrate, 221600 ); + case 8000: + return min( per_channel_bitrate, 114400 ); + default: + assert( false && "unreachable" ); + } + + assert( false && "unreachable" ); + return -1; +} +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT /*-------------------------------------------------------------------* @@ -50,7 +94,19 @@ ivas_error ISAR_LC3PLUS_ENC_Open( ISAR_LC3PLUS_ENC_HANDLE *handle /* o : encoder handle */ ) { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t num_lc3plus_media_times_per_ivas_frame; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t lc3plus_num_bytes_per_frame; +#endif + bool is_last_media_time, is_last_channel; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ivas_error ivas_err; +#endif +#endif +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS int32_t bitsPerSecondPerChannel; +#endif int32_t encoder_size; LC3PLUS_Error err; int32_t lfeChans[1]; @@ -62,8 +118,19 @@ ivas_error ISAR_LC3PLUS_ENC_Open( { return IVAS_ERROR( IVAS_ERR_INTERNAL, "Invalid number of channels\n" ); } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS bitsPerSecondPerChannel = bitsPerSecond / config.channels; - +#endif +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( config.lc3plus_frame_duration_us != 2500 && config.lc3plus_frame_duration_us != 5000 && config.lc3plus_frame_duration_us != 10000 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "Invalid lc3plus_frame_duration_us\n" ); + } + if ( config.isar_frame_duration_us != 20000 && config.isar_frame_duration_us != 10000 && config.isar_frame_duration_us != 5000 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "Invalid isar_frame_duration_us\n" ); + } +#endif encoder_size = lc3plus_enc_get_size( config.samplerate, 1 ); if ( 0 == encoder_size ) { @@ -74,6 +141,10 @@ ivas_error ISAR_LC3PLUS_ENC_Open( { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ( *handle )->config = config; + ( *handle )->frame_type_descriptors = NULL; +#endif ( *handle )->pcm_conversion_buffer = NULL; ( *handle )->num_encs = 0; @@ -88,6 +159,17 @@ ivas_error ISAR_LC3PLUS_ENC_Open( ( *handle )->handles[i] = NULL; } ( *handle )->num_encs = config.channels; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + num_lc3plus_media_times_per_ivas_frame = config.isar_frame_duration_us / config.lc3plus_frame_duration_us; + ( *handle )->fdl_request = s_fdl_request; + ( *handle )->num_ftds = config.channels * num_lc3plus_media_times_per_ivas_frame; + ( *handle )->frame_type_descriptors = malloc( ( *handle )->num_ftds * sizeof( LC3PLUS_RTP_FTD ) ); + if ( NULL == ( *handle )->frame_type_descriptors ) + { + ISAR_LC3PLUS_ENC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus frame_type_descriptors\n" ); + } +#endif for ( int32_t iCh = 0; iCh < config.channels; iCh++ ) { @@ -97,7 +179,11 @@ ivas_error ISAR_LC3PLUS_ENC_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus encoder\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + err = lc3plus_enc_init( ( *handle )->handles[iCh], config.samplerate, 1, config.high_res_mode_enabled, lfeChans ); +#else err = lc3plus_enc_init( ( *handle )->handles[iCh], config.samplerate, 1, 0, lfeChans ); +#endif if ( err != LC3PLUS_OK ) { ISAR_LC3PLUS_ENC_Close( handle ); @@ -110,22 +196,25 @@ ivas_error ISAR_LC3PLUS_ENC_Open( ISAR_LC3PLUS_ENC_Close( handle ); return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_enc_set_frame_dms failed\n" ); } - +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS err = lc3plus_enc_set_bitrate( ( *handle )->handles[iCh], bitsPerSecondPerChannel ); if ( err != LC3PLUS_OK ) { ISAR_LC3PLUS_ENC_Close( handle ); return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_enc_set_bitrate failed\n" ); } +#endif } - if ( config.ivas_frame_duration_us < config.lc3plus_frame_duration_us || config.ivas_frame_duration_us % config.lc3plus_frame_duration_us != 0 ) + if ( config.isar_frame_duration_us < config.lc3plus_frame_duration_us || config.isar_frame_duration_us % config.lc3plus_frame_duration_us != 0 ) { ISAR_LC3PLUS_ENC_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" ); } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS ( *handle )->config = config; +#endif ( *handle )->pcm_conversion_buffer = malloc( sizeof( int16_t ) * config.samplerate * config.lc3plus_frame_duration_us / 1000000 ); if ( NULL == ( *handle )->pcm_conversion_buffer ) { @@ -133,8 +222,170 @@ ivas_error ISAR_LC3PLUS_ENC_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus encoder wrapper pcm_conversion_buffer\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* update FDI fields */ + for ( int32_t iMediaTime = 0; iMediaTime < num_lc3plus_media_times_per_ivas_frame; ++iMediaTime ) + { + for ( uint32_t iEnc = 0; iEnc < ( *handle )->num_encs; ++iEnc ) + { + int32_t ftd_index = iEnc + iMediaTime * ( *handle )->num_encs; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ( *handle )->frame_type_descriptors[ftd_index].frame_data_length = 0; /* will be set to the correct value in IVAS_LC3PLUS_ENC_SetBitrate */ +#else + lc3plus_num_bytes_per_frame = lc3plus_enc_get_num_bytes( ( *handle )->handles[iEnc] ); + if ( lc3plus_num_bytes_per_frame <= 0 ) + { + ISAR_LC3PLUS_ENC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "lc3plus_enc_get_num_bytes reported invalid result failed\n" ); + } + ( *handle )->frame_type_descriptors[ftd_index].frame_data_length = lc3plus_num_bytes_per_frame; +#endif + if ( 0 != LC3PLUS_RTP_ftd_bwr_from_samplerate( &( *handle )->frame_type_descriptors[ftd_index].bwr, config.samplerate, config.high_res_mode_enabled ) ) + { + ISAR_LC3PLUS_ENC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "LC3PLUS_RTP_ftd_bwr_from_samplerate failed\n" ); + } + if ( 0 != LC3PLUS_RTP_ftd_fdi_from_frame_duration_us( &( *handle )->frame_type_descriptors[ftd_index].fdi, config.lc3plus_frame_duration_us ) ) + { + ISAR_LC3PLUS_ENC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "LC3PLUS_RTP_ftd_fdi_from_frame_duration_us failed\n" ); + } + ( *handle )->frame_type_descriptors[ftd_index].h = LC3PLUS_RTP_FTD_H_PRIMARY; + ( *handle )->frame_type_descriptors[ftd_index].frame_data = NULL; + + /* The FTDs in the ToC are included in the following order: + * 1) First the FTD for the first channel of the first FDB (oldest frame) + * 2) Then the FTDs for the remaining channels for the first FDB in increasing CC order + * 3) Then the FTD for the first channel of the second FDB + * 4) Then the FTDs for the remaining channels for the second FDB + * 5) Etc. to the last FDB */ + is_last_media_time = num_lc3plus_media_times_per_ivas_frame - 1 == iMediaTime; + is_last_channel = ( *handle )->num_encs - 1 == iEnc; + if ( is_last_media_time && is_last_channel ) + { + ( *handle )->frame_type_descriptors[ftd_index].fc = LC3PLUS_RTP_FTD_FC_LAST_OVERALL; + } + else if ( !is_last_media_time && is_last_channel ) + { + ( *handle )->frame_type_descriptors[ftd_index].fc = LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME; + } + else + { + ( *handle )->frame_type_descriptors[ftd_index].fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + } + } + } + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ivas_err = IVAS_LC3PLUS_ENC_SetBitrate( *handle, bitsPerSecond ); + if ( ivas_err != IVAS_ERR_OK ) + { + ISAR_LC3PLUS_ENC_Close( handle ); + return ivas_err; + } +#endif +#endif + return IVAS_ERR_OK; +} + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +/*-------------------------------------------------------------------* + * Function IVAS_LC3PLUS_ENC_SetBitrate() + * + * + *-------------------------------------------------------------------*/ + +ivas_error IVAS_LC3PLUS_ENC_SetBitrate( + ISAR_LC3PLUS_ENC_HANDLE handle, /* o : LC3plus encoder handle */ + const uint32_t bitsPerSecond /* i : new target bit rate */ +) +{ + int32_t numLc3plusMediaTimesPerIvasFrame; + int32_t lc3plus_num_bytes_per_frame; + int32_t availableOctetsPerIsarFrame; + int32_t actualOctetsPerFrame; + LC3PLUS_Error err; + int32_t iFtd; + int32_t fdrLength; + int32_t lc3plusPacketRate; + int32_t numSubframes; + int32_t minPayloadOverhead; + int32_t targetLc3PlusBitratePerChannel; + int32_t targetLc3PlusOctetCount; + int32_t lc3plusFdlLength; + + if ( NULL == handle ) + { + return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "LC3PLUS_Enc_Wrap_Handle is NULL\n" ); + } + + availableOctetsPerIsarFrame = bitsPerSecond / ( 1000000 / handle->config.isar_frame_duration_us ) / 8; + lc3plusPacketRate = 1000 * 1000 / handle->config.lc3plus_frame_duration_us; + numLc3plusMediaTimesPerIvasFrame = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; + numSubframes = numLc3plusMediaTimesPerIvasFrame * handle->config.channels; + + /* subtract minimum required payload bytes & calculate a first per-channel target bit rate */ + if ( LC3PLUS_RTP_frame_data_length_get_size( &fdrLength, s_fdl_request ) != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "LC3PLUS_RTP_frame_data_length_get_size failed\n" ); + } + minPayloadOverhead = fdrLength + ( numSubframes * LC3PLUS_RTP_FTD_MIN_SIZE ); + targetLc3PlusBitratePerChannel = ( availableOctetsPerIsarFrame - minPayloadOverhead ) / handle->config.channels * 8 * lc3plusPacketRate / numLc3plusMediaTimesPerIvasFrame; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( targetLc3PlusBitratePerChannel <= 0 ) + { + return IVAS_ERROR( IVAS_ERR_LC3PLUS_INVALID_BITRATE, "available LC3plus bitrate <= 0\n" ); + } +#endif + targetLc3PlusBitratePerChannel = limit_per_channel_bitrate( handle->config, targetLc3PlusBitratePerChannel ); + targetLc3PlusOctetCount = targetLc3PlusBitratePerChannel / 8 / lc3plusPacketRate; + /* check resulting octet count. If it requires larger than 1-byte length fields, decrease the bitrate by enough to make room for the additional length field */ + if ( LC3PLUS_RTP_frame_data_length_get_size( &lc3plusFdlLength, targetLc3PlusOctetCount ) != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "LC3PLUS_RTP_frame_data_length_get_size failed\n" ); + } + if ( lc3plusFdlLength != LC3PLUS_RTP_FDL_MIN_LENGTH ) + { + /* reduce bitrate to allow for the required fdl field */ + targetLc3PlusBitratePerChannel = ( targetLc3PlusOctetCount - ( lc3plusFdlLength - LC3PLUS_RTP_FDL_MIN_LENGTH ) ) / handle->config.channels * 8 * lc3plusPacketRate; + } + + for ( int32_t iCh = 0; iCh < handle->config.channels; iCh++ ) + { + err = lc3plus_enc_set_bitrate( handle->handles[iCh], targetLc3PlusBitratePerChannel ); + if ( err != LC3PLUS_OK ) + { + return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_enc_set_bitrate failed\n" ); + } + } + + // update FTD settings after bitrate change + for ( int32_t iMediaTime = 0; iMediaTime < numLc3plusMediaTimesPerIvasFrame; ++iMediaTime ) + { + for ( uint32_t iEnc = 0; iEnc < handle->num_encs; ++iEnc ) + { + iFtd = iEnc + iMediaTime * handle->num_encs; + lc3plus_num_bytes_per_frame = lc3plus_enc_get_num_bytes( handle->handles[iEnc] ); + if ( lc3plus_num_bytes_per_frame <= 0 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "lc3plus_enc_get_num_bytes reported invalid result failed\n" ); + } + handle->frame_type_descriptors[iFtd].frame_data_length = lc3plus_num_bytes_per_frame; + } + } + + // TODO: remove sanity checks? + if ( ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( handle, &actualOctetsPerFrame ) != IVAS_ERR_OK ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "ISAR_LC3PLUS_ENC_GetOutputBitstreamSize failed\n" ); + } + if ( actualOctetsPerFrame > availableOctetsPerIsarFrame ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "Bitrate reduction logic failed\n" ); + } return IVAS_ERR_OK; } +#endif /*-------------------------------------------------------------------* @@ -191,7 +442,15 @@ ivas_error ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( int32_t *bsSize /* o : size of each bitstream frame in bytes */ ) { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_RTP_ERR rtp_err; + int32_t num_lc3plus_media_times_per_ivas_frame; + int32_t iMediaTime; + int32_t ftd_frame_data_length_size, lc3plus_frame_data_length; + int32_t ftd_index; +#else int32_t bitstreamSizeMultiplier; +#endif if ( NULL == handle ) { return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "LC3PLUS_Enc_Wrap_Handle is NULL\n" ); @@ -201,23 +460,65 @@ ivas_error ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "bsSize is NULL\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( 0 == handle->config.lc3plus_frame_duration_us ) + { + return IVAS_ERROR( IVAS_ERR_INIT_ERROR, "lc3plus_frame_duration_us is 0\n" ); + } + if ( handle->config.isar_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "isar_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); + } + + num_lc3plus_media_times_per_ivas_frame = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#endif *bsSize = 0; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t fdl_request_length; + rtp_err = LC3PLUS_RTP_frame_data_length_get_size( &fdl_request_length, handle->fdl_request ); + if ( rtp_err != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid LC3plus frame_data_length request\n" ); + } + *bsSize += fdl_request_length; +#endif for ( uint32_t iEnc = 0; iEnc < handle->num_encs; iEnc++ ) { if ( NULL == handle->handles[iEnc] ) { return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "LC3plus encoder handle is NULL\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + lc3plus_frame_data_length = lc3plus_enc_get_num_bytes( handle->handles[iEnc] ); + for ( iMediaTime = 0; iMediaTime < num_lc3plus_media_times_per_ivas_frame; ++iMediaTime ) + { + ftd_index = iEnc + iMediaTime * handle->num_encs; + if ( lc3plus_frame_data_length != (int32_t) handle->frame_type_descriptors[ftd_index].frame_data_length ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "LC3plus FTD data not synchronised with encoder bitrate\n" ); + } + rtp_err = LC3PLUS_RTP_frame_data_length_get_size( &ftd_frame_data_length_size, handle->frame_type_descriptors[ftd_index].frame_data_length ); + if ( rtp_err != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid LC3plus frame_data_length\n" ); + } + *bsSize += LC3PLUS_RTP_FTD_LENGTH_EXCLUDING_FDL; + *bsSize += handle->frame_type_descriptors[ftd_index].frame_data_length; + *bsSize += ftd_frame_data_length_size; + } + } +#else *bsSize += lc3plus_enc_get_num_bytes( handle->handles[iEnc] ); } - if ( handle->config.ivas_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) + if ( handle->config.isar_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) { - return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "ivas_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "isar_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); } - bitstreamSizeMultiplier = handle->config.ivas_frame_duration_us / handle->config.lc3plus_frame_duration_us; + bitstreamSizeMultiplier = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; *bsSize *= bitstreamSizeMultiplier; +#endif return IVAS_ERR_OK; } @@ -237,6 +538,12 @@ void ISAR_LC3PLUS_ENC_Close( { return; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( NULL != ( *handle )->frame_type_descriptors ) + { + free( ( *handle )->frame_type_descriptors ); + } +#endif for ( uint32_t iEnc = 0; iEnc < ( *handle )->num_encs; iEnc++ ) { if ( NULL != ( *handle )->handles[iEnc] ) @@ -268,17 +575,28 @@ void ISAR_LC3PLUS_ENC_Close( ivas_error ISAR_LC3PLUS_ENC_Encode( ISAR_LC3PLUS_ENC_HANDLE handle, /* i : LC3plus encoder handle */ float **pcm_in, /* i : pointer input samples */ - void *bitstream_out /* o : pointer to bitstream frame */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + void *bitstream_out, /* o : pointer to bitstream frame */ + const int32_t bitstream_out_size /* i : size of the bitstream_out buffer in bytes. Must be equal to ISAR_LC3PLUS_ENC_GetOutputBitstreamSize. */ +#else + void *bitstream_out /* o : pointer to bitstream frame */ +#endif ) { - uint32_t numSamplesPerLC3plusChannel; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t ftdIndex; + LC3PLUS_RTP_ERR rtpErr; + uint32_t num_media_times; +#else uint32_t lc3framesPerIvasFrame; - int32_t ivasSampleIndex; uint8_t *bitstream_out_iter = bitstream_out; +#endif + uint32_t numSamplesPerLC3plusChannel; + int32_t ivasSampleIndex; int32_t num_bytes = 0; LC3PLUS_Error err; - push_wmops( "IVAS_LC3PLUS_ENC_Encode" ); + push_wmops( "ISAR_LC3PLUS_ENC_Encode" ); if ( NULL == handle ) { @@ -293,26 +611,53 @@ ivas_error ISAR_LC3PLUS_ENC_Encode( return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "bitstream_out is NULL\n" ); } - if ( handle->config.ivas_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) + if ( handle->config.isar_frame_duration_us % handle->config.lc3plus_frame_duration_us != 0 ) { - return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "ivas_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "isar_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); } - lc3framesPerIvasFrame = handle->config.ivas_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + num_media_times = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; + numSamplesPerLC3plusChannel = handle->config.samplerate / ( 1000000 / handle->config.isar_frame_duration_us ) / num_media_times; - numSamplesPerLC3plusChannel = handle->config.samplerate / ( 1000000 / handle->config.ivas_frame_duration_us ) / lc3framesPerIvasFrame; + size_t actual_size; + rtpErr = LC3PLUS_RTP_payload_serialize( bitstream_out, bitstream_out_size, &actual_size, s_fdl_request, handle->frame_type_descriptors, handle->num_ftds ); + if ( rtpErr != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( rtpErr ), "LC3PLUS_RTP_payload_serialize failed\n" ); + } +#else + lc3framesPerIvasFrame = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; + + numSamplesPerLC3plusChannel = handle->config.samplerate / ( 1000000 / handle->config.isar_frame_duration_us ) / lc3framesPerIvasFrame; +#endif for ( uint32_t iEnc = 0; iEnc < handle->num_encs; iEnc++ ) { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + for ( uint32_t iMediaTime = 0; iMediaTime < num_media_times; iMediaTime++ ) +#else for ( uint32_t iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) +#endif { for ( uint32_t iSampleInt16 = 0; iSampleInt16 < numSamplesPerLC3plusChannel; iSampleInt16++ ) { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ivasSampleIndex = iSampleInt16 + iMediaTime * numSamplesPerLC3plusChannel; +#else ivasSampleIndex = iSampleInt16 + iLc3plusFrame * numSamplesPerLC3plusChannel; +#endif handle->pcm_conversion_buffer[iSampleInt16] = (int16_t) max( INT16_MIN, min( pcm_in[iEnc][ivasSampleIndex], INT16_MAX ) ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ftdIndex = iMediaTime * handle->num_encs + iEnc; +#endif num_bytes = 0; push_wmops( "lc3plus_enc16" ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + err = lc3plus_enc16( handle->handles[iEnc], &handle->pcm_conversion_buffer, handle->frame_type_descriptors[ftdIndex].frame_data, &num_bytes, NULL ); +#else err = lc3plus_enc16( handle->handles[iEnc], &handle->pcm_conversion_buffer, bitstream_out_iter, &num_bytes, NULL ); +#endif pop_wmops(); if ( err != LC3PLUS_OK ) { @@ -322,8 +667,15 @@ ivas_error ISAR_LC3PLUS_ENC_Encode( { return IVAS_ERROR( IVAS_ERR_INTERNAL, "lc3plus_enc16 did not produce output\n" ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( num_bytes != (int32_t) handle->frame_type_descriptors[ftdIndex].frame_data_length ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "payload format and lc3plus enc bitrate are not aligned\n" ); + } +#else bitstream_out_iter += num_bytes; +#endif } } diff --git a/lib_isar/isar_lc3plus_enc.h b/lib_isar/isar_lc3plus_enc.h index 1a9f467b5f2f09fe8a83417ad0100dc55e3a1980..3a2dffe63ab3c7f58401fa7903735a8afc5aeaa4 100644 --- a/lib_isar/isar_lc3plus_enc.h +++ b/lib_isar/isar_lc3plus_enc.h @@ -38,6 +38,9 @@ #ifdef SPLIT_REND_WITH_HEAD_ROT #include "lc3.h" #include "isar_lc3plus_common.h" +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#include "isar_lc3plus_payload.h" +#endif /* encoder wrapper */ typedef struct ISAR_LC3PLUS_ENC_HANDLE @@ -46,14 +49,30 @@ typedef struct ISAR_LC3PLUS_ENC_HANDLE LC3PLUS_Enc **handles; uint32_t num_encs; int16_t *pcm_conversion_buffer; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_RTP_FTD *frame_type_descriptors; + int32_t num_ftds; + LC3PLUS_RTP_FDL fdl_request; +#endif } * ISAR_LC3PLUS_ENC_HANDLE; ivas_error ISAR_LC3PLUS_ENC_Open( - const LC3PLUS_CONFIG config, /* i : encoder configuration */ - const uint32_t bitsPerSecond, /* i : bit rate */ + const LC3PLUS_CONFIG config, /* i : encoder configuration */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const uint32_t initialBitsPerSecond, /* i : initial target bit rate */ +#else + const uint32_t bitsPerSecond, /* i : bit rate */ +#endif ISAR_LC3PLUS_ENC_HANDLE *handle /* o : LC3plus encoder handle */ ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +ivas_error IVAS_LC3PLUS_ENC_SetBitrate( + ISAR_LC3PLUS_ENC_HANDLE handle, /* o : LC3plus encoder handle */ + const uint32_t bitsPerSecond /* i : new target bit rate */ +); +#endif + ivas_error ISAR_LC3PLUS_ENC_GetDelay( ISAR_LC3PLUS_ENC_HANDLE handle, /* i : LC3plus encoder handle */ int32_t *delayInSamples /* o : algorithmic delay of encoding and decoding in number of samples per channel */ @@ -61,7 +80,7 @@ ivas_error ISAR_LC3PLUS_ENC_GetDelay( ivas_error ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( ISAR_LC3PLUS_ENC_HANDLE handle, /* i : LC3plus encoder handle */ - int32_t *bsSize /* o : size of each bitstream frame in bytes */ + int32_t *bsSize /* o : size of next bitstream frame in bytes */ ); void ISAR_LC3PLUS_ENC_Close( @@ -71,7 +90,12 @@ void ISAR_LC3PLUS_ENC_Close( ivas_error ISAR_LC3PLUS_ENC_Encode( ISAR_LC3PLUS_ENC_HANDLE handle, /* i : LC3plus encoder handle */ float **pcm_in, /* i : pointer input samples */ - void *bitstream_out /* o : pointer to bitstream frame */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + void *bitstream_out, /* o : pointer to bitstream frame */ + const int32_t bitstream_out_size /* i : size of the bitstream_out buffer in bytes. Must be equal to ISAR_LC3PLUS_ENC_GetOutputBitstreamSize. */ +#else + void *bitstream_out /* o : pointer to bitstream frame */ +#endif ); #endif diff --git a/lib_isar/isar_lc3plus_payload.c b/lib_isar/isar_lc3plus_payload.c new file mode 100644 index 0000000000000000000000000000000000000000..b240897655ab4da7c58f7ffbc602c9adb0eefff5 --- /dev/null +++ b/lib_isar/isar_lc3plus_payload.c @@ -0,0 +1,823 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include +#include "isar_lc3plus_payload.h" +#include "options.h" + +#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +static LC3PLUS_RTP_ERR s_frame_duration_ms_from_fdi( int32_t *frame_duration_us, const LC3PLUS_RTP_FTD_FDI fdi ) +{ + if ( NULL == frame_duration_us ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + switch ( fdi ) + { + case LC3PLUS_RTP_FTD_FDI_2500_US: + *frame_duration_us = 2500; + break; + case LC3PLUS_RTP_FTD_FDI_5000_US: + *frame_duration_us = 5000; + break; + case LC3PLUS_RTP_FTD_FDI_10000_US: + *frame_duration_us = 10000; + break; + case LC3PLUS_RTP_FTD_FDI_RESERVED: + default: + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +static LC3PLUS_RTP_ERR s_sampling_rate_hz_from_bwr( int32_t *sample_rate_hz, const LC3PLUS_RTP_FTD_BWR bwr ) +{ + if ( NULL == sample_rate_hz ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + switch ( bwr ) + { + case LC3PLUS_RTP_FTD_BWR_NB: + *sample_rate_hz = 8000; + break; + case LC3PLUS_RTP_FTD_BWR_WB: + *sample_rate_hz = 16000; + break; + case LC3PLUS_RTP_FTD_BWR_SSWB: + *sample_rate_hz = 24000; + break; + case LC3PLUS_RTP_FTD_BWR_SWB: + *sample_rate_hz = 32000; + break; + case LC3PLUS_RTP_FTD_BWR_FBCD: + *sample_rate_hz = 44100; + break; + case LC3PLUS_RTP_FTD_BWR_FB: + *sample_rate_hz = 48000; + break; + case LC3PLUS_RTP_FTD_BWR_FBHR: + *sample_rate_hz = 48000; + break; + case LC3PLUS_RTP_FTD_BWR_UBHR: + *sample_rate_hz = 96000; + break; + default: + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +static LC3PLUS_RTP_ERR s_high_resolution_flag_from_bwr( int16_t *high_resolution_flag, const LC3PLUS_RTP_FTD_BWR bwr ) +{ + if ( NULL == high_resolution_flag ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + switch ( bwr ) + { + case LC3PLUS_RTP_FTD_BWR_NB: + *high_resolution_flag = 0; + break; + case LC3PLUS_RTP_FTD_BWR_WB: + *high_resolution_flag = 0; + break; + case LC3PLUS_RTP_FTD_BWR_SSWB: + *high_resolution_flag = 0; + break; + case LC3PLUS_RTP_FTD_BWR_SWB: + *high_resolution_flag = 0; + break; + case LC3PLUS_RTP_FTD_BWR_FBCD: + *high_resolution_flag = 0; + break; + case LC3PLUS_RTP_FTD_BWR_FB: + *high_resolution_flag = 0; + break; + case LC3PLUS_RTP_FTD_BWR_FBHR: + *high_resolution_flag = 1; + break; + case LC3PLUS_RTP_FTD_BWR_UBHR: + *high_resolution_flag = 1; + break; + default: + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +LC3PLUS_RTP_ERR LC3PLUS_RTP_frame_data_length_get_size( int32_t *length, const LC3PLUS_RTP_FDL frameDataLengthValue ) +{ + if ( frameDataLengthValue == LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA || frameDataLengthValue == LC3PLUS_RTP_FDL_SPEECH_BAD || frameDataLengthValue == LC3PLUS_RTP_FDL_SPEECH_SID ) + { + *length = 1; + } + else if ( frameDataLengthValue >= LC3PLUS_RTP_FDL_LENGTH_1_MIN && frameDataLengthValue <= LC3PLUS_RTP_FDL_LENGTH_1_MAX ) + { + *length = 1; + } + else if ( frameDataLengthValue >= LC3PLUS_RTP_FDL_LENGTH_2_MIN && frameDataLengthValue <= LC3PLUS_RTP_FDL_LENGTH_2_MAX ) + { + *length = 2; + } + else if ( frameDataLengthValue >= LC3PLUS_RTP_FDL_LENGTH_3_MIN && frameDataLengthValue <= LC3PLUS_RTP_FDL_LENGTH_3_MAX ) + { + *length = 3; + } + else + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +static LC3PLUS_RTP_ERR s_frame_data_length_pack( const LC3PLUS_RTP_FDL frameDataLengthValue, uint8_t *dst ) +{ + int32_t frame_data_length_size; + LC3PLUS_RTP_ERR err; + + if ( NULL == dst ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + + err = LC3PLUS_RTP_frame_data_length_get_size( &frame_data_length_size, frameDataLengthValue ); + if ( err != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return err; + } + if ( 1 == frame_data_length_size ) + { + *dst++ = frameDataLengthValue >> 0 & LC3PLUS_RTP_FDL_EXTENSION_VALUE; + } + else if ( 2 == frame_data_length_size ) + { + const int32_t frameDataLengthValueToWrite = frameDataLengthValue - LC3PLUS_RTP_FDL_EXTENSION_VALUE; + *dst++ = LC3PLUS_RTP_FDL_EXTENSION_VALUE; + *dst = frameDataLengthValueToWrite >> 0 & LC3PLUS_RTP_FDL_EXTENSION_VALUE; + } + else if ( 3 == frame_data_length_size ) + { + const int32_t frameDataLengthValueToWrite = frameDataLengthValue - ( 2 * LC3PLUS_RTP_FDL_EXTENSION_VALUE ); + *dst++ = LC3PLUS_RTP_FDL_EXTENSION_VALUE; + *dst++ = LC3PLUS_RTP_FDL_EXTENSION_VALUE; + *dst = frameDataLengthValueToWrite >> 0 & LC3PLUS_RTP_FDL_EXTENSION_VALUE; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +static int32_t s_get_size_from_fdl( const LC3PLUS_RTP_FDL fdl ) +{ + if ( fdl >= LC3PLUS_RTP_FDL_LENGTH_1_MIN && fdl <= LC3PLUS_RTP_FDL_LENGTH_3_MAX ) + { + return fdl; + } + return 0; +} + +static bool s_fdl_is_magic_value( const LC3PLUS_RTP_FDL fdl ) +{ + if ( fdl == LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA || fdl == LC3PLUS_RTP_FDL_SPEECH_SID || fdl == LC3PLUS_RTP_FDL_SPEECH_BAD ) + { + return true; + } + return false; +} + +static bool s_fdl_value_is_valid_request( const LC3PLUS_RTP_FDL fdl_request ) +{ + /* LC3PLUS_RTP_FDL_SPEECH_SID && LC3PLUS_RTP_FDL_SPEECH_SID are not valid values for the FDL request */ + if ( fdl_request == LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA || ( fdl_request >= LC3PLUS_RTP_FDL_LENGTH_1_MIN && fdl_request <= LC3PLUS_RTP_FDL_LENGTH_3_MAX ) ) + { + return true; + } + return false; +} + +static LC3PLUS_RTP_ERR s_frame_data_length_parse( LC3PLUS_RTP_FDL *frame_data_length_value, const uint8_t *src, const size_t remaining_capacity ) +{ + int32_t frame_data_length_size; + LC3PLUS_RTP_ERR err; + if ( NULL == src || NULL == frame_data_length_value || remaining_capacity < 1 ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + + if ( remaining_capacity > 2 && LC3PLUS_RTP_FDL_EXTENSION_VALUE == *src && LC3PLUS_RTP_FDL_EXTENSION_VALUE == *( src + 1 ) ) + { + *frame_data_length_value = *( src + 2 ) + 2 * LC3PLUS_RTP_FDL_EXTENSION_VALUE; + } + else if ( remaining_capacity > 1 && LC3PLUS_RTP_FDL_EXTENSION_VALUE == *src ) + { + *frame_data_length_value = *( src + 1 ) + 1 * LC3PLUS_RTP_FDL_EXTENSION_VALUE; + } + else if ( remaining_capacity > 0 ) + { + *frame_data_length_value = *src << 0; + } + else + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + + /* sanity check */ + err = LC3PLUS_RTP_frame_data_length_get_size( &frame_data_length_size, *frame_data_length_value ); + if ( err != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return err; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +static LC3PLUS_RTP_ERR s_parse_ftd( const uint8_t *p_read, LC3PLUS_RTP_FTD *receiver_ftd, int32_t *num_bytes_read, const size_t remaining_capacity ) +{ + int32_t frame_data_block_size; + LC3PLUS_RTP_FDL fdl; + LC3PLUS_RTP_ERR err; + if ( NULL == p_read || NULL == receiver_ftd || NULL == num_bytes_read || remaining_capacity < LC3PLUS_RTP_FTD_MIN_SIZE ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + + *num_bytes_read = 0; + receiver_ftd->fc = 0; + receiver_ftd->fdi = 0; + receiver_ftd->bwr = 0; + receiver_ftd->h = 0; + receiver_ftd->fc |= *p_read & LC3PLUS_RTP_FTD_FC_MASK; + receiver_ftd->fdi |= ( *p_read & LC3PLUS_RTP_FTD_FDI_MASK ); + receiver_ftd->bwr |= ( *p_read & LC3PLUS_RTP_FTD_BWR_MASK ); + receiver_ftd->h |= ( *p_read & LC3PLUS_RTP_FTD_H_MASK ); + p_read++; + *num_bytes_read = 1; + + err = s_frame_data_length_parse( &fdl, p_read, remaining_capacity - *num_bytes_read ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + frame_data_block_size = s_get_size_from_fdl( fdl ); + + receiver_ftd->frame_data_length = frame_data_block_size; + int32_t length_field_size; + err = LC3PLUS_RTP_frame_data_length_get_size( &length_field_size, receiver_ftd->frame_data_length ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + *num_bytes_read += length_field_size; + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +LC3PLUS_RTP_ERR LC3PLUS_RTP_payload_serialize( + uint8_t *serialized_buffer, + const size_t serialized_buffer_capacity, + size_t *packed_buffer_actual_size, + const LC3PLUS_RTP_FDL fdl_request, + LC3PLUS_RTP_FTD *sender_ftds, + const size_t sender_ftds_num ) +{ + LC3PLUS_RTP_ERR err; + uint8_t *p_write = serialized_buffer; + uint32_t i; + int32_t bytes_written = 0; + int32_t lc3plus_frame_size_sum; + uint8_t *p_frame_data; + int32_t fdl_request_length; + + if ( NULL == serialized_buffer || NULL == packed_buffer_actual_size || NULL == sender_ftds ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + + *packed_buffer_actual_size = 0; + err = LC3PLUS_RTP_frame_data_length_get_size( &fdl_request_length, fdl_request ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( !s_fdl_value_is_valid_request( fdl_request ) ) + { + return LC3PLUS_RTP_ERR_INVALID_FDL_REQUEST; + } + if ( (int32_t) serialized_buffer_capacity < bytes_written + fdl_request_length ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + err = s_frame_data_length_pack( fdl_request, p_write ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + bytes_written += fdl_request_length; + p_write += bytes_written; + + for ( i = 0; i < sender_ftds_num; ++i ) + { + /* only the last ftd may have the LC3PLUS_RTP_FTD_FC_LAST_OVERALL value */ + if ( sender_ftds[i].fc == LC3PLUS_RTP_FTD_FC_LAST_OVERALL && i != ( sender_ftds_num - 1 ) ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + /* the last ftd must have the LC3PLUS_RTP_FTD_FC_LAST_OVERALL value */ + if ( sender_ftds[i].fc != LC3PLUS_RTP_FTD_FC_LAST_OVERALL && i == ( sender_ftds_num - 1 ) ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + if ( (int32_t) serialized_buffer_capacity < bytes_written + LC3PLUS_RTP_FTD_LENGTH_EXCLUDING_FDL ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + *p_write = 0x00; + *p_write |= LC3PLUS_RTP_FTD_FC_MASK & (uint8_t) sender_ftds[i].fc; + *p_write |= LC3PLUS_RTP_FTD_FDI_MASK & (uint8_t) sender_ftds[i].fdi; + *p_write |= LC3PLUS_RTP_FTD_BWR_MASK & (uint8_t) sender_ftds[i].bwr; + *p_write |= LC3PLUS_RTP_FTD_H_MASK & (uint8_t) sender_ftds[i].h; + p_write++; + bytes_written += LC3PLUS_RTP_FTD_LENGTH_EXCLUDING_FDL; + + int32_t fdl_length; + err = LC3PLUS_RTP_frame_data_length_get_size( &fdl_length, sender_ftds[i].frame_data_length ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( (int32_t) serialized_buffer_capacity < bytes_written + fdl_length ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + err = s_frame_data_length_pack( sender_ftds[i].frame_data_length, p_write ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + p_write += fdl_length; + bytes_written += fdl_length; + } + + lc3plus_frame_size_sum = 0; + p_frame_data = serialized_buffer + bytes_written; + for ( i = 0; i < sender_ftds_num; ++i ) + { + sender_ftds[i].frame_data = p_frame_data; + p_frame_data += sender_ftds[i].frame_data_length; + lc3plus_frame_size_sum += sender_ftds[i].frame_data_length; + } + *packed_buffer_actual_size = bytes_written + lc3plus_frame_size_sum; + assert( *packed_buffer_actual_size <= serialized_buffer_capacity ); + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +static LC3PLUS_RTP_ERR s_ftds_parse( + LC3PLUS_RTP_FTD *receiver_ftds, + const int32_t receiver_ftds_num_max, + int16_t *receiver_ftds_num, + uint8_t *serialized_buffer, + const size_t serialized_buffer_size ) +{ + int32_t diff; + uint8_t *p_read; + uint32_t ftds_offset_sum = 0; + int16_t i; + LC3PLUS_RTP_ERR error; + int32_t frame_offset_counter; + int32_t size; + + p_read = serialized_buffer; + if ( NULL == receiver_ftds || NULL == receiver_ftds_num || NULL == serialized_buffer ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + if ( 0 == serialized_buffer_size ) + { + return LC3PLUS_RTP_ERR_EMPTY_TOC; + } + if ( receiver_ftds_num_max <= 0 ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + { + int32_t num_bytes_read_sum = 0; + const int32_t min_num_bytes_per_ftd = 2; + int16_t receiver_ftds_index = 0; + bool another_ftd = true; + int32_t num_bytes_read_per_ftd; + + while ( another_ftd ) + { + if ( (int32_t) serialized_buffer_size < min_num_bytes_per_ftd ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + if ( num_bytes_read_sum >= (int32_t) serialized_buffer_size - min_num_bytes_per_ftd ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + num_bytes_read_per_ftd = 0; + error = s_parse_ftd( p_read, &receiver_ftds[receiver_ftds_index], &num_bytes_read_per_ftd, serialized_buffer_size - num_bytes_read_sum ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != error ) + { + return error; + } + p_read += num_bytes_read_per_ftd; + num_bytes_read_sum += num_bytes_read_per_ftd; + + if ( receiver_ftds[receiver_ftds_index].fc == LC3PLUS_RTP_FTD_FC_RESERVED ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM; + } + else if ( receiver_ftds[receiver_ftds_index].fc == LC3PLUS_RTP_FTD_FC_LAST_OVERALL ) + { + another_ftd = false; + } + + if ( another_ftd ) + { + if ( receiver_ftds_index >= receiver_ftds_num_max ) + { + return LC3PLUS_RTP_ERR_NOT_ENOUGH_FTDS_ALLOCATED; + } + ( receiver_ftds_index )++; + } + } + *receiver_ftds_num = receiver_ftds_index + 1; + } + + /* set frame-data pointers into serialized_buffer */ + for ( i = 0; i < *receiver_ftds_num; ++i ) + { + error = LC3PLUS_RTP_frame_data_length_get_size( &size, receiver_ftds[i].frame_data_length ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return error; + } + ftds_offset_sum += LC3PLUS_RTP_FTD_LENGTH_EXCLUDING_FDL + size; + } + + frame_offset_counter = 0; + for ( i = 0; i < *receiver_ftds_num; ++i ) + { + if ( s_fdl_is_magic_value( receiver_ftds[i].frame_data_length ) ) + { + receiver_ftds[i].frame_data = NULL; + } + else + { + receiver_ftds[i].frame_data = serialized_buffer + ftds_offset_sum + frame_offset_counter; + frame_offset_counter += receiver_ftds[i].frame_data_length; + } + } + + if ( ftds_offset_sum + frame_offset_counter != serialized_buffer_size ) + { + /* parsed content & size n bytes of input buffer do not line up */ + /* if the buffer capacity is larger and the remaining bytes are zero, we don't treat this as an error since it's due to the IVAS-Split rendering zero padding */ + diff = serialized_buffer_size - ( ftds_offset_sum + frame_offset_counter ); + if ( diff < 0 ) + { + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE; + } + /* verify that all bytes are zero */ + p_read += frame_offset_counter; + for ( i = 0; i < diff; ++i ) + { + if ( *p_read != 0 ) + { + /* non-zero byte in padding region */ + return LC3PLUS_RTP_ERR_NONZERO_PADDING_BYTES; + } + p_read++; + } + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +LC3PLUS_RTP_ERR LC3PLUS_RTP_payload_deserialize( + LC3PLUS_RTP_PAYLOAD *payload, + uint8_t *serialized_buffer, + const size_t serialized_buffer_size ) +{ + int32_t new_frame_duration_us; + int32_t new_sampling_rate_hz; + int16_t new_high_resolution_flag; + int16_t i = 0; + int16_t channel_id = 0; + int16_t media_time_id = 0; + const int16_t invalid_value = -1; + int16_t media_times_per_channel[LC3PLUS_RTP_PAYLOAD_MAX_NUM_CHANNELS]; + int16_t channels_per_media_time[LC3PLUS_RTP_PAYLOAD_MAX_NUM_MEDIA_TIMES]; + LC3PLUS_RTP_ERR err; + + if ( NULL == payload || NULL == serialized_buffer ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + if ( 0 == serialized_buffer_size ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + + for ( media_time_id = 0; media_time_id < LC3PLUS_RTP_PAYLOAD_MAX_NUM_MEDIA_TIMES; ++media_time_id ) + { + channels_per_media_time[media_time_id] = invalid_value; + } + media_time_id = 0; + for ( channel_id = 0; channel_id < LC3PLUS_RTP_PAYLOAD_MAX_NUM_CHANNELS; ++channel_id ) + { + media_times_per_channel[channel_id] = invalid_value; + } + channel_id = 0; + + err = s_frame_data_length_parse( &payload->fdl_request, serialized_buffer, serialized_buffer_size ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + int32_t fdl_request_length; + err = LC3PLUS_RTP_frame_data_length_get_size( &fdl_request_length, payload->fdl_request ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( !s_fdl_value_is_valid_request( payload->fdl_request ) ) + { + return LC3PLUS_RTP_ERR_INVALID_FDL_REQUEST; + } + + err = s_ftds_parse( payload->ftds, sizeof( payload->ftds ) / sizeof( LC3PLUS_RTP_FTD ), &payload->num_ftds, serialized_buffer + fdl_request_length, serialized_buffer_size - fdl_request_length ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( 0 == payload->num_ftds ) + { + return LC3PLUS_RTP_ERR_GENERIC_ERROR; + } + /* verify shared setting between all FTDs [samplerate, frame_duration, channel count] */ + + /* initialize on the first FTD, use this as reference */ + err = s_frame_duration_ms_from_fdi( &payload->frame_duration_us, payload->ftds[0].fdi ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + err = s_sampling_rate_hz_from_bwr( &payload->sampling_rate_hz, payload->ftds[0].bwr ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + err = s_high_resolution_flag_from_bwr( &payload->high_resolution_enabled, payload->ftds[0].bwr ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + payload->num_channels = 0; + payload->num_media_times = 0; + for ( i = 0; i < payload->num_ftds; ++i ) + { + if ( payload->ftds[i].h != LC3PLUS_RTP_FTD_H_PRIMARY ) + { + /* not implemented */ + return LC3PLUS_RTP_ERR_NOT_IMPLEMENTED; + } + + err = s_frame_duration_ms_from_fdi( &new_frame_duration_us, payload->ftds[i].fdi ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( payload->frame_duration_us != new_frame_duration_us ) + { + /* mixed frame durations not supported */ + return LC3PLUS_RTP_ERR_UNSUPPORTED_CONFIGURATION; + } + + err = s_sampling_rate_hz_from_bwr( &new_sampling_rate_hz, payload->ftds[i].bwr ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( payload->sampling_rate_hz != new_sampling_rate_hz ) + { + /* mixed sampling frequencies not supported */ + return LC3PLUS_RTP_ERR_UNSUPPORTED_CONFIGURATION; + } + + + err = s_high_resolution_flag_from_bwr( &new_high_resolution_flag, payload->ftds[i].bwr ); + if ( LC3PLUS_RTP_ERR_NO_ERROR != err ) + { + return err; + } + if ( payload->high_resolution_enabled != new_high_resolution_flag ) + { + /* mixed high resolution mode not supported */ + return LC3PLUS_RTP_ERR_UNSUPPORTED_CONFIGURATION; + } + + switch ( payload->ftds[i].fc ) + { + case LC3PLUS_RTP_FTD_FC_LAST_OVERALL: + channels_per_media_time[media_time_id]++; + media_times_per_channel[channel_id]++; + channel_id = 0; + media_time_id = 0; + break; + case LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL: + media_times_per_channel[channel_id]++; + channels_per_media_time[media_time_id]++; + channel_id++; + break; + case LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME: + media_times_per_channel[channel_id]++; + channels_per_media_time[media_time_id]++; + channel_id = 0; + media_time_id++; + break; + case LC3PLUS_RTP_FTD_FC_RESERVED: + default: + return LC3PLUS_RTP_ERR_INVALID_BITSTREAM; + } + } + + { + int32_t valid_num_media_times_per_channel; + int32_t iCh; + /* check whether all channels exist for each media time */ + if ( media_times_per_channel[0] == invalid_value ) + { + return LC3PLUS_RTP_ERR_NOT_IMPLEMENTED; + } + valid_num_media_times_per_channel = media_times_per_channel[0]; + for ( iCh = 0; iCh < LC3PLUS_RTP_PAYLOAD_MAX_NUM_CHANNELS; ++iCh ) + { + if ( media_times_per_channel[iCh] == invalid_value ) + { + break; + } + if ( valid_num_media_times_per_channel != media_times_per_channel[iCh] ) + { + return LC3PLUS_RTP_ERR_NOT_IMPLEMENTED; + } + } + } + { + /* whether all media times exist for each channel */ + int32_t iMediaTime; + int32_t valid_num_channels_per_media_time; + if ( channels_per_media_time[0] == invalid_value ) + { + return LC3PLUS_RTP_ERR_NOT_IMPLEMENTED; + } + valid_num_channels_per_media_time = channels_per_media_time[0]; + for ( iMediaTime = 0; iMediaTime < LC3PLUS_RTP_PAYLOAD_MAX_NUM_MEDIA_TIMES; ++iMediaTime ) + { + if ( channels_per_media_time[iMediaTime] == invalid_value ) + { + break; + } + if ( valid_num_channels_per_media_time != channels_per_media_time[iMediaTime] ) + { + return LC3PLUS_RTP_ERR_NOT_IMPLEMENTED; + } + } + } + + /* convert zero-index to count */ + payload->num_channels = channels_per_media_time[0] + 1; + payload->num_media_times = media_times_per_channel[0] + 1; + + /* verify that all media times have the same number of channels, partial packets are not supported */ + if ( payload->num_ftds != payload->num_channels * payload->num_media_times ) + { + return LC3PLUS_RTP_ERR_GENERIC_ERROR; + } + return LC3PLUS_RTP_ERR_NO_ERROR; +} + +LC3PLUS_RTP_ERR LC3PLUS_RTP_ftd_bwr_from_samplerate( LC3PLUS_RTP_FTD_BWR *bwr, const int32_t sampling_rate, const int32_t high_res_enabled ) +{ + if ( NULL == bwr ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + switch ( sampling_rate ) + { + case 8000: + if ( high_res_enabled ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + *bwr = LC3PLUS_RTP_FTD_BWR_NB; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 16000: + if ( high_res_enabled ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + *bwr = LC3PLUS_RTP_FTD_BWR_WB; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 24000: + if ( high_res_enabled ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + *bwr = LC3PLUS_RTP_FTD_BWR_SSWB; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 32000: + if ( high_res_enabled ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + *bwr = LC3PLUS_RTP_FTD_BWR_SWB; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 44100: + if ( high_res_enabled ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + *bwr = LC3PLUS_RTP_FTD_BWR_FBCD; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 48000: + if ( 0 == high_res_enabled ) + { + *bwr = LC3PLUS_RTP_FTD_BWR_FB; + return LC3PLUS_RTP_ERR_NO_ERROR; + } + else + { + *bwr = LC3PLUS_RTP_FTD_BWR_FBHR; + return LC3PLUS_RTP_ERR_NO_ERROR; + } + case 96000: + if ( 0 == high_res_enabled ) + { + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; + } + *bwr = LC3PLUS_RTP_FTD_BWR_UBHR; + return LC3PLUS_RTP_ERR_NO_ERROR; + default: + break; + } + + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; +} + +LC3PLUS_RTP_ERR LC3PLUS_RTP_ftd_fdi_from_frame_duration_us( LC3PLUS_RTP_FTD_FDI *fdi, const int32_t frame_duration_us ) +{ + if ( NULL == fdi ) + { + return LC3PLUS_RTP_ERR_NULL_PTR; + } + switch ( frame_duration_us ) + { + case 2500: + *fdi = LC3PLUS_RTP_FTD_FDI_2500_US; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 5000: + *fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + return LC3PLUS_RTP_ERR_NO_ERROR; + case 10000: + *fdi = LC3PLUS_RTP_FTD_FDI_10000_US; + return LC3PLUS_RTP_ERR_NO_ERROR; + default: + break; + } + + return LC3PLUS_RTP_ERR_INVALID_PARAMETERS; +} + +#endif /* ISAR_BITSTREAM_UPDATE_LC3PLUS */ +#endif /* SPLIT_REND_WITH_HEAD_ROT */ diff --git a/lib_isar/isar_lc3plus_payload.h b/lib_isar/isar_lc3plus_payload.h new file mode 100644 index 0000000000000000000000000000000000000000..1e649690ec435fd690e86f57738b3fb399bd2956 --- /dev/null +++ b/lib_isar/isar_lc3plus_payload.h @@ -0,0 +1,216 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef ISAR_LC3PLUS_PAYLOAD_H +#define ISAR_LC3PLUS_PAYLOAD_H + +#include +#include +#include "lc3.h" +#include "options.h" + +#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + +/* Implementation of the "B.2.6 Table of contents" part of the RTP payload format + * for LC3plus as specified in ETSI TS 103 634. */ + +typedef enum LC3PLUS_RTP_ERR +{ + LC3PLUS_RTP_ERR_NO_ERROR, + LC3PLUS_RTP_ERR_NULL_PTR, + LC3PLUS_RTP_ERR_INVALID_PARAMETERS, + LC3PLUS_RTP_ERR_EMPTY_TOC, + LC3PLUS_RTP_ERR_NOT_IMPLEMENTED, + LC3PLUS_RTP_ERR_UNSUPPORTED_CONFIGURATION, + LC3PLUS_RTP_ERR_INVALID_BITSTREAM, + LC3PLUS_RTP_ERR_INVALID_BITSTREAM_SIZE, + LC3PLUS_RTP_ERR_NOT_ENOUGH_FTDS_ALLOCATED, + LC3PLUS_RTP_ERR_INVALID_FDL_REQUEST, + LC3PLUS_RTP_ERR_NONZERO_PADDING_BYTES, + LC3PLUS_RTP_ERR_GENERIC_ERROR +} LC3PLUS_RTP_ERR; + +/* + * The content of the FTD is shown in Figure B.6. + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |FC |FDI| BWR |H| FDL1 | (FDL2) | (FDL3) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +/* FC (2 bits): + * Frame and Channel (FC) indicator for subsequent frame data (if available). The meaning of the FC + * indicator is shown in Table B.2. The FC value defines the media time stamp (in integer increments + * of TSI) and the channel counter (CC, starting from 1 for the first channel) for the subsequent + * FTD (if available). */ +typedef enum LC3PLUS_RTP_FTD_FC +{ + LC3PLUS_RTP_FTD_FC_LAST_OVERALL = 0x00, /* Last FDL in ToC, no FDL follows the current FDL */ + LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL = 0x01, /* The next FDL is for the next channel for the same media time */ + LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME = 0x02, /* The next FDL is for first channel for next media time, channel counter is reset */ + LC3PLUS_RTP_FTD_FC_RESERVED = 0x03, /* Reserved */ +} LC3PLUS_RTP_FTD_FC; +#define LC3PLUS_RTP_FTD_FC_MASK 0x03 + +/* FDI (2 bits): + * Frame Duration Index, with encoding as shown in Table B.3. The FDI shall be static for a given + * payload type during the session. The FDI also dictates the TSI, needed for deriving the media + * time in case of more than one frame in the payload. */ +typedef enum LC3PLUS_RTP_FTD_FDI +{ + LC3PLUS_RTP_FTD_FDI_2500_US = 0x00, + LC3PLUS_RTP_FTD_FDI_5000_US = 0x04, + LC3PLUS_RTP_FTD_FDI_10000_US = 0x08, + LC3PLUS_RTP_FTD_FDI_RESERVED = 0x0C, +} LC3PLUS_RTP_FTD_FDI; +#define LC3PLUS_RTP_FTD_FDI_MASK 0x0C +LC3PLUS_RTP_ERR LC3PLUS_RTP_ftd_fdi_from_frame_duration_us( LC3PLUS_RTP_FTD_FDI *fdi, const int32_t frame_duration_us ); + +/* BWR (3 bits): + * Bandwidth and resolution combination used by the codec is jointly encoded into a bandwidth and + * resolution (BWR) index. The BWR index is encoded as shown in Table B.4. The BWR encoding is + * defined in Table B.4. The BWR index shall be static for a given payload type during the session. */ +typedef enum LC3PLUS_RTP_FTD_BWR +{ + LC3PLUS_RTP_FTD_BWR_NB = 0x00, + LC3PLUS_RTP_FTD_BWR_WB = 0x10, + LC3PLUS_RTP_FTD_BWR_SSWB = 0x20, + LC3PLUS_RTP_FTD_BWR_SWB = 0x30, + LC3PLUS_RTP_FTD_BWR_FBCD = 0x40, + LC3PLUS_RTP_FTD_BWR_FB = 0x50, + LC3PLUS_RTP_FTD_BWR_FBHR = 0x60, + LC3PLUS_RTP_FTD_BWR_UBHR = 0x70, +} LC3PLUS_RTP_FTD_BWR; +#define LC3PLUS_RTP_FTD_BWR_MASK 0x70 +LC3PLUS_RTP_ERR LC3PLUS_RTP_ftd_bwr_from_samplerate( LC3PLUS_RTP_FTD_BWR *bwr, const int32_t sampling_rate, const int32_t high_res_enabled ); + +/* H (1 bit): + * Indicates whether the corresponding frame is a normal frame (primary encoding) or a helper frame + * (secondary encoding). 0 indicates a primary frame, 1 indicates secondary (redundant) frame */ +typedef enum LC3PLUS_RTP_FTD_H +{ + LC3PLUS_RTP_FTD_H_PRIMARY = 0x00, + LC3PLUS_RTP_FTD_H_SECONDARY = 0x80, +} LC3PLUS_RTP_FTD_H; +#define LC3PLUS_RTP_FTD_H_MASK 0x80 + +typedef enum LC3PLUS_RTP_FDL +{ + LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA = 0, + LC3PLUS_RTP_FDL_SPEECH_BAD = 1, + LC3PLUS_RTP_FDL_SPEECH_SID = 2, + LC3PLUS_RTP_FDL_RESERVED_MIN = 3, + LC3PLUS_RTP_FDL_RESERVED_MAX = 19, + LC3PLUS_RTP_FDL_LENGTH_1_MIN = 20, + LC3PLUS_RTP_FDL_LENGTH_1_MAX = 254, + LC3PLUS_RTP_FDL_LENGTH_2_MIN = 255, + LC3PLUS_RTP_FDL_LENGTH_2_MAX = 509, + LC3PLUS_RTP_FDL_LENGTH_3_MIN = 510, + LC3PLUS_RTP_FDL_LENGTH_3_MAX = 765 +} LC3PLUS_RTP_FDL; +/* value used to indicate that the Frame Data Length (FDL) extends to the next byte */ +#define LC3PLUS_RTP_FDL_EXTENSION_VALUE 0xFF + +typedef struct LC3PLUS_RTP_FTD +{ + LC3PLUS_RTP_FTD_FC fc; + LC3PLUS_RTP_FTD_FDI fdi; + LC3PLUS_RTP_FTD_BWR bwr; + LC3PLUS_RTP_FTD_H h; + uint8_t *frame_data; + LC3PLUS_RTP_FDL frame_data_length; +} LC3PLUS_RTP_FTD; +#define LC3PLUS_RTP_FTD_LENGTH_EXCLUDING_FDL 1 +#define LC3PLUS_RTP_FDL_MIN_LENGTH 1 +#define LC3PLUS_RTP_FTD_MIN_SIZE ( LC3PLUS_RTP_FTD_LENGTH_EXCLUDING_FDL + LC3PLUS_RTP_FDL_MIN_LENGTH ) + +/*! Serialize the sender_ftds structs and fdl_request into a linear compact buffer + * @param[out] serialized_buffer pointer to the start of the memory location where the serialized buffer will be written to + * @param[in] serialized_buffer_capacity capacity of the serialized_buffer in bytes + * @param[out] packed_buffer_actual_size actually used size of in bytes of the packed_buffer (<=serialized_buffer_capacity) + * @param[in] fdl_request frame data length request + * @param[in,out] sender_ftds the function will overwrite the frame_data pointer with the correct memory location in + * the packed_buffer (so it can subsequently be used as input for the LC3plus encode call) + * @param[in] sender_ftds_num number of sender_ftds + * @return LC3PLUS_RTP_ERR_NO_ERROR in case of success */ +LC3PLUS_RTP_ERR LC3PLUS_RTP_payload_serialize( + uint8_t *serialized_buffer, + const size_t serialized_buffer_capacity, + size_t *packed_buffer_actual_size, + const LC3PLUS_RTP_FDL fdl_request, + LC3PLUS_RTP_FTD *sender_ftds, + const size_t sender_ftds_num ); + +/*! Get size of the frame data length field for a certain frame data length value in bytes. + * @param[out] length size of the frame data length field in bytes [1,2,3] + * @param[in] frameDataLengthValue frame data length value + * @return LC3PLUS_RTP_ERR_NO_ERROR in case of success */ +LC3PLUS_RTP_ERR LC3PLUS_RTP_frame_data_length_get_size( int32_t *length, const LC3PLUS_RTP_FDL frameDataLengthValue ); + +#define LC3PLUS_RTP_PAYLOAD_MAX_NUM_CHANNELS 16 +#define LC3PLUS_RTP_PAYLOAD_MAX_NUM_MEDIA_TIMES 8 /* max ivas frame duration/min lc3plus frame duration: 20000/2500 */ +#define LC3PLUS_RTP_PAYLOAD_MAX_NUM_FTDS LC3PLUS_RTP_PAYLOAD_MAX_NUM_CHANNELS *LC3PLUS_RTP_PAYLOAD_MAX_NUM_MEDIA_TIMES + +typedef struct LC3PLUS_RTP_PAYLOAD_CONFIG +{ + /* frame duration in us shared among all FTDs */ + int32_t frame_duration_us; + /* high resolution flag shared among all FTDs */ + int16_t high_resolution_enabled; + /* sampling frequency shared among all FTDs */ + int32_t sampling_rate_hz; + /* number of individual channels in the payload */ + int16_t num_channels; + /* number of individual media times in the payload */ + int16_t num_media_times; + /* frame data length request */ + LC3PLUS_RTP_FDL fdl_request; + /* FTD data with pointer to raw frame data */ + LC3PLUS_RTP_FTD ftds[LC3PLUS_RTP_PAYLOAD_MAX_NUM_FTDS]; + /* actual number of ftds */ + int16_t num_ftds; +} LC3PLUS_RTP_PAYLOAD; + +/*! Deserialized a serialized buffer into a LC3PLUS_RTP_PAYLOAD struct + * @param payload pointer to target LC3PLUS_RTP_PAYLOAD object. Note: frame_data pointers in the struct will point to the respective memory locations in the serialized_buffer. + * @param serialized_buffer pointer to the start of the serialized input buffer + * @param serialized_buffer_size size of the serialized input buffer in bytes + * @return LC3PLUS_RTP_ERR_NO_ERROR in case of success */ +LC3PLUS_RTP_ERR LC3PLUS_RTP_payload_deserialize( + LC3PLUS_RTP_PAYLOAD *payload, + uint8_t *serialized_buffer, + const size_t serialized_buffer_size ); + +#endif /* ISAR_BITSTREAM_UPDATE_LC3PLUS */ +#endif /* #ifdef SPLIT_REND_WITH_HEAD_ROT */ +#endif /* ISAR_LC3PLUS_PAYLOAD_H */ diff --git a/lib_isar/isar_prot.h b/lib_isar/isar_prot.h index c5842bab7593a330e1cd7d2cda8670cb6a092e08..ffc42b2283fbfb342e21a89da0524b475d1a7c87 100644 --- a/lib_isar/isar_prot.h +++ b/lib_isar/isar_prot.h @@ -56,7 +56,12 @@ ivas_error split_renderer_open_lc3plus( SPLIT_REND_WRAPPER *hSplitRendWrapper, const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, const int32_t OutSampleRate, - const int16_t num_subframes ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const IVAS_RENDER_FRAMESIZE ivas_frame_size +#else + const int16_t num_subframes +#endif +); void isar_splitBinPreRendClose( ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE *hBinHrSplitPreRend ); @@ -69,7 +74,11 @@ void lc3plusTimeAlignCldfbPoseCorr( ivas_error splitRendLc3plusEncodeAndWrite( SPLIT_REND_WRAPPER *hSplitBin, ISAR_SPLIT_REND_BITS_HANDLE pBits, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const int32_t available_bits, +#else const int32_t SplitRendBitRate, +#endif float *in[] ); int32_t ISAR_SPLIT_REND_BITStream_read_int32( @@ -260,6 +269,9 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( SPLIT_REND_WRAPPER *hSplitBin, const IVAS_QUATERNION headPosition, const int32_t SplitRendBitRate, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const int16_t isar_frame_size_ms, +#endif const int16_t codec_frame_size_ms, ISAR_SPLIT_REND_BITS_HANDLE pBits, const int16_t max_bands, @@ -298,10 +310,12 @@ void isar_set_split_rend_ht_setup( IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES], float Rmat[MAX_PARAM_SPATIAL_SUBFRAMES][3][3] ); +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS int32_t isar_get_lc3plus_bitrate( const int32_t SplitRendBitRate, const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode, const int16_t split_prerender_frame_size_ms ); +#endif ivas_error isar_split_rend_validate_config( const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, @@ -311,15 +325,27 @@ int32_t isar_get_lcld_bitrate( const int32_t SplitRendBitRate, const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode ); +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS int8_t isar_get_lc3plus_bitrate_id( const int32_t SplitRendBitRate ); +#endif int32_t isar_get_split_rend_md_target_brate( const int32_t SplitRendBitRate, const int16_t pcm_out_flag ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +ivas_error isar_framesize_to_ms( + const IVAS_RENDER_FRAMESIZE frame_size, /* i : frame size enum */ + int16_t *ms /* o : frame size in ms */ +); +#endif + ivas_error isar_split_rend_choose_default_codec( ISAR_SPLIT_REND_CODEC *pCodec, /* i/o: pointer to codec setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t *pIsar_frame_size_ms, /* i/o: pointer to isar frame size setting */ +#endif int16_t *pCodec_frame_size_ms, /* i/o: pointer to codec frame size setting */ const int16_t cldfb_in_flag, /* i : flag indicating rendering in TD */ const int16_t pcm_out_flag, /* i : flag to indicate PCM output */ @@ -339,10 +365,12 @@ int16_t wrap_a( const int16_t min_val, const int16_t max_val ); +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS int32_t isar_get_lc3plus_size_from_id( const int8_t SplitRendBitRateId, const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode, const int16_t split_prerender_frame_size_ms ); +#endif void isar_renderSplitUpdateNoCorrectionPoseData( const ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, diff --git a/lib_isar/isar_splitRendererPre.c b/lib_isar/isar_splitRendererPre.c index be899732246ca8d82b45dd2bdd8201fcbbdc8932..ef1072f5c9e3a736c8f70eb973fce9396b47e63b 100644 --- a/lib_isar/isar_splitRendererPre.c +++ b/lib_isar/isar_splitRendererPre.c @@ -1925,19 +1925,55 @@ ivas_error split_renderer_open_lc3plus( SPLIT_REND_WRAPPER *hSplitRendWrapper, const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, const int32_t OutSampleRate, - const int16_t num_subframes ) +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const IVAS_RENDER_FRAMESIZE isar_frame_size +#else + const int16_t num_subframes +#endif +) { ivas_error error; int16_t i, delayBufferLength; LC3PLUS_CONFIG config; +#if defined ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t isar_frame_size_ms; + + if ( ( error = isar_framesize_to_ms( isar_frame_size, &isar_frame_size_ms ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* Check configuration validity */ + if ( isar_frame_size_ms < pSplitRendConfig->codec_frame_size_ms ) + { + return IVAS_ERROR( IVAS_ERR_INVALID_SPLIT_REND_CONFIG, "SR codec frame doesn't fit in one output frame" ); + } +#endif config.lc3plus_frame_duration_us = pSplitRendConfig->codec_frame_size_ms * 1000; - config.ivas_frame_duration_us = ( pSplitRendConfig->dof == 0 ) ? config.lc3plus_frame_duration_us * num_subframes : 20000; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + config.isar_frame_duration_us = ( pSplitRendConfig->dof == 0 ) ? config.lc3plus_frame_duration_us * num_subframes : 20000; +#endif config.samplerate = OutSampleRate; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + config.isar_frame_duration_us = isar_frame_size_ms * 1000; +#endif + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + config.high_res_mode_enabled = ( pSplitRendConfig->lc3plus_highres != 0 ); +#endif config.channels = BINAURAL_CHANNELS; - if ( ( error = ISAR_LC3PLUS_ENC_Open( config, isar_get_lc3plus_bitrate( pSplitRendConfig->splitRendBitRate, pSplitRendConfig->poseCorrectionMode, (int16_t) ( config.ivas_frame_duration_us / 1000 ) ), &hSplitRendWrapper->hLc3plusEnc ) ) != IVAS_ERR_OK ) + if ( ( error = ISAR_LC3PLUS_ENC_Open( config, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + isar_get_lcld_bitrate( pSplitRendConfig->splitRendBitRate, pSplitRendConfig->poseCorrectionMode ), +#else + isar_get_lc3plus_bitrate( pSplitRendConfig->splitRendBitRate, pSplitRendConfig->poseCorrectionMode, (int16_t) ( config.isar_frame_duration_us / 1000 ) ), +#endif + &hSplitRendWrapper->hLc3plusEnc ) ) != IVAS_ERR_OK ) { return error; } @@ -1993,7 +2029,13 @@ ivas_error split_renderer_open_lc3plus( ivas_error splitRendLc3plusEncodeAndWrite( SPLIT_REND_WRAPPER *hSplitBin, ISAR_SPLIT_REND_BITS_HANDLE pBits, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const int32_t available_bits, +#endif +#else const int32_t SplitRendBitRate, +#endif float *in[] ) { ivas_error error; @@ -2013,15 +2055,28 @@ ivas_error splitRendLc3plusEncodeAndWrite( channel_ptrs[i] = in[i]; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( ( error = IVAS_LC3PLUS_ENC_SetBitrate( hSplitBin->hLc3plusEnc, available_bits * FRAMES_PER_SEC ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif + if ( ( error = ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( hSplitBin->hLc3plusEnc, &lc3plusBitstreamSize ) ) != IVAS_ERR_OK ) { return error; } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS ISAR_SPLIT_REND_BITStream_write_int32( pBits, isar_get_lc3plus_bitrate_id( SplitRendBitRate ), 8 ); +#endif /* Write bitstream */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( ( error = ISAR_LC3PLUS_ENC_Encode( hSplitBin->hLc3plusEnc, channel_ptrs, &pBits->bits_buf[pBits->bits_written / 8], lc3plusBitstreamSize ) ) != IVAS_ERR_OK ) +#else if ( ( error = ISAR_LC3PLUS_ENC_Encode( hSplitBin->hLc3plusEnc, channel_ptrs, &pBits->bits_buf[pBits->bits_written / 8] ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -2030,10 +2085,12 @@ ivas_error splitRendLc3plusEncodeAndWrite( pBits->codec = ISAR_SPLIT_REND_CODEC_LC3PLUS; pBits->pose_correction = hSplitBin->multiBinPoseData.poseCorrectionMode; pBits->codec_frame_size_ms = (int16_t) ( hSplitBin->hLc3plusEnc->config.lc3plus_frame_duration_us / 1000 ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + pBits->isar_frame_size_ms = (int16_t) ( hSplitBin->hLc3plusEnc->config.isar_frame_duration_us / 1000 ); +#endif return IVAS_ERR_OK; } - /*------------------------------------------------------------------------- * Function isar_renderMultiTDBinToSplitBinaural() * @@ -2044,6 +2101,9 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( SPLIT_REND_WRAPPER *hSplitBin, const IVAS_QUATERNION headPosition, const int32_t SplitRendBitRate, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const int16_t isar_frame_size_ms, +#endif const int16_t codec_frame_size_ms, ISAR_SPLIT_REND_BITS_HANDLE pBits, const int16_t max_bands, @@ -2053,7 +2113,11 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( const int16_t ro_md_flag ) { ivas_error error; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t bit_len, available_bits, target_md_bits; +#else int32_t bit_len, available_bits, target_md_bits, actual_md_bits; +#endif int16_t num_cldfb_bands, ch, slot_idx, pos_idx, num_poses; float Cldfb_In_BinReal[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; float Cldfb_In_BinImag[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; @@ -2090,7 +2154,9 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( } } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS actual_md_bits = pBits->bits_written; +#endif if ( ( hSplitBin->multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) || ( !useLc3plus && !pcm_out_flag ) ) { num_slots = ( hSplitBin->multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) ? CLDFB_NO_COL_MAX : ( hSplitBin->hSplitBinLCLDEnc->iNumBlocks * hSplitBin->hSplitBinLCLDEnc->iNumIterations ); @@ -2131,7 +2197,9 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( { target_md_bits = isar_get_split_rend_md_target_brate( SplitRendBitRate, pcm_out_flag ) * L_FRAME48k / 48000; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS actual_md_bits = pBits->bits_written; +#endif isar_rend_CldfbSplitPreRendProcess( hSplitBin->hBinHrSplitPreRend, headPosition, &hSplitBin->multiBinPoseData, Cldfb_In_BinReal, Cldfb_In_BinImag, pBits, target_md_bits, low_res_pre_rend_rot, ro_md_flag ); } @@ -2144,15 +2212,32 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( if ( !useLc3plus ) { available_bits = ( SplitRendBitRate * hSplitBin->hSplitBinLCLDEnc->iNumBlocks * hSplitBin->hSplitBinLCLDEnc->iNumIterations ) / ( 16 * FRAMES_PER_SEC ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + available_bits -= pBits->bits_written; +#else actual_md_bits = pBits->bits_written - actual_md_bits; available_bits -= actual_md_bits; +#endif pBits->codec_frame_size_ms = codec_frame_size_ms; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + pBits->isar_frame_size_ms = isar_frame_size_ms; +#endif isar_splitBinLCLDEncProcess( hSplitBin->hSplitBinLCLDEnc, Cldfb_In_BinReal, Cldfb_In_BinImag, available_bits, pBits ); } else { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + available_bits = ( SplitRendBitRate / FRAMES_PER_SEC ) - pBits->bits_written; + if ( ( error = splitRendLc3plusEncodeAndWrite( hSplitBin, pBits, available_bits, in ) ) != IVAS_ERR_OK ) +#else + available_bits = ( SplitRendBitRate / FRAMES_PER_SEC ) - pBits->bits_written; + if ( ( error = splitRendLc3plusEncodeAndWrite( hSplitBin, pBits, in ) ) != IVAS_ERR_OK ) +#endif +#else if ( ( error = splitRendLc3plusEncodeAndWrite( hSplitBin, pBits, SplitRendBitRate, in ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -2177,7 +2262,7 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( } else { - bit_len = hSplitBin->hLc3plusEnc->config.ivas_frame_duration_us / 1000; + bit_len = hSplitBin->hLc3plusEnc->config.isar_frame_duration_us / 1000; bit_len = SplitRendBitRate * bit_len / 1000; } } diff --git a/lib_isar/isar_splitRenderer_utils.c b/lib_isar/isar_splitRenderer_utils.c index b20791f4b9f6aaf12b823a5612f8e5ccb034ec20..f6933796dfcfb1d0a657ec819dbe0193912dff35 100644 --- a/lib_isar/isar_splitRenderer_utils.c +++ b/lib_isar/isar_splitRenderer_utils.c @@ -564,6 +564,7 @@ int32_t isar_get_lcld_bitrate( } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS /*------------------------------------------------------------------------- * Function isar_get_lc3plus_bitrate() * @@ -685,6 +686,7 @@ int32_t isar_get_lc3plus_size_from_id( /* Return size in bytes */ return (int32_t) ( bitrate * split_prerender_frame_size_ms / 1000 / 8 ); } +#endif /*------------------------------------------------------------------------- @@ -749,14 +751,19 @@ ivas_error isar_split_rend_validate_config( break; case SPLIT_REND_384k: case SPLIT_REND_512k: +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + case SPLIT_REND_768k: +#endif /* Always valid */ break; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS case SPLIT_REND_768k: if ( pSplitRendConfig->dof == 0 && pSplitRendConfig->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) { return IVAS_ERROR( IVAS_ERR_INVALID_SPLIT_REND_CONFIG, "Bitrate is too high for LC3plus with 0 DOF" ); } break; +#endif default: return IVAS_ERR_LC3PLUS_INVALID_BITRATE; } @@ -1187,6 +1194,31 @@ void isar_init_multi_bin_pose_data( return; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +ivas_error isar_framesize_to_ms( + const IVAS_RENDER_FRAMESIZE frame_size, /* i : frame size enum */ + int16_t *ms /* o : frame size in ms */ +) +{ + switch ( frame_size ) + { + case IVAS_RENDER_FRAMESIZE_5MS: + *ms = 5; + break; + case IVAS_RENDER_FRAMESIZE_10MS: + *ms = 10; + break; + case IVAS_RENDER_FRAMESIZE_20MS: + *ms = 20; + break; + default: + return IVAS_ERROR( IVAS_ERR_INTERNAL, "Unsupported ISAR frame size" ); + } + + return IVAS_ERR_OK; +} +#endif + /*------------------------------------------------------------------------- * Function isar_split_rend_choose_default_codec() @@ -1196,6 +1228,9 @@ void isar_init_multi_bin_pose_data( ivas_error isar_split_rend_choose_default_codec( ISAR_SPLIT_REND_CODEC *pCodec, /* i/o: pointer to codec setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t *pIsar_frame_size_ms, /* i/o: pointer to isar frame size setting */ +#endif int16_t *pCodec_frame_size_ms, /* i/o: pointer to codec frame size setting */ const int16_t cldfb_in_flag, /* i : flag indicating rendering in TD */ const int16_t pcm_out_flag, /* i : flag to indicate PCM output */ @@ -1229,7 +1264,12 @@ ivas_error isar_split_rend_choose_default_codec( return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unknown split codec value" ); } } - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( *pIsar_frame_size_ms == 0 ) /* isar frame size hasn't been set yet - use default for current configuration */ + { + *pIsar_frame_size_ms = 20; + } +#endif return IVAS_ERR_OK; } diff --git a/lib_isar/lib_isar_post_rend.c b/lib_isar/lib_isar_post_rend.c index 7e27e8e1599e1935015185224fabef1f31054c64..12fc8e6e43991f911abf3582958b5e24fa9c78f5 100644 --- a/lib_isar/lib_isar_post_rend.c +++ b/lib_isar/lib_isar_post_rend.c @@ -80,11 +80,18 @@ typedef struct { const int32_t *pOutSampleRate; const AUDIO_CONFIG *pOutConfig; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS const LSSETUP_CUSTOM_STRUCT *pCustomLsOut; const EFAP_WRAPPER *pEfapOutWrapper; +#endif const ISAR_POST_REND_HeadRotData *pHeadRotData; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS const RENDER_CONFIG_HANDLE *hhRendererConfig; +#endif const int16_t *pSplitRendBFI; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRenderConfig; +#endif } rendering_context; /* Common base for input structs */ @@ -211,6 +218,10 @@ static void convertBitsBufferToInternalBitsBuff( hBits->codec = outBits.config.codec; hBits->pose_correction = outBits.config.poseCorrection; hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hBits->isar_frame_size_ms = outBits.config.isar_frame_size_ms; + hBits->lc3plus_highres = outBits.config.lc3plusHighRes; +#endif return; } @@ -226,6 +237,10 @@ static void convertInternalBitsBuffToBitsBuffer( hOutBits->config.codec = bits.codec; hOutBits->config.poseCorrection = bits.pose_correction; hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hOutBits->config.isar_frame_size_ms = bits.isar_frame_size_ms; + hOutBits->config.lc3plusHighRes = bits.lc3plus_highres; +#endif return; } @@ -455,6 +470,9 @@ static rendering_context getRendCtx( ctx.pOutSampleRate = &hIvasRend->sampleRateOut; ctx.pHeadRotData = &hIvasRend->headRotData; ctx.pSplitRendBFI = &hIvasRend->splitRendBFI; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ctx.pSplitRenderConfig = &hIvasRend->splitRenderConfig; +#endif return ctx; } @@ -477,8 +495,12 @@ static ivas_error getRendInputNumChannels( static ivas_error updateSplitPostRendPanGains( input_split_post_rend *inputSplitPostRend, const AUDIO_CONFIG outConfig, - ISAR_SPLIT_REND_CONFIG_DATA *hRendCfg, - int16_t num_subframes ) + ISAR_SPLIT_REND_CONFIG_DATA *hRendCfg +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t num_subframes +#endif +) { ivas_error error; rendering_context rendCtx; @@ -490,27 +512,34 @@ static ivas_error updateSplitPostRendPanGains( rendCtx = inputSplitPostRend->base.ctx; isar_renderSplitGetMultiBinPoseData( hRendCfg, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, rendCtx.pHeadRotData->sr_pose_pred_axis ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + config.high_res_mode_enabled = ( hRendCfg->lc3plus_highres != 0 ); +#endif config.lc3plus_frame_duration_us = hRendCfg->codec_frame_size_ms * 1000; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + config.isar_frame_duration_us = hRendCfg->isar_frame_size_ms * 1000; +#else if ( num_subframes != MAX_PARAM_SPATIAL_SUBFRAMES ) { if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) { - config.ivas_frame_duration_us = ( hRendCfg->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) ? config.lc3plus_frame_duration_us * num_subframes : 20000; + config.isar_frame_duration_us = ( hRendCfg->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) ? config.lc3plus_frame_duration_us * num_subframes : 20000; } else { - config.ivas_frame_duration_us = ( hRendCfg->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) ? config.lc3plus_frame_duration_us : 20000; + config.isar_frame_duration_us = ( hRendCfg->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) ? config.lc3plus_frame_duration_us : 20000; } iNumLCLDIterationsPerFrame = 1; } else { - config.ivas_frame_duration_us = 20000; + config.isar_frame_duration_us = 20000; } +#endif if ( hRendCfg->codec_frame_size_ms > 0 ) { - iNumLCLDIterationsPerFrame = (int16_t) config.ivas_frame_duration_us / ( 1000 * hRendCfg->codec_frame_size_ms ); + iNumLCLDIterationsPerFrame = (int16_t) config.isar_frame_duration_us / ( 1000 * hRendCfg->codec_frame_size_ms ); iNumLCLDIterationsPerFrame = max( 1, iNumLCLDIterationsPerFrame ); iNumBlocksPerFrame = CLDFB_NO_COL_MAX * hRendCfg->codec_frame_size_ms / 20; } @@ -552,8 +581,12 @@ static ivas_error setRendInputActiveSplitPostRend( void *input, const AUDIO_CONFIG inConfig, const IVAS_REND_InputId id, - ISAR_SPLIT_REND_CONFIG_DATA *hRendCfg, - const int16_t num_subframes ) + ISAR_SPLIT_REND_CONFIG_DATA *hRendCfg +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + const int16_t num_subframes +#endif +) { ivas_error error; rendering_context rendCtx; @@ -572,7 +605,12 @@ static ivas_error setRendInputActiveSplitPostRend( initRendInputBase( &inputSplitPostRend->base, inConfig, id, rendCtx, inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH ); inputSplitPostRend->numCachedSamples = 0; - if ( ( error = updateSplitPostRendPanGains( inputSplitPostRend, outConfig, hRendCfg, num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = updateSplitPostRendPanGains( inputSplitPostRend, outConfig, hRendCfg +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + num_subframes +#endif + ) ) != IVAS_ERR_OK ) { return error; } @@ -907,7 +945,12 @@ ivas_error ISAR_POST_REND_AddInput( int32_t maxNumInputsOfType; void *inputsArray; int32_t inputStructSize; - ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, ISAR_SPLIT_REND_CONFIG_DATA *, int16_t ); + ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, ISAR_SPLIT_REND_CONFIG_DATA * +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t +#endif + ); int32_t inputIndex; /* Validate function arguments */ @@ -935,7 +978,12 @@ ivas_error ISAR_POST_REND_AddInput( } *inputId = makeInputId( inConfig, inputIndex ); - if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, &hIvasRend->splitRenderConfig, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, &hIvasRend->splitRenderConfig +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + hIvasRend->num_subframes +#endif + ) ) != IVAS_ERR_OK ) { return error; } @@ -1136,6 +1184,9 @@ ivas_error ISAR_POST_REND_InitConfig( hIvasRend->splitRenderConfig.hq_mode = 0; hIvasRend->splitRenderConfig.codec_delay_ms = 0; hIvasRend->splitRenderConfig.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hIvasRend->splitRenderConfig.isar_frame_size_ms = 0; /* 0 means "use default for selected codec" */ +#endif hIvasRend->splitRenderConfig.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; hIvasRend->splitRenderConfig.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; hIvasRend->splitRenderConfig.rendererSelection = ISAR_SPLIT_REND_RENDERER_SELECTION_DEFAULT; @@ -1170,6 +1221,9 @@ int16_t ISAR_POST_REND_GetRenderConfig( splitRenderConfig->hq_mode = 0; splitRenderConfig->codec_delay_ms = 0; splitRenderConfig->codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + splitRenderConfig->isar_frame_size_ms = 0; /* 0 means "use default for selected codec" */ +#endif splitRenderConfig->codec = ISAR_SPLIT_REND_CODEC_DEFAULT; splitRenderConfig->poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; splitRenderConfig->rendererSelection = hRCin.rendererSelection; @@ -1286,12 +1340,18 @@ static ivas_error splitBinLc3plusDecode( ISAR_SPLIT_POST_REND_WRAPPER *hSplitBin, ISAR_SPLIT_REND_BITS_HANDLE bits, float outputBuffer[BINAURAL_CHANNELS][L_FRAME48k], +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS ISAR_SPLIT_REND_POSE_CORRECTION_MODE pose_correction, +#endif const int16_t SplitRendBFI ) { ivas_error error; float *channel_ptrs[MAX_HEAD_ROT_POSES * 2]; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t lc3plusBitstreamSize; +#else int32_t lc3plusBitrateId, lc3plusBitstreamSize; +#endif push_wmops( "splitBinLc3plusDecode" ); assert( hSplitBin->hLc3plusDec != NULL ); @@ -1308,9 +1368,15 @@ static ivas_error splitBinLc3plusDecode( { ++bits->bits_read; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* Size is in bytes */ + assert( ( bits->bits_written - bits->bits_read ) % 8 == 0 ); + lc3plusBitstreamSize = ( bits->bits_written - bits->bits_read ) / 8; +#else /* Read LC3plus bitstream size info */ lc3plusBitrateId = ISAR_SPLIT_REND_BITStream_read_int32( bits, 8 ); - lc3plusBitstreamSize = isar_get_lc3plus_size_from_id( (int8_t) lc3plusBitrateId, pose_correction, (int16_t) ( hSplitBin->hLc3plusDec->config.ivas_frame_duration_us / 1000 ) ); + lc3plusBitstreamSize = isar_get_lc3plus_size_from_id( (int8_t) lc3plusBitrateId, pose_correction, (int16_t) ( hSplitBin->hLc3plusDec->config.isar_frame_duration_us / 1000 ) ); +#endif if ( ( error = ISAR_LC3PLUS_DEC_Decode( hSplitBin->hLc3plusDec, &bits->bits_buf[bits->bits_read / 8], lc3plusBitstreamSize, channel_ptrs ) ) != IVAS_ERR_OK ) { @@ -1353,7 +1419,9 @@ static ivas_error renderSplitBinauralWithPostRot( int16_t outBufNumSamplesPerChannel, outBufNumColPerChannel; int16_t numSamplesPerChannelCacheSize, numColPerChannelCacheSize; float *readPtr, *writePtr; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS uint32_t ivas_frame_duration_us; +#endif int16_t iNumBlocksPerFrame, iNumLCLDIterationsPerFrame; const ISAR_POST_REND_HeadRotData *pHeadRotData; @@ -1361,15 +1429,24 @@ static ivas_error renderSplitBinauralWithPostRot( push_wmops( "renderSplitBinauralWithPostRot" ); error = IVAS_ERR_OK; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( outAudio.config.numSamplesPerChannel / *splitBinInput->base.ctx.pOutSampleRate > splitBinInput->hBits->config.isar_frame_size_ms ) + { + return IVAS_ERR_INTERNAL_FATAL; + } +#endif + pHeadRotData = splitBinInput->base.ctx.pHeadRotData; hSplitBin = &splitBinInput->splitPostRendWrapper; convertBitsBufferToInternalBitsBuff( *splitBinInput->hBits, &bits ); +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS ivas_frame_duration_us = 20000; if ( splitBinInput->splitPostRendWrapper.hLc3plusDec != NULL ) { - ivas_frame_duration_us = splitBinInput->splitPostRendWrapper.hLc3plusDec->config.ivas_frame_duration_us; + ivas_frame_duration_us = splitBinInput->splitPostRendWrapper.hLc3plusDec->config.isar_frame_duration_us; } +#endif iNumLCLDIterationsPerFrame = 1; iNumBlocksPerFrame = CLDFB_NO_COL_MAX; @@ -1414,9 +1491,13 @@ static ivas_error renderSplitBinauralWithPostRot( { isPostRendInputCldfb = 1; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outBufNumSamplesPerChannel; +#else preRendFrameSize_ms = (int16_t) ( ivas_frame_duration_us ) / 1000; numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * ( preRendFrameSize_ms - bits.codec_frame_size_ms ) / 1000 ); +#endif outBufNumColPerChannel = MAX_PARAM_SPATIAL_SUBFRAMES; numColPerChannelCacheSize = ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ) - outBufNumColPerChannel; @@ -1459,12 +1540,16 @@ static ivas_error renderSplitBinauralWithPostRot( } else { - if ( ( error = splitBinLc3plusDecode( hSplitBin, &bits, tmpCrendBuffer, bits.pose_correction, SplitRendBFI ) ) != IVAS_ERR_OK ) + if ( ( error = splitBinLc3plusDecode( hSplitBin, &bits, tmpCrendBuffer, +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS + bits.pose_correction, +#endif + SplitRendBFI ) ) != IVAS_ERR_OK ) { return error; } - /* cache the remaining 15ms */ + /* cache the remaining decoded audio */ splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize; mvr2r( &tmpCrendBuffer[0][outBufNumSamplesPerChannel], splitBinInput->bufferData, numSamplesPerChannelCacheSize ); mvr2r( &tmpCrendBuffer[1][outBufNumSamplesPerChannel], splitBinInput->bufferData + numSamplesPerChannelCacheSize, numSamplesPerChannelCacheSize ); @@ -1512,7 +1597,11 @@ static ivas_error renderSplitBinauralWithPostRot( copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer ); if ( splitBinInput->numCachedSamples == 0 ) { +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + preRendFrameSize_ms = splitBinInput->base.ctx.pSplitRenderConfig->isar_frame_size_ms; +#else preRendFrameSize_ms = (int16_t) ( ivas_frame_duration_us ) / 1000; +#endif numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * preRendFrameSize_ms / 1000 ); numSamplesPerChannelCacheSize -= outAudio.config.numSamplesPerChannel; splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize; @@ -1769,7 +1858,12 @@ ivas_error ISAR_REND_SetSplitRendBitstreamHeader( ISAR_POST_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ const ISAR_SPLIT_REND_CODEC codec, /* o: codec setting */ const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection, /* o: pose correction mode */ - const int16_t codec_frame_size_ms /* o: codec frame size setting */ + const int16_t codec_frame_size_ms /* i: codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + const int16_t isar_frame_size_ms, /* i: isar codec frame size setting */ + const int16_t lc3plus_highres /* i: LC3plus Hig-Res setting. Ignored if codec is not LC3plus */ +#endif ) { if ( hIvasRend == NULL ) @@ -1777,8 +1871,14 @@ ivas_error ISAR_REND_SetSplitRendBitstreamHeader( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } hIvasRend->splitRenderConfig.codec = codec; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hIvasRend->splitRenderConfig.isar_frame_size_ms = isar_frame_size_ms; +#endif hIvasRend->splitRenderConfig.codec_frame_size_ms = codec_frame_size_ms; hIvasRend->splitRenderConfig.poseCorrectionMode = poseCorrection; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hIvasRend->splitRenderConfig.lc3plus_highres = lc3plus_highres; +#endif return IVAS_ERR_OK; } diff --git a/lib_isar/lib_isar_post_rend.h b/lib_isar/lib_isar_post_rend.h index 221e0b26ff4e7d370158d3aabf0f0e66d54f237b..7c06895e689c2412ce69baa182445268025bab0a 100644 --- a/lib_isar/lib_isar_post_rend.h +++ b/lib_isar/lib_isar_post_rend.h @@ -62,6 +62,10 @@ typedef struct ISAR_SPLIT_REND_CODEC codec; ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection; int16_t codec_frame_size_ms; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t isar_frame_size_ms; + int16_t lc3plusHighRes; +#endif } ISAR_POST_REND_BitstreamBufferConfig; typedef struct @@ -202,7 +206,12 @@ ivas_error ISAR_REND_SetSplitRendBitstreamHeader( ISAR_POST_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ const ISAR_SPLIT_REND_CODEC codec, /* o: codec setting */ const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection, /* o: pose correction mode */ - const int16_t codec_frame_size_ms /* o: codec frame size setting */ + const int16_t codec_frame_size_ms /* i: codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + const int16_t isar_frame_size_ms, /* i: isar frame size setting */ + const int16_t lc3plus_highres /* i: LC3plus Hig-Res setting. Ignored if codec is not LC3plus */ +#endif ); #ifdef DEBUGGING diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 19a7345b98ec89d7c78ea4c9e643b6eab60b4dc5..c7d66e12632509132c286ceae070080fae2bdb40 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -82,7 +82,11 @@ ivas_error ISAR_PRE_REND_open( const int32_t output_Fs, /* i: output sampling rate */ const int16_t cldfb_in_flag, /* i: Flag to indicate CLDFB or time doamin input */ const int16_t pcm_out_flag, /* i: Flag to indicate PCM output */ - const int16_t num_subframes, /* i: number of subframes */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const IVAS_RENDER_FRAMESIZE ivas_frame_size, /* i: IVAS frame size */ +#else + const int16_t num_subframes, /* i: number of subframes */ +#endif const int16_t mixed_td_cldfb_flag /* i: Flag to indicate combined TD and CLDFB input */ ) { @@ -91,7 +95,19 @@ ivas_error ISAR_PRE_REND_open( int16_t cldfb_in_flag_local = cldfb_in_flag; - if ( ( error = isar_split_rend_choose_default_codec( &( pSplitRendConfig->codec ), &pSplitRendConfig->codec_frame_size_ms, cldfb_in_flag_local, pcm_out_flag, (int16_t) num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = isar_split_rend_choose_default_codec( &( pSplitRendConfig->codec ), +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + &pSplitRendConfig->isar_frame_size_ms, +#endif + &pSplitRendConfig->codec_frame_size_ms, + cldfb_in_flag_local, + pcm_out_flag, (int16_t) +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ivas_frame_size +#else + num_subframes +#endif + ) ) != IVAS_ERR_OK ) { return error; } @@ -176,7 +192,13 @@ ivas_error ISAR_PRE_REND_open( { if ( pSplitRendConfig->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) { - if ( ( error = split_renderer_open_lc3plus( hSplitBinRend, pSplitRendConfig, output_Fs, num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = split_renderer_open_lc3plus( hSplitBinRend, pSplitRendConfig, output_Fs, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ivas_frame_size +#else + num_subframes +#endif + ) ) != IVAS_ERR_OK ) { return error; } @@ -301,8 +323,11 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( const IVAS_QUATERNION headPosition, /* i: head rotation QUATERNION */ const int32_t SplitRendBitRate, /* i: Split renderer bitrate */ ISAR_SPLIT_REND_CODEC splitCodec, /* i/o: Split renderer codec */ - int16_t codec_frame_size_ms, /* i/o: Split renderer codec framesize */ - ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: Split renderer codec framesize */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const int16_t isar_frame_size_ms, /* i: ISAR framesize */ +#endif + int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB real buffer */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB imag buffer */ const int16_t max_bands, /* i: CLDFB bands */ @@ -314,7 +339,11 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( ) { ivas_error error; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int32_t bit_len, target_md_bits, available_bits; +#else int32_t bit_len, target_md_bits, actual_md_bits, available_bits; +#endif error = IVAS_ERR_OK; push_wmops( "isar_pre_rend_MultiBinToSplitBinaural" ); @@ -329,7 +358,19 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( { /*TD input*/ /*if CLDFB handles have been allocated then assume valid multi binaural input in out[][] buffer and perform CLDFB analysis*/ - error = isar_renderMultiTDBinToSplitBinaural( hSplitBin, headPosition, SplitRendBitRate, codec_frame_size_ms, pBits, max_bands, output, low_res_pre_rend_rot, pcm_out_flag, ro_md_flag ); + error = isar_renderMultiTDBinToSplitBinaural( hSplitBin, + headPosition, + SplitRendBitRate, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + isar_frame_size_ms, +#endif + codec_frame_size_ms, + pBits, + max_bands, + output, + low_res_pre_rend_rot, + pcm_out_flag, + ro_md_flag ); pop_wmops(); return error; @@ -341,12 +382,16 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( lc3plusTimeAlignCldfbPoseCorr( hSplitBin, Cldfb_In_BinReal, Cldfb_In_BinImag ); } +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS actual_md_bits = pBits->bits_written; +#endif if ( hSplitBin->multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { target_md_bits = isar_get_split_rend_md_target_brate( SplitRendBitRate, pcm_out_flag ) * L_FRAME48k / 48000; +#ifndef ISAR_BITSTREAM_UPDATE_LC3PLUS actual_md_bits = pBits->bits_written; +#endif isar_rend_CldfbSplitPreRendProcess( hSplitBin->hBinHrSplitPreRend, headPosition, &hSplitBin->multiBinPoseData, Cldfb_In_BinReal, Cldfb_In_BinImag, pBits, target_md_bits, low_res_pre_rend_rot, ro_md_flag ); } @@ -359,15 +404,19 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( if ( splitCodec == ISAR_SPLIT_REND_CODEC_LCLD ) { available_bits = ( SplitRendBitRate * hSplitBin->hSplitBinLCLDEnc->iNumBlocks * hSplitBin->hSplitBinLCLDEnc->iNumIterations ) / ( 16 * FRAMES_PER_SEC ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + available_bits -= pBits->bits_written; +#else actual_md_bits = pBits->bits_written - actual_md_bits; available_bits -= actual_md_bits; +#endif pBits->codec_frame_size_ms = codec_frame_size_ms; isar_splitBinLCLDEncProcess( hSplitBin->hSplitBinLCLDEnc, Cldfb_In_BinReal, Cldfb_In_BinImag, available_bits, pBits ); } else { int16_t ch, slot_idx, num_slots, ivas_fs; - ivas_fs = (int16_t) hSplitBin->hLc3plusEnc->config.ivas_frame_duration_us / 1000; + ivas_fs = (int16_t) hSplitBin->hLc3plusEnc->config.isar_frame_duration_us / 1000; num_slots = (int16_t) ( CLDFB_NO_COL_MAX * ivas_fs ) / 20; /* CLDFB synthesis of main pose */ for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) @@ -384,7 +433,12 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( cldfbSynthesis( Cldfb_In_BinReal_p, Cldfb_In_BinImag_p, output[ch], hSplitBin->hCldfbHandles->cldfbSyn[0]->no_channels * num_slots, hSplitBin->hCldfbHandles->cldfbSyn[ch] ); } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + available_bits = ( SplitRendBitRate / FRAMES_PER_SEC ) - pBits->bits_written; + if ( ( error = splitRendLc3plusEncodeAndWrite( hSplitBin, pBits, available_bits, output ) ) != IVAS_ERR_OK ) +#else if ( ( error = splitRendLc3plusEncodeAndWrite( hSplitBin, pBits, SplitRendBitRate, output ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -425,7 +479,7 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( } else { - bit_len = hSplitBin->hLc3plusEnc->config.ivas_frame_duration_us / 1000; + bit_len = hSplitBin->hLc3plusEnc->config.isar_frame_duration_us / 1000; bit_len = SplitRendBitRate * bit_len / 1000; } } diff --git a/lib_isar/lib_isar_pre_rend.h b/lib_isar/lib_isar_pre_rend.h index 72169d6c35d001ddbf6be4e5274bccdffd4f2d03..a1e658ac123ba0dd78dbec8b1e75be99206e2a7e 100644 --- a/lib_isar/lib_isar_pre_rend.h +++ b/lib_isar/lib_isar_pre_rend.h @@ -48,7 +48,11 @@ ivas_error ISAR_PRE_REND_open( const int32_t output_Fs, /* i: output sampling rate */ const int16_t cldfb_in_flag, /* i: Flag to indicate CLDFB or time doamin input */ const int16_t pcm_out_flag, /* i: Flag to indicate PCM output */ - const int16_t num_subframes, /* i: number of subframes */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const IVAS_RENDER_FRAMESIZE ivas_frame_size, /* i: IVAS frame size */ +#else + const int16_t num_subframes, /* i: number of subframes */ +#endif const int16_t mixed_td_cldfb_flag /* i: Flag to indicate combined TD and CLDFB input */ ); @@ -68,8 +72,11 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( const IVAS_QUATERNION headPosition, /* i: head rotation QUATERNION */ const int32_t SplitRendBitRate, /* i: Split renderer bitrate */ ISAR_SPLIT_REND_CODEC splitCodec, /* i/o: Split renderer codec */ - int16_t codec_frame_size_ms, /* i/o: Split renderer codec framesize */ - ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: Split renderer codec framesize */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + const int16_t isar_frame_size_ms, /* i: ISAR framesize */ +#endif + int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB real buffer */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB imag buffer */ const int16_t max_bands, /* i: CLDFB bands */ diff --git a/lib_rend/ivas_render_config.c b/lib_rend/ivas_render_config.c index e9c9fa749aec261cf80fb46ea90632b72588a3f3..0b61ef7ab46c28994f33f1568a4037b2b4a37be7 100644 --- a/lib_rend/ivas_render_config.c +++ b/lib_rend/ivas_render_config.c @@ -136,10 +136,16 @@ ivas_error ivas_render_config_init_from_rom( ( *hRenderConfig )->split_rend_config.dof = 3; ( *hRenderConfig )->split_rend_config.hq_mode = 0; ( *hRenderConfig )->split_rend_config.codec_delay_ms = 0; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ( *hRenderConfig )->split_rend_config.isar_frame_size_ms = 20; +#endif ( *hRenderConfig )->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */ ( *hRenderConfig )->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; ( *hRenderConfig )->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; ( *hRenderConfig )->split_rend_config.rendererSelection = ISAR_SPLIT_REND_RENDERER_SELECTION_DEFAULT; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ( *hRenderConfig )->split_rend_config.lc3plus_highres = 0; +#endif #endif return IVAS_ERR_OK; diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index a0d31fa8a642e38b1649da2a2288357dea523924..1ade3c85f43d471ce4a6d5820a588983a94bc7b5 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -4378,10 +4378,16 @@ int16_t IVAS_REND_GetRenderConfig( hRCout->split_rend_config.dof = 3; hRCout->split_rend_config.hq_mode = 0; hRCout->split_rend_config.codec_delay_ms = 0; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hRCout->split_rend_config.isar_frame_size_ms = 20; +#endif hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */ hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hRCout->split_rend_config.lc3plus_highres = 0; +#endif #endif hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er; @@ -7847,8 +7853,23 @@ static ivas_error getSamplesInternal( } } - if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( &hIvasRend->splitRendWrapper, hIvasRend->headRotData.headPositions[0], hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, hIvasRend->hRendererConfig->split_rend_config.codec, hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, - &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), tmpBinaural, 1, cldfb_in_flag, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, ro_md_flag ) ) != IVAS_ERR_OK ) + if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( &hIvasRend->splitRendWrapper, + hIvasRend->headRotData.headPositions[0], + hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, + hIvasRend->hRendererConfig->split_rend_config.codec, +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, +#endif + hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, + &bits, + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, + ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), + tmpBinaural, + 1, + cldfb_in_flag, + ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, + ro_md_flag ) ) != IVAS_ERR_OK ) { return error; } @@ -7941,6 +7962,10 @@ ivas_error IVAS_REND_GetSplitRendBitstreamHeader( ISAR_SPLIT_REND_CODEC *pCodec, /* o: pointer to codec setting */ ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o: pointer to pose correction mode */ int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t *pIsar_frame_size_ms /* o: pointer to isar frame size setting */ +#endif ) { if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL ) @@ -7949,6 +7974,9 @@ ivas_error IVAS_REND_GetSplitRendBitstreamHeader( } *pCodec = hIvasRend->hRendererConfig->split_rend_config.codec; *pCodec_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + *pIsar_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms; +#endif *poseCorrection = hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode; return IVAS_ERR_OK; } diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index e3a1bd614701a62c2e5231791ff5b4dcfcd89973..768a53cfa52e2d0126961a7eb11032c16a00f727 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -62,6 +62,10 @@ typedef struct ISAR_SPLIT_REND_CODEC codec; ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection; int16_t codec_frame_size_ms; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int16_t isar_frame_size_ms; + int16_t lc3plus_highres; +#endif } IVAS_REND_BitstreamBufferConfig; typedef struct { @@ -271,7 +275,11 @@ ivas_error IVAS_REND_GetSplitRendBitstreamHeader( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ ISAR_SPLIT_REND_CODEC *pCodec, /* o: pointer to codec setting */ ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o: pointer to pose correction mode */ - int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ + int16_t *pCodec_frame_size_ms /* o: pointer to codec frame size setting */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t *pIsar_frame_size_ms /* o: pointer to isar frame size setting */ +#endif ); #endif diff --git a/lib_util/render_config_reader.c b/lib_util/render_config_reader.c index 981f2614204202cd2122b3e835b27a5291171d93..01a72d0598e5b278208c322fecefc1a5550e31a0 100644 --- a/lib_util/render_config_reader.c +++ b/lib_util/render_config_reader.c @@ -2561,6 +2561,15 @@ ivas_error RenderConfigReader_read( errorHandler( pValue, ERROR_VALUE_INVALID ); } } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + else if ( strcmp( item, "LC3PLUS_HIGHRES" ) == 0 ) + { + if ( !sscanf( pValue, "%hd", &hRenderConfig->split_rend_config.lc3plus_highres ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + } + } +#endif #ifdef DEBUGGING else { diff --git a/lib_util/split_render_file_read_write.c b/lib_util/split_render_file_read_write.c index 714467b1189e88ce38410a7e656b6623036f7f1e..6a676235be767e8ca22ce41af3cc77db9b583f54 100644 --- a/lib_util/split_render_file_read_write.c +++ b/lib_util/split_render_file_read_write.c @@ -66,7 +66,14 @@ ivas_error split_rend_reader_open( char *filename, ISAR_SPLIT_REND_CODEC *codec, ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, - int16_t *codec_frame_size_ms ) + int16_t *codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t *isar_frame_size_ms, + int32_t *sampling_rate, + int16_t *lc3plus_highres +#endif +) { SplitFileReadWrite *hSplitRendFileReadWrite; size_t header_len, h; @@ -113,11 +120,28 @@ ivas_error split_rend_reader_open( { return IVAS_ERR_FAILED_FILE_READ; } - /* read frame size signalling */ + /* read transport codec frame size signalling */ if ( fread( codec_frame_size_ms, sizeof( *codec_frame_size_ms ), 1, hSplitRendFileReadWrite->file ) != 1 ) { return IVAS_ERR_FAILED_FILE_READ; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* read isar bitstream frame size signalling */ + if ( fread( isar_frame_size_ms, sizeof( *isar_frame_size_ms ), 1, hSplitRendFileReadWrite->file ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + /* read sampling rate signalling */ + if ( fread( sampling_rate, sizeof( *sampling_rate ), 1, hSplitRendFileReadWrite->file ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + /* read LC3plus highres signalling */ + if ( fread( lc3plus_highres, sizeof( *lc3plus_highres ), 1, hSplitRendFileReadWrite->file ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_READ; + } +#endif *hhSplitRendFileReadWrite = hSplitRendFileReadWrite; @@ -138,7 +162,14 @@ ivas_error split_rend_writer_open( const int32_t delayTimeScale, ISAR_SPLIT_REND_CODEC codec, ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection, - int16_t codec_frame_size_ms ) + int16_t codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + const int16_t isar_frame_size_ms, + const int32_t sampling_rate, + const int16_t lc3plus_highres +#endif +) { SplitFileReadWrite *hSplitRendFileReadWrite; size_t header_len, h; @@ -184,11 +215,28 @@ ivas_error split_rend_writer_open( { return IVAS_ERR_FAILED_FILE_WRITE; } - /* Write frame size signalling */ + /* Write transport codec frame size signalling */ if ( fwrite( &codec_frame_size_ms, sizeof( codec_frame_size_ms ), 1, hSplitRendFileReadWrite->file ) != 1 ) { return IVAS_ERR_FAILED_FILE_WRITE; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* Write isar bit stream frame size signalling */ + if ( fwrite( &isar_frame_size_ms, sizeof( isar_frame_size_ms ), 1, hSplitRendFileReadWrite->file ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_WRITE; + } + /* Write sampling rate signalling */ + if ( fwrite( &sampling_rate, sizeof( sampling_rate ), 1, hSplitRendFileReadWrite->file ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_WRITE; + } + /* Write LC3plus highres signalling */ + if ( fwrite( &lc3plus_highres, sizeof( lc3plus_highres ), 1, hSplitRendFileReadWrite->file ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_WRITE; + } +#endif *hhSplitRendFileReadWrite = hSplitRendFileReadWrite; diff --git a/lib_util/split_render_file_read_write.h b/lib_util/split_render_file_read_write.h index 69d50c4951eb0824afd903772befa170ecdd3b5a..ea277cfc52a57caf2e0412561306569441494b02 100644 --- a/lib_util/split_render_file_read_write.h +++ b/lib_util/split_render_file_read_write.h @@ -44,7 +44,14 @@ ivas_error split_rend_reader_open( char *filename, ISAR_SPLIT_REND_CODEC *codec, ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, - int16_t *codec_frame_size_ms ); + int16_t *codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + int16_t *isar_frame_size_ms, + int32_t *sampling_rate, + int16_t *lc3plus_highres +#endif +); /* Allocates and initializes a a split renderer writer instance */ @@ -55,7 +62,14 @@ ivas_error split_rend_writer_open( const int32_t delayTimeScale, ISAR_SPLIT_REND_CODEC codec, ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection, - int16_t codec_frame_size_ms ); + int16_t codec_frame_size_ms +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + , + const int16_t isar_frame_size_ms, + const int32_t sampling_rate, + const int16_t lc3plus_highres +#endif +); /* Closes the split renderer reader/writer and deallocates memory */ diff --git a/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test.c b/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test.c index 048b18eef3b22893688c327e9ce3fcb540357784..53c7c45165aab75e1f11bf81e7b8c2f16e19cf1d 100644 --- a/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test.c +++ b/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test.c @@ -30,6 +30,7 @@ the United Nations Convention on Contracts on the International Sales of Goods. *******************************************************************************************************/ +#include #include #include #include "options.h" @@ -37,15 +38,21 @@ the United Nations Convention on Contracts on the International Sales of Goods. #include "isar_lc3plus_common.h" #include "isar_lc3plus_dec.h" #include "ivas_error_utils.h" +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#include "lc3.h" +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#define MAX_SAMPLES_PER_CHANNEL 960 / 4 +#else #define MAX_SAMPLES_PER_CHANNEL 960 +#endif +#define DEFAULT_BPS 256000 -static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config ) +static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) { ivas_error err; - uint32_t bps = 128000; int32_t encDelay = -1; int32_t decDelay = -1; @@ -59,15 +66,17 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config ) err = ISAR_LC3PLUS_ENC_GetDelay( encHandle, &encDelay ); if ( IVAS_ERR_OK != err ) { + ISAR_LC3PLUS_ENC_Close( &encHandle ); return err; } if ( encDelay == -1 || encDelay == 0 ) { + ISAR_LC3PLUS_ENC_Close( &encHandle ); return IVAS_ERROR( IVAS_ERR_INTERNAL, "encDelay is zero or uninitialized\n" ); } /* encode one frame */ - int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.ivas_frame_duration_us ); + int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); float *pcm_in[2]; float pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( float ) ); @@ -79,14 +88,38 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config ) int32_t bitstreamSizePerIvasFrame = 0; err = ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( encHandle, &bitstreamSizePerIvasFrame ); if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); return err; - + } uint8_t *bitstream_out = malloc( bitstreamSizePerIvasFrame ); memset( bitstream_out, 0, bitstreamSizePerIvasFrame ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + int perChannelBitrate = lc3plus_enc_get_real_bitrate(encHandle->handles[0]); + int perLc3plusFrameDataBlockOctets = encHandle->num_ftds * perChannelBitrate / 8 / (1000*1000/config.lc3plus_frame_duration_us); + int targetOctets = bps / 8 / (1000*1000/config.isar_frame_duration_us); + printf("IVAS-FS=%i LC3plus-FS=%i ch=%i targetBps=%i targetOctets=%i\n", config.isar_frame_duration_us, config.lc3plus_frame_duration_us, config.channels, bps, targetOctets); + printf(" coreBps=%i corePerChBps=%i coreCodecOctets=%i nFtds=%i \n", perChannelBitrate * encHandle->num_encs, perChannelBitrate, perLc3plusFrameDataBlockOctets, encHandle->num_ftds); + int pfOctets = bitstreamSizePerIvasFrame - perLc3plusFrameDataBlockOctets; + int pfBps = pfOctets * 8 * (1000*1000 / config.isar_frame_duration_us); + printf(" payloadFormatBps=%i payloadFormatOctets=%i \n\n", pfBps, pfOctets); + if(pfBps <= 0) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + return err; + } + + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame ); +#else err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out ); +#endif if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + free( bitstream_out ); return err; + } ISAR_LC3PLUS_ENC_Close( &encHandle ); /* decode one frame */ @@ -98,16 +131,21 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config ) &decHandle ); if ( IVAS_ERR_OK != err ) { + free( bitstream_out ); return err; } err = ISAR_LC3PLUS_DEC_GetDelay( decHandle, &decDelay ); if ( IVAS_ERR_OK != err ) { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out ); return err; } if ( decDelay == -1 || decDelay == 0 ) { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out ); return IVAS_ERROR( IVAS_ERR_INTERNAL, "decDelay is zero or uninitialized\n" ); } @@ -124,18 +162,24 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config ) err = ISAR_LC3PLUS_DEC_Conceal( decHandle, pcm_out ); if ( IVAS_ERR_OK != err ) { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out ); return err; } err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstreamSizePerIvasFrame, pcm_out ); if ( IVAS_ERR_OK != err ) { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out ); return err; } err = ISAR_LC3PLUS_DEC_Conceal( decHandle, pcm_out ); if ( IVAS_ERR_OK != err ) { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out ); return err; } @@ -149,7 +193,11 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config ) static int openCloseEncoder( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif uint32_t bps = 128000; ISAR_LC3PLUS_ENC_HANDLE encHandle; @@ -166,31 +214,55 @@ static int openCloseEncoder( void ) static int tryOpenEncoderWithInvalidBitrate( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif /* lc3plus max bitrate is 320000 per channel */ uint32_t invalid_high_bps = 700000; uint32_t invalid_low_bps = 8; - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + uint32_t limitedBitrate; +#endif ISAR_LC3PLUS_ENC_HANDLE encHandle; err = ISAR_LC3PLUS_ENC_Open( config, invalid_high_bps, &encHandle ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + /* setting an invalid bitrate should result in a limited bitrate*/ + if ( IVAS_ERR_OK != err ) +#else /* setting an invalid bitrate should trigger an error - which is what we expect */ if ( IVAS_ERR_LC3PLUS_INVALID_BITRATE != err ) +#endif { return 1; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + limitedBitrate = lc3plus_enc_get_real_bitrate(encHandle->handles[0]); + if(limitedBitrate != 320000) + { + return 1; + } +#endif + ISAR_LC3PLUS_ENC_Close(&encHandle); err = ISAR_LC3PLUS_ENC_Open( config, invalid_low_bps, &encHandle ); /* setting an invalid bitrate should trigger an error - which is what we expect */ if ( IVAS_ERR_LC3PLUS_INVALID_BITRATE != err ) { return 1; } + ISAR_LC3PLUS_ENC_Close(&encHandle); return 0; } static int tryOpenEncoderWithInvalidFrameDuration( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif config.lc3plus_frame_duration_us = 1234; /*unsupported frame duration*/ uint32_t bps = 320000; @@ -207,7 +279,11 @@ static int tryOpenEncoderWithInvalidFrameDuration( void ) static int tryOpenEncoderWithInvalidSampleRate( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif config.samplerate = 1234; /*unsupported sample rate */ uint32_t bps = 320000; @@ -247,11 +323,19 @@ static int tryCallEncoderApiWithInvalidParams( void ) return 1; } ISAR_LC3PLUS_ENC_Close( &invalidEncHandle ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, invalidBitstream_out, bsSize ) ) +#else if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, invalidBitstream_out ) ) +#endif { return 1; } +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, invalidBitstream_out, bsSize ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, bitstream_out, bsSize ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, bitstream_out, bsSize ) ) +#else if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, invalidBitstream_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, bitstream_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, bitstream_out ) ) +#endif { return 1; } @@ -297,8 +381,11 @@ static int tryCallDecoderApiWithInvalidParams( void ) static int openCloseDecoderWithCaching( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif ISAR_LC3PLUS_DEC_HANDLE decHandle; err = ISAR_LC3PLUS_DEC_Open( config, #ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING @@ -317,8 +404,11 @@ static int openCloseDecoderWithCaching( void ) static int openCloseDecoderWithoutCaching( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif ISAR_LC3PLUS_DEC_HANDLE decHandle; err = ISAR_LC3PLUS_DEC_Open( config, #ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING @@ -338,7 +428,11 @@ static int openCloseDecoderWithoutCaching( void ) static int tryOpenDecoderWithInvalidFrameDuration( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif config.lc3plus_frame_duration_us = 1234; /*unsupported frame duration*/ ISAR_LC3PLUS_DEC_HANDLE decHandle; @@ -358,7 +452,11 @@ static int tryOpenDecoderWithInvalidFrameDuration( void ) static int tryOpenDecoderWithInvalidSampleRate( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif config.samplerate = 1234; /*unsupported sample rate*/ ISAR_LC3PLUS_DEC_HANDLE decHandle; @@ -378,7 +476,11 @@ static int tryOpenDecoderWithInvalidSampleRate( void ) static int encodeOneFrame( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif uint32_t bps = 128000; ISAR_LC3PLUS_ENC_HANDLE encHandle; @@ -386,7 +488,7 @@ static int encodeOneFrame( void ) if ( IVAS_ERR_OK != err ) return err; - int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.ivas_frame_duration_us ); + int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); float *pcm[1]; float pcm_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; @@ -399,8 +501,11 @@ static int encodeOneFrame( void ) return err; uint8_t *bitstream_out = malloc( bitstreamSizePerIvasFrame ); memset( bitstream_out, 0, bitstreamSizePerIvasFrame ); - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm, bitstream_out, bitstreamSizePerIvasFrame ); +#else err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm, bitstream_out ); +#endif if ( IVAS_ERR_OK != err ) return err; @@ -413,7 +518,11 @@ static int encodeOneFrame( void ) static int encodeAndDecodeOneMonoFrame( void ) { ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20000, .channels = 1, .samplerate = 48000 }; +#endif uint32_t bps = 128000; ISAR_LC3PLUS_ENC_HANDLE encHandle; @@ -424,7 +533,7 @@ static int encodeAndDecodeOneMonoFrame( void ) } /* encode one frame */ - int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.ivas_frame_duration_us ); + int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); float *pcm_in[1]; float pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( float ) ); @@ -437,8 +546,11 @@ static int encodeAndDecodeOneMonoFrame( void ) uint8_t *bitstream_out = malloc( bitstreamSizePerIvasFrame ); memset( bitstream_out, 0, bitstreamSizePerIvasFrame ); - +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame ); +#else err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out ); +#endif if ( IVAS_ERR_OK != err ) return err; ISAR_LC3PLUS_ENC_Close( &encHandle ); @@ -481,147 +593,264 @@ static int encodeAndDecodeOneMonoFrame( void ) static int encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_48kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000 }; - return encodeAndDecodeOneStereoFrame( config ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } static int encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_32kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 32000 }; - return encodeAndDecodeOneStereoFrame( config ); + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 32000 }; + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } static int encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_16kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 16000 }; - return encodeAndDecodeOneStereoFrame( config ); + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 16000 }; + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } static int encodeAndDecodeOneStereoFrameIvas5msLc3plus5ms_48kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 5 * 1000, .channels = 2, .samplerate = 48000 }; - return encodeAndDecodeOneStereoFrame( config ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); +} + +static int encodeAndDecodeOneStereoFrameIvas10msLc3plus10ms_48kHz( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } static int encodeAndDecodeOneMonoFrameIvas20msLc3plus10ms_48kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000 }; - return encodeAndDecodeOneStereoFrame( config ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } static int encodeAndDecodeOneMonoFrameIvas5msLc3plus5ms_48kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 5 * 1000, .channels = 1, .samplerate = 48000 }; - return encodeAndDecodeOneStereoFrame( config ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5 * 1000, .channels = 1, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } static int encodeAndDecodeOneStereoFrameIvas20msLc3plus2_5ms_48kHz( void ) { - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 2.5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000 }; - return encodeAndDecodeOneStereoFrame( config ); +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 2.5 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 2.5 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); } -#include "ivas_lc3plus_unit_test_selective_decoding.c" +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_80kbpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 82*1000 ); +} + +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_96kbpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 98*1000 ); +} + +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_124kbpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 126*1000 ); +} + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_800kbpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 800*1000 ); +} +#endif + +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_204800bpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 204800 ); +} + +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_205600bpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 205600 ); +} + +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_206400bpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 206400 ); +} + +static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_207200bpsPerChannel( void ) +{ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; +#else + LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000 }; +#endif + return encodeAndDecodeOneStereoFrame( config, config.channels * 207200 ); +} + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS +#include "ivas_lc3plus_unit_test_payload_format.c" +#endif int main( int argc, char *argv[] ) { + (void)argc; + (void)argv; int ret = 0; ret = openCloseEncoder(); if ( ret != 0 ) - return ret; + return 1; ret = tryOpenEncoderWithInvalidBitrate(); if ( ret != 0 ) - return ret; + return 1; ret = tryOpenEncoderWithInvalidFrameDuration(); if ( ret != 0 ) - return ret; + return 1; ret = tryOpenEncoderWithInvalidSampleRate(); if ( ret != 0 ) - return ret; + return 1; ret = tryCallEncoderApiWithInvalidParams(); if ( ret != 0 ) - return ret; + return 1; ret = openCloseDecoderWithCaching(); if ( ret != 0 ) - return ret; + return 1; ret = openCloseDecoderWithoutCaching(); if ( ret != 0 ) - return ret; + return 1; ret = tryOpenDecoderWithInvalidFrameDuration(); if ( ret != 0 ) - return ret; + return 1; ret = tryOpenDecoderWithInvalidSampleRate(); if ( ret != 0 ) - return ret; + return 1; ret = tryCallDecoderApiWithInvalidParams(); if ( ret != 0 ) - return ret; + return 1; ret = encodeOneFrame(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneMonoFrame(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_48kHz(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_32kHz(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_16kHz(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneStereoFrameIvas5msLc3plus5ms_48kHz(); if ( ret != 0 ) - return ret; + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3plus10ms_48kHz(); + if ( ret != 0 ) + return 1; ret = encodeAndDecodeOneMonoFrameIvas20msLc3plus10ms_48kHz(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneMonoFrameIvas5msLc3plus5ms_48kHz(); if ( ret != 0 ) - return ret; + return 1; ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus2_5ms_48kHz(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_decode_all_subframes(); - if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_dont_decode_last_2_subframes(); - if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_dont_decode_last_3_subframes(); + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_80kbpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_skip_first_subframe(); + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_96kbpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_decode_cache(); + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_124kbpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_switches_skip_first(); + return 1; +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_800kbpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_switches_dec_first(); + return 1; +#endif + /* start configs around the FDL threshold */ + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_204800bpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_bundle_switches_dec_first(); + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_205600bpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_bundle_switches_skip_first(); + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_206400bpsPerChannel(); if ( ret != 0 ) - return ret; - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_get_active_dont_cache(); + return 1; + ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_207200bpsPerChannel(); if ( ret != 0 ) - return ret; -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING - ret = selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_switches_dec_first_no_caching(); + return 1; + /* end configs around the FDL threshold */ +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + ret = run_all_payload_tests(); if ( ret != 0 ) - return ret; + return 1; #endif - return ret; + return 0; } #else int main( void ) diff --git a/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test_payload_format.c b/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test_payload_format.c new file mode 100644 index 0000000000000000000000000000000000000000..a303d01f53ee873fe70c0fbad2a9b6a540daa154 --- /dev/null +++ b/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test_payload_format.c @@ -0,0 +1,451 @@ +/****************************************************************************************************** + +(C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +contributors to this repository. All Rights Reserved. + +This software is protected by copyright law and by international treaties. +The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +contributors to this repository retain full ownership rights in their respective contributions in +the software. This notice grants no license of any kind, including but not limited to patent +license, nor is any license granted by implication, estoppel or otherwise. + +Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +contributions. + +This software is provided "AS IS", without any express or implied warranties. The software is in the +development stage. It is intended exclusively for experts who have experience with such software and +solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +and fitness for a particular purpose are hereby disclaimed and excluded. + +Any dispute, controversy or claim arising under or in relation to providing this software shall be +submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include +#include "isar_lc3plus_payload.h" +#include "ivas_error_utils.h" +#include "isar_lc3plus_common.h" +#include "options.h" + +#ifdef ISAR_BITSTREAM_UPDATE_LC3PLUS + +/* included by ivas_lc3plus_unit_test.c */ + +#define LC3PLUS_MAX_NUM_CODERS 16 +#define LC3PLUS_MAX_BS_SIZE LC3PLUS_MAX_NUM_CODERS *( 720 * LC3PLUS_RTP_PAYLOAD_MAX_NUM_MEDIA_TIMES ) +#define SIZE_70 70 +#define SIZE_160 160 +#define SIZE_320 320 +#define SIZE_600 600 + +static int pack_and_unpack_payload_config_2ch_10ms_lc3plus_20ms_ivas( void ) +{ + LC3PLUS_RTP_FTD sender_ftds[LC3PLUS_MAX_NUM_CODERS]; + int32_t sender_ftds_num = 0; + const LC3PLUS_RTP_FDL fdl_req = LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA; + + LC3PLUS_RTP_FTD *ftd_L_01 = &sender_ftds[0]; + ftd_L_01->fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + ftd_L_01->fdi = LC3PLUS_RTP_FTD_FDI_10000_US; + ftd_L_01->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_01->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_01->frame_data = NULL; + ftd_L_01->frame_data_length = SIZE_160; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_R_01 = &sender_ftds[1]; + ftd_R_01->fc = LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME; + ftd_R_01->fdi = LC3PLUS_RTP_FTD_FDI_10000_US; + ftd_R_01->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_R_01->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_R_01->frame_data = NULL; + ftd_R_01->frame_data_length = SIZE_600; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_L_02 = &sender_ftds[2]; + ftd_L_02->fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + ftd_L_02->fdi = LC3PLUS_RTP_FTD_FDI_10000_US; + ftd_L_02->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_02->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_02->frame_data = NULL; + ftd_L_02->frame_data_length = SIZE_320; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_R_02 = &sender_ftds[3]; + ftd_R_02->fc = LC3PLUS_RTP_FTD_FC_LAST_OVERALL; + ftd_R_02->fdi = LC3PLUS_RTP_FTD_FDI_10000_US; + ftd_R_02->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_R_02->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_R_02->frame_data = NULL; + ftd_R_02->frame_data_length = SIZE_160; + sender_ftds_num++; + + const size_t packed_buffer_capacity = LC3PLUS_MAX_BS_SIZE; + size_t packed_buffer_actual_size; + uint8_t packed_buffer[LC3PLUS_MAX_BS_SIZE]; + memset( packed_buffer, 0, packed_buffer_capacity ); + // prepare bitstream buffer headers & layout + LC3PLUS_RTP_ERR error = LC3PLUS_RTP_payload_serialize( packed_buffer, packed_buffer_capacity, &packed_buffer_actual_size, fdl_req, sender_ftds, sender_ftds_num ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_serialize failed\n" ); + } + + // copy encoded frames into their expected memory locations + uint8_t frame_data_L_01[SIZE_160]; + memset( frame_data_L_01, 0x01, sizeof( frame_data_L_01 ) ); + uint8_t frame_data_R_01[SIZE_600]; + memset( frame_data_R_01, 0x02, sizeof( frame_data_R_01 ) ); + uint8_t frame_data_L_02[SIZE_320]; + memset( frame_data_L_02, 0x03, sizeof( frame_data_L_02 ) ); + uint8_t frame_data_R_02[SIZE_160]; + memset( frame_data_R_02, 0x04, sizeof( frame_data_R_02 ) ); + memcpy( sender_ftds[0].frame_data, frame_data_L_01, sender_ftds[0].frame_data_length ); + memcpy( sender_ftds[1].frame_data, frame_data_R_01, sender_ftds[1].frame_data_length ); + memcpy( sender_ftds[2].frame_data, frame_data_L_02, sender_ftds[2].frame_data_length ); + memcpy( sender_ftds[3].frame_data, frame_data_R_02, sender_ftds[3].frame_data_length ); + + uint8_t *receiverBuffer = malloc( packed_buffer_actual_size ); + assert( NULL != receiverBuffer ); + memcpy( receiverBuffer, packed_buffer, packed_buffer_actual_size ); + + LC3PLUS_RTP_PAYLOAD payload_config; + error = LC3PLUS_RTP_payload_deserialize( &payload_config, receiverBuffer, packed_buffer_actual_size ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_deserialize failed\n" ); + } + + assert( payload_config.fdl_request == fdl_req ); + assert( payload_config.frame_duration_us == 10000 ); + assert( payload_config.high_resolution_enabled == 0 ); + assert( payload_config.sampling_rate_hz == 48000 ); + assert( payload_config.num_ftds == 4 ); + assert( payload_config.num_media_times == 2 ); + assert( payload_config.num_channels == 2 ); + for ( int32_t i = 0; i < payload_config.num_ftds; ++i ) + { + assert( payload_config.ftds[i].frame_data_length == sender_ftds[i].frame_data_length ); + assert( payload_config.ftds[i].h == sender_ftds[i].h ); + assert( payload_config.ftds[i].fdi == sender_ftds[i].fdi ); + assert( payload_config.ftds[i].bwr == sender_ftds[i].bwr ); + assert( payload_config.ftds[i].fc == sender_ftds[i].fc ); + assert( payload_config.ftds[i].frame_data_length == sender_ftds[i].frame_data_length ); + assert( payload_config.ftds[i].frame_data != sender_ftds[i].frame_data ); + assert( 0 == memcmp( payload_config.ftds[i].frame_data, sender_ftds[i].frame_data, sender_ftds[i].frame_data_length ) ); + } + + free( receiverBuffer ); + return 0; +} + +static int pack_and_unpack_payload_config_2ch_5ms_lc3plus_20ms_ivas( void ) +{ + LC3PLUS_RTP_FTD sender_ftds[LC3PLUS_MAX_NUM_CODERS]; + int32_t sender_ftds_num = 0; + const LC3PLUS_RTP_FDL fdl_req = LC3PLUS_RTP_FDL_NO_REQ_OR_NO_DATA; + + LC3PLUS_RTP_FTD *ftd_L_01 = &sender_ftds[0]; + ftd_L_01->fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + ftd_L_01->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_L_01->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_01->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_01->frame_data = NULL; + ftd_L_01->frame_data_length = SIZE_70; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_R_01 = &sender_ftds[1]; + ftd_R_01->fc = LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME; + ftd_R_01->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_R_01->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_R_01->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_R_01->frame_data = NULL; + ftd_R_01->frame_data_length = SIZE_320; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_L_02 = &sender_ftds[2]; + ftd_L_02->fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + ftd_L_02->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_L_02->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_02->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_02->frame_data = NULL; + ftd_L_02->frame_data_length = SIZE_70; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_R_02 = &sender_ftds[3]; + ftd_R_02->fc = LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME; + ftd_R_02->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_R_02->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_R_02->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_R_02->frame_data = NULL; + ftd_R_02->frame_data_length = SIZE_160; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_L_03 = &sender_ftds[4]; + ftd_L_03->fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + ftd_L_03->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_L_03->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_03->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_03->frame_data = NULL; + ftd_L_03->frame_data_length = SIZE_70; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_R_03 = &sender_ftds[5]; + ftd_R_03->fc = LC3PLUS_RTP_FTD_FC_LAST_IN_MEDIATIME; + ftd_R_03->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_R_03->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_R_03->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_R_03->frame_data = NULL; + ftd_R_03->frame_data_length = SIZE_320; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_L_04 = &sender_ftds[6]; + ftd_L_04->fc = LC3PLUS_RTP_FTD_FC_SUBSEQUENT_CHANNEL; + ftd_L_04->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_L_04->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_04->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_04->frame_data = NULL; + ftd_L_04->frame_data_length = SIZE_70; + sender_ftds_num++; + + LC3PLUS_RTP_FTD *ftd_R_04 = &sender_ftds[7]; + ftd_R_04->fc = LC3PLUS_RTP_FTD_FC_LAST_OVERALL; + ftd_R_04->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_R_04->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_R_04->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_R_04->frame_data = NULL; + ftd_R_04->frame_data_length = SIZE_160; + sender_ftds_num++; + + const size_t packed_buffer_capacity = LC3PLUS_MAX_BS_SIZE; + size_t packed_buffer_actual_size; + uint8_t packed_buffer[LC3PLUS_MAX_BS_SIZE]; + memset( packed_buffer, 0, packed_buffer_capacity ); + // prepare bitstream buffer headers & layout + LC3PLUS_RTP_ERR error = LC3PLUS_RTP_payload_serialize( packed_buffer, packed_buffer_capacity, &packed_buffer_actual_size, fdl_req, sender_ftds, sender_ftds_num ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_serialize failed\n" ); + } + + + // copy encoded frames into their expected memory locations + uint8_t frame_data_L_01[SIZE_70]; + assert( ftd_L_01->frame_data_length == sizeof( frame_data_L_01 ) ); + memset( frame_data_L_01, 0x01, sizeof( frame_data_L_01 ) ); + uint8_t frame_data_R_01[SIZE_320]; + assert( ftd_R_01->frame_data_length == sizeof( frame_data_R_01 ) ); + memset( frame_data_R_01, 0x02, sizeof( frame_data_R_01 ) ); + uint8_t frame_data_L_02[SIZE_70]; + assert( ftd_L_02->frame_data_length == sizeof( frame_data_L_02 ) ); + memset( frame_data_L_02, 0x03, sizeof( frame_data_L_02 ) ); + uint8_t frame_data_R_02[SIZE_160]; + assert( ftd_R_02->frame_data_length == sizeof( frame_data_R_02 ) ); + memset( frame_data_R_02, 0x04, sizeof( frame_data_R_02 ) ); + uint8_t frame_data_L_03[SIZE_70]; + assert( ftd_L_03->frame_data_length == sizeof( frame_data_L_03 ) ); + memset( frame_data_L_03, 0x05, sizeof( frame_data_L_03 ) ); + uint8_t frame_data_R_03[SIZE_320]; + assert( ftd_R_03->frame_data_length == sizeof( frame_data_R_03 ) ); + memset( frame_data_R_03, 0x06, sizeof( frame_data_R_03 ) ); + uint8_t frame_data_L_04[SIZE_70]; + assert( ftd_L_04->frame_data_length == sizeof( frame_data_L_04 ) ); + memset( frame_data_L_04, 0x07, sizeof( frame_data_L_04 ) ); + uint8_t frame_data_R_04[SIZE_160]; + assert( ftd_R_04->frame_data_length == sizeof( frame_data_R_04 ) ); + memset( frame_data_R_04, 0x08, sizeof( frame_data_R_04 ) ); + memcpy( sender_ftds[0].frame_data, frame_data_L_01, sender_ftds[0].frame_data_length ); + memcpy( sender_ftds[1].frame_data, frame_data_R_01, sender_ftds[1].frame_data_length ); + memcpy( sender_ftds[2].frame_data, frame_data_L_02, sender_ftds[2].frame_data_length ); + memcpy( sender_ftds[3].frame_data, frame_data_R_02, sender_ftds[3].frame_data_length ); + memcpy( sender_ftds[4].frame_data, frame_data_L_03, sender_ftds[4].frame_data_length ); + memcpy( sender_ftds[5].frame_data, frame_data_R_03, sender_ftds[5].frame_data_length ); + memcpy( sender_ftds[6].frame_data, frame_data_L_04, sender_ftds[6].frame_data_length ); + memcpy( sender_ftds[7].frame_data, frame_data_R_04, sender_ftds[7].frame_data_length ); + + uint8_t *receiverBuffer = malloc( packed_buffer_actual_size ); + assert( NULL != receiverBuffer ); + memcpy( receiverBuffer, packed_buffer, packed_buffer_actual_size ); + + LC3PLUS_RTP_PAYLOAD payload_config; + error = LC3PLUS_RTP_payload_deserialize( &payload_config, receiverBuffer, packed_buffer_actual_size ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_deserialize failed\n" ); + } + + assert( payload_config.fdl_request == fdl_req ); + assert( payload_config.frame_duration_us == 5000 ); + assert( payload_config.high_resolution_enabled == 0 ); + assert( payload_config.sampling_rate_hz == 48000 ); + assert( payload_config.num_ftds == 8 ); + assert( payload_config.num_media_times == 4 ); + assert( payload_config.num_channels == 2 ); + for ( int32_t i = 0; i < payload_config.num_ftds; ++i ) + { + assert( payload_config.ftds[i].frame_data_length == sender_ftds[i].frame_data_length ); + assert( payload_config.ftds[i].h == sender_ftds[i].h ); + assert( payload_config.ftds[i].fdi == sender_ftds[i].fdi ); + assert( payload_config.ftds[i].bwr == sender_ftds[i].bwr ); + assert( payload_config.ftds[i].fc == sender_ftds[i].fc ); + assert( payload_config.ftds[i].frame_data_length == sender_ftds[i].frame_data_length ); + assert( payload_config.ftds[i].frame_data != sender_ftds[i].frame_data ); + assert( 0 == memcmp( payload_config.ftds[i].frame_data, sender_ftds[i].frame_data, sender_ftds[i].frame_data_length ) ); + } + + free( receiverBuffer ); + return 0; +} + +static int try_unpack_invalid_values( void ) +{ + LC3PLUS_RTP_FTD sender_ftds[LC3PLUS_MAX_NUM_CODERS]; + int32_t sender_ftds_num = 0; + const LC3PLUS_RTP_FDL fdl_req = LC3PLUS_RTP_FDL_LENGTH_3_MAX; + + LC3PLUS_RTP_FTD *ftd_L_01 = &sender_ftds[0]; + ftd_L_01->fc = LC3PLUS_RTP_FTD_FC_LAST_OVERALL; + ftd_L_01->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_L_01->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_01->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_01->frame_data = NULL; + ftd_L_01->frame_data_length = SIZE_70; + sender_ftds_num++; + + const size_t packed_buffer_capacity = LC3PLUS_MAX_BS_SIZE; + size_t packed_buffer_actual_size; + uint8_t packed_buffer[LC3PLUS_MAX_BS_SIZE]; + memset( packed_buffer, 0, packed_buffer_capacity ); + // prepare bitstream buffer headers & layout + LC3PLUS_RTP_ERR error = LC3PLUS_RTP_payload_serialize( packed_buffer, packed_buffer_capacity, &packed_buffer_actual_size, fdl_req, sender_ftds, sender_ftds_num ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_serialize failed\n" ); + } + + // copy encoded frames into their expected memory locations + uint8_t frame_data_L_01[SIZE_70]; + assert( ftd_L_01->frame_data_length == sizeof( frame_data_L_01 ) ); + memset( frame_data_L_01, 0x01, sizeof( frame_data_L_01 ) ); + + uint8_t *receiverBuffer = malloc( packed_buffer_actual_size ); + assert( NULL != receiverBuffer ); + memcpy( receiverBuffer, packed_buffer, packed_buffer_actual_size ); + + int32_t fdl_req_length; + error = LC3PLUS_RTP_frame_data_length_get_size( &fdl_req_length, fdl_req ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_frame_data_length_get_size error\n" ); + } + for ( int16_t packed_buffer_incorrect_size = 0; packed_buffer_incorrect_size < ( fdl_req_length + 2 + SIZE_70 ); ++packed_buffer_incorrect_size ) + { + LC3PLUS_RTP_PAYLOAD payload_config; + error = LC3PLUS_RTP_payload_deserialize( &payload_config, receiverBuffer, packed_buffer_incorrect_size ); + if ( error == LC3PLUS_RTP_ERR_NO_ERROR ) + { + free( receiverBuffer ); + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_deserialize failed to detect error\n" ); + } + } + + LC3PLUS_RTP_PAYLOAD payload_config; + error = LC3PLUS_RTP_payload_deserialize( &payload_config, receiverBuffer, packed_buffer_actual_size ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + free( receiverBuffer ); + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_deserialize failed\n" ); + } + free( receiverBuffer ); + return 0; +} + +#define LC3PLUS_RTP_TEST_NUM_FTDS_UT 3 +static int pack_and_unpack_different_fdl_sizes( void ) +{ + int32_t iFtdUt; + LC3PLUS_RTP_FDL fdl_requests_ut[LC3PLUS_RTP_TEST_NUM_FTDS_UT]; + fdl_requests_ut[0] = LC3PLUS_RTP_FDL_LENGTH_1_MIN; + fdl_requests_ut[1] = LC3PLUS_RTP_FDL_LENGTH_2_MIN; + fdl_requests_ut[2] = LC3PLUS_RTP_FDL_LENGTH_3_MIN; + + for ( iFtdUt = 0; iFtdUt < LC3PLUS_RTP_TEST_NUM_FTDS_UT; ++iFtdUt ) + { + LC3PLUS_RTP_FTD sender_ftds[LC3PLUS_MAX_NUM_CODERS]; + int32_t sender_ftds_num = 0; + + LC3PLUS_RTP_FTD *ftd_L_01 = &sender_ftds[0]; + ftd_L_01->fc = LC3PLUS_RTP_FTD_FC_LAST_OVERALL; + ftd_L_01->fdi = LC3PLUS_RTP_FTD_FDI_5000_US; + ftd_L_01->bwr = LC3PLUS_RTP_FTD_BWR_FB; + ftd_L_01->h = LC3PLUS_RTP_FTD_H_PRIMARY; + ftd_L_01->frame_data = NULL; + ftd_L_01->frame_data_length = fdl_requests_ut[iFtdUt]; + sender_ftds_num++; + + const size_t packed_buffer_capacity = LC3PLUS_MAX_BS_SIZE; + size_t packed_buffer_actual_size; + uint8_t packed_buffer[LC3PLUS_MAX_BS_SIZE]; + memset( packed_buffer, 0, packed_buffer_capacity ); + // prepare bitstream buffer headers & layout + LC3PLUS_RTP_ERR error = LC3PLUS_RTP_payload_serialize( packed_buffer, packed_buffer_capacity, &packed_buffer_actual_size, fdl_requests_ut[iFtdUt], sender_ftds, sender_ftds_num ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_serialize failed\n" ); + } + + // copy encoded frames into their expected memory locations + uint8_t frame_data_L_01[SIZE_600]; + assert( ftd_L_01->frame_data_length <= sizeof( frame_data_L_01 ) ); + memset( frame_data_L_01, 0x01, ftd_L_01->frame_data_length ); + + uint8_t *receiverBuffer = malloc( packed_buffer_actual_size ); + assert( NULL != receiverBuffer ); + memcpy( receiverBuffer, packed_buffer, packed_buffer_actual_size ); + + LC3PLUS_RTP_PAYLOAD payload_config; + error = LC3PLUS_RTP_payload_deserialize( &payload_config, receiverBuffer, packed_buffer_actual_size ); + if ( error != LC3PLUS_RTP_ERR_NO_ERROR ) + { + free( receiverBuffer ); + return IVAS_ERROR( IVAS_LC3PLUS_LC3plusRtpErrToIvasErr( error ), "LC3PLUS_RTP_payload_deserialize failed\n" ); + } + assert( payload_config.fdl_request == fdl_requests_ut[iFtdUt] ); + assert( payload_config.ftds[0].frame_data_length == fdl_requests_ut[iFtdUt] ); + free( receiverBuffer ); + } + return 0; +} + +static int run_all_payload_tests( void ) +{ + if ( pack_and_unpack_payload_config_2ch_10ms_lc3plus_20ms_ivas() != 0 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); + } + if ( pack_and_unpack_payload_config_2ch_5ms_lc3plus_20ms_ivas() != 0 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); + } + if ( try_unpack_invalid_values() != 0 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); + } + if ( pack_and_unpack_different_fdl_sizes() != 0 ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); + } + return 0; +} +#endif diff --git a/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test_selective_decoding.c b/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test_selective_decoding.c deleted file mode 100644 index 637ef6997b66f9ce40a91114978e6b12718a5970..0000000000000000000000000000000000000000 --- a/scripts/split_rendering/lc3plus/ivas_lc3plus_unit_test_selective_decoding.c +++ /dev/null @@ -1,1966 +0,0 @@ -/****************************************************************************************************** - -(C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, -Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., -Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, -Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other -contributors to this repository. All Rights Reserved. - -This software is protected by copyright law and by international treaties. -The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, -Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., -Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, -Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other -contributors to this repository retain full ownership rights in their respective contributions in -the software. This notice grants no license of any kind, including but not limited to patent -license, nor is any license granted by implication, estoppel or otherwise. - -Contributors are required to enter into the IVAS codec Public Collaboration agreement before making -contributions. - -This software is provided "AS IS", without any express or implied warranties. The software is in the -development stage. It is intended exclusively for experts who have experience with such software and -solely for the purpose of inspection. All implied warranties of non-infringement, merchantability -and fitness for a particular purpose are hereby disclaimed and excluded. - -Any dispute, controversy or claim arising under or in relation to providing this software shall be -submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in -accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and -the United Nations Convention on Contracts on the International Sales of Goods. - -*******************************************************************************************************/ - -#include -#include -#include "isar_lc3plus_enc.h" -#include "isar_lc3plus_common.h" -#include "isar_lc3plus_dec.h" -#include "ivas_error_utils.h" - -#ifdef SPLIT_REND_WITH_HEAD_ROT - -#define MAX_SAMPLES_PER_CHANNEL 960 - -/* included by ivas_lc3plus_unit_test.c */ - -typedef int ( *ScenarioFnPtr )( const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE dec, - uint8_t *bitstream_in, - int32_t bitstream_in_size, - float **pcm_out ); - -static void ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( - int16_t **subframeChannelMatrix ) -{ - for ( int16_t i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) - { - free( subframeChannelMatrix[i] ); - } - - free( subframeChannelMatrix ); - - return; -} - -static int encodeAndDecodeOne6chFrameFixture( LC3PLUS_CONFIG config, const int16_t enableCaching, const int32_t bps, ScenarioFnPtr scenarioFn ) -{ - ivas_error err; - int32_t encDelay = -1; - int32_t decDelay = -1; - - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, bps, &encHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - err = ISAR_LC3PLUS_ENC_GetDelay( encHandle, &encDelay ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - if ( encDelay == -1 || encDelay == 0 ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "encDelay is zero or uninitialized\n" ); - } - - /* encode one frame */ - int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.ivas_frame_duration_us ); - float *pcm_in[6]; - float pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_in_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_in_ch2, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_in_ch3[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_in_ch3, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_in_ch4[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_in_ch4, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_in_ch5[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_in_ch5, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_in_ch6[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_in_ch6, 0, numSamplesPerChannels * sizeof( float ) ); - pcm_in[0] = pcm_in_ch1; - pcm_in[1] = pcm_in_ch2; - pcm_in[2] = pcm_in_ch3; - pcm_in[3] = pcm_in_ch4; - pcm_in[4] = pcm_in_ch5; - pcm_in[5] = pcm_in_ch6; - - int32_t bitstreamSizePerIvasFrame = 0; - err = ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( encHandle, &bitstreamSizePerIvasFrame ); - if ( IVAS_ERR_OK != err ) - return err; - - uint8_t *bitstream_out = malloc( bitstreamSizePerIvasFrame ); - memset( bitstream_out, 0, bitstreamSizePerIvasFrame ); - - err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out ); - if ( IVAS_ERR_OK != err ) - return err; - ISAR_LC3PLUS_ENC_Close( &encHandle ); - - /* decode one frame */ - ISAR_LC3PLUS_DEC_HANDLE decHandle; - err = ISAR_LC3PLUS_DEC_Open( config, -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING - enableCaching, -#endif - &decHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - err = ISAR_LC3PLUS_DEC_GetDelay( decHandle, &decDelay ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - if ( decDelay == -1 || decDelay == 0 ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "decDelay is zero or uninitialized\n" ); - } - - uint8_t *bitstream_in = bitstream_out; - - float *pcm_out[6]; - float pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_out_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_out_ch2, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_out_ch3[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_out_ch3, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_out_ch4[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_out_ch4, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_out_ch5[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_out_ch5, 0, numSamplesPerChannels * sizeof( float ) ); - float pcm_out_ch6[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; - memset( pcm_out_ch6, 0, numSamplesPerChannels * sizeof( float ) ); - pcm_out[0] = pcm_out_ch1; - pcm_out[1] = pcm_out_ch2; - pcm_out[2] = pcm_out_ch3; - pcm_out[3] = pcm_out_ch4; - pcm_out[4] = pcm_out_ch5; - pcm_out[5] = pcm_out_ch6; - - err = ISAR_LC3PLUS_DEC_Conceal( decHandle, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstreamSizePerIvasFrame, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - if ( NULL != scenarioFn ) - { - err = ( *scenarioFn )( config, decHandle, bitstream_in, bitstreamSizePerIvasFrame, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstreamSizePerIvasFrame, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - err = ISAR_LC3PLUS_DEC_Conceal( decHandle, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - ISAR_LC3PLUS_DEC_Close( &decHandle ); - free( bitstream_out ); - - return 0; -} - -/* - * in: [dec, dec, dec, dec] - * expected out: [dec_and_use, dec_and_use, dec_and_use, dec_and_use] - */ -static int scenario_decode_all_subframes( const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - // const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - assert( decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame == 0 ); - if(NULL != decHandle->bitstream_caches) - { - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - } - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct post decoding state */ - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - - -/* - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, cache] - */ -static int scenario_dont_decode_last_2_subframes( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - if(NULL != decHandle->bitstream_caches) - { - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - } - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - -/* - * in: [dec, skip, skip, skip] - * expected out: [dec_and_use, skip, skip, cache] - */ -static int scenario_dont_decode_last_3_subframes( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 3 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last three subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframes before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 3 ) - { - /* subframes before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - - -/* - * in: [skip, dec, dec, dec] - * expected out: [dec_and_drop, dec_and_use, dec_and_use, dec_and_use] - */ -static int scenario_skip_first_subframe( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - if ( iSubframeIdx == 0 ) - { - /* skip the first subframe */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the following subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - - if ( iLc3plusFrame == 0 ) - { - /* first subframe is expected to be decoded and dropped */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_DROP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - -/* - * Step1: - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, cache] - * - * Step2: - * in: [dec, dec, dec, dec] - * expected out: [dec_cache & dec_and_use, dec_and_use, dec_and_use, dec_and_use] - */ -static int scenario_decode_cache( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2, ensure that the cache is used */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - /* decode all */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 1 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - -/* - * Step1: - * in: [skip, skip, dec, dec] - * expected out: [skip, dec_and_drop, dec_and_use, dec_and_use] - * - * Step2: - * in: [dec, dec, dec, dec] - * expected out: [no_cache & dec_and_use, dec_and_use, dec_and_use, dec_and_use] - */ -static int scenario_get_active_dont_cache( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions - * * expected out: [skip, dec_and_drop, dec_and_use, dec_and_use] */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 3 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_DROP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2, ensure that there is no cache */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - /* decode all [dec, dec, dec, dec]*/ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct decoder actions - * expected out: [no_cache & dec_and_use, dec_and_use, dec_and_use, dec_and_use]*/ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - - -/* - * Step1: - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, cache] - * - * Step2: - * in: [skip, dec, skip, dec] - * expected out: [drop_cache & dec_and_drop, dec_and_use, dec_and_drop, dec_and_use] - * */ -static int scenario_per_subframe_switches_skip_first( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2 - * in: [skip, dec, skip, dec] - * */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - if(iSubframeIdx == 0 || iSubframeIdx == 2) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else if(iSubframeIdx == 1 || iSubframeIdx == 3) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - else - { - //unsupported iSubframeIdx count; - return 1; - } - - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions - * expected out: [drop_cache & dec_and_drop, dec_and_use, dec_and_drop, dec_and_use] - * */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == 1 || iLc3plusFrame == 3) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 0 || iLc3plusFrame == 2) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_DROP ); - } - else - { - assert(0); - } - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - -/* - * Step1: - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, cache] - * - * Step2: - * in: [dec, skip, dec, skip] - * expected out: [dec_cache & dec_and_use, dec_and_drop, dec_and_use, cache] - * */ -static int scenario_per_subframe_switches_dec_first( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2 - * in: [dec, skip, dec, skip] - * */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - if(iSubframeIdx == 0 || iSubframeIdx == 2) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - else if(iSubframeIdx == 1 || iSubframeIdx == 3) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - // unsupported iSubframeIdx count - return 1; - } - - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions - * expected out: [dec_cache & dec_and_use, dec_and_drop, dec_and_use, cache] - * */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 1 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == 0 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 1 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_DROP ); - } - else if ( iLc3plusFrame == 2 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 3) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else - { - assert(0); - } - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING -/* - * Step1: - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, skip] - * - * Step2: - * in: [dec, skip, dec, skip] - * expected out: [drop_cache & dec_and_use, skip, dec_and_use, skip] - * */ -static int scenario_per_subframe_switches_dec_first_no_caching( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( NULL == decHandle->bitstream_caches ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( NULL == decHandle->bitstream_caches ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2 - * in: [dec, skip, dec, skip] - * */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - if(iSubframeIdx == 0 || iSubframeIdx == 2) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - else if(iSubframeIdx == 1 || iSubframeIdx == 3) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - // unsupported iSubframeIdx count - return 1; - } - - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions - * expected out: [drop_cache & dec_and_use, skip, dec_and_use, skip] - * */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( NULL == decHandle->bitstream_caches ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == 0 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 1 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else if ( iLc3plusFrame == 2 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 3) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert(0); - } - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( NULL == decHandle->bitstream_caches ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} -#endif - -/* - * Step1: - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, cache] - * - * Step2: - * in: [dec, skip, skip, dec] - * expected out: [dec_cache & dec_and_use, skip, dec_and_drop, dec_and_use] - * */ -static int scenario_per_subframe_bundle_switches_dec_first( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2 - * in: [dec, skip, skip, dec] - * */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - if(iSubframeIdx == 0 || iSubframeIdx == 3) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - else if(iSubframeIdx == 1 || iSubframeIdx == 2) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - // unsupported iSubframeIdx count - return 1; - } - - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions - * expected out: [dec_cache & dec_and_use, skip, dec_and_drop, dec_and_use] - * */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 1 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == 0 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 1 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else if ( iLc3plusFrame == 2 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_DROP ); - } - else if ( iLc3plusFrame == 3) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else - { - assert(0); - } - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - -/* - * Step1: - * in: [dec, dec, skip, skip] - * expected out: [dec_and_use, dec_and_use, skip, cache] - * - * Step2: - * in: [skip, dec, dec, skip] - * expected out: [drop_cache & dec_and_drop, dec_and_use, dec_and_use, cache] - * */ -static int scenario_per_subframe_bundle_switches_skip_first( - const LC3PLUS_CONFIG config, - ISAR_LC3PLUS_DEC_HANDLE decHandle, /* i: decoder handle */ - uint8_t *bitstream_in, /* i: pointer to input bitstream */ - int32_t bitstream_in_size, /* i: size of bitstream_in */ - float **pcm_out /* o: decoded samples */ ) -{ - ivas_error err; - const int16_t decode = 1; - const int16_t skipDecoding = 0; - uint32_t iDec = 0; - int iLc3plusFrame = 0; - int lc3framesPerIvasFrame; - int16_t **selective_decoding_matrix; - err = ISAR_LC3PLUS_DEC_AllocateSubframeDecodingMatrix( &selective_decoding_matrix, config.channels ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* Set selective decoding scenario */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - assert( MAX_PARAM_SPATIAL_SUBFRAMES == 4 ); - if ( iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 1 || iSubframeIdx == MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) /*only valid for MAX_PARAM_SPATIAL_SUBFRAMES == 4 */ - { - /* skip the last two subframes */ - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - /* decode the previous ones */ - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - } - } - - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 0 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 == decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == lc3framesPerIvasFrame - 1 ) - { - /* last subframe is expected to be cached */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else if ( iLc3plusFrame == lc3framesPerIvasFrame - 2 ) - { - /* subframe before the last one is expected to be skipped, since only the last one is required to flush the decoder after a pause */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_SKIP ); - } - else - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - } - - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder caching */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - /* Step 2 - * in: [skip, dec, dec, skip] - * */ - for ( int16_t iSubframeIdx = 0; iSubframeIdx < MAX_PARAM_SPATIAL_SUBFRAMES; iSubframeIdx++ ) - { - for ( int16_t decIdx = 0; decIdx < config.channels; decIdx++ ) - { - if(iSubframeIdx == 1 || iSubframeIdx == 2) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = decode; - } - else if(iSubframeIdx == 0 || iSubframeIdx == 3) - { - selective_decoding_matrix[iSubframeIdx][decIdx] = skipDecoding; - } - else - { - // unsupported iSubframeIdx count - return 1; - } - - } - } - /* Apply selective decoding scenario */ - err = ISAR_LC3PLUS_DEC_SetSelectiveDecodingMatrix( decHandle, selective_decoding_matrix ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* verify correct decoder actions - * expected out: [drop_cache & dec_and_drop, dec_and_use, dec_and_use, cache] - * */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - if ( iLc3plusFrame == 0 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_DROP ); - } - else if ( iLc3plusFrame == 1 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 2 ) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - else if ( iLc3plusFrame == 3) - { - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_CACHE ); - } - else - { - assert(0); - } - } - } - err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstream_in_size, pcm_out ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - /* verify correct post-decoding state */ - lc3framesPerIvasFrame = decHandle->config.ivas_frame_duration_us / decHandle->config.lc3plus_frame_duration_us; - for ( iDec = 0; iDec < decHandle->num_decs; iDec++ ) - { - assert( 1 == decHandle->selective_decoding_states[iDec]->has_skipped_a_frame ); - assert( 0 == decHandle->selective_decoding_states[iDec]->shall_decode_cached_frame ); - assert( 0 != decHandle->bitstream_caches[iDec]->bitstream_cache_size ); - for ( iLc3plusFrame = 0; iLc3plusFrame < lc3framesPerIvasFrame; iLc3plusFrame++ ) - { - /* default action after decoding should be DEC_ACTION_DECODE_AND_USE again */ - assert( decHandle->selective_decoding_states[iDec]->frame_actions[iLc3plusFrame] == DEC_ACTION_DECODE_AND_USE ); - } - } - - ISAR_LC3PLUS_DEC_FreeSubframeDecodingMatrix( selective_decoding_matrix ); - return IVAS_ERR_OK; -} - - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_decode_all_subframes( void ) -{ - int err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_decode_all_subframes ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_dont_decode_last_2_subframes( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_dont_decode_last_2_subframes ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_dont_decode_last_3_subframes( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_dont_decode_last_3_subframes ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_skip_first_subframe( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_skip_first_subframe ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_decode_cache( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_decode_cache ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_switches_skip_first( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_per_subframe_switches_skip_first ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_switches_dec_first( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_per_subframe_switches_dec_first ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_bundle_switches_dec_first( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_per_subframe_bundle_switches_dec_first ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_bundle_switches_skip_first( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_per_subframe_bundle_switches_skip_first ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} - -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_per_subframe_switches_dec_first_no_caching( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 0; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_per_subframe_switches_dec_first_no_caching ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} -#endif - -static int selectiveDecIvas20msLc3plus5ms_48kHz_scenario_get_active_dont_cache( void ) -{ - int err = 0; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .ivas_frame_duration_us = 20 * 1000, .channels = 6, .samplerate = 48000 }; - const int16_t enableCaching = 1; - err = encodeAndDecodeOne6chFrameFixture( config, enableCaching, 768000, &scenario_get_active_dont_cache ); - if ( 0 != err ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "test failed\n" ); - } - return err; -} -#endif /* SPLIT_REND_WITH_HEAD_ROT */ diff --git a/tests/codec_be_on_mr_nonselection/test_param_file.py b/tests/codec_be_on_mr_nonselection/test_param_file.py index 12e9208da89f6d57edf4e4cc486ffcdadea4ae5b..137000976fd2fc3e5533231f58f26cb7fc2e00ca 100644 --- a/tests/codec_be_on_mr_nonselection/test_param_file.py +++ b/tests/codec_be_on_mr_nonselection/test_param_file.py @@ -352,7 +352,12 @@ def test_param_file_tests( max_diff =0 if output_differs: search_result = re.search(MAX_DIFF_PATTERN, reason) - max_diff = search_result.groups(1)[0] + if search_result: + max_diff = search_result.groups(1)[0] + else: + msg = "Error " + MAX_DIFF_PATTERN + " not found" + print(msg) + pytest.fail(msg) record_property("MAXIMUM ABS DIFF", max_diff) metadata_differs = False diff --git a/tests/split_rendering/constants.py b/tests/split_rendering/constants.py index 2c2530d3c61acc7a9339c9af476ac51ffe28a034..11c76e3d62db933effdf30eea2c852e42c98971e 100644 --- a/tests/split_rendering/constants.py +++ b/tests/split_rendering/constants.py @@ -44,6 +44,7 @@ from tests.renderer.constants import ( """ Set up paths """ TESTS_DIR = Path(__file__).parent RENDER_CFG_DIR = TESTS_DIR.joinpath("renderer_configs").resolve() +RENDER_FRAMING_CFG_DIR = TESTS_DIR.joinpath("renderer_configs").joinpath("framing").resolve() ERROR_PATTERNS_DIR = TESTS_DIR.joinpath("error_patterns").resolve() OUTPUT_PATH_REF = TESTS_DIR.joinpath("ref") @@ -69,6 +70,10 @@ RENDERER_CONFIGS_FASTCONV_RENDERER = [ str(cfg.stem) for cfg in RENDER_CFG_DIR.glob("*_fastconv.txt") ] +RENDERER_CONFIGS_FRAMING = [ + str(cfg.stem) for cfg in RENDER_FRAMING_CFG_DIR.glob("framing*.txt") +] + RENDERER_CONFIGS_TO_TEST_AMBI = ( RENDERER_CONFIGS_DEFAULT_CODEC + RENDERER_CONFIGS_LC3PLUS_CODEC ) @@ -159,6 +164,8 @@ IVAS_MAX_ISM_BITRATE = { } RENDERER_FORMATS = ["BINAURAL_SPLIT_CODED", "BINAURAL_SPLIT_PCM"] +SPLIT_RENDERER_PRE_FRAMINGS = ["5", "10", "20"] +SPLIT_RENDERER_POST_FRAMINGS = ["5", "10", "20"] INPUT_DURATION_SEC = 5 @@ -181,10 +188,12 @@ SPLIT_PRE_DEC_CMD = [ "", # 2 -> pre-trajectory file "-render_config", "", # 4 -> render config file - "", # 5 -> renderer format + "-fr", + "", # 6 -> pre_rend_fs + "", # 7 -> renderer format "48", - "", # 7 -> encoder bitstream - "", # 8 -> split rendering bitstream + "", # 9 -> encoder bitstream + "", # 10 -> split rendering bitstream ] """ Split-pre Renderer commandline template """ @@ -204,6 +213,8 @@ SPLIT_PRE_REND_CMD = [ "", # 12 -> renderer format "-T", "", # 14 -> post-trajectory file + "-fr", + "", # 16 -> pre rend framing ] """ Split-post Renderer commandline template """ @@ -219,4 +230,6 @@ SPLIT_POST_REND_CMD = [ "", # 8 -> output file "-T", "", # 10 -> post-trajectory file + "-fr", + "", # 12 -> frame size ] diff --git a/tests/split_rendering/renderer_configs/framing/framing_lc3plus_0dof_10ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_0dof_10ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b2aaca70ee8feed8c2f6932d2d05ddef719ff94 --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_0dof_10ms.txt @@ -0,0 +1,6 @@ +[SPLITREND] +BITRATE = 256000; +DOF = 0; +HQMODE = 0; +FRAMESIZE = 10; +CODEC = LC3PLUS; diff --git a/tests/split_rendering/renderer_configs/framing/framing_lc3plus_0dof_5ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_0dof_5ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..1a9ea0b076213f675b86d3dee36e493b24b6f3eb --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_0dof_5ms.txt @@ -0,0 +1,6 @@ +[SPLITREND] +BITRATE = 256000; +DOF = 0; +HQMODE = 0; +FRAMESIZE = 5; +CODEC = LC3PLUS; diff --git a/tests/split_rendering/renderer_configs/framing/framing_lc3plus_1dof_10ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_1dof_10ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..568e62039665bc9231088f9a6d41ff704c917665 --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_1dof_10ms.txt @@ -0,0 +1,7 @@ +[SPLITREND] +BITRATE = 384000; +DOF = 1; +HQMODE = 0; +FRAMESIZE = 10; +CODEC = LC3PLUS; + diff --git a/tests/split_rendering/renderer_configs/framing/framing_lc3plus_1dof_5ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_1dof_5ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbbfa32168e96abc32ef0493cb3b667de73b283f --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lc3plus_1dof_5ms.txt @@ -0,0 +1,7 @@ +[SPLITREND] +BITRATE = 384000; +DOF = 1; +HQMODE = 0; +FRAMESIZE = 5; +CODEC = LC3PLUS; + diff --git a/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_10ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_10ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c8a639d15a819c94648f88286f8fc96f4a60e34 --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_10ms.txt @@ -0,0 +1,7 @@ +[SPLITREND] +BITRATE = 256000; +DOF = 0; +HQMODE = 0; +FRAMESIZE = 10; +CODEC = LCLD; + diff --git a/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_20ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_20ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..9aff176960b60d662cd560da6b9bfc134ac7e06f --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_20ms.txt @@ -0,0 +1,7 @@ +[SPLITREND] +BITRATE = 256000; +DOF = 0; +HQMODE = 0; +FRAMESIZE = 20; +CODEC = LCLD; + diff --git a/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_5ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_5ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..23ffd6a05e593da0516164a2af03a7c0f6f6fa9f --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lcld_0dof_5ms.txt @@ -0,0 +1,7 @@ +[SPLITREND] +BITRATE = 256000; +DOF = 0; +HQMODE = 0; +FRAMESIZE = 5; +CODEC = LCLD; + diff --git a/tests/split_rendering/renderer_configs/framing/framing_lcld_1dof_20ms.txt b/tests/split_rendering/renderer_configs/framing/framing_lcld_1dof_20ms.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8b5856edfc04ad081de5860d04cf42a041c37dc --- /dev/null +++ b/tests/split_rendering/renderer_configs/framing/framing_lcld_1dof_20ms.txt @@ -0,0 +1,7 @@ +[SPLITREND] +BITRATE = 384000; +DOF = 1; +HQMODE = 0; +FRAMESIZE = 20; +CODEC = LCLD; + diff --git a/tests/split_rendering/test_split_rendering.py b/tests/split_rendering/test_split_rendering.py index 96fcdf2d5b9328972efff249a3398b4e4bb70abb..b5886e478fdca4d5ef3647b231f1484d2bc93efe 100644 --- a/tests/split_rendering/test_split_rendering.py +++ b/tests/split_rendering/test_split_rendering.py @@ -35,37 +35,6 @@ import pytest from tests.split_rendering.utils import * -def check_xfail(test_info, in_fmt, render_config, bitrate=None): - if ( - "768k" in render_config - and "0dof" in render_config - and ( - "lc3plus" in render_config - or ( - in_fmt in INPUT_FORMATS_ISM_SPLIT_REND - or in_fmt in INPUT_FORMATS_MC_SPLIT_REND - ) - or ( - "external_split" in test_info.node.name - and in_fmt in INPUT_FORMATS_AMBI_SPLIT_REND - ) # CREND for external renderer ambisonics rendering uses LC3plus by default - ) - ): - pytest.xfail("0DOF 768kbps LC3plus codec is unsupported") - - if ( - "256k" in render_config or "320k" in render_config - ) and "0dof" not in render_config: - pytest.xfail("320kbps and lower are only supported with 0DOF") - - if ( - bitrate - and (in_fmt in INPUT_FORMATS_ISM_SPLIT_REND) - and (int(bitrate) > int(IVAS_MAX_ISM_BITRATE[in_fmt[-1]])) - ): - pytest.skip(f"Unsupported configuration with {in_fmt} at {bitrate}bps") - - """ Ambisonics """ @@ -76,8 +45,6 @@ def check_xfail(test_info, in_fmt, render_config, bitrate=None): def test_ambisonics_full_chain_split( test_info, in_fmt, bitrate, render_config, trajectory ): - check_xfail(test_info, in_fmt, render_config, bitrate) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -95,8 +62,6 @@ def test_ambisonics_full_chain_split( @pytest.mark.parametrize("render_config", RENDERER_CONFIGS_TO_TEST_AMBI) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_AMBI_SPLIT_REND) def test_ambisonics_external_split(test_info, in_fmt, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -119,8 +84,6 @@ def test_ambisonics_external_split(test_info, in_fmt, render_config, trajectory) def test_multichannel_full_chain_split( test_info, in_fmt, bitrate, render_config, trajectory ): - check_xfail(test_info, in_fmt, render_config, bitrate) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -138,8 +101,6 @@ def test_multichannel_full_chain_split( @pytest.mark.parametrize("render_config", RENDERER_CONFIGS_TO_TEST_MC) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MC_SPLIT_REND) def test_multichannel_external_split(test_info, in_fmt, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -160,8 +121,6 @@ def test_multichannel_external_split(test_info, in_fmt, render_config, trajector @pytest.mark.parametrize("bitrate", IVAS_BITRATES_ISM) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_ISM_SPLIT_REND) def test_ism_full_chain_split(test_info, in_fmt, bitrate, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config, bitrate) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -179,8 +138,6 @@ def test_ism_full_chain_split(test_info, in_fmt, bitrate, render_config, traject @pytest.mark.parametrize("render_config", RENDERER_CONFIGS_TO_TEST_ISM) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_ISM_SPLIT_REND) def test_ism_external_split(test_info, in_fmt, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -201,8 +158,6 @@ def test_ism_external_split(test_info, in_fmt, render_config, trajectory): @pytest.mark.parametrize("bitrate", IVAS_BITRATES_MASA) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MASA_SPLIT_REND) def test_masa_full_chain_split(test_info, in_fmt, bitrate, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config, bitrate) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -220,8 +175,6 @@ def test_masa_full_chain_split(test_info, in_fmt, bitrate, render_config, trajec @pytest.mark.parametrize("render_config", RENDERER_CONFIGS_TO_TEST_MASA) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MASA_SPLIT_REND) def test_masa_external_split(test_info, in_fmt, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -242,8 +195,6 @@ def test_masa_external_split(test_info, in_fmt, render_config, trajectory): @pytest.mark.parametrize("bitrate", IVAS_BITRATES_OMASA) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_OMASA_SPLIT_REND) def test_omasa_full_chain_split(test_info, in_fmt, bitrate, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config, bitrate) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -265,8 +216,6 @@ def test_omasa_full_chain_split(test_info, in_fmt, bitrate, render_config, traje @pytest.mark.parametrize("bitrate", IVAS_BITRATES_OSBA) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_OSBA_SPLIT_REND) def test_osba_full_chain_split(test_info, in_fmt, bitrate, render_config, trajectory): - check_xfail(test_info, in_fmt, render_config, bitrate) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -288,8 +237,6 @@ def test_osba_full_chain_split(test_info, in_fmt, bitrate, render_config, trajec @pytest.mark.parametrize("render_config", RENDERER_CONFIGS_TO_TEST_PLC) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_AMBI_SPLIT_REND[-1:]) def test_post_rend_plc(test_info, in_fmt, render_config, trajectory, error_pattern): - check_xfail(test_info, in_fmt, render_config) - post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -317,8 +264,6 @@ full_chain_split_pcm_params = [ @pytest.mark.parametrize("in_fmt,bitrate,render_config", full_chain_split_pcm_params) def test_full_chain_split_pcm(test_info, in_fmt, bitrate, render_config): - check_xfail(test_info, in_fmt, render_config, bitrate) - trajectory = SPLIT_REND_HR_TRAJECTORIES_TO_TEST[0] post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -343,8 +288,6 @@ external_split_pcm_params = [ @pytest.mark.parametrize("in_fmt,render_config", external_split_pcm_params) def test_external_split_pcm(test_info, in_fmt, render_config): - check_xfail(test_info, in_fmt, render_config) - trajectory = SPLIT_REND_HR_TRAJECTORIES_TO_TEST[0] post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") @@ -357,3 +300,43 @@ def test_external_split_pcm(test_info, in_fmt, render_config): post_trajectory=post_trajectory, renderer_fmt="BINAURAL_SPLIT_PCM", ) + +@pytest.mark.parametrize("trajectory", SPLIT_REND_HR_TRAJECTORIES_TO_TEST) +@pytest.mark.parametrize("render_config", RENDERER_CONFIGS_FRAMING) +@pytest.mark.parametrize("in_fmt", ["5_1"]) +@pytest.mark.parametrize("pre_rend_fr", SPLIT_RENDERER_PRE_FRAMINGS) +@pytest.mark.parametrize("post_rend_fr", SPLIT_RENDERER_POST_FRAMINGS) +def test_framing_combinations_external_split(test_info, in_fmt, render_config, trajectory, post_rend_fr, pre_rend_fr): + post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") + pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") + + run_external_split_rendering( + test_info, + in_fmt=in_fmt, + render_config=RENDER_FRAMING_CFG_DIR.joinpath(f"{render_config}.txt"), + pre_trajectory=pre_trajectory, + post_trajectory=post_trajectory, + post_rend_fr=post_rend_fr, + pre_rend_fr=pre_rend_fr, + ) +@pytest.mark.parametrize("trajectory", SPLIT_REND_HR_TRAJECTORIES_TO_TEST) +@pytest.mark.parametrize("render_config", RENDERER_CONFIGS_FRAMING) +@pytest.mark.parametrize("in_fmt", ["5_1"]) +@pytest.mark.parametrize("pre_rend_fr", SPLIT_RENDERER_PRE_FRAMINGS) +@pytest.mark.parametrize("post_rend_fr", SPLIT_RENDERER_POST_FRAMINGS) +def test_framing_combinations_full_chain_split( + test_info, in_fmt, render_config, trajectory, post_rend_fr, pre_rend_fr +): + post_trajectory = HR_TRAJECTORY_DIR.joinpath(f"{trajectory}.csv") + pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") + + run_full_chain_split_rendering( + test_info, + in_fmt=in_fmt, + render_config=RENDER_FRAMING_CFG_DIR.joinpath(f"{render_config}.txt"), + pre_trajectory=pre_trajectory, + bitrate="256000", + post_trajectory=post_trajectory, + post_rend_fr=post_rend_fr, + pre_rend_fr=pre_rend_fr, + ) diff --git a/tests/split_rendering/utils.py b/tests/split_rendering/utils.py index 9c7f290c4d346c29f12f86a7920263f8fbac92fc..270746b0d5f55c47c4f8c5dd178f17b6c583f34d 100644 --- a/tests/split_rendering/utils.py +++ b/tests/split_rendering/utils.py @@ -31,6 +31,7 @@ """ import sys +import re from pathlib import Path from tempfile import TemporaryDirectory from typing import Tuple @@ -45,6 +46,90 @@ sys.path.append(SCRIPTS_DIR) from pyaudio3dtools.audiofile import readfile, writefile +def lc3plus_used(test_info, in_fmt, render_config): + return ( + # LC3plus used explicitly + "lc3plus" in render_config + # or default codec resolving to LC3plus in decoder + or ( + "default" in render_config + and "full_chain" in test_info.node.name + and in_fmt in [*INPUT_FORMATS_ISM_SPLIT_REND, *INPUT_FORMATS_MC_SPLIT_REND] + ) + # or default codec resolving to LC3plus in IVAS_rend + or ("default" in render_config and "external_split" in test_info.node.name) + ) + +FRAME_SIZE_RE = re.compile(r"(\d+)ms") + +def transport_codec_frame_size_ms(test_info, in_fmt, render_config, pre_rend_fr): + explicit_frame_size_ms = FRAME_SIZE_RE.search(render_config) + + # If explicit frame size set in config file, return that + if explicit_frame_size_ms: + return int(explicit_frame_size_ms[1]) + + # Otherwise infer default ISAR frame size. + if lc3plus_used(test_info, in_fmt, render_config): + # LC3plus always uses 5 ms + return 5 + + # LCLD adjusts to prerenderer frame size + return int(pre_rend_fr) + + +def check_xfail( + test_info, in_fmt, render_config, pre_rend_fr, post_rend_fr, ivas_bitrate=None +): + pre_rend_fr = int(pre_rend_fr) + post_rend_fr = int(post_rend_fr) + + lc3plus_in_use = lc3plus_used(test_info, in_fmt, render_config) + + if ( + "256k" in render_config or "320k" in render_config + ) and "0dof" not in render_config: + pytest.xfail("320kbps and lower are only supported with 0DOF") + + if ( + ivas_bitrate + and (in_fmt in INPUT_FORMATS_ISM_SPLIT_REND) + and (int(ivas_bitrate) > int(IVAS_MAX_ISM_BITRATE[in_fmt[-1]])) + ): + pytest.skip( + f"Unsupported configuration with {in_fmt} at IVAS bitrate {ivas_bitrate}bps" + ) + + if not "0dof" in render_config and pre_rend_fr != 20: + pytest.xfail("pose correction (== !0dof) is expected to use 20ms") + + if ( + "1dof" in render_config or "2dof" in render_config or "3dof" in render_config + ) and pre_rend_fr != 20: + pytest.xfail( + "unsupported framing: for 1+dof pre_rend_fr framing shall always be 20ms" + ) + + if pre_rend_fr < post_rend_fr: + pytest.xfail( + # This would require decoding multiple ISAR frames for one post renderer output frame, which is not supported. + "unsupported framing: Post-renderer frame size must be equal or smaller than ISAR codec frame size" + ) + + transport_codec_frame_size = transport_codec_frame_size_ms( + test_info, in_fmt, render_config, pre_rend_fr + ) + if pre_rend_fr < transport_codec_frame_size: + pytest.xfail( + "unsupported framing: ISAR codec frame must fit in one output frame" + ) + + if not lc3plus_in_use and transport_codec_frame_size != pre_rend_fr: + pytest.xfail( + "unsupported framing: LCLD codec doesn't support aggregation. Pre-renderer (ISAR) frame size must match LCLD frame size." + ) + + def truncate_signal( in_file: Path, out_file: Path, @@ -74,11 +159,16 @@ def run_full_chain_split_rendering( post_trajectory: Path, renderer_fmt: str = "BINAURAL_SPLIT_CODED", binary_suffix: str = "", + post_rend_fr: str = "20", + pre_rend_fr: str = "20", ) -> str: """ Runs the full split rendering chain consisting of the IVAS encoder, decoder and split renderer """ + + check_xfail(test_info, in_fmt, render_config.name, pre_rend_fr, post_rend_fr, bitrate) + with TemporaryDirectory() as tmp_dir: tmp_dir = Path(tmp_dir) cut_in_file = tmp_dir.joinpath("cut_input.wav") @@ -86,7 +176,7 @@ def run_full_chain_split_rendering( split_bitstream = tmp_dir.joinpath("split.bit") if renderer_fmt == "BINAURAL_SPLIT_PCM": split_md_file = tmp_dir.joinpath("split_md.bin") - out_file_stem = f"{in_fmt}_{bitrate}bps_{renderer_fmt}_{pre_trajectory.stem}_split_full_{post_trajectory.stem}_config_{render_config.stem}.wav" + out_file_stem = f"{in_fmt}_{bitrate}bps_{renderer_fmt}_{pre_trajectory.stem}_split_full_{post_trajectory.stem}_config_{render_config.stem}_prerfr_{pre_rend_fr}_postrfr_{post_rend_fr}_.wav" if test_info.config.option.create_ref: output_path_base = OUTPUT_PATH_REF @@ -136,9 +226,10 @@ def run_full_chain_split_rendering( cmd[0] += binary_suffix cmd[2] = str(pre_trajectory) cmd[4] = str(render_config) - cmd[5] = renderer_fmt - cmd[7] = str(ivas_bitstream) - cmd[8] = str(split_bitstream) + cmd[6] = str(pre_rend_fr) + cmd[7] = renderer_fmt + cmd[9] = str(ivas_bitstream) + cmd[10] = str(split_bitstream) if renderer_fmt == "BINAURAL_SPLIT_PCM": cmd[5:5] = ["-om", str(split_md_file)] @@ -155,6 +246,7 @@ def run_full_chain_split_rendering( cmd[6] = renderer_fmt cmd[8] = str(out_file) cmd[10] = str(post_trajectory) + cmd[12] = post_rend_fr if renderer_fmt == "BINAURAL_SPLIT_PCM": cmd[7:7] = ["-im", str(split_md_file)] @@ -189,19 +281,23 @@ def run_external_split_rendering( renderer_fmt: str = "BINAURAL_SPLIT_CODED", binary_suffix: str = "", is_comparetest: bool = False, + post_rend_fr: str = "20", + pre_rend_fr: str = "20", ) -> Tuple[np.ndarray, int]: """ Runs the exeternal split rendering chain consisting of the IVAS renderer in split-pre and split-post rendering mode """ + check_xfail(test_info, in_fmt, render_config.name, pre_rend_fr, post_rend_fr) + with TemporaryDirectory() as tmp_dir: tmp_dir = Path(tmp_dir) cut_in_file = tmp_dir.joinpath("cut_input.wav") split_bitstream = tmp_dir.joinpath("split.bit") if renderer_fmt == "BINAURAL_SPLIT_PCM": split_md_file = tmp_dir.joinpath("split_md.bin") - out_file_stem = f"{in_fmt}_{renderer_fmt}_{pre_trajectory.stem}_split_ext_{post_trajectory.stem}_config_{render_config.stem}.wav" + out_file_stem = f"{in_fmt}_{renderer_fmt}_{pre_trajectory.stem}_split_ext_{post_trajectory.stem}_config_{render_config.stem}_postrfr_{pre_rend_fr}_prerfr_{post_rend_fr}.wav" if test_info.config.option.create_ref: output_path_base = OUTPUT_PATH_REF @@ -239,6 +335,7 @@ def run_external_split_rendering( cmd[10] = str(split_bitstream) cmd[12] = renderer_fmt cmd[14] = str(pre_trajectory) + cmd[16] = pre_rend_fr if renderer_fmt == "BINAURAL_SPLIT_PCM": cmd[13:13] = ["-om", str(split_md_file)] @@ -258,6 +355,7 @@ def run_external_split_rendering( cmd[6] = renderer_fmt cmd[8] = str(out_file) cmd[10] = str(post_trajectory) + cmd[12] = post_rend_fr if renderer_fmt == "BINAURAL_SPLIT_PCM": cmd[7:7] = ["-im", str(split_md_file)]