diff --git a/apps/decoder.c b/apps/decoder.c index dd9885e7cb26a23caae4e5c174cd961cda9d4468..57e8ac75c78a657a2655b9e4b0c320571a028503 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3897,9 +3897,17 @@ static ivas_error decodeVoIP( } else if ( decodedGoodFrame ) { +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + srInfo.bitrateKbps = splitRendBits->bits_written * 1000 / splitRendBits->isar_frame_size_ms; +#else srInfo.bitrateKbps = splitRendBits->bits_written * 1000 / splitRendBits->codec_frame_size_ms; +#endif srInfo.codec = ( splitRendBits->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) ? IVAS_SR_TRANSPORT_LC3PLUS : IVAS_SR_TRANSPORT_LCLD; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + srInfo.codecFrameSizeMs = (uint32_t) splitRendBits->isar_frame_size_ms; +#else srInfo.codecFrameSizeMs = (uint32_t) splitRendBits->codec_frame_size_ms; +#endif if ( ( error = IVAS_RTP_WriteNextFrame( &srRtp, splitRendBits->bits_buf, &srInfo, (int16_t) splitRendBits->bits_written, false, false ) ) != IVAS_ERR_OK ) { diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index c3790facbc5ed9d918ff09698f0fa115c595987f..c85f190cfe925697af72063e93231cf07ce58dee 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -812,6 +812,13 @@ static ivas_error parseSRParamsFile( *codec = ( srInfo.codec == IVAS_SR_TRANSPORT_LCLD ) ? ISAR_SPLIT_REND_CODEC_LCLD : ISAR_SPLIT_REND_CODEC_LC3PLUS; *codec_frame_size_ms = (int16_t) srInfo.codecFrameSizeMs; *isar_frame_size_ms = *codec_frame_size_ms; /* for rtp force codec framesize as isar renderer frame size */ +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + if ( *codec == ISAR_SPLIT_REND_CODEC_LC3PLUS && *isar_frame_size_ms == 20 ) + { + /* For LC3plus, the codec frame size is limited to max 10 ms */ + *codec_frame_size_ms = 10; + } +#endif break; } } @@ -1194,7 +1201,11 @@ int main( bitsBuffer.config.bitsRead = 0; bitsBuffer.config.bitsWritten = 0; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + while ( frameMS < (int16_t) ( args.render_num_subframes * 5 ) ) +#else while ( frameMS < bitsBuffer.config.isar_frame_size_ms ) +#endif { error = IVAS_RTP_ReadNextFrame( &srRTP, bitBuffer, &auSizeBits, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &srInfo, &qBit ); if ( error != IVAS_ERR_OK ) @@ -1220,7 +1231,11 @@ int main( bitBuffer += ( auSizeBits + 7 ) / 8; bitsBuffer.config.bitsWritten += auSizeBits; bitsBuffer.config.codec = srInfo.codec == IVAS_SR_TRANSPORT_LC3PLUS ? ISAR_SPLIT_REND_CODEC_LC3PLUS : ISAR_SPLIT_REND_CODEC_LCLD; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + frameMS += bitsBuffer.config.isar_frame_size_ms; +#else frameMS += bitsBuffer.config.codec_frame_size_ms; +#endif } } else if ( ( hSplitRendFileReadWrite != NULL ) && splitBinNeedsNewFrame ) diff --git a/lib_com/options.h b/lib_com/options.h index 6abf37fd8a0e654ae7a37abad7ad22e2c7558d9c..aa927db0ecb8390072177d4e316175e47524d745 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -165,6 +165,7 @@ #define FIX_FLOAT_1560_SVD_NO_OPT_MAX_W_SIGN /* FhG: float issue 1560: Avoid optimizing the division on the result of maxWithSign() with -funsafe-math-optimizations */ #define FIX_2095_REMOVE_UNUSED_ISAR_TABLES /* Dolby: remove unused ISAR */ #define FIX_FLOAT_1582_STEREO_DFT_QUANTIZE_ITD /* FhG: float issue 1582: Remove unncessary statement from stereo_dft_quantize_itd() */ +#define FIX_1515_ISAR_FRAME_SIZES_IN_RTP /* FhG: Fix ISAR frame sizes in RTP. This includes reconfiguration of the LC3plus decoder */ /* #################### End BE switches ################################## */ diff --git a/lib_isar/isar_lc3plus_dec.c b/lib_isar/isar_lc3plus_dec.c index de4515aa0edbe15841f52ff961522739e853ac47..fa5ad3b0590adedcd88fae92b3d44fa15da8a61c 100644 --- a/lib_isar/isar_lc3plus_dec.c +++ b/lib_isar/isar_lc3plus_dec.c @@ -30,6 +30,7 @@ *******************************************************************************************************/ +#include #include #include "options.h" #include "prot.h" @@ -41,6 +42,205 @@ #include "wmc_auto.h" +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP /* "open" and "close" were refactored (mostly copy-paste) into separate steps of (de)allocate handle and (de)init handle */ +static ivas_error isar_lc3plus_dec_init_handle( + const LC3PLUS_CONFIG config, /* i : LC3plus decoder configuration */ + ISAR_LC3PLUS_DEC_HANDLE *handle /* o : decoder handle */ +) +{ + LC3PLUS_Error err; + int32_t decoder_size; + int16_t i; + + if ( 0 == config.lc3plus_frame_duration_us ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid lc3plus_frame_duration_us (0)\n" ); + } + + if ( config.channels > ISAR_LC3PLUS_MAX_NUM_DECODERS ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INIT_ERROR, "Maximum number of channels exceeds ISAR_LC3PLUS_MAX_NUM_DECODERS\n" ); + } + + ( *handle )->num_decs = 0; + ( *handle )->pcm_conversion_buffer = NULL; + ( *handle )->handles = NULL; + ( *handle )->selective_decoding_states = NULL; + ( *handle )->bitstream_caches = NULL; + + if ( ( ( *handle )->handles = malloc( config.channels * sizeof( ISAR_LC3PLUS_DEC_HANDLE ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + + if ( ( ( *handle )->selective_decoding_states = malloc( config.channels * sizeof( ISAR_LC3PLUS_DEC_SELECTIVE_DECODING_STATE * ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + + for ( i = 0; i < config.channels; ++i ) + { + ( *handle )->handles[i] = NULL; + ( *handle )->selective_decoding_states[i] = NULL; + } + + if ( ( ( *handle )->bitstream_caches = malloc( config.channels * sizeof( ISAR_LC3PLUS_DEC_BITSTREAM_CACHE * ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + for ( i = 0; i < config.channels; ++i ) + { + ( *handle )->bitstream_caches[i] = NULL; + } + + ( *handle )->num_decs = config.channels; + for ( int32_t iCh = 0; iCh < config.channels; iCh++ ) + { + ( *handle )->selective_decoding_states[iCh] = NULL; + if ( NULL != ( *handle )->bitstream_caches ) + { + ( *handle )->bitstream_caches[iCh] = NULL; + } + /* allocate and configure LC3plus decoder */ + decoder_size = lc3plus_dec_get_size( config.samplerate, 1 ); + if ( 0 == decoder_size ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "lc3plus_dec_get_size failed\n" ); + } + + if ( ( ( *handle )->handles[iCh] = malloc( decoder_size ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + + err = lc3plus_dec_init( ( *handle )->handles[iCh], config.samplerate, 1, LC3PLUS_PLC_ADVANCED, config.high_res_mode_enabled ); + + if ( LC3PLUS_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_dec_init failed\n" ); + } + + err = lc3plus_dec_set_frame_dms( ( *handle )->handles[iCh], IVAS_LC3PLUS_UsToLC3plusFrameDuration( config.lc3plus_frame_duration_us ) ); + if ( LC3PLUS_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( ISAR_LC3PLUS_LC3plusErrToIvasErr( err ), "lc3plus_dec_set_frame_dms failed\n" ); + } + + /* allocate and configure per LC3plus decoder skip state */ + if ( ( ( *handle )->selective_decoding_states[iCh] = malloc( sizeof( ISAR_LC3PLUS_DEC_SELECTIVE_DECODING_STATE ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + + ( *handle )->selective_decoding_states[iCh]->has_skipped_a_frame = 0; + ( *handle )->selective_decoding_states[iCh]->shall_decode_cached_frame = 0; + ( *handle )->selective_decoding_states[iCh]->frame_action = DEC_ACTION_DECODE_AND_USE; + + /* allocate and configure per LC3plus decoder bitstream cache */ + if ( ( ( *handle )->bitstream_caches[iCh] = malloc( sizeof( ISAR_LC3PLUS_DEC_BITSTREAM_CACHE ) ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + + ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity = 400 /*LC3plus max non-HR octet count*/; + + if ( ( ( *handle )->bitstream_caches[iCh]->bitstream_cache = malloc( ( *handle )->bitstream_caches[iCh]->bitstream_cache_capacity ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder\n" ); + } + ( *handle )->bitstream_caches[iCh]->bitstream_cache_size = 0; + } + + ( *handle )->config = config; + if ( config.isar_frame_duration_us < config.lc3plus_frame_duration_us || config.isar_frame_duration_us % config.lc3plus_frame_duration_us != 0 ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "Current pcm_conversion_buffer sizing requires that lc3plus uses a shorter or equal frame duration than ivas\n" ); + } + + if ( ( ( *handle )->pcm_conversion_buffer = malloc( sizeof( int16_t ) * config.samplerate * config.lc3plus_frame_duration_us / 1000000 ) ) == NULL ) + { + ISAR_LC3PLUS_DEC_Close( handle ); + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus decoder wrapper pcm_conversion_buffer\n" ); + } + + return IVAS_ERR_OK; +} + +static void isar_lc3plus_dec_deinit_handle( + ISAR_LC3PLUS_DEC_HANDLE handle /* i/o: decoder handle */ +) +{ + if ( NULL == handle ) + { + return; + } + for ( uint32_t iDec = 0; iDec < handle->num_decs; iDec++ ) + { + if ( NULL != handle->handles && NULL != handle->handles[iDec] ) + { + lc3plus_free_decoder_structs( handle->handles[iDec] ); + free( handle->handles[iDec] ); + } + + if ( NULL != handle->selective_decoding_states && NULL != handle->selective_decoding_states[iDec] ) + { + free( handle->selective_decoding_states[iDec] ); + } + + if ( NULL != handle->bitstream_caches && NULL != handle->bitstream_caches[iDec] ) + { + free( handle->bitstream_caches[iDec]->bitstream_cache ); + free( handle->bitstream_caches[iDec] ); + } + } + + if ( NULL != handle->pcm_conversion_buffer ) + { + free( handle->pcm_conversion_buffer ); + } + free( handle->handles ); + + if ( NULL != handle->bitstream_caches ) + { + free( handle->bitstream_caches ); + } + free( handle->selective_decoding_states ); + + return; +} + +/*------------------------------------------------------------------------- + * ISAR_LC3PLUS_DEC_Open() + * + * + *------------------------------------------------------------------------*/ + +ivas_error ISAR_LC3PLUS_DEC_Open( + const LC3PLUS_CONFIG config, /* i : LC3plus decoder configuration */ + ISAR_LC3PLUS_DEC_HANDLE *handle /* o : decoder handle */ +) +{ + if ( ( *handle = malloc( sizeof( struct ISAR_LC3PLUS_DEC_HANDLE ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LC3plus wrapper handle\n" ); + } + + return isar_lc3plus_dec_init_handle( config, handle ); +} +#else /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_Open() * @@ -185,7 +385,7 @@ ivas_error ISAR_LC3PLUS_DEC_Open( return IVAS_ERR_OK; } - +#endif /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_GetDelay() @@ -232,6 +432,29 @@ ivas_error ISAR_LC3PLUS_DEC_GetDelay( } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP +/*------------------------------------------------------------------------- + * ISAR_LC3PLUS_DEC_Close() + * + * + *------------------------------------------------------------------------*/ + +void ISAR_LC3PLUS_DEC_Close( + ISAR_LC3PLUS_DEC_HANDLE *handle /* i/o: Pointer to LC3plus decoder handle */ +) +{ + if ( NULL == handle || NULL == *handle ) + { + return; + } + isar_lc3plus_dec_deinit_handle( *handle ); + + free( *handle ); + *handle = NULL; + + return; +} +#else /*------------------------------------------------------------------------- * ISAR_LC3PLUS_DEC_Close() * @@ -283,6 +506,7 @@ void ISAR_LC3PLUS_DEC_Close( return; } +#endif /*------------------------------------------------------------------------- @@ -341,6 +565,9 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( int32_t ivasSampleIndex; int16_t numSamplesPerLC3plusChannel; ivas_error err; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + bool reInitRequired = false; +#endif if ( NULL == handle ) { @@ -368,7 +595,9 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "isar_frame_duration_us must be equal or multiple of lc3plus_frame_duration_us \n" ); } +#ifndef FIX_1515_ISAR_FRAME_SIZES_IN_RTP config_num_media_times = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#endif if ( !badFrameIndicator ) { if ( LC3PLUS_RTP_payload_deserialize( &payload, bitstream_in, bitstream_in_size ) != LC3PLUS_RTP_ERR_NO_ERROR ) @@ -383,6 +612,50 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of channels) in bitstream is not supported\n" ); } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + if ( payload.frame_duration_us != handle->config.lc3plus_frame_duration_us ) + { + if ( payload.num_media_times * payload.frame_duration_us == handle->config.isar_frame_duration_us ) + { + reInitRequired = true; + } + else + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (frame duration) in bitstream is only supported when the ISAR frame duration stays the same\n" ); + } + } + if ( payload.high_resolution_enabled != handle->config.high_res_mode_enabled ) + { + reInitRequired = true; + } + if ( payload.num_media_times != handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us ) + { + if ( payload.num_media_times * payload.frame_duration_us == handle->config.isar_frame_duration_us ) + { + reInitRequired = true; + } + else + { + return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of media times per frame data block) in bitstream is only supported when the ISAR frame duration stays the same\n" ); + } + } + if ( reInitRequired ) + { + isar_lc3plus_dec_deinit_handle( handle ); + LC3PLUS_CONFIG newConfig; + newConfig.channels = payload.num_channels; + newConfig.samplerate = payload.sampling_rate_hz; + newConfig.high_res_mode_enabled = payload.high_resolution_enabled; + newConfig.isar_frame_duration_us = (int16_t) ( payload.num_media_times * payload.frame_duration_us ); + newConfig.lc3plus_frame_duration_us = (int16_t) payload.frame_duration_us; + newConfig.samplerate = payload.sampling_rate_hz; + err = isar_lc3plus_dec_init_handle( newConfig, &handle ); + if ( err != IVAS_ERR_OK ) + { + return IVAS_ERROR( err, "ISAR_LC3PLUS_DEC_Open failed\n" ); + } + } +#else if ( payload.frame_duration_us != handle->config.lc3plus_frame_duration_us ) { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (frame duration) in bitstream is not supported\n" ); @@ -395,8 +668,12 @@ static ivas_error isar_LC3PLUS_DEC_Decode_or_Conceal_internal( { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "LC3plus config change (number of media times per frame data block) in bitstream is not supported\n" ); } +#endif } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + config_num_media_times = handle->config.isar_frame_duration_us / handle->config.lc3plus_frame_duration_us; +#endif numSamplesPerLC3plusChannel = (int16_t) ( handle->config.samplerate / ( 1000000 / handle->config.isar_frame_duration_us ) / config_num_media_times ); for ( iDec = 0; iDec < handle->num_decs; iDec++ ) { diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 6ba81ec709e2ec53d95eab28aad6965fe04df78e..cee1f3d9bcdee372079399561798754d31c707b3 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -354,6 +354,9 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( available_bits = ( SplitRendBitRate * hSplitBin->hSplitBinLCLDEnc->iNumBlocks * hSplitBin->hSplitBinLCLDEnc->iNumIterations ) / ( 16 * FRAMES_PER_SEC ); available_bits -= pBits->bits_written; pBits->codec_frame_size_ms = codec_frame_size_ms; +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + pBits->isar_frame_size_ms = isar_frame_size_ms; +#endif isar_splitBinLCLDEncProcess( hSplitBin->hSplitBinLCLDEnc, Cldfb_In_BinReal, Cldfb_In_BinImag, available_bits, pBits ); } else diff --git a/scripts/split_rendering/isar_bstool.py b/scripts/split_rendering/isar_bstool.py index 10c1119667156d0561882abeb0e6fbaf100089fe..3412776d7894cdf77024ee54e8fb7f0badbcb7b8 100755 --- a/scripts/split_rendering/isar_bstool.py +++ b/scripts/split_rendering/isar_bstool.py @@ -1,53 +1,58 @@ #!/usr/bin/env python3 """ - (C) 2022-2026 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. +(C) 2022-2026 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. """ from __future__ import annotations + import argparse +import io import math import sys +from collections.abc import Callable from pathlib import Path +from typing import Protocol, cast, final, override class IsarBstoolError(Exception): pass +@final class IsarBitstream: def __init__(self, file_path: Path) -> None: self.file_path = file_path with open(file_path, "rb") as reader: self.header = IsarFileHeader(reader) - self.frames = [] + self.frames: list[IsarFileFrame] = [] while reader.peek(1): self.frames.append(IsarFileFrame(reader)) @@ -138,10 +143,10 @@ class IsarBitstream: self.file_path = file_path with open(file_path, "wb") as writer: - writer.write(self.header.as_bytes) + self.header.write(writer) for frame in self.frames: - writer.write(frame.as_bytes) + frame.write(writer) def trim(self, start_time_s: float, length_s: float | None = None) -> IsarBitstream: if length_s is None: @@ -178,62 +183,94 @@ class IsarBitstream: return self - def is_same_as(self, other: IsarBitstream) -> bool: + @override + def __eq__(self, other: object) -> bool: + if not isinstance(other, IsarBitstream): + return NotImplemented + return self.header == other.header and self.frames == other.frames -class _AsBytes: - def __init__(self) -> None: - self.as_bytes = bytearray() +@final +class IsarFileHeader: + FILE_HEADER = b"MAIN_SPLITH" - def _read(self, reader, num_bytes): - bytes_ = reader.read(num_bytes) - self.as_bytes.extend(bytes_) - return bytes_ + def __init__(self, reader: io.BufferedReader) -> None: + super().__init__() - def __eq__(self, value: object, /) -> bool: - if not isinstance(value, _AsBytes): - return False - return self.as_bytes == value.as_bytes + file_header_top = reader.read(len(self.FILE_HEADER)) + if file_header_top != self.FILE_HEADER: + raise IsarBstoolError(f"Not a valid ISAR file: {reader.name}") + self.delay_ns = _int_from_bytes(reader.read(4)) + self.codec = _codec_from_bytes(reader.read(4)) + self.pose_correction = _pose_corr_from_bytes(reader.read(4)) + self.codec_frame_size_ms = _int_from_bytes(reader.read(2)) + self.isar_frame_size_ms = _int_from_bytes(reader.read(2)) + self.sample_rate = _int_from_bytes(reader.read(4)) + self.lc3plus_hires = bool(_int_from_bytes(reader.read(2))) -class IsarFileHeader(_AsBytes): - def __init__(self, reader) -> None: - super().__init__() + @override + def __eq__(self, other: object) -> bool: + if not isinstance(other, IsarFileHeader): + return NotImplemented - FILE_HEADER = b"MAIN_SPLITH" - file_header_top = self._read(reader, len(FILE_HEADER)) - if file_header_top != FILE_HEADER: - raise IsarBstoolError(f"Not a valid ISAR file: {reader.name}") + return ( + self.delay_ns == other.delay_ns + and self.codec == other.codec + and self.pose_correction == other.pose_correction + and self.codec_frame_size_ms == other.codec_frame_size_ms + and self.isar_frame_size_ms == other.isar_frame_size_ms + and self.sample_rate == other.sample_rate + and self.lc3plus_hires == other.lc3plus_hires + ) + + def write(self, writer: io.BufferedWriter) -> None: + _write_exact(writer, self.FILE_HEADER) + _write_exact(writer, _int_to_bytes(self.delay_ns, 4)) + _write_exact(writer, _codec_to_bytes(self.codec)) + _write_exact(writer, _pose_corr_to_bytes(self.pose_correction)) + _write_exact(writer, _int_to_bytes(self.codec_frame_size_ms, 2)) + _write_exact(writer, _int_to_bytes(self.isar_frame_size_ms, 2)) + _write_exact(writer, _int_to_bytes(self.sample_rate, 4)) + _write_exact(writer, _int_to_bytes(int(self.lc3plus_hires), 2)) - self.delay_ns = _int_from_bytes(self._read(reader, 4)) - self.codec = _codec_from_bytes(self._read(reader, 4)) - self.pose_correction = _pose_corr_from_bytes(self._read(reader, 4)) - self.codec_frame_size_ms = _int_from_bytes(self._read(reader, 2)) - self.isar_frame_size_ms = _int_from_bytes(self._read(reader, 2)) - self.sample_rate = _int_from_bytes(self._read(reader, 4)) - self.lc3plus_hires = bool(_int_from_bytes(self._read(reader, 2))) +@final +class IsarFileFrame: + FRAME_HEADER = b"SPLIT_FRAME" + VERSION = 0 -class IsarFileFrame(_AsBytes): - def __init__(self, reader) -> None: + def __init__(self, reader: io.BufferedReader) -> None: super().__init__() - FRAME_HEADER = b"SPLIT_FRAME" - frame_header = self._read(reader, len(FRAME_HEADER)) - if frame_header != FRAME_HEADER: + frame_header = reader.read(len(self.FRAME_HEADER)) + if frame_header != self.FRAME_HEADER: raise IsarBstoolError(f"Not a valid ISAR file: {reader.name}") - version = _int_from_bytes(self._read(reader, 1)) - if version != 0: + version = _int_from_bytes(reader.read(1)) + if version != self.VERSION: raise IsarBstoolError( f"Unupported version of ISAR file format: {reader.name}" ) - self.num_bits = _int_from_bytes(self._read(reader, 4)) + self.num_bits = _int_from_bytes(reader.read(4)) payload_size = math.ceil(self.num_bits / 8) - self.payload = self._read(reader, payload_size) + self.payload = reader.read(payload_size) + + @override + def __eq__(self, other: object) -> bool: + if not isinstance(other, IsarFileFrame): + return NotImplemented + + return self.num_bits == other.num_bits and self.payload == other.payload + + def write(self, writer: io.BufferedWriter) -> None: + _write_exact(writer, self.FRAME_HEADER) + _write_exact(writer, _int_to_bytes(self.VERSION, 1)) + _write_exact(writer, _int_to_bytes(self.num_bits, 4)) + _write_exact(writer, self.payload) ###################################################################################### @@ -241,11 +278,24 @@ class IsarFileFrame(_AsBytes): ###################################################################################### -def _int_from_bytes(bytes_): +def _write_exact(writer: io.BufferedWriter, data: bytes) -> None: + num_written = writer.write(data) + if num_written != len(data): + file_name = getattr(writer, "name", "") + raise IsarBstoolError( + f"Failed to write to {file_name}: wrote {num_written} of {len(data)} bytes" + ) + + +def _int_from_bytes(bytes_: bytes) -> int: return int.from_bytes(bytes_, byteorder="little") -def _codec_from_bytes(bytes_): +def _int_to_bytes(x: int, num_bytes: int) -> bytes: + return x.to_bytes(num_bytes, byteorder="little") + + +def _codec_from_bytes(bytes_: bytes) -> str: # Refer to ISAR_SPLIT_REND_CODEC enum in C code CODECS = ["LCLD", "LC3PLUS", "DEFAULT", "NONE"] x = _int_from_bytes(bytes_) @@ -253,10 +303,16 @@ def _codec_from_bytes(bytes_): if x < len(CODECS): return CODECS[x] - return "UNKNOWN" + raise IsarBstoolError(f"Unknown codec value in ISAR file header: {x}") -def _pose_corr_from_bytes(bytes_): +def _codec_to_bytes(codec: str) -> bytes: + # Refer to ISAR_SPLIT_REND_CODEC enum in C code + CODECS = {"LCLD": 0, "LC3PLUS": 1, "DEFAULT": 2, "NONE": 3} + return CODECS[codec].to_bytes(4, byteorder="little") + + +def _pose_corr_from_bytes(bytes_: bytes) -> str: # Refer to ISAR_SPLIT_REND_POSE_CORRECTION_MODE enum in C code POSE_CORR_MODES = ["NONE", "CLDFB"] x = _int_from_bytes(bytes_) @@ -264,7 +320,13 @@ def _pose_corr_from_bytes(bytes_): if x < len(POSE_CORR_MODES): return POSE_CORR_MODES[x] - return "UNKNOWN" + raise IsarBstoolError(f"Unknown pose correction value in ISAR file header: {x}") + + +def _pose_corr_to_bytes(pose_corr: str) -> bytes: + # Refer to ISAR_SPLIT_REND_POSE_CORRECTION_MODE enum in C code + POSE_CORR_MODES = {"NONE": 0, "CLDFB": 1} + return POSE_CORR_MODES[pose_corr].to_bytes(4, byteorder="little") ###################################################################################### @@ -272,7 +334,12 @@ def _pose_corr_from_bytes(bytes_): ###################################################################################### -def _subcmd_info(args): +class _InfoArgs(Protocol): + file_in: Path + only: str | None + + +def _subcmd_info(args: _InfoArgs) -> None: bs = IsarBitstream(args.file_in) match args.only: @@ -314,9 +381,37 @@ def _subcmd_info(args): raise IsarBstoolError(f"Not a valid parameter value: '{args.only}'") -def _subcmd_trim(args): +class _TrimArgs(Protocol): + file_in: Path + file_out: Path + start_time: str + length: str | None + + +def _subcmd_trim(args: _TrimArgs) -> None: + bs = IsarBitstream(args.file_in) + _ = bs.trim(float(args.start_time), float(args.length) if args.length else None) + bs.write(args.file_out) + + +class _PatchCodecFrameSizeArgs(Protocol): + file_in: Path + file_out: Path + codec_frame_size_ms: str + + +def _subcmd_patch_codec_frame_size(args: _PatchCodecFrameSizeArgs) -> None: bs = IsarBitstream(args.file_in) - bs.trim(float(args.start_time), float(args.length) if args.length else None) + codec_frame_size_ms = int(args.codec_frame_size_ms) + + match codec_frame_size_ms: + case 5 | 10 | 20: + bs.header.codec_frame_size_ms = codec_frame_size_ms + case _: + raise IsarBstoolError( + f"Invalid codec frame size (in ms): {args.codec_frame_size_ms}. Valid values are 5 and 10." + ) + bs.write(args.file_out) @@ -324,17 +419,18 @@ def _subcmd_trim(args): # main ###################################################################################### + if __name__ == "__main__": parser = argparse.ArgumentParser( prog="isar_bstool", description="Utility for inspecting and modifying ISAR bitstreams", ) - parser.set_defaults(func=lambda _: parser.print_help()) + parser.set_defaults(func=lambda: parser.print_help()) subparsers = parser.add_subparsers(title="Commands") info = subparsers.add_parser("info", help="Print information about a bitstream") - info.add_argument("file_in", help="Path to input file") - info.add_argument( + _ = info.add_argument("file_in", type=Path, help="Path to input file") + _ = info.add_argument( "--only", help="Print only a specific parameter", default=None, @@ -362,23 +458,44 @@ if __name__ == "__main__": trim = subparsers.add_parser( "trim", help="Remove initial frames from a bitstream file" ) - trim.add_argument("file_in", help="Path to input file") - trim.add_argument("file_out", help="Path to output file") - trim.add_argument( + _ = trim.add_argument("file_in", type=Path, help="Path to input file") + _ = trim.add_argument("file_out", type=Path, help="Path to output file") + _ = trim.add_argument( "start_time", help="Start point (in s) from which content should be copied to the output.", ) - trim.add_argument( + _ = trim.add_argument( "--length", help="Amount of time (in s) to copy to the output. If not given, content is copied until the end of the input is reached.", default=None, ) trim.set_defaults(func=_subcmd_trim) + patch_codec_frame_size = subparsers.add_parser( + "patch_codec_frame_size", + help="Overwrite the codec frame size field in the header of an ISAR bitstream file", + description=( + "Note that this doesn't modify the actual frames in the file. The purpose of this command " + "is to inject incorrect frame size info into the header for testing LC3plus reconfiguration handling." + ), + ) + _ = patch_codec_frame_size.add_argument( + "file_in", type=Path, help="Path to input file" + ) + _ = patch_codec_frame_size.add_argument( + "file_out", type=Path, help="Path to output file" + ) + _ = patch_codec_frame_size.add_argument( + "codec_frame_size_ms", + help="Codec frame size (in ms) to write into the header of the output file", + ) + patch_codec_frame_size.set_defaults(func=_subcmd_patch_codec_frame_size) + args = parser.parse_args() + func = cast(Callable[[argparse.Namespace], None], args.func) try: - args.func(args) + func(args) except (FileNotFoundError, PermissionError, IsarBstoolError) as e: print(e, file=sys.stderr) sys.exit(1) diff --git a/scripts/split_rendering/lc3plus_basop/ivas_lc3plus_unit_test.c b/scripts/split_rendering/lc3plus_basop/ivas_lc3plus_unit_test.c deleted file mode 100644 index f91da0aa5097d33bedfb1c2ce88c1371de18b203..0000000000000000000000000000000000000000 --- a/scripts/split_rendering/lc3plus_basop/ivas_lc3plus_unit_test.c +++ /dev/null @@ -1,729 +0,0 @@ -/****************************************************************************************************** - -(C) 2022-2026 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 "options.h" -#include "isar_lc3plus_enc.h" -#include "isar_lc3plus_common.h" -#include "isar_lc3plus_dec.h" -#include "ivas_error_utils.h" -#include "lc3plus.h" - -#define MAX_SAMPLES_PER_CHANNEL 960 / 4 -#define DEFAULT_BPS 256000 - -#ifndef PCM_SAMPLE_TYPEDEF_DEFINED -#define PCM_SAMPLE_TYPEDEF_DEFINED -typedef int32_t PcmSample; -#endif - -static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) -{ - 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 ) - { - 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.isar_frame_duration_us ); - PcmSample *pcm_in[2]; - PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - PcmSample pcm_in_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_in_ch2, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm_in[0] = pcm_in_ch1; - pcm_in[1] = pcm_in_ch2; - - 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 ); - - 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; - } - - Word16 Q_in[16]; - memset( Q_in, 0, sizeof( Q_in ) ); - err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame, Q_in ); - if ( IVAS_ERR_OK != err ) - { - ISAR_LC3PLUS_ENC_Close( &encHandle ); - free( bitstream_out ); - 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 - 1 /*caching enabled*/, -#endif - &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" ); - } - - uint8_t *bitstream_in = bitstream_out; - - PcmSample *pcm_out[2]; - PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - PcmSample pcm_out_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_out_ch2, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm_out[0] = pcm_out_ch1; - pcm_out[1] = pcm_out_ch2; - - 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; - } - - ISAR_LC3PLUS_DEC_Close( &decHandle ); - free( bitstream_out ); - - return 0; -} - - -static int openCloseEncoder( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - uint32_t bps = 128000; - - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, bps, &encHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - ISAR_LC3PLUS_ENC_Close( &encHandle ); - return 0; -} - -static int tryOpenEncoderWithInvalidBitrate( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - /* lc3plus max bitrate is 320000 per channel */ - uint32_t invalid_high_bps = 700000; - uint32_t invalid_low_bps = 8; - uint32_t limitedBitrate; - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, invalid_high_bps, &encHandle ); - /* setting an invalid bitrate should result in a limited bitrate*/ - if ( IVAS_ERR_OK != err ) - { - return 1; - } - limitedBitrate = lc3plus_enc_get_real_bitrate( encHandle->handles[0] ); - if ( limitedBitrate != 320000 ) - { - return 1; - } - 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 = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - config.lc3plus_frame_duration_us = 1234; /*unsupported frame duration*/ - uint32_t bps = 320000; - - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, bps, &encHandle ); - /* setting an invalid fame duration should trigger an error - which is what we expect */ - if ( IVAS_ERR_OK == err ) - { - return 1; - } - return 0; -} - -static int tryOpenEncoderWithInvalidSampleRate( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - config.samplerate = 1234; /*unsupported sample rate */ - uint32_t bps = 320000; - - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, bps, &encHandle ); - /* setting an invalid sample rate should trigger an error - which is what we expect */ - if ( IVAS_ERR_OK == err ) - { - return 1; - } - return 0; -} - -static int tryCallEncoderApiWithInvalidParams( void ) -{ - ISAR_LC3PLUS_ENC_HANDLE invalidEncHandle = NULL; - int32_t *invalidBsSize = NULL; - int32_t bsSize; - int32_t *invalidDelayInSamples = NULL; - int32_t delayInSamples; - PcmSample **invalidPcm_in = NULL; - void *invalidBitstream_out = NULL; - - const int16_t numSamplesPerChannels = MAX_SAMPLES_PER_CHANNEL; - PcmSample *pcm_in[1]; - PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm_in[0] = pcm_in_ch1; - uint8_t bitstream_out[1200]; - - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_GetDelay( invalidEncHandle, invalidDelayInSamples ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_GetDelay( invalidEncHandle, &delayInSamples ) ) - { - return 1; - } - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( invalidEncHandle, invalidBsSize ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( invalidEncHandle, &bsSize ) ) - { - return 1; - } - ISAR_LC3PLUS_ENC_Close( &invalidEncHandle ); - Word16 Q_in[16]; - memset( Q_in, 0, sizeof( Q_in ) ); - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, invalidBitstream_out, bsSize, Q_in ) ) - { - return 1; - } - memset( Q_in, 0, sizeof( Q_in ) ); - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, invalidBitstream_out, bsSize, Q_in ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, bitstream_out, bsSize, Q_in ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, bitstream_out, bsSize, Q_in ) ) - { - return 1; - } - return 0; -} - - -static int tryCallDecoderApiWithInvalidParams( void ) -{ - ISAR_LC3PLUS_DEC_HANDLE invalidDecHandle = NULL; - - int32_t *invalidDelayInSamples = NULL; - int32_t delayInSamples; - PcmSample **invalidPcm_out = NULL; - void *invalidBitstream_in = NULL; - int32_t invalidBitstream_in_size = 0; - int32_t bitstream_in_size = 100; - - const int16_t numSamplesPerChannels = MAX_SAMPLES_PER_CHANNEL; - PcmSample *pcm_out[1]; - PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm_out[0] = pcm_out_ch1; - uint8_t bitstream_in[1200]; - - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_GetDelay( invalidDecHandle, invalidDelayInSamples ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_GetDelay( invalidDecHandle, &delayInSamples ) ) - { - return 1; - } - ISAR_LC3PLUS_DEC_Close( &invalidDecHandle ); - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, invalidBitstream_in, invalidBitstream_in_size, invalidPcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, invalidBitstream_in, invalidBitstream_in_size, pcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, invalidBitstream_in, bitstream_in_size, invalidPcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, invalidBitstream_in, bitstream_in_size, pcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, bitstream_in, invalidBitstream_in_size, invalidPcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, bitstream_in, invalidBitstream_in_size, pcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Decode( invalidDecHandle, bitstream_in, bitstream_in_size, pcm_out ) ) - { - return 1; - } - - if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Conceal( invalidDecHandle, invalidPcm_out ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_DEC_Conceal( invalidDecHandle, pcm_out ) ) - { - return 1; - } - return 0; -} - -static int openCloseDecoderWithCaching( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - ISAR_LC3PLUS_DEC_HANDLE decHandle; - err = ISAR_LC3PLUS_DEC_Open( config, -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING - 1 /*caching enabled*/, -#endif - &decHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - ISAR_LC3PLUS_DEC_Close( &decHandle ); - return 0; -} - -static int openCloseDecoderWithoutCaching( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - ISAR_LC3PLUS_DEC_HANDLE decHandle; - err = ISAR_LC3PLUS_DEC_Open( config, -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING - 1 /*caching enabled*/, -#endif - &decHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - ISAR_LC3PLUS_DEC_Close( &decHandle ); - return 0; -} - - -static int tryOpenDecoderWithInvalidFrameDuration( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - config.lc3plus_frame_duration_us = 1234; /*unsupported frame duration*/ - - ISAR_LC3PLUS_DEC_HANDLE decHandle; - err = ISAR_LC3PLUS_DEC_Open( config, -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING - 1 /*caching enabled*/, -#endif - &decHandle ); - /* setting an invalid fame duration should trigger an error - which is what we expect */ - if ( IVAS_ERR_OK == err ) - { - return 1; - } - return 0; -} - -static int tryOpenDecoderWithInvalidSampleRate( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - config.samplerate = 1234; /*unsupported sample rate*/ - - ISAR_LC3PLUS_DEC_HANDLE decHandle; - err = ISAR_LC3PLUS_DEC_Open( config, -#ifdef LC3PLUS_DEC_ALLOW_DISABLE_CACHING - 1 /*caching enabled*/, -#endif - &decHandle ); - /* setting an invalid sample rate should trigger an error - which is what we expect */ - if ( IVAS_ERR_OK == err ) - { - return 1; - } - return 0; -} - -static int encodeOneFrame( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - uint32_t bps = 128000; - - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, bps, &encHandle ); - if ( IVAS_ERR_OK != err ) - return err; - - int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); - - PcmSample *pcm[1]; - PcmSample pcm_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm[0] = pcm_ch1; - - 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 ); - Word16 Q_in[16]; - memset( Q_in, 0, sizeof( Q_in ) ); - err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm, bitstream_out, bitstreamSizePerIvasFrame, Q_in ); - - if ( IVAS_ERR_OK != err ) - return err; - - ISAR_LC3PLUS_ENC_Close( &encHandle ); - free( bitstream_out ); - return 0; -} - - -static int encodeAndDecodeOneMonoFrame( void ) -{ - ivas_error err; - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - uint32_t bps = 128000; - - ISAR_LC3PLUS_ENC_HANDLE encHandle; - err = ISAR_LC3PLUS_ENC_Open( config, bps, &encHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - /* encode one frame */ - int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); - PcmSample *pcm_in[1]; - PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm_in[0] = pcm_in_ch1; - - 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 ); - Word16 Q_in[16]; - memset( Q_in, 0, sizeof( Q_in ) ); - err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame, Q_in ); - 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 - 1 /*caching enabled*/, -#endif - &decHandle ); - if ( IVAS_ERR_OK != err ) - { - return err; - } - - uint8_t *bitstream_in = bitstream_out; - - PcmSample *pcm_out[1]; - PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; - memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); - pcm_out[0] = pcm_out_ch1; - 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; -} - -static int encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_48kHz( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); -} - -static int encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_32kHz( void ) -{ - 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, .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, .isar_frame_duration_us = 5 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3plus10ms_48kHz( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); -} - -static int encodeAndDecodeOneMonoFrameIvas20msLc3plus10ms_48kHz( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); -} - -static int encodeAndDecodeOneMonoFrameIvas5msLc3plus5ms_48kHz( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 5 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); -} - -static int encodeAndDecodeOneStereoFrameIvas20msLc3plus2_5ms_48kHz( void ) -{ - 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 }; - return encodeAndDecodeOneStereoFrame( config, DEFAULT_BPS ); -} - - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_80kbpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 82 * 1000 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_96kbpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 98 * 1000 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_124kbpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 126 * 1000 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_800kbpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 800 * 1000 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_204800bpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 204800 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_205600bpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 205600 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_206400bpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 206400 ); -} - -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_207200bpsPerChannel( void ) -{ - LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; - return encodeAndDecodeOneStereoFrame( config, config.channels * 207200 ); -} - -#include "ivas_lc3plus_unit_test_payload_format.c" - -int main( - int argc, - char *argv[] ) -{ - (void) argc; - (void) argv; - int ret = 0; - ret = openCloseEncoder(); - if ( ret != 0 ) - return 1; - ret = tryOpenEncoderWithInvalidBitrate(); - if ( ret != 0 ) - return 1; - ret = tryOpenEncoderWithInvalidFrameDuration(); - if ( ret != 0 ) - return 1; - ret = tryOpenEncoderWithInvalidSampleRate(); - if ( ret != 0 ) - return 1; - ret = tryCallEncoderApiWithInvalidParams(); - if ( ret != 0 ) - return 1; - ret = openCloseDecoderWithCaching(); - if ( ret != 0 ) - return 1; - ret = openCloseDecoderWithoutCaching(); - if ( ret != 0 ) - return 1; - ret = tryOpenDecoderWithInvalidFrameDuration(); - if ( ret != 0 ) - return 1; - ret = tryOpenDecoderWithInvalidSampleRate(); - if ( ret != 0 ) - return 1; - ret = tryCallDecoderApiWithInvalidParams(); - if ( ret != 0 ) - return 1; - ret = encodeOneFrame(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneMonoFrame(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_48kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_32kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus10ms_16kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas5msLc3plus5ms_48kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3plus10ms_48kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneMonoFrameIvas20msLc3plus10ms_48kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneMonoFrameIvas5msLc3plus5ms_48kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas20msLc3plus2_5ms_48kHz(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_80kbpsPerChannel(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_96kbpsPerChannel(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_124kbpsPerChannel(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_800kbpsPerChannel(); - if ( ret != 0 ) - return 1; - /* start configs around the FDL threshold */ - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_204800bpsPerChannel(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_205600bpsPerChannel(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_206400bpsPerChannel(); - if ( ret != 0 ) - return 1; - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_207200bpsPerChannel(); - if ( ret != 0 ) - return 1; - /* end configs around the FDL threshold */ - ret = run_all_payload_tests(); - if ( ret != 0 ) - return 1; - return 0; -} diff --git a/scripts/split_rendering/lc3plus_basop/ivas_lc3plus_unit_test_payload_format.c b/scripts/split_rendering/lc3plus_basop/ivas_lc3plus_unit_test_payload_format.c deleted file mode 100644 index 24b9deba71a91c2c026d41d793b5344852c4dbb1..0000000000000000000000000000000000000000 --- a/scripts/split_rendering/lc3plus_basop/ivas_lc3plus_unit_test_payload_format.c +++ /dev/null @@ -1,449 +0,0 @@ -/****************************************************************************************************** - -(C) 2022-2026 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" - - -/* 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; -} diff --git a/scripts/split_rendering/lc3plus_float/ivas_lc3plus_unit_test.c b/scripts/split_rendering/lc3plus_float/ivas_lc3plus_unit_test.c index 5ba66f721b934c83ba33124c522a8819c37d4603..44574a0b8d841665e0db64521f20f17f1764293b 100644 --- a/scripts/split_rendering/lc3plus_float/ivas_lc3plus_unit_test.c +++ b/scripts/split_rendering/lc3plus_float/ivas_lc3plus_unit_test.c @@ -43,6 +43,13 @@ the United Nations Convention on Contracts on the International Sales of Goods. #define MAX_SAMPLES_PER_CHANNEL 960 / 4 #define DEFAULT_BPS 256000 +#ifdef LC3PLUS_UNIT_TEST_BASOP +#ifndef PCM_SAMPLE_TYPEDEF_DEFINED +#define PCM_SAMPLE_TYPEDEF_DEFINED +typedef int32_t PcmSample; +#endif +#endif + static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) { ivas_error err; @@ -70,11 +77,19 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) /* encode one frame */ int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm_in[2]; + PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); + PcmSample pcm_in_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_in_ch2, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else float *pcm_in[2]; 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 ) ); +#endif pcm_in[0] = pcm_in_ch1; pcm_in[1] = pcm_in_ch2; @@ -102,7 +117,13 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) return err; } +#ifdef LC3PLUS_UNIT_TEST_BASOP + Word16 Q_in[16]; + memset( Q_in, 0, sizeof( Q_in ) ); + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame, Q_in ); +#else err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame ); +#endif if ( IVAS_ERR_OK != err ) { ISAR_LC3PLUS_ENC_Close( &encHandle ); @@ -140,11 +161,19 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) uint8_t *bitstream_in = bitstream_out; +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm_out[2]; + PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); + PcmSample pcm_out_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_out_ch2, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else float *pcm_out[2]; 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 ) ); +#endif pcm_out[0] = pcm_out_ch1; pcm_out[1] = pcm_out_ch2; @@ -177,6 +206,234 @@ static int encodeAndDecodeOneStereoFrame( LC3PLUS_CONFIG config, uint32_t bps ) return 0; } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP +static int encodeAndDecodeOneStereoFrameWithConfigSwitch( LC3PLUS_CONFIG config_01, uint32_t bps_01, LC3PLUS_CONFIG config_02, uint32_t bps_02 ) +{ + ivas_error err; + int32_t encDelay = -1; + int32_t decDelay = -1; + + ISAR_LC3PLUS_ENC_HANDLE encHandle; + err = ISAR_LC3PLUS_ENC_Open( config_01, bps_01, &encHandle ); + if ( IVAS_ERR_OK != err ) + { + return err; + } + + 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_01.samplerate / ( 1000000 / config_01.isar_frame_duration_us ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm_in[2]; + PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); + PcmSample pcm_in_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_in_ch2, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else + float *pcm_in[2]; + 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 ) ); +#endif + pcm_in[0] = pcm_in_ch1; + pcm_in[1] = pcm_in_ch2; + + int32_t bitstreamSizePerIvasFrame_01 = 0; + err = ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( encHandle, &bitstreamSizePerIvasFrame_01 ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + return err; + } + uint8_t *bitstream_out_01 = malloc( bitstreamSizePerIvasFrame_01 ); + memset( bitstream_out_01, 0, bitstreamSizePerIvasFrame_01 ); + + int perChannelBitrate = lc3plus_enc_get_real_bitrate( encHandle->handles[0] ); + int perLc3plusFrameDataBlockOctets = encHandle->num_ftds * perChannelBitrate / 8 / ( 1000 * 1000 / config_01.lc3plus_frame_duration_us ); + int targetOctets = bps_01 / 8 / ( 1000 * 1000 / config_01.isar_frame_duration_us ); + printf( "IVAS-FS=%i LC3plus-FS=%i ch=%i targetBps=%i targetOctets=%i\n", config_01.isar_frame_duration_us, config_01.lc3plus_frame_duration_us, config_01.channels, bps_01, targetOctets ); + printf( " coreBps=%i corePerChBps=%i coreCodecOctets=%i nFtds=%i \n", perChannelBitrate * encHandle->num_encs, perChannelBitrate, perLc3plusFrameDataBlockOctets, encHandle->num_ftds ); + int pfOctets = bitstreamSizePerIvasFrame_01 - perLc3plusFrameDataBlockOctets; + int pfBps = pfOctets * 8 * ( 1000 * 1000 / config_01.isar_frame_duration_us ); + printf( " payloadFormatBps=%i payloadFormatOctets=%i \n\n", pfBps, pfOctets ); + if ( pfBps <= 0 ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + return err; + } + +#ifdef LC3PLUS_UNIT_TEST_BASOP + Word16 Q_in[16]; + memset( Q_in, 0, sizeof( Q_in ) ); + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out_01, bitstreamSizePerIvasFrame_01, Q_in ); +#else + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out_01, bitstreamSizePerIvasFrame_01 ); +#endif + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + free( bitstream_out_01 ); + return err; + } + ISAR_LC3PLUS_ENC_Close( &encHandle ); + + // Enc2 + err = ISAR_LC3PLUS_ENC_Open( config_02, bps_02, &encHandle ); + if ( IVAS_ERR_OK != err ) + { + return err; + } + + 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 */ + int32_t bitstreamSizePerIvasFrame_02 = 0; + err = ISAR_LC3PLUS_ENC_GetOutputBitstreamSize( encHandle, &bitstreamSizePerIvasFrame_02 ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + return err; + } + uint8_t *bitstream_out_02 = malloc( bitstreamSizePerIvasFrame_02 ); + memset( bitstream_out_02, 0, bitstreamSizePerIvasFrame_02 ); + + perChannelBitrate = lc3plus_enc_get_real_bitrate( encHandle->handles[0] ); + perLc3plusFrameDataBlockOctets = encHandle->num_ftds * perChannelBitrate / 8 / ( 1000 * 1000 / config_02.lc3plus_frame_duration_us ); + targetOctets = bps_02 / 8 / ( 1000 * 1000 / config_02.isar_frame_duration_us ); + printf( "IVAS-FS=%i LC3plus-FS=%i ch=%i targetBps=%i targetOctets=%i\n", config_02.isar_frame_duration_us, config_02.lc3plus_frame_duration_us, config_02.channels, bps_02, targetOctets ); + printf( " coreBps=%i corePerChBps=%i coreCodecOctets=%i nFtds=%i \n", perChannelBitrate * encHandle->num_encs, perChannelBitrate, perLc3plusFrameDataBlockOctets, encHandle->num_ftds ); + pfOctets = bitstreamSizePerIvasFrame_02 - perLc3plusFrameDataBlockOctets; + pfBps = pfOctets * 8 * ( 1000 * 1000 / config_02.isar_frame_duration_us ); + printf( " payloadFormatBps=%i payloadFormatOctets=%i \n\n", pfBps, pfOctets ); + if ( pfBps <= 0 ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + return err; + } + + +#ifdef LC3PLUS_UNIT_TEST_BASOP + memset( Q_in, 0, sizeof( Q_in ) ); + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out_02, bitstreamSizePerIvasFrame_02, Q_in ); +#else + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out_02, bitstreamSizePerIvasFrame_02 ); +#endif + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_ENC_Close( &encHandle ); + free( bitstream_out_02 ); + return err; + } + ISAR_LC3PLUS_ENC_Close( &encHandle ); + + /* decode one frame */ + ISAR_LC3PLUS_DEC_HANDLE decHandle; + err = ISAR_LC3PLUS_DEC_Open( config_01, &decHandle ); + if ( IVAS_ERR_OK != err ) + { + free( bitstream_out_01 ); + return err; + } + + err = ISAR_LC3PLUS_DEC_GetDelay( decHandle, &decDelay ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + return err; + } + if ( decDelay == -1 || decDelay == 0 ) + { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "decDelay is zero or uninitialized\n" ); + } + +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm_out[2]; + PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); + PcmSample pcm_out_ch2[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_out_ch2, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else + float *pcm_out[2]; + 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 ) ); +#endif + pcm_out[0] = pcm_out_ch1; + pcm_out[1] = pcm_out_ch2; + + + // err = ISAR_LC3PLUS_DEC_Conceal( decHandle, pcm_out ); + // if ( IVAS_ERR_OK != err ) + // { + // ISAR_LC3PLUS_DEC_Close( &decHandle ); + // free( bitstream_out_01 ); + // return err; + // } + + err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_out_01, bitstreamSizePerIvasFrame_01, pcm_out ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + return err; + } + + err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_out_02, bitstreamSizePerIvasFrame_02, pcm_out ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + return err; + } + + err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_out_01, bitstreamSizePerIvasFrame_01, pcm_out ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + return err; + } + + err = ISAR_LC3PLUS_DEC_Conceal( decHandle, pcm_out ); + if ( IVAS_ERR_OK != err ) + { + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + return err; + } + + ISAR_LC3PLUS_DEC_Close( &decHandle ); + free( bitstream_out_01 ); + + return 0; +} +#endif static int openCloseEncoder( void ) @@ -268,13 +525,20 @@ static int tryCallEncoderApiWithInvalidParams( void ) int32_t bsSize; int32_t *invalidDelayInSamples = NULL; int32_t delayInSamples; - float **invalidPcm_in = NULL; void *invalidBitstream_out = NULL; const int16_t numSamplesPerChannels = MAX_SAMPLES_PER_CHANNEL; +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample **invalidPcm_in = NULL; + PcmSample *pcm_in[1]; + PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else + float **invalidPcm_in = NULL; float *pcm_in[1]; float pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( float ) ); +#endif pcm_in[0] = pcm_in_ch1; uint8_t bitstream_out[1200]; @@ -287,11 +551,23 @@ static int tryCallEncoderApiWithInvalidParams( void ) return 1; } ISAR_LC3PLUS_ENC_Close( &invalidEncHandle ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + Word16 Q_in[16]; + memset( Q_in, 0, sizeof( Q_in ) ); + if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, invalidBitstream_out, bsSize, Q_in ) ) + +#else if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, invalidBitstream_out, bsSize ) ) +#endif { return 1; } +#ifdef LC3PLUS_UNIT_TEST_BASOP + memset( Q_in, 0, sizeof( Q_in ) ); + if ( IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, invalidBitstream_out, bsSize, Q_in ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, invalidPcm_in, bitstream_out, bsSize, Q_in ) || IVAS_ERR_UNEXPECTED_NULL_POINTER != ISAR_LC3PLUS_ENC_Encode( invalidEncHandle, pcm_in, bitstream_out, bsSize, Q_in ) ) +#else 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 ) ) +#endif { return 1; } @@ -305,15 +581,22 @@ static int tryCallDecoderApiWithInvalidParams( void ) int32_t *invalidDelayInSamples = NULL; int32_t delayInSamples; - float **invalidPcm_out = NULL; void *invalidBitstream_in = NULL; int32_t invalidBitstream_in_size = 0; int32_t bitstream_in_size = 100; const int16_t numSamplesPerChannels = MAX_SAMPLES_PER_CHANNEL; +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample **invalidPcm_out = NULL; + PcmSample *pcm_out[1]; + PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else + float **invalidPcm_out = NULL; float *pcm_out[1]; float pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( float ) ); +#endif pcm_out[0] = pcm_out_ch1; uint8_t bitstream_in[1200]; @@ -426,9 +709,15 @@ static int encodeOneFrame( void ) int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm[1]; + PcmSample pcm_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else float *pcm[1]; float pcm_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_ch1, 0, numSamplesPerChannels * sizeof( float ) ); +#endif pcm[0] = pcm_ch1; int32_t bitstreamSizePerIvasFrame = 0; @@ -437,7 +726,13 @@ static int encodeOneFrame( void ) return err; uint8_t *bitstream_out = malloc( bitstreamSizePerIvasFrame ); memset( bitstream_out, 0, bitstreamSizePerIvasFrame ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + Word16 Q_in[16]; + memset( Q_in, 0, sizeof( Q_in ) ); + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm, bitstream_out, bitstreamSizePerIvasFrame, Q_in ); +#else err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm, bitstream_out, bitstreamSizePerIvasFrame ); +#endif if ( IVAS_ERR_OK != err ) return err; @@ -462,9 +757,15 @@ static int encodeAndDecodeOneMonoFrame( void ) /* encode one frame */ int16_t numSamplesPerChannels = config.samplerate / ( 1000000 / config.isar_frame_duration_us ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm_in[1]; + PcmSample pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else float *pcm_in[1]; float pcm_in_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_in_ch1, 0, numSamplesPerChannels * sizeof( float ) ); +#endif pcm_in[0] = pcm_in_ch1; int32_t bitstreamSizePerIvasFrame = 0; @@ -474,7 +775,13 @@ static int encodeAndDecodeOneMonoFrame( void ) uint8_t *bitstream_out = malloc( bitstreamSizePerIvasFrame ); memset( bitstream_out, 0, bitstreamSizePerIvasFrame ); +#ifdef LC3PLUS_UNIT_TEST_BASOP + Word16 Q_in[16]; + memset( Q_in, 0, sizeof( Q_in ) ); + err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame, Q_in ); +#else err = ISAR_LC3PLUS_ENC_Encode( encHandle, pcm_in, bitstream_out, bitstreamSizePerIvasFrame ); +#endif if ( IVAS_ERR_OK != err ) return err; ISAR_LC3PLUS_ENC_Close( &encHandle ); @@ -493,9 +800,15 @@ static int encodeAndDecodeOneMonoFrame( void ) uint8_t *bitstream_in = bitstream_out; +#ifdef LC3PLUS_UNIT_TEST_BASOP + PcmSample *pcm_out[1]; + PcmSample pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( PcmSample )]; + memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( PcmSample ) ); +#else float *pcm_out[1]; float pcm_out_ch1[MAX_SAMPLES_PER_CHANNEL * sizeof( float )]; memset( pcm_out_ch1, 0, numSamplesPerChannels * sizeof( float ) ); +#endif pcm_out[0] = pcm_out_ch1; err = ISAR_LC3PLUS_DEC_Decode( decHandle, bitstream_in, bitstreamSizePerIvasFrame, pcm_out ); if ( IVAS_ERR_OK != err ) @@ -576,11 +889,7 @@ static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_96kbpsPerChannel( return encodeAndDecodeOneStereoFrame( config, config.channels * 98 * 1000 ); } -#ifdef LC3PLUS_LEA_COMPAT_BITRATES_48_6 static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_126kbpsPerChannel( void ) -#else -static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_124kbpsPerChannel( void ) -#endif { LC3PLUS_CONFIG config = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 2, .samplerate = 48000, .high_res_mode_enabled = 0 }; return encodeAndDecodeOneStereoFrame( config, config.channels * 126 * 1000 ); @@ -616,6 +925,43 @@ static int encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_207200bpsPerChann return encodeAndDecodeOneStereoFrame( config, config.channels * 207200 ); } +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP +static int encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_20ms(void) +{ + LC3PLUS_CONFIG config_2x10ms = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + LC3PLUS_CONFIG config_4x5ms = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + return encodeAndDecodeOneStereoFrameWithConfigSwitch( config_2x10ms, config_2x10ms.channels * DEFAULT_BPS, config_4x5ms, config_4x5ms.channels * DEFAULT_BPS ); +} + +static int encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_10ms(void) +{ + LC3PLUS_CONFIG config_1x10ms = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + LC3PLUS_CONFIG config_2x5ms = { .lc3plus_frame_duration_us = 5 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + return encodeAndDecodeOneStereoFrameWithConfigSwitch( config_1x10ms, config_1x10ms.channels * DEFAULT_BPS, config_2x5ms, config_2x5ms.channels * DEFAULT_BPS ); +} + +static int encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_20ms_HighRes_switch(void) +{ + LC3PLUS_CONFIG config_2x10ms_HR_ON = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 1 }; + LC3PLUS_CONFIG config_2x10ms_HR_OFF = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + return encodeAndDecodeOneStereoFrameWithConfigSwitch( config_2x10ms_HR_ON, config_2x10ms_HR_ON.channels * DEFAULT_BPS, config_2x10ms_HR_OFF, config_2x10ms_HR_OFF.channels * DEFAULT_BPS ); +} + +static int encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_10ms_to_20ms_will_fail(void) +{ + LC3PLUS_CONFIG config_1x10ms = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + LC3PLUS_CONFIG config_2x10ms = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + return encodeAndDecodeOneStereoFrameWithConfigSwitch( config_1x10ms, config_1x10ms.channels * DEFAULT_BPS, config_2x10ms, config_2x10ms.channels * DEFAULT_BPS ); +} + +static int encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_20ms_to_10ms_will_fail(void) +{ + LC3PLUS_CONFIG config_2x10ms = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 20 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + LC3PLUS_CONFIG config_1x10ms = { .lc3plus_frame_duration_us = 10 * 1000, .isar_frame_duration_us = 10 * 1000, .channels = 1, .samplerate = 48000, .high_res_mode_enabled = 0 }; + return encodeAndDecodeOneStereoFrameWithConfigSwitch( config_2x10ms, config_2x10ms.channels * DEFAULT_BPS, config_1x10ms, config_1x10ms.channels * DEFAULT_BPS ); +} +#endif + #include "ivas_lc3plus_unit_test_payload_format.c" int main( @@ -691,11 +1037,7 @@ int main( ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_96kbpsPerChannel(); if ( ret != 0 ) return 1; -#ifdef LC3PLUS_LEA_COMPAT_BITRATES_48_6 ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_126kbpsPerChannel(); -#else - ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_124kbpsPerChannel(); -#endif if ( ret != 0 ) return 1; ret = encodeAndDecodeOneStereoFrameIvas10msLc3_10ms_48kHz_800kbpsPerChannel(); @@ -715,6 +1057,23 @@ int main( if ( ret != 0 ) return 1; /* end configs around the FDL threshold */ +#ifdef FIX_1515_ISAR_FRAME_SIZES_IN_RTP + ret = encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_20ms(); + if ( ret != 0 ) + return 1; + ret = encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_10ms(); + if ( ret != 0 ) + return 1; + ret = encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_20ms_HighRes_switch(); + if ( ret != 0 ) + return 1; + ret = encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_20ms_to_10ms_will_fail(); + if ( ret == 0 /* will fail, switching is only supported when the ISAR frame duration stays the same*/ ) + return 1; + ret = encodeAndDecodeOneStereoFrameWithLc3plusConfigSwitch_ISAR_10ms_to_20ms_will_fail(); + if ( ret == 0 /* will fail, switching is only supported when the ISAR frame duration stays the same*/ ) + return 1; +#endif ret = run_all_payload_tests(); if ( ret != 0 ) return 1; diff --git a/tests/split_rendering/constants.py b/tests/split_rendering/constants.py index f7b22218074d6a530fb6d526fbc95e2a30e7b19c..fccd044c7afea800256e7c2aecb5b9eff99ce90e 100644 --- a/tests/split_rendering/constants.py +++ b/tests/split_rendering/constants.py @@ -82,6 +82,9 @@ RENDERER_CONFIGS_FASTCONV_RENDERER = [ RENDERER_CONFIGS_FRAMING = [ str(cfg.stem) for cfg in RENDER_FRAMING_CFG_DIR.glob("framing*.txt") ] +RENDERER_CONFIGS_FRAMING_LC3PLUS = [ + str(cfg.stem) for cfg in RENDER_FRAMING_CFG_DIR.glob("framing_lc3plus*.txt") +] RENDERER_CONFIGS_TO_TEST_AMBI = ( RENDERER_CONFIGS_DEFAULT_CODEC + RENDERER_CONFIGS_LC3PLUS_CODEC diff --git a/tests/split_rendering/test_split_rendering.py b/tests/split_rendering/test_split_rendering.py index 7d0bb9d1ce893e4ce47904a374d4f3352b639631..06b002939f6493c4e0d1f214b8c836e199e7c548 100644 --- a/tests/split_rendering/test_split_rendering.py +++ b/tests/split_rendering/test_split_rendering.py @@ -740,3 +740,51 @@ def test_framing_combinations_full_chain_split( get_odg_bin=get_odg_bin, delay_profile=SCRIPTS_DIR / "dly_error_profiles" / f"{delay_profile}.dat" if delay_profile else None, ) + + +""" +Tests cases where the transport codec framing information is incorrect and the LC3plus decoder needs +to reconfigure on the first frame. Required for RTP use cases. +""" +@pytest.mark.parametrize("render_config", RENDERER_CONFIGS_FRAMING_LC3PLUS) +@pytest.mark.parametrize("pre_rend_fr", SPLIT_RENDERER_PRE_FRAMINGS) +@pytest.mark.parametrize("post_rend_fr", SPLIT_RENDERER_POST_FRAMINGS) +@pytest.mark.parametrize("patch_codec_frame_size_ms", [5, 10]) +def test_lc3plus_framing_reconfiguration( + record_property, + props_to_record, + get_mld, + get_mld_lim, + get_ssnr, + get_odg, + get_odg_bin, + test_info, + render_config, + post_rend_fr, + pre_rend_fr, + patch_codec_frame_size_ms, +): + if int(patch_codec_frame_size_ms) > int(pre_rend_fr): + pytest.xfail("Codec frame size must fit within the ISAR frame size") + + post_trajectory = HR_TRAJECTORY_DIR.joinpath("rotate_euler_quaternion_30s.csv") + pre_trajectory = post_trajectory.with_stem(f"{post_trajectory.stem}_delayed") + + run_external_split_rendering( + record_property, + props_to_record, + test_info, + in_fmt="5_1", + render_config=RENDER_FRAMING_CFG_DIR.joinpath(f"{render_config}.txt"), + pre_trajectory=pre_trajectory, + post_trajectory=post_trajectory, + binary_suffix=EXE_SUFFIX, + post_rend_fr=post_rend_fr, + pre_rend_fr=pre_rend_fr, + get_mld=get_mld, + mld_lim=get_mld_lim, + get_ssnr=get_ssnr, + get_odg=get_odg, + get_odg_bin=get_odg_bin, + patch_codec_frame_size_ms=patch_codec_frame_size_ms, + ) diff --git a/tests/split_rendering/utils.py b/tests/split_rendering/utils.py index 2f878c0eb465b6c6255c6e4ebbea812e4ce6b77b..7c5414a2f609a99b379a2abf61c12818d0920a56 100644 --- a/tests/split_rendering/utils.py +++ b/tests/split_rendering/utils.py @@ -61,6 +61,7 @@ from ..conftest import parse_properties sys.path.append(SCRIPTS_DIR) from pyaudio3dtools.audiofile import readfile, writefile +from split_rendering.isar_bstool import IsarBitstream def lc3plus_used(test_info, in_fmt, render_config): @@ -345,6 +346,7 @@ def run_external_split_rendering( get_ssnr=False, get_odg=False, get_odg_bin=False, + patch_codec_frame_size_ms: int | None = None, ) -> Tuple[np.ndarray, int]: """ Runs the exeternal split rendering chain consisting of @@ -362,6 +364,9 @@ def run_external_split_rendering( if plc_error_pattern: filename_base += f"_plc_{plc_error_pattern.stem}" + if patch_codec_frame_size_ms: + filename_base += f"_tcfrmod_{patch_codec_frame_size_ms}ms" + split_bitstream_stem = f"{filename_base}.splt.bit" if renderer_fmt == "BINAURAL_SPLIT_PCM": split_md_file_stem = f"{filename_base}.spltmd.bit" @@ -415,6 +420,14 @@ def run_external_split_rendering( run_isar_ext_rend_cmd(split_pre_cmd, test_info=test_info) + # If patch_codec_frame_size_ms is set, overwrite the frame size in the split bitstream + # header with the provided value. This tests LC3plus framing reconfiguration. + if patch_codec_frame_size_ms: + isar_bs = IsarBitstream(split_bitstream) + isar_bs.header.codec_frame_size_ms = patch_codec_frame_size_ms + split_bitstream_mod = split_bitstream.with_stem(split_bitstream.stem + f"_patched") + isar_bs.write(split_bitstream_mod) + # run ISAR post-renderer split_post_cmd = SPLIT_POST_REND_CMD[:] @@ -435,6 +448,20 @@ def run_external_split_rendering( run_isar_ext_rend_cmd(split_post_cmd, test_info=test_info) + if patch_codec_frame_size_ms: + split_post_cmd[4] = str(split_bitstream_mod) + out_file_mod = out_file.with_stem(out_file.stem + f"_patched") + split_post_cmd[8] = str(out_file_mod) + run_isar_ext_rend_cmd(split_post_cmd, test_info=test_info) + output_differs, reason = cmp_pcm( + out_file, + out_file_mod, + 2, # is always "BINAURAL", + 48000, # currently only 48 kHz tests + ) + if output_differs[0]: + pytest.fail(f"ISAR output differs when codec frame size in bitstream is patched: ({reason[0]})") + if test_info.config.option.create_cut: # CUT creation mode will run a comparison with REF out_file_ref = OUTPUT_PATH_REF.joinpath(out_file_stem) diff --git a/tests/test_be_for_jbm_neutral_dly_profile.py b/tests/test_be_for_jbm_neutral_dly_profile.py index dee54b7d94a6f8dd0984e7d9203176f0028e8512..330f6aad4c498c480ea7ec91194308b000162478 100644 --- a/tests/test_be_for_jbm_neutral_dly_profile.py +++ b/tests/test_be_for_jbm_neutral_dly_profile.py @@ -228,7 +228,7 @@ def compare_audio(non_voip_output, voip_output, sampling_rate_khz): def compare_isar_files(non_voip_isar, voip_isar): isar_bs = IsarBitstream(non_voip_isar) isar_bs_voip = IsarBitstream(voip_isar).trim(JBM_NEUTRAL_DELAY_MS / 1000) - if not isar_bs_voip.is_same_as(isar_bs): + if isar_bs_voip != isar_bs: pytest.fail( "Difference between no jbm and zero-delay jbm decoding found! ISAR files differ" )