From 87b1a7531792f5bb1726b45975f2992c395fa629 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 11:42:56 +0200 Subject: [PATCH 01/34] Initial rtpdump port - Add rtpdump related files to lib_util - Add flags IVAS_RTPDUMP and RTP_S4_251135_CR26253_0016_REV1 - Port changes to rtpdump.c, g192.c/.h, ivas_error.h - Add functionality to encoder.c and decoder.c --- apps/decoder.c | 75 ++ apps/encoder.c | 233 ++++- lib_com/ivas_error.h | 24 + lib_com/options.h | 4 + lib_util/g192.c | 4 + lib_util/g192.h | 4 + lib_util/ivas_bpool.c | 153 +++ lib_util/ivas_bpool.h | 57 ++ lib_util/ivas_queue.c | 137 +++ lib_util/ivas_queue.h | 68 ++ lib_util/ivas_rtp_api.h | 591 +++++++++++ lib_util/ivas_rtp_file.c | 612 +++++++++++ lib_util/ivas_rtp_file.h | 79 ++ lib_util/ivas_rtp_internal.h | 140 +++ lib_util/ivas_rtp_payload.c | 1854 ++++++++++++++++++++++++++++++++++ lib_util/ivas_rtp_pi_data.c | 850 ++++++++++++++++ lib_util/ivas_rtp_pi_data.h | 471 +++++++++ lib_util/mutex.h | 104 ++ lib_util/rtpdump.c | 13 + readme.txt | 12 +- 20 files changed, 5474 insertions(+), 11 deletions(-) create mode 100644 lib_util/ivas_bpool.c create mode 100644 lib_util/ivas_bpool.h create mode 100644 lib_util/ivas_queue.c create mode 100644 lib_util/ivas_queue.h create mode 100644 lib_util/ivas_rtp_api.h create mode 100644 lib_util/ivas_rtp_file.c create mode 100644 lib_util/ivas_rtp_file.h create mode 100644 lib_util/ivas_rtp_internal.h create mode 100644 lib_util/ivas_rtp_payload.c create mode 100644 lib_util/ivas_rtp_pi_data.c create mode 100644 lib_util/ivas_rtp_pi_data.h create mode 100644 lib_util/mutex.h diff --git a/apps/decoder.c b/apps/decoder.c index 5221ec628..0e7931fe8 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -52,6 +52,9 @@ #include "wmc_auto.h" #include "options.h" #include "stl.h" +#ifdef IVAS_RTPDUMP +#include "ivas_rtp_file.h" +#endif #define WMC_TOOL_SKIP @@ -129,6 +132,9 @@ typedef struct uint16_t directivityPatternId[IVAS_MAX_NUM_OBJECTS]; bool objEditEnabled; char *objEditFileName; +#ifdef IVAS_RTPDUMP + char *piOutputFilename; +#endif } DecArguments; @@ -840,6 +846,9 @@ static bool parseCmdlIVAS_dec( arg->referenceVectorTrajFileName = NULL; arg->enableExternalOrientation = false; arg->externalOrientationTrajFileName = NULL; +#ifdef IVAS_RTPDUMP + arg->piOutputFilename = NULL; +#endif #ifdef SUPPORT_JBM_TRACEFILE arg->jbmTraceFilename = NULL; @@ -918,6 +927,20 @@ static bool parseCmdlIVAS_dec( arg->inputFormat = IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF; i++; } +#ifdef IVAS_RTPDUMP + else if ( strcmp( argv_to_upper, "-PIDATAFILE" ) == 0 ) + { + i++; + if ( argc - i <= 3 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: PI Data Output file name not specified!\n\n" ); + usage_dec(); + return false; + } + + arg->piOutputFilename = argv[i++]; + } +#endif #ifdef SUPPORT_JBM_TRACEFILE else if ( strcmp( argv_to_upper, "-TRACEFILE" ) == 0 ) { @@ -1511,10 +1534,19 @@ static void usage_dec( void ) fprintf( stdout, "--------\n" ); fprintf( stdout, "-VOIP : VoIP mode: RTP in G192\n" ); fprintf( stdout, "-VOIP_hf_only=0 : VoIP mode: EVS RTP Payload Format hf_only=0 in rtpdump\n" ); +#ifdef IVAS_RTPDUMP + fprintf( stdout, "-VOIP_hf_only=1 : VoIP mode: EVS or IVAS RTP Payload Format hf_only=1 in rtpdump\n" ); + fprintf( stdout, " The decoder may read rtpdump files containing TS26.445 Annex A.2.2\n" ); + fprintf( stdout, " EVS RTP Payload Format or rtpdump files containing TS26.253 Annex A\n" ); + fprintf( stdout, " IVAS RTP Payload Format. The SDP parameter hf_only is required.\n" ); + fprintf( stdout, " Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.\n" ); + fprintf( stdout, "-PiDataFile PF Log the timestampped PI data.\n" ); +#else fprintf( stdout, "-VOIP_hf_only=1 : VoIP mode: EVS RTP Payload Format hf_only=1 in rtpdump\n" ); fprintf( stdout, " The decoder may read rtpdump files containing TS26.445 Annex A.2.2\n" ); fprintf( stdout, " EVS RTP Payload Format. The SDP parameter hf_only is required.\n" ); fprintf( stdout, " Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.\n" ); +#endif #ifdef SUPPORT_JBM_TRACEFILE fprintf( stdout, "-Tracefile TF : VoIP mode: Generate trace file named TF. Requires -no_delay_cmp to\n" ); fprintf( stdout, " be enabled so that trace contents remain in sync with audio output.\n" ); @@ -2654,12 +2686,18 @@ static ivas_error decodeVoIP( int16_t delayNumSamples = -1; int32_t delayTimeScale = -1; int16_t i; +#ifdef IVAS_RTPDUMP + IVAS_RTP ivasRtp = { 0 }; +#else FILE *f_rtpstream = NULL; EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; +#endif uint8_t *auPtr = NULL; +#ifndef IVAS_RTPDUMP bool isAMRWB_IOmode; uint16_t frameTypeIndex; +#endif bool qBit; IVAS_DEC_BS_FORMAT bsFormat = IVAS_DEC_BS_UNKOWN; @@ -2695,11 +2733,20 @@ static ivas_error decodeVoIP( delayNumSamples_orig[0] = -1; +#ifndef IVAS_RTPDUMP rtpdumpDepacker.rtpdump = NULL; +#endif switch ( arg.inputFormat ) { case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: +#ifdef IVAS_RTPDUMP + if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_READER_Init(): %d\n", error ); + goto cleanup; + } +#else f_rtpstream = fopen( arg.inputBitstreamFilename, "r" ); if ( f_rtpstream == NULL ) @@ -2714,6 +2761,7 @@ static ivas_error decodeVoIP( fprintf( stderr, "error in EVS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError ); goto cleanup; } +#endif break; case IVAS_DEC_INPUT_FORMAT_G192: auPtr = au; @@ -2755,12 +2803,20 @@ static ivas_error decodeVoIP( else { auPtr = au; /* might have been set to RTP packet in prev call */ +#ifdef IVAS_RTPDUMP + error = IVAS_RTP_ReadNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); +#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSize ); +#endif /* EVS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; } +#ifdef IVAS_RTPDUMP + if ( error != IVAS_ERR_OK ) +#else if ( error != IVAS_ERR_OK || rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) +#endif { fprintf( stderr, "failed to read first RTP packet\n" ); goto cleanup; @@ -2931,19 +2987,34 @@ static ivas_error decodeVoIP( else { auPtr = au; /* might have been set to RTP packet in prev call */ +#ifdef IVAS_RTPDUMP + error = IVAS_RTP_ReadNextFrame( &ivasRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + + /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ + rtpTimeStamp = rtpTimeStamp / 16; +#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSize ); /* EVS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; +#endif } +#ifdef IVAS_RTPDUMP + if ( error == IVAS_ERR_END_OF_FILE ) +#else if ( error == IVAS_ERR_END_OF_FILE || rtpdumpDepackerError == EVS_RTPDUMP_DEPACKER_EOF ) +#endif { /* finished reading */ nextPacketRcvTime_ms = (uint32_t) -1; } +#ifdef IVAS_RTPDUMP + else if ( error != IVAS_ERR_OK ) +#else else if ( error != IVAS_ERR_OK || rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) +#endif { fprintf( stderr, "\nError in BS_Reader_ReadVoipFrame_compact, error code: %d\n", error ); goto cleanup; @@ -3285,7 +3356,11 @@ static ivas_error decodeVoIP( cleanup: +#ifdef IVAS_RTPDUMP + IVAS_RTP_Term( &ivasRtp ); +#else EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); +#endif AudioFileWriter_close( &afWriter ); JbmOffsetFileWriter_close( &jbmOffsetWriter ); #ifdef SUPPORT_JBM_TRACEFILE diff --git a/apps/encoder.c b/apps/encoder.c index 2a8ef469f..122875635 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -44,6 +44,10 @@ #include "jbm_file_reader.h" #include "masa_file_reader.h" #include "wmc_auto.h" +#ifdef IVAS_RTPDUMP +#include "rotation_file_reader.h" +#include "ivas_rtp_file.h" +#endif #ifdef DEBUG_FORCE_DIR /* Windows does not define the S_ISREG and S_ISDIR macros in stat.h, so we do. @@ -155,6 +159,12 @@ typedef struct #endif bool pca; bool ism_extended_metadata; +#ifdef IVAS_RTPDUMP + bool rtpdumpOutput; + uint32_t numFramesPerPacket; + char *sceneOrientationTrajFileName; + char *deviceOrientationTrajFileName; +#endif } EncArguments; @@ -198,6 +208,10 @@ int main( MasaFileReader *masaReader = NULL; IsmFileReader *ismReaders[IVAS_MAX_NUM_OBJECTS] = { NULL, NULL, NULL, NULL }; int16_t *pcmBuf = NULL; +#ifdef IVAS_RTPDUMP + RotFileReader *sceneOrientationFileReader = NULL; + RotFileReader *deviceOrientationFileReader = NULL; +#endif #ifdef DEBUGGING FILE *f_forcedModeProfile = NULL; #endif @@ -207,6 +221,11 @@ int main( reset_mem( USE_BYTES ); #endif +#ifdef IVAS_RTPDUMP + uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; + IVAS_RTP ivasRtp = { 0 }; +#endif + /*------------------------------------------------------------------------------------------* * Parse command-line arguments *------------------------------------------------------------------------------------------*/ @@ -233,7 +252,11 @@ int main( const BS_WRITER_FORMAT bsWriterFormat = arg.mimeOutput ? BS_WRITER_FORMAT_MIME : BS_WRITER_FORMAT_G192; +#ifdef IVAS_RTPDUMP + if ( !arg.rtpdumpOutput && BS_Writer_Open_filename( &hBsWriter, arg.outputBitstreamFilename, bsWriterFormat ) != IVAS_ERR_OK ) +#else if ( BS_Writer_Open_filename( &hBsWriter, arg.outputBitstreamFilename, bsWriterFormat ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nCan't open %s\n\n", arg.outputBitstreamFilename ); goto cleanup; @@ -591,6 +614,47 @@ int main( } } +#ifdef IVAS_RTPDUMP + /*------------------------------------------------------------------------------------------* + * RTPDump + *------------------------------------------------------------------------------------------*/ + + if ( arg.rtpdumpOutput ) + { + if ( ( error = IVAS_RTP_WRITER_Init( &ivasRtp, arg.outputBitstreamFilename, arg.numFramesPerPacket ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open output bitstream file for RTP output %s \n\n", arg.outputBitstreamFilename ); + goto cleanup; + } + } + + /*------------------------------------------------------------------------------------------* + * Open scene orientation file + *------------------------------------------------------------------------------------------*/ + + if ( arg.sceneOrientationTrajFileName != NULL ) + { + if ( ( error = RotationFileReader_open( arg.sceneOrientationTrajFileName, &sceneOrientationFileReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open scene orientation file %s \n\n", arg.sceneOrientationTrajFileName ); + goto cleanup; + } + } + + /*------------------------------------------------------------------------------------------* + * Open device orientation file + *------------------------------------------------------------------------------------------*/ + + if ( arg.deviceOrientationTrajFileName != NULL ) + { + if ( ( error = RotationFileReader_open( arg.deviceOrientationTrajFileName, &deviceOrientationFileReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open device orientation file %s \n\n", arg.deviceOrientationTrajFileName ); + goto cleanup; + } + } +#endif + int16_t numSamplesRead = 0; uint16_t bitStream[IVAS_MAX_BITS_PER_FRAME]; uint16_t numBits = 0; @@ -755,18 +819,78 @@ int main( } /* *** Encode one frame *** */ - if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, pcmBuf, pcmBufSize, bitStream, &numBits ) ) != IVAS_ERR_OK ) +#ifdef IVAS_RTPDUMP + if ( ivasRtp.hPack ) { - fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); - goto cleanup; - } + bool isMono = ( arg.inputFormat == IVAS_ENC_INPUT_MONO ); + bool forcePacket = ( numSamplesRead < pcmBufSize ); /* If EoF force Packet generation */ + + ivasRtp.nWrittenPiData = 0; + + /* scene orientation */ + if ( sceneOrientationFileReader ) + { + PIDATA_TS *piDataTs = &ivasRtp.piData[ivasRtp.nWrittenPiData++]; + IVAS_PIDATA_ORIENTATION *scene = &piDataTs->data.scene; + + memset( piDataTs, 0, sizeof( PIDATA_TS ) ); + scene->size = sizeof( IVAS_PIDATA_ORIENTATION ); + scene->piDataType = IVAS_PI_SCENE_ORIENTATION; + + if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &scene->orientation, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading scene orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( sceneOrientationFileReader ) ); + goto cleanup; + } + } + + /* device orientation */ + if ( deviceOrientationFileReader ) + { + PIDATA_TS *piDataTs = &ivasRtp.piData[ivasRtp.nWrittenPiData++]; + IVAS_PIDATA_ORIENTATION *device = &piDataTs->data.deviceUnCompensated; + + memset( piDataTs, 0, sizeof( PIDATA_TS ) ); + device->size = sizeof( IVAS_PIDATA_ORIENTATION ); + device->piDataType = IVAS_PI_DEVICE_ORIENTATION_COMPENSATED; - /* write bitstream */ - if ( ( error = BS_Writer_WriteFrame_short( hBsWriter, bitStream, numBits, totalBitrate ) ) != IVAS_ERR_OK ) + if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &device->orientation, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading device orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( deviceOrientationFileReader ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_ENC_EncodeFrameToCompact( hIvasEnc, pcmBuf, pcmBufSize, au, &numBits ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( error = IVAS_RTP_WriteNextFrame( &ivasRtp, au, numBits, isMono, forcePacket ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while pushing audio frame to RTP pack\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + else { - fprintf( stderr, "\nBS_Writer_WriteFrame_short failed, error code %d\n\n", error ); - goto cleanup; +#endif + if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, pcmBuf, pcmBufSize, bitStream, &numBits ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + /* write bitstream */ + if ( ( error = BS_Writer_WriteFrame_short( hBsWriter, bitStream, numBits, totalBitrate ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nBS_Writer_WriteFrame_short failed, error code %d\n\n", error ); + goto cleanup; + } +#ifdef IVAS_RTPDUMP } +#endif frame++; if ( !arg.quietModeEnabled ) @@ -835,6 +959,20 @@ cleanup: fclose( f_bitrateProfile ); } +#ifdef IVAS_RTPDUMP + if ( sceneOrientationFileReader ) + { + RotationFileReader_close( &sceneOrientationFileReader ); + } + + if ( deviceOrientationFileReader ) + { + RotationFileReader_close( &deviceOrientationFileReader ); + } + + IVAS_RTP_Term( &ivasRtp ); +#endif + IVAS_ENC_Close( &hIvasEnc ); #ifdef WMOPS @@ -890,6 +1028,11 @@ static bool parseCmdlIVAS_enc( arg->mimeOutput = false; arg->ism_extended_metadata = false; arg->complexityLevel = IVAS_ENC_COMPLEXITY_LEVEL_THREE; +#ifdef IVAS_RTPDUMP + arg->rtpdumpOutput = false; + arg->sceneOrientationTrajFileName = NULL; + arg->deviceOrientationTrajFileName = NULL; +#endif #ifdef DEBUGGING arg->forcedMode = IVAS_ENC_FORCE_UNFORCED; arg->forcedModeFile = NULL; @@ -1668,6 +1811,72 @@ static bool parseCmdlIVAS_enc( i++; } +#ifdef IVAS_RTPDUMP + /*-----------------------------------------------------------------* + * RTPDump output + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-RTPDUMP" ) == 0 ) + { + i++; + arg->rtpdumpOutput = true; + if ( i < argc - 4 ) + { + if ( !is_digits_only( argv[i] ) ) + { + arg->numFramesPerPacket = 1; /* Default to 1 frame per packet */ + } + else + { + arg->numFramesPerPacket = atoi( argv[i++] ); + if ( arg->numFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET ) + { + fprintf( stderr, "numFramesPerPacket(%d) exceeds max frames per packet (%d) \n", arg->numFramesPerPacket, IVAS_MAX_FRAMES_PER_RTP_PACKET ); + arg->numFramesPerPacket = 1; + } + } + } + fprintf( stdout, "Output format: RTPDump using %d frames/packet \n", arg->numFramesPerPacket ); + } + + /*-----------------------------------------------------------------* + * Scene orientation + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-SCENE_ORIENTATION" ) == 0 ) + { + i++; + if ( argc - i <= 4 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: Scene orientation file name not specified!\n\n" ); + usage_enc(); + return false; + } + + arg->sceneOrientationTrajFileName = argv[i]; + i++; + } + + /*-----------------------------------------------------------------* + * Device orientation + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-DEVICE_ORIENTATION" ) == 0 ) + { + i++; + if ( argc - i <= 4 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: Device orientation file name not specified!\n\n" ); + usage_enc(); + return false; + } + + arg->deviceOrientationTrajFileName = argv[i]; + i++; + } + +#endif + /*-----------------------------------------------------------------* * Option not recognized *-----------------------------------------------------------------*/ @@ -1880,6 +2089,14 @@ static void usage_enc( void ) #endif fprintf( stdout, "-q : Quiet mode, no frame counters\n" ); fprintf( stdout, " default is deactivated\n" ); +#ifdef IVAS_RTPDUMP + fprintf( stdout, "-rtpdump : RTPDump output, hf_only=1 by default. The encoder will packetize the \n" ); + fprintf( stdout, " bitstream frames into TS26.253 Annex A IVAS RTP Payload Format packets and \n" ); + fprintf( stdout, " writes those to the output file. In EVS mono operating mode, TS26.445 Annex A.2.2 \n" ); + fprintf( stdout, " EVS RTP Payload Format is used. Optional N represents number of frames per RTP packet\n" ); + fprintf( stdout, "-scene_orientation : Scene orientation trajectory file. Only used with rtpdump output.\n" ); + fprintf( stdout, "-device_orientation : Device orientation trajectory file. Only used with rtpdump output.\n" ); +#endif fprintf( stdout, "\n" ); return; diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index 1ba3b52ae..3b49667d4 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -147,6 +147,14 @@ typedef enum IVAS_ERR_LC3PLUS_INVALID_BITRATE, IVAS_ERR_INVALID_SPLIT_REND_CONFIG, + /*----------------------------------------* + * rtp errors * + *----------------------------------------*/ + IVAS_ERR_RTP_UNDERFLOW = 0x7000, + IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, + IVAS_ERR_RTP_UNPACK_PI_DATA, + IVAS_ERR_RTP_UNSUPPORTED_FRAME, + /*----------------------------------------* * unknown error * *----------------------------------------*/ @@ -286,6 +294,22 @@ static inline const char *ivas_error_to_string( ivas_error error_code ) { return "data error"; } + if ( ( error_code & 0x7000 ) == 0x7000 ) + { + switch ( error_code ) + { + case IVAS_ERR_RTP_UNDERFLOW: + return "RTP Undeflow in reading frame/packet"; + case IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE: + return "Output buffer size is insufficient"; + case IVAS_ERR_RTP_UNPACK_PI_DATA: + return "Unpacking PI data failure"; + case IVAS_ERR_RTP_UNSUPPORTED_FRAME: + return "Unsupported RTP frame"; + default: + return "rtp error"; + } + } return "Unknown error"; } diff --git a/lib_com/options.h b/lib_com/options.h index 37fffd13e..58e866a18 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -135,6 +135,10 @@ #define FIX_2140_OBJECT_EDITING_SANITIZER_ISSUES /* Nokia: Issue 2140, fixes three different sanitizer issues persisting in object editing code. */ #define NONBE_FIX_1172_OBJ_EDIT_JBM /* VA: issue 1172: fix OMASA object editing in JBM */ +// RTPDUMP porting +#define RTP_S4_251135_CR26253_0016_REV1 /* RTP Pack/Unpack API corresponding to CR 26253 */ +#define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ + /* #################### End BASOP porting switches ############################ */ #endif diff --git a/lib_util/g192.c b/lib_util/g192.c index 898e9753d..99c0b84dc 100644 --- a/lib_util/g192.c +++ b/lib_util/g192.c @@ -482,7 +482,11 @@ G192_ERROR G192_WriteVoipFrame_short( const uint16_t *serial, const int16_t numBits, uint16_t const rtpSequenceNumber, +#ifdef IVAS_RTPDUMP + uint32_t const rtpTimeStamp, +#else uint16_t const rtpTimeStamp, +#endif uint32_t const rcvTime_ms ) { int16_t G192_HEADER[2], G192_DATA[IVAS_MAX_BITS_PER_FRAME]; diff --git a/lib_util/g192.h b/lib_util/g192.h index 62eeaae8f..e2f28a0f6 100644 --- a/lib_util/g192.h +++ b/lib_util/g192.h @@ -93,7 +93,11 @@ G192_ERROR G192_Writer_Open_filename( G192_HANDLE *phG192, const char *filename G192_ERROR G192_WriteFrame( G192_HANDLE const hG192, const uint16_t *serial, const int16_t numBits ); +#ifdef IVAS_RTPDUMP +G192_ERROR G192_WriteVoipFrame_short( G192_HANDLE const hG192, const uint16_t *serial, const int16_t num_bits, uint16_t const rtpSequenceNumber, uint32_t const rtpTimeStamp, uint32_t const rcvTime_ms ); +#else G192_ERROR G192_WriteVoipFrame_short( G192_HANDLE const hG192, const uint16_t *serial, const int16_t num_bits, uint16_t const rtpSequenceNumber, uint16_t const rtpTimeStamp, uint32_t const rcvTime_ms ); +#endif G192_ERROR G192_Writer_Close( G192_HANDLE *phG192 ); diff --git a/lib_util/ivas_bpool.c b/lib_util/ivas_bpool.c new file mode 100644 index 000000000..9db909f53 --- /dev/null +++ b/lib_util/ivas_bpool.c @@ -0,0 +1,153 @@ +/****************************************************************************************************** + + (C) 2022-2025 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 "ivas_bpool.h" +#include "ivas_error_utils.h" +#include "mutex.h" + +struct BPOOL +{ + mtx_t lock; + uint32_t bufferSize; + uint32_t numBuffers; + uint32_t numFreeBuffers; + void **freeBuffers; +}; + +ivas_error BPOOL_Create( BPOOL_HANDLE *pHandle, size_t bufferSize, uint32_t numBuffers ) +{ + uint32_t n; + uint8_t *base = NULL; + BPOOL_HANDLE handle; + size_t allocSize = sizeof( struct BPOOL ); + + if ( pHandle == NULL ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer to Buffer Pool Handle" ); + } + + *pHandle = NULL; + + allocSize += bufferSize * numBuffers; /* pool memory */ + allocSize += sizeof( void * ) * numBuffers; /* free buffers stack */ + + base = calloc( allocSize, sizeof( uint8_t ) ); + if ( base == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Couldn't allocate Buffer pool" ); + } + + handle = (BPOOL_HANDLE) base; + base += sizeof( struct BPOOL ); + + mtx_init( &handle->lock, 0 ); + handle->bufferSize = bufferSize; + handle->numBuffers = numBuffers; + handle->numFreeBuffers = numBuffers; + handle->freeBuffers = (void **) base; + base += ( sizeof( void * ) * numBuffers ); + for ( n = 0; n < numBuffers; n++ ) + { + handle->freeBuffers[n] = base; + base += bufferSize; + } + + *pHandle = handle; + return IVAS_ERR_OK; +} + +void BPOOL_Destroy( BPOOL_HANDLE *pHandle ) +{ + if ( ( pHandle != NULL ) && ( *pHandle != NULL ) ) + { + mtx_destroy( &( *pHandle )->lock ); + free( *pHandle ); + *pHandle = NULL; + } +} + +ivas_error BPOOL_GetBuffer( BPOOL_HANDLE handle, void **dataPtr ) +{ + uint32_t idx = 0; + bool isFree = false; + + if ( handle == NULL || dataPtr == NULL ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer args in GetBuffer" ); + } + + mtx_lock( &handle->lock ); + isFree = ( handle->numFreeBuffers > 0 ); + if ( isFree ) + { + idx = --handle->numFreeBuffers; + } + mtx_unlock( &handle->lock ); + + if ( !isFree ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow, no free buffers in pool" ); + } + + *dataPtr = handle->freeBuffers[idx]; + return IVAS_ERR_OK; +} + +/* return the buffer back to pool */ +ivas_error BPOOL_FreeBuffer( BPOOL_HANDLE handle, void *dataPtr ) +{ + uint32_t idx; + + if ( handle == NULL || dataPtr == NULL ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer args in GetBuffer" ); + } + + mtx_lock( &handle->lock ); + idx = handle->numFreeBuffers++; + mtx_unlock( &handle->lock ); + + handle->freeBuffers[idx] = dataPtr; + + return IVAS_ERR_OK; +} + +/* return the number of free buffers available atm in the pool */ +uint32_t BPOOL_AvailableBuffers( BPOOL_HANDLE handle ) +{ + uint32_t numFreeBuffers; + mtx_lock( &handle->lock ); + numFreeBuffers = handle->numFreeBuffers; + mtx_unlock( &handle->lock ); + return numFreeBuffers; +} diff --git a/lib_util/ivas_bpool.h b/lib_util/ivas_bpool.h new file mode 100644 index 000000000..30cf4962b --- /dev/null +++ b/lib_util/ivas_bpool.h @@ -0,0 +1,57 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_BPOOL_H +#define IVAS_BPOOL_H + +#include +#include "common_api_types.h" + +/* Forward declaraiton of opaque buffer pool handle */ +typedef struct BPOOL *BPOOL_HANDLE; + +/* Create a buffer pool with given element size and max number of buffers */ +ivas_error BPOOL_Create( BPOOL_HANDLE *pHandle, size_t bufferSize, uint32_t numBuffers ); + +/* Destroy the buffer pool and all free-up all allocated memory */ +void BPOOL_Destroy( BPOOL_HANDLE *pHandle ); + +/* request a buffer from the pool */ +ivas_error BPOOL_GetBuffer( BPOOL_HANDLE handle, void **dataPtr ); + +/* return the buffer back to pool */ +ivas_error BPOOL_FreeBuffer( BPOOL_HANDLE handle, void *dataPtr ); + +/* return the number of free buffers available atm in the pool */ +uint32_t BPOOL_AvailableBuffers( BPOOL_HANDLE handle ); + +#endif /* IVAS_BPOOL_H */ diff --git a/lib_util/ivas_queue.c b/lib_util/ivas_queue.c new file mode 100644 index 000000000..b17cf3e21 --- /dev/null +++ b/lib_util/ivas_queue.c @@ -0,0 +1,137 @@ +/****************************************************************************************************** + + (C) 2022-2025 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 "ivas_queue.h" +#include "ivas_error_utils.h" +#include "mutex.h" + +struct QUEUE +{ + mtx_t lock; + NODE *front; + NODE *back; + uint32_t size; +}; + +ivas_error QUEUE_Create( QUEUE_HANDLE *pHandle ) +{ + QUEUE_HANDLE handle = NULL; + *pHandle = NULL; + + if ( pHandle == NULL ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer to Buffer Pool Handle" ); + } + + handle = calloc( 1, sizeof( struct QUEUE ) ); + if ( handle != NULL ) + { + mtx_init( &handle->lock, 0 ); + } + + *pHandle = handle; + return IVAS_ERR_OK; +} + +/* Destroy the queue and free-up all allocated memory */ +void QUEUE_Destroy( QUEUE_HANDLE *pHandle ) +{ + if ( ( pHandle != NULL ) && ( *pHandle != NULL ) ) + { + mtx_destroy( &( *pHandle )->lock ); + free( *pHandle ); + *pHandle = NULL; + } +} + +void QUEUE_Push( QUEUE_HANDLE handle, NODE *node ) +{ + mtx_lock( &handle->lock ); + if ( handle->back == NULL ) + { + handle->front = node; + } + else + { + handle->back->next = node; + } + handle->back = node; + handle->size++; + mtx_unlock( &handle->lock ); +} + +/* return the buffer back to pool */ +NODE *QUEUE_Pop( QUEUE_HANDLE handle ) +{ + NODE *node; + mtx_lock( &handle->lock ); + node = handle->front; + handle->front = handle->front->next; + if ( NULL == handle->front ) + { + handle->back = NULL; + } + handle->size--; + mtx_unlock( &handle->lock ); + return node; +} + +/* returns the first element in the queue */ +NODE *QUEUE_Front( QUEUE_HANDLE handle ) +{ + NODE *node; + mtx_lock( &handle->lock ); + node = handle->front; + mtx_unlock( &handle->lock ); + return node; +} + +/* returns the last element in the queue */ +NODE *QUEUE_Back( QUEUE_HANDLE handle ) +{ + NODE *node; + mtx_lock( &handle->lock ); + node = handle->back; + mtx_unlock( &handle->lock ); + return node; +} + +/* return the number of elements in the queue */ +size_t QUEUE_Size( QUEUE_HANDLE handle ) +{ + uint32_t numNodes; + mtx_lock( &handle->lock ); + numNodes = handle->size; + mtx_unlock( &handle->lock ); + return numNodes; +} diff --git a/lib_util/ivas_queue.h b/lib_util/ivas_queue.h new file mode 100644 index 000000000..1c6b77504 --- /dev/null +++ b/lib_util/ivas_queue.h @@ -0,0 +1,68 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_QUEUE_H +#define IVAS_QUEUE_H + +#include +#include "common_api_types.h" + +typedef struct NODE +{ + struct NODE *next; +} NODE; + +/* Forward declaraiton of opaque queue handle */ +typedef struct QUEUE *QUEUE_HANDLE; + +/* Create a queue with given element size and max number of buffers */ +ivas_error QUEUE_Create( QUEUE_HANDLE *pHandle ); + +/* Destroy the queue and all free-up all allocated memory */ +void QUEUE_Destroy( QUEUE_HANDLE *pHandle ); + +/* push a buffer to a queue */ +void QUEUE_Push( QUEUE_HANDLE handle, NODE *data ); + +/* pop the buffer from the front */ +NODE *QUEUE_Pop( QUEUE_HANDLE handle ); + +/* returns the first element from the front */ +NODE *QUEUE_Front( QUEUE_HANDLE handle ); + +/* returns the last element from the back */ +NODE *QUEUE_Back( QUEUE_HANDLE handle ); + +/* return the number of elements in the queue */ +size_t QUEUE_Size( QUEUE_HANDLE handle ); + +#endif /* IVAS_QUEUE_H */ diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h new file mode 100644 index 000000000..06c56cd70 --- /dev/null +++ b/lib_util/ivas_rtp_api.h @@ -0,0 +1,591 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_API_H +#define IVAS_RTP_API_H + +#include +#include +#include "common_api_types.h" + +/* + * +-----------------------+---------------------+--------------------+----------+ + * | RTP Header (+ HDREXT) | payload header | frame data | PI data | + * +-----------------------+---------------------+--------------------+----------+ + * \--------------------\ /------------------------------/ + * IVAS payload + * + * This api provides a mechanism to generate/unpack the IVAS payload. The RTP Header + * and header extension fields must be handled by caller. + * + * IVAS General Payload structure + * =============================== + * + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * H H H H F H + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1| T | D |1| ET1 |x x x x|1| ET2 |x x x x|0|1|0 1| BR |1| ET3 |x x x x|… + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \--------------/\--------------/\--------------/\--------------/\--------------/ + * Initial E byte Subsqnt Ebyte1 Subsqnt Ebyte2 ToC1 Subsqnt Ebyte3 + * + * H F + * +-+-+-+-+-+-+-+-+-------------------------- ---+-------------------- ---+-------+ + * …|0|0|0 1| BR | IVAS frame 1 ... | IVAS frame 2 ... |PI data| + * +-+-+-+-+-+-+-+-+-------------------------- ---+-------------------- ---+-------+ + * \--------------/ + * ToC2 + * + */ + +#define IVAS_MAX_FRAMES_PER_RTP_PACKET ( 8 ) /* Max supported frames per RTP packet */ + +/* It is difficult to decide the RTP Payload buffer's capacity intrinsically however computing + * using the maximum frame size and all currently supported PI data present gives a crude + * estimate or RTP packet size per frame. The additional PI data is assumed to add upto a 20% + * overhead in bitrate for the computation. + */ +#define NOMINAL_BUFFER_SIZE( numFramesPerPacket ) ( ( IVAS_MAX_BITS_PER_FRAME + ( IVAS_MAX_BITS_PER_FRAME / 5 ) ) * ( numFramesPerPacket ) / 8 ) + +#define DEFAULT_MAX_PACKET_BYTES ( 1400 ) /* Typical MTU size of 4G/5G Cellular Interfaces */ + +#define NO_BITRATE_REQ ( 0u ) /* If no bitrate is requested from remote */ + +/* IVAS Codec Types */ +typedef enum +{ + IVAS_RTP_EVS, /* EVS */ + IVAS_RTP_IVAS /* IVAS */ +} IVAS_RTP_CODEC; + +/* IVAS Bandwidth Requests */ +typedef enum +{ + IVAS_BANDWIDTH_NB, /* Narrowband */ + IVAS_BANDWIDTH_WB, /* Wideband*/ + IVAS_BANDWIDTH_SWB, /* SuperWideband*/ + IVAS_BANDWIDTH_FB, /* Fullband */ + IVAS_BANDWIDTH_NO_REQ, /* No Preference */ +} IVAS_RTP_BANDWIDTH; + +/* Channel Aware Coding */ +typedef enum +{ + IVAS_RTP_CA_LO_O2, /* FER=LO, OFFSET=2 */ + IVAS_RTP_CA_LO_O3, /* FER=LO, OFFSET=3 */ + IVAS_RTP_CA_LO_O5, /* FER=LO, OFFSET=5 */ + IVAS_RTP_CA_LO_O7, /* FER=LO, OFFSET=7 */ + IVAS_RTP_CA_HI_O2, /* FER=HI, OFFSET=2 */ + IVAS_RTP_CA_HI_O3, /* FER=HI, OFFSET=3 */ + IVAS_RTP_CA_HI_O5, /* FER=HI, OFFSET=5 */ + IVAS_RTP_CA_HI_O7, /* FER=HI, OFFSET=7 */ + IVAS_RTP_CA_NO_REQ /* No request */ +} IVAS_RTP_CA_MODE; + +/* Coded Format Requests */ +typedef enum +{ + IVAS_FMT_STEREO, /* Stereo */ + IVAS_FMT_SBA, /* Scene Based Audio */ + IVAS_FMT_MASA, /* Metadata Assisted Spatial Audio */ + IVAS_FMT_ISM, /* Object Based Audio */ + IVAS_FMT_MC, /* Multichannel Audio */ + IVAS_FMT_OMASA, /* Object + MASA */ + IVAS_FMT_OSBA, /* Object + SBA */ + IVAS_FMT_NO_REQ, /* No preference */ +} IVAS_RTP_FORMAT; + +#ifdef RTP_S4_251135_CR26253_0016_REV1 +/* Coded Subformat Requests */ +typedef enum +{ + IVAS_SUBFMT_FOA_PLANAR, + IVAS_SUBFMT_HOA2_PLANAR, + IVAS_SUBFMT_HOA3_PLANAR, + IVAS_SUBFMT_FOA, + IVAS_SUBFMT_HOA2, + IVAS_SUBFMT_HOA3, + IVAS_SUBFMT_MASA1, + IVAS_SUBFMT_MASA2, + IVAS_SUBFMT_ISM1, + IVAS_SUBFMT_ISM2, + IVAS_SUBFMT_ISM3, + IVAS_SUBFMT_ISM4, + IVAS_SUBFMT_ISM1_EXTENDED_METADATA, + IVAS_SUBFMT_ISM2_EXTENDED_METADATA, + IVAS_SUBFMT_ISM3_EXTENDED_METADATA, + IVAS_SUBFMT_ISM4_EXTENDED_METADATA, + IVAS_SUBFMT_MC_5_1, + IVAS_SUBFMT_MC_7_1, + IVAS_SUBFMT_MC_5_1_2, + IVAS_SUBFMT_MC_5_1_4, + IVAS_SUBFMT_MC_7_1_4, + IVAS_SUBFMT_RESERVED_21, + IVAS_SUBFMT_RESERVED_22, + IVAS_SUBFMT_RESERVED_23, + IVAS_SUBFMT_RESERVED_24, + IVAS_SUBFMT_RESERVED_25, + IVAS_SUBFMT_RESERVED_26, + IVAS_SUBFMT_RESERVED_27, + IVAS_SUBFMT_RESERVED_28, + IVAS_SUBFMT_RESERVED_29, + IVAS_SUBFMT_RESERVED_30, + IVAS_SUBFMT_RESERVED_31, + IVAS_SUBFMT_OMASA_ISM1_1TC, + IVAS_SUBFMT_OMASA_ISM2_1TC, + IVAS_SUBFMT_OMASA_ISM3_1TC, + IVAS_SUBFMT_OMASA_ISM4_1TC, + IVAS_SUBFMT_OMASA_ISM1_2TC, + IVAS_SUBFMT_OMASA_ISM2_2TC, + IVAS_SUBFMT_OMASA_ISM3_2TC, + IVAS_SUBFMT_OMASA_ISM4_2TC, + IVAS_SUBFMT_OSBA_ISM1_FOA_PLANAR, + IVAS_SUBFMT_OSBA_ISM2_FOA_PLANAR, + IVAS_SUBFMT_OSBA_ISM3_FOA_PLANAR, + IVAS_SUBFMT_OSBA_ISM4_FOA_PLANAR, + IVAS_SUBFMT_OSBA_ISM1_FOA, + IVAS_SUBFMT_OSBA_ISM2_FOA, + IVAS_SUBFMT_OSBA_ISM3_FOA, + IVAS_SUBFMT_OSBA_ISM4_FOA, + IVAS_SUBFMT_OSBA_ISM1_HOA2_PLANAR, + IVAS_SUBFMT_OSBA_ISM2_HOA2_PLANAR, + IVAS_SUBFMT_OSBA_ISM3_HOA2_PLANAR, + IVAS_SUBFMT_OSBA_ISM4_HOA2_PLANAR, + IVAS_SUBFMT_OSBA_ISM1_HOA2, + IVAS_SUBFMT_OSBA_ISM2_HOA2, + IVAS_SUBFMT_OSBA_ISM3_HOA2, + IVAS_SUBFMT_OSBA_ISM4_HOA2, + IVAS_SUBFMT_OSBA_ISM1_HOA3_PLANAR, + IVAS_SUBFMT_OSBA_ISM2_HOA3_PLANAR, + IVAS_SUBFMT_OSBA_ISM3_HOA3_PLANAR, + IVAS_SUBFMT_OSBA_ISM4_HOA3_PLANAR, + IVAS_SUBFMT_OSBA_ISM1_HOA3, + IVAS_SUBFMT_OSBA_ISM2_HOA3, + IVAS_SUBFMT_OSBA_ISM3_HOA3, + IVAS_SUBFMT_OSBA_ISM4_HOA3, + IVAS_SUBFMT_NO_REQ +} IVAS_RTP_SUBFORMAT; + +/* Split Rendering Requests */ +typedef struct +{ + uint32_t valid : 1; /* is split rendering request valid */ + uint32_t diegetic : 1; /* enabling diegetic support for Split Rendering */ + uint32_t yaw : 1; /* transmission metadata for correction around yaw axis */ + uint32_t pitch : 1; /* transmission metadata for correction around pitch axis */ + uint32_t roll : 1; /* transmission metadata for correction around roll axis */ + uint32_t reserved : 27; /* reserved */ +} IVAS_RTP_SPLITRENDER; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + +/* Remote Requests Types (Keys) */ +typedef enum +{ + IVAS_REQUEST_CODEC, /* Request codec type, value of type IVAS_RTP_CODEC */ + IVAS_REQUEST_BITRATE, /* Request bitrate, value of type uint32_t in kbps */ + IVAS_REQUEST_BANDWIDTH, /* Request bandwidth, value of type IVAS_RTP_BANDWIDTH */ + IVAS_REQUEST_FORMAT, /* Request format, value of type IVAS_RTP_FORMAT */ + IVAS_REQUEST_CA_MODE, /* Request channel awareness, value of type IVAS_RTP_CA_MODE */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_REQUEST_SUBFORMAT, /* Request subFormat, value of type IVAS_RTP_SUBFORMAT */ + IVAS_REQUEST_SR_CONFIG, /* Request spit rendering, value of type IVAS_RTP_SPLITRENDER */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + IVAS_REQUEST_MAX /* Max number of requests */ +} IVAS_RTP_REQUEST_TYPE; + +/* Remote Request Values */ +typedef union +{ + uint32_t bitrate; /* bitrate in kbps when request type is IVAS_REQUEST_BITRATE */ + IVAS_RTP_CODEC codec; /* codec id when request type is IVAS_REQUEST_CODEC */ + IVAS_RTP_BANDWIDTH bandwidth; /* badwidth when request type is IVAS_REQUEST_BANDWIDTH */ + IVAS_RTP_FORMAT formatType; /* format type when request type is IVAS_REQUEST_FORMAT */ + IVAS_RTP_CA_MODE caMode; /* channel aware mode when request type is IVAS_REQUEST_CA_MODE */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SUBFORMAT subFormatType; /* sub-format type when request type is IVAS_REQUEST_SUBFORMAT */ + IVAS_RTP_SPLITRENDER srConfig; /* split rendering config when request type is IVAS_REQUEST_SR_CONFIG */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ +} IVAS_RTP_REQUEST_VALUE; + +/* Template for pi data types, all defined pi data follow this template + * for example scene orientation pi data can be represented as :- + * + * typedef struct { + * size_t size; // sizeof(IVAS_PIDATA_SCENE_ORIENTATION) + * uint32_t piDataType; // IVAS_PI_SCENE_ORIENTATION + * float w, x, y, z; // pi data of scene orientation in quaternions + * } IVAS_PIDATA_SCENE_ORIENTATION; + * + */ +typedef struct +{ + size_t size; /* size of this structure */ + uint32_t piDataType; /* IVAS PI data type */ + uint8_t data[1]; /* Variable length array */ +} IVAS_PIDATA_GENERIC; + +/* Generic data buffer for sending/receiving coded frames / rtp payloads + * data buffer is owned and initialized by caller, rtp api will ensure + * buffer write does not exceed capacity. + */ +typedef struct +{ + size_t capacity; /* allocated size of the data buffer */ + size_t length; /* length of the initialized data in the buffer */ + uint8_t *buffer; /* pointer to the payload buffer */ +} IVAS_DATA_BUFFER; + +#ifdef RTP_S4_251135_CR26253_0016_REV1 +typedef enum +{ + IVAS_SR_TRANSPORT_LCLD, + IVAS_SR_TRANSPORT_LC3PLUS +} IVAS_RTP_SR_TRANSPORT; + +typedef struct +{ + bool valid; /* Valid Split Rendering Info for/in the ToC */ + bool diegetic; /* SR content digetic */ + IVAS_RTP_SR_TRANSPORT codec; /* SR Transport Codec used*/ +} IVAS_RTP_SR_INFO; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + +/**********************************************/ +/* IVAS RTP PACKER API */ +/**********************************************/ + +/* Forward declaration of rtp pack/unpack handle types */ +typedef struct IVAS_RTP_PACK *IVAS_RTP_PACK_HANDLE; /* rtp packer handle type */ + +/* Initial configuration for rtp packer + * - maxFramesPerPacket is used to define if more than one frame should be packed + * in the same rtp packet. If zero, will use IVAS_MAX_FRAMES_PER_RTP_PACKET. + */ +typedef struct +{ + uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */ +} IVAS_RTP_PACK_CONFIG; + +/* Open an instance of the RTP packer and return a handle to rtp packer on success + * error code is retured on failure and handle is set to NULL + */ +ivas_error IVAS_RTP_PACK_Open( + IVAS_RTP_PACK_HANDLE *phIvasPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ + const IVAS_RTP_PACK_CONFIG *config /* i : pointer to initial config for RTP Packer */ +); + +/* Close and free an existing instance of rtp packer */ +void IVAS_RTP_PACK_Close( + IVAS_RTP_PACK_HANDLE *phIvasPack /* i/o : pointer to an IVAS rtp packer handle to be closed */ +); + +/* Update the RTP Header structure */ +ivas_error IVAS_RTP_PACK_UpdateHeader( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ + uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */ + uint8_t numCC, /* i : numCC indicates no. of contributing sources */ + uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */ + uint16_t extHeaderId, /* i : extension header ID */ + uint16_t numExtensionBytes, /* i : length of the extension data */ + uint8_t *extData /* i : extension data pointer */ +); + +/* Add requests for remote sender using a key value pair api + * each key must be provided with a corresponding value type + * + * Cross validation of some key,value pairs will not be done + * in this API. E.g. Codec ID and supported bitrates/bandwidths + * will not be performed at this level. + */ +ivas_error IVAS_RTP_PACK_PushRemoteRequest( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ + IVAS_RTP_REQUEST_TYPE reqType, /* i : remote request type */ + IVAS_RTP_REQUEST_VALUE reqValue /* i : value of the requested type */ +); + +/* Push a single IVAS/EVS frame to rtp packer + * + * If multiple frames per RTP packet are desired, multiple frames must be explicitly + * pushed before a call to IVAS_RTP_PACK_GetPayload to generate a rtp payload. + * + * It is possible to have variable frames per packet until maxFramesPerPacket frames + * if IVAS_RTP_PACK_GetPayload is invoked asyncronously w.r.t this api. + * + */ +ivas_error IVAS_RTP_PACK_PushFrame( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ + IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info (NULL if absent) */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */ +); + +/* Get the number of frames in the FiFo currently */ +uint32_t IVAS_RTP_PACK_GetNumFrames( + IVAS_RTP_PACK_HANDLE hIvasPack /* i/o : IVAS rtp packer handle */ +); + +/* Push single PI data to rtp packer + * + * Provide PI data for a current RTP packet. All PI data is locally cached in the packer + * and set to the rtp payload with policy defined in initial configuration during call to + * IVAS_RTP_PACK_GetPayload. + * + */ +ivas_error IVAS_RTP_PACK_PushPiData( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ + const IVAS_PIDATA_GENERIC *data /* i : pointer to the PIData stucture */ +); + +/* Generate a rtp payload using available pushed frames + * + * Available remote requests, pi data and frames will be packed into a rtp payload. The + * capacity field of payload is used to limits the maximum RTP packet size. + * + */ +ivas_error IVAS_RTP_PACK_GetPayload( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ + IVAS_DATA_BUFFER *payload, /* o : encapsulated rtp payload */ + uint32_t *numFramesInPayload /* o : no. of frames in payload */ +); + +/* Generate a rtp packet using available pushed frames + * + * Available remote requests, pi data and frames will be packed into a rtp packet. If no + * frame is pushed before call to this api, NO_DATA_FRAME will be generated + * Takes care of updates to the RTP Header + * + */ +ivas_error IVAS_RTP_PACK_GetPacket( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ + IVAS_DATA_BUFFER *packet, /* o : encapsulated rtp packet */ + uint32_t *numFramesInPacket /* o : no. of frames in packet */ +); + +/**********************************************/ +/* IVAS RTP UNPACKER API */ +/**********************************************/ + +/* Forward declaration of rtp unpack handle types */ +typedef struct IVAS_RTP_UNPACK *IVAS_RTP_UNPACK_HANDLE; /* rtp unpacker handle type */ + +/* Initial configuration for rtp unpacker + * - maxFramesPerPacket is used to define maximum supported frames per rtp packet + * to allow for internal memory allocaton, if zero, will use IVAS_MAX_FRAMES_PER_RTP_PACKET + */ + +typedef struct +{ + uint32_t maxFramesPerPacket; /* maximum no of frame per packet expected during the session */ +} IVAS_RTP_UNPACK_CONFIG; + +/* Open an instance of the RTP unpacker and return a handle to rtp unpacker on success + * error code is retured on failure and handle is set to NULL + */ +ivas_error IVAS_RTP_UNPACK_Open( + IVAS_RTP_UNPACK_HANDLE *phIvasUnpack, /* i/o : rtp unpacker handle */ + const IVAS_RTP_UNPACK_CONFIG *config /* i : initial configuration for rtp unpacker */ +); + +/* Close and free an existing instance of rtp unpacker */ +void IVAS_RTP_UNPACK_Close( + IVAS_RTP_UNPACK_HANDLE *phIvasUnpack /* i/o : IVAS rtp unpacker handle */ +); + +/* Push a received rtp Ivas Payload to unpacker to extract number of frames, pi data and + * any remote request present in the payload. Caller must extract RTP header and header + * extension and feed Ivas Payload alongwith RTP Timestamp and sequence number. + * + * In case of DTX transmission modes, the number of frames in packet will be reduced by + * the number of NO_DATA frame received. All PullFrame calls for non NO_DATA frames shall + * be reported with timestamp jump indicating missing/NO_DATA IVAS frames. + * + * It is important to ensure IVAS_RTP_UNPACK_PushPayload, IVAS_RTP_UNPACK_PullFrame and + * IVAS_RTP_UNPACK_PullNextPiData API are invoked in same thread context or in a thread + * safe manner else a race condition can arise if new packet is pushed while frames/pidata + * are still being pulled out. The IVAS_RTP_UNPACK_PushPayload will gererate an error if + * new paylod is pushed before all frames/pidata are pulled out. + * + * Example usage : - + * ================== + * err = IVAS_RTP_UNPACK_PushPayload(hIvasUnpack, payload, rtpTs, seqNum, + * &nFrames, &nPiData, &reqBitmap); + * if (err != IVAS_ERR_OK) { return err; } + * + * // Read the frames in payload and feed to decoder + * while (nFrames-- > 0) { + * err = IVAS_RTP_UNPACK_PullFrame(hIvasUnpack, &recCodecId, &srInfo, &frame, &frameTs, &seqNum, &SpeechLostIndicated); + * if (err != IVAS_ERR_OK) { return err; } + * err = IVAS_DEC_VoIP_FeedFrame(hIvasDec, frame.buffer, frame.length, seqNum, frameTs, rcvTime, isGoodFrame); + * if (err != IVAS_ERR_OK) { return err; } + * } + * + * // Read PI Data + * while (nPiData-- > 0) { + * err = IVAS_RTP_UNPACK_PullNextPiData(hIvasUnpack, &piData, &piTs); + * if (err != IVAS_ERR_OK) { return err; } + * // handle pi data based on fwd/rev pi data types + * handlePIData(&piData, piTs) + * } + * + * // Read remote requests + * for (req = 0; req < IVAS_REQUEST_MAX; req++) { + * if (reqBitmap & (1u << req)) { + * err = IVAS_RTP_UNPACK_GetRequest(hIvasUnpack, req, &value); + * if (err != IVAS_ERR_OK) { return err; } + * switch(req) { + * case IVAS_REQUEST_CODEC : handleCodec(value.codec); break; + * case IVAS_REQUEST_BITRATE : handleBitrate(value.bitrate); break; + * case IVAS_REQUEST_BANDWIDTH : handleBandwidth(value.bandwidth); break; + * case IVAS_REQUEST_FORMAT : handleFormat(value.formatType); break; + * case IVAS_REQUEST_SUBFORMAT : handleSubFormat(value.subFormatType); break; + * case IVAS_REQUEST_CA_MODE : handleCAModevalue.caMode); break; + * case IVAS_REQUEST_SR_CONFIG : handleSRConfig(value.srConfig); break; + * } + * } + * } + * + */ +ivas_error IVAS_RTP_UNPACK_PushPayload( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + const IVAS_DATA_BUFFER *payload, /* i : received rtp payload */ + uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */ + uint16_t sequenceNumber, /* i : sequence number from rtp header */ + uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */ + uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */ + uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */ +); + +/* Push a received rtp Ivas Packet to unpacker to extract number of frames, pi data and + * any remote request present in the Packet. + * + * In case of DTX transmission modes, the number of frames in packet will be reduced by + * the number of NO_DATA frame received. All PullFrame calls for non NO_DATA frames shall + * be reported with timestamp jump indicating missing/NO_DATA IVAS frames. + * + * It is important to ensure IVAS_RTP_UNPACK_PushPacket, IVAS_RTP_UNPACK_PullFrame and + * IVAS_RTP_UNPACK_PullNextPiData API are invoked in same thread context or in a thread + * safe manner else a race condition can arise if new packet is pushed while frames/pidata + * are still being pulled out. The IVAS_RTP_UNPACK_PushPacket will gererate an error if + * new packet is pushed before all frames/pidata are pulled out. + * + * Example usage : - + * ================== + * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, packet, &nFrames, &nPiData, &reqBitmap); + * if (err != IVAS_ERR_OK) { return err; } + * + * // Read the frames in packet and feed to decoder + * while (nFrames-- > 0) { + * err = IVAS_RTP_UNPACK_PullFrame(hIvasUnpack, &recCodecId, &srInfo, &frame, &frameTs, &seqNum, &SpeechLostIndicated); + * if (err != IVAS_ERR_OK) { return err; } + * err = IVAS_DEC_VoIP_FeedFrame(hIvasDec, frame.buffer, frame.length, seqNum, frameTs, rcvTime, isGoodFrame); + * if (err != IVAS_ERR_OK) { return err; } + * } + * + * // Read PI Data + * while (nPiData-- > 0) { + * err = IVAS_RTP_UNPACK_PullNextPiData(hIvasUnpack, &piData, &piTs); + * if (err != IVAS_ERR_OK) { return err; } + * // handle pi data based on fwd/rev pi data types + * handlePIData(&piData, piTs) + * } + * + * // Read remote requests + * for (req = 0; req < IVAS_REQUEST_MAX; req++) { + * if (reqBitmap & (1u << req)) { + * err = IVAS_RTP_UNPACK_GetRequest(hIvasUnpack, req, &value); + * if (err != IVAS_ERR_OK) { return err; } + * switch(req) { + * case IVAS_REQUEST_CODEC : handleCodec(value.codec); break; + * case IVAS_REQUEST_BITRATE : handleBitrate(value.bitrate); break; + * case IVAS_REQUEST_BANDWIDTH : handleBandwidth(value.bandwidth); break; + * case IVAS_REQUEST_FORMAT : handleFormat(value.formatType); break; + * case IVAS_REQUEST_SUBFORMAT : handleSubFormat(value.subFormatType); break; + * case IVAS_REQUEST_CA_MODE : handleCAModevalue.caMode); break; + * case IVAS_REQUEST_SR_CONFIG : handleSRConfig(value.srConfig); break; + * } + * } + * } + */ +ivas_error IVAS_RTP_UNPACK_PushPacket( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + const IVAS_DATA_BUFFER *packet, /* i : received rtp Packet */ + uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */ + uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */ + uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */ +); + +/* Fetch requests from sender using a key value pair api + * each key must be provided with a corresponding value storage type + * + * On call to IVAS_RTP_UNPACK_PushPayload(), remoteRequestBitmap can be used + * an indicator of new request available this frame + * + */ +ivas_error IVAS_RTP_UNPACK_GetRequest( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp packer handle */ + IVAS_RTP_REQUEST_TYPE type, /* i : remote request type */ + IVAS_RTP_REQUEST_VALUE *value /* o : pointer of the requested type */ +); + +/* Extract a single IVAS/EVS frame from provided rtp payload alongwith rtp timestamp + * and sequence number + * + * If multiple frames per RTP packet are available, multiple calls to IVAS_RTP_UNPACK_PullFrame + * are needed. + */ +ivas_error IVAS_RTP_UNPACK_PullFrame( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + IVAS_RTP_CODEC *receivedCodecId, /* o : Codec type (IVAS/EVS) */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO *srInfo, /* o : Split Rendering Info */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + IVAS_DATA_BUFFER *frameBuffer, /* o : packed frame bitstream for IVAS/EVS */ + int16_t *frameSizeInBits, /* o : exact frame size in bits (AMRWB IO) */ + uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */ + uint16_t *sequenceNumber, /* o : sequence number from rtp header */ + bool *speechLostIndicated, /* o : Is current frame indicated as Lost */ + bool *isAMRWB_IOmode /* o : Is AMRWB_IO mode EVS frame */ +); + +/* Pull a single PI data from rtp unpacker instance for current packet + * Each Pi data is accompanied with a corresponding timestamp + */ +ivas_error IVAS_RTP_UNPACK_PullNextPiData( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + IVAS_PIDATA_GENERIC *data, /* o : output data buffer for the Pi data */ + size_t capacity, /* i : capacity of pi data buffer in bytes */ + uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */ +); + +#endif /* IVAS_RTP_API_H */ diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c new file mode 100644 index 000000000..8555480ef --- /dev/null +++ b/lib_util/ivas_rtp_file.c @@ -0,0 +1,612 @@ +/****************************************************************************************************** + + (C) 2022-2025 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 "ivas_rtp_file.h" +#include "ivas_error_utils.h" + +struct IVAS_RTP_FILE +{ + bool isFileWriter; + FILE *f_rtpstream; +}; + +static ivas_error IvasRtpFile_Open( + const char *filePath, /* i : path to CA config file */ + bool isFileWriter, /* i : instance is a file writer else reader */ + IVAS_RTP_FILE_HANDLE *phRtpFile /* o : pointer to an IVAS file reader handle */ +) +{ + const char *mode = isFileWriter ? "wb" : "rb"; + FILE *f_rtpstream = fopen( filePath, mode ); + if ( f_rtpstream == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_FILE_OPEN, "could not open: %s\n", filePath ); + } + + *phRtpFile = calloc( 1, sizeof( struct IVAS_RTP_FILE ) ); + if ( *phRtpFile != NULL ) + { + ( *phRtpFile )->isFileWriter = isFileWriter; + ( *phRtpFile )->f_rtpstream = f_rtpstream; + } + + return IVAS_ERR_OK; +} + +static ivas_error IvasRtpFile_Close( + IVAS_RTP_FILE_HANDLE *phReader /* i : pointer to an IVAS file reader handle */ +) +{ + if ( phReader != NULL && *phReader != NULL ) + { + if ( ( *phReader )->f_rtpstream != NULL ) + { + fclose( ( *phReader )->f_rtpstream ); + ( *phReader )->f_rtpstream = NULL; + } + free( *phReader ); + *phReader = NULL; + } + + return IVAS_ERR_OK; +} + +static ivas_error IvasRtpFile_Write( + IVAS_RTP_FILE_HANDLE hRtpFile, /* i : pointer to an IVAS file writer handle */ + const uint8_t *packet, /* i : rtp packet to be written to rtpdump file */ + size_t numBytes ) /* i : size in bytes of the rtp packet */ +{ + ivas_error error = IVAS_ERR_OK; + if ( hRtpFile->isFileWriter ) + { + uint32_t length = (uint32_t) numBytes; /* Max packet length is < 32 bits*/ + fwrite( &length, sizeof( uint32_t ), 1, hRtpFile->f_rtpstream ); + fwrite( packet, sizeof( uint8_t ), numBytes, hRtpFile->f_rtpstream ); + } + else + { + error = IVAS_ERR_WRONG_PARAMS; + } + return error; +} + +static ivas_error IvasRtpFile_Read( + IVAS_RTP_FILE_HANDLE hRtpFile, /* i : pointer to an IVAS file reader handle */ + uint8_t *packet, /* o : read rtp packet */ + size_t *numBytes, /* o : no of bytes in packet */ + size_t capacity /* i : max capacity of the packet buffer */ +) +{ + size_t nread = 0; + uint32_t length = 0; + if ( hRtpFile->isFileWriter ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "File open for writing cannot be read" ); + } + + nread = fread( &length, sizeof( uint32_t ), 1, hRtpFile->f_rtpstream ); /* Read Packet Length */ + if ( nread == 0 ) + { + return IVAS_ERR_END_OF_FILE; + } + + *numBytes = length; + if ( ( *numBytes ) > capacity ) + { + fprintf( stderr, "RTP packet > buffer capacity %lu bytes\n", capacity ); + return IVAS_ERR_INVALID_OUTPUT_BUFFER_SIZE; + } + + nread = fread( packet, sizeof( uint8_t ), ( *numBytes ), hRtpFile->f_rtpstream ); /* Read Packet */ + if ( nread < ( *numBytes ) ) + { + return IVAS_ERR_END_OF_FILE; + } + + return IVAS_ERR_OK; +} + +static const char *const PiDataNames[IVAS_PI_MAX_ID] = { + "SCENE_ORIENTATION", "DEVICE_ORIENTATION_COMPENSATED", "DEVICE_ORIENTATION_UNCOMPENSATED", + "ACOUSTIC_ENVIRONMENT", "AUDIO_DESCRIPTION", "ISM_NUM", "ISM_ID", "ISM_GAIN", "ISM_ORIENTATION", + "ISM_POSITION", "ISM_DISTANCE_ATTENUATION", "ISM_DIRECTIVITY", "DIEGETIC_TYPE", "RESERVED13", + "AUDIO_FOCUS_INDICATION", "RESERVED15", "PLAYBACK_DEVICE_ORIENTATION", "HEAD_ORIENTATION", "LISTENER_POSITION", + "DYNAMIC_AUDIO_SUPPRESSION", "AUDIO_FOCUS_REQUEST", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN", + "R_ISM_ORIENTATION", "R_ISM_POSITION", "R_ISM_DIRECTION", "RESERVED27", "RESERVED28", "RESERVED29", + "RESERVED30", "NO_DATA" +}; + +void IVAS_RTP_LogPiData( + FILE *f_piDataOut, /* i/o : Output json file handle to dump PI data for debug/test */ + const PIDATA_TS *piData, /* i : PI Data + Timestamp array containing all PI data in current packet */ + uint32_t nPiDataPresent /* i : Number of valid elements in the piData array */ +) +{ + uint32_t timestamp = ~0u; + if ( f_piDataOut == NULL || piData == NULL || nPiDataPresent == 0 ) + { + return; + } + + if ( ftell( f_piDataOut ) > 2 ) + { + fprintf( f_piDataOut, ",\n" ); + } + + while ( nPiDataPresent-- > 0 ) + { + const PIDATA_TS *cur = piData++; + + if ( timestamp != ( ~0u ) && timestamp != cur->timestamp ) + { + fprintf( f_piDataOut, "\n\t},\n\t\"%d\": {\n", cur->timestamp ); + } + else if ( timestamp != cur->timestamp ) + { + fprintf( f_piDataOut, "\t\"%d\": {\n", cur->timestamp ); + } + else + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\"%s\" : ", PiDataNames[cur->data.noPiData.piDataType] ); + switch ( cur->data.noPiData.piDataType ) + { + case IVAS_PI_SCENE_ORIENTATION: + case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: + case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: + case IVAS_PI_HEAD_ORIENTATION: + case IVAS_PI_R_ISM_ORIENTATION: +#endif + { + fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + cur->data.scene.orientation.w, cur->data.scene.orientation.x, cur->data.scene.orientation.y, cur->data.scene.orientation.z ); + } + break; + + case IVAS_PI_ACOUSTIC_ENVIRONMENT: + { + fprintf( f_piDataOut, "{\n\t\t\t\"aeid\": %d", cur->data.acousticEnv.aeid ); + if ( cur->data.acousticEnv.availLateReverb ) + { + fprintf( f_piDataOut, ",\n\t\t\t\"rt60\": [ %f, %f, %f ],\n", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] ); + fprintf( f_piDataOut, "\t\t\t\"dsr\": [ %f, %f, %f ]", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] ); + } + if ( cur->data.acousticEnv.availEarlyReflections ) + { + fprintf( f_piDataOut, ",\n\t\t\t\"dim\": [ %f, %f, %f ],\n", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z ); + fprintf( f_piDataOut, "\t\t\t\"abscoeff\": [ %f, %f, %f, %f, %f, %f ]", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] ); + } + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_PI_LISTENER_POSITION: + case IVAS_PI_R_ISM_POSITION: + { + fprintf( f_piDataOut, "{\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + cur->data.listnerPosition.position.x, cur->data.listnerPosition.position.y, cur->data.listnerPosition.position.z ); + } + break; + case IVAS_PI_AUDIO_DESCRIPTION: + { + uint32_t nEntries = cur->data.audioDesc.nValidEntries; + const IVAS_AUDIO_ID *audioId = cur->data.audioDesc.audioId; + + fprintf( f_piDataOut, "[\n" ); + while ( nEntries-- > 0 ) + { + fprintf( f_piDataOut, "\t\t\t{\n" ); + fprintf( f_piDataOut, "\t\t\t\t\"isSpeech\": %s,\n", audioId->speech ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isMusic\": %s,\n", audioId->music ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isAmbiance\": %s,\n", audioId->ambiance ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isEditable\": %s,\n", audioId->editable ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isBinaural\": %s\n", audioId->binaural ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t}%c\n", ( nEntries == 0 ) ? ' ' : ',' ); + audioId++; + } + fprintf( f_piDataOut, "\t\t]" ); + } + break; + case IVAS_PI_DIEGETIC_TYPE: + { + const bool *isDiegetic = cur->data.digeticIndicator.isDiegetic; + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"isDigetic\": [\n" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[0] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[1] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[2] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[3] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s\n", isDiegetic[4] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t]\n\t\t}" ); + } + break; + case IVAS_PI_AUDIO_FOCUS_INDICATION: + { + fprintf( f_piDataOut, "{" ); + if ( cur->data.focusIndication.availDirection ) + { + fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", + cur->data.focusIndication.direction.w, cur->data.focusIndication.direction.x, cur->data.focusIndication.direction.y, cur->data.focusIndication.direction.z ); + if ( cur->data.focusIndication.availLevel ) + { + fprintf( f_piDataOut, "," ); + } + } + if ( cur->data.focusIndication.availLevel ) + { + fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusIndication.flvl ); + } + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION: + { + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppression; + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_RESERVED13: + case IVAS_PI_AUDIO_FOCUS_REQUEST: + { + fprintf( f_piDataOut, "{" ); + if ( cur->data.focusRequest.availDirection ) + { + fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", + cur->data.focusRequest.direction.w, cur->data.focusRequest.direction.x, cur->data.focusRequest.direction.y, cur->data.focusRequest.direction.z ); + if ( cur->data.focusRequest.availLevel ) + { + fprintf( f_piDataOut, "," ); + } + } + if ( cur->data.focusRequest.availLevel ) + { + fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusRequest.flvl ); + } + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_RESERVED15: + case IVAS_PI_RESERVED27: + case IVAS_PI_RESERVED28: + case IVAS_PI_RESERVED29: + case IVAS_PI_RESERVED30: + { + fprintf( f_piDataOut, "{}" ); + } + break; + case IVAS_PI_ISM_NUM: + case IVAS_PI_ISM_ID: + case IVAS_PI_ISM_GAIN: + case IVAS_PI_ISM_ORIENTATION: + case IVAS_PI_ISM_POSITION: + case IVAS_PI_ISM_DISTANCE_ATTENUATION: + case IVAS_PI_ISM_DIRECTIVITY: + case IVAS_PI_PI_LATENCY: + case IVAS_PI_R_ISM_ID: + case IVAS_PI_R_ISM_GAIN: + case IVAS_PI_R_ISM_DIRECTION: +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + case IVAS_PI_NO_DATA: + { + fprintf( f_piDataOut, "{}" ); + } + break; + } + timestamp = cur->timestamp; + } + fprintf( f_piDataOut, "\n\t}" ); +} + +void IVAS_RTP_Term( + IVAS_RTP *rtp /* i/o : IVAS RTP File reader/writer handle */ +) +{ + if ( NULL != rtp ) + { + if ( rtp->hPack != NULL ) + { + /* Complete the last packet */ + if ( IVAS_RTP_PACK_GetNumFrames( rtp->hPack ) != 0 ) + { + ivas_error error = IVAS_ERR_OK; + uint32_t numFramesInPayload = 0; + + if ( ( error = IVAS_RTP_PACK_GetPacket( rtp->hPack, &rtp->rtpPacket, &numFramesInPayload ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while packing RTP Packet\n", ivas_error_to_string( error ) ); + } + else if ( numFramesInPayload > 0 ) + { + if ( ( error = IvasRtpFile_Write( rtp->hRtpFile, rtp->rtpPacket.buffer, rtp->rtpPacket.length ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while writing RTP packet\n", ivas_error_to_string( error ) ); + } + } + } + IVAS_RTP_PACK_Close( &rtp->hPack ); + } + + if ( rtp->hUnpack != NULL ) + { + IVAS_RTP_UNPACK_Close( &rtp->hUnpack ); + } + + if ( rtp->f_piDataOut != NULL ) + { + fprintf( rtp->f_piDataOut, "\n}\n" ); + fclose( rtp->f_piDataOut ); + rtp->f_piDataOut = NULL; + } + + if ( rtp->hRtpFile != NULL ) + { + IvasRtpFile_Close( &rtp->hRtpFile ); + } + } +} + +ivas_error IVAS_RTP_WRITER_Init( + IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */ + const char *outputBitstreamFilename, /* i : RTP Dump filename */ + uint32_t numFramesPerPacket /* i : No. of frames per packet desired */ +) +{ + uint32_t SSRC = ( rand() & 0xFFFF ) | ( (uint32_t) rand() << 16 ); + ivas_error error = IVAS_ERR_OK; + + memset( rtp, 0, sizeof( IVAS_RTP ) ); + + rtp->packCfg.maxFramesPerPacket = numFramesPerPacket; + rtp->rtpPacket.buffer = rtp->packet; + rtp->rtpPacket.capacity = sizeof( rtp->packet ); + + error = IVAS_RTP_PACK_Open( &rtp->hPack, &rtp->packCfg ); + if ( error == IVAS_ERR_OK ) + { + /* Open the output file for RTPDump writing */ + error = IvasRtpFile_Open( outputBitstreamFilename, true, &rtp->hRtpFile ); + if ( error != IVAS_ERR_OK ) + { + return error; + } + + error = IVAS_RTP_PACK_UpdateHeader( rtp->hPack, SSRC, 0, NULL, 0, 0, NULL ); + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_PACK_UpdateHeader(): %d\n", error ); + } + } + + return error; +} + +ivas_error IVAS_RTP_READER_Init( + IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */ + const char *inputBitstreamFilename, /* i : Input rtpdump filename */ + const char *piOutputFilename /* i : Output PI data json filename */ +) +{ + ivas_error error = IVAS_ERR_OK; + + memset( rtp, 0, sizeof( IVAS_RTP ) ); + + rtp->unpackCfg.maxFramesPerPacket = IVAS_MAX_FRAMES_PER_RTP_PACKET; + rtp->rtpPacket.buffer = rtp->packet; + rtp->rtpPacket.capacity = sizeof( rtp->packet ); + + error = IVAS_RTP_UNPACK_Open( &rtp->hUnpack, &rtp->unpackCfg ); + if ( error == IVAS_ERR_OK ) + { + error = IvasRtpFile_Open( inputBitstreamFilename, false, &rtp->hRtpFile ); + if ( error != IVAS_ERR_OK ) + { + return error; + } + + if ( piOutputFilename != NULL ) + { + rtp->f_piDataOut = fopen( piOutputFilename, "w" ); + if ( rtp->f_piDataOut == NULL ) + { + fprintf( stderr, "could not open: %s\n", piOutputFilename ); + return IVAS_ERR_FAILED_FILE_OPEN; + } + fprintf( rtp->f_piDataOut, "{\n" ); + } + } + + return error; +} + +ivas_error IVAS_RTP_WriteNextFrame( + IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */ + uint8_t *au, /* i : IVAS Compressed AU (Packed frame) */ + int16_t auSizeBits, /* i : Frame size in bits */ + bool isMono, /* i : input was evs(true) or ivas(false) */ + bool forcePacket /* i : force packets with whatever frames pushed so far */ +) +{ + ivas_error error = IVAS_ERR_OK; + uint32_t nProcPiData = 0; + IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; + + packedFrame.capacity = ( auSizeBits + 7 ) / 8; + packedFrame.length = ( auSizeBits + 7 ) / 8; + packedFrame.buffer = (uint8_t *) au; + rtp->rtpPacket.length = 0; + + /* Push Encoded Stream to */ + error = IVAS_RTP_PACK_PushFrame( rtp->hPack, + isMono ? IVAS_RTP_EVS : IVAS_RTP_IVAS, +#ifdef RTP_S4_251135_CR26253_0016_REV1 + NULL, +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + &packedFrame ); + if ( error != IVAS_ERR_OK ) + { + return error; + } + + while ( rtp->nWrittenPiData-- > 0 ) + { + PIDATA_TS *piDataTs = &rtp->piData[nProcPiData++]; + if ( ( error = IVAS_RTP_PACK_PushPiData( rtp->hPack, (const IVAS_PIDATA_GENERIC *) &piDataTs->data ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while pushing scene orientation\n", ivas_error_to_string( error ) ); + return error; + } + } + + if ( forcePacket || IVAS_RTP_PACK_GetNumFrames( rtp->hPack ) == rtp->packCfg.maxFramesPerPacket ) + { + uint32_t numFramesInPayload = 0; + + /* Generate RTP Packet */ + if ( ( error = IVAS_RTP_PACK_GetPacket( rtp->hPack, &rtp->rtpPacket, &numFramesInPayload ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while packing RTP Header\n", ivas_error_to_string( error ) ); + return error; + } + + if ( ( error = IvasRtpFile_Write( rtp->hRtpFile, rtp->rtpPacket.buffer, rtp->rtpPacket.length ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while writing RTP packet\n", ivas_error_to_string( error ) ); + return error; + } + } + + return error; +} + +ivas_error IVAS_RTP_ReadNextFrame( + IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */ + uint8_t *au, /* o : Read next IVAS Compressed AU (Packed frame) */ + int16_t *auSizeBits, /* o : Reported Frame size in bits */ + uint32_t *rtpTimeStamp, /* o : RTP Timestamp for this frame */ + uint16_t *rtpSequenceNumber, /* o : RTP sequence number for this packet */ + uint32_t *nextPacketRcvTime_ms, /* i/o : Clock indicating packet receive times need in JBM */ + bool *qBit /* o : AMRWB Q bite as indicated in the RTP packet */ +) +{ + ivas_error error = IVAS_ERR_OK; + IVAS_DATA_BUFFER packedFrame; + IVAS_RTP_CODEC codecId = IVAS_RTP_IVAS; + bool isAMRWB_IOmode = false; + + packedFrame.length = 0; + packedFrame.buffer = au; + packedFrame.capacity = ( IVAS_MAX_BITS_PER_FRAME / 8 ); + if ( rtp->numFramesInPacket == 0 ) + { + rtp->rtpPacket.length = 0; + if ( ( error = IvasRtpFile_Read( rtp->hRtpFile, rtp->rtpPacket.buffer, &rtp->rtpPacket.length, rtp->rtpPacket.capacity ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( ( error = IVAS_RTP_UNPACK_PushPacket( rtp->hUnpack, &rtp->rtpPacket, + &rtp->numFramesInPacket, &rtp->numPiDataInPacket, + &rtp->remoteRequestBitmap ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "failed to unpack RTP packet error = %s\n", ivas_error_to_string( error ) ); + return error; + } + + rtp->nReadPiData = 0; + rtp->nProcPiData = 0; + + /* Pre-read all PI data */ + while ( rtp->numPiDataInPacket != 0 ) + { + PIDATA_TS *piData = &rtp->piData[rtp->nReadPiData]; + if ( ( error = IVAS_RTP_UNPACK_PullNextPiData( rtp->hUnpack, (IVAS_PIDATA_GENERIC *) &piData->data, sizeof( piData->data ), &piData->timestamp ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "failed to pull PI Data, error = %s\n", ivas_error_to_string( error ) ); + return error; + } + rtp->nReadPiData++; + rtp->numPiDataInPacket--; + } + IVAS_RTP_LogPiData( rtp->f_piDataOut, rtp->piData, rtp->nReadPiData ); + } + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &codecId, &rtp->srInfo, &packedFrame, auSizeBits, rtpTimeStamp, rtpSequenceNumber, &rtp->speechLostIndicated, &isAMRWB_IOmode ); +#else + error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &codecId, &packedFrame, auSizeBits, rtpTimeStamp, rtpSequenceNumber, &rtp->speechLostIndicated, &isAMRWB_IOmode ); +#endif + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "failed to pull frame after unpack\n" ); + return error; + } + + rtp->restartNeeded = false; + if ( *auSizeBits == 0 ) + { + /* NO_DATA_FRAME/SPEECH_LOST for IVAS and EVS is indicated by same bits + Do not restart decoder on codec/amrwb mode change in this case */ + } + else + { + rtp->restartNeeded = ( rtp->codecId != codecId ) || + ( codecId == IVAS_RTP_EVS && ( rtp->isAMRWB_IOmode != isAMRWB_IOmode ) ); + + if ( rtp->restartNeeded ) + { + fprintf( stdout, "\nRTP packet codec changed %s -> %s\n", + ( rtp->codecId == IVAS_RTP_EVS ) ? ( rtp->isAMRWB_IOmode ? "AMRWB_IO" : "EVS" ) : "IVAS", + ( codecId == IVAS_RTP_EVS ) ? ( isAMRWB_IOmode ? "AMRWB_IO" : "EVS" ) : "IVAS" ); + } + + rtp->codecId = codecId; + rtp->isAMRWB_IOmode = isAMRWB_IOmode; + } + + *qBit = !rtp->speechLostIndicated; + rtp->numFramesInPacket--; + rtp->numFramesProduced++; + *nextPacketRcvTime_ms += 20; + + return IVAS_ERR_OK; +} diff --git a/lib_util/ivas_rtp_file.h b/lib_util/ivas_rtp_file.h new file mode 100644 index 000000000..2a58dc1c9 --- /dev/null +++ b/lib_util/ivas_rtp_file.h @@ -0,0 +1,79 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_FILE_H +#define IVAS_RTP_FILE_H + +#include "common_api_types.h" +#include "ivas_rtp_api.h" +#include "ivas_rtp_pi_data.h" + +typedef struct IVAS_RTP_FILE *IVAS_RTP_FILE_HANDLE; + +typedef struct +{ + uint8_t packet[NOMINAL_BUFFER_SIZE( IVAS_MAX_FRAMES_PER_RTP_PACKET )]; + PIDATA_TS piData[IVAS_PI_MAX_ID * IVAS_MAX_FRAMES_PER_RTP_PACKET]; + + IVAS_RTP_FILE_HANDLE hRtpFile; + FILE *f_piDataOut; + IVAS_RTP_CODEC codecId; + uint32_t nWrittenPiData; + uint32_t nReadPiData; + uint32_t nProcPiData; + uint32_t numFramesInPacket; + uint32_t numPiDataInPacket; + uint32_t remoteRequestBitmap; + bool speechLostIndicated; + bool restartNeeded; + bool isAMRWB_IOmode; + size_t numFramesProduced; + + IVAS_DATA_BUFFER rtpPacket; + IVAS_RTP_PACK_HANDLE hPack; + IVAS_RTP_UNPACK_HANDLE hUnpack; + IVAS_RTP_PACK_CONFIG packCfg; + IVAS_RTP_UNPACK_CONFIG unpackCfg; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO srInfo; +#endif +} IVAS_RTP; + +ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilename, uint32_t numFramesPerPacket ); +ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, const char *inputBitstreamFilename, const char *piOutputFilename ); +void IVAS_RTP_Term( IVAS_RTP *rtp ); +ivas_error IVAS_RTP_WriteNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t auSizeBits, bool isMono, bool forcePacket ); +ivas_error IVAS_RTP_ReadNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit ); +void IVAS_RTP_LogPiData( FILE *f_piDataOut, const PIDATA_TS *piData, uint32_t nPiDataPresent ); + + +#endif /* IVAS_RTP_FILE_H */ diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h new file mode 100644 index 000000000..f3569ca03 --- /dev/null +++ b/lib_util/ivas_rtp_internal.h @@ -0,0 +1,140 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_INTERNAL_H +#define IVAS_RTP_INTERNAL_H + +#include "ivas_rtp_api.h" +#include "ivas_rtp_pi_data.h" + +#ifdef IVAS_RTPDUMP + +enum MASK_BITS +{ + MASK_1BIT = 0x1, + MASK_2BIT = 0x3, + MASK_3BIT = 0x7, + MASK_4BIT = 0xF, + MASK_5BIT = 0x1F, + MASK_6BIT = 0x3F, + MASK_7BIT = 0x7F, + MASK_8BIT = 0xFF, + +}; + +/* tables */ +#define NBITS_AEID ( 7 ) +#define NBITS_RT60 ( 5 ) +#define NBITS_DSR ( 6 ) +#define NBITS_DIM ( 4 ) +#define NBITS_ABS ( 2 ) + +#define MASK_AEID ( ( 1u << NBITS_AEID ) - 1 ) +#define MASK_RT60 ( ( 1u << NBITS_RT60 ) - 1 ) +#define MASK_DSR ( ( 1u << NBITS_DSR ) - 1 ) +#define MASK_DIM ( ( 1u << NBITS_DIM ) - 1 ) +#define MASK_ABS ( ( 1u << NBITS_ABS ) - 1 ) + +#define MAX_PI_POSITION_METERS ( 327.68f ) +#define FLOAT_FROM_Q15( q15Val ) ( (float) ( q15Val ) / 32768.0f ) + +extern const float mapDSR[1u << NBITS_DSR]; +extern const float mapRT60[1u << NBITS_RT60]; +extern const float mapRoomDims[1u << NBITS_DIM]; +extern const float mapAbsorbtion[1u << NBITS_ABS]; + +enum IVAS_RTP_HEADER_BITS +{ + + EBYTE_TOC_HEADER_BIT = 0x80, /* Ebyte/ToC indicator H bit, 1 = EByte, 0 = ToC */ + + TOC_HEADER_FOLLOWS = 0x40, /* ToC header byte is followed by another header byte */ + TOC_INDICATE_NO_DATA_AMRWB = 0x3F, /* ToC byte indicates NO_DATA in DTX mode for AMRWB */ + TOC_INDICATE_NO_DATA = 0x0F, /* ToC header byte indicates NO_DATA in DTX mode */ + TOC_INDICATE_IVAS = 0x10, /* ToC header byte indicates IVAS data */ + TOC_INDICATE_EVS = 0x00, /* ToC header byte indicates EVS data */ + TOC_INDICATE_AMRWB = 0x30, /* ToC header byte indicates AMR-WB IO data */ + TOC_INDICATE_ARMWB_Q = 0x20, /* ToC header byte indicates AMR-WB IO lost frame */ + TOC_INDICATE_SR = 0x1E, /* Indicate Split Rendering in ToC bytes */ + + EBYTE_CMR_T_EVS_NB = 0x80, /* Initial E-byte indicating EVS NarrowBand modes */ + EBYTE_CMR_T_EVS_IO = 0x90, /* Initial E-byte indicating EVS AMRWB IO modes */ + EBYTE_CMR_T_EVS_WB = 0xA0, /* Initial E-byte indicating EVS WideBand modes */ + EBYTE_CMR_T_EVS_SWB = 0xB0, /* Initial E-byte indicating EVS SuperWideBand modes */ + EBYTE_CMR_T_EVS_FB = 0xC0, /* Initial E-byte indicating EVS FullBand modes */ + EBYTE_CMR_T_EVS_CA_WB = 0xD0, /* Initial E-byte indicating EVS CA WideBand modes */ + EBYTE_CMR_T_EVS_CA_SWB = 0xE0, /* Initial E-byte indicating EVS CA SuperWideBand modes */ + EBYTE_CMR_T_IVAS = 0xF0, /* Initial E-byte indicating IVAS modes */ + EBYTE_CMR_T_NO_REQ = 0xFF, /* If no bitrate and no CA mode requested for IVAS/EVS */ + + EBYTE_BANDWIDTH_REQUEST = 0x80, /* Subsequent E-byte for Bandwidth Request */ + EBYTE_FORMAT_REQUEST = 0x90, /* Subsequent E-byte for Format Request */ + EBYTE_SUBFORMAT_REQUEST = 0x9F, /* Subsequent E-byte for SubFormat Request */ + EBYTE_PI_INDICATOR = 0xA0, /* Subsequent E-byte for PI Indicator */ + EBYTE_SR_REQUEST = 0xB0, /* Subsequent E-byte for Split Rendering Request */ + + PI_HEADER_PF_LAST = 0x00, /* Last PI header of the Payload in PI Header */ + PI_HEADER_PF_NOT_LAST = 0x80, /* Another PI header follows after this in PI Header */ + PI_HEADER_PM_NOT_LAST = 0x20, /* PI Frame Marker, not the last PI Header in current frame */ + PI_HEADER_PM_LAST = 0x40, /* PI Frame Marker, the last PI Header in current frame */ + PI_HEADER_PM_GENERIC = 0x60, /* PI Frame Marker, Generic applied to all frames */ + + PI_AD_SPEECH_INDICATED = 0x80, /* Audio Description indicate Speech in Audio data */ + PI_AD_MUSIC_INDICATED = 0x40, /* Audio Description indicate Misuc in Audio data */ + PI_AD_AMBIANCE_INDICATED = 0x20, /* Audio Description indicate Ambiance in Audio data */ + PI_AD_EDITABLE_INDICATED = 0x10, /* Audio Description indicate metadata is editable */ + PI_AD_BINAURAL_INDICATED = 0x8, /* Audio Description indicate Stereo stream in Binaural */ + +}; + + +#define ERR_CHECK_RETURN( err ) \ + { \ + if ( ( err ) != IVAS_ERR_OK ) \ + { \ + return ( err ); \ + } \ + } + + +typedef struct +{ + uint32_t size; + uint8_t data[IVAS_PI_MAX_DATA_SIZE]; +} PIDATA_PACKED; + +ivas_error PI_PackData( const IVAS_PIDATA_GENERIC *piData, PIDATA_PACKED *packed, uint8_t pmBits ); +ivas_error PI_UnPackData( uint8_t piDataType, uint32_t piSize, const uint8_t *piDataBuffer, IVAS_PIDATA_GENERIC *piData ); + +#endif /* IVAS_RTPDUMP */ + +#endif /* IVAS_RTP_INTERNAL_H */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c new file mode 100644 index 000000000..4e4b11f2a --- /dev/null +++ b/lib_util/ivas_rtp_payload.c @@ -0,0 +1,1854 @@ +/****************************************************************************************************** + + (C) 2022-2025 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 +#include "common_api_types.h" + +#ifdef IVAS_RTPDUMP + +#include "ivas_rtp_internal.h" +#include "ivas_bpool.h" +#include "ivas_queue.h" +#include "ivas_error_utils.h" +#include "mutex.h" + +#define IVAS_MAX_BYTES_PER_FRAME ( ( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3 ) +#define MAX_TOC_PER_FRAME ( 2u ) /* Main ToC Byte + SR-ToC byte */ + +/* Generic RTP Header + Header Extension data structure */ +typedef struct +{ + uint32_t ssrc; /* synchronization source id as negotiated in SDP */ + uint8_t version; /* version of RTP protocol, currently 2 */ + bool padding; /* false = no padding, true = zeoo padded payload (last byte = padding count) */ + bool extension; /* true = extension header is present before payload */ + uint8_t CC; /* if some streams mixed together, CC indicates no. of contributing sources (4 bits) */ + bool marker; /* Marker bit field */ + uint8_t payloadType; /* 7-bit payload type field indicating IVAS */ + uint16_t seqNumber; /* 16-bit sequence number for RTP packets */ + uint32_t timestamp; /* timer ticks @ 16KHz clock corrsponding to 1st frame in the Payload */ + uint32_t CSRC[15]; /* SSRC of contributing Sources for a mixed stream */ + uint16_t extHeaderId; /* extension header ID */ + uint16_t numExtUnits; /* length of the extension data in 32-bit words */ + uint8_t *extData; /* Extension data pointer */ +} RTP_HEADER; + +typedef struct +{ + PIDATA_PACKED piData[IVAS_PI_MAX_ID]; /* pi data per frame */ + uint32_t piDataBitmap; /* bitmap showing available pi */ + uint32_t numPiDataAvailable; /* number of pi data available */ +} PIDATA_FRAME; + +static void initRequests( IVAS_RTP_REQUEST_VALUE *requests ) +{ + requests[IVAS_REQUEST_CODEC].codec = IVAS_RTP_IVAS; + requests[IVAS_REQUEST_BITRATE].bitrate = 0; + requests[IVAS_REQUEST_BANDWIDTH].bandwidth = IVAS_BANDWIDTH_NO_REQ; + requests[IVAS_REQUEST_FORMAT].formatType = IVAS_FMT_NO_REQ; + requests[IVAS_REQUEST_CA_MODE].caMode = IVAS_RTP_CA_NO_REQ; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + requests[IVAS_REQUEST_SUBFORMAT].subFormatType = IVAS_SUBFMT_NO_REQ; + requests[IVAS_REQUEST_SR_CONFIG].srConfig.valid = false; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ +} + +static void initPiDataFrame( PIDATA_FRAME *piDataFrm ) +{ + /* Add NO_PI_DATA by default */ + piDataFrm->numPiDataAvailable = 1; + piDataFrm->piDataBitmap = ( 1u << IVAS_PI_NO_DATA ); + piDataFrm->piData[IVAS_PI_NO_DATA].size = 2; + piDataFrm->piData[IVAS_PI_NO_DATA].data[0] = ( IVAS_PI_NO_DATA ); /* PF/PM populated during final packing */ + piDataFrm->piData[IVAS_PI_NO_DATA].data[1] = 0; /* NO_PI_DATA is 0 bytes */ +} + +typedef struct FRAME_NODE +{ + struct FRAME_NODE *next; /* next node */ + PIDATA_FRAME piDataFrame; /* PI data for this frame */ + uint8_t au[IVAS_MAX_BYTES_PER_FRAME]; /* ivas/evs packed frame (AU) */ + uint8_t toc[MAX_TOC_PER_FRAME]; /* ToC bytes for this frame */ + uint32_t auNumBits; /* Actual frame size in bits */ + uint32_t tocNumBytes; /* valid ToC bytes (1 or 2) */ +} FRAME_NODE; + +static void initFrameNode( FRAME_NODE *node ) +{ + node->next = NULL; + initPiDataFrame( &node->piDataFrame ); + node->auNumBits = 0; + node->tocNumBytes = 0; +} + +struct IVAS_RTP_PACK +{ + mtx_t apilock; /* Lock to handle concurrent API invocation */ + bool amrwbIOMode; /* If EVS is an AMRWB-IO mode frame */ + RTP_HEADER header; /* RTP Header Params */ + BPOOL_HANDLE packNodePool; /* Buffer pool to allocate FRAME_NODEs */ + PIDATA_FRAME piDataCache; /* temporary cache for PI data pushed before any frame is available in Queue */ + IVAS_RTP_PACK_CONFIG initConfig; /* Initial Configuration for Unpacker */ + IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX]; /* Requests Storage */ + QUEUE_HANDLE frameQ; /* frames queue for FRAME_NODEs */ +}; + +typedef struct +{ + IVAS_RTP_CODEC codecId; /* Coded frame type (IVAS/EVS) */ + uint32_t auNumBits; /* Actual frame size in bits */ + bool speechLostIndicated; /* Speech Lost indicated */ + bool isAMRWB_IOmode; /* EVS frame is AMRWB_IO */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO srInfo; /* Split Rendering Info */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ +} TOC_INFO; + +typedef struct PIDATA_NODE +{ + struct PIDATA_NODE *next; /* next node is first element */ + PIDATA data; /* unpacked pi data per frame */ + uint32_t timestamp; /* rtp timestamp of this frame */ +} PIDATA_NODE; + +typedef struct UNPACK_NODE +{ + struct UNPACK_NODE *next; /* next node is first element */ + uint8_t au[IVAS_MAX_BYTES_PER_FRAME]; /* ivas/evs packed frame (AU) */ + TOC_INFO toc; /* unpacked ToC information */ + uint32_t timestamp; /* timestamp of this frame */ + uint16_t seqNumber; /* sequence number of the packet */ +} UNPACK_NODE; + +struct IVAS_RTP_UNPACK +{ + mtx_t apilock; /* Lock to handle concurrent API invocation */ + size_t maxNumberOfFrames; + size_t maxNumberOfPiData; + RTP_HEADER header; + BPOOL_HANDLE unpackNodePool; + BPOOL_HANDLE piDataPool; + IVAS_RTP_UNPACK_CONFIG initConfig; + IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX]; + uint32_t numPiDataAvailable; /* number of pi data available */ + QUEUE_HANDLE frameQ; /* frame queue */ + QUEUE_HANDLE piDataQ; /* pi data queue */ +}; + +static const uint32_t ivasFrameSizeInBits[] = { + 264, 328, 488, 640, 960, 1280, 1600, 1920, 2560, 3200, 3840, 5120, 7680, 10240, 0, 104 +}; + +static const uint32_t evsFrameSizeInBits[] = { + 56, 144, 160, 192, 264, 328, 488, 640, 960, 1280, 1920, 2560, 48 +}; + +static const uint32_t amrWBIOFrameSizeInBits[] = { + 132, 177, 253, 285, 317, 365, 397, 461, 477, 35 +}; + + +/* Update the RTP Header structure */ +ivas_error IVAS_RTP_PACK_UpdateHeader( + IVAS_RTP_PACK_HANDLE hPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ + uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */ + uint8_t numCC, /* i : numCC indicates no. of contributing sources */ + uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */ + uint16_t extHeaderId, /* i : extension header ID */ + uint16_t numExtensionBytes, /* i : length of the extension data */ + uint8_t *extData /* i : extension data pointer */ +) +{ + RTP_HEADER *header = &hPack->header; + + if ( numCC > 15 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "CC must be less than 16" ); + } + + header->ssrc = ssrc; + header->CC = numCC; + memcpy( header->CSRC, csrc, numCC & 0xF ); + + if ( ( numExtensionBytes > 0 ) && ( extData != NULL ) ) + { + header->extHeaderId = extHeaderId; + header->extData = realloc( header->extData, numExtensionBytes ); + if ( header->extData == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" ); + } + memcpy( header->extData, extData, numExtensionBytes ); + header->extension = true; + header->numExtUnits = numExtensionBytes / sizeof( uint32_t ); + } + else + { + header->numExtUnits = 0; + header->extension = false; + } + + return IVAS_ERR_OK; +} + +static void InitRtpHeader( + RTP_HEADER *header /* RTP header structure */ +) +{ + time_t t; + memset( header, 0, sizeof( *header ) ); + srand( (uint32_t) time( &t ) ); + header->version = 2; + header->seqNumber = rand() & 0xFFFF; +} + +static ivas_error PackRtpHeader( + RTP_HEADER *header, + IVAS_DATA_BUFFER *buf ) +{ + uint32_t nBytes = 0; + uint8_t CC = header->CC & MASK_4BIT; + uint32_t *CSRC = header->CSRC; + bool extension = header->extension && ( NULL != header->extData ); + uint32_t extensionLength = header->extension ? ( 1 + header->numExtUnits ) : 0; /* in u32 words */ + uint32_t packedLength = 12 + ( 4 * CC ) + ( 4 * extensionLength ); + + buf->length = 0; + if ( packedLength > buf->capacity ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient output buffer for RTP header packing" ); + } + + /* + +---+---+---+---+---+---+---+---+ + | V | V | P | X | CC (4 - bits) | + +---+---+---+---+---+---+---+---+ + */ + buf->buffer[nBytes++] = ( header->version << 6 ) | + ( (uint8_t) header->padding << 5 ) | + ( (uint8_t) extension << 4 ) | + CC; + /* + +---+---+---+---+---+---+---+---+ + | M | PT (7 - bits) | + +---+---+---+---+---+---+---+---+ + */ + buf->buffer[nBytes++] = ( (uint8_t) header->marker << 7 ) | + ( header->payloadType & MASK_7BIT ); + /* + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | SEQUENCE NUMBER (16 bit) | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + */ + buf->buffer[nBytes++] = (uint8_t) ( header->seqNumber >> 8 ); + buf->buffer[nBytes++] = (uint8_t) ( header->seqNumber ); + + /* Timestamp (32-bit) */ + buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 24 ); + buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 16 ); + buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 8 ); + buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 0 ); + + /* SSRC (32-bit) */ + buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 24 ); + buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 16 ); + buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 8 ); + buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 0 ); + + /* CSRC Identifiers */ + while ( CC ) + { + /* CSRC[n] (32-bit) */ + uint32_t id = *CSRC++; + buf->buffer[nBytes++] = (uint8_t) ( id >> 24 ); + buf->buffer[nBytes++] = (uint8_t) ( id >> 16 ); + buf->buffer[nBytes++] = (uint8_t) ( id >> 8 ); + buf->buffer[nBytes++] = (uint8_t) ( id >> 0 ); + CC--; + } + + if ( extension ) + { + buf->buffer[nBytes++] = (uint8_t) ( header->extHeaderId >> 8 ); + buf->buffer[nBytes++] = (uint8_t) ( header->extHeaderId >> 0 ); + buf->buffer[nBytes++] = (uint8_t) ( header->numExtUnits >> 8 ); + buf->buffer[nBytes++] = (uint8_t) ( header->numExtUnits >> 0 ); + + memcpy( &buf->buffer[nBytes], header->extData, header->numExtUnits * 4 ); + nBytes += header->numExtUnits; + } + + buf->length = nBytes; + return IVAS_ERR_OK; +} + +static void UpdateRtpHeader( + RTP_HEADER *header, /* RTP header structure */ + uint32_t timestampOffset /* Timestamp offset @ 16KHz clock for next frame */ +) +{ + header->seqNumber++; + header->timestamp += timestampOffset; +} + +static ivas_error UnpackRtpPacket( + const IVAS_DATA_BUFFER *packet, /* Input buffer with RTP Packet */ + RTP_HEADER *header, /* RTP header structure */ + uint32_t *numHeaderBytes /* No. of rtp header bytes */ +) +{ + uint32_t n = 0, nByte = 0, expectedSize = 12; + uint8_t byte; + + if ( packet->length < expectedSize ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Insufficient input buffer for RTP header unpacking" ); + } + + /* + +---+---+---+---+---+---+---+---+ + | V | V | P | X | CC (4 - bits) | + +---+---+---+---+---+---+---+---+ + */ + byte = packet->buffer[nByte++]; + header->version = ( byte >> 6 ) & MASK_2BIT; + header->padding = ( byte >> 5 ) & MASK_1BIT; + header->extension = ( byte >> 4 ) & MASK_1BIT; + header->CC = ( byte & MASK_4BIT ); + + /* + +---+---+---+---+---+---+---+---+ + | M | PT (7 - bits) | + +---+---+---+---+---+---+---+---+ + */ + byte = packet->buffer[nByte++]; + header->marker = ( byte >> 7 ) & MASK_1BIT; + header->payloadType = byte & MASK_7BIT; + + /* + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | SEQUENCE NUMBER (16 bit) | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + */ + header->seqNumber = (uint16_t) packet->buffer[nByte++] << 8; + header->seqNumber |= (uint16_t) packet->buffer[nByte++] << 8; + + /* Timestamp (32-bit) */ + header->timestamp = ( (uint32_t) packet->buffer[nByte++] << 24 ); + header->timestamp |= ( (uint32_t) packet->buffer[nByte++] << 16 ); + header->timestamp |= ( (uint32_t) packet->buffer[nByte++] << 8 ); + header->timestamp |= ( (uint32_t) packet->buffer[nByte++] ); + + /* SSRC (32-bit) */ + header->ssrc = ( (uint32_t) packet->buffer[nByte++] << 24 ); + header->ssrc |= ( (uint32_t) packet->buffer[nByte++] << 16 ); + header->ssrc |= ( (uint32_t) packet->buffer[nByte++] << 8 ); + header->ssrc |= ( (uint32_t) packet->buffer[nByte++] ); + + expectedSize += ( header->CC ) * 4 + ( header->extension ? 4 : 0 ); + if ( packet->length < expectedSize ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "CC indicated but insufficient input buffer" ); + } + + /* CSRC Identifiers */ + for ( n = 0; n < header->CC; n++ ) + { + /* CSRC[n] (32-bit) */ + header->CSRC[n] = ( (uint32_t) packet->buffer[nByte++] << 24 ); + header->CSRC[n] |= ( (uint32_t) packet->buffer[nByte++] << 16 ); + header->CSRC[n] |= ( (uint32_t) packet->buffer[nByte++] << 8 ); + header->CSRC[n] |= ( (uint32_t) packet->buffer[nByte++] ); + } + + if ( header->extension ) + { + header->extHeaderId = ( (uint32_t) packet->buffer[nByte++] << 8 ); + header->extHeaderId |= ( (uint32_t) packet->buffer[nByte++] ); + header->numExtUnits = ( (uint32_t) packet->buffer[nByte++] << 8 ); + header->numExtUnits |= ( (uint32_t) packet->buffer[nByte++] ); + + expectedSize += header->numExtUnits * 4; + if ( packet->length < expectedSize ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Extension Header indicated but insufficient input buffer" ); + } + + header->extData = realloc( header->extData, header->numExtUnits * 4 ); + if ( header->extData == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" ); + } + memcpy( header->extData, &packet->buffer[nByte], header->numExtUnits * 4 ); + nByte += header->numExtUnits * 4; + } + + *numHeaderBytes = nByte; + return IVAS_ERR_OK; +} + +static ivas_error getBitrateFromCodecAndFrameSize( + IVAS_RTP_CODEC codecId, + uint32_t frameLengthBytes, + uint32_t *bitrateKbps, + uint32_t *frameLenInBits, + uint8_t *tocByte, + bool *isAmrwbIOMode ) +{ + size_t n; + *bitrateKbps = 0; + *frameLenInBits = 0; + if ( codecId == IVAS_RTP_IVAS ) + { + /* Validate the framelength is supported for ivas frame */ + for ( n = 0; n < sizeof( ivasFrameSizeInBits ) / sizeof( ivasFrameSizeInBits[0] ); n++ ) + { + if ( ivasFrameSizeInBits[n] == frameLengthBytes * 8 ) + { + *bitrateKbps = ( frameLengthBytes * IVAS_NUM_FRAMES_PER_SEC * 8 ); /* bitrate in kbps */ + *frameLenInBits = frameLengthBytes * 8; /* frame length in bits */ + *tocByte = TOC_INDICATE_IVAS | ( n & MASK_4BIT ); /* bitrate index */ + return IVAS_ERR_OK; + } + } + return IVAS_ERR_INVALID_BITRATE; + } + else + { + /* Try if frameLength is a supported EVS frame length */ + for ( n = 0; n < sizeof( evsFrameSizeInBits ) / sizeof( evsFrameSizeInBits[0] ); n++ ) + { + if ( evsFrameSizeInBits[n] == frameLengthBytes * 8 ) + { + *bitrateKbps = ( frameLengthBytes * IVAS_NUM_FRAMES_PER_SEC * 8 ); /* bitrate in kbps */ + *frameLenInBits = frameLengthBytes * 8; /* frame length in bits */ + *tocByte = TOC_INDICATE_EVS | ( n & MASK_4BIT ); /* bitrate index */ + return IVAS_ERR_OK; + } + } + /* Try if frameLength is a supported AMRWB-IO frame length */ + for ( n = 0; n < sizeof( amrWBIOFrameSizeInBits ) / sizeof( amrWBIOFrameSizeInBits[0] ); n++ ) + { + uint32_t lengthInBits = amrWBIOFrameSizeInBits[n]; + if ( ( ( lengthInBits + 7 ) / 8 ) == frameLengthBytes ) + { + *isAmrwbIOMode = true; + *bitrateKbps = ( lengthInBits * IVAS_NUM_FRAMES_PER_SEC ); /* bitrate in kbps */ + *frameLenInBits = lengthInBits; /* frame length in bits */ + *tocByte = TOC_INDICATE_AMRWB | ( n & MASK_4BIT ); /* bitrate index */ + return IVAS_ERR_OK; + } + } + return IVAS_ERR_INVALID_BITRATE; + } +} + +ivas_error IVAS_RTP_PACK_Open( + IVAS_RTP_PACK_HANDLE *phPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ + const IVAS_RTP_PACK_CONFIG *config /* i : pointer to initial config for RTP Packer */ +) +{ + ivas_error error; + IVAS_RTP_PACK_HANDLE hPack; + uint32_t numFramesPerPacket = ( config->maxFramesPerPacket == 0 ) ? IVAS_MAX_FRAMES_PER_RTP_PACKET : config->maxFramesPerPacket; + + if ( phPack == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( numFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Max frame per packet exeeds %d", IVAS_MAX_FRAMES_PER_RTP_PACKET ); + } + + *phPack = NULL; + if ( ( hPack = (IVAS_RTP_PACK_HANDLE) calloc( 1, sizeof( struct IVAS_RTP_PACK ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtppack handle" ); + } + + error = BPOOL_Create( &hPack->packNodePool, sizeof( FRAME_NODE ), numFramesPerPacket * 4 ); + ERR_CHECK_RETURN( error ); + + error = QUEUE_Create( &hPack->frameQ ); + ERR_CHECK_RETURN( error ); + + mtx_init( &hPack->apilock, 0 ); + hPack->initConfig = *config; + initRequests( hPack->requests ); + InitRtpHeader( &hPack->header ); + initPiDataFrame( &hPack->piDataCache ); + *phPack = hPack; + return IVAS_ERR_OK; +} + +/* Close and free an existing instance of rtp packer */ +void IVAS_RTP_PACK_Close( + IVAS_RTP_PACK_HANDLE *phPack /* i/o : pointer to an IVAS rtp packer handle to be closed */ +) +{ + IVAS_RTP_PACK_HANDLE hPack; + + /* Free all memory */ + if ( phPack == NULL || *phPack == NULL ) + { + return; + } + + hPack = *phPack; + QUEUE_Destroy( &hPack->frameQ ); + mtx_destroy( &hPack->apilock ); + BPOOL_Destroy( &hPack->packNodePool ); + free( hPack->header.extData ); + free( hPack ); + *phPack = NULL; +} + +ivas_error IVAS_RTP_PACK_PushRemoteRequest( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + IVAS_RTP_REQUEST_TYPE reqType, /* i : remote request type */ + IVAS_RTP_REQUEST_VALUE reqValue /* i : value of the requested type */ +) +{ + if ( reqType < 0 || reqType >= IVAS_REQUEST_MAX ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid request key provided" ); + } + + /* Sanity on API */ + switch ( reqType ) + { + case IVAS_REQUEST_CODEC: + { + uint32_t codec = reqValue.codec; + if ( codec != IVAS_RTP_IVAS && codec != IVAS_RTP_EVS ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported codec id provided" ); + } + } + break; + case IVAS_REQUEST_BITRATE: + { + uint32_t bitrate = reqValue.bitrate; + if ( bitrate < 5900 || bitrate > 512000 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate provided" ); + } + } + break; + case IVAS_REQUEST_BANDWIDTH: + { + uint32_t bandwidth = reqValue.bandwidth; + if ( bandwidth > IVAS_BANDWIDTH_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bandwidth provided" ); + } + } + break; + case IVAS_REQUEST_FORMAT: + { + uint32_t format = reqValue.formatType; + if ( format > IVAS_FMT_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported format provided" ); + } + } + break; + case IVAS_REQUEST_CA_MODE: + { + uint32_t caMode = reqValue.caMode; + if ( caMode > IVAS_RTP_CA_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported channel aware mode provided" ); + } + } + break; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_REQUEST_SUBFORMAT: + { + uint32_t subFormat = reqValue.subFormatType; + if ( subFormat > IVAS_SUBFMT_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported subformat provided" ); + } + } + break; + case IVAS_REQUEST_SR_CONFIG: + { + IVAS_RTP_SPLITRENDER srConfig = reqValue.srConfig; + if ( srConfig.reserved != 0 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported reserved bits in SR config provided" ); + } + } + break; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + default: + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported request type" ); + } + + hPack->requests[reqType] = reqValue; + + return IVAS_ERR_OK; +} + +static bool isAmrWBIOMode( uint32_t bitrate, uint32_t *idx ) +{ + size_t n; + *idx = 0; + for ( n = 0; n < sizeof( amrWBIOFrameSizeInBits ) / sizeof( amrWBIOFrameSizeInBits[0] ); n++ ) + { + if ( bitrate == ( amrWBIOFrameSizeInBits[n] * IVAS_NUM_FRAMES_PER_SEC ) ) + { + *idx = n; + return true; + } + } + return false; +} + +static uint32_t getBitrateIdx( const uint32_t *table, uint32_t tableLen, uint32_t bitrate ) +{ + size_t n, idx = 0; + + for ( n = 0; n < tableLen; n++ ) + { + if ( bitrate > ( table[n] * IVAS_NUM_FRAMES_PER_SEC ) ) + { + idx = n; + } + else + { + return idx; + } + } + return idx; +} + +static void packEBytes( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + bool piDataPresent, /* i : Signals if PI data present */ + size_t maxNumEBytes, /* i : max capacity of eByte buffer */ + uint8_t *eByte, /* o : output buffer for E-Bytes */ + size_t *nBytesWritten /* o : max capacity of eByte buffer */ +) +{ + /* Initial E-byte structure + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |H|T|T|T| BR | + * +-+-+-+-+-+-+-+-+ + */ + uint32_t nByte = 0; + uint8_t T = EBYTE_CMR_T_IVAS; /* IVAS */ + uint8_t BR = 0; + + IVAS_RTP_CODEC codec = hPack->requests[IVAS_REQUEST_CODEC].codec; + IVAS_RTP_BANDWIDTH bandwidth = hPack->requests[IVAS_REQUEST_BANDWIDTH].bandwidth; + uint32_t bitrate = hPack->requests[IVAS_REQUEST_BITRATE].bitrate; + uint32_t bitrateIdx = 0; + + *nBytesWritten = 0; + + if ( codec == IVAS_RTP_EVS ) + { + /* If requesting EVS/AMRWB IO from farend, only Initial E-byte present */ + IVAS_RTP_CA_MODE caMode = hPack->requests[IVAS_REQUEST_CA_MODE].caMode; + + if ( caMode != IVAS_RTP_CA_NO_REQ ) + { + T = ( bandwidth == IVAS_BANDWIDTH_SWB ) ? EBYTE_CMR_T_EVS_CA_SWB : EBYTE_CMR_T_EVS_CA_WB; + BR = caMode & MASK_3BIT; /* only 8 valid values */ + if ( nByte < maxNumEBytes ) + { + eByte[nByte++] = ( T | BR ); + } + } + else if ( bitrate > 0 && isAmrWBIOMode( bitrate, &bitrateIdx ) ) + { + /* AMR WB IO Mode */ + T = EBYTE_CMR_T_EVS_IO; + BR = (uint8_t) bitrateIdx & MASK_4BIT; + if ( nByte < maxNumEBytes ) + { + eByte[nByte++] = ( T | BR ); + } + } + else if ( bitrate > 0 ) + { + /* EVS Modes */ + bitrate = ( bitrate > 128000 ) ? 128000 : bitrate; + bitrate = ( bitrate < 5900 ) ? 5900 : bitrate; + bitrateIdx = getBitrateIdx( evsFrameSizeInBits, sizeof( evsFrameSizeInBits ) / sizeof( evsFrameSizeInBits[0] ), bitrate ); + BR = (uint8_t) bitrateIdx & MASK_4BIT; + + /* If a bandwidth choice cannot be signalled for a given bitrate + preference is given to bitrate choice, bandwidth req is modified */ + switch ( bandwidth ) + { + case IVAS_BANDWIDTH_NB: + T = ( bitrate <= 24400u ) ? EBYTE_CMR_T_EVS_NB : EBYTE_CMR_T_EVS_SWB; + break; + case IVAS_BANDWIDTH_WB: + T = EBYTE_CMR_T_EVS_WB; + break; + case IVAS_BANDWIDTH_SWB: + T = ( bitrate >= 9600u ) ? EBYTE_CMR_T_EVS_SWB : EBYTE_CMR_T_EVS_WB; + break; + case IVAS_BANDWIDTH_FB: + T = ( bitrate >= 16400u ) ? EBYTE_CMR_T_EVS_FB : EBYTE_CMR_T_EVS_WB; + break; + default: /*IVAS_BANDWIDTH_NO_REQ */ + T = ( bitrate >= 9600u ) ? EBYTE_CMR_T_EVS_SWB : EBYTE_CMR_T_EVS_WB; + break; + } + if ( nByte < maxNumEBytes ) + { + eByte[nByte++] = ( T | BR ); + } + } + else if ( piDataPresent ) + { + /* Send an initial E-byte to allow for subsequent PI indication E-byte */ + if ( nByte < maxNumEBytes ) + { + eByte[nByte++] = EBYTE_CMR_T_NO_REQ; + } + } + } + else + { + /* Requesting IVAS from farend, Subsequent E-byte indicate BW, CFR, SR */ + IVAS_RTP_FORMAT format = hPack->requests[IVAS_REQUEST_FORMAT].formatType; + bool isBandwidthProvided = ( bandwidth != IVAS_BANDWIDTH_NO_REQ && bandwidth != IVAS_BANDWIDTH_NB ); + bool isFormatProvided = ( format != IVAS_FMT_NO_REQ ); + bool isSubFormatProvided = false; + bool isSRConfigProvided = false; + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SUBFORMAT subFormat = hPack->requests[IVAS_REQUEST_SUBFORMAT].subFormatType; + IVAS_RTP_SPLITRENDER srConfig = hPack->requests[IVAS_REQUEST_SR_CONFIG].srConfig; + + isSubFormatProvided = ( subFormat != IVAS_SUBFMT_NO_REQ ); + isSRConfigProvided = srConfig.valid; +#endif + + /* Initial E-Byte only sent if either bitrate requested or subsequent E-byte is requested */ + if ( !( ( bitrate > 0 ) || isBandwidthProvided || isFormatProvided || + isSubFormatProvided || isSRConfigProvided || piDataPresent ) ) + { + return; + } + + if ( bitrate > 0 ) + { + /* Initial E-Byte */ + bitrate = ( bitrate > 512000 ) ? 512000 : bitrate; + bitrate = ( bitrate < 13200 ) ? 13200 : bitrate; + bitrateIdx = getBitrateIdx( ivasFrameSizeInBits, sizeof( ivasFrameSizeInBits ) / sizeof( ivasFrameSizeInBits[0] ), bitrate ); + BR = (uint8_t) bitrateIdx & MASK_4BIT; + if ( nByte < maxNumEBytes ) + { + eByte[nByte++] = ( EBYTE_CMR_T_IVAS | BR ); + } + } + else + { + if ( nByte < maxNumEBytes ) + { + eByte[nByte++] = EBYTE_CMR_T_NO_REQ; + } + } + + /* Subsequent E-bytes - Bandwidth Request */ + if ( isBandwidthProvided && nByte < maxNumEBytes ) + { + uint8_t bw = ( bandwidth - IVAS_BANDWIDTH_WB ) & MASK_2BIT; + eByte[nByte++] = ( EBYTE_BANDWIDTH_REQUEST | bw ); + } + + /* Subsequent E-bytes - Coded Format Request */ + if ( ( isFormatProvided || isSubFormatProvided ) && nByte < maxNumEBytes ) + { + uint8_t fmtEByte = ( EBYTE_FORMAT_REQUEST | ( (uint8_t) format & MASK_3BIT ) ); + eByte[nByte++] = isSubFormatProvided ? EBYTE_SUBFORMAT_REQUEST : fmtEByte; + } +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( isSubFormatProvided && nByte < maxNumEBytes ) + { + eByte[nByte++] = ( (uint8_t) subFormat & MASK_6BIT ); /* Requested Coded subFormat */ + } + /* Subsequent E-bytes - Split Renderer Configuration Request */ + if ( isSRConfigProvided && nByte < maxNumEBytes ) + { + eByte[nByte++] = EBYTE_SR_REQUEST | + ( (uint8_t) srConfig.diegetic << 3 ) | ( (uint8_t) srConfig.yaw << 2 ) | + ( (uint8_t) srConfig.pitch << 1 ) | ( (uint8_t) srConfig.roll << 0 ); + } +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + } + + /* Final E-byte is the PI Indicator E-Byte */ + if ( piDataPresent && ( nByte < maxNumEBytes ) ) + { + eByte[nByte++] = EBYTE_PI_INDICATOR; /* PI Indication */ + } + + *nBytesWritten = nByte; +} + + +#ifdef RTP_S4_251135_CR26253_0016_REV1 +static ivas_error getSRToCByte( + IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */ + uint32_t bitrateKbps, /* i : Bitrate in kbps */ + uint8_t *tocByte /* o : toc byte 2 */ +) +{ + uint8_t bitIdx, codecId, digetic; + if ( bitrateKbps < 256000 || bitrateKbps > 512000 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate for SR" ); + } + + bitIdx = ( ( bitrateKbps / 128000u ) - 1 ) & MASK_2BIT; + codecId = (uint8_t) srInfo->codec; + digetic = srInfo->diegetic ? 1 : 0; + + *tocByte = ( digetic << 6 ) | ( codecId << 5 ) | ( bitIdx << 3 ); + + return IVAS_ERR_OK; +} +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + +static void addPackedPiDataToFrame( PIDATA_FRAME *piDataFrm, const PIDATA_PACKED *packedPiData, uint32_t piDataType ) +{ + piDataFrm->piData[piDataType].size = packedPiData->size; + memcpy( piDataFrm->piData[piDataType].data, packedPiData->data, packedPiData->size ); + + /* Indicate th PI data type presense in bitmap, If the same pi data type is + already pushed for this frame, it is overwritten with the newer data */ + if ( !( piDataFrm->piDataBitmap & ( 1u << piDataType ) ) ) + { + piDataFrm->piDataBitmap |= ( 1u << piDataType ); + piDataFrm->numPiDataAvailable++; + } + + /* Atleast one valid PI data is now pushed for this frame, clear No PI data + for this frame */ + if ( piDataFrm->piDataBitmap & ( 1u << IVAS_PI_NO_DATA ) ) + { + piDataFrm->piDataBitmap &= ~( 1u << IVAS_PI_NO_DATA ); + piDataFrm->numPiDataAvailable--; + } +} + +ivas_error IVAS_RTP_PACK_PushFrame( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */ +) +{ + ivas_error error = IVAS_ERR_OK; + uint32_t bitrate = 0; + uint32_t frameLengthInBits = 0; + uint8_t tocByte = 0; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + uint8_t tocByte1 = 0; +#endif + FRAME_NODE *node = NULL; + PIDATA_FRAME *piDataFrame = &hPack->piDataCache; + uint32_t piDataType = 0; + + if ( frameBuffer == NULL || frameBuffer->length == 0 ) + { + /* Indicates a NO_DATA_FRAME in case of DTX mode */ + tocByte = ( hPack->amrwbIOMode ) ? TOC_INDICATE_NO_DATA_AMRWB : TOC_INDICATE_NO_DATA; + } +#ifdef RTP_S4_251135_CR26253_0016_REV1 + else if ( srInfo != NULL && srInfo->valid ) + { + tocByte = TOC_INDICATE_SR; + error = getSRToCByte( srInfo, bitrate, &tocByte1 ); + ERR_CHECK_RETURN( error ); + } +#endif + else + { + error = getBitrateFromCodecAndFrameSize( codecId, frameBuffer->length, &bitrate, &frameLengthInBits, &tocByte, &hPack->amrwbIOMode ); + ERR_CHECK_RETURN( error ); + } + + /* Allocate a new frame node for this frame */ + error = BPOOL_GetBuffer( hPack->packNodePool, (void **) &node ); + ERR_CHECK_RETURN( error ); + + initFrameNode( node ); + + /* Set ToC byte & frame */ + node->toc[node->tocNumBytes++] = tocByte; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( srInfo != NULL && srInfo->valid ) + { + node->toc[node->tocNumBytes++] = tocByte1; + } +#endif + + node->auNumBits = frameLengthInBits; + if ( frameBuffer != NULL ) + { + memcpy( node->au, frameBuffer->buffer, frameBuffer->length ); + } + + /* If some Pi data is is Cache add to Frame Node's associated Pi Data */ + mtx_lock( &hPack->apilock ); /* Lock to prevent access to shared cache */ + if ( piDataFrame->numPiDataAvailable ) + { + uint32_t bitmap = piDataFrame->piDataBitmap; + for ( piDataType = 0; piDataType < 32 && ( bitmap != 0 ); piDataType++ ) + { + uint32_t mask = ( 1u << piDataType ); + if ( bitmap & mask ) + { + bitmap &= ~mask; /* Mask out this pi type to indicate processed */ + addPackedPiDataToFrame( &node->piDataFrame, &piDataFrame->piData[piDataType], piDataType ); + } + } + initPiDataFrame( piDataFrame ); /* Reset Cache */ + } + mtx_unlock( &hPack->apilock ); + + /* Add to frames FiFo */ + QUEUE_Push( hPack->frameQ, (NODE *) node ); + + return IVAS_ERR_OK; +} + +uint32_t IVAS_RTP_PACK_GetNumFrames( + IVAS_RTP_PACK_HANDLE hPack /* i/o : IVAS rtp packer handle */ +) +{ + uint32_t nFrames = 0; + if ( hPack ) + { + nFrames = QUEUE_Size( hPack->frameQ ); + } + return nFrames; +} + +/* Push single PI data to rtp packer + * + * Provide PI data for a current RTP Payload. All PI data is locally cached in the packer + * and set to the rtp packet with policy defined in initial configuration during call to + * IVAS_RTP_PACK_GetPacket. + * + */ +ivas_error IVAS_RTP_PACK_PushPiData( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + const IVAS_PIDATA_GENERIC *data /* i : pointer to the PIData stucture */ +) +{ + ivas_error error = IVAS_ERR_OK; + PIDATA_PACKED packedPiData; + + if ( data == NULL || + data->piDataType >= IVAS_PI_NO_DATA || /* NO_PI_DATA cannot be provided by user, it is generated in packing */ + data->size > sizeof( PIDATA ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong PI Data provided" ); + } + + error = PI_PackData( data, &packedPiData, 0 ); + ERR_CHECK_RETURN( error ); + + mtx_lock( &hPack->apilock ); /* Lock to prevent access to shared cache */ + { + FRAME_NODE *node = (FRAME_NODE *) QUEUE_Back( hPack->frameQ ); + /* use cache if no frame in Queue to associate PI data */ + PIDATA_FRAME *piDataFrm = ( node != NULL ) ? &node->piDataFrame : &hPack->piDataCache; + addPackedPiDataToFrame( piDataFrm, &packedPiData, data->piDataType ); + } + mtx_unlock( &hPack->apilock ); + + return IVAS_ERR_OK; +} + +#define WRITE_BYTE_PAYLOAD_OR_EXIT( payload, byte ) \ + if ( payload->length < payload->capacity ) \ + { \ + uint8_t _byte = ( byte ); \ + payload->buffer[payload->length++] = _byte; \ + } \ + else \ + { \ + error = IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); \ + goto err_exit; \ + } + +ivas_error IVAS_RTP_PACK_GetPayload( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + IVAS_DATA_BUFFER *payload, /* o : encapsulated rtp payload */ + uint32_t *numFramesInPayload /* o : no. of frames in payload */ +) +{ + uint32_t n = 0, numFrame = 0; + ivas_error error = IVAS_ERR_OK; + uint32_t numPiDataPresent = 0; + FRAME_NODE *availableFrameNodes[IVAS_MAX_FRAMES_PER_RTP_PACKET]; + size_t numEBytes = 0; + + if ( payload == NULL ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Output data buffer is NULL" ); + } + + /* Calculate number of frames to pack in this payload */ + numFrame = QUEUE_Size( hPack->frameQ ); + numFrame = ( numFrame > hPack->initConfig.maxFramesPerPacket ) ? hPack->initConfig.maxFramesPerPacket : numFrame; + *numFramesInPayload = numFrame; /* numFrames in Packet */ + + /* Collect all the frame nodes from FiFo */ + for ( n = 0; n < numFrame; n++ ) + { + FRAME_NODE *node = (FRAME_NODE *) QUEUE_Pop( hPack->frameQ ); + if ( node == NULL ) + { + assert( 0 ); /* catastrophic error, implementation issue somewhere */ + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "NULL found in frame nodes" ); + } + /* Calculate number of PI data present in total */ + numPiDataPresent += node->piDataFrame.numPiDataAvailable; + availableFrameNodes[n] = node; + } + + /* IVAS Payload starts with E-Bytes */ + packEBytes( hPack, ( numPiDataPresent > 0 ), payload->capacity, &payload->buffer[payload->length], &numEBytes ); + payload->length += numEBytes; + + /* ToC bytes (atleast 1 byte per frame, 2 if SR )*/ + for ( n = 0; n < numFrame; n++ ) + { + FRAME_NODE *node = availableFrameNodes[n]; + uint8_t fBit = ( n != ( numFrame - 1 ) ) ? TOC_HEADER_FOLLOWS : 0; /* Next ToC present */ + + WRITE_BYTE_PAYLOAD_OR_EXIT( payload, ( node->toc[0] | fBit ) ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( node->tocNumBytes == 2 ) + { + WRITE_BYTE_PAYLOAD_OR_EXIT( payload, node->toc[1] ); + } +#endif + } + + /* Frame Data */ + for ( n = 0; n < numFrame; n++ ) + { + FRAME_NODE *node = availableFrameNodes[n]; + size_t frameLength = ( node->auNumBits + 7 ) >> 3; /* zero padded length in bytes */ + if ( payload->length + frameLength <= payload->capacity ) + { + memcpy( &payload->buffer[payload->length], node->au, frameLength ); + } + else + { + error = IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + goto err_exit; + } + payload->length += frameLength; + } + + /* PI Data */ + if ( numPiDataPresent > 0 ) + { + bool skipPiData = false; + size_t nBytes = payload->length; + uint32_t numPiDataWritten = 0; + + for ( n = 0; n < numFrame; n++ ) + { + uint32_t piDataType = 0; + FRAME_NODE *node = availableFrameNodes[n]; + PIDATA_FRAME *piDataFrame = &node->piDataFrame; + uint32_t bitmap = piDataFrame->piDataBitmap; + uint8_t PM = 0, PF = 0; + + for ( piDataType = 0; piDataType < 32 && ( bitmap != 0 ); piDataType++ ) + { + uint32_t mask = ( 1u << piDataType ); + if ( bitmap & mask ) + { + bitmap &= ~mask; /* Mask out this pi type to indicate processing */ + /* Check if last PI data this frame */ + PM = piDataFrame->piData[piDataType].data[0] & 0x60; + PM = (uint8_t) ( ( bitmap == 0 && PM != PI_HEADER_PM_GENERIC ) ? PI_HEADER_PM_LAST : PM ); + /* Check if last PI data all frames */ + PF = (uint8_t) ( ( bitmap == 0 && ( numPiDataWritten + 1 == numPiDataPresent ) ) ? PI_HEADER_PF_LAST : PI_HEADER_PF_NOT_LAST ); /* Last PI in Payload */ + /* Update the first byte of PI Header with PF/PM */ + piDataFrame->piData[piDataType].data[0] |= ( PF | PM ); + if ( nBytes + piDataFrame->piData[piDataType].size < payload->capacity ) + { + memcpy( &payload->buffer[nBytes], piDataFrame->piData[piDataType].data, piDataFrame->piData[piDataType].size ); + nBytes += piDataFrame->piData[piDataType].size; + } + else + { + skipPiData = true; /* Not enough bytes in output for PI data */ + } + numPiDataWritten++; + } + } + } + if ( !skipPiData ) + { + payload->length = nBytes; /* update payload length after PI packing */ + } + } + +err_exit: + /* Pop frames from Queue */ + for ( n = 0; n < numFrame; n++ ) + { + if ( BPOOL_FreeBuffer( hPack->packNodePool, availableFrameNodes[n] ) != IVAS_ERR_OK ) + { + assert( 0 ); /* catastrophic error if this fails */ + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "frame node could not be freed" ); + } + availableFrameNodes[n] = NULL; + } + + return error; +} + +ivas_error IVAS_RTP_PACK_GetPacket( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + IVAS_DATA_BUFFER *packet, /* o : encapsulated rtp packet */ + uint32_t *numFramesInPacket /* o : no. of frames in packet */ +) +{ + ivas_error error = PackRtpHeader( &hPack->header, packet ); + ERR_CHECK_RETURN( error ); + + error = IVAS_RTP_PACK_GetPayload( hPack, packet, numFramesInPacket ); + ERR_CHECK_RETURN( error ); + + UpdateRtpHeader( &hPack->header, ( *numFramesInPacket ) * 320 ); + + return IVAS_ERR_OK; +} + +ivas_error IVAS_RTP_UNPACK_Open( + IVAS_RTP_UNPACK_HANDLE *phUnpack, /* i/o : rtp unpacker handle */ + const IVAS_RTP_UNPACK_CONFIG *config /* i : initial configuration for rtp unpacker */ +) +{ + ivas_error error = IVAS_ERR_OK; + IVAS_RTP_UNPACK_HANDLE hUnpack; + + if ( phUnpack == NULL || config == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + *phUnpack = NULL; + if ( ( hUnpack = (IVAS_RTP_UNPACK_HANDLE) calloc( 1, sizeof( struct IVAS_RTP_UNPACK ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtp unpack handle" ); + } + + if ( config->maxFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Max frame per packet exeeds %d", IVAS_MAX_FRAMES_PER_RTP_PACKET ); + } + + hUnpack->maxNumberOfFrames = ( config->maxFramesPerPacket == 0 ) ? IVAS_MAX_FRAMES_PER_RTP_PACKET : config->maxFramesPerPacket; + hUnpack->maxNumberOfPiData = hUnpack->maxNumberOfFrames * IVAS_PI_MAX_ID; + + error = BPOOL_Create( &hUnpack->unpackNodePool, sizeof( UNPACK_NODE ), hUnpack->maxNumberOfFrames ); + ERR_CHECK_RETURN( error ); + + error = BPOOL_Create( &hUnpack->piDataPool, sizeof( PIDATA_NODE ), hUnpack->maxNumberOfPiData ); + ERR_CHECK_RETURN( error ); + + error = QUEUE_Create( &hUnpack->frameQ ); + ERR_CHECK_RETURN( error ); + + error = QUEUE_Create( &hUnpack->piDataQ ); + ERR_CHECK_RETURN( error ); + + hUnpack->initConfig = *config; + mtx_init( &hUnpack->apilock, 0 ); + + initRequests( hUnpack->requests ); + + *phUnpack = hUnpack; + return IVAS_ERR_OK; +} + +/* Close and free an existing instance of rtp unpacker */ +void IVAS_RTP_UNPACK_Close( + IVAS_RTP_UNPACK_HANDLE *phUnpack /* i/o : IVAS rtp unpacker handle */ +) +{ + IVAS_RTP_UNPACK_HANDLE hUnpack; + + /* Free all memory */ + if ( phUnpack == NULL || *phUnpack == NULL ) + { + return; + } + + hUnpack = *phUnpack; + mtx_destroy( &hUnpack->apilock ); + QUEUE_Destroy( &hUnpack->frameQ ); + QUEUE_Destroy( &hUnpack->piDataQ ); + BPOOL_Destroy( &hUnpack->piDataPool ); + BPOOL_Destroy( &hUnpack->unpackNodePool ); + free( hUnpack->header.extData ); + free( hUnpack ); + *phUnpack = NULL; +} + +static void setEVSRequests( IVAS_RTP_BANDWIDTH bandwidth, uint32_t bitrate, IVAS_RTP_CA_MODE caMode, IVAS_RTP_REQUEST_VALUE *requests ) +{ + requests[IVAS_REQUEST_CODEC].codec = IVAS_RTP_EVS; + requests[IVAS_REQUEST_CA_MODE].caMode = caMode; + requests[IVAS_REQUEST_BITRATE].bitrate = bitrate; + requests[IVAS_REQUEST_BANDWIDTH].bandwidth = bandwidth; +} + +static uint32_t parseInitialEByte( const IVAS_DATA_BUFFER *payload, uint32_t nBytes, IVAS_RTP_REQUEST_VALUE *requests ) +{ + if ( nBytes < payload->length ) + { + uint8_t byte = payload->buffer[nBytes]; + uint8_t EvsIvasIndicator = ( byte & ( ~MASK_4BIT ) ); + uint8_t BR = ( byte & MASK_4BIT ); + + if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 ) + { + return nBytes; + } + + nBytes++; /* Consume this e-byte */ + + switch ( EvsIvasIndicator ) + { + case EBYTE_CMR_T_EVS_NB: + if ( BR < 7 ) + { + uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC; + setEVSRequests( IVAS_BANDWIDTH_NB, bitrate, IVAS_RTP_CA_NO_REQ, requests ); + } + break; + case EBYTE_CMR_T_EVS_IO: /* AMRWB-IO */ + if ( BR < 9 ) + { + uint32_t bitrate = amrWBIOFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC; + setEVSRequests( IVAS_BANDWIDTH_NO_REQ, bitrate, IVAS_RTP_CA_NO_REQ, requests ); + } + break; + case EBYTE_CMR_T_EVS_CA_WB: + if ( BR < 8 ) + { + uint32_t bitrate = 13200; /* Fixed in CA Mode */ + setEVSRequests( IVAS_BANDWIDTH_WB, bitrate, BR, requests ); + } + break; + case EBYTE_CMR_T_EVS_CA_SWB: + if ( BR < 8 ) + { + uint32_t bitrate = 13200; /* Fixed in CA Mode */ + setEVSRequests( IVAS_BANDWIDTH_SWB, bitrate, BR, requests ); + } + break; + case EBYTE_CMR_T_EVS_WB: + if ( BR < 12 ) + { + uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC; + setEVSRequests( IVAS_BANDWIDTH_WB, bitrate, IVAS_RTP_CA_NO_REQ, requests ); + } + break; + case EBYTE_CMR_T_EVS_SWB: /* Intentional fall through */ + if ( BR < 12 && BR > 2 ) + { + uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC; + setEVSRequests( IVAS_BANDWIDTH_SWB, bitrate, IVAS_RTP_CA_NO_REQ, requests ); + } + break; + case EBYTE_CMR_T_EVS_FB: + if ( BR < 12 && BR > 4 ) + { + uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC; + setEVSRequests( IVAS_BANDWIDTH_FB, bitrate, IVAS_RTP_CA_NO_REQ, requests ); + } + break; + case EBYTE_CMR_T_IVAS: /* IVAS */ + if ( BR != 14 ) + { + requests[IVAS_REQUEST_CODEC].codec = IVAS_RTP_IVAS; + requests[IVAS_REQUEST_BITRATE].bitrate = ( BR == 0xF ) ? 0 : ivasFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC; + requests[IVAS_REQUEST_CA_MODE].caMode = IVAS_RTP_CA_NO_REQ; + } + break; + } + } + + return nBytes; +} + +static uint32_t parseSubsequentEByte( const IVAS_DATA_BUFFER *payload, uint32_t nBytes, IVAS_RTP_REQUEST_VALUE *requests, bool *piDataIndicated ) +{ + while ( nBytes < payload->length ) + { + uint8_t byte = payload->buffer[nBytes]; + uint8_t ET = ( byte & ( ~MASK_4BIT ) ); + + if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 ) + { + return nBytes; + } + + nBytes++; /* Consume this e-byte */ + + switch ( ET ) + { + case EBYTE_BANDWIDTH_REQUEST: /* Bandwidth Request */ + { + requests[IVAS_REQUEST_BANDWIDTH].bandwidth = IVAS_BANDWIDTH_WB + ( byte & MASK_2BIT ); + } + break; + case EBYTE_FORMAT_REQUEST: /* Format Request */ + { +#ifdef RTP_S4_251135_CR26253_0016_REV1 + bool S = ( byte >> 3 ) & MASK_1BIT; + if ( S ) + { + /* Use the next byte to extract SubFormat */ + if ( nBytes < payload->length ) + { + byte = payload->buffer[nBytes++]; + requests[IVAS_REQUEST_SUBFORMAT].subFormatType = byte & MASK_6BIT; + } + } +#endif + requests[IVAS_REQUEST_FORMAT].formatType = byte & MASK_3BIT; + } + break; + case EBYTE_PI_INDICATOR: /* PI Indication */ + *piDataIndicated = true; + break; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case EBYTE_SR_REQUEST: /* Split Rendering Request */ + { + IVAS_RTP_SPLITRENDER *srConfig = &requests[IVAS_REQUEST_SR_CONFIG].srConfig; + srConfig->diegetic = ( byte >> 3 ) & MASK_1BIT; + srConfig->yaw = ( byte >> 2 ) & MASK_1BIT; + srConfig->pitch = ( byte >> 1 ) & MASK_1BIT; + srConfig->roll = byte & MASK_1BIT; + srConfig->valid = true; + } + break; +#endif + default: /* Reserved for future use - unhandled atm */ + assert( 0 ); + } + } + + return nBytes; +} + +static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc, uint32_t maxNumberOfToCBytes ) +{ + bool headerFollows = true; + uint32_t nBytes = *numBytes; + + *numFrames = 0; + while ( nBytes < payload->length && headerFollows ) + { + uint8_t byte = payload->buffer[nBytes]; + uint8_t BR = byte & MASK_4BIT; + uint8_t FT = byte & ( ( ~MASK_4BIT ) & MASK_6BIT ); + + headerFollows = ( byte & ( ~MASK_6BIT ) ) == TOC_HEADER_FOLLOWS; + + if ( ( byte & EBYTE_TOC_HEADER_BIT ) != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Expected ToC byte missing" ); + } + + nBytes++; /* Consume this e-byte */ + + if ( *numFrames == maxNumberOfToCBytes ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "No of frames in packet exceed max defined" ); + } + + *numFrames += 1; + memset( toc, 0, sizeof( *toc ) ); + + if ( FT == TOC_INDICATE_ARMWB_Q || FT == TOC_INDICATE_AMRWB ) + { + toc->codecId = IVAS_RTP_EVS; + toc->isAMRWB_IOmode = true; + toc->speechLostIndicated = ( FT == TOC_INDICATE_ARMWB_Q ) ? true : false; /* Q bit = 0 for AMRWB, BR is valid */ + if ( BR <= 9 ) + { + toc->auNumBits = amrWBIOFrameSizeInBits[BR]; + } + else if ( BR < 14 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved bitrate provided in AMRWB ToC" ); + } + else + { + toc->speechLostIndicated = ( BR == 14 ); /* SPEECH_LOST */ + toc->auNumBits = 0; + } + } + else if ( FT == TOC_INDICATE_IVAS ) + { + toc->codecId = IVAS_RTP_IVAS; + if ( BR == 14 ) + { +#ifdef RTP_S4_251135_CR26253_0016_REV1 + /* Read Unconditional SR-ToC byte */ + if ( nBytes < payload->length ) + { + uint8_t SR_BR; + byte = payload->buffer[nBytes++]; + SR_BR = ( byte >> 3 ) & MASK_2BIT; + if ( SR_BR == 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved bitrate provided in SR ToC" ); + } + toc->srInfo.valid = true; + toc->srInfo.diegetic = ( byte >> 6 ) & MASK_1BIT; + toc->srInfo.codec = IVAS_SR_TRANSPORT_LCLD + ( ( byte >> 5 ) & MASK_1BIT ); + toc->auNumBits = ( SR_BR + 1 ) * 128000u / IVAS_NUM_FRAMES_PER_SEC; + } + else + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during ToC SR byte" ); + } +#else + /* Reserved bit not expected */ + return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved BR idx reported in ToC" ); +#endif + } + else + { + toc->auNumBits = ivasFrameSizeInBits[BR]; + } + } + else /* EVS */ + { + toc->codecId = IVAS_RTP_EVS; + toc->speechLostIndicated = ( FT == TOC_INDICATE_ARMWB_Q ) ? true : false; /* Q bit = 0 for AMRWB, BR is valid */ + if ( BR < 13 ) + { + toc->auNumBits = evsFrameSizeInBits[BR]; + } + else if ( BR == 13 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved bitrate provided in EVS ToC" ); + } + else + { + toc->speechLostIndicated = ( BR == 14 ); /* SPEECH_LOST */ + toc->auNumBits = 0; + } + } + + toc++; + + /* Handle any frame specific E-Bytes here currently there are none, so we skip any E-Bytes here after */ + if ( headerFollows ) + { + while ( nBytes < payload->length ) + { + byte = payload->buffer[nBytes]; + if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 ) + { + break; + } + nBytes++; + } + } + } + + *numBytes = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimestamp, const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numPiDataInPacket ) +{ + bool PF = true; + uint32_t nBytes = *numBytes; + + while ( PF ) + { + uint8_t piHeader0, PM, piDataType, byte = 0; + uint32_t piSize = 0; + + if ( nBytes + 1 >= payload->length ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during expected PI Header read" ); + } + + piHeader0 = payload->buffer[nBytes++]; + + PF = ( piHeader0 >> 7 ) & MASK_1BIT; /* New PI header follows this PI Data Frame */ + PM = ( piHeader0 & ( ~MASK_5BIT ) ) & MASK_7BIT; /* PI Marker Bits */ + piDataType = ( piHeader0 & MASK_5BIT ); + + do + { + byte = payload->buffer[nBytes++]; + piSize += byte; + if ( nBytes >= payload->length ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during reading piSize" ); + } + } while ( byte == 255 ); + + if ( piDataType == IVAS_PI_NO_DATA ) + { + if ( piSize > 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "NO_PI_DATA should be 0 sized" ); + } + + /* Do not add a node for NO_DATA */ + } + else if ( nBytes + piSize <= payload->length ) + { + PIDATA_NODE *node = NULL; + ivas_error error = BPOOL_GetBuffer( hUnpack->piDataPool, (void **) &node ); + ERR_CHECK_RETURN( error ); + + node->next = NULL; + + error = PI_UnPackData( piDataType, piSize, &payload->buffer[nBytes], (IVAS_PIDATA_GENERIC *) &node->data ); + ERR_CHECK_RETURN( error ); + + node->timestamp = rtpTimestamp; + + nBytes += piSize; + *numPiDataInPacket += 1; + + QUEUE_Push( hUnpack->piDataQ, (NODE *) node ); + } + else + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during reading pi data" ); + } + + if ( PM == PI_HEADER_PM_LAST ) + { + rtpTimestamp += 16000 / IVAS_NUM_FRAMES_PER_SEC; + } + } + + *numBytes = nBytes; + return IVAS_ERR_OK; +} + +ivas_error IVAS_RTP_UNPACK_PushPayload( + IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */ + const IVAS_DATA_BUFFER *payload, /* i : received rtp payload */ + uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */ + uint16_t sequenceNumber, /* i : sequence number from rtp header */ + uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */ + uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */ + uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */ +) +{ + ivas_error error = IVAS_ERR_OK; + uint32_t nBytes = 0, numFrames = 0, numPiData = 0, n; + bool piDataIndicated = false; + TOC_INFO toc[IVAS_MAX_FRAMES_PER_RTP_PACKET]; + + IVAS_RTP_REQUEST_VALUE oldRequests[IVAS_REQUEST_MAX]; + + if ( hUnpack == NULL || payload == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( remoteRequestBitmap != NULL ) + { + *remoteRequestBitmap = 0; + } + + if ( numFramesInPacket != NULL ) + { + *numFramesInPacket = 0; + } + + if ( numPiDataInPacket != NULL ) + { + *numPiDataInPacket = 0; + } + + /* Sanity check if any frame or PI data from last packet is still not pulled */ + if ( QUEUE_Size( hUnpack->frameQ ) > 0 || QUEUE_Size( hUnpack->piDataQ ) > 0 ) + { + assert( 0 ); + return IVAS_ERROR( IVAS_ERR_INTERNAL, "Previous packet data should be consumed before next packet is pushed" ); + } + + memcpy( oldRequests, hUnpack->requests, sizeof( oldRequests ) ); + + /* Unpack IVAS Payload, starting with the E-Bytes */ + nBytes = parseInitialEByte( payload, nBytes, hUnpack->requests ); + + /* Unpack any subsequent E-bytes */ + nBytes = parseSubsequentEByte( payload, nBytes, hUnpack->requests, &piDataIndicated ); + + /* Unpack the ToC Bytes => Extract number of frames in packet */ + error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ) ); + ERR_CHECK_RETURN( error ); + + /* Read frame bits */ + for ( n = 0; n < numFrames; n++ ) + { + uint32_t frameSizeBytes; + UNPACK_NODE *node = NULL; + + /* Get a new node */ + error = BPOOL_GetBuffer( hUnpack->unpackNodePool, (void **) &node ); + ERR_CHECK_RETURN( error ); + + node->next = NULL; + node->timestamp = timestamp + ( n * 320 ); + node->seqNumber = sequenceNumber; + node->toc = toc[n]; + + frameSizeBytes = ( node->toc.auNumBits + 7 ) / 8; + if ( nBytes + frameSizeBytes <= payload->length ) + { + memcpy( node->au, &payload->buffer[nBytes], frameSizeBytes ); + nBytes += frameSizeBytes; + } + else + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during expected frame bits" ); + } + + /* Add to frames FiFo */ + QUEUE_Push( hUnpack->frameQ, (NODE *) node ); + } + + if ( piDataIndicated ) + { + error = parsePIData( hUnpack, timestamp, payload, &nBytes, &numPiData ); + if ( error != IVAS_ERR_OK ) + { + /* PI Parsing errors are not fatal => indicate no PI data in packet as workaround */ + numPiData = 0; + } + } + + if ( numFramesInPacket != NULL ) + { + *numFramesInPacket = numFrames; + } + + if ( numPiDataInPacket ) + { + *numPiDataInPacket = numPiData; + } + + if ( remoteRequestBitmap ) + { + for ( n = 0; n < IVAS_REQUEST_MAX; n++ ) + { + bool changed = ( memcmp( &hUnpack->requests[n], &oldRequests[n], sizeof( IVAS_RTP_REQUEST_VALUE ) ) != 0 ); + *remoteRequestBitmap |= changed ? ( 1u << n ) : 0; + } + } + + return IVAS_ERR_OK; +} + +ivas_error IVAS_RTP_UNPACK_PushPacket( + IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */ + const IVAS_DATA_BUFFER *packet, /* i : received rtp Packet */ + uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */ + uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */ + uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */ +) +{ + ivas_error error = IVAS_ERR_OK; + uint32_t numHeaderBytes = 0; + IVAS_DATA_BUFFER payload; + + error = UnpackRtpPacket( packet, &hUnpack->header, &numHeaderBytes ); + ERR_CHECK_RETURN( error ); + + /* Offset to RTP Payload */ + payload.capacity = packet->capacity; + payload.buffer = packet->buffer + numHeaderBytes; + payload.length = packet->length - numHeaderBytes; + + return IVAS_RTP_UNPACK_PushPayload( + hUnpack, + &payload, + hUnpack->header.timestamp, + hUnpack->header.seqNumber, + numFramesInPacket, + numPiDataInPacket, + remoteRequestBitmap ); +} + +ivas_error IVAS_RTP_UNPACK_GetRequest( + IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp packer handle */ + IVAS_RTP_REQUEST_TYPE type, /* i : remote request type */ + IVAS_RTP_REQUEST_VALUE *value /* o : pointer of the requested type */ +) +{ + if ( type < 0 || type >= IVAS_REQUEST_MAX ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid request key provided" ); + } + *value = hUnpack->requests[type]; + return IVAS_ERR_OK; +} + +ivas_error IVAS_RTP_UNPACK_PullFrame( + IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */ + IVAS_RTP_CODEC *receivedCodecId, /* o : Codec type (IVAS/EVS) */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO *srInfo, /* o : Split Rendering Info */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + IVAS_DATA_BUFFER *frameBuffer, /* o : packed frame bitstream for IVAS/EVS */ + int16_t *frameSizeInBits, /* o : exact frame size in bits (AMRWB IO) */ + uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */ + uint16_t *sequenceNumber, /* o : sequence number from rtp header */ + bool *speechLostIndicated, /* o : Is current frame indicated as Lost */ + bool *isAMRWB_IOmode /* o : Is AMRWB_IO mode EVS frame */ +) +{ + size_t length = 0; + UNPACK_NODE *node = (UNPACK_NODE *) QUEUE_Pop( hUnpack->frameQ ); + + /* Check if a node is available in FiFo */ + if ( node == NULL ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "No more frames in unpack fifo" ); + } + + length = ( node->toc.auNumBits + 7 ) / 8; + if ( frameBuffer != NULL && ( length <= frameBuffer->capacity ) ) + { + memcpy( frameBuffer->buffer, node->au, length ); + frameBuffer->length = length; + } + + if ( frameSizeInBits != NULL ) + { + *frameSizeInBits = (int16_t) node->toc.auNumBits; + } + + if ( receivedCodecId != NULL ) + { + *receivedCodecId = node->toc.codecId; + } + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( srInfo != NULL ) + { + *srInfo = node->toc.srInfo; + } +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + + if ( timestamp != NULL ) + { + *timestamp = node->timestamp; + } + + if ( sequenceNumber != NULL ) + { + *sequenceNumber = node->seqNumber; + } + + if ( speechLostIndicated != NULL ) + { + *speechLostIndicated = node->toc.speechLostIndicated; + } + + if ( isAMRWB_IOmode != NULL ) + { + *isAMRWB_IOmode = node->toc.isAMRWB_IOmode; + } + + return BPOOL_FreeBuffer( hUnpack->unpackNodePool, node ); +} + +ivas_error IVAS_RTP_UNPACK_PullNextPiData( + IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */ + IVAS_PIDATA_GENERIC *data, /* o : output data buffer for the Pi data */ + size_t capacity, /* i : capacity of pi data buffer in bytes */ + uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */ +) +{ + IVAS_PIDATA_GENERIC *pi = NULL; + PIDATA_NODE *node = (PIDATA_NODE *) QUEUE_Pop( hUnpack->piDataQ ); + + /* Check if a node is available in FiFo */ + if ( node == NULL ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "No more pi data in unpack fifo" ); + } + + pi = (IVAS_PIDATA_GENERIC *) &node->data; + + if ( data != NULL && ( pi->size <= capacity ) ) + { + memcpy( data, pi, pi->size ); + } + + if ( timestamp != NULL ) + { + *timestamp = node->timestamp; + } + + return BPOOL_FreeBuffer( hUnpack->piDataPool, node ); +} + +#endif /* IVAS_RTPDUMP */ diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c new file mode 100644 index 000000000..7150cfe4a --- /dev/null +++ b/lib_util/ivas_rtp_pi_data.c @@ -0,0 +1,850 @@ +/****************************************************************************************************** + + (C) 2022-2025 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 "ivas_error_utils.h" +#include "ivas_rtp_internal.h" + +#ifdef IVAS_RTPDUMP + +/* Generic PI data packing/unpacking functions */ +typedef ivas_error ( *PACK_PI_FN )( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ); +typedef ivas_error ( *UNPACK_PI_FN )( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ); + +static __inline uint32_t writeInt16( uint8_t *buffer, uint32_t idx, int16_t val ) +{ + buffer[idx++] = (uint8_t) ( val >> 8 ); + buffer[idx++] = (uint8_t) ( val & 0x00FF ); + return idx; +} + +static __inline int16_t readInt16( const uint8_t *buffer ) +{ + return (int16_t) ( (uint16_t) buffer[0] << 8 ) | ( (uint16_t) buffer[1] ); +} + +/*-----------------------------------------------------------------------* + * ivasPayload_convertToQ15() + * + * Convert a float value into a Q15 encoded value. + *-----------------------------------------------------------------------*/ +static int16_t ivasPayload_convertToQ15( float value ) +{ + value = ( value * 32768.0f ); + value = value > +32767.0f ? +32767.0f : value; + value = value < -32768.0f ? -32768.0f : value; + return (int16_t) ( value ); +} + +static ivas_error packUnsupportedData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + (void) piData; + (void) buffer; + (void) maxDataBytes; + /* Skip packing */ + *nBytesWritten = 0; + return IVAS_ERR_OK; +} + +static ivas_error unpackUnsupportedData( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + (void) piData; + (void) buffer; + (void) numDataBytes; + /* Skip unpacking */ + return IVAS_ERR_OK; +} + +static ivas_error packNoPiData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + (void) piData; + + *nBytesWritten = 0; + + /* NO_PI_DATA is just PI header with no data */ + if ( maxDataBytes < 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in PI data buffer for NO_PI_DATA" ); + } + + buffer[nBytes++] = ( IVAS_PI_NO_DATA ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 0; /* NO_PI_DATA is 0 bytes */ + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackNoPiData( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + (void) buffer; + + if ( numDataBytes != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "NO_PI_DATA must be 0 byte" ); + } + + piData->size = sizeof( IVAS_PIDATA_NO_DATA ); + return IVAS_ERR_OK; +} + +static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ORIENTATION *orientation = (const IVAS_PIDATA_ORIENTATION *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ORIENTATION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in Orientation PI data" ); + } + + if ( ( piData->piDataType != IVAS_PI_SCENE_ORIENTATION ) && ( piData->piDataType != IVAS_PI_DEVICE_ORIENTATION_COMPENSATED ) && ( piData->piDataType != IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED ) +#ifdef RTP_S4_251135_CR26253_0016_REV1 + && ( piData->piDataType != IVAS_PI_PLAYBACK_DEVICE_ORIENTATION ) && ( piData->piDataType != IVAS_PI_HEAD_ORIENTATION ) +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Orientation PI data" ); + } + + /* Orientation data is 8 bytes, header is 2 bytes */ + if ( maxDataBytes < 8 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Orientation PI data" ); + } + + buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 8; + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.w ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.x ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.y ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.z ) ); + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData; + + /* Orientation data is 8 bytes */ + if ( numDataBytes != 8 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + } + + piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); + orientation->orientation.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ); + orientation->orientation.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ); + orientation->orientation.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ); + orientation->orientation.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) ); + + return IVAS_ERR_OK; +} + +static uint32_t getIndexTable( const float *table, uint32_t tableLength, float value ) +{ + uint32_t idx = 0; + if ( value <= table[0] ) + { + return 0; + } + + for ( idx = 1; idx < tableLength; idx++ ) + { + if ( value < table[idx] ) + { + break; + } + } + return idx - 1; +} + +#define GET_IDX( table, nBits, value ) getIndexTable( table, ( 1u << ( nBits ) ), ( value ) ) + +static ivas_error packAcousticEnvironment( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + uint8_t packedSize = 1; + const IVAS_PIDATA_ACOUSTIC_ENV *aeEnv = (const IVAS_PIDATA_ACOUSTIC_ENV *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ACOUSTIC_ENV ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in PI data of type Acoustic Environment" ); + } + + if ( aeEnv->availEarlyReflections ) + { + packedSize = 8; + } + else if ( aeEnv->availLateReverb ) + { + packedSize = 5; + } + + /* Acoustic Env data is packedSize bytes, header is 2 bytes */ + if ( maxDataBytes < (uint32_t) packedSize + 2 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Insufficient space to pack Orientation PI data" ); + } + + buffer[nBytes++] = ( IVAS_PI_ACOUSTIC_ENVIRONMENT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = packedSize; + + if ( packedSize == 1 ) + { + buffer[nBytes++] = aeEnv->aeid & 0x7F; + } + else + { + uint64_t dWord = (uint64_t) aeEnv->aeid << 57; + + dWord |= (uint64_t) GET_IDX( mapRT60, NBITS_RT60, aeEnv->rt60[IVAS_PI_AE_LOW] ) << 52; + dWord |= (uint64_t) GET_IDX( mapDSR, NBITS_DSR, aeEnv->dsr[IVAS_PI_AE_LOW] ) << 46; + dWord |= (uint64_t) GET_IDX( mapRT60, NBITS_RT60, aeEnv->rt60[IVAS_PI_AE_MID] ) << 41; + dWord |= (uint64_t) GET_IDX( mapDSR, NBITS_DSR, aeEnv->dsr[IVAS_PI_AE_MID] ) << 35; + dWord |= (uint64_t) GET_IDX( mapRT60, NBITS_RT60, aeEnv->rt60[IVAS_PI_AE_HIGH] ) << 30; + dWord |= (uint64_t) GET_IDX( mapDSR, NBITS_DSR, aeEnv->dsr[IVAS_PI_AE_HIGH] ) << 24; + + buffer[nBytes++] = (uint8_t) ( dWord >> 56 ); + buffer[nBytes++] = (uint8_t) ( dWord >> 48 ); + buffer[nBytes++] = (uint8_t) ( dWord >> 40 ); + buffer[nBytes++] = (uint8_t) ( dWord >> 32 ); + buffer[nBytes++] = (uint8_t) ( dWord >> 24 ); + + if ( packedSize > 5 ) + { + dWord |= (uint64_t) GET_IDX( mapRoomDims, NBITS_DIM, aeEnv->roomDimensions.x ) << 20; + dWord |= (uint64_t) GET_IDX( mapRoomDims, NBITS_DIM, aeEnv->roomDimensions.y ) << 16; + dWord |= (uint64_t) GET_IDX( mapRoomDims, NBITS_DIM, aeEnv->roomDimensions.z ) << 12; + dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_FRONT] ) << 10; + dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_BACK] ) << 8; + dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_LEFT] ) << 6; + dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_RIGHT] ) << 4; + dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_CEILING] ) << 2; + dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_FLOOR] ); + + buffer[nBytes++] = (uint8_t) ( dWord >> 16 ); + buffer[nBytes++] = (uint8_t) ( dWord >> 8 ); + buffer[nBytes++] = (uint8_t) ( dWord ); + } + } + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackAcousticEnvironment( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ACOUSTIC_ENV *aeEnv = (IVAS_PIDATA_ACOUSTIC_ENV *) piData; + + /* Acooustic Env data is either 1, 5 or 8 bytes */ + if ( numDataBytes != 1 && numDataBytes != 5 && numDataBytes != 8 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack PI data of type Acoustic Environment" ); + } + + piData->size = sizeof( IVAS_PIDATA_ACOUSTIC_ENV ); + aeEnv->availLateReverb = ( numDataBytes >= 5 ); + aeEnv->availEarlyReflections = ( numDataBytes == 8 ); + + if ( numDataBytes == 1 ) + { + aeEnv->aeid = buffer[0]; + } + else + { + uint64_t dWord = 0ull; + uint32_t n; + for ( n = 0; n < numDataBytes; n++ ) + { + dWord <<= 8; + dWord |= buffer[n]; + } + dWord <<= ( 8 - numDataBytes ) * 8; + + aeEnv->aeid = (uint8_t) ( ( dWord >> 57 ) & MASK_AEID ); + aeEnv->rt60[IVAS_PI_AE_LOW] = mapRT60[( dWord >> 52 ) & MASK_RT60]; + aeEnv->dsr[IVAS_PI_AE_LOW] = mapDSR[( dWord >> 46 ) & MASK_DSR]; + aeEnv->rt60[IVAS_PI_AE_MID] = mapRT60[( dWord >> 41 ) & MASK_RT60]; + aeEnv->dsr[IVAS_PI_AE_MID] = mapDSR[( dWord >> 35 ) & MASK_DSR]; + aeEnv->rt60[IVAS_PI_AE_HIGH] = mapRT60[( dWord >> 30 ) & MASK_RT60]; + aeEnv->dsr[IVAS_PI_AE_HIGH] = mapDSR[( dWord >> 24 ) & MASK_DSR]; + + aeEnv->roomDimensions.x = mapRoomDims[( dWord >> 20 ) & MASK_DIM]; + aeEnv->roomDimensions.y = mapRoomDims[( dWord >> 16 ) & MASK_DIM]; + aeEnv->roomDimensions.z = mapRoomDims[( dWord >> 12 ) & MASK_DIM]; + + aeEnv->absorbCoeffs[IVAS_PI_AE_FRONT] = mapAbsorbtion[( dWord >> 10 ) & MASK_ABS]; + aeEnv->absorbCoeffs[IVAS_PI_AE_BACK] = mapAbsorbtion[( dWord >> 8 ) & MASK_ABS]; + aeEnv->absorbCoeffs[IVAS_PI_AE_LEFT] = mapAbsorbtion[( dWord >> 6 ) & MASK_ABS]; + aeEnv->absorbCoeffs[IVAS_PI_AE_RIGHT] = mapAbsorbtion[( dWord >> 4 ) & MASK_ABS]; + aeEnv->absorbCoeffs[IVAS_PI_AE_CEILING] = mapAbsorbtion[( dWord >> 2 ) & MASK_ABS]; + aeEnv->absorbCoeffs[IVAS_PI_AE_FLOOR] = mapAbsorbtion[( dWord >> 0 ) & MASK_ABS]; + } + + return IVAS_ERR_OK; +} + +#ifdef RTP_S4_251135_CR26253_0016_REV1 +static ivas_error packAudioDescription( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t n; + uint32_t nBytes = 0; + const IVAS_PIDATA_AUDIO_DESC *audioDesc = (const IVAS_PIDATA_AUDIO_DESC *) piData; + uint32_t packedSize = audioDesc->nValidEntries; /* Each Entry is 1 byte */ + + *nBytesWritten = 0; + + if ( audioDesc->nValidEntries > ( IVAS_MAX_NUM_OBJECTS + 1 ) ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Audio Description cannot have more than 5 entries" ); + } + + /* Audio Description data is max 5 bytes, 2 bytes header */ + if ( maxDataBytes < packedSize + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in Audio Description PI data buffer" ); + } + + buffer[nBytes++] = ( IVAS_PI_AUDIO_DESCRIPTION ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) packedSize; + + for ( n = 0; n < audioDesc->nValidEntries; n++ ) + { + buffer[nBytes++] = ( audioDesc->audioId[n].speech ? PI_AD_SPEECH_INDICATED : 0 ) | + ( audioDesc->audioId[n].music ? PI_AD_MUSIC_INDICATED : 0 ) | + ( audioDesc->audioId[n].ambiance ? PI_AD_AMBIANCE_INDICATED : 0 ) | + ( audioDesc->audioId[n].editable ? PI_AD_EDITABLE_INDICATED : 0 ) | + ( audioDesc->audioId[n].binaural ? PI_AD_BINAURAL_INDICATED : 0 ); + } + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackAudioDescription( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n; + IVAS_PIDATA_AUDIO_DESC *audioDesc = (IVAS_PIDATA_AUDIO_DESC *) piData; + + /* Audio Description data is max 5 bytes */ + if ( numDataBytes > ( IVAS_MAX_NUM_OBJECTS + 1 ) ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + } + + audioDesc->size = sizeof( IVAS_PIDATA_AUDIO_DESC ); + audioDesc->nValidEntries = numDataBytes; + audioDesc->piDataType = IVAS_PI_AUDIO_DESCRIPTION; + + for ( n = 0; n < audioDesc->nValidEntries; n++ ) + { + audioDesc->audioId[n].speech = ( buffer[n] & PI_AD_SPEECH_INDICATED ) != 0; + audioDesc->audioId[n].music = ( buffer[n] & PI_AD_MUSIC_INDICATED ) != 0; + audioDesc->audioId[n].ambiance = ( buffer[n] & PI_AD_AMBIANCE_INDICATED ) != 0; + audioDesc->audioId[n].editable = ( buffer[n] & PI_AD_EDITABLE_INDICATED ) != 0; + audioDesc->audioId[n].binaural = ( buffer[n] & PI_AD_BINAURAL_INDICATED ) != 0; + } + + return IVAS_ERR_OK; +} + +static ivas_error packDynamicSuppression( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = (const IVAS_PIDATA_DYNAMIC_SUPPRESSION *) piData; + + *nBytesWritten = 0; + + /* Dynamic Audio Suppression data is 2 bytes, 2 bytes header */ + if ( maxDataBytes < 2 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in DAS PI data buffer" ); + } + + buffer[nBytes++] = ( IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 2u; + + buffer[nBytes++] = ( das->speech ? PI_AD_SPEECH_INDICATED : 0 ) | + ( das->music ? PI_AD_MUSIC_INDICATED : 0 ) | + ( das->ambiance ? PI_AD_AMBIANCE_INDICATED : 0 ); + buffer[nBytes++] = ( (uint8_t) das->sli & MASK_4BIT ) << 4; + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackDynamicSuppression( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = (IVAS_PIDATA_DYNAMIC_SUPPRESSION *) piData; + + /* Dynamic Suppression data is 2 bytes */ + if ( numDataBytes != 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack DAS PI data" ); + } + + das->size = sizeof( IVAS_PIDATA_AUDIO_DESC ); + das->piDataType = IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION; + das->speech = ( buffer[0] & PI_AD_SPEECH_INDICATED ) != 0; + das->music = ( buffer[0] & PI_AD_MUSIC_INDICATED ) != 0; + das->ambiance = ( buffer[0] & PI_AD_AMBIANCE_INDICATED ) != 0; + das->sli = ( buffer[1] >> 4 ); + + return IVAS_ERR_OK; +} + +static ivas_error packListenerPosition( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_LISTENER_POSITION *listener = (const IVAS_PIDATA_LISTENER_POSITION *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_LISTENER_POSITION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in LISTENER POSITION PI data" ); + } + + if ( piData->piDataType != IVAS_PI_LISTENER_POSITION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in LISTENER POSITION PI data" ); + } + + /* Position data is 6 bytes, header is 2 bytes */ + if ( maxDataBytes < 6 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack LISTENER POSITION PI data" ); + } + + buffer[nBytes++] = ( listener->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 6; + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.x / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.y / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.z / MAX_PI_POSITION_METERS ) ); + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_LISTENER_POSITION *listener = (IVAS_PIDATA_LISTENER_POSITION *) piData; + + /* Position data is 6 bytes */ + if ( numDataBytes != 6 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack LISTENER POSITION PI data" ); + } + + listener->size = sizeof( IVAS_PIDATA_LISTENER_POSITION ); + listener->piDataType = IVAS_PI_LISTENER_POSITION; + listener->position.x = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ) * MAX_PI_POSITION_METERS; + listener->position.y = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ) * MAX_PI_POSITION_METERS; + listener->position.z = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ) * MAX_PI_POSITION_METERS; + return IVAS_ERR_OK; +} + +static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + uint8_t byte = 0; + const IVAS_PIDATA_DIEGETIC *diegetic = (const IVAS_PIDATA_DIEGETIC *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_DIEGETIC ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in Diegetic Type PI data" ); + } + + if ( piData->piDataType != IVAS_PI_DIEGETIC_TYPE ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Diegetic Type PI data" ); + } + + /* Diegetic data is 1 bytes, header is 2 bytes */ + if ( maxDataBytes < 1 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Diegetic Type PI data" ); + } + + /* Valid bits must be based on active bits defined for the input format */ + for ( n = 0; n < ( IVAS_MAX_NUM_OBJECTS + 1 ); n++ ) + { + byte <<= 1; + byte |= ( diegetic->isDiegetic[n] ); + } + byte <<= 3; + + buffer[nBytes++] = ( diegetic->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 1; + buffer[nBytes++] = byte; + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackDiegetic( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n; + IVAS_PIDATA_DIEGETIC *diegetic = (IVAS_PIDATA_DIEGETIC *) piData; + uint8_t byte; + + /* Diegetic data is 1 bytes */ + if ( numDataBytes != 1 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Diegetic PI data" ); + } + + diegetic->size = sizeof( IVAS_PIDATA_DIEGETIC ); + diegetic->piDataType = IVAS_PI_DIEGETIC_TYPE; + + byte = buffer[0]; + /* Valid bits must be based on active bits defined for the input format */ + for ( n = 0; n < ( IVAS_MAX_NUM_OBJECTS + 1 ); n++ ) + { + diegetic->isDiegetic[n] = ( ( byte >> ( 7 - n ) ) & 1 ) != 0; + } + + return IVAS_ERR_OK; +} + +static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + uint8_t packedSize = 1; + const IVAS_PIDATA_AUDIO_FOCUS *audioFocus = (const IVAS_PIDATA_AUDIO_FOCUS *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_AUDIO_FOCUS ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in PI data of type Audio Focus" ); + } + + if ( audioFocus->availDirection && audioFocus->availLevel ) + { + packedSize = 9; + } + else if ( audioFocus->availDirection ) + { + packedSize = 8; + } + else if ( audioFocus->availLevel ) + { + packedSize = 1; + } + else + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Neither direction or level is available for packing Audio Focus" ); + } + + /* Audio Focus data is packedSize bytes, header is 2 bytes */ + if ( maxDataBytes < (uint32_t) packedSize + 2 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Insufficient space to pack Audio Focus PI data" ); + } + + buffer[nBytes++] = ( audioFocus->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = packedSize; + + if ( packedSize == 9 || packedSize == 8 ) + { + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.w ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.x ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.y ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.z ) ); + } + if ( packedSize == 9 || packedSize == 1 ) + { + buffer[nBytes++] = ( (uint8_t) audioFocus->flvl & MASK_4BIT ) << 4; + } + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_AUDIO_FOCUS *audioFocus = (IVAS_PIDATA_AUDIO_FOCUS *) piData; + + /* Audio Focus data is either 1, 8 or 9 bytes */ + if ( numDataBytes != 1 && numDataBytes != 8 && numDataBytes != 9 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack PI data of type Audio Focus" ); + } + + piData->size = sizeof( IVAS_PIDATA_AUDIO_FOCUS ); + audioFocus->availDirection = ( numDataBytes >= 8 ); + audioFocus->availLevel = ( numDataBytes == 1 || numDataBytes == 9 ); + + if ( numDataBytes == 1 ) + { + audioFocus->flvl = ( buffer[0] >> 4 ); + } + else + { + audioFocus->direction.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ); + audioFocus->direction.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ); + audioFocus->direction.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ); + audioFocus->direction.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) ); + + if ( numDataBytes == 9 ) + { + audioFocus->flvl = ( buffer[8] >> 4 ); + } + } + + return IVAS_ERR_OK; +} + + +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + +static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { + packOrientation, /* SCENE_ORIENTATION */ + packOrientation, /* DEVICE_ORIENTATION_COMPENSATED */ + packOrientation, /* DEVICE_ORIENTATION_UNCOMPENSATED */ + packAcousticEnvironment, /* ACOUSTIC_ENVIRONMENT */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packAudioDescription, /* AUDIO_DESCRIPTION */ +#else + packUnsupportedData, /* AUDIO_DESCRIPTION */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + packUnsupportedData, /* ISM_NUM */ + packUnsupportedData, /* ISM_ID */ + packUnsupportedData, /* ISM_GAIN */ + packUnsupportedData, /* ISM_ORIENTATION */ + packUnsupportedData, /* ISM_POSITION */ + packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + packUnsupportedData, /* ISM_DIRECTIVITY */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packDiegetic, /* DIEGETIC_TYPE */ +#else + packUnsupportedData, /* DIEGETIC_TYPE */ +#endif + packUnsupportedData, /* RESERVED13 */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ +#else + packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ +#endif + packUnsupportedData, /* RESERVED15 */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + packOrientation, /* HEAD_ORIENTATION */ + packListenerPosition, /* LISTENER_POSITION */ + packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ + packAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ +#else + packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ + packUnsupportedData, /* HEAD_ORIENTATION */ + packUnsupportedData, /* LISTENER_POSITION */ + packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ + packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ +#endif + packUnsupportedData, /* PI_LATENCY */ + packUnsupportedData, /* R_ISM_ID */ + packUnsupportedData, /* R_ISM_GAIN */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packOrientation, /* R_ISM_ORIENTATION */ +#else + packUnsupportedData, /* R_ISM_ORIENTATION */ +#endif + packUnsupportedData, /* R_ISM_POSITION */ + packUnsupportedData, /* R_ISM_DIRECTION */ + packUnsupportedData, /* RESERVED27 */ + packUnsupportedData, /* RESERVED28 */ + packUnsupportedData, /* RESERVED29 */ + packUnsupportedData, /* RESERVED30 */ + packNoPiData /* NO_DATA */ +}; + +static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { + unpackOrientation, /* SCENE_ORIENTATION */ + unpackOrientation, /* DEVICE_ORIENTATION_COMPENSATED */ + unpackOrientation, /* DEVICE_ORIENTATION_UNCOMPENSATED */ + unpackAcousticEnvironment, /* ACOUSTIC_ENVIRONMENT */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackAudioDescription, /* AUDIO_DESCRIPTION */ +#else + unpackUnsupportedData, /* AUDIO_DESCRIPTION */ +#endif + unpackUnsupportedData, /* ISM_NUM */ + unpackUnsupportedData, /* ISM_ID */ + unpackUnsupportedData, /* ISM_GAIN */ + unpackUnsupportedData, /* ISM_ORIENTATION */ + unpackUnsupportedData, /* ISM_POSITION */ + unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + unpackUnsupportedData, /* ISM_DIRECTIVITY */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackDiegetic, /* DIEGETIC_TYPE */ +#else + unpackUnsupportedData, /* DIEGETIC_TYPE */ +#endif + unpackUnsupportedData, /* RESERVED13 */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ +#else + unpackUnsupportedData, /* AUDIO_FOCUS_INDICATION */ +#endif + unpackUnsupportedData, /* RESERVED15 */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + unpackOrientation, /* HEAD_ORIENTATION */ + unpackListenerPosition, /* LISTENER_POSITION */ + unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ + unpackAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ +#else + unpackUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ + unpackUnsupportedData, /* HEAD_ORIENTATION */ + unpackUnsupportedData, /* LISTENER_POSITION */ + unpackUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ + unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ +#endif + unpackUnsupportedData, /* PI_LATENCY */ + unpackUnsupportedData, /* R_ISM_ID */ + unpackUnsupportedData, /* R_ISM_GAIN */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackOrientation, /* R_ISM_ORIENTATION */ +#else + unpackUnsupportedData, /* R_ISM_ORIENTATION */ +#endif + unpackUnsupportedData, /* R_ISM_POSITION */ + unpackUnsupportedData, /* R_ISM_DIRECTION */ + unpackUnsupportedData, /* RESERVED27 */ + unpackUnsupportedData, /* RESERVED28 */ + unpackUnsupportedData, /* RESERVED29 */ + unpackUnsupportedData, /* RESERVED30 */ + unpackNoPiData /* NO_DATA */ +}; + +static const uint32_t maxPiDataSize[IVAS_PI_MAX_ID] = { + 8, /* IVAS_PI_SCENE_ORIENTATION */ + 8, /* IVAS_PI_DEVICE_ORIENTATION_COMPENSATED */ + 8, /* IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED */ + 8, /* IVAS_PI_ACOUSTIC_ENVIRONMENT */ + 5, /* IVAS_PI_AUDIO_DESCRIPTION */ + 1, /* IVAS_PI_ISM_NUM */ + 4, /* IVAS_PI_ISM_ID */ + 4, /* IVAS_PI_ISM_GAIN */ + 32, /* IVAS_PI_ISM_ORIENTATION */ + 24, /* IVAS_PI_ISM_POSITION */ + 12, /* IVAS_PI_ISM_DISTANCE_ATTENUATION */ + 8, /* IVAS_PI_ISM_DIRECTIVITY */ + 1, /* IVAS_PI_DIEGETIC_TYPE */ + 0, /* IVAS_PI_RESERVED13 */ + 9, /* IVAS_PI_AUDIO_FOCUS_INDICATION */ + 0, /* IVAS_PI_RESERVED15 */ + 8, /* IVAS_PI_PLAYBACK_DEVICE_ORIENTATION */ + 8, /* IVAS_PI_HEAD_ORIENTATION */ + 6, /* IVAS_PI_LISTENER_POSITION */ + 2, /* IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION */ + 9, /* IVAS_PI_AUDIO_FOCUS_REQUEST */ + 4, /* IVAS_PI_PI_LATENCY */ + 1, /* IVAS_PI_R_ISM_ID */ + 1, /* IVAS_PI_R_ISM_GAIN */ + 8, /* IVAS_PI_R_ISM_ORIENTATION */ + 6, /* IVAS_PI_R_ISM_POSITION */ + 2, /* IVAS_PI_R_ISM_DIRECTION */ + 0, /* IVAS_PI_RESERVED27 */ + 0, /* IVAS_PI_RESERVED28 */ + 0, /* IVAS_PI_RESERVED29 */ + 0, /* IVAS_PI_RESERVED30 */ + 0, /* IVAS_PI_NO_DATA = 31 */ +}; + +ivas_error PI_PackData( const IVAS_PIDATA_GENERIC *piData, PIDATA_PACKED *packed, uint8_t pmBits ) +{ + uint32_t type = (IVAS_PI_TYPE) ( piData->piDataType & MASK_5BIT ); + ivas_error error = packPiDataFuntions[type]( piData, packed->data, sizeof( packed->data ), &packed->size ); + if ( error == IVAS_ERR_OK ) + { + packed->data[0] |= pmBits; /* Update the PM bits */ + } + assert( packed->size != 0 ); + return error; +} + +ivas_error PI_UnPackData( uint8_t piDataType, uint32_t piSize, const uint8_t *piDataBuffer, IVAS_PIDATA_GENERIC *piData ) +{ + ivas_error error; + + /* Sanitize maximum sizes for each PI Type */ + if ( piSize > maxPiDataSize[piDataType] ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Max size for PI Data type exceeded" ); + } + + error = unpackPiDataFuntions[piDataType]( piDataBuffer, piSize, piData ); + ERR_CHECK_RETURN( error ); + + /* since some pi data share piData structure, pi id are re-filled after unpacking */ + piData->piDataType = piDataType; + + return IVAS_ERR_OK; +} + +/* PIDATA Tables */ +const float mapRT60[1u << NBITS_RT60] = { + 0.01f, 0.0126f, 0.0159f, 0.02f, 0.0252f, 0.0317f, 0.04f, 0.0504f, + 0.0635f, 0.08f, 0.1008f, 0.1270f, 0.16f, 0.2016f, 0.2540f, 0.32f, + 0.4032f, 0.5080f, 0.64f, 0.8063f, 1.0159f, 1.28f, 1.6127f, 2.0319f, + 2.56f, 3.2254f, 4.0637f, 5.12f, 6.4508f, 8.1275f, 10.24f, 12.9016f +}; + +const float mapDSR[1u << NBITS_DSR] = { + -20.f, -21.f, -22.f, -23.f, -24.f, -25.f, -26.f, -27.f, + -28.f, -29.f, -30.f, -31.f, -32.f, -33.f, -34.f, -35.f, + -36.f, -37.f, -38.f, -39.f, -40.f, -41.f, -42.f, -43.f, + -44.f, -45.f, -46.f, -47.f, -48.f, -49.f, -50.f, -51.f, + -52.f, -53.f, -54.f, -55.f, -56.f, -57.f, -58.f, -59.f, + -60.f, -61.f, -62.f, -63.f, -64.f, -65.f, -66.f, -67.f, + -68.f, -69.f, -70.f, -71.f, -72.f, -73.f, -74.f, -75.f, + -76.f, -77.f, -78.f, -79.f, -80.f, -81.f, -82.f, -83.f +}; + +const float mapRoomDims[1u << NBITS_DIM] = { + 0.5f, 0.707f, 1.f, 1.4141f, 2, 2.8282f, 4.f, 5.6568f, + 8.f, 11.314f, 16.f, 22.627f, 32.f, 45.255f, 64.f, 90.51f +}; + +const float mapAbsorbtion[1u << NBITS_ABS] = { + 0.0800f, 0.1656f, 0.3430f, 0.7101f +}; + + +#endif /* IVAS_RTPDUMP */ diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h new file mode 100644 index 000000000..3fc95f8d8 --- /dev/null +++ b/lib_util/ivas_rtp_pi_data.h @@ -0,0 +1,471 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_PI_DATA_H +#define IVAS_RTP_PI_DATA_H + +#include "common_api_types.h" + +#ifdef IVAS_RTPDUMP + +#define IVAS_PI_MAX_DATA_SIZE ( 32 + 2 ) /* max packed PI data bytes + pi header bytes */ + +/* IVAS PI Data Types */ +typedef enum +{ + /* Forward direction PI types */ + IVAS_PI_SCENE_ORIENTATION, /* orientation of audio scene in unit quaternions */ + IVAS_PI_DEVICE_ORIENTATION_COMPENSATED, /* orientation of device in unit quaternions (compensated) */ + IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED, /* orientation of device in unit quaternions (un-compensated) */ + IVAS_PI_ACOUSTIC_ENVIRONMENT, /* describe the acoustic environment */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_PI_AUDIO_DESCRIPTION, /* audio content description (voice/music/ambiance) */ + IVAS_PI_ISM_NUM, /* Number of objects */ + IVAS_PI_ISM_ID, /* id of each object */ + IVAS_PI_ISM_GAIN, /* gain of each object */ + IVAS_PI_ISM_ORIENTATION, /* orientation of each object */ + IVAS_PI_ISM_POSITION, /* position of each object */ + IVAS_PI_ISM_DISTANCE_ATTENUATION, /* distance attenuation for each object */ + IVAS_PI_ISM_DIRECTIVITY, /* directivity of each object */ + IVAS_PI_DIEGETIC_TYPE, /* digetic audio indication */ + IVAS_PI_RESERVED13, /* reserved */ + IVAS_PI_AUDIO_FOCUS_INDICATION, /* audio focus indication (direction in Quaternions and/or level) */ + IVAS_PI_RESERVED15, /* reserved */ + + /* Reverse direction PI types */ + IVAS_PI_PLAYBACK_DEVICE_ORIENTATION, /* orientation of the playback device in quaternions */ + IVAS_PI_HEAD_ORIENTATION, /* head orientation of the listener in Quaternions */ + IVAS_PI_LISTENER_POSITION, /* position of the listener in 3D space */ + IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION, /* receiver’s preference with respect to audio suppression */ + IVAS_PI_AUDIO_FOCUS_REQUEST, /* direction of interest for the listener in Quaternions and/or audio focus level */ + IVAS_PI_PI_LATENCY, /* round-trip latency for PI frames */ + IVAS_PI_R_ISM_ID, /* id of an object for editing */ + IVAS_PI_R_ISM_GAIN, /* editing request for gain factor for received object */ + IVAS_PI_R_ISM_ORIENTATION, /* editing request for orientation for received object */ + IVAS_PI_R_ISM_POSITION, /* editing request for position for received object */ + IVAS_PI_R_ISM_DIRECTION, /* editing request for direction for received object */ + IVAS_PI_RESERVED27, /* reserved */ + IVAS_PI_RESERVED28, /* reserved */ + IVAS_PI_RESERVED29, /* reserved */ + IVAS_PI_RESERVED30, /* reserved */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + IVAS_PI_NO_DATA = 31, /* Indicates an empty PI data frame */ + IVAS_PI_MAX_ID /* Max number of PI data IDs supprted */ +} IVAS_PI_TYPE; + +/* cartesian coordinates (X,Y,Z) in 3D space */ +typedef struct +{ + float x, y, z; +} IVAS_COORDINATE; + +/* orientation data corresponding to any of the following pi data types :- + * - IVAS_PI_SCENE_ORIENTATION + * - IVAS_PI_DEVICE_ORIENTATION_COMPENSATED + * - IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED + * - IVAS_PI_PLAYBACK_DEVICE_ORIENTATION + * - IVAS_PI_HEAD_ORIENTATION + * - IVAS_PI_R_ISM_ORIENTATION + * + * piDataType is used to identify the correct pi data type contained here + */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_SCENE_ORIENTATION) */ + uint32_t piDataType; /* one of supported orientation data types */ + IVAS_QUATERNION orientation; /* orientation data expressed as quartenions */ +} IVAS_PIDATA_ORIENTATION; + +/* Acoustic environment corresponding to IVAS_PI_ACOUSTIC_ENVIRONMENT + * + * acoustic environment ID + * late reverb parameters + * - RT60 – indicating the time that it takes for the reflections to reduce 60 dB in energy level, per frequency band + * - DSR – diffuse to source signal energy ratio, per frequency band + * - Pre-delay – delay at which the computation of DSR values was performed + * early reflections + * - 3D rectangular virtual room dimensions + * - Broadband energy absorption coefficient per wall surface + */ +typedef enum +{ + IVAS_PI_AE_LOW, /* center frequency 25 Hz */ + IVAS_PI_AE_MID, /* center frequency 250 Hz */ + IVAS_PI_AE_HIGH, /* center frequency 2.5 kHz */ + IVAS_PI_AE_NUM_BANDS /* number of ae bands */ +} IVAS_PI_AE_BANDS; + +typedef enum +{ + IVAS_PI_AE_FRONT, + IVAS_PI_AE_BACK, + IVAS_PI_AE_LEFT, + IVAS_PI_AE_RIGHT, + IVAS_PI_AE_CEILING, + IVAS_PI_AE_FLOOR, + IVAS_PI_AE_NUM_SURFACE +} IVAS_PI_AE_SURFACE; + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ACOUSTIC_ENV) */ + uint32_t piDataType; /* IVAS_PI_ACOUSTIC_ENVIRONMENT */ + bool availLateReverb; /* AE contains only late reverb parameters */ + bool availEarlyReflections; /* AE containing late reverb and simplified early reflections */ + uint8_t aeid; /* seven-bit acoustic environment identifier */ + + /* only valid if availLateReverb==true or availEarlyReflections==true */ + float rt60[IVAS_PI_AE_NUM_BANDS]; /* time for the reflections to reduce 60 dB per band in seconds */ + float dsr[IVAS_PI_AE_NUM_BANDS]; /* diffuse to source signal energy ratio per band in dB */ + + /* only valid if availEarlyReflections==true */ + IVAS_COORDINATE roomDimensions; /* room dimensions in meters length (x), width (y), height (z) */ + float absorbCoeffs[IVAS_PI_AE_NUM_SURFACE]; /* absorption coefficients for all surfaces */ +} IVAS_PIDATA_ACOUSTIC_ENV; + +#ifdef RTP_S4_251135_CR26253_0016_REV1 +/* Audio Description corresponding to IVAS_PI_AUDIO_DESCRIPTION + * Describe the following audio decriptors per object/type :- + * - audio content type is speech/music/ambiance + * - if audio rendering is editable + * - if stereo audio is binaural + * + * number of valid entries decide on basis of audio format:- + * - Stereo/SBA/MASA = 1 entry + * - MultiChannel = 2 entries (1 for center channel + 1 for all other channels) + * - ISM = Number of Object entries ( 1 per object ) + * - OMASA/OSBA = 1 + Num Discrete Coded Objects + * + */ +typedef struct +{ + bool speech; /* audio has voice/speech */ + bool music; /* audio has music */ + bool ambiance; /* audio has background ambiance */ + bool editable; /* rendering audio metadata is editable */ + bool binaural; /* stereo stream is binaural */ +} IVAS_AUDIO_ID; + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_AUDIO_DESC) */ + uint32_t piDataType; /* IVAS_PI_AUDIO_DESCRIPTION */ + uint32_t nValidEntries; /* Number of valid audio IDs */ + IVAS_AUDIO_ID audioId[1 + IVAS_MAX_NUM_OBJECTS]; /* audio id as per format */ +} IVAS_PIDATA_AUDIO_DESC; + +/* ISM specific PI data related to PI types : - + * + * - IVAS_PI_ISM_NUM + * - IVAS_PI_ISM_ID + * - IVAS_PI_ISM_GAIN + * - IVAS_PI_ISM_ORIENTATION + * - IVAS_PI_ISM_POSITION + * - IVAS_PI_ISM_DISTANCE_ATTENUATION + * - IVAS_PI_ISM_DIRECTIVITY + */ + +/* Number of ISMs */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_NUM) */ + uint32_t piDataType; /* IVAS_PI_ISM_NUM */ + uint32_t numObjects; /* Number of ISM */ +} IVAS_PIDATA_ISM_NUM; + +/* ISM ID */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_ID) */ + uint32_t piDataType; /* IVAS_PI_ISM_ID */ + uint8_t id[IVAS_MAX_NUM_OBJECTS]; /* 8-bit ISM id of object */ +} IVAS_PIDATA_ISM_ID; + +/* ISM gain */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_GAIN) */ + uint32_t piDataType; /* IVAS_PI_ISM_GAIN */ + int8_t dB[IVAS_MAX_NUM_OBJECTS]; /* ISM gain in dB per object [-96, +3] */ +} IVAS_PIDATA_ISM_GAIN; + +/* ISM orientation */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_ORIENTATION) */ + uint32_t piDataType; /* IVAS_PI_ISM_ORIENTATION */ + IVAS_QUATERNION orientation[IVAS_MAX_NUM_OBJECTS]; /* Orientation of audio objects in ISM(s) */ +} IVAS_PIDATA_ISM_ORIENTATION; + +/* ISM position */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_POSITION) */ + uint32_t piDataType; /* IVAS_PI_ISM_POSITION */ + IVAS_COORDINATE position[IVAS_MAX_NUM_OBJECTS]; /* Position of audio objects in ISM(s) */ +} IVAS_PIDATA_ISM_POSITION; + +/* ISM distance attenuation comprising of following gains per ISM + * - reference distance + * - maximum distance + * - roll-off factor + */ +typedef struct +{ + float ref_dist; /* reference distance in meters */ + float max_dist; /* maximum distance in meters */ + float roll; /* roll-off factor values */ +} IVAS_DIST_ATTEN; + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_ATTENUATION) */ + uint32_t piDataType; /* IVAS_PI_ISM_DISTANCE_ATTENUATION */ + IVAS_DIST_ATTEN distAtten[IVAS_MAX_NUM_OBJECTS]; /* Distance attenuation of audio objects */ +} IVAS_PIDATA_ISM_ATTENUATION; + +/* ISM Directivity comprising of following per ISM :- + * - inner cone angle determines the size of the main cone directed to the front of the object + * - outer cone angle determines the size of the outer (back) cone + * - outer attenuation gain determines the attenuation outside the outer cone + */ +typedef struct +{ + uint16_t innerConeAngle; /* inner cone angle in degrees (0 - 360) */ + uint16_t outerConeAngle; /* outer cone angle in degrees (0 - 360) */ + float outerAttenuationdB; /* attenuation outside the outer cone in dB */ +} IVAS_ISM_DIRECTIVITY; + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_DIRECTIVITY) */ + uint32_t piDataType; /* IVAS_PI_ISM_DIRECTIVITY */ + IVAS_ISM_DIRECTIVITY directivity[IVAS_MAX_NUM_OBJECTS]; /* Directivity of audio objects */ +} IVAS_PIDATA_ISM_DIRECTIVITY; + +/* Diegetic and non-diegetic indication flag as per audio format + * + * number of valid entries decided on basis of audio format:- + * - Stereo/SBA/MASA/MultiChannel = 1 entry + * - ISM = Number of Object entries ( 1 per object ) + * - OMASA/OSBA = 1 (last) + Num Discrete Coded Objects + */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_DIEGETIC) */ + uint32_t piDataType; /* IVAS_PI_DIEGETIC_TYPE */ + bool isDiegetic[1 + IVAS_MAX_NUM_OBJECTS]; /* diegetic indication as per audio format */ +} IVAS_PIDATA_DIEGETIC; + +/* Audio focus direction indicates a direction of interest. + * The audio focus level indicates the amount of suppression applied to the + * directions other than the audio focus direction. + */ +typedef enum +{ + IVAS_FLVL_NO_AUDIO_FOCUS = 0, /* Apply no audio focus */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_1, /* Audio focus level 1 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_2, /* Audio focus level 2 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_3, /* Audio focus level 3 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_4, /* Audio focus level 4 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_5, /* Audio focus level 5 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_6, /* Audio focus level 6 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_7, /* Audio focus level 7 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_8, /* Audio focus level 8 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_9, /* Audio focus level 9 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_10, /* Audio focus level 10 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_11, /* Audio focus level 11 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_12, /* Audio focus level 12 */ + IVAS_FLVL_FOCUS_LEVEL_LEVEL_13, /* Audio focus level 13 */ + IVAS_FLVL_DEFAULT_AUDIO_FOCUS, /* Default audio focus */ + IVAS_FLVL_MAX_AUDIO_FOCUS, /* Apply max audio focus */ +} IVAS_FLVL; + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_AUDIO_FOCUS) */ + uint32_t piDataType; /* IVAS_PI_AUDIO_FOCUS_INDCATION or IVAS_PI_AUDIO_FOCUS_REQUEST */ + bool availDirection; /* audio focus contains direction */ + bool availLevel; /* audio focus contains level */ + IVAS_QUATERNION direction; /* direction data expressed as quarternions */ + IVAS_FLVL flvl; /* audio focus level */ +} IVAS_PIDATA_AUDIO_FOCUS; + +/* Listener position */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_LISTENER_POSITION) */ + uint32_t piDataType; /* IVAS_PI_LISTENER_POSITION */ + IVAS_COORDINATE position; /* Position of audio objects in ISM(s) */ +} IVAS_PIDATA_LISTENER_POSITION; + + +/* Dynamic Audio Suppression describes receiver’s preference with respect to the + * type of audio content that should be enhanced and the amount of suppression to + * be applied to the background noise + */ +typedef enum +{ + IVAS_SLI_NO_SUPPRESSION = 0, /* Apply no suppression */ + IVAS_SLI_SUPPRESSION_LEVEL_1, /* Suppression level 1 */ + IVAS_SLI_SUPPRESSION_LEVEL_2, /* Suppression level 2 */ + IVAS_SLI_SUPPRESSION_LEVEL_3, /* Suppression level 3 */ + IVAS_SLI_SUPPRESSION_LEVEL_4, /* Suppression level 4 */ + IVAS_SLI_SUPPRESSION_LEVEL_5, /* Suppression level 5 */ + IVAS_SLI_SUPPRESSION_LEVEL_6, /* Suppression level 6 */ + IVAS_SLI_SUPPRESSION_LEVEL_7, /* Suppression level 7 */ + IVAS_SLI_SUPPRESSION_LEVEL_8, /* Suppression level 8 */ + IVAS_SLI_SUPPRESSION_LEVEL_9, /* Suppression level 9 */ + IVAS_SLI_SUPPRESSION_LEVEL_10, /* Suppression level 10 */ + IVAS_SLI_SUPPRESSION_LEVEL_11, /* Suppression level 11 */ + IVAS_SLI_SUPPRESSION_LEVEL_12, /* Suppression level 12 */ + IVAS_SLI_SUPPRESSION_LEVEL_13, /* Suppression level 13 */ + IVAS_SLI_SUPPRESSION_LEVEL_14, /* Suppression level 14 */ + IVAS_SLI_MAX_SUPPRESSION, /* Apply max suppression */ +} IVAS_SLI; + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_DYNAMIC_SUPPRESSION) */ + uint32_t piDataType; /* IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION */ + bool speech; /* receiver's preference is voice/speech */ + bool music; /* receiver's preference is music */ + bool ambiance; /* receiver's preference is background ambiance */ + IVAS_SLI sli; /* suppression level indicator [0, 15] */ +} IVAS_PIDATA_DYNAMIC_SUPPRESSION; + +/* Reverse PI latency calculated as the elapsed time between the sent reverse PI data + * and received forward PI data. It is based on the receiving device experiencing the + * result of its sent data by receiving the corresponding data in forward direction as + * forward PI data + */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_REVERSE_PI_LATENCY) */ + uint32_t piDataType; /* IVAS_PI_PI_LATENCY */ + IVAS_PI_TYPE type; /* Reverse PI used for computation of Latency */ + int32_t latency; /* Latency as 27-bit int on RTP Clock @ 16KHz */ +} IVAS_PIDATA_REVERSE_PI_LATENCY; + +/* ISM specific PI data editing requests */ + +/* ISM ID in editing requests */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_ID) */ + uint32_t piDataType; /* IVAS_PI_R_ISM_ID */ + uint8_t id; /* 8-bit ISM id of object to edit */ +} IVAS_PIDATA_ISM_EDIT_ID; + +/* Editing request for ISM gain */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_GAIN) */ + uint32_t piDataType; /* IVAS_PI_R_ISM_GAIN */ + int8_t dB; /* Preferred ISM gain in dB [-96, +3] */ +} IVAS_PIDATA_ISM_EDIT_GAIN; + +/* Editing request for ISM orientation */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_ORIENTATION) */ + uint32_t piDataType; /* IVAS_PI_R_ISM_ORIENTATION */ + IVAS_QUATERNION orientation; /* orientation editing request for received ISM */ +} IVAS_PIDATA_ISM_EDIT_ORIENTATION; + +/* Editing request for ISM position */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_POSITION) */ + uint32_t piDataType; /* IVAS_PI_R_ISM_POSITION */ + IVAS_COORDINATE position; /* Positional editing request for received ISM */ +} IVAS_PIDATA_ISM_EDIT_POSITION; + +/* Editing request for ISM direction */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_DIRECTION) */ + uint32_t piDataType; /* IVAS_PI_R_ISM_DIRECTION */ + float azimuth; /* azimuth angle in degrees [-180, 180] */ + float elevation; /* elevation angle in degrees [-90°, 90°] */ +} IVAS_PIDATA_ISM_EDIT_DIRECTION; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_NO_DATA) */ + uint32_t piDataType; /* IVAS_PI_NO_DATA */ +} IVAS_PIDATA_NO_DATA; + + +typedef union +{ + IVAS_PIDATA_ORIENTATION scene; + IVAS_PIDATA_ORIENTATION deviceCompensated; + IVAS_PIDATA_ORIENTATION deviceUnCompensated; + IVAS_PIDATA_ACOUSTIC_ENV acousticEnv; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_PIDATA_AUDIO_DESC audioDesc; + IVAS_PIDATA_ISM_NUM ismNum; + IVAS_PIDATA_ISM_ID ismId; + IVAS_PIDATA_ISM_GAIN ismGain; + IVAS_PIDATA_ISM_ORIENTATION ismOrientation; + IVAS_PIDATA_ISM_POSITION ismPosition; + IVAS_PIDATA_ISM_ATTENUATION ismAttenuation; + IVAS_PIDATA_ISM_DIRECTIVITY ismDirectivity; + IVAS_PIDATA_DIEGETIC digeticIndicator; + IVAS_PIDATA_AUDIO_FOCUS focusIndication; + + IVAS_PIDATA_ORIENTATION playbackOrientation; + IVAS_PIDATA_ORIENTATION headOrientation; + IVAS_PIDATA_LISTENER_POSITION listnerPosition; + IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppression; + IVAS_PIDATA_AUDIO_FOCUS focusRequest; + IVAS_PIDATA_REVERSE_PI_LATENCY piLatency; + IVAS_PIDATA_ISM_EDIT_ID ismEditId; + IVAS_PIDATA_ISM_EDIT_GAIN ismEditGain; + IVAS_PIDATA_ISM_EDIT_ORIENTATION ismEditOrientation; + IVAS_PIDATA_ISM_EDIT_POSITION ismEditPosition; + IVAS_PIDATA_ISM_EDIT_DIRECTION ismEditDirection; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + IVAS_PIDATA_NO_DATA noPiData; +} PIDATA; + +typedef struct +{ + PIDATA data; + uint32_t timestamp; +} PIDATA_TS; + +#endif /* IVAS_RTPDUMP */ + +#endif /* IVAS_RTP_PI_DATA_H */ diff --git a/lib_util/mutex.h b/lib_util/mutex.h new file mode 100644 index 000000000..82094b61c --- /dev/null +++ b/lib_util/mutex.h @@ -0,0 +1,104 @@ +/****************************************************************************************************** + + (C) 2022-2025 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. + +*******************************************************************************************************/ + +/*==================================================================================== + EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0 + ====================================================================================*/ + +#ifndef _MUTEX_H +#define _MUTEX_H + +#if defined( __unix__ ) || defined( __linux__ ) || ( defined( __MACH__ ) && defined( __APPLE__ ) ) +#include +typedef pthread_mutex_t mtx_t; +#define _USE_POSIX ( 1 ) +#elif defined( _WIN32 ) || defined( _WIN64 ) +#include +typedef CRITICAL_SECTION mtx_t; +#define _USE_WIN ( 1 ) +#else +typedef int mtx_t; +#warning Mutex implementation to be defined for this platform here. +#endif + +static __inline int mtx_init( mtx_t *mutex, int type ) +{ + int err = 0; + (void) type; +#ifdef _USE_POSIX + err = pthread_mutex_init( mutex, NULL ); +#elif defined( _USE_WIN ) + InitializeCriticalSection( mutex ); +#else + (void) mutex; +#endif + return err; +} + +static __inline void mtx_destroy( mtx_t *mutex ) +{ +#if _USE_POSIX + pthread_mutex_destroy( mutex ); +#elif defined( _USE_WIN ) + DeleteCriticalSection( mutex ); +#else + (void) mutex; +#endif +} + +static __inline int mtx_lock( mtx_t *mutex ) +{ + int err = 0; +#if _USE_POSIX + err = pthread_mutex_lock( mutex ); +#elif defined( _USE_WIN ) + EnterCriticalSection( mutex ); +#else + (void) mutex; +#endif + return err; +} + +static __inline int mtx_unlock( mtx_t *mutex ) +{ + int err = 0; +#if _USE_POSIX + err = pthread_mutex_unlock( mutex ); +#elif defined( _USE_WIN ) + LeaveCriticalSection( mutex ); +#else + (void) mutex; +#endif + return err; +} + +#endif /* _MUTEX_H */ diff --git a/lib_util/rtpdump.c b/lib_util/rtpdump.c index d2f13f6bc..5c9faf59a 100644 --- a/lib_util/rtpdump.c +++ b/lib_util/rtpdump.c @@ -38,6 +38,7 @@ #include #include #include "rtpdump.h" +#include "options.h" struct RTPDUMP { @@ -118,10 +119,17 @@ static int readShort( FILE *file, unsigned short *value ) static int writeLong( FILE *file, unsigned int value ) { char buffer[4] = { 0 }; +#ifdef IVAS_RTPDUMP + buffer[3] = (char) ( value & 0xff ); + buffer[2] = (char) ( ( value >> 8 ) & 0xff ); + buffer[1] = (char) ( ( value >> 16 ) & 0xff ); + buffer[0] = (char) ( ( value >> 24 ) & 0xff ); +#else buffer[3] = value & 0xff; buffer[2] = ( value >> 8 ) & 0xff; buffer[1] = ( value >> 16 ) & 0xff; buffer[0] = ( value >> 24 ) & 0xff; +#endif if ( fwrite( buffer, 4, 1, file ) != 1U ) { return -1; @@ -133,8 +141,13 @@ static int writeLong( FILE *file, unsigned int value ) static int writeShort( FILE *file, unsigned short value ) { char buffer[2] = { 0 }; +#ifdef IVAS_RTPDUMP + buffer[1] = (char) ( value & 0xff ); + buffer[0] = (char) ( ( value >> 8 ) & 0xff ); +#else buffer[1] = value & 0xff; buffer[0] = ( value >> 8 ) & 0xff; +#endif if ( fwrite( buffer, 2, 1, file ) != 1U ) { return -1; diff --git a/readme.txt b/readme.txt index 391e0a35f..65be85c12 100644 --- a/readme.txt +++ b/readme.txt @@ -250,7 +250,12 @@ EVS mono is default, for IVAS choose one of the following: -stereo, -ism, -sba, -level level : Complexity level, level = (1, 2, 3), will be defined after characterisation. Currently, all values default to level 3 (full functionality). -q : Quiet mode, limit printouts to terminal, default is deactivated - +-rtpdump : RTPDump output, hf_only=1 by default. The encoder will packetize the + bitstream frames into TS26.253 Annex A IVAS RTP Payload Format packets and + writes those to the output file. In EVS mono operating mode, TS26.445 Annex A.2.2 + EVS RTP Payload Format is used. Optional N represents number of frames per RTP packet +-scene_orientation : Scene orientation trajectory file. Only used with rtpdump output. +-device_orientation : Device orientation trajectory file. Only used with rtpdump output. The usage of the "IVAS_dec" program is as follows: -------------------------------------------------- @@ -275,9 +280,10 @@ Options: -------- -VOIP : VoIP mode: RTP in G192 -VOIP_hf_only=0 : VoIP mode: EVS RTP Payload Format hf_only=0 in rtpdump --VOIP_hf_only=1 : VoIP mode: EVS RTP Payload Format hf_only=1 in rtpdump +-VOIP_hf_only=1 : VoIP mode: EVS or IVAS RTP Payload Format hf_only=1 in rtpdump The decoder may read rtpdump files containing TS26.445 Annex A.2.2 - EVS RTP Payload Format. The SDP parameter hf_only is required. + EVS RTP Payload Format or rtpdump files containing TS26.253 Annex A + IVAS RTP Payload Format. The SDP parameter hf_only is required. Reading RFC4867 AMR/AMR-WB RTP payload format is not supported. -Tracefile TF : VoIP mode: Generate trace file named TF. Requires -no_delay_cmp to be enabled so that trace contents remain in sync with audio output. -- GitLab From 61bf6252ec5740cd2e9af3e7dbade718c84a2174 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 12:02:54 +0200 Subject: [PATCH 02/34] Adapt PI orientations to use fx orientations --- lib_util/ivas_rtp_file.c | 12 ++++++------ lib_util/ivas_rtp_pi_data.c | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 8555480ef..f5da78017 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -191,8 +191,8 @@ void IVAS_RTP_LogPiData( case IVAS_PI_R_ISM_ORIENTATION: #endif { - fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", - cur->data.scene.orientation.w, cur->data.scene.orientation.x, cur->data.scene.orientation.y, cur->data.scene.orientation.z ); + fprintf( f_piDataOut, "{\n\t\t\t\"w\": %d,\n\t\t\t\"x\": %d,\n\t\t\t\"y\": %d,\n\t\t\t\"z\": %d \n\t\t}", + cur->data.scene.orientation.w_fx, cur->data.scene.orientation.x_fx, cur->data.scene.orientation.y_fx, cur->data.scene.orientation.z_fx ); } break; @@ -259,8 +259,8 @@ void IVAS_RTP_LogPiData( if ( cur->data.focusIndication.availDirection ) { fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); - fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", - cur->data.focusIndication.direction.w, cur->data.focusIndication.direction.x, cur->data.focusIndication.direction.y, cur->data.focusIndication.direction.z ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %d,\n\t\t\t\t\t\t\"x\": %d,\n\t\t\t\t\t\t\"y\": %d,\n\t\t\t\t\t\t\"z\": %d \n\t\t\t}", + cur->data.focusIndication.direction.w_fx, cur->data.focusIndication.direction.x_fx, cur->data.focusIndication.direction.y_fx, cur->data.focusIndication.direction.z_fx ); if ( cur->data.focusIndication.availLevel ) { fprintf( f_piDataOut, "," ); @@ -291,8 +291,8 @@ void IVAS_RTP_LogPiData( if ( cur->data.focusRequest.availDirection ) { fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); - fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", - cur->data.focusRequest.direction.w, cur->data.focusRequest.direction.x, cur->data.focusRequest.direction.y, cur->data.focusRequest.direction.z ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %d,\n\t\t\t\t\t\t\"x\": %d,\n\t\t\t\t\t\t\"y\": %d,\n\t\t\t\t\t\t\"z\": %d \n\t\t\t}", + cur->data.focusRequest.direction.w_fx, cur->data.focusRequest.direction.x_fx, cur->data.focusRequest.direction.y_fx, cur->data.focusRequest.direction.z_fx ); if ( cur->data.focusRequest.availLevel ) { fprintf( f_piDataOut, "," ); diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index 7150cfe4a..419d2ea9f 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -145,10 +145,10 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ buffer[nBytes++] = 8; - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.w ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.x ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.y ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.z ) ); + nBytes = writeInt16( buffer, nBytes, orientation->orientation.w_fx ); + nBytes = writeInt16( buffer, nBytes, orientation->orientation.x_fx ); + nBytes = writeInt16( buffer, nBytes, orientation->orientation.y_fx ); + nBytes = writeInt16( buffer, nBytes, orientation->orientation.z_fx ); *nBytesWritten = nBytes; return IVAS_ERR_OK; @@ -165,10 +165,10 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); - orientation->orientation.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ); - orientation->orientation.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ); - orientation->orientation.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ); - orientation->orientation.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) ); + orientation->orientation.w_fx = readInt16( &buffer[0] ); + orientation->orientation.x_fx = readInt16( &buffer[2] ); + orientation->orientation.y_fx = readInt16( &buffer[4] ); + orientation->orientation.z_fx = readInt16( &buffer[6] ); return IVAS_ERR_OK; } @@ -583,10 +583,10 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 if ( packedSize == 9 || packedSize == 8 ) { - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.w ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.x ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.y ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.z ) ); + nBytes = writeInt16( buffer, nBytes, audioFocus->direction.w_fx ); + nBytes = writeInt16( buffer, nBytes, audioFocus->direction.x_fx ); + nBytes = writeInt16( buffer, nBytes, audioFocus->direction.y_fx ); + nBytes = writeInt16( buffer, nBytes, audioFocus->direction.z_fx ); } if ( packedSize == 9 || packedSize == 1 ) { @@ -617,10 +617,10 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat } else { - audioFocus->direction.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ); - audioFocus->direction.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ); - audioFocus->direction.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ); - audioFocus->direction.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) ); + audioFocus->direction.w_fx = readInt16( &buffer[0] ); + audioFocus->direction.x_fx = readInt16( &buffer[2] ); + audioFocus->direction.y_fx = readInt16( &buffer[4] ); + audioFocus->direction.z_fx = readInt16( &buffer[6] ); if ( numDataBytes == 9 ) { -- GitLab From f986548d5f2fa95f7749fedb0a631b1fa9deb41a Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 12:04:49 +0200 Subject: [PATCH 03/34] Port float MR2296 sanitizer fix --- lib_util/ivas_rtp_payload.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 4e4b11f2a..e759f674b 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -199,7 +199,10 @@ ivas_error IVAS_RTP_PACK_UpdateHeader( header->ssrc = ssrc; header->CC = numCC; - memcpy( header->CSRC, csrc, numCC & 0xF ); + if ( csrc != NULL ) + { + memcpy( header->CSRC, csrc, numCC & 0xF ); + } if ( ( numExtensionBytes > 0 ) && ( extData != NULL ) ) { -- GitLab From abad172317e16975e3f24c0915a59e1905891aa3 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 12:15:24 +0200 Subject: [PATCH 04/34] Add compact frame encoding --- lib_com/bitstream_fx.c | 32 ++++++++++++++++++++++++++++++++ lib_com/prot_fx.h | 8 ++++++++ 2 files changed, 40 insertions(+) diff --git a/lib_com/bitstream_fx.c b/lib_com/bitstream_fx.c index b1c7a2efd..334fa3dbc 100644 --- a/lib_com/bitstream_fx.c +++ b/lib_com/bitstream_fx.c @@ -3839,6 +3839,38 @@ ivas_error write_indices_ivas_fx( return error; } +#ifdef IVAS_RTPDUMP + + +/*---------------------------------------------------------------------* + * convertSerialToBytestream( ) + * + * convert 16-bit short serial streams with 0x0000 and 0x0001 to a bytstream + *---------------------------------------------------------------------*/ + +void convertSerialToBytestream_fx( + const UWord16 *const serial, /* i : input serial bitstream with values 0 and 1 */ + const UWord16 num_bits, /* i : number of bits in the input bitstream */ + UWord8 *const bytestream /* o : output compact bitstream (bytestream) */ +) +{ + UWord32 i; + UWord8 bit, bitinbyte; + + for ( i = 0; i < num_bits; ++i ) + { + bit = ( serial[i] == 0x0001 ) ? 1 : 0; + bitinbyte = bit << ( 7 - ( i & 0x7 ) ); + if ( !( i & 0x7 ) ) + { + bytestream[i >> 3] = 0; + } + bytestream[i >> 3] |= bitinbyte; + } + + return; +} +#endif /*-------------------------------------------------------------------* diff --git a/lib_com/prot_fx.h b/lib_com/prot_fx.h index 85984d53d..ddfb27c3a 100644 --- a/lib_com/prot_fx.h +++ b/lib_com/prot_fx.h @@ -11189,6 +11189,14 @@ void ivas_set_bitstream_pointers( Decoder_State **reset_elements( Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ ); +#ifdef IVAS_RTPDUMP + +void convertSerialToBytestream_fx( + const UWord16 *const serial, /* i : input serial bitstream with values 0 and 1 */ + const UWord16 num_bits, /* i : number of bits in the input bitstream */ + UWord8 *const bytestream /* o : output compact bitstream (bytestream) */ +); +#endif void mdct_switching_dec_fx( Decoder_State *st /* i/o: decoder state structure */ -- GitLab From 3dcabfbf5c843677edd5ede3d673b087e091af0c Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 12:16:15 +0200 Subject: [PATCH 05/34] Add compact frame encoding (missing add) --- lib_enc/lib_enc_fx.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib_enc/lib_enc_fx.c b/lib_enc/lib_enc_fx.c index a242ad679..522f89d0e 100644 --- a/lib_enc/lib_enc_fx.c +++ b/lib_enc/lib_enc_fx.c @@ -1525,6 +1525,36 @@ move16(); return error; } +#ifdef IVAS_RTPDUMP + + +/*---------------------------------------------------------------------* + * IVAS_ENC_EncodeFrameToCompact() + * + * Main function to encode one frame to a compact bitstream (bytestream) + *---------------------------------------------------------------------*/ + +ivas_error IVAS_ENC_EncodeFrameToCompact( + IVAS_ENC_HANDLE hIvasEnc, /* i/o: IVAS encoder handle */ + Word16 *inputBuffer, /* i : PCM input */ + const Word16 inputBufferSize, /* i : total number of samples in the input buffer. Related function: IVAS_ENC_GetInputBufferSize() */ + UWord8 *outputBitStream, /* o : pointer to compact output bitstream. The array must already be allocated. */ + UWord16 *numOutBits /* o : number of bits written to output bitstream */ +) +{ + ivas_error error; + UWord16 bitstream[IVAS_MAX_BITS_PER_FRAME]; + + if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, inputBuffer, inputBufferSize, bitstream, numOutBits ) ) != IVAS_ERR_OK ) + { + return error; + } + + convertSerialToBytestream_fx( bitstream, *numOutBits, outputBitStream ); + + return IVAS_ERR_OK; +} +#endif /*---------------------------------------------------------------------* -- GitLab From 1ec0d89cd7a9c629890a2c14bc4e8ccf356cf798 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 13:09:12 +0200 Subject: [PATCH 06/34] Clang format --- lib_enc/lib_enc_fx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib_enc/lib_enc_fx.c b/lib_enc/lib_enc_fx.c index 522f89d0e..5eac61b60 100644 --- a/lib_enc/lib_enc_fx.c +++ b/lib_enc/lib_enc_fx.c @@ -1535,11 +1535,11 @@ return error; *---------------------------------------------------------------------*/ ivas_error IVAS_ENC_EncodeFrameToCompact( - IVAS_ENC_HANDLE hIvasEnc, /* i/o: IVAS encoder handle */ - Word16 *inputBuffer, /* i : PCM input */ - const Word16 inputBufferSize, /* i : total number of samples in the input buffer. Related function: IVAS_ENC_GetInputBufferSize() */ - UWord8 *outputBitStream, /* o : pointer to compact output bitstream. The array must already be allocated. */ - UWord16 *numOutBits /* o : number of bits written to output bitstream */ + IVAS_ENC_HANDLE hIvasEnc, /* i/o: IVAS encoder handle */ + Word16 *inputBuffer, /* i : PCM input */ + const Word16 inputBufferSize, /* i : total number of samples in the input buffer. Related function: IVAS_ENC_GetInputBufferSize() */ + UWord8 *outputBitStream, /* o : pointer to compact output bitstream. The array must already be allocated. */ + UWord16 *numOutBits /* o : number of bits written to output bitstream */ ) { ivas_error error; -- GitLab From a87d3e602bf4a7e1452af2fe7c69903490998848 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 15:12:06 +0200 Subject: [PATCH 07/34] Port float MR1809 --- apps/decoder.c | 188 +++++++++++++- apps/encoder.c | 4 + apps/isar_post_rend.c | 228 +++++++++++++++++ lib_dec/ivas_binRenderer_internal_fx.c | 4 + lib_dec/ivas_dirac_dec_fx.c | 4 + lib_dec/ivas_init_dec_fx.c | 4 + lib_dec/ivas_mc_param_dec_fx.c | 4 + lib_dec/ivas_mc_paramupmix_dec_fx.c | 4 + lib_dec/ivas_mct_dec_fx.c | 4 + lib_dec/ivas_output_config_fx.c | 16 ++ lib_dec/lib_dec.h | 5 + lib_dec/lib_dec_fx.c | 130 ++++++++++ lib_rend/ivas_rotation_fx.c | 76 ++++++ lib_rend/ivas_stat_rend.h | 4 + lib_util/ivas_rtp_api.h | 7 +- lib_util/ivas_rtp_file.c | 330 ++++++++++++++++++++++++- lib_util/ivas_rtp_file.h | 16 +- lib_util/ivas_rtp_internal.h | 9 + lib_util/ivas_rtp_payload.c | 31 ++- lib_util/ivas_rtp_pi_data.c | 3 +- lib_util/ivas_rtp_pi_data.h | 77 +++--- 21 files changed, 1087 insertions(+), 61 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 0e7931fe8..c7707df5d 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -133,7 +133,9 @@ typedef struct bool objEditEnabled; char *objEditFileName; #ifdef IVAS_RTPDUMP + bool applyPiData; char *piOutputFilename; + bool rtpOutSR; #endif } DecArguments; @@ -412,6 +414,10 @@ int main( asked_frame_size = arg.renderFramesize; uint16_t aeID = arg.aeSequence.count > 0 ? arg.aeSequence.pID[0] : 65535; +#ifdef IVAS_RTPDUMP + arg.enableHeadRotation = arg.enableHeadRotation || arg.outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || arg.outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM; +#endif + if ( ( error = IVAS_DEC_Configure( hIvasDec, arg.output_Fs, arg.outputConfig, arg.renderFramesize, arg.customLsOutputEnabled, arg.hrtfReaderEnabled, arg.enableHeadRotation, arg.enableExternalOrientation, arg.orientation_tracking, arg.renderConfigEnabled, arg.non_diegetic_pan_enabled, arg.non_diegetic_pan_gain_fx, arg.dpidEnabled, aeID, arg.objEditEnabled, arg.delayCompensationEnabled ) ) != IVAS_ERR_OK ) @@ -450,7 +456,9 @@ int main( goto cleanup; } +#ifndef IVAS_RTPDUMP arg.enableHeadRotation = true; +#endif } /*------------------------------------------------------------------------------------------* @@ -847,7 +855,9 @@ static bool parseCmdlIVAS_dec( arg->enableExternalOrientation = false; arg->externalOrientationTrajFileName = NULL; #ifdef IVAS_RTPDUMP + arg->applyPiData = false; arg->piOutputFilename = NULL; + arg->rtpOutSR = false; #endif #ifdef SUPPORT_JBM_TRACEFILE @@ -940,6 +950,16 @@ static bool parseCmdlIVAS_dec( arg->piOutputFilename = argv[i++]; } + else if ( strcmp( argv_to_upper, "-APPLYPIDATA" ) == 0 ) + { + arg->applyPiData = true; + i++; + } + else if ( strcmp( argv_to_upper, "-RTPOUTSR" ) == 0 ) + { + arg->rtpOutSR = true; + i++; + } #endif #ifdef SUPPORT_JBM_TRACEFILE else if ( strcmp( argv_to_upper, "-TRACEFILE" ) == 0 ) @@ -1541,6 +1561,8 @@ static void usage_dec( void ) fprintf( stdout, " IVAS RTP Payload Format. The SDP parameter hf_only is required.\n" ); fprintf( stdout, " Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.\n" ); fprintf( stdout, "-PiDataFile PF Log the timestampped PI data.\n" ); + fprintf( stdout, "-ApplyPiData Apply the PI data found in the rtp packet.\n" ); + fprintf( stdout, "-rtpOutSR : Split Rendering bitstream RTPDump output \n" ); #else fprintf( stdout, "-VOIP_hf_only=1 : VoIP mode: EVS RTP Payload Format hf_only=1 in rtpdump\n" ); fprintf( stdout, " The decoder may read rtpdump files containing TS26.445 Annex A.2.2\n" ); @@ -1618,6 +1640,9 @@ static ivas_error initOnFirstGoodFrame( IsmFileWriter *ismWriters[IVAS_MAX_NUM_OBJECTS], /* o : */ int16_t *pNumOutChannels, /* o : */ uint16_t *pNumObj, /* o : */ +#ifdef IVAS_RTPDUMP + IVAS_RTP *srRtp, /* o : */ +#endif SplitFileReadWrite **splitRendWriter ) { int16_t isSplitRend, isSplitCoded; @@ -1682,7 +1707,41 @@ static ivas_error initOnFirstGoodFrame( return error; } +#ifdef IVAS_RTPDUMP + /* Split Rendering RTPDump Output file */ + if ( arg.rtpOutSR && srRtp != NULL ) + { + FILE *fParamsSR = NULL; + char srParamsFile[FILENAME_MAX], *ext = ".sr.txt"; + strncpy( srParamsFile, arg.outputWavFilename, FILENAME_MAX - sizeof( ext ) ); + strncat( srParamsFile, ext, sizeof( ext ) + 1 ); + + /* Write the Split Rendering Params passed from SDP to srParamsFile */ + fParamsSR = fopen( srParamsFile, "w" ); + if ( NULL != fParamsSR ) + { + fprintf( fParamsSR, "CODEC = %s;\nDOF = %d;\nFRAMESIZE = %d;\nRENDERSIZE = %d;\nLC3PLUS_HIGHRES = %d;\n", + splitRendCodec == ISAR_SPLIT_REND_CODEC_LC3PLUS ? "LC3PLUS" : "LCLD", + poseCorrection, + splitRendCodecFrameSizeMs, + splitRendIsarFrameSizeMs, + lc3plusHighRes ); + fclose( fParamsSR ); + fParamsSR = NULL; + } + + + /* Split Rendering RTPDump Output file */ + if ( ( error = IVAS_RTP_WRITER_Init( srRtp, arg.outputWavFilename, 1000 / ( IVAS_NUM_FRAMES_PER_SEC * splitRendCodecFrameSizeMs ) ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open SR output bitstream file for RTP output %s \n\n", arg.outputWavFilename ); + return error; + } + } + else if ( isSplitCoded ) +#else if ( isSplitCoded ) +#endif { if ( ( error = split_rend_writer_open( splitRendWriter, arg.outputWavFilename, delayNumSamples_temp[0], delayTimeScale_temp, splitRendCodec, poseCorrection, splitRendCodecFrameSizeMs, splitRendIsarFrameSizeMs, arg.output_Fs, lc3plusHighRes ) ) != IVAS_ERR_OK ) { @@ -1716,6 +1775,65 @@ static ivas_error initOnFirstGoodFrame( } } +#ifdef IVAS_RTPDUMP + if ( !arg.rtpOutSR ) + { + int16_t pcmFrameSize; + if ( ( error = IVAS_DEC_GetOutputBufferSize( hIvasDec, &pcmFrameSize ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetOutputBufferSize, error code: %d\n", error ); + return error; + } + + /* Write zeros to the output audio buffer */ + int16_t *zeroBuf = calloc( pcmFrameSize, sizeof( int16_t ) ); + if ( zeroBuf == NULL ) + { + fprintf( stdout, "Error: Unable to allocate memory for output buffer.\n" ); + return IVAS_ERR_FAILED_ALLOC; + } + + for ( int16_t i = 0; i < numInitialBadFrames; ++i ) + { + if ( *splitRendWriter != NULL ) + { + ISAR_SPLIT_REND_BITS_DATA splitRendBitsZero; + splitRendBitsZero.bits_buf = NULL; + splitRendBitsZero.bits_read = 0; + splitRendBitsZero.bits_written = 0; + splitRendBitsZero.buf_len = 0; + splitRendBitsZero.codec = ISAR_SPLIT_REND_CODEC_DEFAULT; + splitRendBitsZero.pose_correction = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE; + splitRendBitsZero.codec_frame_size_ms = 0; + splitRendBitsZero.isar_frame_size_ms = 20; + + if ( split_rend_write_bitstream_to_file( *splitRendWriter, splitRendBitsZero.bits_buf, &splitRendBitsZero.bits_read, &splitRendBitsZero.bits_written ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to write to bitstream file!\n" ); + return error; + } + } + else + { + if ( *pRemainingDelayNumSamples < *numOutSamples ) + { + if ( ( error = AudioFileWriter_write( *ppAfWriter, zeroBuf, *numOutSamples * *pNumOutChannels - ( *pRemainingDelayNumSamples * *pNumOutChannels ) ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nOutput audio file writer error\n" ); + return error; + } + *pRemainingDelayNumSamples = 0; + } + else + { + *pRemainingDelayNumSamples -= *numOutSamples; + } + } + } + + free( zeroBuf ); + } +#else int16_t pcmFrameSize; if ( ( error = IVAS_DEC_GetOutputBufferSize( hIvasDec, &pcmFrameSize ) ) != IVAS_ERR_OK ) { @@ -1770,6 +1888,7 @@ static ivas_error initOnFirstGoodFrame( } free( zeroBuf ); +#endif /* Open other output files if EXT output config - now details about ISM or MASA are known */ if ( arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL ) @@ -1863,7 +1982,11 @@ static ivas_error initOnFirstGoodFrame( } } +#ifdef IVAS_RTPDUMP + if ( arg.rtpOutSR || *splitRendWriter != NULL ) +#else if ( *splitRendWriter != NULL ) +#endif { if ( numOutSamples == NULL || vec_pos_len == NULL ) { @@ -2306,7 +2429,11 @@ static ivas_error decodeG192( /* Once good frame decoded, catch up */ if ( decodedGoodFrame ) { +#ifdef IVAS_RTPDUMP + if ( ( error = initOnFirstGoodFrame( hIvasDec, arg, numInitialBadFrames, &nOutSamples, &vec_pos_len, delayNumSamples_orig, &delayNumSamples, &delayTimeScale, &bsFormat, &afWriter, &masaWriter, ismWriters, &nOutChannels, &numObj, NULL, &splitRendWriter ) ) != IVAS_ERR_OK ) +#else if ( ( error = initOnFirstGoodFrame( hIvasDec, arg, numInitialBadFrames, &nOutSamples, &vec_pos_len, delayNumSamples_orig, &delayNumSamples, &delayTimeScale, &bsFormat, &afWriter, &masaWriter, ismWriters, &nOutChannels, &numObj, &splitRendWriter ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "Error in initOnFirstGoodFrame(): %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; @@ -2688,6 +2815,9 @@ static ivas_error decodeVoIP( int16_t i; #ifdef IVAS_RTPDUMP IVAS_RTP ivasRtp = { 0 }; + IVAS_RTP srRtp = { 0 }; + IVAS_RTP_SR_INFO srInfo = { true, false, 0, IVAS_SR_TRANSPORT_LCLD }; + int32_t initialTsOffsetSystemAndRTP = 0; #else FILE *f_rtpstream = NULL; EVS_RTPDUMP_DEPACKER rtpdumpDepacker; @@ -2741,7 +2871,11 @@ static ivas_error decodeVoIP( case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: #ifdef IVAS_RTPDUMP - if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename ) ) != IVAS_ERR_OK ) +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, 0, arg.inputBitstreamFilename, arg.piOutputFilename, arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL, arg.outputWavFilename ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename, arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL, arg.outputWavFilename ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "error in IVAS_RTP_READER_Init(): %d\n", error ); goto cleanup; @@ -2804,7 +2938,12 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP +#ifdef RTP_S4_251135_CR26253_0016_REV1 + error = IVAS_RTP_ReadNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, NULL, &qBit ); +#else error = IVAS_RTP_ReadNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); +#endif + initialTsOffsetSystemAndRTP = rtpTimeStamp - systemTime_ms * 16; /* For time mapping */ #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSize ); #endif @@ -2988,7 +3127,11 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP +#ifdef RTP_S4_251135_CR26253_0016_REV1 + error = IVAS_RTP_ReadNextFrame( &ivasRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, NULL, &qBit ); +#else error = IVAS_RTP_ReadNextFrame( &ivasRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); +#endif /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; @@ -3033,6 +3176,28 @@ static ivas_error decodeVoIP( /* decode and get samples */ while ( nSamplesRendered < nOutSamples ) { +#ifdef IVAS_RTPDUMP + if ( arg.applyPiData ) + { + /* Rudimentry Time Mapping to map system time to rtp timestamp */ + uint32_t piTs = systemTime_ms * 16 + initialTsOffsetSystemAndRTP; + uint32_t numPiData = 0; + + while ( ivasRtp.nProcPiData + numPiData < ivasRtp.nReadPiData && + ivasRtp.piData[ivasRtp.nProcPiData + numPiData].timestamp <= piTs ) + { + numPiData++; + } + + if ( ( error = IVAS_RTP_FeedPiDataToDecoder( hIvasDec, &ivasRtp.piData[ivasRtp.nProcPiData], numPiData ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + ivasRtp.nProcPiData += numPiData; + } +#endif #ifdef SUPPORT_JBM_TRACEFILE if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, (void *) pcmBuf, writeJbmTraceFileFrameWrapper, jbmTraceWriter, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) #else @@ -3124,7 +3289,11 @@ static ivas_error decodeVoIP( SplitFileReadWrite *splitRendWriter = NULL; if ( ( error = initOnFirstGoodFrame( hIvasDec, arg, numInitialBadFrames, &nOutSamples, NULL, delayNumSamples_orig, &delayNumSamples, &delayTimeScale, +#ifdef IVAS_RTPDUMP + &bsFormat, &afWriter, &masaWriter, ismWriters, &nOutChannels, &numObj, &srRtp, &splitRendWriter ) ) != IVAS_ERR_OK ) +#else &bsFormat, &afWriter, &masaWriter, ismWriters, &nOutChannels, &numObj, &splitRendWriter ) ) != IVAS_ERR_OK ) +#endif { goto cleanup; } @@ -3136,7 +3305,11 @@ static ivas_error decodeVoIP( } /* Write current frame */ +#ifdef IVAS_RTPDUMP + if ( !srRtp.hPack && decodedGoodFrame ) +#else if ( decodedGoodFrame ) +#endif { if ( delayNumSamples < nOutSamples ) { @@ -3205,6 +3378,10 @@ static ivas_error decodeVoIP( goto cleanup; } } +#ifdef IVAS_RTPDUMP + + IVAS_RTP_WriteExtPiData( ivasRtp.f_piExtOut, ivasRtp.piData, ivasRtp.nReadPiData, numObj ); +#endif } } @@ -3300,6 +3477,10 @@ static ivas_error decodeVoIP( goto cleanup; } } +#ifdef IVAS_RTPDUMP + + IVAS_RTP_WriteExtPiData( ivasRtp.f_piExtOut, ivasRtp.piData, ivasRtp.nReadPiData, numObj ); +#endif } } @@ -3346,6 +3527,10 @@ static ivas_error decodeVoIP( { fprintf( stdout, "\nOutput MASA metadata file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); } +#ifdef IVAS_RTPDUMP + + fprintf( stdout, "\nOutput PI data file: %s\n", IVAS_RTP_GetExtPiFilePath( &ivasRtp ) ); +#endif } /*------------------------------------------------------------------------------------------* @@ -3357,6 +3542,7 @@ static ivas_error decodeVoIP( cleanup: #ifdef IVAS_RTPDUMP + IVAS_RTP_Term( &srRtp ); IVAS_RTP_Term( &ivasRtp ); #else EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); diff --git a/apps/encoder.c b/apps/encoder.c index 122875635..5e2de5f45 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -867,7 +867,11 @@ int main( goto cleanup; } +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( ( error = IVAS_RTP_WriteNextFrame( &ivasRtp, au, NULL, numBits, isMono, forcePacket ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_RTP_WriteNextFrame( &ivasRtp, au, numBits, isMono, forcePacket ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError %s while pushing audio frame to RTP pack\n", IVAS_ENC_GetErrorMessage( error ) ); goto cleanup; diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index aa799c3f2..2ebea17a6 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -47,6 +47,9 @@ #endif #include "stl.h" #include "wmc_auto.h" +#ifdef RTP_S4_251135_CR26253_0016_REV1 +#include "ivas_rtp_file.h" +#endif #define WMC_TOOL_SKIP @@ -79,6 +82,9 @@ static typedef struct { +#ifdef RTP_S4_251135_CR26253_0016_REV1 + bool srRtp; +#endif IVAS_AUDIO_CONFIG audioConfig; int32_t inputChannelIndex; float gain_dB; @@ -100,6 +106,9 @@ typedef struct char executableName[POST_REND_MAX_CLI_ARG_LENGTH]; char inputFilePath[POST_REND_MAX_CLI_ARG_LENGTH]; char outputFilePath[POST_REND_MAX_CLI_ARG_LENGTH]; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + char srParamsFilePath[POST_REND_MAX_CLI_ARG_LENGTH]; +#endif int32_t sampleRate; InputConfig inConfig; OutputConfig outConfig; @@ -129,6 +138,9 @@ typedef enum CmdLnOptionId_listFormats, CmdLnOptionId_SplitRendBFIFile, CmdLnOptionId_framing, +#ifdef RTP_S4_251135_CR26253_0016_REV1 + CmdLnOptionId_srParamsFile, +#endif } CmdLnOptionId; static const CmdLnParser_Option cliOptions[] = { @@ -204,6 +216,14 @@ static const CmdLnParser_Option cliOptions[] = { .matchShort = "fr", .description = "Set Render audio framing.", }, +#ifdef RTP_S4_251135_CR26253_0016_REV1 + { + .id = CmdLnOptionId_srParamsFile, + .match = "sr_params", + .matchShort = "s", + .description = "Path to the split rendering init params file", + }, +#endif }; @@ -215,7 +235,11 @@ static const int32_t numCliOptions = sizeof( cliOptions ) / sizeof( CmdLnParser_ static void printSupportedAudioConfigs( void ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 +static IVAS_AUDIO_CONFIG parseAudioConfig( const char *configString, bool *srRtp ); +#else static IVAS_AUDIO_CONFIG parseAudioConfig( const char *configString ); +#endif static void convertOutputBuffer( const Word32 *fixedBuffer, Word16 q, const int16_t numSamplesPerChannel, const int16_t numChannels, int16_t *intBuffer ); @@ -303,12 +327,20 @@ static bool parseInConfig( } /* Check for single-format inputs. The given string should map to a member of AUDIO_CONFIG enum. */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + bool srRtp = false; + IVAS_AUDIO_CONFIG audioConfig = parseAudioConfig( inFormatStr, &srRtp ); +#else IVAS_AUDIO_CONFIG audioConfig = parseAudioConfig( inFormatStr ); +#endif switch ( audioConfig ) { case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED: case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM: inConfig->numBinBuses = 1; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + inConfig->binBuses[0].srRtp = srRtp; +#endif inConfig->binBuses[0].audioConfig = audioConfig; inConfig->binBuses[0].inputChannelIndex = 0; inConfig->binBuses[0].gain_dB = 0.0f; @@ -359,11 +391,19 @@ static bool parseRenderFramesize( static IVAS_AUDIO_CONFIG parseAudioConfig( +#ifdef RTP_S4_251135_CR26253_0016_REV1 + const char *configString, + bool *srRtp ) +#else const char *configString ) +#endif { char charBuf[25]; charBuf[24] = '\0'; + #ifdef RTP_S4_251135_CR26253_0016_REV1 + *srRtp = false; + #endif strncpy( charBuf, configString, sizeof( charBuf ) - 1 ); charBuf[sizeof( charBuf ) - 1] = '\0'; to_upper( charBuf ); @@ -380,6 +420,13 @@ static IVAS_AUDIO_CONFIG parseAudioConfig( { return IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED; } +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( strcmp( charBuf, "RTPDUMP" ) == 0 ) + { + *srRtp = true; + return IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED; + } +#endif return IVAS_AUDIO_CONFIG_INVALID; } @@ -436,6 +483,9 @@ static CmdlnArgs defaultArgs( strncpy( args.executableName, executableName, POST_REND_MAX_CLI_ARG_LENGTH ); clearString( args.inputFilePath ); clearString( args.outputFilePath ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 + clearString( args.srParamsFilePath ); +#endif args.sampleRate = 0; args.outConfig.audioConfig = IVAS_AUDIO_CONFIG_INVALID; @@ -543,6 +593,12 @@ static void parseOption( } break; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case CmdLnOptionId_srParamsFile: + assert( numOptionValues == 1 ); + strncpy( args->srParamsFilePath, optionValues[0], POST_REND_MAX_CLI_ARG_LENGTH - 1 ); + break; +#endif default: assert( 0 && "This should be unreachable - all command line options should be explicitly handled." ); break; @@ -579,6 +635,9 @@ static void printSupportedAudioConfigs( void ) "BINAURAL (output only)", "BINAURAL_SPLIT_PCM", "BINAURAL_SPLIT_CODED", +#ifdef RTP_S4_251135_CR26253_0016_REV1 + "RTPDUMP", +#endif }; fprintf( stdout, "Supported audio formats:\n" ); @@ -670,6 +729,97 @@ static void convertOutputBuffer( return; } +#ifdef RTP_S4_251135_CR26253_0016_REV1 +static void trim( char *str ) +{ + char c; + int r = 0, w = 0; + while ( ( c = str[r] ) != 0 && ( c == ' ' || c == '\t' || c == ';' ) ) + { + r++; + } + + while ( ( c = str[r] ) != 0 && ( c != ' ' && c != '\t' && c != ';' ) ) + { + str[w++] = c; + r++; + } + str[w] = 0; +} + +static ivas_error parseSRParamsFile( + const char *srParamsFilePath, + ISAR_SPLIT_REND_CODEC *codec, + ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, + int16_t *codec_frame_size_ms, + int16_t *isar_frame_size_ms, + int16_t *lc3plusHighRes ) +{ + FILE *fParamSR = fopen( srParamsFilePath, "r" ); + if ( NULL == fParamSR ) + { + fprintf( stderr, "error in opening srParams File %s)\n", srParamsFilePath ); + return IVAS_ERR_FAILED_FILE_OPEN; + } + + *codec = ISAR_SPLIT_REND_CODEC_NONE; + *poseCorrection = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE; + *codec_frame_size_ms = 5; + *lc3plusHighRes = 0; + + while ( !feof( fParamSR ) ) + { + char key[16], value[16]; + if ( 2 == fscanf( fParamSR, "%15s = %15s", key, value ) ) + { + trim( key ); + trim( value ); + + if ( 0 == strncmp( key, "CODEC", 5 ) ) + { + *codec = ( 0 == strncmp( value, "LCLD", 4 ) ) ? ISAR_SPLIT_REND_CODEC_LCLD : *codec; + *codec = ( 0 == strncmp( value, "LC3PLUS", 7 ) ) ? ISAR_SPLIT_REND_CODEC_LC3PLUS : *codec; + } + else if ( 0 == strncmp( key, "DOF", 3 ) ) + { + int val = atoi( value ); + if ( val == 0 || val == 1 ) + { + *poseCorrection = ( val == 0 ) ? ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE : ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; + } + } + else if ( 0 == strncmp( key, "FRAMESIZE", 9 ) ) + { + int val = atoi( value ); + if ( val == 5 || val == 10 || val == 20 ) + { + *codec_frame_size_ms = (int16_t) val; + } + } + else if ( 0 == strncmp( key, "RENDERSIZE", 9 ) ) + { + int val = atoi( value ); + if ( val == 5 || val == 10 || val == 20 ) + { + *isar_frame_size_ms = (int16_t) val; + } + } + else if ( 0 == strncmp( key, "LC3PLUS_HIGHRES", 15 ) ) + { + int val = atoi( value ); + if ( val == 0 || val == 1 ) + { + *lc3plusHighRes = (int16_t) val; + } + } + } + } + + fclose( fParamSR ); + return IVAS_ERR_OK; +} +#endif + /*------------------------------------------------------------------------------------------* * main() @@ -710,6 +860,9 @@ int main( int16_t i, numChannels; ivas_error error = IVAS_ERR_OK; bool splitBinNeedsNewFrame = true; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP srRTP = { 0 }; +#endif #ifdef WMOPS reset_wmops(); @@ -739,6 +892,9 @@ int main( convert_backslash( args.inputFilePath ); convert_backslash( args.outputFilePath ); convert_backslash( args.headRotationFilePath ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 + convert_backslash( args.srParamsFilePath ); +#endif /*------------------------------------------------------------------------------------------* * Open head-rotation file @@ -789,8 +945,34 @@ int main( } } +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].srRtp ) ) + { + error = parseSRParamsFile( args.srParamsFilePath, + &bitsBuffer.config.codec, + &bitsBuffer.config.poseCorrection, + &bitsBuffer.config.codec_frame_size_ms, + &bitsBuffer.config.isar_frame_size_ms, + &bitsBuffer.config.lc3plusHighRes ); + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "\nCould not open split rend params file %s\n", args.srParamsFilePath ); + goto cleanup; + } + + if ( ( error = IVAS_RTP_READER_Init( &srRTP, (uint32_t) bitsBuffer.config.codec_frame_size_ms, args.inputFilePath, NULL, false, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_READER_Init(): %d\n", error ); + goto cleanup; + } + audioReader = NULL; + } + /*if split renderer is running in post renderer mode*/ + else if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ) +#else /*if split renderer is running in post renderer mode*/ if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ) +#endif { error = split_rend_reader_open( &hSplitRendFileReadWrite, args.inputFilePath, @@ -997,7 +1179,53 @@ int main( num_in_channels = inBuffer.config.numChannels; numSamplesRead = 0; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( srRTP.hRtpFile && splitBinNeedsNewFrame ) + { + IVAS_RTP_SR_INFO srInfo = { 0 }; + uint32_t rtpTimeStamp = 0, nextPacketRcvTime_ms = 0; + uint16_t rtpSequenceNumber = 0; + int16_t auSizeBits = 0; + bool qBit = false; + uint8_t *bitBuffer = bitsBuffer.bits; + int16_t frameMS = 0; + + numSamplesRead = (int16_t) inBufferSize; + bitsBuffer.config.bitsRead = 0; + bitsBuffer.config.bitsWritten = 0; + + while ( frameMS < bitsBuffer.config.isar_frame_size_ms ) + { + error = IVAS_RTP_ReadNextFrame( &srRTP, bitBuffer, &auSizeBits, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &srInfo, &qBit ); + if ( error != IVAS_ERR_OK ) + { + if ( error == IVAS_ERR_END_OF_FILE ) + { + numSamplesRead = 0; + } + else + { + fprintf( stderr, "\nUnable to read from bitstream file!\n" ); + goto cleanup; + } + } + /* Ensure a SR RTP stream was received */ + if ( !srInfo.valid ) + { + fprintf( stderr, "\nNon-SR RTP stream detected !\n" ); + goto cleanup; + } + + 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; + frameMS += bitsBuffer.config.codec_frame_size_ms; + } + } + else if ( ( hSplitRendFileReadWrite != NULL ) && splitBinNeedsNewFrame ) +#else if ( ( hSplitRendFileReadWrite != NULL ) && splitBinNeedsNewFrame ) +#endif { ivas_error error_tmp; numSamplesRead = (int16_t) inBufferSize; diff --git a/lib_dec/ivas_binRenderer_internal_fx.c b/lib_dec/ivas_binRenderer_internal_fx.c index 70e288ba3..0ed0696d2 100644 --- a/lib_dec/ivas_binRenderer_internal_fx.c +++ b/lib_dec/ivas_binRenderer_internal_fx.c @@ -1245,7 +1245,11 @@ ivas_error ivas_binRenderer_open_fx( // Q29: hBinRenderer->hReverb->foa_enc_fx[k] } } +#ifdef IVAS_RTPDUMP + ELSE IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else ELSE IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { IF( NE_32( ( error = efap_init_data_fx( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth_fx, st_ivas->hIntSetup.ls_elevation_fx, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) ) { diff --git a/lib_dec/ivas_dirac_dec_fx.c b/lib_dec/ivas_dirac_dec_fx.c index 6e30bc084..0f4e513d6 100644 --- a/lib_dec/ivas_dirac_dec_fx.c +++ b/lib_dec/ivas_dirac_dec_fx.c @@ -3082,7 +3082,11 @@ void ivas_dirac_dec_render_sf_fx( test(); test(); +#ifdef IVAS_RTPDUMP + IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) && st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) +#else IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) +#endif { num_freq_bands = hDirAC->band_grouping[hDirAC->hConfig->enc_param_start_band]; move16(); diff --git a/lib_dec/ivas_init_dec_fx.c b/lib_dec/ivas_init_dec_fx.c index 5cf6a86e1..4aadcf6fb 100644 --- a/lib_dec/ivas_init_dec_fx.c +++ b/lib_dec/ivas_init_dec_fx.c @@ -2579,7 +2579,11 @@ ivas_error ivas_init_decoder_fx( test(); test(); test(); +#ifdef IVAS_RTPDUMP + IF( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_MIXER_CONV_ROOM ) && EQ_32( st_ivas->ivas_format, MC_FORMAT ) && ( hDecoderConfig->Opt_Headrotation || hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else IF( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_MIXER_CONV_ROOM ) && EQ_32( st_ivas->ivas_format, MC_FORMAT ) && ( hDecoderConfig->Opt_Headrotation || hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { IF( NE_32( ( error = efap_init_data_fx( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth_fx, st_ivas->hIntSetup.ls_elevation_fx, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) ) { diff --git a/lib_dec/ivas_mc_param_dec_fx.c b/lib_dec/ivas_mc_param_dec_fx.c index 1aa07241e..4faac7183 100644 --- a/lib_dec/ivas_mc_param_dec_fx.c +++ b/lib_dec/ivas_mc_param_dec_fx.c @@ -461,7 +461,11 @@ ivas_error ivas_param_mc_dec_open_fx( test(); test(); test(); +#ifdef IVAS_RTPDUMP + IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { IF( ( hParamMC->hoa_encoder_fx = (Word32 *) malloc( st_ivas->hTransSetup.nchan_out_woLFE * MAX_INTERN_CHANNELS * sizeof( Word32 ) ) ) == NULL ) { diff --git a/lib_dec/ivas_mc_paramupmix_dec_fx.c b/lib_dec/ivas_mc_paramupmix_dec_fx.c index 75b9de19e..09be09281 100644 --- a/lib_dec/ivas_mc_paramupmix_dec_fx.c +++ b/lib_dec/ivas_mc_paramupmix_dec_fx.c @@ -381,7 +381,11 @@ ivas_error ivas_mc_paramupmix_dec_open( } /* Head or external rotation */ +#ifdef IVAS_RTPDUMP + IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { IF( ( hMCParamUpmix->hoa_encoder_fx = (Word32 *) malloc( st_ivas->hTransSetup.nchan_out_woLFE * MAX_INTERN_CHANNELS * sizeof( Word32 ) ) ) == NULL ) diff --git a/lib_dec/ivas_mct_dec_fx.c b/lib_dec/ivas_mct_dec_fx.c index 7881c2976..15d3ba346 100644 --- a/lib_dec/ivas_mct_dec_fx.c +++ b/lib_dec/ivas_mct_dec_fx.c @@ -1369,7 +1369,11 @@ static ivas_error ivas_mc_dec_reconfig_fx( ivas_binRenderer_close_fx( &st_ivas->hBinRenderer ); test(); +#ifdef IVAS_RTPDUMP + IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { efap_free_data_fx( &st_ivas->hEFAPdata ); } diff --git a/lib_dec/ivas_output_config_fx.c b/lib_dec/ivas_output_config_fx.c index 284bd0859..5ce0eea84 100644 --- a/lib_dec/ivas_output_config_fx.c +++ b/lib_dec/ivas_output_config_fx.c @@ -70,7 +70,11 @@ void ivas_renderer_select( *-----------------------------------------------------------------*/ test(); +#ifdef IVAS_RTPDUMP + IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) +#else IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) +#endif { st_ivas->hCombinedOrientationData->shd_rot_max_order = -1; move16(); @@ -163,7 +167,11 @@ void ivas_renderer_select( } test(); +#ifdef IVAS_RTPDUMP + IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) +#else IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) +#endif { nchan_internal = ivas_sba_get_nchan_metadata_fx( st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); test(); @@ -220,7 +228,11 @@ void ivas_renderer_select( test(); test(); test(); +#ifdef IVAS_RTPDUMP + IF( ( EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_7_1 ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) && EQ_32( st_ivas->mc_mode, MC_MODE_MCT ) ) +#else IF( ( EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_7_1 ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && EQ_32( st_ivas->mc_mode, MC_MODE_MCT ) ) +#endif { *renderer_type = RENDERER_BINAURAL_OBJECTS_TD; move16(); @@ -239,7 +251,11 @@ void ivas_renderer_select( } test(); +#ifdef IVAS_RTPDUMP + IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) +#else IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) +#endif { /* force HOA3 domain for rotation*/ *internal_config = IVAS_AUDIO_CONFIG_HOA3; diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index cf23f0e64..0177b8709 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -492,6 +492,11 @@ void IVAS_DEC_PrintDisclaimer( void ); +#ifdef IVAS_RTPDUMP +#include "ivas_rtp_pi_data.h" +ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *piData, uint32_t numPiData ); +#endif + /* clang-format on */ #endif diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 73c8c9a40..3ac27bd2c 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -5618,3 +5618,133 @@ Word16 IVAS_DEC_is_split_rendering_coded_out( return IVAS_ERR_OK; } + +#ifdef IVAS_RTPDUMP +/*---------------------------------------------------------------------* + * IVAS_DEC_feedSinglePIorientation( ) + * + * Feed a single orientation PI data to external orientation handle. + *---------------------------------------------------------------------*/ + +static ivas_error IVAS_DEC_feedSinglePIorientation( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + bool isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ + IVAS_QUATERNION *savedOrientation /* i : previously saved orientation for this PI type */ +) +{ + int16_t i; + ivas_error error = IVAS_ERR_OK; + IVAS_QUATERNION savedInvOrientation; + + if ( isOrientationSaved ) + { + if ( !hIvasDec->st_ivas->hExtOrientationData ) + { + if ( ( error = ivas_external_orientation_open_fx( &( hIvasDec->st_ivas->hExtOrientationData ), hIvasDec->st_ivas->hDecoderConfig->render_framesize ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + if ( !hIvasDec->st_ivas->hCombinedOrientationData ) + { + if ( ( error = ivas_combined_orientation_open_fx( &( hIvasDec->st_ivas->hCombinedOrientationData ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, hIvasDec->st_ivas->hDecoderConfig->render_framesize ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + QuaternionInverse_fx( *savedOrientation, &savedInvOrientation ); + + /* use the new PI orientation or the previously saved orientation in processing */ + for ( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) + { + QuaternionProduct_fx( hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], savedInvOrientation, + &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i] ); + hIvasDec->st_ivas->hExtOrientationData->enableExternalOrientation[i] = true; + } + hIvasDec->updateOrientation = true; + } + return error; +} +#endif + +#ifdef RTP_S4_251135_CR26253_0016_REV1 +/*---------------------------------------------------------------------* + * IVAS_DEC_setDiegeticInput( ) + * + * Set isDiegeticInput flag for combined orientation handle based on PI data. + *---------------------------------------------------------------------*/ + +static void IVAS_DEC_setDiegeticInputPI( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const bool *diegeticPIValues /* i : diegetic values for the input stream */ +) +{ + if ( hIvasDec->st_ivas->hCombinedOrientationData != NULL ) + { + int8_t i; + for ( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ ) + { + hIvasDec->st_ivas->hCombinedOrientationData->isDiegeticInputPI[i] = diegeticPIValues[i]; + } + hIvasDec->st_ivas->hCombinedOrientationData->isDiegeticInputPISet = true; + } +} +#endif + +#ifdef IVAS_RTPDUMP +ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *piData, uint32_t numPiData ) +{ + ivas_error error = IVAS_ERR_OK; + while ( numPiData-- ) + { + uint32_t piDataType = piData->data.noPiData.piDataType; + switch ( piDataType ) + { + case IVAS_PI_SCENE_ORIENTATION: + { + IVAS_QUATERNION *quat = &piData->data.scene.orientation; +#ifdef DEBUGGING + fprintf( stdout, "PI_SCENE_ORIENTATION : %f, %f, %f, %f\n", quat->w, quat->x, quat->y, quat->z ); +#endif + error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); + } + break; + + case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: + { + IVAS_QUATERNION *quat = &piData->data.deviceCompensated.orientation; +#ifdef DEBUGGING + fprintf( stdout, "PI_DEVICE_ORIENTATION : %f, %f, %f, %f\n", quat->w, quat->x, quat->y, quat->z ); +#endif + error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); + } + break; + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_PI_DIEGETIC_TYPE: + { +#ifdef DEBUGGING + fprintf( stdout, "PI_DIEGETIC_TYPE : %d, %d, %d, %d, %d\n", piData->data.digeticIndicator.isDiegetic[0], piData->data.digeticIndicator.isDiegetic[1], piData->data.digeticIndicator.isDiegetic[2], piData->data.digeticIndicator.isDiegetic[3], piData->data.digeticIndicator.isDiegetic[4] ); +#endif + IVAS_DEC_setDiegeticInputPI( hIvasDec, piData->data.digeticIndicator.isDiegetic ); + } + break; +#endif + + default: + { + /* NOT HANDLED PI DATA - DO NOTHING */ + } + break; + } + if ( error != IVAS_ERR_OK ) + { + return error; + } + piData++; + } + return error; +} +#endif diff --git a/lib_rend/ivas_rotation_fx.c b/lib_rend/ivas_rotation_fx.c index b58294d06..cf0386c63 100644 --- a/lib_rend/ivas_rotation_fx.c +++ b/lib_rend/ivas_rotation_fx.c @@ -1439,6 +1439,16 @@ ivas_error ivas_combined_orientation_open_fx( move16(); ( *hCombinedOrientationData )->cur_subframe_samples_rendered = 0; move16(); +#ifdef RTP_S4_251135_CR26253_0016_REV1 + + FOR ( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ ) + { + ( *hCombinedOrientationData )->isDiegeticInputPI[i] = TRUE; + move16(); + } + ( *hCombinedOrientationData )->isDiegeticInputPISet = FALSE; + move16(); +#endif return IVAS_ERR_OK; } @@ -1629,11 +1639,30 @@ ivas_error combine_external_and_head_orientations( } ELSE IF( hExtOrientationData == NULL && headRotQuaternions != NULL ) { +#ifdef RTP_S4_251135_CR26253_0016_REV1 + /* Disable head rotation if diegetic PI data indicating non-diegetic audio is received */ + IF( hCombinedOrientationData->isDiegeticInputPISet && !hCombinedOrientationData->isDiegeticInputPI[0] && !hCombinedOrientationData->isDiegeticInputPI[1] && !hCombinedOrientationData->isDiegeticInputPI[2] && !hCombinedOrientationData->isDiegeticInputPI[3] && !hCombinedOrientationData->isDiegeticInputPI[4] ) + { + FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) + { + hCombinedOrientationData->Quaternions[i] = identity; + } + } + ELSE + { + /* Head rotation only */ + FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) + { + hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + } + } +#else /* Head rotation only */ FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) { hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; } +#endif } IF( hExtOrientationData != NULL ) @@ -1755,6 +1784,41 @@ ivas_error combine_external_and_head_orientations( hCombinedOrientationData->isHeadRotationFrozen = 0; move16(); } + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + /* Disable head rotation if diegetic PI data indicating non-diegetic audio is received */ + IF( hCombinedOrientationData->isDiegeticInputPISet && !hCombinedOrientationData->isDiegeticInputPI[0] && !hCombinedOrientationData->isDiegeticInputPI[1] && !hCombinedOrientationData->isDiegeticInputPI[2] && !hCombinedOrientationData->isDiegeticInputPI[3] && !hCombinedOrientationData->isDiegeticInputPI[4] ) + { + continue; + } + ELSE + { + /* Use the most recent head rotation */ + IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 1 ) ) + { + IF( hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + QuaternionProduct_fx( hCombinedOrientationData->Quaternions[i], headRotQuaternions[i], &hCombinedOrientationData->Quaternions[i] ); + } + ELSE + { + hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + } + } + /* Use the freezed head rotation */ + ELSE IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 2 ) ) + { + IF( hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + QuaternionProduct_fx( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Quaternion_frozen_head, &hCombinedOrientationData->Quaternions[i] ); + } + ELSE + { + hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_head; + } + } + } +#else /* Use the most recent head rotation */ IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 1 ) ) { @@ -1779,6 +1843,7 @@ ivas_error combine_external_and_head_orientations( hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_head; } } +#endif /* Reset the combined orientations to identity */ test(); if ( hExtOrientationData->enableHeadRotation[i] == 0 && hExtOrientationData->enableExternalOrientation[i] == 0 ) @@ -1908,6 +1973,17 @@ ivas_error combine_external_and_head_orientations( } hCombinedOrientationData->sr_pose_pred_axis = sr_pose_pred_axis; +#ifdef IVAS_RTPDUMP + + /* Reset external orientations */ + IF( hExtOrientationData != NULL ) + { + FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) + { + hExtOrientationData->Quaternions[i] = identity; + } + } +#endif return IVAS_ERR_OK; } diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index aec8eb3b9..be7ec113c 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -851,6 +851,10 @@ typedef struct ivas_combined_orientation_struct Word16 cur_subframe_samples_rendered; Word16 subframe_idx_start; Word16 cur_subframe_samples_rendered_start; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + bool isDiegeticInputPI[1 + IVAS_MAX_NUM_OBJECTS]; + bool isDiegeticInputPISet; +#endif } COMBINED_ORIENTATION_DATA, *COMBINED_ORIENTATION_HANDLE; diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 06c56cd70..405893581 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -33,7 +33,6 @@ #ifndef IVAS_RTP_API_H #define IVAS_RTP_API_H -#include #include #include "common_api_types.h" @@ -275,6 +274,7 @@ typedef struct { bool valid; /* Valid Split Rendering Info for/in the ToC */ bool diegetic; /* SR content digetic */ + uint32_t bitrateKbps; /* SR bitrate in kbps */ IVAS_RTP_SR_TRANSPORT codec; /* SR Transport Codec used*/ } IVAS_RTP_SR_INFO; #endif /* RTP_S4_251135_CR26253_0016_REV1 */ @@ -345,7 +345,7 @@ ivas_error IVAS_RTP_PACK_PushFrame( IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info (NULL if absent) */ + const IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info (NULL if absent) */ #endif /* RTP_S4_251135_CR26253_0016_REV1 */ const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */ ); @@ -407,6 +407,9 @@ typedef struct IVAS_RTP_UNPACK *IVAS_RTP_UNPACK_HANDLE; /* rtp unpacker handle t typedef struct { uint32_t maxFramesPerPacket; /* maximum no of frame per packet expected during the session */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + uint32_t srCodecFrameSizeMs; /* split rendering transport codec frame size in ms (5/10/20) set by sdp negotiation */ +#endif } IVAS_RTP_UNPACK_CONFIG; /* Open an instance of the RTP unpacker and return a handle to rtp unpacker on success diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index f5da78017..5846b0423 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -139,9 +139,9 @@ static ivas_error IvasRtpFile_Read( static const char *const PiDataNames[IVAS_PI_MAX_ID] = { "SCENE_ORIENTATION", "DEVICE_ORIENTATION_COMPENSATED", "DEVICE_ORIENTATION_UNCOMPENSATED", "ACOUSTIC_ENVIRONMENT", "AUDIO_DESCRIPTION", "ISM_NUM", "ISM_ID", "ISM_GAIN", "ISM_ORIENTATION", - "ISM_POSITION", "ISM_DISTANCE_ATTENUATION", "ISM_DIRECTIVITY", "DIEGETIC_TYPE", "RESERVED13", + "ISM_POSITION", "ISM_DISTANCE_ATTENUATION", "ISM_DIRECTIVITY", "DIEGETIC_TYPE", "DYNAMIC_AUDIO_SUPPRESSION_INDICATION", "AUDIO_FOCUS_INDICATION", "RESERVED15", "PLAYBACK_DEVICE_ORIENTATION", "HEAD_ORIENTATION", "LISTENER_POSITION", - "DYNAMIC_AUDIO_SUPPRESSION", "AUDIO_FOCUS_REQUEST", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN", + "DYNAMIC_AUDIO_SUPPRESSION_REQUEST", "AUDIO_FOCUS_REQUEST", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN", "R_ISM_ORIENTATION", "R_ISM_POSITION", "R_ISM_DIRECTION", "RESERVED27", "RESERVED28", "RESERVED29", "RESERVED30", "NO_DATA" }; @@ -273,9 +273,20 @@ void IVAS_RTP_LogPiData( fprintf( f_piDataOut, "\n\t\t}" ); } break; - case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION: + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_REQUEST: { - const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppression; + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionRequest; + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_INDICATION: + { + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionIndication; fprintf( f_piDataOut, "{\n" ); fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); @@ -284,7 +295,6 @@ void IVAS_RTP_LogPiData( fprintf( f_piDataOut, "\n\t\t}" ); } break; - case IVAS_PI_RESERVED13: case IVAS_PI_AUDIO_FOCUS_REQUEST: { fprintf( f_piDataOut, "{" ); @@ -337,6 +347,262 @@ void IVAS_RTP_LogPiData( fprintf( f_piDataOut, "\n\t}" ); } +void IVAS_RTP_WriteExtPiData( + FILE *f_piDataOut, /* i/o : Output csv file handle to dump PI data for external output */ + const PIDATA_TS *piData, /* i : PI Data + Timestamp array containing all PI data in current packet */ + uint32_t nPiDataPresent, /* i : Number of valid elements in the piData array */ + uint16_t numObj /* i : Number of objects */ +) +{ + if ( f_piDataOut == NULL || piData == NULL || nPiDataPresent == 0 ) + { + return; + } + + int i = 0; + + while ( nPiDataPresent-- > 0 ) + { + const PIDATA_TS *cur = piData++; + + /* The writing follows the pattern of: timestamp, PI DATA TYPE, PI DATA */ + + fprintf( f_piDataOut, "%d,%s,", cur->timestamp, PiDataNames[cur->data.noPiData.piDataType] ); + switch ( cur->data.noPiData.piDataType ) + { + case IVAS_PI_SCENE_ORIENTATION: + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.scene.orientation.w_fx, cur->data.scene.orientation.x_fx, cur->data.scene.orientation.y_fx, cur->data.scene.orientation.z_fx ); + } + break; + case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.deviceCompensated.orientation.w_fx, cur->data.deviceCompensated.orientation.x_fx, cur->data.deviceCompensated.orientation.y_fx, cur->data.deviceCompensated.orientation.z_fx ); + } + break; + case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.deviceUnCompensated.orientation.w_fx, cur->data.deviceUnCompensated.orientation.x_fx, cur->data.deviceUnCompensated.orientation.y_fx, cur->data.deviceUnCompensated.orientation.z_fx ); + } + break; + case IVAS_PI_ACOUSTIC_ENVIRONMENT: + { + fprintf( f_piDataOut, "%d", cur->data.acousticEnv.aeid ); + if ( cur->data.acousticEnv.availLateReverb ) + { + fprintf( f_piDataOut, ",%f,%f,%f", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] ); + fprintf( f_piDataOut, ",%f,%f,%f", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] ); + } + if ( cur->data.acousticEnv.availEarlyReflections ) + { + fprintf( f_piDataOut, ",%f,%f,%f", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z ); + fprintf( f_piDataOut, ",%f,%f,%f,%f,%f,%f", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] ); + } + } + break; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_PI_AUDIO_DESCRIPTION: + { + uint32_t nEntries = cur->data.audioDesc.nValidEntries; + const IVAS_AUDIO_ID *audioId = cur->data.audioDesc.audioId; + + while ( nEntries-- > 0 ) + { + fprintf( f_piDataOut, "%d,%d,%d,%d,%d", audioId->speech, audioId->music, audioId->ambiance, audioId->editable, audioId->binaural ); + audioId++; + } + } + break; + case IVAS_PI_ISM_NUM: + { + fprintf( f_piDataOut, "%d", cur->data.ismNum.numObjects ); + } + break; + case IVAS_PI_ISM_ID: + { + for ( i = 0; i < numObj; ++i ) + { + if ( i != 0 ) + { + fprintf( f_piDataOut, "," ); + } + fprintf( f_piDataOut, "%d", cur->data.ismId.id[i] ); + } + } + break; + case IVAS_PI_ISM_GAIN: + { + for ( i = 0; i < numObj; ++i ) + { + if ( i != 0 ) + { + fprintf( f_piDataOut, "," ); + } + fprintf( f_piDataOut, "%d", cur->data.ismGain.dB[i] ); + } + } + break; + case IVAS_PI_ISM_ORIENTATION: + { + for ( i = 0; i < numObj; ++i ) + { + if ( i != 0 ) + { + fprintf( f_piDataOut, "," ); + } + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.ismOrientation.orientation[i].w_fx, cur->data.ismOrientation.orientation[i].x_fx, cur->data.ismOrientation.orientation[i].y_fx, cur->data.ismOrientation.orientation[i].z_fx ); + } + } + break; + case IVAS_PI_ISM_POSITION: + { + for ( i = 0; i < numObj; ++i ) + { + if ( i != 0 ) + { + fprintf( f_piDataOut, "," ); + } + fprintf( f_piDataOut, "%f,%f,%f", cur->data.ismPosition.position[i].x, cur->data.ismPosition.position[i].y, cur->data.ismPosition.position[i].z ); + } + } + break; + case IVAS_PI_ISM_DISTANCE_ATTENUATION: + { + for ( i = 0; i < numObj; ++i ) + { + if ( i != 0 ) + { + fprintf( f_piDataOut, "," ); + } + fprintf( f_piDataOut, "%f,%f,%f", cur->data.ismAttenuation.distAtten[i].ref_dist, cur->data.ismAttenuation.distAtten[i].max_dist, cur->data.ismAttenuation.distAtten[i].roll ); + } + } + break; + case IVAS_PI_ISM_DIRECTIVITY: + { + for ( i = 0; i < numObj; ++i ) + { + if ( i != 0 ) + { + fprintf( f_piDataOut, "," ); + } + fprintf( f_piDataOut, "%d,%d,%f", cur->data.ismDirectivity.directivity[i].innerConeAngle, cur->data.ismDirectivity.directivity[i].outerConeAngle, cur->data.ismDirectivity.directivity[i].outerAttenuationdB ); + } + } + break; + case IVAS_PI_DIEGETIC_TYPE: + { + const bool *isDiegetic = cur->data.digeticIndicator.isDiegetic; + fprintf( f_piDataOut, "%d,%d,%d,%d,%d", isDiegetic[0], isDiegetic[1], isDiegetic[2], isDiegetic[3], isDiegetic[4] ); + } + break; + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_INDICATION: + { + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionIndication; + fprintf( f_piDataOut, "%d,%d,%d,%d", das->speech, das->music, das->ambiance, das->sli ); + } + break; + case IVAS_PI_AUDIO_FOCUS_INDICATION: + { + if ( cur->data.focusIndication.availDirection ) + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.focusIndication.direction.w_fx, cur->data.focusIndication.direction.x_fx, cur->data.focusIndication.direction.y_fx, cur->data.focusIndication.direction.z_fx ); + if ( cur->data.focusIndication.availLevel ) + { + fprintf( f_piDataOut, "," ); + } + } + if ( cur->data.focusIndication.availLevel ) + { + fprintf( f_piDataOut, "%d", cur->data.focusIndication.flvl ); + } + } + break; + case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.playbackOrientation.orientation.w_fx, cur->data.playbackOrientation.orientation.x_fx, cur->data.playbackOrientation.orientation.y_fx, cur->data.playbackOrientation.orientation.z_fx ); + } + break; + case IVAS_PI_HEAD_ORIENTATION: + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.headOrientation.orientation.w_fx, cur->data.headOrientation.orientation.x_fx, cur->data.headOrientation.orientation.y_fx, cur->data.headOrientation.orientation.z_fx ); + } + break; + case IVAS_PI_LISTENER_POSITION: + { + fprintf( f_piDataOut, "%f,%f,%f", cur->data.listnerPosition.position.x, cur->data.listnerPosition.position.y, cur->data.listnerPosition.position.z ); + } + break; + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_REQUEST: + { + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionRequest; + fprintf( f_piDataOut, "%d,%d,%d,%d", das->speech, das->music, das->ambiance, das->sli ); + } + break; + case IVAS_PI_AUDIO_FOCUS_REQUEST: + { + + if ( cur->data.focusRequest.availDirection ) + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.focusRequest.direction.w_fx, cur->data.focusRequest.direction.x_fx, cur->data.focusRequest.direction.y_fx, cur->data.focusRequest.direction.z_fx ); + if ( cur->data.focusRequest.availLevel ) + { + fprintf( f_piDataOut, "," ); + } + } + if ( cur->data.focusRequest.availLevel ) + { + fprintf( f_piDataOut, "%d", cur->data.focusRequest.flvl ); + } + } + break; + case IVAS_PI_PI_LATENCY: + { + fprintf( f_piDataOut, "%d", cur->data.piLatency.latency ); + } + break; + case IVAS_PI_R_ISM_ID: + { + fprintf( f_piDataOut, "%d", cur->data.ismEditId.id ); + } + break; + case IVAS_PI_R_ISM_GAIN: + { + fprintf( f_piDataOut, "%d", cur->data.ismEditGain.piDataType ); + } + break; + case IVAS_PI_R_ISM_ORIENTATION: + { + fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.ismEditOrientation.orientation.w_fx, cur->data.ismEditOrientation.orientation.x_fx, cur->data.ismEditOrientation.orientation.y_fx, cur->data.ismEditOrientation.orientation.z_fx ); + } + break; + case IVAS_PI_R_ISM_POSITION: + { + fprintf( f_piDataOut, "%f,%f,%f", cur->data.ismEditPosition.position.x, cur->data.ismEditPosition.position.y, cur->data.ismEditPosition.position.z ); + } + break; + case IVAS_PI_R_ISM_DIRECTION: + { + fprintf( f_piDataOut, "%f,%f", cur->data.ismEditDirection.azimuth, cur->data.ismEditDirection.elevation ); + } + break; + case IVAS_PI_RESERVED15: + case IVAS_PI_RESERVED27: + case IVAS_PI_RESERVED28: + case IVAS_PI_RESERVED29: + case IVAS_PI_RESERVED30: + break; +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + } + fprintf( f_piDataOut, "\n" ); + } +} + +const char *IVAS_RTP_GetExtPiFilePath( IVAS_RTP *rtp ) +{ + return rtp->piExtFilename; +} + void IVAS_RTP_Term( IVAS_RTP *rtp /* i/o : IVAS RTP File reader/writer handle */ ) @@ -378,6 +644,12 @@ void IVAS_RTP_Term( rtp->f_piDataOut = NULL; } + if ( rtp->f_piExtOut != NULL ) + { + fclose( rtp->f_piExtOut ); + rtp->f_piExtOut = NULL; + } + if ( rtp->hRtpFile != NULL ) { IvasRtpFile_Close( &rtp->hRtpFile ); @@ -422,8 +694,13 @@ ivas_error IVAS_RTP_WRITER_Init( ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + uint32_t srCodecFrameSizeMs, /* i : SR Codec Framesize in ms */ +#endif const char *inputBitstreamFilename, /* i : Input rtpdump filename */ - const char *piOutputFilename /* i : Output PI data json filename */ + const char *piOutputFilename, /* i : Output PI data json filename */ + bool isExtOutput, /* i : External output mode */ + const char *outputWavFilename /* i : name of the output audio file */ ) { ivas_error error = IVAS_ERR_OK; @@ -431,6 +708,9 @@ ivas_error IVAS_RTP_READER_Init( memset( rtp, 0, sizeof( IVAS_RTP ) ); rtp->unpackCfg.maxFramesPerPacket = IVAS_MAX_FRAMES_PER_RTP_PACKET; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + rtp->unpackCfg.srCodecFrameSizeMs = srCodecFrameSizeMs; +#endif rtp->rtpPacket.buffer = rtp->packet; rtp->rtpPacket.capacity = sizeof( rtp->packet ); @@ -455,12 +735,36 @@ ivas_error IVAS_RTP_READER_Init( } } + if ( isExtOutput ) + { + char ext_pi[12]; + + /* sizeof( ext_pi ) accounts for terminating NULL, don't subtract extra 1 */ + const int32_t maxNameLenWithoutExt = FILENAME_MAX - (int32_t) sizeof( ext_pi ); + strncpy( rtp->piExtFilename, outputWavFilename, maxNameLenWithoutExt ); + snprintf( ext_pi, sizeof( ext_pi ), ".pidata.csv" ); + + /* strlen( metadata_filename[0] ) doesn't account for terminating NULL, subtract extra 1 */ + const int32_t maxNumCharactersToAppend = FILENAME_MAX - (int32_t) strlen( rtp->piExtFilename ) - 1; + strncat( rtp->piExtFilename, ext_pi, maxNumCharactersToAppend ); + + rtp->f_piExtOut = fopen( rtp->piExtFilename, "w" ); + if ( rtp->f_piExtOut == NULL ) + { + fprintf( stderr, "could not open: %s\n", rtp->piExtFilename ); + return IVAS_ERR_FAILED_FILE_OPEN; + } + } + return error; } ivas_error IVAS_RTP_WriteNextFrame( IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */ uint8_t *au, /* i : IVAS Compressed AU (Packed frame) */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + const IVAS_RTP_SR_INFO *srInfo, /* i : Split rendering info in present, else NULL */ +#endif int16_t auSizeBits, /* i : Frame size in bits */ bool isMono, /* i : input was evs(true) or ivas(false) */ bool forcePacket /* i : force packets with whatever frames pushed so far */ @@ -479,7 +783,7 @@ ivas_error IVAS_RTP_WriteNextFrame( error = IVAS_RTP_PACK_PushFrame( rtp->hPack, isMono ? IVAS_RTP_EVS : IVAS_RTP_IVAS, #ifdef RTP_S4_251135_CR26253_0016_REV1 - NULL, + srInfo, #endif /* RTP_S4_251135_CR26253_0016_REV1 */ &packedFrame ); if ( error != IVAS_ERR_OK ) @@ -487,7 +791,7 @@ ivas_error IVAS_RTP_WriteNextFrame( return error; } - while ( rtp->nWrittenPiData-- > 0 ) + while ( rtp->nWrittenPiData > 0 ) { PIDATA_TS *piDataTs = &rtp->piData[nProcPiData++]; if ( ( error = IVAS_RTP_PACK_PushPiData( rtp->hPack, (const IVAS_PIDATA_GENERIC *) &piDataTs->data ) ) != IVAS_ERR_OK ) @@ -495,6 +799,7 @@ ivas_error IVAS_RTP_WriteNextFrame( fprintf( stderr, "\nError %s while pushing scene orientation\n", ivas_error_to_string( error ) ); return error; } + rtp->nWrittenPiData--; } if ( forcePacket || IVAS_RTP_PACK_GetNumFrames( rtp->hPack ) == rtp->packCfg.maxFramesPerPacket ) @@ -525,6 +830,9 @@ ivas_error IVAS_RTP_ReadNextFrame( uint32_t *rtpTimeStamp, /* o : RTP Timestamp for this frame */ uint16_t *rtpSequenceNumber, /* o : RTP sequence number for this packet */ uint32_t *nextPacketRcvTime_ms, /* i/o : Clock indicating packet receive times need in JBM */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO *srInfo, /* o : Split Rendering info if SR RTP frame unpacked */ +#endif bool *qBit /* o : AMRWB Q bite as indicated in the RTP packet */ ) { @@ -603,6 +911,12 @@ ivas_error IVAS_RTP_ReadNextFrame( rtp->isAMRWB_IOmode = isAMRWB_IOmode; } +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( srInfo != NULL ) + { + *srInfo = rtp->srInfo; + } +#endif *qBit = !rtp->speechLostIndicated; rtp->numFramesInPacket--; rtp->numFramesProduced++; diff --git a/lib_util/ivas_rtp_file.h b/lib_util/ivas_rtp_file.h index 2a58dc1c9..d5fbc0504 100644 --- a/lib_util/ivas_rtp_file.h +++ b/lib_util/ivas_rtp_file.h @@ -46,6 +46,8 @@ typedef struct IVAS_RTP_FILE_HANDLE hRtpFile; FILE *f_piDataOut; + FILE *f_piExtOut; + char piExtFilename[FILENAME_MAX]; IVAS_RTP_CODEC codecId; uint32_t nWrittenPiData; uint32_t nReadPiData; @@ -69,11 +71,23 @@ typedef struct } IVAS_RTP; ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilename, uint32_t numFramesPerPacket ); -ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, const char *inputBitstreamFilename, const char *piOutputFilename ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 +ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, uint32_t srCodecFrameSizeMs, const char *inputBitstreamFilename, const char *piOutputFilename, bool isExtOutput, const char *outputWavFilename ); +#else +ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, const char *inputBitstreamFilename, const char *piOutputFilename, bool isExtOutput, const char *outputWavFilename ); +#endif void IVAS_RTP_Term( IVAS_RTP *rtp ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 +ivas_error IVAS_RTP_WriteNextFrame( IVAS_RTP *rtp, uint8_t *au, const IVAS_RTP_SR_INFO *srInfo, int16_t auSizeBits, bool isMono, bool forcePacket ); +ivas_error IVAS_RTP_ReadNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, IVAS_RTP_SR_INFO *srInfo, bool *qBit ); +#else + ivas_error IVAS_RTP_WriteNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t auSizeBits, bool isMono, bool forcePacket ); ivas_error IVAS_RTP_ReadNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit ); +#endif void IVAS_RTP_LogPiData( FILE *f_piDataOut, const PIDATA_TS *piData, uint32_t nPiDataPresent ); +void IVAS_RTP_WriteExtPiData( FILE *f_piDataOut, const PIDATA_TS *piData, uint32_t nPiDataPresent, uint16_t numObj ); +const char *IVAS_RTP_GetExtPiFilePath( IVAS_RTP *rtp ); #endif /* IVAS_RTP_FILE_H */ diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h index f3569ca03..032717d8f 100644 --- a/lib_util/ivas_rtp_internal.h +++ b/lib_util/ivas_rtp_internal.h @@ -96,11 +96,20 @@ enum IVAS_RTP_HEADER_BITS EBYTE_CMR_T_IVAS = 0xF0, /* Initial E-byte indicating IVAS modes */ EBYTE_CMR_T_NO_REQ = 0xFF, /* If no bitrate and no CA mode requested for IVAS/EVS */ + +#ifdef RTP_S4_251135_CR26253_0016_REV1 EBYTE_BANDWIDTH_REQUEST = 0x80, /* Subsequent E-byte for Bandwidth Request */ EBYTE_FORMAT_REQUEST = 0x90, /* Subsequent E-byte for Format Request */ EBYTE_SUBFORMAT_REQUEST = 0x9F, /* Subsequent E-byte for SubFormat Request */ EBYTE_PI_INDICATOR = 0xA0, /* Subsequent E-byte for PI Indicator */ EBYTE_SR_REQUEST = 0xB0, /* Subsequent E-byte for Split Rendering Request */ +#else + EBYTE_BANDWIDTH_REQUEST = 0x40, /* Subsequent E-byte for Bandwidth Request */ + EBYTE_FORMAT_REQUEST = 0x50, /* Subsequent E-byte for Format Request */ + EBYTE_SUBFORMAT_REQUEST = 0x9F, /* Subsequent E-byte for SubFormat Request */ + EBYTE_PI_INDICATOR = 0x60, /* Subsequent E-byte for PI Indicator */ + EBYTE_SR_REQUEST = 0x70, /* Subsequent E-byte for Split Rendering Request */ +#endif PI_HEADER_PF_LAST = 0x00, /* Last PI header of the Payload in PI Header */ PI_HEADER_PF_NOT_LAST = 0x80, /* Another PI header follows after this in PI Header */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index e759f674b..46198011a 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -835,18 +835,17 @@ static void packEBytes( #ifdef RTP_S4_251135_CR26253_0016_REV1 static ivas_error getSRToCByte( - IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */ - uint32_t bitrateKbps, /* i : Bitrate in kbps */ - uint8_t *tocByte /* o : toc byte 2 */ + const IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */ + uint8_t *tocByte /* o : toc byte 2 */ ) { uint8_t bitIdx, codecId, digetic; - if ( bitrateKbps < 256000 || bitrateKbps > 512000 ) + if ( srInfo->bitrateKbps < 256000 || srInfo->bitrateKbps > 512000 ) { return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate for SR" ); } - bitIdx = ( ( bitrateKbps / 128000u ) - 1 ) & MASK_2BIT; + bitIdx = ( ( srInfo->bitrateKbps / 128000u ) - 1 ) & MASK_2BIT; codecId = (uint8_t) srInfo->codec; digetic = srInfo->diegetic ? 1 : 0; @@ -882,7 +881,7 @@ ivas_error IVAS_RTP_PACK_PushFrame( IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */ + const IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */ #endif /* RTP_S4_251135_CR26253_0016_REV1 */ const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */ ) @@ -907,7 +906,8 @@ ivas_error IVAS_RTP_PACK_PushFrame( else if ( srInfo != NULL && srInfo->valid ) { tocByte = TOC_INDICATE_SR; - error = getSRToCByte( srInfo, bitrate, &tocByte1 ); + frameLengthInBits = frameBuffer->length * 8; + error = getSRToCByte( srInfo, &tocByte1 ); ERR_CHECK_RETURN( error ); } #endif @@ -1339,7 +1339,11 @@ static uint32_t parseSubsequentEByte( const IVAS_DATA_BUFFER *payload, uint32_t while ( nBytes < payload->length ) { uint8_t byte = payload->buffer[nBytes]; +#ifdef RTP_S4_251135_CR26253_0016_REV1 uint8_t ET = ( byte & ( ~MASK_4BIT ) ); +#else + uint8_t ET = ( byte & ( ~MASK_3BIT ) ); +#endif if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 ) { @@ -1388,14 +1392,18 @@ static uint32_t parseSubsequentEByte( const IVAS_DATA_BUFFER *payload, uint32_t break; #endif default: /* Reserved for future use - unhandled atm */ - assert( 0 ); + break; } } return nBytes; } +#ifdef RTP_S4_251135_CR26253_0016_REV1 +static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc, uint32_t maxNumberOfToCBytes, uint32_t srCodecFrameSizeMs ) +#else static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc, uint32_t maxNumberOfToCBytes ) +#endif { bool headerFollows = true; uint32_t nBytes = *numBytes; @@ -1462,7 +1470,8 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy toc->srInfo.valid = true; toc->srInfo.diegetic = ( byte >> 6 ) & MASK_1BIT; toc->srInfo.codec = IVAS_SR_TRANSPORT_LCLD + ( ( byte >> 5 ) & MASK_1BIT ); - toc->auNumBits = ( SR_BR + 1 ) * 128000u / IVAS_NUM_FRAMES_PER_SEC; + toc->srInfo.bitrateKbps = ( SR_BR + 1 ) * 128000u; + toc->auNumBits = toc->srInfo.bitrateKbps * srCodecFrameSizeMs / 1000; } else { @@ -1644,7 +1653,11 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( nBytes = parseSubsequentEByte( payload, nBytes, hUnpack->requests, &piDataIndicated ); /* Unpack the ToC Bytes => Extract number of frames in packet */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ), hUnpack->initConfig.srCodecFrameSizeMs ); +#else error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ) ); +#endif ERR_CHECK_RETURN( error ); /* Read frame bits */ diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index 419d2ea9f..8d50b9681 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -396,7 +396,7 @@ static ivas_error packDynamicSuppression( const IVAS_PIDATA_GENERIC *piData, uin return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in DAS PI data buffer" ); } - buffer[nBytes++] = ( IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION ); /* PF/PM populated during final packing */ + buffer[nBytes++] = ( das->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ buffer[nBytes++] = 2u; buffer[nBytes++] = ( das->speech ? PI_AD_SPEECH_INDICATED : 0 ) | @@ -419,7 +419,6 @@ static ivas_error unpackDynamicSuppression( const uint8_t *buffer, uint32_t numD } das->size = sizeof( IVAS_PIDATA_AUDIO_DESC ); - das->piDataType = IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION; das->speech = ( buffer[0] & PI_AD_SPEECH_INDICATED ) != 0; das->music = ( buffer[0] & PI_AD_MUSIC_INDICATED ) != 0; das->ambiance = ( buffer[0] & PI_AD_AMBIANCE_INDICATED ) != 0; diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index 3fc95f8d8..dc4c7f8ba 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -48,38 +48,38 @@ typedef enum IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED, /* orientation of device in unit quaternions (un-compensated) */ IVAS_PI_ACOUSTIC_ENVIRONMENT, /* describe the acoustic environment */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - IVAS_PI_AUDIO_DESCRIPTION, /* audio content description (voice/music/ambiance) */ - IVAS_PI_ISM_NUM, /* Number of objects */ - IVAS_PI_ISM_ID, /* id of each object */ - IVAS_PI_ISM_GAIN, /* gain of each object */ - IVAS_PI_ISM_ORIENTATION, /* orientation of each object */ - IVAS_PI_ISM_POSITION, /* position of each object */ - IVAS_PI_ISM_DISTANCE_ATTENUATION, /* distance attenuation for each object */ - IVAS_PI_ISM_DIRECTIVITY, /* directivity of each object */ - IVAS_PI_DIEGETIC_TYPE, /* digetic audio indication */ - IVAS_PI_RESERVED13, /* reserved */ - IVAS_PI_AUDIO_FOCUS_INDICATION, /* audio focus indication (direction in Quaternions and/or level) */ - IVAS_PI_RESERVED15, /* reserved */ + IVAS_PI_AUDIO_DESCRIPTION, /* audio content description (voice/music/ambiance) */ + IVAS_PI_ISM_NUM, /* Number of objects */ + IVAS_PI_ISM_ID, /* id of each object */ + IVAS_PI_ISM_GAIN, /* gain of each object */ + IVAS_PI_ISM_ORIENTATION, /* orientation of each object */ + IVAS_PI_ISM_POSITION, /* position of each object */ + IVAS_PI_ISM_DISTANCE_ATTENUATION, /* distance attenuation for each object */ + IVAS_PI_ISM_DIRECTIVITY, /* directivity of each object */ + IVAS_PI_DIEGETIC_TYPE, /* digetic audio indication */ + IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_INDICATION, /* audio suppression indication */ + IVAS_PI_AUDIO_FOCUS_INDICATION, /* audio focus indication (direction in Quaternions and/or level) */ + IVAS_PI_RESERVED15, /* reserved */ /* Reverse direction PI types */ - IVAS_PI_PLAYBACK_DEVICE_ORIENTATION, /* orientation of the playback device in quaternions */ - IVAS_PI_HEAD_ORIENTATION, /* head orientation of the listener in Quaternions */ - IVAS_PI_LISTENER_POSITION, /* position of the listener in 3D space */ - IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION, /* receiver’s preference with respect to audio suppression */ - IVAS_PI_AUDIO_FOCUS_REQUEST, /* direction of interest for the listener in Quaternions and/or audio focus level */ - IVAS_PI_PI_LATENCY, /* round-trip latency for PI frames */ - IVAS_PI_R_ISM_ID, /* id of an object for editing */ - IVAS_PI_R_ISM_GAIN, /* editing request for gain factor for received object */ - IVAS_PI_R_ISM_ORIENTATION, /* editing request for orientation for received object */ - IVAS_PI_R_ISM_POSITION, /* editing request for position for received object */ - IVAS_PI_R_ISM_DIRECTION, /* editing request for direction for received object */ - IVAS_PI_RESERVED27, /* reserved */ - IVAS_PI_RESERVED28, /* reserved */ - IVAS_PI_RESERVED29, /* reserved */ - IVAS_PI_RESERVED30, /* reserved */ -#endif /* RTP_S4_251135_CR26253_0016_REV1 */ - IVAS_PI_NO_DATA = 31, /* Indicates an empty PI data frame */ - IVAS_PI_MAX_ID /* Max number of PI data IDs supprted */ + IVAS_PI_PLAYBACK_DEVICE_ORIENTATION, /* orientation of the playback device in quaternions */ + IVAS_PI_HEAD_ORIENTATION, /* head orientation of the listener in Quaternions */ + IVAS_PI_LISTENER_POSITION, /* position of the listener in 3D space */ + IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_REQUEST, /* receiver’s preference with respect to audio suppression */ + IVAS_PI_AUDIO_FOCUS_REQUEST, /* direction of interest for the listener in Quaternions and/or audio focus level */ + IVAS_PI_PI_LATENCY, /* round-trip latency for PI frames */ + IVAS_PI_R_ISM_ID, /* id of an object for editing */ + IVAS_PI_R_ISM_GAIN, /* editing request for gain factor for received object */ + IVAS_PI_R_ISM_ORIENTATION, /* editing request for orientation for received object */ + IVAS_PI_R_ISM_POSITION, /* editing request for position for received object */ + IVAS_PI_R_ISM_DIRECTION, /* editing request for direction for received object */ + IVAS_PI_RESERVED27, /* reserved */ + IVAS_PI_RESERVED28, /* reserved */ + IVAS_PI_RESERVED29, /* reserved */ + IVAS_PI_RESERVED30, /* reserved */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + IVAS_PI_NO_DATA = 31, /* Indicates an empty PI data frame */ + IVAS_PI_MAX_ID /* Max number of PI data IDs supprted */ } IVAS_PI_TYPE; /* cartesian coordinates (X,Y,Z) in 3D space */ @@ -305,9 +305,9 @@ typedef enum IVAS_FLVL_FOCUS_LEVEL_LEVEL_10, /* Audio focus level 10 */ IVAS_FLVL_FOCUS_LEVEL_LEVEL_11, /* Audio focus level 11 */ IVAS_FLVL_FOCUS_LEVEL_LEVEL_12, /* Audio focus level 12 */ - IVAS_FLVL_FOCUS_LEVEL_LEVEL_13, /* Audio focus level 13 */ - IVAS_FLVL_DEFAULT_AUDIO_FOCUS, /* Default audio focus */ IVAS_FLVL_MAX_AUDIO_FOCUS, /* Apply max audio focus */ + IVAS_FLVL_DEFAULT_AUDIO_FOCUS, /* Default audio focus */ + IVAS_FLVL_NO_PREFERENCE, /* No preference / No indication */ } IVAS_FLVL; typedef struct @@ -335,7 +335,7 @@ typedef struct */ typedef enum { - IVAS_SLI_NO_SUPPRESSION = 0, /* Apply no suppression */ + IVAS_SLI_MIN_SUPPRESSION = 0, /* Apply min suppression */ IVAS_SLI_SUPPRESSION_LEVEL_1, /* Suppression level 1 */ IVAS_SLI_SUPPRESSION_LEVEL_2, /* Suppression level 2 */ IVAS_SLI_SUPPRESSION_LEVEL_3, /* Suppression level 3 */ @@ -347,16 +347,16 @@ typedef enum IVAS_SLI_SUPPRESSION_LEVEL_9, /* Suppression level 9 */ IVAS_SLI_SUPPRESSION_LEVEL_10, /* Suppression level 10 */ IVAS_SLI_SUPPRESSION_LEVEL_11, /* Suppression level 11 */ - IVAS_SLI_SUPPRESSION_LEVEL_12, /* Suppression level 12 */ - IVAS_SLI_SUPPRESSION_LEVEL_13, /* Suppression level 13 */ - IVAS_SLI_SUPPRESSION_LEVEL_14, /* Suppression level 14 */ IVAS_SLI_MAX_SUPPRESSION, /* Apply max suppression */ + IVAS_SLI_NO_SUPPRESSION, /* Apply no suppression */ + IVAS_SLI_DEFAULT_SUPPRESSION, /* Apply default suppression */ + IVAS_SLI_NO_PREFERENCE, /* No preference / No indication */ } IVAS_SLI; typedef struct { size_t size; /* sizeof(IVAS_PIDATA_DYNAMIC_SUPPRESSION) */ - uint32_t piDataType; /* IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION */ + uint32_t piDataType; /* IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_REQUEST or IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_INDICATION */ bool speech; /* receiver's preference is voice/speech */ bool music; /* receiver's preference is music */ bool ambiance; /* receiver's preference is background ambiance */ @@ -443,12 +443,13 @@ typedef union IVAS_PIDATA_ISM_ATTENUATION ismAttenuation; IVAS_PIDATA_ISM_DIRECTIVITY ismDirectivity; IVAS_PIDATA_DIEGETIC digeticIndicator; + IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppressionIndication; IVAS_PIDATA_AUDIO_FOCUS focusIndication; IVAS_PIDATA_ORIENTATION playbackOrientation; IVAS_PIDATA_ORIENTATION headOrientation; IVAS_PIDATA_LISTENER_POSITION listnerPosition; - IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppression; + IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppressionRequest; IVAS_PIDATA_AUDIO_FOCUS focusRequest; IVAS_PIDATA_REVERSE_PI_LATENCY piLatency; IVAS_PIDATA_ISM_EDIT_ID ismEditId; -- GitLab From 7b668297291b268e93a15b015d7b686aeb19d2a6 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 15:17:08 +0200 Subject: [PATCH 08/34] Clang format --- apps/isar_post_rend.c | 6 +++--- lib_dec/lib_dec_fx.c | 2 +- lib_rend/ivas_rotation_fx.c | 2 +- lib_util/ivas_rtp_file.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index 2ebea17a6..bb8b3eaf2 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -401,9 +401,9 @@ static IVAS_AUDIO_CONFIG parseAudioConfig( char charBuf[25]; charBuf[24] = '\0'; - #ifdef RTP_S4_251135_CR26253_0016_REV1 - *srRtp = false; - #endif +#ifdef RTP_S4_251135_CR26253_0016_REV1 + *srRtp = false; +#endif strncpy( charBuf, configString, sizeof( charBuf ) - 1 ); charBuf[sizeof( charBuf ) - 1] = '\0'; to_upper( charBuf ); diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 3ac27bd2c..66193ac60 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -5660,7 +5660,7 @@ static ivas_error IVAS_DEC_feedSinglePIorientation( for ( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) { QuaternionProduct_fx( hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], savedInvOrientation, - &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i] ); + &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i] ); hIvasDec->st_ivas->hExtOrientationData->enableExternalOrientation[i] = true; } hIvasDec->updateOrientation = true; diff --git a/lib_rend/ivas_rotation_fx.c b/lib_rend/ivas_rotation_fx.c index cf0386c63..676ca7147 100644 --- a/lib_rend/ivas_rotation_fx.c +++ b/lib_rend/ivas_rotation_fx.c @@ -1441,7 +1441,7 @@ ivas_error ivas_combined_orientation_open_fx( move16(); #ifdef RTP_S4_251135_CR26253_0016_REV1 - FOR ( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ ) + FOR( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ ) { ( *hCombinedOrientationData )->isDiegeticInputPI[i] = TRUE; move16(); diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 5846b0423..ab08b5e02 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -693,7 +693,7 @@ ivas_error IVAS_RTP_WRITER_Init( } ivas_error IVAS_RTP_READER_Init( - IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */ + IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */ #ifdef RTP_S4_251135_CR26253_0016_REV1 uint32_t srCodecFrameSizeMs, /* i : SR Codec Framesize in ms */ #endif @@ -760,8 +760,8 @@ ivas_error IVAS_RTP_READER_Init( } ivas_error IVAS_RTP_WriteNextFrame( - IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */ - uint8_t *au, /* i : IVAS Compressed AU (Packed frame) */ + IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */ + uint8_t *au, /* i : IVAS Compressed AU (Packed frame) */ #ifdef RTP_S4_251135_CR26253_0016_REV1 const IVAS_RTP_SR_INFO *srInfo, /* i : Split rendering info in present, else NULL */ #endif @@ -833,7 +833,7 @@ ivas_error IVAS_RTP_ReadNextFrame( #ifdef RTP_S4_251135_CR26253_0016_REV1 IVAS_RTP_SR_INFO *srInfo, /* o : Split Rendering info if SR RTP frame unpacked */ #endif - bool *qBit /* o : AMRWB Q bite as indicated in the RTP packet */ + bool *qBit /* o : AMRWB Q bite as indicated in the RTP packet */ ) { ivas_error error = IVAS_ERR_OK; -- GitLab From c17ed8c8d8921f06670adfd084c62fa15e2f7c05 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 15:24:40 +0200 Subject: [PATCH 09/34] Remove unused parameter --- apps/decoder.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/decoder.c b/apps/decoder.c index c7707df5d..256926c56 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -2816,7 +2816,6 @@ static ivas_error decodeVoIP( #ifdef IVAS_RTPDUMP IVAS_RTP ivasRtp = { 0 }; IVAS_RTP srRtp = { 0 }; - IVAS_RTP_SR_INFO srInfo = { true, false, 0, IVAS_SR_TRANSPORT_LCLD }; int32_t initialTsOffsetSystemAndRTP = 0; #else FILE *f_rtpstream = NULL; -- GitLab From 1f22a948a660e17c651db8ee99ed3e590e255fbd Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 3 Nov 2025 16:39:54 +0200 Subject: [PATCH 10/34] Fix PI orientations --- lib_util/ivas_rtp_file.c | 70 +++++++++++++++++++++++++++++-------- lib_util/ivas_rtp_pi_data.c | 32 ++++++++--------- 2 files changed, 72 insertions(+), 30 deletions(-) diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index ab08b5e02..10eaa73c1 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -33,6 +33,7 @@ #include #include "ivas_rtp_file.h" #include "ivas_error_utils.h" +#include "prot_fx.h" struct IVAS_RTP_FILE { @@ -191,8 +192,11 @@ void IVAS_RTP_LogPiData( case IVAS_PI_R_ISM_ORIENTATION: #endif { - fprintf( f_piDataOut, "{\n\t\t\t\"w\": %d,\n\t\t\t\"x\": %d,\n\t\t\t\"y\": %d,\n\t\t\t\"z\": %d \n\t\t}", - cur->data.scene.orientation.w_fx, cur->data.scene.orientation.x_fx, cur->data.scene.orientation.y_fx, cur->data.scene.orientation.z_fx ); + fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + fixedToFloat( cur->data.scene.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.z_fx, Q15 ) ); } break; @@ -259,8 +263,11 @@ void IVAS_RTP_LogPiData( if ( cur->data.focusIndication.availDirection ) { fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); - fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %d,\n\t\t\t\t\t\t\"x\": %d,\n\t\t\t\t\t\t\"y\": %d,\n\t\t\t\t\t\t\"z\": %d \n\t\t\t}", - cur->data.focusIndication.direction.w_fx, cur->data.focusIndication.direction.x_fx, cur->data.focusIndication.direction.y_fx, cur->data.focusIndication.direction.z_fx ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", + fixedToFloat( cur->data.focusIndication.direction.w_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.x_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.y_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.z_fx, Q15 ) ); if ( cur->data.focusIndication.availLevel ) { fprintf( f_piDataOut, "," ); @@ -301,8 +308,11 @@ void IVAS_RTP_LogPiData( if ( cur->data.focusRequest.availDirection ) { fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); - fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %d,\n\t\t\t\t\t\t\"x\": %d,\n\t\t\t\t\t\t\"y\": %d,\n\t\t\t\t\t\t\"z\": %d \n\t\t\t}", - cur->data.focusRequest.direction.w_fx, cur->data.focusRequest.direction.x_fx, cur->data.focusRequest.direction.y_fx, cur->data.focusRequest.direction.z_fx ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", + fixedToFloat( cur->data.focusRequest.direction.w_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.x_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.y_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.z_fx, Q15 ) ); if ( cur->data.focusRequest.availLevel ) { fprintf( f_piDataOut, "," ); @@ -372,17 +382,29 @@ void IVAS_RTP_WriteExtPiData( { case IVAS_PI_SCENE_ORIENTATION: { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.scene.orientation.w_fx, cur->data.scene.orientation.x_fx, cur->data.scene.orientation.y_fx, cur->data.scene.orientation.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.scene.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.z_fx, Q15 ) ); } break; case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.deviceCompensated.orientation.w_fx, cur->data.deviceCompensated.orientation.x_fx, cur->data.deviceCompensated.orientation.y_fx, cur->data.deviceCompensated.orientation.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.deviceCompensated.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.deviceCompensated.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.deviceCompensated.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.deviceCompensated.orientation.z_fx, Q15 ) ); } break; case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.deviceUnCompensated.orientation.w_fx, cur->data.deviceUnCompensated.orientation.x_fx, cur->data.deviceUnCompensated.orientation.y_fx, cur->data.deviceUnCompensated.orientation.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.deviceUnCompensated.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.deviceUnCompensated.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.deviceUnCompensated.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.deviceUnCompensated.orientation.z_fx, Q15 ) ); } break; case IVAS_PI_ACOUSTIC_ENVIRONMENT: @@ -450,7 +472,11 @@ void IVAS_RTP_WriteExtPiData( { fprintf( f_piDataOut, "," ); } - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.ismOrientation.orientation[i].w_fx, cur->data.ismOrientation.orientation[i].x_fx, cur->data.ismOrientation.orientation[i].y_fx, cur->data.ismOrientation.orientation[i].z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.ismOrientation.orientation[i].w_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[i].x_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[i].y_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[i].z_fx, Q15 ) ); } } break; @@ -506,7 +532,11 @@ void IVAS_RTP_WriteExtPiData( { if ( cur->data.focusIndication.availDirection ) { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.focusIndication.direction.w_fx, cur->data.focusIndication.direction.x_fx, cur->data.focusIndication.direction.y_fx, cur->data.focusIndication.direction.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.focusIndication.direction.w_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.x_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.y_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.z_fx, Q15 ) ); if ( cur->data.focusIndication.availLevel ) { fprintf( f_piDataOut, "," ); @@ -520,12 +550,20 @@ void IVAS_RTP_WriteExtPiData( break; case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.playbackOrientation.orientation.w_fx, cur->data.playbackOrientation.orientation.x_fx, cur->data.playbackOrientation.orientation.y_fx, cur->data.playbackOrientation.orientation.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.playbackOrientation.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.playbackOrientation.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.playbackOrientation.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.playbackOrientation.orientation.z_fx, Q15 ) ); } break; case IVAS_PI_HEAD_ORIENTATION: { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.headOrientation.orientation.w_fx, cur->data.headOrientation.orientation.x_fx, cur->data.headOrientation.orientation.y_fx, cur->data.headOrientation.orientation.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.headOrientation.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.headOrientation.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.headOrientation.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.headOrientation.orientation.z_fx, Q15 ) ); } break; case IVAS_PI_LISTENER_POSITION: @@ -544,7 +582,11 @@ void IVAS_RTP_WriteExtPiData( if ( cur->data.focusRequest.availDirection ) { - fprintf( f_piDataOut, "%d,%d,%d,%d", cur->data.focusRequest.direction.w_fx, cur->data.focusRequest.direction.x_fx, cur->data.focusRequest.direction.y_fx, cur->data.focusRequest.direction.z_fx ); + fprintf( f_piDataOut, "%f,%f,%f,%f", + fixedToFloat( cur->data.focusRequest.direction.w_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.x_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.y_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.z_fx, Q15 ) ); if ( cur->data.focusRequest.availLevel ) { fprintf( f_piDataOut, "," ); diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index 8d50b9681..be2e9dd4d 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -145,10 +145,10 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ buffer[nBytes++] = 8; - nBytes = writeInt16( buffer, nBytes, orientation->orientation.w_fx ); - nBytes = writeInt16( buffer, nBytes, orientation->orientation.x_fx ); - nBytes = writeInt16( buffer, nBytes, orientation->orientation.y_fx ); - nBytes = writeInt16( buffer, nBytes, orientation->orientation.z_fx ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation.w_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation.x_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation.y_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation.z_fx ) ); *nBytesWritten = nBytes; return IVAS_ERR_OK; @@ -165,10 +165,10 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); - orientation->orientation.w_fx = readInt16( &buffer[0] ); - orientation->orientation.x_fx = readInt16( &buffer[2] ); - orientation->orientation.y_fx = readInt16( &buffer[4] ); - orientation->orientation.z_fx = readInt16( &buffer[6] ); + orientation->orientation.w_fx = L_deposit_l( readInt16( &buffer[0] ) ); + orientation->orientation.x_fx = L_deposit_l( readInt16( &buffer[2] ) ); + orientation->orientation.y_fx = L_deposit_l( readInt16( &buffer[4] ) ); + orientation->orientation.z_fx = L_deposit_l( readInt16( &buffer[6] ) ); return IVAS_ERR_OK; } @@ -582,10 +582,10 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 if ( packedSize == 9 || packedSize == 8 ) { - nBytes = writeInt16( buffer, nBytes, audioFocus->direction.w_fx ); - nBytes = writeInt16( buffer, nBytes, audioFocus->direction.x_fx ); - nBytes = writeInt16( buffer, nBytes, audioFocus->direction.y_fx ); - nBytes = writeInt16( buffer, nBytes, audioFocus->direction.z_fx ); + nBytes = writeInt16( buffer, nBytes, round_fx( audioFocus->direction.w_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( audioFocus->direction.x_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( audioFocus->direction.y_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( audioFocus->direction.z_fx ) ); } if ( packedSize == 9 || packedSize == 1 ) { @@ -616,10 +616,10 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat } else { - audioFocus->direction.w_fx = readInt16( &buffer[0] ); - audioFocus->direction.x_fx = readInt16( &buffer[2] ); - audioFocus->direction.y_fx = readInt16( &buffer[4] ); - audioFocus->direction.z_fx = readInt16( &buffer[6] ); + audioFocus->direction.w_fx = L_deposit_l( readInt16( &buffer[0] ) ); + audioFocus->direction.x_fx = L_deposit_l( readInt16( &buffer[2] ) ); + audioFocus->direction.y_fx = L_deposit_l( readInt16( &buffer[4] ) ); + audioFocus->direction.z_fx = L_deposit_l( readInt16( &buffer[6] ) ); if ( numDataBytes == 9 ) { -- GitLab From 37df39ef5555b3682ce713bc9cec8954d517f82e Mon Sep 17 00:00:00 2001 From: Tapani Pihlajakuja Date: Tue, 4 Nov 2025 14:42:44 +0200 Subject: [PATCH 11/34] Convert more to BASOP. --- lib_com/bitstream_fx.c | 15 +++++++-- lib_dec/ivas_binRenderer_internal_fx.c | 3 ++ lib_dec/ivas_dirac_dec_fx.c | 1 + lib_dec/ivas_init_dec_fx.c | 1 + lib_dec/ivas_mc_param_dec_fx.c | 1 + lib_dec/ivas_mc_paramupmix_dec_fx.c | 4 +++ lib_dec/ivas_mct_dec_fx.c | 1 + lib_dec/ivas_output_config_fx.c | 4 +++ lib_dec/lib_dec.h | 2 +- lib_dec/lib_dec_fx.c | 45 +++++++++++++++----------- lib_enc/lib_enc_fx.c | 2 +- lib_rend/ivas_rotation_fx.c | 34 +++++++++++++++++-- 12 files changed, 87 insertions(+), 26 deletions(-) diff --git a/lib_com/bitstream_fx.c b/lib_com/bitstream_fx.c index 334fa3dbc..b5162777e 100644 --- a/lib_com/bitstream_fx.c +++ b/lib_com/bitstream_fx.c @@ -3857,11 +3857,20 @@ void convertSerialToBytestream_fx( UWord32 i; UWord8 bit, bitinbyte; - for ( i = 0; i < num_bits; ++i ) + FOR( i = 0; i < num_bits; ++i ) { - bit = ( serial[i] == 0x0001 ) ? 1 : 0; + IF( EQ_32( serial[i], 0x0001 ) ) + { + bit = 1; + move16(); + } + ELSE + { + bit = 0; + move16(); + } bitinbyte = bit << ( 7 - ( i & 0x7 ) ); - if ( !( i & 0x7 ) ) + IF( !( i & 0x7 ) ) { bytestream[i >> 3] = 0; } diff --git a/lib_dec/ivas_binRenderer_internal_fx.c b/lib_dec/ivas_binRenderer_internal_fx.c index 0ed0696d2..36471b156 100644 --- a/lib_dec/ivas_binRenderer_internal_fx.c +++ b/lib_dec/ivas_binRenderer_internal_fx.c @@ -1237,6 +1237,9 @@ ivas_error ivas_binRenderer_open_fx( { test(); test(); +#ifdef IVAS_RTPDUMP + test(); +#endif IF( hBinRenderer->hInputSetup->is_loudspeaker_setup == 0 ) { FOR( k = 0; k < 11; k++ ) diff --git a/lib_dec/ivas_dirac_dec_fx.c b/lib_dec/ivas_dirac_dec_fx.c index 0f4e513d6..0a19a4968 100644 --- a/lib_dec/ivas_dirac_dec_fx.c +++ b/lib_dec/ivas_dirac_dec_fx.c @@ -3083,6 +3083,7 @@ void ivas_dirac_dec_render_sf_fx( test(); test(); #ifdef IVAS_RTPDUMP + test(); IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) && st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) #else IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) diff --git a/lib_dec/ivas_init_dec_fx.c b/lib_dec/ivas_init_dec_fx.c index 28022bbfa..658f32938 100644 --- a/lib_dec/ivas_init_dec_fx.c +++ b/lib_dec/ivas_init_dec_fx.c @@ -2583,6 +2583,7 @@ ivas_error ivas_init_decoder_fx( test(); test(); #ifdef IVAS_RTPDUMP + test(); IF( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_MIXER_CONV_ROOM ) && EQ_32( st_ivas->ivas_format, MC_FORMAT ) && ( hDecoderConfig->Opt_Headrotation || hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) #else IF( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_MIXER_CONV_ROOM ) && EQ_32( st_ivas->ivas_format, MC_FORMAT ) && ( hDecoderConfig->Opt_Headrotation || hDecoderConfig->Opt_ExternalOrientation ) ) diff --git a/lib_dec/ivas_mc_param_dec_fx.c b/lib_dec/ivas_mc_param_dec_fx.c index 4faac7183..e6de1f286 100644 --- a/lib_dec/ivas_mc_param_dec_fx.c +++ b/lib_dec/ivas_mc_param_dec_fx.c @@ -462,6 +462,7 @@ ivas_error ivas_param_mc_dec_open_fx( test(); test(); #ifdef IVAS_RTPDUMP + test(); IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) #else IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) diff --git a/lib_dec/ivas_mc_paramupmix_dec_fx.c b/lib_dec/ivas_mc_paramupmix_dec_fx.c index 09be09281..74411d502 100644 --- a/lib_dec/ivas_mc_paramupmix_dec_fx.c +++ b/lib_dec/ivas_mc_paramupmix_dec_fx.c @@ -382,6 +382,10 @@ ivas_error ivas_mc_paramupmix_dec_open( /* Head or external rotation */ #ifdef IVAS_RTPDUMP + test(); + test(); + test(); + test(); IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) #else IF( ( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_FASTCONV_ROOM ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) diff --git a/lib_dec/ivas_mct_dec_fx.c b/lib_dec/ivas_mct_dec_fx.c index 81b8bfe64..8970a0820 100644 --- a/lib_dec/ivas_mct_dec_fx.c +++ b/lib_dec/ivas_mct_dec_fx.c @@ -1376,6 +1376,7 @@ static ivas_error ivas_mc_dec_reconfig_fx( test(); #ifdef IVAS_RTPDUMP + test(); IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) #else IF( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) diff --git a/lib_dec/ivas_output_config_fx.c b/lib_dec/ivas_output_config_fx.c index 5ce0eea84..a1b8ae846 100644 --- a/lib_dec/ivas_output_config_fx.c +++ b/lib_dec/ivas_output_config_fx.c @@ -71,6 +71,7 @@ void ivas_renderer_select( test(); #ifdef IVAS_RTPDUMP + test(); IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) #else IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) @@ -168,6 +169,7 @@ void ivas_renderer_select( test(); #ifdef IVAS_RTPDUMP + test(); IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) #else IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) @@ -229,6 +231,7 @@ void ivas_renderer_select( test(); test(); #ifdef IVAS_RTPDUMP + test(); IF( ( EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_7_1 ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) && EQ_32( st_ivas->mc_mode, MC_MODE_MCT ) ) #else IF( ( EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_7_1 ) ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && EQ_32( st_ivas->mc_mode, MC_MODE_MCT ) ) @@ -252,6 +255,7 @@ void ivas_renderer_select( test(); #ifdef IVAS_RTPDUMP + test(); IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) #else IF( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 0177b8709..67a0297a9 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -494,7 +494,7 @@ void IVAS_DEC_PrintDisclaimer( #ifdef IVAS_RTPDUMP #include "ivas_rtp_pi_data.h" -ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *piData, uint32_t numPiData ); +ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *piData, UWord32 numPiData ); #endif /* clang-format on */ diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 66193ac60..cba2367c8 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -5632,23 +5632,23 @@ static ivas_error IVAS_DEC_feedSinglePIorientation( IVAS_QUATERNION *savedOrientation /* i : previously saved orientation for this PI type */ ) { - int16_t i; + Word16 i; ivas_error error = IVAS_ERR_OK; IVAS_QUATERNION savedInvOrientation; - if ( isOrientationSaved ) + IF( isOrientationSaved ) { - if ( !hIvasDec->st_ivas->hExtOrientationData ) + IF( !hIvasDec->st_ivas->hExtOrientationData ) { - if ( ( error = ivas_external_orientation_open_fx( &( hIvasDec->st_ivas->hExtOrientationData ), hIvasDec->st_ivas->hDecoderConfig->render_framesize ) ) != IVAS_ERR_OK ) + IF( NE_32( error = ivas_external_orientation_open_fx( &( hIvasDec->st_ivas->hExtOrientationData ), hIvasDec->st_ivas->hDecoderConfig->render_framesize ), IVAS_ERR_OK ) ) { return error; } } - if ( !hIvasDec->st_ivas->hCombinedOrientationData ) + IF( !hIvasDec->st_ivas->hCombinedOrientationData ) { - if ( ( error = ivas_combined_orientation_open_fx( &( hIvasDec->st_ivas->hCombinedOrientationData ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, hIvasDec->st_ivas->hDecoderConfig->render_framesize ) ) != IVAS_ERR_OK ) + IF( NE_32( error = ivas_combined_orientation_open_fx( &( hIvasDec->st_ivas->hCombinedOrientationData ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, hIvasDec->st_ivas->hDecoderConfig->render_framesize ), IVAS_ERR_OK ) ) { return error; } @@ -5657,13 +5657,15 @@ static ivas_error IVAS_DEC_feedSinglePIorientation( QuaternionInverse_fx( *savedOrientation, &savedInvOrientation ); /* use the new PI orientation or the previously saved orientation in processing */ - for ( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) + FOR( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) { QuaternionProduct_fx( hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], savedInvOrientation, &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i] ); hIvasDec->st_ivas->hExtOrientationData->enableExternalOrientation[i] = true; + move16(); } hIvasDec->updateOrientation = true; + move16(); } return error; } @@ -5681,26 +5683,31 @@ static void IVAS_DEC_setDiegeticInputPI( const bool *diegeticPIValues /* i : diegetic values for the input stream */ ) { - if ( hIvasDec->st_ivas->hCombinedOrientationData != NULL ) + IF( hIvasDec->st_ivas->hCombinedOrientationData != NULL ) { - int8_t i; - for ( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ ) + Word8 i; + FOR( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ ) { hIvasDec->st_ivas->hCombinedOrientationData->isDiegeticInputPI[i] = diegeticPIValues[i]; + move16(); } hIvasDec->st_ivas->hCombinedOrientationData->isDiegeticInputPISet = true; + move16(); } } #endif #ifdef IVAS_RTPDUMP -ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *piData, uint32_t numPiData ) +ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *piData, UWord32 numPiData ) { ivas_error error = IVAS_ERR_OK; - while ( numPiData-- ) + move32(); + WHILE( numPiData ) { - uint32_t piDataType = piData->data.noPiData.piDataType; - switch ( piDataType ) + UWord32 piDataType = piData->data.noPiData.piDataType; + move32(); + numPiData = UL_subNsD( numPiData, 1 ); /* Subtraction of WHILE variable */ + SWITCH( piDataType ) { case IVAS_PI_SCENE_ORIENTATION: { @@ -5710,7 +5717,7 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } - break; + BREAK; case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: { @@ -5720,7 +5727,7 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } - break; + BREAK; #ifdef RTP_S4_251135_CR26253_0016_REV1 case IVAS_PI_DIEGETIC_TYPE: @@ -5730,16 +5737,16 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi #endif IVAS_DEC_setDiegeticInputPI( hIvasDec, piData->data.digeticIndicator.isDiegetic ); } - break; + BREAK; #endif default: { /* NOT HANDLED PI DATA - DO NOTHING */ } - break; + BREAK; } - if ( error != IVAS_ERR_OK ) + IF( NE_32(error, IVAS_ERR_OK) ) { return error; } diff --git a/lib_enc/lib_enc_fx.c b/lib_enc/lib_enc_fx.c index 5eac61b60..98a522e69 100644 --- a/lib_enc/lib_enc_fx.c +++ b/lib_enc/lib_enc_fx.c @@ -1545,7 +1545,7 @@ ivas_error IVAS_ENC_EncodeFrameToCompact( ivas_error error; UWord16 bitstream[IVAS_MAX_BITS_PER_FRAME]; - if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, inputBuffer, inputBufferSize, bitstream, numOutBits ) ) != IVAS_ERR_OK ) + IF( NE_32( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, inputBuffer, inputBufferSize, bitstream, numOutBits ), IVAS_ERR_OK ) ) { return error; } diff --git a/lib_rend/ivas_rotation_fx.c b/lib_rend/ivas_rotation_fx.c index 676ca7147..b0f9e547e 100644 --- a/lib_rend/ivas_rotation_fx.c +++ b/lib_rend/ivas_rotation_fx.c @@ -1641,11 +1641,21 @@ ivas_error combine_external_and_head_orientations( { #ifdef RTP_S4_251135_CR26253_0016_REV1 /* Disable head rotation if diegetic PI data indicating non-diegetic audio is received */ + test(); + test(); + test(); + test(); + test(); IF( hCombinedOrientationData->isDiegeticInputPISet && !hCombinedOrientationData->isDiegeticInputPI[0] && !hCombinedOrientationData->isDiegeticInputPI[1] && !hCombinedOrientationData->isDiegeticInputPI[2] && !hCombinedOrientationData->isDiegeticInputPI[3] && !hCombinedOrientationData->isDiegeticInputPI[4] ) { FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) { hCombinedOrientationData->Quaternions[i] = identity; + move32(); /* Copying full struct */ + move32(); + move32(); + move32(); + move16(); } } ELSE @@ -1654,6 +1664,11 @@ ivas_error combine_external_and_head_orientations( FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) { hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + move32(); /* Copying full struct */ + move32(); + move32(); + move32(); + move16(); } } #else @@ -1789,20 +1804,25 @@ ivas_error combine_external_and_head_orientations( /* Disable head rotation if diegetic PI data indicating non-diegetic audio is received */ IF( hCombinedOrientationData->isDiegeticInputPISet && !hCombinedOrientationData->isDiegeticInputPI[0] && !hCombinedOrientationData->isDiegeticInputPI[1] && !hCombinedOrientationData->isDiegeticInputPI[2] && !hCombinedOrientationData->isDiegeticInputPI[3] && !hCombinedOrientationData->isDiegeticInputPI[4] ) { - continue; + CONTINUE; } ELSE { /* Use the most recent head rotation */ IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 1 ) ) { - IF( hExtOrientationData->enableExternalOrientation[i] > 0 ) + IF( GT_16(hExtOrientationData->enableExternalOrientation[i], 0) ) { QuaternionProduct_fx( hCombinedOrientationData->Quaternions[i], headRotQuaternions[i], &hCombinedOrientationData->Quaternions[i] ); } ELSE { hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + move32(); /* Copying full struct */ + move32(); + move32(); + move32(); + move16(); } } /* Use the freezed head rotation */ @@ -1815,6 +1835,11 @@ ivas_error combine_external_and_head_orientations( ELSE { hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_head; + move32(); /* Copying full struct */ + move32(); + move32(); + move32(); + move16(); } } } @@ -1981,6 +2006,11 @@ ivas_error combine_external_and_head_orientations( FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) { hExtOrientationData->Quaternions[i] = identity; + move32(); + move32(); + move32(); + move32(); + move16(); } } #endif -- GitLab From de32410c5896bb3145d8998db4d5b000d7e85bad Mon Sep 17 00:00:00 2001 From: Tommy Date: Wed, 5 Nov 2025 09:36:15 -0500 Subject: [PATCH 12/34] convert to fixed point convertSerialToBytestream_fx, debug code included --- lib_com/bitstream_fx.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/lib_com/bitstream_fx.c b/lib_com/bitstream_fx.c index b5162777e..e507a7c9d 100644 --- a/lib_com/bitstream_fx.c +++ b/lib_com/bitstream_fx.c @@ -3854,9 +3854,12 @@ void convertSerialToBytestream_fx( UWord8 *const bytestream /* o : output compact bitstream (bytestream) */ ) { - UWord32 i; + Word16 i, ia7, isr3; UWord8 bit, bitinbyte; - +#ifdef DEBUGGING + UWord8 bitinbyte2, bytestream_tmp; + assert( num_bits <= MAX_16 ); /* 512 kbps = 10240 bits, num_bits should always fits Word16 */ +#endif FOR( i = 0; i < num_bits; ++i ) { IF( EQ_32( serial[i], 0x0001 ) ) @@ -3869,12 +3872,29 @@ void convertSerialToBytestream_fx( bit = 0; move16(); } - bitinbyte = bit << ( 7 - ( i & 0x7 ) ); - IF( !( i & 0x7 ) ) + /*bitinbyte = bit << ( 7 - ( i & 0x7 ) );*/ + ia7 = s_and( i, 0x7 ); + isr3 = shr( i, 3 ); + bitinbyte = (UWord8) shl( (Word16) bit, sub( 7, ia7 ) ); +#ifdef DEBUGGING + bitinbyte2 = bit << ( 7 - ( i & 0x7 ) ); + assert( bitinbyte2 == bitinbyte ); +#endif + IF( !( ia7 ) ) { - bytestream[i >> 3] = 0; + bytestream[isr3] = 0; + move16(); } - bytestream[i >> 3] |= bitinbyte; + /*bytestream[i >> 3] |= bitinbyte;*/ +#ifdef DEBUGGING + bytestream_tmp = bytestream[isr3]; + bytestream_tmp |= bitinbyte2; +#endif + bytestream[isr3] = (Word8) s_or( bytestream[isr3], bitinbyte ); +#ifdef DEBUGGING + assert( bytestream_tmp == bytestream[isr3] ); +#endif + move16(); } return; -- GitLab From 9c6b784a2080ef3471075c87ccd8d19ddd201e15 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 5 Nov 2025 17:24:37 +0200 Subject: [PATCH 13/34] Port float MR2320 --- apps/decoder.c | 15 +++++++++++++++ apps/encoder.c | 17 +++++++++++++++++ lib_com/options.h | 1 + lib_util/ivas_rtp_api.h | 13 +++++++++++++ lib_util/ivas_rtp_file.c | 13 +++++++++++++ lib_util/ivas_rtp_file.h | 4 ++++ lib_util/ivas_rtp_payload.c | 13 +++++++++++++ 7 files changed, 76 insertions(+) diff --git a/apps/decoder.c b/apps/decoder.c index 9c303e9ad..3e8dc09de 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -56,6 +56,9 @@ #include "ivas_rtp_file.h" #endif +#ifdef FIXED_RTP_SEQUENCE_NUM +#define RANDOM_INITSEED_DEC ( 0xFEEDFADE ) +#endif #define WMC_TOOL_SKIP @@ -1702,6 +1705,14 @@ static ivas_error initOnFirstGoodFrame( ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection; int16_t splitRendIsarFrameSizeMs; int16_t lc3plusHighRes; +#ifdef FIXED_RTP_SEQUENCE_NUM + /* Ideally ssrc is negotiated via SDP and sequence number is radomized but we + use fixed seed for random num generator for regression based tests. Any realtime + application should implement this initialization seperately */ + srand( RANDOM_INITSEED_DEC ); + uint32_t ssrc = ( (uint32_t) rand() & 0x0000FFFF ) | ( (uint32_t) rand() << 16 ); + uint16_t seqNumInitVal = (uint16_t) ( rand() & 0xFFFF ); +#endif if ( ( error = IVAS_DEC_GetDelay( hIvasDec, delayNumSamples_temp, &delayTimeScale_temp ) ) != IVAS_ERR_OK ) { @@ -1740,7 +1751,11 @@ static ivas_error initOnFirstGoodFrame( /* Split Rendering RTPDump Output file */ +#ifdef FIXED_RTP_SEQUENCE_NUM + if ( ( error = IVAS_RTP_WRITER_Init( srRtp, arg.outputWavFilename, 1000 / ( IVAS_NUM_FRAMES_PER_SEC * splitRendCodecFrameSizeMs ), ssrc, seqNumInitVal ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_RTP_WRITER_Init( srRtp, arg.outputWavFilename, 1000 / ( IVAS_NUM_FRAMES_PER_SEC * splitRendCodecFrameSizeMs ) ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError: Can't open SR output bitstream file for RTP output %s \n\n", arg.outputWavFilename ); return error; diff --git a/apps/encoder.c b/apps/encoder.c index 5e2de5f45..fe64442e1 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -63,6 +63,10 @@ #endif #endif +#ifdef FIXED_RTP_SEQUENCE_NUM +#define RANDOM_INITSEED_ENC ( 0xFEEDDEAF ) +#endif + #define WMC_TOOL_SKIP /*------------------------------------------------------------------------------------------* @@ -226,6 +230,15 @@ int main( IVAS_RTP ivasRtp = { 0 }; #endif +#ifdef FIXED_RTP_SEQUENCE_NUM + /* Ideally ssrc is negotiated via SDP and sequence number is radomized but we + use fixed seed for random num generator for regression based tests. Any realtime + application should implement this initialization seperately */ + srand( RANDOM_INITSEED_ENC ); + uint32_t ssrc = ( (uint32_t) rand() & 0x0000FFFF ) | ( (uint32_t) rand() << 16 ); + uint16_t seqNumInitVal = (uint16_t) ( rand() & 0xFFFF ); +#endif + /*------------------------------------------------------------------------------------------* * Parse command-line arguments *------------------------------------------------------------------------------------------*/ @@ -621,7 +634,11 @@ int main( if ( arg.rtpdumpOutput ) { +#ifdef FIXED_RTP_SEQUENCE_NUM + if ( ( error = IVAS_RTP_WRITER_Init( &ivasRtp, arg.outputBitstreamFilename, arg.numFramesPerPacket, ssrc, seqNumInitVal ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_RTP_WRITER_Init( &ivasRtp, arg.outputBitstreamFilename, arg.numFramesPerPacket ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError: Can't open output bitstream file for RTP output %s \n\n", arg.outputBitstreamFilename ); goto cleanup; diff --git a/lib_com/options.h b/lib_com/options.h index b8e650b8e..6dc0310f5 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -141,6 +141,7 @@ // RTPDUMP porting #define RTP_S4_251135_CR26253_0016_REV1 /* RTP Pack/Unpack API corresponding to CR 26253 */ #define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ +#define FIXED_RTP_SEQUENCE_NUM /* Remove random sequence number initialization */ /* #################### End BASOP porting switches ############################ */ diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 405893581..8e551c5ff 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -309,8 +309,10 @@ void IVAS_RTP_PACK_Close( ); /* Update the RTP Header structure */ +#ifdef FIXED_RTP_SEQUENCE_NUM ivas_error IVAS_RTP_PACK_UpdateHeader( IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ + uint16_t seqNumInitVal, /* i : Initial sequence number to be used for 1st packet */ uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */ uint8_t numCC, /* i : numCC indicates no. of contributing sources */ uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */ @@ -318,6 +320,17 @@ ivas_error IVAS_RTP_PACK_UpdateHeader( uint16_t numExtensionBytes, /* i : length of the extension data */ uint8_t *extData /* i : extension data pointer */ ); +#else +ivas_error IVAS_RTP_PACK_UpdateHeader( + IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ + uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */ + uint8_t numCC, /* i : numCC indicates no. of contributing sources */ + uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */ + uint16_t extHeaderId, /* i : extension header ID */ + uint16_t numExtensionBytes, /* i : length of the extension data */ + uint8_t *extData /* i : extension data pointer */ +); +#endif /* Add requests for remote sender using a key value pair api * each key must be provided with a corresponding value type diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 10eaa73c1..91a63f598 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -702,10 +702,19 @@ void IVAS_RTP_Term( ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */ const char *outputBitstreamFilename, /* i : RTP Dump filename */ +#ifdef FIXED_RTP_SEQUENCE_NUM + uint32_t numFramesPerPacket, /* i : No. of frames per packet desired */ + uint32_t SSRC, /* i : SSRC for RTP Header */ + uint16_t seqNumInitVal /* i : Initial seq number in rtp header */ +#else uint32_t numFramesPerPacket /* i : No. of frames per packet desired */ +#endif ) { + +#ifndef FIXED_RTP_SEQUENCE_NUM uint32_t SSRC = ( rand() & 0xFFFF ) | ( (uint32_t) rand() << 16 ); +#endif ivas_error error = IVAS_ERR_OK; memset( rtp, 0, sizeof( IVAS_RTP ) ); @@ -724,7 +733,11 @@ ivas_error IVAS_RTP_WRITER_Init( return error; } +#ifdef FIXED_RTP_SEQUENCE_NUM + error = IVAS_RTP_PACK_UpdateHeader( rtp->hPack, seqNumInitVal, SSRC, 0, NULL, 0, 0, NULL ); +#else error = IVAS_RTP_PACK_UpdateHeader( rtp->hPack, SSRC, 0, NULL, 0, 0, NULL ); +#endif if ( error != IVAS_ERR_OK ) { fprintf( stderr, "error in IVAS_RTP_PACK_UpdateHeader(): %d\n", error ); diff --git a/lib_util/ivas_rtp_file.h b/lib_util/ivas_rtp_file.h index d5fbc0504..78126b393 100644 --- a/lib_util/ivas_rtp_file.h +++ b/lib_util/ivas_rtp_file.h @@ -70,7 +70,11 @@ typedef struct #endif } IVAS_RTP; +#ifdef FIXED_RTP_SEQUENCE_NUM +ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilename, uint32_t numFramesPerPacket, uint32_t SSRC, uint16_t seqNumInitVal ); +#else ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilename, uint32_t numFramesPerPacket ); +#endif #ifdef RTP_S4_251135_CR26253_0016_REV1 ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, uint32_t srCodecFrameSizeMs, const char *inputBitstreamFilename, const char *piOutputFilename, bool isExtOutput, const char *outputWavFilename ); #else diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 46198011a..30ba918d7 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -32,7 +32,9 @@ #include #include #include +#ifndef FIXED_RTP_SEQUENCE_NUM #include +#endif #include "common_api_types.h" #ifdef IVAS_RTPDUMP @@ -182,6 +184,9 @@ static const uint32_t amrWBIOFrameSizeInBits[] = { /* Update the RTP Header structure */ ivas_error IVAS_RTP_PACK_UpdateHeader( IVAS_RTP_PACK_HANDLE hPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */ +#ifdef FIXED_RTP_SEQUENCE_NUM + uint16_t seqNumInitVal, /* i : Initial sequence number to be used for 1st packet */ +#endif uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */ uint8_t numCC, /* i : numCC indicates no. of contributing sources */ uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */ @@ -197,6 +202,9 @@ ivas_error IVAS_RTP_PACK_UpdateHeader( return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "CC must be less than 16" ); } +#ifdef FIXED_RTP_SEQUENCE_NUM + header->seqNumber = seqNumInitVal; +#endif header->ssrc = ssrc; header->CC = numCC; if ( csrc != NULL ) @@ -229,11 +237,16 @@ static void InitRtpHeader( RTP_HEADER *header /* RTP header structure */ ) { +#ifdef FIXED_RTP_SEQUENCE_NUM + memset( header, 0, sizeof( *header ) ); + header->version = 2; +#else time_t t; memset( header, 0, sizeof( *header ) ); srand( (uint32_t) time( &t ) ); header->version = 2; header->seqNumber = rand() & 0xFFFF; +#endif } static ivas_error PackRtpHeader( -- GitLab From 2e2f1c406bb783e12dac65270238c4a42a980556 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 5 Nov 2025 17:27:48 +0200 Subject: [PATCH 14/34] Add define switches --- lib_com/ivas_error.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index 3b49667d4..64209e04e 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -147,6 +147,7 @@ typedef enum IVAS_ERR_LC3PLUS_INVALID_BITRATE, IVAS_ERR_INVALID_SPLIT_REND_CONFIG, +#ifdef IVAS_RTPDUMP /*----------------------------------------* * rtp errors * *----------------------------------------*/ @@ -154,6 +155,7 @@ typedef enum IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, IVAS_ERR_RTP_UNPACK_PI_DATA, IVAS_ERR_RTP_UNSUPPORTED_FRAME, +#endif /*----------------------------------------* * unknown error * @@ -294,6 +296,7 @@ static inline const char *ivas_error_to_string( ivas_error error_code ) { return "data error"; } +#ifdef IVAS_RTPDUMP if ( ( error_code & 0x7000 ) == 0x7000 ) { switch ( error_code ) @@ -310,6 +313,7 @@ static inline const char *ivas_error_to_string( ivas_error error_code ) return "rtp error"; } } +#endif return "Unknown error"; } -- GitLab From ec36366c76c57e80d1ca01e66847ab3ac5c221a2 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 5 Nov 2025 17:35:15 +0200 Subject: [PATCH 15/34] Bring back removed srinfo parameter and related code --- apps/decoder.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/decoder.c b/apps/decoder.c index 3e8dc09de..0b799b377 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -2872,6 +2872,7 @@ static ivas_error decodeVoIP( #ifdef IVAS_RTPDUMP IVAS_RTP ivasRtp = { 0 }; IVAS_RTP srRtp = { 0 }; + IVAS_RTP_SR_INFO srInfo = { true, false, 0, IVAS_SR_TRANSPORT_LCLD }; int32_t initialTsOffsetSystemAndRTP = 0; #else FILE *f_rtpstream = NULL; @@ -3515,6 +3516,20 @@ static ivas_error decodeVoIP( #endif } } +#ifdef IVAS_RTPDUMP + else if ( decodedGoodFrame ) + { + srInfo.bitrateKbps = splitRendBits->bits_written * 1000 / splitRendBits->codec_frame_size_ms; + srInfo.codec = ( splitRendBits->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) ? IVAS_SR_TRANSPORT_LC3PLUS : IVAS_SR_TRANSPORT_LCLD; + if ( ( error = IVAS_RTP_WriteNextFrame( &srRtp, splitRendBits->bits_buf, &srInfo, (int16_t) splitRendBits->bits_written, false, false ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while pushing SR audio bitstream to RTP pack\n", ivas_error_to_string( error ) ); + goto cleanup; + } + splitRendBits->bits_written = 0; + splitRendBits->bits_read = 0; + } +#endif vec_pos_update = ( vec_pos_update + 1 ) % vec_pos_len; if ( vec_pos_update == 0 ) -- GitLab From 8006da630d5ec6082a5226dcf63bb07c0fd5fb9f Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 6 Nov 2025 09:27:54 +0200 Subject: [PATCH 16/34] Port float MR2282 --- lib_dec/lib_dec_fx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index aa27b6113..9e64630f2 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -412,11 +412,17 @@ void IVAS_DEC_Close( ( *phIvasDec )->hVoIP = NULL; } +#ifndef IVAS_RTPDUMP /* destroy Split binaural renderer (ISAR) handle */ ivas_destroy_handle_isar( &( *phIvasDec )->st_ivas->hSplitBinRend ); +#endif IF( ( *phIvasDec )->st_ivas ) { +#ifdef IVAS_RTPDUMP + /* destroy Split binaural renderer (ISAR) handle */ + ivas_destroy_handle_isar( &( *phIvasDec )->st_ivas->hSplitBinRend ); +#endif ivas_destroy_dec_fx( ( *phIvasDec )->st_ivas ); ( *phIvasDec )->st_ivas = NULL; } -- GitLab From ea7914163b6f578a8ffd81cea5b8534830436a15 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 6 Nov 2025 17:22:58 +0200 Subject: [PATCH 17/34] Add missing files to windows build --- Workspace_msvc/lib_dec.vcxproj | 2 +- Workspace_msvc/lib_util.vcxproj | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Workspace_msvc/lib_dec.vcxproj b/Workspace_msvc/lib_dec.vcxproj index 9d98513e8..e93fc6c7c 100644 --- a/Workspace_msvc/lib_dec.vcxproj +++ b/Workspace_msvc/lib_dec.vcxproj @@ -68,7 +68,7 @@ Disabled - ..\lib_basop;..\lib_com;..\lib_debug;..\lib_dec;..\lib_enc;..\lib_rend;..\lib_isar;..\lib_rend;..\lib_lc3plus;.%(AdditionalIncludeDirectories) + ..\lib_basop;..\lib_com;..\lib_debug;..\lib_dec;..\lib_enc;..\lib_rend;..\lib_isar;..\lib_rend;..\lib_lc3plus;..\lib_util;.%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;$(Macros);WIN32;%(PreprocessorDefinitions) EnableFastChecks diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 7b793cc4c..72dac3925 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -110,6 +110,11 @@ + + + + + @@ -137,6 +142,13 @@ + + + + + + + -- GitLab From 576c006b44637b4b78d2691a08e529ae74d2d1e7 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 6 Nov 2025 17:29:58 +0200 Subject: [PATCH 18/34] Clang format --- apps/decoder.c | 36 ++++++++++++++++++------------------ lib_dec/lib_dec_fx.c | 10 +++++----- lib_rend/ivas_rotation_fx.c | 2 +- lib_util/ivas_rtp_file.c | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 709e45961..c176e5be7 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3388,28 +3388,28 @@ static ivas_error decodeVoIP( SplitFileReadWrite *splitRendWriter = NULL; #endif - if ( ( error = initOnFirstGoodFrame( hIvasDec, - arg, - numInitialBadFrames, - &nOutSamples, + if ( ( error = initOnFirstGoodFrame( hIvasDec, + arg, + numInitialBadFrames, + &nOutSamples, #ifdef FIX_1119_SPLIT_RENDERING_VOIP - &vec_pos_len, + &vec_pos_len, #else - NULL, -#endif - delayNumSamples_orig, - &delayNumSamples, - &delayTimeScale, - &bsFormat, - &afWriter, - &masaWriter, - ismWriters, - &nOutChannels, - &numObj, + NULL, +#endif + delayNumSamples_orig, + &delayNumSamples, + &delayTimeScale, + &bsFormat, + &afWriter, + &masaWriter, + ismWriters, + &nOutChannels, + &numObj, #ifdef IVAS_RTPDUMP - &srRtp, + &srRtp, #endif - &splitRendWriter ) ) != IVAS_ERR_OK ) + &splitRendWriter ) ) != IVAS_ERR_OK ) { goto cleanup; } diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 9e64630f2..6c6700558 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -6422,7 +6422,7 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } - BREAK; + BREAK; case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: { @@ -6432,7 +6432,7 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } - BREAK; + BREAK; #ifdef RTP_S4_251135_CR26253_0016_REV1 case IVAS_PI_DIEGETIC_TYPE: @@ -6442,16 +6442,16 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi #endif IVAS_DEC_setDiegeticInputPI( hIvasDec, piData->data.digeticIndicator.isDiegetic ); } - BREAK; + BREAK; #endif default: { /* NOT HANDLED PI DATA - DO NOTHING */ } - BREAK; + BREAK; } - IF( NE_32(error, IVAS_ERR_OK) ) + IF( NE_32( error, IVAS_ERR_OK ) ) { return error; } diff --git a/lib_rend/ivas_rotation_fx.c b/lib_rend/ivas_rotation_fx.c index b0f9e547e..b9762f72c 100644 --- a/lib_rend/ivas_rotation_fx.c +++ b/lib_rend/ivas_rotation_fx.c @@ -1811,7 +1811,7 @@ ivas_error combine_external_and_head_orientations( /* Use the most recent head rotation */ IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 1 ) ) { - IF( GT_16(hExtOrientationData->enableExternalOrientation[i], 0) ) + IF( GT_16( hExtOrientationData->enableExternalOrientation[i], 0 ) ) { QuaternionProduct_fx( hCombinedOrientationData->Quaternions[i], headRotQuaternions[i], &hCombinedOrientationData->Quaternions[i] ); } diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 91a63f598..82f198135 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -707,7 +707,7 @@ ivas_error IVAS_RTP_WRITER_Init( uint32_t SSRC, /* i : SSRC for RTP Header */ uint16_t seqNumInitVal /* i : Initial seq number in rtp header */ #else - uint32_t numFramesPerPacket /* i : No. of frames per packet desired */ + uint32_t numFramesPerPacket /* i : No. of frames per packet desired */ #endif ) { -- GitLab From a5c226d73dcd818280126138e0d54c7b901eeeba Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 14:23:24 +0200 Subject: [PATCH 19/34] Port float MR2369 reverse direction ISM PI --- lib_com/options.h | 1 + lib_util/ivas_rtp_file.c | 42 ++++++ lib_util/ivas_rtp_internal.h | 3 + lib_util/ivas_rtp_pi_data.c | 266 +++++++++++++++++++++++++++++++++++ lib_util/ivas_rtp_pi_data.h | 32 +++++ 5 files changed, 344 insertions(+) diff --git a/lib_com/options.h b/lib_com/options.h index c6a4efa4b..9f6426547 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -161,6 +161,7 @@ #define RTP_S4_251135_CR26253_0016_REV1 /* RTP Pack/Unpack API corresponding to CR 26253 */ #define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ #define FIXED_RTP_SEQUENCE_NUM /* Remove random sequence number initialization */ +#define REVERSE_ISM_PI_DATA /* Add reading and packing/unpacking of reverse ISM PI data */ /* #################### End BASOP porting switches ############################ */ diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 82f198135..cf721edf4 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -189,7 +189,9 @@ void IVAS_RTP_LogPiData( #ifdef RTP_S4_251135_CR26253_0016_REV1 case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: case IVAS_PI_HEAD_ORIENTATION: +#ifndef REVERSE_ISM_PI_DATA case IVAS_PI_R_ISM_ORIENTATION: +#endif #endif { fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", @@ -218,7 +220,9 @@ void IVAS_RTP_LogPiData( break; #ifdef RTP_S4_251135_CR26253_0016_REV1 case IVAS_PI_LISTENER_POSITION: +#ifndef REVERSE_ISM_PI_DATA case IVAS_PI_R_ISM_POSITION: +#endif { fprintf( f_piDataOut, "{\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", cur->data.listnerPosition.position.x, cur->data.listnerPosition.position.y, cur->data.listnerPosition.position.z ); @@ -343,8 +347,46 @@ void IVAS_RTP_LogPiData( case IVAS_PI_ISM_DIRECTIVITY: case IVAS_PI_PI_LATENCY: case IVAS_PI_R_ISM_ID: +#ifdef REVERSE_ISM_PI_DATA + { + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"id\": %d", cur->data.ismEditId.id ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; +#endif case IVAS_PI_R_ISM_GAIN: +#ifdef REVERSE_ISM_PI_DATA + { + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"gain\": %d", cur->data.ismEditGain.dB ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_R_ISM_ORIENTATION: + { + fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + fixedToFloat( cur->data.ismEditOrientation.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.ismEditOrientation.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.ismEditOrientation.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.ismEditOrientation.orientation.z_fx, Q15 ) ); + } + break; + case IVAS_PI_R_ISM_POSITION: + { + fprintf( f_piDataOut, "{\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + cur->data.ismEditPosition.position.x, cur->data.ismEditPosition.position.y, cur->data.ismEditPosition.position.z ); + } + break; +#endif case IVAS_PI_R_ISM_DIRECTION: +#ifdef REVERSE_ISM_PI_DATA + { + fprintf( f_piDataOut, "{\n\t\t\t\"azi\": %f,\n\t\t\t\"elev\": %f \n\t\t}", + cur->data.ismEditDirection.azimuth, cur->data.ismEditDirection.elevation ); + } + break; +#endif #endif /* RTP_S4_251135_CR26253_0016_REV1 */ case IVAS_PI_NO_DATA: { diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h index 032717d8f..8ee65bbe9 100644 --- a/lib_util/ivas_rtp_internal.h +++ b/lib_util/ivas_rtp_internal.h @@ -48,6 +48,9 @@ enum MASK_BITS MASK_6BIT = 0x3F, MASK_7BIT = 0x7F, MASK_8BIT = 0xFF, +#ifdef REVERSE_ISM_PI_DATA + MASK_9BIT = 0x1FF, +#endif }; diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index be2e9dd4d..6a55a64fb 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -32,6 +32,9 @@ #include "ivas_error_utils.h" #include "ivas_rtp_internal.h" +#ifdef REVERSE_ISM_PI_DATA +#include +#endif #ifdef IVAS_RTPDUMP @@ -427,6 +430,56 @@ static ivas_error unpackDynamicSuppression( const uint8_t *buffer, uint32_t numD return IVAS_ERR_OK; } +#ifdef REVERSE_ISM_PI_DATA +static ivas_error packPosition( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_POSITION *position = (const IVAS_PIDATA_POSITION *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_POSITION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in position PI data" ); + } + + if ( piData->piDataType != IVAS_PI_LISTENER_POSITION && piData->piDataType != IVAS_PI_R_ISM_POSITION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in position PI data" ); + } + + /* Position data is 6 bytes, header is 2 bytes */ + if ( maxDataBytes < 6 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack position PI data" ); + } + + buffer[nBytes++] = ( position->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 6; + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( position->position.x / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( position->position.y / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( position->position.z / MAX_PI_POSITION_METERS ) ); + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackPosition( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_POSITION *position = (IVAS_PIDATA_POSITION *) piData; + + /* Position data is 6 bytes */ + if ( numDataBytes != 6 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack position PI data" ); + } + + position->size = sizeof( IVAS_PIDATA_POSITION ); + position->position.x = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ) * MAX_PI_POSITION_METERS; + position->position.y = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ) * MAX_PI_POSITION_METERS; + position->position.z = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ) * MAX_PI_POSITION_METERS; + return IVAS_ERR_OK; +} +#else static ivas_error packListenerPosition( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { uint32_t nBytes = 0; @@ -476,6 +529,7 @@ static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDat listener->position.z = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ) * MAX_PI_POSITION_METERS; return IVAS_ERR_OK; } +#endif static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { @@ -630,6 +684,189 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat return IVAS_ERR_OK; } +#ifdef REVERSE_ISM_PI_DATA +static ivas_error packReverseISMID( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ISM_EDIT_ID *r_ism_id = (const IVAS_PIDATA_ISM_EDIT_ID *) piData; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_EDIT_ID ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in R_ISM_ID PI data" ); + } + + if ( piData->piDataType != IVAS_PI_R_ISM_ID ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in R_ISM_ID PI data" ); + } + + /* R_ISM_ID data is 1 byte, header is 2 bytes */ + if ( maxDataBytes < 1 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack R_ISM_NUM PI data" ); + } + + buffer[nBytes++] = ( r_ism_id->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = ( r_ism_id->id & MASK_8BIT ); + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackReverseISMID( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ISM_EDIT_ID *r_ism_id = (IVAS_PIDATA_ISM_EDIT_ID *) piData; + + /* ISM_ID data is 1 byte*/ + if ( numDataBytes > 1 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack R_ISM_ID PI data" ); + } + + r_ism_id->size = sizeof( IVAS_PIDATA_ISM_EDIT_ID ); + r_ism_id->piDataType = IVAS_PI_R_ISM_ID; + r_ism_id->id = *buffer; + + return IVAS_ERR_OK; +} + +static ivas_error packReverseISMGain( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, idx; + int16_t gain; + const IVAS_PIDATA_ISM_EDIT_GAIN *r_ism_gain = (const IVAS_PIDATA_ISM_EDIT_GAIN *) piData; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_EDIT_GAIN ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in R_ISM_GAIN PI data" ); + } + + if ( piData->piDataType != IVAS_PI_R_ISM_GAIN ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in R_ISM_GAIN PI data" ); + } + + /* R_ISM_GAIN data is 1 byte, header is 2 bytes */ + if ( maxDataBytes < 1 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack R_ISM_GAIN PI data" ); + } + + buffer[nBytes++] = ( r_ism_gain->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + gain = (int16_t) r_ism_gain->dB; + idx = min( -gain, 97 ); + if ( gain > 0 ) + { + idx += 97; + } + + buffer[nBytes++] = ( idx & MASK_7BIT ) << 1; + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackReverseISMGain( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t idx; + IVAS_PIDATA_ISM_EDIT_GAIN *r_ism_gain = (IVAS_PIDATA_ISM_EDIT_GAIN *) piData; + + /* R_ISM_GAIN data is 1 byte */ + if ( numDataBytes > 1 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack R_ISM_GAIN PI data" ); + } + + r_ism_gain->size = sizeof( IVAS_PIDATA_ISM_EDIT_GAIN ); + r_ism_gain->piDataType = IVAS_PI_R_ISM_GAIN; + + /* Unpack gain */ + idx = ( *buffer ) >> 1; + /* negative gains*/ + if ( idx < 97 ) + { + r_ism_gain->dB = -(int8_t) ( idx ); + } + /* Set to min for muting, to be interpreted as -Inf */ + else if ( idx == 97 ) + { + r_ism_gain->dB = -128; + } + /* postive gains */ + else if ( idx < 101 ) + { + r_ism_gain->dB = (int8_t) idx - 97; + } + else + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect index for R_ISM_GAIN PI data" ); + } + + return IVAS_ERR_OK; +} + +static ivas_error packReverseISMDirection( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ISM_EDIT_DIRECTION *r_ism_direction = (const IVAS_PIDATA_ISM_EDIT_DIRECTION *) piData; + uint16_t word; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_EDIT_DIRECTION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in R_ISM_DIRECTION PI data" ); + } + + if ( piData->piDataType != IVAS_PI_R_ISM_DIRECTION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_DIRECTION PI data" ); + } + + /* R_ISM_DIRECTION data is 2 bytes, header is 2 bytes */ + if ( maxDataBytes > 2 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack R_ISM_DIRECTION PI data" ); + } + + buffer[nBytes++] = ( r_ism_direction->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + + word = (uint16_t) ( min( (uint16_t) ceilf( r_ism_direction->azimuth * REVERSE_ISM_DIRECTION_AZIMUTH_STEP_INV ) + 256, 511 ) << 7 ); + word |= (uint16_t) ( min( (uint16_t) ceilf( r_ism_direction->elevation * REVERSE_ISM_DIRECTION_ELEVATION_STEP_INV ) + 64, 127 ) << 6 ); + + buffer[nBytes++] = ( word >> 8 ) & MASK_8BIT; + buffer[nBytes++] = word & MASK_8BIT; + + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackReverseISMDirection( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint16_t word; + IVAS_PIDATA_ISM_EDIT_DIRECTION *r_ism_direction = (IVAS_PIDATA_ISM_EDIT_DIRECTION *) piData; + + /* R_ISM_DIRECTION data is 2 bytes */ + if ( numDataBytes > 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack R_ISM_DIRECTION PI data" ); + } + + r_ism_direction->size = sizeof( IVAS_PIDATA_ISM_EDIT_DIRECTION ); + r_ism_direction->piDataType = IVAS_PI_R_ISM_DIRECTION; + + word = ( buffer[0] ) << 8; + word |= ( buffer[1] ); + + r_ism_direction->azimuth = (float) ( ( ( word >> 7 ) & MASK_9BIT ) + 1 ) * REVERSE_ISM_DIRECTION_AZIMUTH_STEP - 180.0f; + r_ism_direction->elevation = (float) ( word & MASK_7BIT ) * REVERSE_ISM_DIRECTION_ELEVATION_STEP - 90.0f; + + return IVAS_ERR_OK; +} +#endif + #endif /* RTP_S4_251135_CR26253_0016_REV1 */ @@ -665,7 +902,11 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ packOrientation, /* HEAD_ORIENTATION */ +#ifdef REVERSE_ISM_PI_DATA + packPosition, /* LISTENER_POSITION */ +#else packListenerPosition, /* LISTENER_POSITION */ +#endif packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ packAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ #else @@ -676,15 +917,26 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif packUnsupportedData, /* PI_LATENCY */ +#ifdef REVERSE_ISM_PI_DATA + packReverseISMID, /* R_ISM_ID */ + packReverseISMGain, /* R_ISM_GAIN */ +#else packUnsupportedData, /* R_ISM_ID */ packUnsupportedData, /* R_ISM_GAIN */ +#endif #ifdef RTP_S4_251135_CR26253_0016_REV1 packOrientation, /* R_ISM_ORIENTATION */ #else packUnsupportedData, /* R_ISM_ORIENTATION */ #endif + +#ifdef REVERSE_ISM_PI_DATA + packPosition, /* R_ISM_POSITION */ + packReverseISMDirection, /* R_ISM_DIRECTION */ +#else packUnsupportedData, /* R_ISM_POSITION */ packUnsupportedData, /* R_ISM_DIRECTION */ +#endif packUnsupportedData, /* RESERVED27 */ packUnsupportedData, /* RESERVED28 */ packUnsupportedData, /* RESERVED29 */ @@ -724,7 +976,11 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ unpackOrientation, /* HEAD_ORIENTATION */ +#ifdef REVERSE_ISM_PI_DATA + unpackPosition, /* LISTENER_POSITION */ +#else unpackListenerPosition, /* LISTENER_POSITION */ +#endif unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ #else @@ -735,15 +991,25 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif unpackUnsupportedData, /* PI_LATENCY */ +#ifdef REVERSE_ISM_PI_DATA + unpackReverseISMID, /* R_ISM_ID */ + unpackReverseISMGain, /* R_ISM_GAIN */ +#else unpackUnsupportedData, /* R_ISM_ID */ unpackUnsupportedData, /* R_ISM_GAIN */ +#endif #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackOrientation, /* R_ISM_ORIENTATION */ #else unpackUnsupportedData, /* R_ISM_ORIENTATION */ #endif +#ifdef REVERSE_ISM_PI_DATA + unpackPosition, /* R_ISM_POSITION */ + unpackReverseISMDirection, /* R_ISM_DIRECTION */ +#else unpackUnsupportedData, /* R_ISM_POSITION */ unpackUnsupportedData, /* R_ISM_DIRECTION */ +#endif unpackUnsupportedData, /* RESERVED27 */ unpackUnsupportedData, /* RESERVED28 */ unpackUnsupportedData, /* RESERVED29 */ diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index dc4c7f8ba..e9effd359 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -39,6 +39,13 @@ #define IVAS_PI_MAX_DATA_SIZE ( 32 + 2 ) /* max packed PI data bytes + pi header bytes */ +#ifdef REVERSE_ISM_PI_DATA +#define REVERSE_ISM_DIRECTION_AZIMUTH_STEP 0.703125f +#define REVERSE_ISM_DIRECTION_ELEVATION_STEP 1.417322835f +#define REVERSE_ISM_DIRECTION_AZIMUTH_STEP_INV 1.4222222222f +#define REVERSE_ISM_DIRECTION_ELEVATION_STEP_INV 0.7055555556f +#endif + /* IVAS PI Data Types */ typedef enum { @@ -320,6 +327,20 @@ typedef struct IVAS_FLVL flvl; /* audio focus level */ } IVAS_PIDATA_AUDIO_FOCUS; +#ifdef REVERSE_ISM_PI_DATA +/* Position data corresponding to any of the following pi data types :- + * - IVAS_PI_LISTENER_POSITION + * - IVAS_PI_R_ISM_POSITION + * + * piDataType is used to identify the correct pi data type contained here + */ +typedef struct +{ + size_t size; /* sizeof(IVAS_PIDATA_POSITION) */ + uint32_t piDataType; /* one of supported position data types */ + IVAS_COORDINATE position; /* Position data */ +} IVAS_PIDATA_POSITION; +#else /* Listener position */ typedef struct { @@ -327,6 +348,7 @@ typedef struct uint32_t piDataType; /* IVAS_PI_LISTENER_POSITION */ IVAS_COORDINATE position; /* Position of audio objects in ISM(s) */ } IVAS_PIDATA_LISTENER_POSITION; +#endif /* Dynamic Audio Suppression describes receiver’s preference with respect to the @@ -402,6 +424,7 @@ typedef struct IVAS_QUATERNION orientation; /* orientation editing request for received ISM */ } IVAS_PIDATA_ISM_EDIT_ORIENTATION; +#ifndef REVERSE_ISM_PI_DATA /* Editing request for ISM position */ typedef struct { @@ -409,6 +432,7 @@ typedef struct uint32_t piDataType; /* IVAS_PI_R_ISM_POSITION */ IVAS_COORDINATE position; /* Positional editing request for received ISM */ } IVAS_PIDATA_ISM_EDIT_POSITION; +#endif /* Editing request for ISM direction */ typedef struct @@ -448,14 +472,22 @@ typedef union IVAS_PIDATA_ORIENTATION playbackOrientation; IVAS_PIDATA_ORIENTATION headOrientation; +#ifdef REVERSE_ISM_PI_DATA + IVAS_PIDATA_POSITION listnerPosition; +#else IVAS_PIDATA_LISTENER_POSITION listnerPosition; +#endif IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppressionRequest; IVAS_PIDATA_AUDIO_FOCUS focusRequest; IVAS_PIDATA_REVERSE_PI_LATENCY piLatency; IVAS_PIDATA_ISM_EDIT_ID ismEditId; IVAS_PIDATA_ISM_EDIT_GAIN ismEditGain; IVAS_PIDATA_ISM_EDIT_ORIENTATION ismEditOrientation; +#ifdef REVERSE_ISM_PI_DATA + IVAS_PIDATA_POSITION ismEditPosition; +#else IVAS_PIDATA_ISM_EDIT_POSITION ismEditPosition; +#endif IVAS_PIDATA_ISM_EDIT_DIRECTION ismEditDirection; #endif /* RTP_S4_251135_CR26253_0016_REV1 */ IVAS_PIDATA_NO_DATA noPiData; -- GitLab From e3a98f0858a54e5d8d645a19e3cf1ba5513a97fc Mon Sep 17 00:00:00 2001 From: "@ragot" Date: Mon, 10 Nov 2025 13:36:48 +0100 Subject: [PATCH 20/34] adding support for format switching to encoder (porting from float main) --- CMakeLists.txt | 7 + Makefile | 9 +- Workspace_msvc/Workspace_msvc.sln | 11 + Workspace_msvc/encoder_fmtsw.vcxproj | 183 ++ apps/encoder_fmtsw.c | 2474 ++++++++++++++++++++++++++ 5 files changed, 2682 insertions(+), 2 deletions(-) create mode 100644 Workspace_msvc/encoder_fmtsw.vcxproj create mode 100644 apps/encoder_fmtsw.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e975df2b9..0347d98a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -201,6 +201,12 @@ if(WIN32) target_link_libraries(IVAS_cod Ws2_32) endif() +add_executable(IVAS_cod_fmtsw apps/encoder_fmtsw.c) +target_link_libraries(IVAS_cod_fmtsw lib_enc lib_util) +if(WIN32) + target_link_libraries(IVAS_cod_fmtsw Ws2_32) +endif() + add_executable(IVAS_dec apps/decoder.c) target_link_libraries(IVAS_dec lib_dec lib_util) if(WIN32) @@ -225,6 +231,7 @@ target_include_directories(ambi_converter PRIVATE lib_basop lib_util lib_com lib if(COPY_EXECUTABLES_FROM_BUILD_DIR) # Optionally copy executables to the same place where Make puts them (useful for tests that expect executables in specific places) add_custom_command(TARGET IVAS_cod POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") + add_custom_command(TARGET IVAS_cod_fmtsw POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") add_custom_command(TARGET IVAS_dec POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") add_custom_command(TARGET IVAS_rend POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") add_custom_command(TARGET ISAR_post_rend POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") diff --git a/Makefile b/Makefile index 4febdc988..8e0502434 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ SRC_DIRS = $(sort -u $(SRC_LIBBASOP) $(SRC_LIBCOM) $(SRC_LIBDEBUG) $(SRC_LIBDEC # Name of CLI binaries CLI_APIDEC ?= IVAS_dec CLI_APIENC ?= IVAS_cod +CLI_APIENC_FMTSW ?= IVAS_cod_fmtsw CLI_APIREND ?= IVAS_rend CLI_APIPOSTREND ?= ISAR_post_rend CLI_AMBICONVERT ?= ambi_converter @@ -169,6 +170,7 @@ OBJS_LIBUTIL = $(addprefix $(OBJDIR)/,$(SRCS_LIBUTIL:.c=.o)) OBJS_AMBICONVERT = $(OBJDIR)/ambi_convert.o OBJS_CLI_APIDEC = $(OBJDIR)/decoder.o OBJS_CLI_APIENC = $(OBJDIR)/encoder.o +OBJS_CLI_APIENC_FMTSW = $(OBJDIR)/encoder_fmtsw.o OBJS_CLI_APPREND = $(OBJDIR)/renderer.o OBJS_CLI_APPPOSTREND = $(OBJDIR)/isar_post_rend.o OBJS_CLI_AMBICONVERT = $(OBJDIR)/ambi_converter.o @@ -181,7 +183,7 @@ DEPS = $(addprefix $(OBJDIR)/,$(SRCS_LIBBASOP:.c=.P) $(SRCS_LIBCOM:.c=.P) $(SRCS .PHONY: all clean -all: $(CLI_APIENC) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) +all: $(CLI_APIENC) $(CLI_APIENC_FMTSW) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) $(OBJDIR): $(QUIET)mkdir -p $(OBJDIR) @@ -217,6 +219,9 @@ $(LIB_LIBUTIL): $(OBJS_LIBUTIL) $(OBJS_LIBBASOP) $(OBJS_LIBCOM) $(CLI_APIENC): $(OBJS_CLI_APIENC) $(LIB_LIBBASOP) $(LIB_LIBENC) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS) $(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APIENC) -L. -livasbasop -livasenc -livascom -livasutil -livasdebug $(LDLIBS) -o $(CLI_APIENC) +$(CLI_APIENC_FMTSW): $(OBJS_CLI_APIENC_FMTSW) $(LIB_LIBBASOP) $(LIB_LIBENC) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS) + $(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APIENC_FMTSW) -L. -livasbasop -livasenc -livascom -livasutil -livasdebug $(LDLIBS) -o $(CLI_APIENC_FMTSW) + $(CLI_APIDEC): $(OBJS_CLI_APIDEC) $(LIB_LIBBASOP) $(LIB_LIBDEC) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS) $(LIB_LIBISAR) $(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APIDEC) -L. -livasbasop -livasdec -livascom -livasutil -livasdebug -llc3plus $(LDLIBS) -o $(CLI_APIDEC) @@ -235,7 +240,7 @@ clean: $(QUIET)$(RM) $(OBJS_LIBENC) $(OBJS_LIBDEC) $(DEPS) $(QUIET)$(RM) $(DEPS:.P=.d) $(QUIET)test ! -d $(OBJDIR) || rm -rf $(OBJDIR) - $(QUIET)$(RM) $(CLI_APIENC) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) $(CLI_AMBICONVERT) $(LIB_LIBENC) $(LIB_LIBDEBUG) $(OBJS_LIBBASOP) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBUTIL) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS) + $(QUIET)$(RM) $(CLI_APIENC) $(CLI_APIENC_FMTSW) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) $(CLI_AMBICONVERT) $(LIB_LIBENC) $(LIB_LIBDEBUG) $(OBJS_LIBBASOP) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBUTIL) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS) $(OBJDIR)/%.o : %.c | $(OBJDIR) $(QUIET_CC)$(CC) $(CFLAGS) -c -MD -o $@ $< diff --git a/Workspace_msvc/Workspace_msvc.sln b/Workspace_msvc/Workspace_msvc.sln index abb9650fc..c9c1f0fde 100644 --- a/Workspace_msvc/Workspace_msvc.sln +++ b/Workspace_msvc/Workspace_msvc.sln @@ -24,6 +24,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "encoder", "encoder.vcxproj" {63747FE7-94BA-410C-8D7F-EB47555DD994} = {63747FE7-94BA-410C-8D7F-EB47555DD994} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "encoder_fmtsw", "encoder_fmtsw.vcxproj", "{CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}" + ProjectSection(ProjectDependencies) = postProject + {63747FE7-94BA-410C-8D7F-EB47555DD994} = {63747FE7-94BA-410C-8D7F-EB47555DD994} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "renderer", "renderer.vcxproj", "{12B4C8A5-1E06-4E30-B443-D1F916F52B47}" ProjectSection(ProjectDependencies) = postProject {63747FE7-94BA-410C-8D7F-EB47555DD994} = {63747FE7-94BA-410C-8D7F-EB47555DD994} @@ -106,6 +111,12 @@ Global {B3FC9DFC-7268-8660-7C0D-B60BAF02C554}.Release|Win32.ActiveCfg = Release|Win32 {B3FC9DFC-7268-8660-7C0D-B60BAF02C554}.Release|Win32.Build.0 = Release|Win32 {B3FC9DFC-7268-8660-7C0D-B60BAF02C554}.Release|x64.ActiveCfg = Release|Win32 + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}.Debug|Win32.ActiveCfg = Debug|Win32 + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}.Debug|Win32.Build.0 = Debug|Win32 + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}.Debug|x64.ActiveCfg = Debug|Win32 + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}.Release|Win32.ActiveCfg = Release|Win32 + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}.Release|Win32.Build.0 = Release|Win32 + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B}.Release|x64.ActiveCfg = Release|Win32 {12B4C8A5-1E06-4E30-B443-D1F916F52B47}.Debug|Win32.ActiveCfg = Debug|Win32 {12B4C8A5-1E06-4E30-B443-D1F916F52B47}.Debug|Win32.Build.0 = Debug|Win32 {12B4C8A5-1E06-4E30-B443-D1F916F52B47}.Debug|x64.ActiveCfg = Debug|Win32 diff --git a/Workspace_msvc/encoder_fmtsw.vcxproj b/Workspace_msvc/encoder_fmtsw.vcxproj new file mode 100644 index 000000000..7af057ae8 --- /dev/null +++ b/Workspace_msvc/encoder_fmtsw.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + encoder_fmtsw + {CA7EA15E-09A4-4196-A8EA-2A5F6F84862B} + encoder_fmtsw + 10.0.17763.0 + + + + Application + v141 + false + MultiByte + + + Application + v141 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27428.2015 + + + ..\ + .\Debug_$(ProjectName)\ + false + false + IVAS_cod_fmtsw + + + ..\ + .\Release_$(ProjectName)\ + false + false + IVAS_cod_fmtsw + + + + + + + $(IntDir)$(ProjectName).tlb + + + + Disabled + ..\lib_basop;..\lib_enc;..\lib_com;..\lib_util;..\lib_debug;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;$(Macros);%(PreprocessorDefinitions) + + EnableFastChecks + MultiThreadedDebug + false + + + $(IntDir)$(ProjectName).pdb + Level4 + true + OldStyle + Default + %(DisableSpecificWarnings) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c0c + + + + $(OutDir)$(TargetName).exe + true + + false + true + $(IntDir)$(ProjectName).pdb + Console + + false + + MachineX86 + + + + + + + + + + + $(IntDir)$(ProjectName).tlb + + + + MaxSpeed + AnySuitable + false + Neither + false + false + ..\lib_basop;..\lib_enc;..\lib_com;..\lib_util;..\lib_debug;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;$(Macros);%(PreprocessorDefinitions) + true + + Default + MultiThreaded + true + Precise + false + + + $(IntDir)$(ProjectName).pdb + Level4 + true + + Default + %(DisableSpecificWarnings) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c0c + + + $(OutDir)$(TargetName).exe + true + + false + $(IntDir)$(ProjectName).pdb + Console + false + + MachineX86 + + + + + + + + {63747fe7-94ba-410c-8d7f-eb47555dd994} + + + {824da4cf-06f0-45c9-929a-8792f0e19c3e} + false + + + {2fa8f384-0775-f3b7-f8c3-85209222fc70} + false + + + + + + + + + + + \ No newline at end of file diff --git a/apps/encoder_fmtsw.c b/apps/encoder_fmtsw.c new file mode 100644 index 000000000..143d8a1a6 --- /dev/null +++ b/apps/encoder_fmtsw.c @@ -0,0 +1,2474 @@ +/****************************************************************************************************** + + (C) 2022-2025 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 "options.h" +#ifdef DEBUGGING +#include "debug.h" +#endif +#include "stl.h" +#include "lib_enc.h" +#include "cmdl_tools.h" +#include "audio_file_reader.h" +#include "bitstream_writer.h" +#include "ism_file_reader.h" +#include "jbm_file_reader.h" +#include "masa_file_reader.h" +#include "wmc_auto.h" +#ifdef IVAS_RTPDUMP +#include "rotation_file_reader.h" +#include "ivas_rtp_file.h" +#endif + +#ifdef DEBUG_FORCE_DIR +/* Windows does not define the S_ISREG and S_ISDIR macros in stat.h, so we do. + We have to define _CRT_INTERNAL_NONSTDC_NAMES 1 before #including sys/stat.h + in order for Microsoft's stat.h to define names like S_IFMT, S_IFREG, and S_IFDIR, + rather than just defining _S_IFMT, _S_IFREG, and _S_IFDIR as it normally does. */ +#include +#if !defined( S_ISREG ) && defined( S_IFMT ) && defined( S_IFREG ) +#define S_ISREG( m ) ( ( (m) &S_IFMT ) == S_IFREG ) +#endif +#if !defined( S_ISDIR ) && defined( S_IFMT ) && defined( S_IFDIR ) +#define S_ISDIR( m ) ( ( (m) &S_IFMT ) == S_IFDIR ) +#endif +#endif + +#ifdef FIXED_RTP_SEQUENCE_NUM +#define RANDOM_INITSEED_ENC ( 0xFEEDDEAF ) +#endif + +#define WMC_TOOL_SKIP + +/*------------------------------------------------------------------------------------------* + * Local constants, enums + *------------------------------------------------------------------------------------------*/ + +#define MAX_ARGV 20 /* maximum number of command line arguments that can be \ + in one line of the format switching file */ + +#if !defined( DEBUGGING ) && !defined( WMOPS ) +static +#endif + int32_t frame = 0; /* Counter of frames */ + +#define DEFAULT_FIXED_SID_RATE 8 /* DTX SID rate */ + +/* Additional config info for each input format */ +typedef union _EncInputFormatConfig +{ + /* MONO details */ + bool stereoToMonoDownmix; + +#ifdef DEBUGGING + /* STEREO details */ + IVAS_ENC_STEREO_MODE stereoMode; +#endif + + /* ISM details */ + struct EncIsmConfig + { + int16_t numObjects; + const char *metadataFiles[IVAS_MAX_NUM_OBJECTS]; + } ism; + + /* SBA details */ + struct EncSbaConfig + { + IVAS_ENC_SBA_ORDER order; + bool isPlanar; + } sba; + + /* MASA details */ + IVAS_ENC_MASA_VARIANT masaVariant; + + /* MC details */ + IVAS_ENC_MC_LAYOUT mcLayout; + + struct EncMasaIsmConfig + { + int16_t numObjects; + const char *metadataFiles[IVAS_MAX_NUM_OBJECTS]; + IVAS_ENC_MASA_VARIANT masaVariant; + } masa_ism; + + struct EncSbaIsmConfig + { + int16_t numObjects; + const char *metadataFiles[IVAS_MAX_NUM_OBJECTS]; + IVAS_ENC_SBA_ORDER order; + bool isPlanar; + } sba_ism; + +} EncInputFormatConfig; + + +/*------------------------------------------------------------------------------------------* + * Local structure for storing cmdln arguments + *------------------------------------------------------------------------------------------*/ + +typedef struct +{ + char *inputWavFilename; + char *outputBitstreamFilename; + int32_t inputFs; + IVAS_ENC_INPUT_FORMAT inputFormat; + bool is_binaural; + EncInputFormatConfig inputFormatConfig; + bool max_bwidth_user; + IVAS_ENC_BANDWIDTH maxBandwidth; + const char *bandwithProfileFile; + IVAS_ENC_DTX_CONFIG dtxConfig; + int32_t initBitrate; + const char *bitrateProfileFile; + bool quietModeEnabled; + bool delayCompensationEnabled; + const char *masaMetadataFile; + IVAS_ENC_CHANNEL_AWARE_CONFIG caConfig; + const char *ca_config_file; + bool mimeOutput; + IVAS_ENC_COMPLEXITY_LEVEL complexityLevel; +#ifdef DEBUGGING + IVAS_ENC_FORCED_MODE forcedMode; + const char *forcedModeFile; +#ifdef DEBUG_FORCE_DIR + const char *forcedModeDir; +#endif +#endif + bool pca; + bool ism_extended_metadata; +#ifdef IVAS_RTPDUMP + bool rtpdumpOutput; + uint32_t numFramesPerPacket; + char *sceneOrientationTrajFileName; + char *deviceOrientationTrajFileName; +#endif + +} EncArguments; + + +/*------------------------------------------------------------------------------------------* + * Local functions prototypes + *------------------------------------------------------------------------------------------*/ + +static bool parseCmdlIVAS_enc( int16_t argc, char *argv[], EncArguments *arg ); +static void usage_enc( void ); +static bool readBandwidth( FILE *file, IVAS_ENC_BANDWIDTH *bandwidth, int32_t *bandwidthFrameCounter ); +static bool readBitrate( FILE *file, int32_t *bitrate ); +#ifdef DEBUGGING +static ivas_error readForcedMode( FILE *file, IVAS_ENC_FORCED_MODE *forcedMode, int32_t *forceFrameCounter ); +static IVAS_ENC_FORCED_MODE parseForcedMode( char *forcedModeChar ); +#endif +static void str2arg( char *str, int *argc_local, char *argv_local[] ); +#ifdef IVAS_RTPDUMP +static int encoder_main( int argc, char *argv[], IVAS_RTP *ivasRtp, int init_RtpWriter ); +#else +static int encoder_main( int argc, char *argv[] ); +#endif + +/*------------------------------------------------------------------------------------------* + * main() + * + * Main IVAS encoder function for command-line interface + * supporting format switching +*------------------------------------------------------------------------------------------*/ + +int main( + int argc, + char *argv[] ) +{ + FILE *FmtSWFile = NULL; + char line[2048]; + int argc_local = 0; + char *argv_local[MAX_ARGV] = { 0 }; +#ifdef IVAS_RTPDUMP + IVAS_RTP ivasRtp = { 0 }; + char prev_outputBitstreamFilename[2048] = { 0 }; + int rtp_term = 0; +#endif + + IVAS_ENC_PrintDisclaimer(); + + if ( argc != 2 ) + { + fprintf( stdout, "Usage: IVAS_cod_fmtsw.exe format_switching_file\n\n" ); + fprintf( stdout, "where format_switching_file is a text file containg a valid encoder command line in each line\n\n" ); + exit( 0 ); + } + fprintf( stdout, "Input format switching file: %s\n", argv[1] ); + + if ( ( FmtSWFile = fopen( argv[1], "r" ) ) == NULL ) + { + fprintf( stdout, "error: cannot open format switching file %s\n", argv[1] ); + exit( 0 ); + } + + while ( fgets( line, sizeof( line ), FmtSWFile ) ) + { + /* remove trimming newline */ + line[strcspn( line, "\r\n" )] = 0; + printf( "Processing format switching commandline: %s\n", line ); + str2arg( line, &argc_local, argv_local ); +#ifdef IVAS_RTPDUMP + if ( strcmp( argv_local[argc_local - 1], (char *) prev_outputBitstreamFilename ) == 0 ) + { + /* append to last Rtp file */ + encoder_main( argc_local, argv_local, &ivasRtp, 0 ); + } + else + { + if ( rtp_term == 1 ) + { + IVAS_RTP_Term( &ivasRtp ); + } + /* write in separate Rtp file */ + encoder_main( argc_local, argv_local, &ivasRtp, 1 ); + rtp_term = 1; + } + strcpy( (char *) prev_outputBitstreamFilename, argv_local[argc_local - 1] ); +#else + encoder_main( argc_local, argv_local ); +#endif + } +#ifdef IVAS_RTPDUMP + IVAS_RTP_Term( &ivasRtp ); +#endif + fclose( FmtSWFile ); + exit( 0 ); +} + + +/*-------------------------------------------------------------------* + * Local functions + *-------------------------------------------------------------------*/ + +void str2arg( + char *str, /* input string */ + int *argc_local, /* number of argument */ + char *argv_local[] /* array of arguments */ +) +{ + int i = 0; + char *token = strtok( str, " " ); + while ( token && ( i < MAX_ARGV - 1 ) ) + { + argv_local[i++] = token; + token = strtok( 0, " " ); + } + argv_local[i] = 0; + *argc_local = i; + return; +} + +int encoder_main( + int argc, +#ifdef IVAS_RTPDUMP + char *argv[], + IVAS_RTP *ivasRtp, + int init_RtpWriter ) +#else + char *argv[] ) +#endif +{ + bool mainFailed = true; /* Assume main failed until cleanup is reached without errors */ + EncArguments arg; + int16_t i; + ivas_error error = IVAS_ERR_UNKNOWN; + + /* Any handles that require cleanup must be declared here and initialized to NULL */ + IVAS_ENC_HANDLE hIvasEnc = NULL; + BS_WRITER_HANDLE hBsWriter = NULL; + AudioFileReader *audioReader = NULL; + FILE *f_bitrateProfile = NULL; + FILE *f_bwProfile = NULL; + JbmFileReader *jbmReader = NULL; + MasaFileReader *masaReader = NULL; + IsmFileReader *ismReaders[IVAS_MAX_NUM_OBJECTS] = { NULL, NULL, NULL, NULL }; + int16_t *pcmBuf = NULL; +#ifdef IVAS_RTPDUMP + RotFileReader *sceneOrientationFileReader = NULL; + RotFileReader *deviceOrientationFileReader = NULL; +#endif +#ifdef DEBUGGING + FILE *f_forcedModeProfile = NULL; +#endif + +#ifdef WMOPS + reset_wmops(); + reset_mem( USE_BYTES ); +#endif + +#ifdef IVAS_RTPDUMP + uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; + /* IVAS_RTP ivasRtp = { 0 }; */ +#endif + +#ifdef FIXED_RTP_SEQUENCE_NUM + /* Ideally ssrc is negotiated via SDP and sequence number is radomized but we + use fixed seed for random num generator for regression based tests. Any realtime + application should implement this initialization seperately */ + srand( RANDOM_INITSEED_ENC ); + uint32_t ssrc = ( (uint32_t) rand() & 0x0000FFFF ) | ( (uint32_t) rand() << 16 ); + uint16_t seqNumInitVal = (uint16_t) ( rand() & 0xFFFF ); +#endif + + /*------------------------------------------------------------------------------------------* + * Parse command-line arguments + *------------------------------------------------------------------------------------------*/ + + if ( !parseCmdlIVAS_enc( (int16_t) argc, argv, &arg ) ) + { + /* Error printout done internally in parseCmdlIVAS_enc() */ + goto cleanup; + } + + /*------------------------------------------------------------------------------------------* + * Open and initialize IVAS encoder + *------------------------------------------------------------------------------------------*/ + if ( ( error = IVAS_ENC_Open_fx( &hIvasEnc ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Opening IVAS encoder failed: %s\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + /*------------------------------------------------------------------------------------------* + * Open output bitstream file + *------------------------------------------------------------------------------------------*/ + + const BS_WRITER_FORMAT bsWriterFormat = arg.mimeOutput ? BS_WRITER_FORMAT_MIME : BS_WRITER_FORMAT_G192; + +#ifdef IVAS_RTPDUMP + if ( !arg.rtpdumpOutput && BS_Writer_Open_filename( &hBsWriter, arg.outputBitstreamFilename, bsWriterFormat ) != IVAS_ERR_OK ) +#else + if ( BS_Writer_Open_filename( &hBsWriter, arg.outputBitstreamFilename, bsWriterFormat ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nCan't open %s\n\n", arg.outputBitstreamFilename ); + goto cleanup; + } + + /*------------------------------------------------------------------------------------------* + * Print out file names + *------------------------------------------------------------------------------------------*/ + + if ( arg.inputFormat == IVAS_ENC_INPUT_ISM || arg.inputFormat == IVAS_ENC_INPUT_SBA_ISM ) + { + for ( i = 0; i < arg.inputFormatConfig.ism.numObjects; i++ ) + { + fprintf( stdout, "Object %d input metadata: %s\n", i + 1, arg.inputFormatConfig.ism.metadataFiles[i] ); + } + } + + if ( arg.masaMetadataFile != NULL ) + { + fprintf( stdout, "MASA inp. metadata file: %s\n", arg.masaMetadataFile ); + } + + fprintf( stdout, "Input audio file: %s\n", arg.inputWavFilename ); + fprintf( stdout, "Output bitstream file: %s\n\n", arg.outputBitstreamFilename ); + + /*------------------------------------------------------------------------------------------* + * Open auxiliary input files + *------------------------------------------------------------------------------------------*/ + + int32_t totalBitrate = arg.initBitrate; + + if ( arg.bitrateProfileFile ) + { + if ( ( f_bitrateProfile = fopen( arg.bitrateProfileFile, "rb" ) ) == NULL ) + { + fprintf( stderr, "Error: bitrate profile file %s could not be opened\n\n", arg.bitrateProfileFile ); + usage_enc(); + goto cleanup; + } + + if ( !readBitrate( f_bitrateProfile, &totalBitrate ) ) + { + fprintf( stderr, "Error: bitrate profile file %s could not be read\n\n", arg.bitrateProfileFile ); + goto cleanup; + } + rewind( f_bitrateProfile ); + + fprintf( stdout, "Bitrate switching file: %s\n", arg.bitrateProfileFile ); + } + + int32_t bandwidthFrameCounter = 0; + IVAS_ENC_BANDWIDTH bandwidth = arg.maxBandwidth; + + if ( arg.bandwithProfileFile ) + { + if ( ( f_bwProfile = fopen( arg.bandwithProfileFile, "rb" ) ) == NULL ) + { + fprintf( stderr, "Error: incorrect bandwidth specification or the bandwidth profile file could not be opened: %s\n\n", arg.bandwithProfileFile ); + usage_enc(); + goto cleanup; + } + fprintf( stdout, "Bandwidth switching file: %s\n", arg.bandwithProfileFile ); + + if ( !readBandwidth( f_bwProfile, &bandwidth, &bandwidthFrameCounter ) ) + { + fprintf( stderr, "Error: bandwidth switching file %s could not be read\n\n", arg.bandwithProfileFile ); + goto cleanup; + } + rewind( f_bwProfile ); + bandwidthFrameCounter = 0; + } + else + { + if ( bandwidth == IVAS_ENC_BANDWIDTH_NB && arg.inputFormat != IVAS_ENC_INPUT_MONO ) + { + fprintf( stdout, "\nNB coding not supported in IVAS. Switching to WB.\n\n" ); + } + else + { + switch ( bandwidth ) + { + case IVAS_ENC_BANDWIDTH_UNDEFINED: + break; + case IVAS_ENC_BANDWIDTH_NB: + fprintf( stdout, "Max. encoded bandwidth: NB\n" ); + break; + case IVAS_ENC_BANDWIDTH_WB: + fprintf( stdout, "Max. encoded bandwidth: WB\n" ); + break; + case IVAS_ENC_BANDWIDTH_SWB: + fprintf( stdout, "Max. encoded bandwidth: SWB\n" ); + break; + case IVAS_ENC_BANDWIDTH_FB: + fprintf( stdout, "Max. encoded bandwidth: FB\n" ); + break; + default: + fprintf( stderr, "Error: Invalid bandwidth value\n" ); + usage_enc(); + goto cleanup; + } + } + } + + /*------------------------------------------------------------------------------------------* + * Handle Channel-aware mode + *------------------------------------------------------------------------------------------*/ + + IVAS_ENC_CHANNEL_AWARE_CONFIG caConfig = arg.caConfig; + + if ( arg.ca_config_file ) + { + if ( ( jbmReader = JbmFileReader_open( arg.ca_config_file ) ) == NULL ) + { + fprintf( stderr, "\nError: Channel aware configuration file could not be opened: %s\n\n", arg.ca_config_file ); + usage_enc(); + goto cleanup; + } + + fprintf( stdout, "Channel-aware mode: ON, config file: %s \n", arg.ca_config_file ); + } + else if ( caConfig.channelAwareModeEnabled ) + { + fprintf( stdout, "Channel-aware mode: ON, FEC indicator : %s FEC offset: %d \n\n", ( caConfig.fec_indicator == IVAS_ENC_FEC_LO ) ? "LO" : "HI", caConfig.fec_offset ); + } + + if ( arg.inputFormat != IVAS_ENC_INPUT_MONO && ( caConfig.channelAwareModeEnabled || arg.ca_config_file ) ) + { + fprintf( stderr, "Channel-aware mode is not supported in IVAS.\n\n" ); + usage_enc(); + goto cleanup; + } + +#ifdef SUPPORT_FORCE_TCX10_TCX20 +#ifdef DEBUGGING + if ( arg.forcedMode == IVAS_ENC_FORCE_TCX10 && totalBitrate < 48000 ) + { + fprintf( stderr, "Warning: Enforcing the TCX10 mode is only supported for bitrates higher or equal than 48 kbps!\n\n" ); + } +#endif +#endif + + /*------------------------------------------------------------------------------------------* + * Configure and initialize (allocate memory for static variables) the encoder + *------------------------------------------------------------------------------------------*/ + + switch ( arg.inputFormat ) + { + case IVAS_ENC_INPUT_MONO: + if ( ( error = IVAS_ENC_ConfigureForMono( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, caConfig, arg.inputFormatConfig.stereoToMonoDownmix, arg.is_binaural ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForMono failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + break; + case IVAS_ENC_INPUT_STEREO: +#ifdef DEBUGGING + if ( ( error = IVAS_ENC_ConfigureForStereo( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, arg.is_binaural, arg.inputFormatConfig.stereoMode ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_ENC_ConfigureForStereo( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, arg.is_binaural ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForStereo failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + break; + case IVAS_ENC_INPUT_ISM: + if ( ( error = IVAS_ENC_ConfigureForObjects( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, arg.inputFormatConfig.ism.numObjects, arg.ism_extended_metadata ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForObjects failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + break; + case IVAS_ENC_INPUT_SBA: + if ( ( error = IVAS_ENC_ConfigureForAmbisonics( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, arg.inputFormatConfig.sba.order, arg.inputFormatConfig.sba.isPlanar, + arg.pca ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForAmbisonics failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + break; + case IVAS_ENC_INPUT_MASA: + if ( ( error = IVAS_ENC_ConfigureForMasa( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, arg.inputFormatConfig.masaVariant ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForMasa failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + break; + case IVAS_ENC_INPUT_MC: + if ( ( error = IVAS_ENC_ConfigureForMultichannel( hIvasEnc, arg.inputFs, totalBitrate, arg.max_bwidth_user, bandwidth, arg.dtxConfig, arg.inputFormatConfig.mcLayout ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForMultichannel failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + break; + case IVAS_ENC_INPUT_SBA_ISM: + if ( ( error = IVAS_ENC_ConfigureForSBAObjects( hIvasEnc, arg.inputFs, totalBitrate, bandwidth, arg.dtxConfig, arg.inputFormatConfig.sba_ism.numObjects, arg.inputFormatConfig.sba_ism.order, arg.inputFormatConfig.sba_ism.isPlanar, arg.pca ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForSBAObjects failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + exit( -1 ); + } + break; + case IVAS_ENC_INPUT_MASA_ISM: + if ( ( error = IVAS_ENC_ConfigureForMASAObjects( hIvasEnc, arg.inputFs, totalBitrate, bandwidth, arg.dtxConfig, arg.inputFormatConfig.masa_ism.numObjects, arg.inputFormatConfig.masa_ism.masaVariant ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_ConfigureForMASAObjects failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + exit( -1 ); + } + break; + default: + fprintf( stderr, "\nInvalid input type\n\n" ); + goto cleanup; + } + + if ( ( error = IVAS_ENC_PrintConfig( hIvasEnc, caConfig.channelAwareModeEnabled ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\n IVAS_ENC_PrintConfig failed %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + /*------------------------------------------------------------------------------------------* + * Open input audio file + *------------------------------------------------------------------------------------------*/ + + if ( AudioFileReader_open( &audioReader, arg.inputWavFilename ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nCan't open %s\n\n", arg.inputWavFilename ); + goto cleanup; + } + + /* Validate input sampling rate */ + int32_t inFileSampleRate = 0; + error = AudioFileReader_getSamplingRate( audioReader, &inFileSampleRate ); + switch ( error ) + { + case IVAS_ERR_OK: + if ( inFileSampleRate != arg.inputFs ) + { + fprintf( stderr, "\nSampling rate mismatch: %d Hz requested, but %d Hz found in file %s\n\n", arg.inputFs, inFileSampleRate, arg.inputWavFilename ); + goto cleanup; + } + break; + case IVAS_ERR_SAMPLING_RATE_UNKNOWN: + /* IVAS_ERR_SAMPLING_RATE_UNKNOWN will be returned for raw PCM files. + * Nothing to check here */ + break; + default: + fprintf( stderr, "\nError: %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } + + /* Validate number of channels */ + int16_t encInNumChannels = 0; + if ( ( error = IVAS_ENC_GetNumInChannels( hIvasEnc, &encInNumChannels ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } + + int16_t inFileNumChannels = 0; + error = AudioFileReader_getNumChannels( audioReader, &inFileNumChannels ); + switch ( error ) + { + case IVAS_ERR_OK: + if ( inFileNumChannels != encInNumChannels ) + { + fprintf( stderr, "\nNumber of input audio channels mismatch: %d accepted by encoder, but %d found in file %s\n\n", encInNumChannels, inFileNumChannels, arg.inputWavFilename ); + goto cleanup; + } + break; + case IVAS_ERR_NUM_CHANNELS_UNKNOWN: + /* IVAS_ERR_NUM_CHANNELS_UNKNOWN will be returned for raw PCM files. + * Nothing to check here */ + break; + default: + fprintf( stderr, "\nError: %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } + + /*------------------------------------------------------------------------------------------* + * Open input metadata files + *------------------------------------------------------------------------------------------*/ + + if ( arg.masaMetadataFile ) + { + if ( ( masaReader = MasaFileReader_open( arg.masaMetadataFile ) ) == NULL ) + { + fprintf( stderr, "\nError: MASA input metadata file %s could not be opened\n\n", arg.masaMetadataFile ); + usage_enc(); + goto cleanup; + } + } + + const int16_t numIsmInputs = ( arg.inputFormat == IVAS_ENC_INPUT_ISM || arg.inputFormat == IVAS_ENC_INPUT_MASA_ISM || arg.inputFormat == IVAS_ENC_INPUT_SBA_ISM ) ? arg.inputFormatConfig.ism.numObjects : 0; + + for ( i = 0; i < numIsmInputs; ++i ) + { + if ( arg.inputFormatConfig.ism.metadataFiles[i] != NULL ) + { + if ( ( ismReaders[i] = IsmFileReader_open( arg.inputFormatConfig.ism.metadataFiles[i] ) ) == NULL ) + { + fprintf( stderr, "\nError: ISM input metadata file %s could not be opened\n\n", arg.inputFormatConfig.ism.metadataFiles[i] ); + usage_enc(); + goto cleanup; + } + } + } + +#ifdef DEBUGGING + IVAS_ENC_FORCED_MODE forcedMode = arg.forcedMode; + int32_t force_profile_cnt = 0; + + if ( arg.forcedModeFile ) + { + if ( ( f_forcedModeProfile = fopen( arg.forcedModeFile, "rb" ) ) == NULL ) + { + fprintf( stderr, "\nError: Incorrect mode specification or the profile file could not be opened: %s\n\n", arg.forcedModeFile ); + usage_enc(); + goto cleanup; + } + } +#endif + + /*------------------------------------------------------------------------------------------* + * Allocate input data buffer + *------------------------------------------------------------------------------------------*/ + + int16_t pcmBufSize; + if ( ( error = IVAS_ENC_GetInputBufferSize( hIvasEnc, &pcmBufSize ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nGetInputBufferSize failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + pcmBuf = malloc( pcmBufSize * sizeof( int16_t ) ); + + /*------------------------------------------------------------------------------------------* + * Compensate for encoder delay (bitstream aligned with input signal) + *------------------------------------------------------------------------------------------*/ + + int16_t encDelayInSamples; + if ( ( error = IVAS_ENC_GetDelay( hIvasEnc, &encDelayInSamples ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nGetDelay failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( arg.delayCompensationEnabled && encDelayInSamples ) + { + /* read samples and throw them away */ + int16_t numSamplesRead = 0; + if ( ( error = AudioFileReader_read( audioReader, pcmBuf, encDelayInSamples, &numSamplesRead ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError reading from file %s\n%s\n", arg.inputWavFilename, IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + +#ifdef IVAS_RTPDUMP + /*------------------------------------------------------------------------------------------* + * RTPDump + *------------------------------------------------------------------------------------------*/ + + if ( arg.rtpdumpOutput && init_RtpWriter ) + { +#ifdef FIXED_RTP_SEQUENCE_NUM + if ( ( error = IVAS_RTP_WRITER_Init( ivasRtp, arg.outputBitstreamFilename, arg.numFramesPerPacket, ssrc, seqNumInitVal ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_RTP_WRITER_Init( ivasRtp, arg.outputBitstreamFilename, arg.numFramesPerPacket ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError: Can't open output bitstream file for RTP output %s \n\n", arg.outputBitstreamFilename ); + goto cleanup; + } + } + + /*------------------------------------------------------------------------------------------* + * Open scene orientation file + *------------------------------------------------------------------------------------------*/ + + if ( arg.sceneOrientationTrajFileName != NULL ) + { + if ( ( error = RotationFileReader_open( arg.sceneOrientationTrajFileName, &sceneOrientationFileReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open scene orientation file %s \n\n", arg.sceneOrientationTrajFileName ); + goto cleanup; + } + } + + /*------------------------------------------------------------------------------------------* + * Open device orientation file + *------------------------------------------------------------------------------------------*/ + + if ( arg.deviceOrientationTrajFileName != NULL ) + { + if ( ( error = RotationFileReader_open( arg.deviceOrientationTrajFileName, &deviceOrientationFileReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open device orientation file %s \n\n", arg.deviceOrientationTrajFileName ); + goto cleanup; + } + } +#endif + + int16_t numSamplesRead = 0; + uint16_t bitStream[IVAS_MAX_BITS_PER_FRAME]; + uint16_t numBits = 0; + + if ( !arg.quietModeEnabled ) + { + fprintf( stdout, "\n------ Running the encoder ------\n\n" ); + fprintf( stdout, "Frames processed: " ); + } + else + { + fprintf( stdout, "\n\n-- Start the encoder (quiet mode) --\n\n" ); + } + +#ifdef WMOPS + reset_stack(); + reset_wmops(); +#endif + + /*------------------------------------------------------------------------------------------* + * Loop for every frame of input data + * - Read the input data + * - Process switching files + * - Read input metadata + * - Run the encoder + * - Write the parameters into output bitstream file + *------------------------------------------------------------------------------------------*/ + + while ( 1 ) + { + /* Read the input data */ + if ( ( error = AudioFileReader_read( audioReader, pcmBuf, pcmBufSize, &numSamplesRead ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError reading from file %s\n%s\n", arg.inputWavFilename, IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( numSamplesRead == 0 ) + { + /* end of input data */ + break; + } + + /* Zero-pad if not enough samples were read (expected in last frame) */ + if ( numSamplesRead < pcmBufSize ) + { + for ( i = numSamplesRead; i < pcmBufSize; ++i ) + { + pcmBuf[i] = 0; + } + } + + /* Process switching files */ + if ( f_bitrateProfile ) + { + if ( !readBitrate( f_bitrateProfile, &totalBitrate ) ) + { + fprintf( stderr, "Error: bitrate profile file %s could not be read\n\n", arg.bitrateProfileFile ); + goto cleanup; + } + + if ( ( error = IVAS_ENC_SetBitrate( hIvasEnc, totalBitrate ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_SetBitrate failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + if ( f_bwProfile ) + { + if ( !readBandwidth( f_bwProfile, &bandwidth, &bandwidthFrameCounter ) ) + { + fprintf( stderr, "Error: bandwidth switching file %s could not be read\n\n", arg.bandwithProfileFile ); + goto cleanup; + } + + if ( ( error = IVAS_ENC_SetBandwidth( hIvasEnc, bandwidth ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_SetBandwidth failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + if ( jbmReader ) + { + if ( ( error = JbmFileReader_readCAconfig( jbmReader, &caConfig ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError (%s) while reading Channel-Aware Config. from: %s\n\n", IVAS_ENC_GetErrorMessage( error ), JbmFileReader_getFilePath( jbmReader ) ); + goto cleanup; + } + + if ( ( error = IVAS_ENC_SetChannelAwareConfig( hIvasEnc, caConfig ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "IVAS_ENC_SetChannelAwareConfig failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + +#ifdef DEBUGGING + if ( f_forcedModeProfile ) + { + if ( ( error = readForcedMode( f_forcedModeProfile, &forcedMode, &force_profile_cnt ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError reading from file: %s\n%s\n", arg.forcedModeFile, IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + /* Force mode not set when configuring, set in first frame even if not reading from file */ + if ( f_forcedModeProfile || frame == 0 ) + { + if ( ( error = IVAS_ENC_SetForcedMode( hIvasEnc, forcedMode +#ifdef DEBUG_FORCE_DIR + , + arg.forcedModeDir +#endif + ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_ENC_SetForcedMode failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } +#endif + + /* Read ISM input metadata */ + for ( i = 0; i < numIsmInputs; ++i ) + { + if ( ismReaders[i] == NULL ) + { + continue; + } + + IVAS_ISM_METADATA ismMetadata; + if ( ( error = IsmFileReader_readNextFrame( ismReaders[i], &ismMetadata ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError (%s) while reading ism metadata from: %s\n\n", IVAS_ENC_GetErrorMessage( error ), IsmFileReader_getFilePath( ismReaders[i] ) ); + goto cleanup; + } + + if ( ( error = IVAS_ENC_FeedObjectMetadata( hIvasEnc, i, ismMetadata ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nfeed_ISM_metadata failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + /* Read MASA input metadata */ + if ( masaReader ) + { + if ( ( error = MasaFileReader_readNextFrame( masaReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError (%s) while reading masa metadata from: %s\n\n", IVAS_ENC_GetErrorMessage( error ), arg.masaMetadataFile ); + goto cleanup; + } + IVAS_MASA_METADATA_HANDLE hMetadata = MasaFileReader_getMetadataHandle( masaReader ); + + if ( ( error = IVAS_ENC_FeedMasaMetadata( hIvasEnc, hMetadata ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nfeed_MASA_frame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + /* *** Encode one frame *** */ +#ifdef IVAS_RTPDUMP + if ( ivasRtp->hPack ) + { + bool isMono = ( arg.inputFormat == IVAS_ENC_INPUT_MONO ); + bool forcePacket = ( numSamplesRead < pcmBufSize ); /* If EoF force Packet generation */ + + ivasRtp->nWrittenPiData = 0; + + /* scene orientation */ + if ( sceneOrientationFileReader ) + { + PIDATA_TS *piDataTs = &ivasRtp->piData[ivasRtp->nWrittenPiData++]; + IVAS_PIDATA_ORIENTATION *scene = &piDataTs->data.scene; + + memset( piDataTs, 0, sizeof( PIDATA_TS ) ); + scene->size = sizeof( IVAS_PIDATA_ORIENTATION ); + scene->piDataType = IVAS_PI_SCENE_ORIENTATION; + + if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &scene->orientation, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading scene orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( sceneOrientationFileReader ) ); + goto cleanup; + } + } + + /* device orientation */ + if ( deviceOrientationFileReader ) + { + PIDATA_TS *piDataTs = &ivasRtp->piData[ivasRtp->nWrittenPiData++]; + IVAS_PIDATA_ORIENTATION *device = &piDataTs->data.deviceUnCompensated; + + memset( piDataTs, 0, sizeof( PIDATA_TS ) ); + device->size = sizeof( IVAS_PIDATA_ORIENTATION ); + device->piDataType = IVAS_PI_DEVICE_ORIENTATION_COMPENSATED; + + if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &device->orientation, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading device orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( deviceOrientationFileReader ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_ENC_EncodeFrameToCompact( hIvasEnc, pcmBuf, pcmBufSize, au, &numBits ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( ( error = IVAS_RTP_WriteNextFrame( ivasRtp, au, NULL, numBits, isMono, forcePacket ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_RTP_WriteNextFrame( ivasRtp, au, numBits, isMono, forcePacket ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError %s while pushing audio frame to RTP pack\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } + else + { +#endif + if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, pcmBuf, pcmBufSize, bitStream, &numBits ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + /* write bitstream */ + if ( ( error = BS_Writer_WriteFrame_short( hBsWriter, bitStream, numBits, totalBitrate ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nBS_Writer_WriteFrame_short failed, error code %d\n\n", error ); + goto cleanup; + } +#ifdef IVAS_RTPDUMP + } +#endif + + frame++; + if ( !arg.quietModeEnabled ) + { + fprintf( stdout, "%-8d\b\b\b\b\b\b\b\b", frame ); + } + +#ifdef WMOPS + update_mem(); + update_wmops(); +#endif + } + + if ( arg.quietModeEnabled ) + { + fprintf( stdout, "Encoding finished\n" ); + } + else + { + fprintf( stdout, "\n\nEncoding of %d frames finished\n", frame ); + } + + /*------------------------------------------------------------------------------------------* + * Close files and deallocate resources + *------------------------------------------------------------------------------------------*/ + + mainFailed = false; /* This will stay set to true if cleanup is reached via a goto due to an error */ + +cleanup: + + free( pcmBuf ); + + if ( ( error = BS_Writer_Close( &hBsWriter ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Can't close bitstream writer, error code %d\n", error ); + mainFailed = true; + } + + AudioFileReader_close( &audioReader ); + + if ( jbmReader ) + { + JbmFileReader_close( &jbmReader ); + } + + for ( i = 0; i < IVAS_MAX_NUM_OBJECTS; ++i ) + { + if ( ismReaders[i] != NULL ) + { + IsmFileReader_close( &ismReaders[i] ); + } + } + + if ( masaReader ) + { + MasaFileReader_close( &masaReader ); + } + + if ( f_bwProfile ) + { + fclose( f_bwProfile ); + } + + if ( f_bitrateProfile ) + { + fclose( f_bitrateProfile ); + } + +#ifdef IVAS_RTPDUMP + if ( sceneOrientationFileReader ) + { + RotationFileReader_close( &sceneOrientationFileReader ); + } + + if ( deviceOrientationFileReader ) + { + RotationFileReader_close( &deviceOrientationFileReader ); + } + + /* IVAS_RTP_Term( &ivasRtp ); */ +#endif + + IVAS_ENC_Close( &hIvasEnc ); + +#ifdef WMOPS + print_wmops(); + print_mem( NULL ); +#endif + + return mainFailed ? -1 : 0; +} + + +/*---------------------------------------------------------------------* + * parseCmdlIVAS_enc() + * + * Encoder command-line parsing + *---------------------------------------------------------------------*/ + +static bool parseCmdlIVAS_enc( + int16_t argc, + char *argv[], + EncArguments *arg ) +{ + int16_t i, j; + char argv_to_upper[FILENAME_MAX]; + char stmp[FILENAME_MAX]; + int32_t tmp; + + /*-----------------------------------------------------------------* + * Set default values + *-----------------------------------------------------------------*/ + + arg->inputWavFilename = NULL; + arg->outputBitstreamFilename = NULL; + arg->inputFs = 0; + arg->inputFormat = IVAS_ENC_INPUT_MONO; + arg->is_binaural = false; + arg->inputFormatConfig.stereoToMonoDownmix = false; + arg->max_bwidth_user = false; + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_UNDEFINED; + arg->bandwithProfileFile = NULL; + arg->dtxConfig = IVAS_ENC_GetDefaultDtxConfig(); + arg->initBitrate = 0; + arg->bitrateProfileFile = NULL; + arg->quietModeEnabled = false; + arg->delayCompensationEnabled = true; + arg->masaMetadataFile = NULL; + arg->caConfig = IVAS_ENC_GetDefaultChannelAwareConfig(); + arg->ca_config_file = NULL; + arg->mimeOutput = false; + arg->ism_extended_metadata = false; + arg->complexityLevel = IVAS_ENC_COMPLEXITY_LEVEL_THREE; +#ifdef IVAS_RTPDUMP + arg->rtpdumpOutput = false; + arg->sceneOrientationTrajFileName = NULL; + arg->deviceOrientationTrajFileName = NULL; +#endif +#ifdef DEBUGGING + arg->forcedMode = IVAS_ENC_FORCE_UNFORCED; + arg->forcedModeFile = NULL; +#ifdef DEBUG_FORCE_DIR + arg->forcedModeDir = NULL; +#endif +#endif + arg->pca = false; + + /*-----------------------------------------------------------------* + * Initialization + *-----------------------------------------------------------------*/ + + if ( argc < 5 ) + { + fprintf( stderr, "Error: Not enough input parameters. Exiting!\n\n" ); + usage_enc(); + return false; + } + + /*-----------------------------------------------------------------* + * Optional input arguments + *-----------------------------------------------------------------*/ + + i = 1; + while ( i < argc - 4 ) + { + strncpy( argv_to_upper, argv[i], sizeof( argv_to_upper ) - 1 ); + argv_to_upper[sizeof( argv_to_upper ) - 1] = '\0'; + to_upper( argv_to_upper ); + + /*-----------------------------------------------------------------* + * Bandwidth limitation + *-----------------------------------------------------------------*/ + + if ( strcmp( argv_to_upper, "-MAX_BAND" ) == 0 ) + { + arg->max_bwidth_user = true; + + strncpy( stmp, argv[i + 1], sizeof( stmp ) - 1 ); + stmp[sizeof( stmp ) - 1] = '\0'; + to_upper( stmp ); + + if ( strcmp( stmp, "-NB" ) == 0 || strcmp( stmp, "NB" ) == 0 ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_NB; + } + else if ( strcmp( stmp, "-WB" ) == 0 || strcmp( stmp, "WB" ) == 0 ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_WB; + } + else if ( strcmp( stmp, "-SWB" ) == 0 || strcmp( stmp, "SWB" ) == 0 ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_SWB; + } + else if ( strcmp( stmp, "-FB" ) == 0 || strcmp( stmp, "FB" ) == 0 ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_FB; + } + else + { + arg->bandwithProfileFile = argv[i + 1]; + } + + i += 2; + } + + /*-----------------------------------------------------------------* + * Quiet mode + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-Q" ) == 0 ) + { + i++; + arg->quietModeEnabled = true; + } + + /*-----------------------------------------------------------------* + * DTX/CNG + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-DTX" ) == 0 ) + { + i++; + if ( i < argc - 4 ) + { + if ( sscanf( argv[i], "%d", &tmp ) <= 0 ) + { + tmp = DEFAULT_FIXED_SID_RATE; + } + else + { + i++; + } + } + else + { + tmp = DEFAULT_FIXED_SID_RATE; + } + + arg->dtxConfig.enabled = true; + + if ( tmp == 0 ) + { + arg->dtxConfig.variable_SID_rate = true; + arg->dtxConfig.SID_interval = 0; + } + else if ( tmp >= 3 && tmp <= 100 ) + { + arg->dtxConfig.variable_SID_rate = false; + arg->dtxConfig.SID_interval = (int16_t) tmp; + } + else + { + fprintf( stderr, "Error: Incorrect SID update interval specified: %d (supported 3-100)\n\n", tmp ); + usage_enc(); + return false; + } + } +#ifdef DEBUGGING + /*-----------------------------------------------------------------* + * Force specific mode + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-FORCE" ) == 0 ) + { + strncpy( stmp, argv[i + 1], sizeof( stmp ) ); + + arg->forcedMode = parseForcedMode( stmp ); + +#ifdef DEBUG_FORCE_DIR + if ( arg->forcedMode < IVAS_ENC_FORCE_FILE ) + { + fprintf( stdout, "Forcing codec to: %s\n", argv[i + 1] ); + } + else if ( arg->forcedMode == IVAS_ENC_FORCE_FILE ) + { + arg->forcedModeFile = argv[i + 1]; + fprintf( stdout, "Force switching file: %s\n", argv[i + 1] ); + } + else if ( arg->forcedMode == IVAS_ENC_FORCE_DIR ) + { + arg->forcedModeDir = argv[i + 1]; + fprintf( stdout, "Forcing switching directory: %s\n", argv[i + 1] ); + } + else + { + fprintf( stderr, "\nError: The force switching profile file/dir %s does not exist or could not be opened!\n\n", argv[i + 1] ); + usage_enc(); + return false; + } +#else + if ( arg->forcedMode == IVAS_ENC_FORCE_UNDEFINED ) + { + arg->forcedModeFile = argv[i + 1]; + fprintf( stdout, "Force switching file: %s\n", argv[i + 1] ); + } + else + { +#ifdef SUPPORT_FORCE_TCX10_TCX20 + if ( arg->forcedMode == IVAS_ENC_FORCE_TCX10 ) + { + strcpy( stmp, "TCX10" ); + } + else if ( arg->forcedMode == IVAS_ENC_FORCE_TCX20 ) + { + strcpy( stmp, "TCX20" ); + } + else + { + strncpy( stmp, argv[i + 1], sizeof( stmp ) ); + } + + fprintf( stdout, "Forcing codec to: %s\n", stmp ); +#else + fprintf( stdout, "Forcing codec to: %s\n", argv[i + 1] ); +#endif + } +#endif + + i += 2; + } +#ifdef DEBUG_MODE_INFO +#ifdef DEBUG_MODE_INFO_TWEAK + /*-----------------------------------------------------------------* + * Define additional subfolder for debug info output in ./res + *-----------------------------------------------------------------*/ + else if ( strcmp( argv_to_upper, "-INFO" ) == 0 ) + { + extern char infoFolder[FILENAME_MAX]; + strncpy( infoFolder, argv[i + 1], sizeof( infoFolder ) ); + i += 2; + } +#endif /* #ifdef DEBUG_MODE_INFO_TWEAK */ +#endif /* #ifdef DEBUG_MODE_INFO */ +#endif /* #ifdef DEBUGGING */ + + /*-----------------------------------------------------------------* + * deactivate delay compensation + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-NO_DELAY_CMP" ) == 0 ) + { + arg->delayCompensationEnabled = false; + i++; + } + + /*-----------------------------------------------------------------* + * Activate channel-aware mode + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-RF" ) == 0 ) + { + arg->caConfig.channelAwareModeEnabled = 1; + i++; + + if ( i < argc - 4 ) + { + strncpy( stmp, argv[i], sizeof( stmp ) ); + stmp[sizeof( stmp ) - 1] = '\0'; + to_upper( stmp ); + if ( strcmp( stmp, "LO" ) == 0 ) + { + arg->caConfig.fec_indicator = IVAS_ENC_FEC_LO; + } + else if ( strcmp( stmp, "HI" ) == 0 ) + { + arg->caConfig.fec_indicator = IVAS_ENC_FEC_HI; + } + else + { + arg->ca_config_file = argv[i]; + } + i++; + + if ( ( sscanf( argv[i], "%d", &tmp ) == 1 ) && ( i < argc - 4 ) ) + { + if ( tmp == 0 ) + { + arg->caConfig.channelAwareModeEnabled = 0; + arg->caConfig.fec_offset = 0; + i++; + } + else + { + arg->caConfig.fec_offset = (int16_t) tmp; + i++; + } + } + } + else + { + arg->caConfig.fec_indicator = IVAS_ENC_FEC_HI; + } + } + + /*-----------------------------------------------------------------* + * MIME output file format + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-MIME" ) == 0 ) + { + arg->mimeOutput = true; + fprintf( stdout, "Output bitstream file format: MIME\n" ); + ++i; + } + + + /*-----------------------------------------------------------------* + * Complexity Level + *-----------------------------------------------------------------*/ + + /* actual parsing of level will be implemented after characterization */ + else if ( strcmp( argv_to_upper, "-LEVEL" ) == 0 ) + { + int16_t level; + + ++i; + level = (int16_t) atoi( argv[i++] ); + if ( level < IVAS_ENC_COMPLEXITY_LEVEL_ONE || level > IVAS_ENC_COMPLEXITY_LEVEL_THREE ) + { + fprintf( stdout, "Invalid complexity level specified.\n" ); + usage_enc(); + return false; + } + else if ( level == IVAS_ENC_COMPLEXITY_LEVEL_ONE || level == IVAS_ENC_COMPLEXITY_LEVEL_TWO ) + { + fprintf( stdout, "Complexity levels 1 and 2 will be defined after characterisation - default to level 3 (full functionality).\n" ); + } + } + + /*-----------------------------------------------------------------* + * IVAS Formats + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-STEREO" ) == 0 ) + { + i++; + arg->inputFormat = IVAS_ENC_INPUT_STEREO; + +#ifdef DEBUGGING + if ( ( i < argc - 4 ) && argv[i][0] != 45 ) /* note: 45 corresponds to "-" */ + { + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + if ( tmp == 1 ) + { + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_DFT; + i++; + } + else if ( tmp == 2 ) + { + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_TD; + i++; + } + else if ( tmp == 3 ) + { + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_MDCT_DECISION; +#ifdef DEBUG_FORCE_MDCT_STEREO_MODE + i++; + + /* force mdct stereo mode for debugging purposes */ + if ( i < argc - 4 ) + { + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + if ( tmp == 0 ) + { + /* keep "DECISION" */ + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_MDCT_DECISION; + i++; + } + else if ( tmp == 1 ) + { + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_MDCT_FORCE_LR; + i++; + } + else if ( tmp == 2 ) + { + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_MDCT_FORCE_MS; + i++; + } + else + { + fprintf( stderr, "Error: Incorrect mdct stereo coding method (%d) specified\n\n", tmp ); + usage_enc(); + return false; + } + } + } +#endif + } + else + { + fprintf( stderr, "Error: Incorrect stereo mode (%d) specified\n\n", tmp ); + usage_enc(); + return false; + } + } + else + { + fprintf( stderr, "Error: Stereo mode not specified.\n\n" ); /* in the debugging stage */ + usage_enc(); + return false; + } + } + else + { + arg->inputFormatConfig.stereoMode = IVAS_ENC_STEREO_MODE_UNIFIED; + } +#endif /* DEBUGGING */ + } + else if ( strcmp( argv_to_upper, "-BINAURAL" ) == 0 ) + { + arg->is_binaural = true; + i++; + } + else if ( strcmp( argv_to_upper, "-ISM" ) == 0 ) + { + arg->inputFormat = IVAS_ENC_INPUT_ISM; + i++; + + if ( i < argc - 4 ) + { + if ( argv[i][0] == '+' ) + { + argv[i]++; + arg->ism_extended_metadata = true; + } + if ( !is_digits_only( argv[i] ) ) + { + fprintf( stderr, "Error: Number of ISM channels must be an integer number!\n\n" ); + usage_enc(); + return false; + } + + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + + if ( tmp <= 0 ) + { + fprintf( stderr, "Error: Too low number of ISM channels specified!\n\n" ); + usage_enc(); + return false; + } + else if ( tmp > IVAS_MAX_NUM_OBJECTS ) + { + fprintf( stderr, "Error: Too high number of ISM channels specified!\n\n" ); + usage_enc(); + return false; + } + else + { + arg->inputFormatConfig.ism.numObjects = (int16_t) tmp; + } + } + else + { + fprintf( stderr, "Error: Number of ISM channels not specified!\n\n" ); + usage_enc(); + return false; + } + + /* read input metadata files */ + for ( j = 0; j < arg->inputFormatConfig.ism.numObjects; j++ ) + { + if ( i < argc - 4 ) + { + if ( strcmp( argv[i], "NULL" ) == 0 || strcmp( argv[i], "null" ) == 0 ) + { + /* no metadata input file -> encode only audio streams */ + arg->inputFormatConfig.ism.metadataFiles[j] = NULL; + } + else + { + arg->inputFormatConfig.ism.metadataFiles[j] = argv[i]; + } + + i++; + } + else + { + fprintf( stderr, "Error: not enough metadata arguments specified!\n\n" ); + usage_enc(); + return false; + } + } + } + else if ( strcmp( argv_to_upper, "-SBA" ) == 0 ) + { + i++; + arg->inputFormat = IVAS_ENC_INPUT_SBA; + + /* SBA configuration */ + if ( i < argc - 4 && is_number( argv[i] ) && sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + else + { + tmp = -1; /* this is to avoid a compilation warning */ + fprintf( stderr, "Error: SBA order must be specified, expecting a number!\n\n" ); + usage_enc(); + return false; + } + + arg->inputFormatConfig.sba.isPlanar = ( tmp < 0 ); + + tmp = abs( tmp ); + switch ( tmp ) + { + case 1: + arg->inputFormatConfig.sba.order = IVAS_ENC_SBA_FOA; + break; + case 2: + arg->inputFormatConfig.sba.order = IVAS_ENC_SBA_HOA2; + break; + case 3: + arg->inputFormatConfig.sba.order = IVAS_ENC_SBA_HOA3; + break; + default: + fprintf( stderr, "Error: Wrong SBA order specified!\n\n" ); + usage_enc(); + return false; + } + } + else if ( strcmp( argv_to_upper, "-MASA" ) == 0 ) + { + arg->inputFormat = IVAS_ENC_INPUT_MASA; + i++; + + if ( i < argc - 4 ) + { + if ( !is_digits_only( argv[i] ) ) + { + fprintf( stderr, "Error: Number of MASA channels must be an integer number!\n\n" ); + usage_enc(); + return false; + } + + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + + switch ( tmp ) + { + case 1: + arg->inputFormatConfig.masaVariant = IVAS_ENC_MASA_1CH; + break; + case 2: + arg->inputFormatConfig.masaVariant = IVAS_ENC_MASA_2CH; + break; + default: + fprintf( stderr, "Error: MASA channels must be 1 or 2.\n\n" ); + usage_enc(); + return false; + } + } + + if ( i < argc - 4 ) + { + arg->masaMetadataFile = argv[i]; + i++; + } + else + { + fprintf( stderr, "Error: not enough MASA arguments\n\n" ); + usage_enc(); + return false; + } + } + else if ( strcmp( argv_to_upper, "-MC" ) == 0 ) + { + i++; + arg->inputFormat = IVAS_ENC_INPUT_MC; + + if ( i < argc - 4 ) + { + if ( strcmp( argv[i], "5_1" ) == 0 ) + { + arg->inputFormatConfig.mcLayout = IVAS_ENC_MC_5_1; + } + else if ( strcmp( argv[i], "7_1" ) == 0 ) + { + arg->inputFormatConfig.mcLayout = IVAS_ENC_MC_7_1; + } + else if ( strcmp( argv[i], "5_1_2" ) == 0 ) + { + arg->inputFormatConfig.mcLayout = IVAS_ENC_MC_5_1_2; + } + else if ( strcmp( argv[i], "5_1_4" ) == 0 ) + { + arg->inputFormatConfig.mcLayout = IVAS_ENC_MC_5_1_4; + } + else if ( strcmp( argv[i], "7_1_4" ) == 0 ) + { + arg->inputFormatConfig.mcLayout = IVAS_ENC_MC_7_1_4; + } + else + { + fprintf( stderr, "Error: Incorrect input configuration specified for Multi-channel\n\n" ); + usage_enc(); + return false; + } + i++; + } + else + { + fprintf( stderr, "Error: Multi-channel configuration not specified!\n\n" ); + usage_enc(); + return false; + } + } + else if ( strcmp( to_upper( argv[i] ), "-ISM_MASA" ) == 0 ) + { + arg->inputFormat = IVAS_ENC_INPUT_MASA_ISM; + i++; + + if ( i < argc - 5 ) + { + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + + if ( tmp <= 0 ) + { + fprintf( stderr, "Error: Too low number of ISM channels specified!\n\n" ); + usage_enc(); + return false; + } + else + { + if ( tmp <= IVAS_MAX_NUM_OBJECTS ) /* number of ISM channels */ + { + arg->inputFormatConfig.masa_ism.numObjects = (int16_t) tmp; + } + else + { + fprintf( stderr, "Error: Too high number of ISM channels!\n\n" ); + usage_enc(); + return false; + } + } + } + else + { + fprintf( stderr, "Error: Number of ISM channels not specified!\n\n" ); + usage_enc(); + return false; + } + if ( i < argc - 4 ) + { + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + + switch ( tmp ) + { + case 1: + arg->inputFormatConfig.masa_ism.masaVariant = IVAS_ENC_MASA_1CH; + break; + case 2: + arg->inputFormatConfig.masa_ism.masaVariant = IVAS_ENC_MASA_2CH; + break; + default: + fprintf( stderr, "Error: MASA channels must be 1 or 2.\n\n" ); + usage_enc(); + return false; + } + } + + /* read input metadata files */ + for ( j = 0; j < arg->inputFormatConfig.masa_ism.numObjects; j++ ) + { + if ( i < argc - 4 ) + { + if ( strcmp( argv[i], "NULL" ) == 0 || strcmp( argv[i], "null" ) == 0 ) + { + /* no metadata input file -> encode only audio streams */ + arg->inputFormatConfig.masa_ism.metadataFiles[j] = NULL; + } + else + { + arg->inputFormatConfig.masa_ism.metadataFiles[j] = argv[i]; + } + + i++; + } + else + { + fprintf( stderr, "Error: not enough arguments\n\n" ); + usage_enc(); + return false; + } + } + + if ( i < argc - 4 ) + { + arg->masaMetadataFile = argv[i]; + i++; + } + else + { + fprintf( stderr, "Error: not enough MASA arguments\n\n" ); + usage_enc(); + return false; + } + } + else if ( strcmp( to_upper( argv[i] ), "-ISM_SBA" ) == 0 ) + { + arg->inputFormat = IVAS_ENC_INPUT_SBA_ISM; + i++; + + if ( i < argc - 5 ) + { + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + + if ( tmp <= 0 ) + { + fprintf( stderr, "Error: Too low number of ISM channels specified!\n\n" ); + usage_enc(); + return false; + } + else + { + if ( tmp <= IVAS_MAX_NUM_OBJECTS ) /* number of ISM channels */ + { + arg->inputFormatConfig.sba_ism.numObjects = (int16_t) tmp; + } + else + { + fprintf( stderr, "Error: Too high number of ISM channels!\n\n" ); + usage_enc(); + return false; + } + } + } + else + { + fprintf( stderr, "Error: Number of ISM channels not specified!\n\n" ); + usage_enc(); + return false; + } + + if ( i < argc - 4 ) + { + if ( sscanf( argv[i], "%d", &tmp ) > 0 ) + { + i++; + } + + arg->inputFormatConfig.sba_ism.isPlanar = ( tmp < 0 ); + + tmp = abs( tmp ); + switch ( tmp ) + { + case 1: + arg->inputFormatConfig.sba_ism.order = IVAS_ENC_SBA_FOA; + break; + case 2: + arg->inputFormatConfig.sba_ism.order = IVAS_ENC_SBA_HOA2; + break; + case 3: + arg->inputFormatConfig.sba_ism.order = IVAS_ENC_SBA_HOA3; + break; + default: + fprintf( stderr, "Error: Wrong SBA order specified!\n\n" ); + usage_enc(); + return false; + } + } + + /* read input metadata files */ + for ( j = 0; j < arg->inputFormatConfig.sba_ism.numObjects; j++ ) + { + if ( i < argc - 4 ) + { + if ( strcmp( argv[i], "NULL" ) == 0 || strcmp( argv[i], "null" ) == 0 ) + { + /* no metadata input file -> encode only audio streams */ + arg->inputFormatConfig.sba_ism.metadataFiles[j] = NULL; + } + else + { + arg->inputFormatConfig.sba_ism.metadataFiles[j] = argv[i]; + } + + i++; + } + else + { + fprintf( stderr, "Error: not enough arguments\n\n" ); + usage_enc(); + return false; + } + } + } + else if ( strcmp( argv_to_upper, "-STEREO_DMX_EVS" ) == 0 ) + { + arg->inputFormat = IVAS_ENC_INPUT_MONO; + arg->inputFormatConfig.stereoToMonoDownmix = true; + + i++; + } + else if ( strcmp( argv_to_upper, "-PCA" ) == 0 ) + { + arg->pca = 1; + i++; + } + +#ifdef IVAS_RTPDUMP + /*-----------------------------------------------------------------* + * RTPDump output + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-RTPDUMP" ) == 0 ) + { + i++; + arg->rtpdumpOutput = true; + if ( i < argc - 4 ) + { + if ( !is_digits_only( argv[i] ) ) + { + arg->numFramesPerPacket = 1; /* Default to 1 frame per packet */ + } + else + { + arg->numFramesPerPacket = atoi( argv[i++] ); + if ( arg->numFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET ) + { + fprintf( stderr, "numFramesPerPacket(%d) exceeds max frames per packet (%d) \n", arg->numFramesPerPacket, IVAS_MAX_FRAMES_PER_RTP_PACKET ); + arg->numFramesPerPacket = 1; + } + } + } + fprintf( stdout, "Output format: RTPDump using %d frames/packet \n", arg->numFramesPerPacket ); + } + + /*-----------------------------------------------------------------* + * Scene orientation + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-SCENE_ORIENTATION" ) == 0 ) + { + i++; + if ( argc - i <= 4 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: Scene orientation file name not specified!\n\n" ); + usage_enc(); + return false; + } + + arg->sceneOrientationTrajFileName = argv[i]; + i++; + } + + /*-----------------------------------------------------------------* + * Device orientation + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-DEVICE_ORIENTATION" ) == 0 ) + { + i++; + if ( argc - i <= 4 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: Device orientation file name not specified!\n\n" ); + usage_enc(); + return false; + } + + arg->deviceOrientationTrajFileName = argv[i]; + i++; + } + +#endif + + /*-----------------------------------------------------------------* + * Option not recognized + *-----------------------------------------------------------------*/ + else + { + fprintf( stderr, "Error: option not recognized, %s\n\n", argv[i] ); + usage_enc(); + return false; + } + } /* end of while */ + + /*-----------------------------------------------------------------* + * Mandatory input arguments + *-----------------------------------------------------------------*/ + + /*-----------------------------------------------------------------* + * Bitrate + *-----------------------------------------------------------------*/ + + if ( i < argc - 2 ) + { + /* check if profile file has been entered instead of a fixed bitrate */ + if ( !is_digits_only( argv[i] ) ) + { + arg->bitrateProfileFile = argv[i]; + } + else + { + arg->initBitrate = atoi( argv[i] ); + } + + i++; + } + else + { + fprintf( stderr, "Error: no bitrate specified\n\n" ); + usage_enc(); + return false; + } + + /*-----------------------------------------------------------------* + * Input sampling frequency + *-----------------------------------------------------------------*/ + + if ( i < argc - 2 ) + { + arg->inputFs = atoi( argv[i] ) * 1000; + i++; + } + else + { + fprintf( stderr, "Error: no input sampling frequency specified\n\n" ); + usage_enc(); + return false; + } + + /* for EVS mono, restore default behavior, i.e. SWB as default maxBandwidth if not set by the user otherwise */ + if ( arg->max_bwidth_user == false ) + { + arg->maxBandwidth = IVAS_ENC_GetDefaultBandwidth( ( arg->inputFormat == IVAS_ENC_INPUT_MONO ) ? true : false ); + } + + /* Prevent maxBandwidth from being higher than inputFs/2 */ + if ( arg->inputFs == 8000 && arg->maxBandwidth > IVAS_ENC_BANDWIDTH_NB ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_NB; + } + else if ( arg->inputFs == 16000 && arg->maxBandwidth > IVAS_ENC_BANDWIDTH_WB ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_WB; + } + else if ( arg->inputFs == 32000 && arg->maxBandwidth > IVAS_ENC_BANDWIDTH_SWB ) + { + arg->maxBandwidth = IVAS_ENC_BANDWIDTH_SWB; + } + + /*-----------------------------------------------------------------* + * Input file + *-----------------------------------------------------------------*/ + + if ( i < argc - 1 ) + { + arg->inputWavFilename = argv[i]; + i++; + } + else + { + fprintf( stderr, "Error: no input file specified\n\n" ); + usage_enc(); + return false; + } + + /*-----------------------------------------------------------------* + * Output bitstream file + *-----------------------------------------------------------------*/ + + if ( i < argc ) + { + arg->outputBitstreamFilename = argv[i]; + i++; + } + else + { + fprintf( stderr, "Error: no output bitstream file specified\n\n" ); + usage_enc(); + return false; + } + + return true; +} + + +/*---------------------------------------------------------------------* + * usage_enc() + * + * Print the usage of the "ivas_cod" program + *---------------------------------------------------------------------*/ + +static void usage_enc( void ) +{ + fprintf( stdout, "Usage: IVAS_cod.exe [Options] R Fs input_file bitstream_file\n\n" ); + + fprintf( stdout, "Mandatory parameters:\n" ); + fprintf( stdout, "---------------------\n" ); + + fprintf( stdout, "R : Bitrate in bps, \n" ); + fprintf( stdout, " for EVS native modes R = (5900*, 7200, 8000, 9600, 13200, 16400,\n" ); + fprintf( stdout, " 24400, 32000, 48000, 64000, 96000, 128000) \n" ); + fprintf( stdout, " *VBR mode (average bitrate),\n" ); + fprintf( stdout, " for AMR-WB IO modes R = (6600, 8850, 12650, 14250, 15850, 18250,\n" ); + fprintf( stdout, " 19850, 23050, 23850) \n" ); + fprintf( stdout, " for IVAS stereo R = (13200, 16400, 24400, 32000, 48000, 64000, 80000, \n" ); + fprintf( stdout, " 96000, 128000, 160000, 192000, 256000) \n" ); + fprintf( stdout, " for IVAS ISM R = 13200 for 1 ISM, 16400 for 1 ISM and 2 ISM, \n" ); + fprintf( stdout, " (24400, 32000, 48000, 64000, 80000, 96000, 128000) \n" ); + fprintf( stdout, " for 2 ISM, 3 ISM and 4 ISM also 160000, 192000, 256000) \n" ); + fprintf( stdout, " for 3 ISM and 4 ISM also 384000 \n" ); + fprintf( stdout, " for 4 ISM also 512000 \n" ); + fprintf( stdout, " for IVAS SBA, MASA, MC, ISM-SBA, and ISM-MASA R=(13200, 16400, 24400, 32000, 48000, 64000,\n" ); + fprintf( stdout, " 80000, 96000, 128000, 160000, 192000, 256000, 384000, 512000) \n" ); + fprintf( stdout, " Alternatively, R can be a bitrate switching file which consists of R values\n" ); + fprintf( stdout, " indicating the bitrate for each frame in bps. These values are stored in\n" ); + fprintf( stdout, " binary format using 4 bytes per value\n" ); + fprintf( stdout, "Fs : Input sampling rate in kHz, Fs = (8, 16, 32 or 48) \n" ); + + fprintf( stdout, "input_file : Input audio filename \n" ); + fprintf( stdout, "bitstream_file : Output bitstream filename \n\n" ); + + fprintf( stdout, "Options:\n" ); + fprintf( stdout, "--------\n" ); + fprintf( stdout, "EVS mono is default, for IVAS choose one of the following: -stereo, -ism, -sba, -masa, -mc, -ism_sba, -ism_masa\n" ); + fprintf( stdout, "-stereo : Stereo format \n" ); + fprintf( stdout, "-ism (+)Ch Files : ISM format \n" ); + fprintf( stdout, " where Ch specifies the number of ISMs (1-4)\n" ); + fprintf( stdout, " where positive (+) indicates extended metadata (only 64 kbps and up) \n" ); + fprintf( stdout, " and Files specify input files containing metadata, one file per object\n" ); + fprintf( stdout, " (use NULL for no input metadata)\n" ); + fprintf( stdout, "-sba +/-Order : Scene Based Audio input format (Ambisonics ACN/SN3D),\n" ); + fprintf( stdout, " where Order specifies the Ambisionics order (1-3),\n" ); + fprintf( stdout, " where positive (+) means full 3D and negative (-) only 2D/planar components to be coded\n" ); + fprintf( stdout, "-masa Ch File : MASA format \n" ); + fprintf( stdout, " where Ch specifies the number of MASA input/transport channels (1 or 2): \n" ); + fprintf( stdout, " and File specifies input file containing parametric MASA metadata \n" ); + fprintf( stdout, "-ism_sba IsmCh +/-Order IsmFiles : SBA and ISM combined format\n" ); + fprintf( stdout, " where IsmCh specifies the number of ISMs (1-4)\n" ); + fprintf( stdout, " and Order specifies the SBA order (1 to 3) \n" ); + fprintf( stdout, " and IsmFiles specify input files containing ISM metadata, one file per object \n" ); + fprintf( stdout, "-ism_masa IsmCh MasaCh IsmFiles MasaFile : MASA and ISM combined format \n" ); + fprintf( stdout, " where IsmCh specifies the number of ISMs (1-4),\n" ); + fprintf( stdout, " MasaCh specifies the number of MASA input/transport channels (1-2), \n" ); + fprintf( stdout, " IsmFiles specify input files containing ISM metadata, one file per object, \n" ); + fprintf( stdout, " and MasaFile specifies input file containing parametric MASA metadata \n" ); + fprintf( stdout, "-mc InputConf : Multi-channel format\n" ); + fprintf( stdout, " where InputConf specifies the channel configuration: 5_1, 7_1, 5_1_2, 5_1_4, 7_1_4\n" ); + fprintf( stdout, " Loudspeaker positions are assumed to have azimuth and elevation as per \n" ); + fprintf( stdout, " ISO/IEC 23091-3:2018 Table 3. Channel order is as per ISO/IEC 23008-3:2015 Table 95.\n" ); + fprintf( stdout, " See readme.txt for details.\n" ); + fprintf( stdout, "-dtx D : Activate DTX mode, D = (0, 3-100) is the SID update rate\n" ); + fprintf( stdout, " where 0 = adaptive, 3-100 = fixed in number of frames,\n" ); + fprintf( stdout, " default is deactivated\n" ); + fprintf( stdout, "-dtx : Activate DTX mode with a SID update rate of 8 frames\n" ); + fprintf( stdout, " Note: DTX is supported in EVS, stereo, ISM, SBA up to 80kbps and MASA up to 128kbps \n" ); + fprintf( stdout, "-rf p o : Activate channel-aware mode for WB and SWB signal at 13.2kbps, \n" ); + fprintf( stdout, " where FEC indicator, p: LO or HI, and FEC offset, o: 2, 3, 5, or 7 in number of frames.\n" ); + fprintf( stdout, " Alternatively p and o can be replaced by a rf configuration file with each line \n" ); + fprintf( stdout, " contains the values of p and o separated by a space, \n" ); + fprintf( stdout, " default is deactivated \n" ); + fprintf( stdout, "-max_band B : Activate bandwidth limitation, B = (NB, WB, SWB or FB)\n" ); + fprintf( stdout, " alternatively, B can be a text file where each line contains \"nb_frames B\"\n" ); + fprintf( stdout, "-no_delay_cmp : Turn off delay compensation\n" ); + fprintf( stdout, "-stereo_dmx_evs : Activate stereo downmix function for EVS.\n" ); + fprintf( stdout, "-binaural : Optional indication that input is binaural audio (to be used with -stereo or -stereo_dmx_evs)\n" ); + fprintf( stdout, "-mime : Mime output bitstream file format\n" ); + fprintf( stdout, " The encoder produces TS26.445 Annex.2.6 Mime Storage Format, (not RFC4867 Mime Format).\n" ); + fprintf( stdout, " default output bitstream file format is G.192\n" ); + fprintf( stdout, "-pca : activate PCA in SBA format FOA at 256 kbps \n" ); + fprintf( stdout, "-level level : Complexity level, level = (1, 2, 3), will be defined after characterisation. \n" ); + fprintf( stdout, " Currently, all values default to level 3 (full functionality).\n" ); +#ifdef DEBUGGING + fprintf( stdout, "-force T : Force specific mode, T = (speech, music, ACELP, GSC, TCX, HQ),\n" ); + fprintf( stdout, " alternatively, T can be a text file where each line contains \"nb_frames T\"\n" ); +#ifdef DEBUG_FORCE_DIR + fprintf( stdout, " or T can be a directory containing external binary files for modes/parameters enforcement\n" ); +#endif +#endif +#ifdef DEBUG_MODE_INFO +#ifdef DEBUG_MODE_INFO_TWEAK + fprintf( stdout, "-info : specify subfolder name for debug output\n" ); +#endif +#endif + fprintf( stdout, "-q : Quiet mode, no frame counters\n" ); + fprintf( stdout, " default is deactivated\n" ); +#ifdef IVAS_RTPDUMP + fprintf( stdout, "-rtpdump : RTPDump output, hf_only=1 by default. The encoder will packetize the \n" ); + fprintf( stdout, " bitstream frames into TS26.253 Annex A IVAS RTP Payload Format packets and \n" ); + fprintf( stdout, " writes those to the output file. In EVS mono operating mode, TS26.445 Annex A.2.2 \n" ); + fprintf( stdout, " EVS RTP Payload Format is used. Optional N represents number of frames per RTP packet\n" ); + fprintf( stdout, "-scene_orientation : Scene orientation trajectory file. Only used with rtpdump output.\n" ); + fprintf( stdout, "-device_orientation : Device orientation trajectory file. Only used with rtpdump output.\n" ); +#endif + fprintf( stdout, "\n" ); + + return; +} + + +/*---------------------------------------------------------------------* + * readBandwidth() + * + * + *---------------------------------------------------------------------*/ + +static bool readBandwidth( + FILE *file, + IVAS_ENC_BANDWIDTH *bandwidth, + int32_t *bandwidthFrameCounter ) +{ + int16_t res; + char stmp[4]; + + if ( *bandwidthFrameCounter == 0 ) + { + /* read next bandwidth value and number of frames from the profile file */ + while ( ( res = (int16_t) fscanf( file, "%d %3s", bandwidthFrameCounter, stmp ) ) != 2 && feof( file ) ) + { + rewind( file ); + } + + ( *bandwidthFrameCounter )--; + + to_upper( stmp ); + + if ( strcmp( stmp, "NB" ) == 0 ) + { + *bandwidth = IVAS_ENC_BANDWIDTH_NB; + } + else if ( strcmp( stmp, "WB" ) == 0 ) + { + *bandwidth = IVAS_ENC_BANDWIDTH_WB; + } + else if ( strcmp( stmp, "SWB" ) == 0 ) + { + *bandwidth = IVAS_ENC_BANDWIDTH_SWB; + } + else if ( strcmp( stmp, "FB" ) == 0 ) + { + *bandwidth = IVAS_ENC_BANDWIDTH_FB; + } + else + { + fprintf( stderr, "Error: incorrect bandwidth specified (only NB, WB, SWB and FB are supported)\n\n" ); + usage_enc(); + return false; + } + } + else + { + /* current profile still active, only decrease the counter */ + ( *bandwidthFrameCounter )--; + } + + return true; +} + + +/*---------------------------------------------------------------------* + * readBitrate() + * + * + *---------------------------------------------------------------------*/ + +static bool readBitrate( + FILE *file, + int32_t *bitrate ) +{ + for ( int32_t i = 0; i < 2; ++i ) + { + if ( fread( bitrate, sizeof( int32_t ), 1, file ) == 1 ) + { + return true; + } + + rewind( file ); + } + + fprintf( stderr, "Error: cannot read the bitrate profile file\n\n" ); + usage_enc(); + return false; +} + + +#ifdef DEBUGGING +/*---------------------------------------------------------------------* + * parseForcedMode() + * + * + *---------------------------------------------------------------------*/ + +static IVAS_ENC_FORCED_MODE parseForcedMode( + char *forcedModeChar ) +{ +#ifdef DEBUG_FORCE_DIR + struct stat path_stat; +#endif + + to_upper( forcedModeChar ); + +#ifdef DEBUG_FORCE_DIR + if ( ( strcmp( forcedModeChar, "SPEECH" ) == 0 ) || ( strcmp( forcedModeChar, "'SPEECH'" ) == 0 ) || + ( strcmp( forcedModeChar, "0" ) == 0 ) ) + { + return IVAS_ENC_FORCE_SPEECH; + } + else if ( ( strcmp( forcedModeChar, "MUSIC" ) == 0 ) || ( strcmp( forcedModeChar, "'MUSIC'" ) == 0 ) || ( strcmp( forcedModeChar, "AUDIO" ) == 0 ) || ( strcmp( forcedModeChar, "'AUDIO'" ) == 0 ) || ( strcmp( forcedModeChar, "1" ) == 0 ) ) + { + return IVAS_ENC_FORCE_MUSIC; + } + else if ( ( strcmp( forcedModeChar, "ACELP" ) == 0 ) || ( strcmp( forcedModeChar, "'ACELP'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_ACELP; + } + else if ( ( strcmp( forcedModeChar, "GSC" ) == 0 ) || ( strcmp( forcedModeChar, "'GSC'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_GSC; + } + if ( ( strcmp( forcedModeChar, "TCX" ) == 0 ) || ( strcmp( forcedModeChar, "'TCX'" ) == 0 ) +#ifdef SUPPORT_FORCE_TCX10_TCX20 + || ( strcmp( forcedModeChar, "TCX20" ) == 0 ) || ( strcmp( forcedModeChar, "'TCX20'" ) == 0 ) +#endif + ) + { +#ifdef SUPPORT_FORCE_TCX10_TCX20 + return IVAS_ENC_FORCE_TCX20; +#else + return IVAS_ENC_FORCE_TCX; +#endif + } +#ifdef SUPPORT_FORCE_TCX10_TCX20 + if ( ( strcmp( forcedModeChar, "TCX10" ) == 0 ) || ( strcmp( forcedModeChar, "'TCX10'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_TCX10; + } +#endif + else if ( ( strcmp( forcedModeChar, "HQ" ) == 0 ) || ( strcmp( forcedModeChar, "'HQ'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_HQ; + } + else + { + if ( stat( forcedModeChar, &path_stat ) != 0 ) + { + return IVAS_ENC_FORCE_UNDEFINED; + } + + /* check if the argument represents an existing file or directory */ + if ( S_ISDIR( path_stat.st_mode ) ) + { + /* it's a directory */ + return IVAS_ENC_FORCE_DIR; + } + else + { + /* it's a file */ + return IVAS_ENC_FORCE_FILE; + } + } +#else + if ( ( strcmp( forcedModeChar, "SPEECH" ) == 0 ) || ( strcmp( forcedModeChar, "'SPEECH'" ) == 0 ) || + ( strcmp( forcedModeChar, "0" ) == 0 ) ) + { + return IVAS_ENC_FORCE_SPEECH; + } + if ( ( strcmp( forcedModeChar, "MUSIC" ) == 0 ) || ( strcmp( forcedModeChar, "'MUSIC'" ) == 0 ) || ( strcmp( forcedModeChar, "AUDIO" ) == 0 ) || ( strcmp( forcedModeChar, "'AUDIO'" ) == 0 ) || ( strcmp( forcedModeChar, "1" ) == 0 ) ) + { + return IVAS_ENC_FORCE_MUSIC; + } + if ( ( strcmp( forcedModeChar, "ACELP" ) == 0 ) || ( strcmp( forcedModeChar, "'ACELP'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_ACELP; + } + if ( ( strcmp( forcedModeChar, "GSC" ) == 0 ) || ( strcmp( forcedModeChar, "'GSC'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_GSC; + } + if ( ( strcmp( forcedModeChar, "TCX" ) == 0 ) || ( strcmp( forcedModeChar, "'TCX'" ) == 0 ) +#ifdef SUPPORT_FORCE_TCX10_TCX20 + || ( strcmp( forcedModeChar, "TCX20" ) == 0 ) || ( strcmp( forcedModeChar, "'TCX20'" ) == 0 ) +#endif + ) + { +#ifdef SUPPORT_FORCE_TCX10_TCX20 + return IVAS_ENC_FORCE_TCX20; +#else + return IVAS_ENC_FORCE_TCX; +#endif + } +#ifdef SUPPORT_FORCE_TCX10_TCX20 + if ( ( strcmp( forcedModeChar, "TCX10" ) == 0 ) || ( strcmp( forcedModeChar, "'TCX10'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_TCX10; + } +#endif + if ( ( strcmp( forcedModeChar, "HQ" ) == 0 ) || ( strcmp( forcedModeChar, "'HQ'" ) == 0 ) ) + { + return IVAS_ENC_FORCE_HQ; + } + + return IVAS_ENC_FORCE_UNDEFINED; +#endif +} + + +/*---------------------------------------------------------------------* + * readForcedMode() + * + * + *---------------------------------------------------------------------*/ + +static ivas_error readForcedMode( + FILE *file, + IVAS_ENC_FORCED_MODE *forcedMode, + int32_t *forceFrameCounter ) +{ + int16_t res; + char stmp[8]; + + if ( *forceFrameCounter == 0 ) + { + /* read next force and number of frames from the profile file */ + while ( ( res = (int16_t) fscanf( file, "%d %7s", forceFrameCounter, stmp ) ) != 2 && feof( file ) ) + { + rewind( file ); + } + + *forcedMode = parseForcedMode( stmp ); + + if ( *forcedMode == IVAS_ENC_FORCE_UNDEFINED ) + { + fprintf( stderr, "Error: incorect mode specification or the force profile file could not be opened: %s\n\n", stmp ); + return IVAS_ERR_WRONG_PARAMS; + } + + if ( res != 2 && !feof( file ) ) + { + fprintf( stderr, "Error: incorrect format of the force profile file (please ensure that it does not contain any empty lines)\n\n" ); + return IVAS_ERR_WRONG_PARAMS; + } + } + + /* current profile still active, only decrease the counter */ + ( *forceFrameCounter )--; + + return IVAS_ERR_OK; +} +#endif + + +#undef WMC_TOOL_SKIP -- GitLab From 1cfdb16eeb90cb44d4bb43ce7d16b40fc0219020 Mon Sep 17 00:00:00 2001 From: "@ragot" Date: Mon, 10 Nov 2025 14:05:20 +0100 Subject: [PATCH 21/34] fix clang --- apps/encoder_fmtsw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/encoder_fmtsw.c b/apps/encoder_fmtsw.c index 143d8a1a6..ff04c87fd 100644 --- a/apps/encoder_fmtsw.c +++ b/apps/encoder_fmtsw.c @@ -56,10 +56,10 @@ rather than just defining _S_IFMT, _S_IFREG, and _S_IFDIR as it normally does. */ #include #if !defined( S_ISREG ) && defined( S_IFMT ) && defined( S_IFREG ) -#define S_ISREG( m ) ( ( (m) &S_IFMT ) == S_IFREG ) +#define S_ISREG( m ) ( ( ( m ) & S_IFMT ) == S_IFREG ) #endif #if !defined( S_ISDIR ) && defined( S_IFMT ) && defined( S_IFDIR ) -#define S_ISDIR( m ) ( ( (m) &S_IFMT ) == S_IFDIR ) +#define S_ISDIR( m ) ( ( ( m ) & S_IFMT ) == S_IFDIR ) #endif #endif @@ -200,7 +200,7 @@ static int encoder_main( int argc, char *argv[] ); * * Main IVAS encoder function for command-line interface * supporting format switching -*------------------------------------------------------------------------------------------*/ + *------------------------------------------------------------------------------------------*/ int main( int argc, -- GitLab From 6e97e6410acde5118ff1a3b1184af05a09c10192 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 15:20:19 +0200 Subject: [PATCH 22/34] Clang format --- lib_util/ivas_rtp_pi_data.c | 30 +++++++++++++++--------------- lib_util/ivas_rtp_pi_data.h | 6 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index 6a55a64fb..c9583e048 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -900,10 +900,10 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #endif packUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ - packOrientation, /* HEAD_ORIENTATION */ + packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + packOrientation, /* HEAD_ORIENTATION */ #ifdef REVERSE_ISM_PI_DATA - packPosition, /* LISTENER_POSITION */ + packPosition, /* LISTENER_POSITION */ #else packListenerPosition, /* LISTENER_POSITION */ #endif @@ -918,11 +918,11 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #endif packUnsupportedData, /* PI_LATENCY */ #ifdef REVERSE_ISM_PI_DATA - packReverseISMID, /* R_ISM_ID */ + packReverseISMID, /* R_ISM_ID */ packReverseISMGain, /* R_ISM_GAIN */ #else - packUnsupportedData, /* R_ISM_ID */ - packUnsupportedData, /* R_ISM_GAIN */ + packUnsupportedData, /* R_ISM_ID */ + packUnsupportedData, /* R_ISM_GAIN */ #endif #ifdef RTP_S4_251135_CR26253_0016_REV1 packOrientation, /* R_ISM_ORIENTATION */ @@ -931,11 +931,11 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #endif #ifdef REVERSE_ISM_PI_DATA - packPosition, /* R_ISM_POSITION */ + packPosition, /* R_ISM_POSITION */ packReverseISMDirection, /* R_ISM_DIRECTION */ #else - packUnsupportedData, /* R_ISM_POSITION */ - packUnsupportedData, /* R_ISM_DIRECTION */ + packUnsupportedData, /* R_ISM_POSITION */ + packUnsupportedData, /* R_ISM_DIRECTION */ #endif packUnsupportedData, /* RESERVED27 */ packUnsupportedData, /* RESERVED28 */ @@ -974,12 +974,12 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #endif unpackUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ - unpackOrientation, /* HEAD_ORIENTATION */ + unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + unpackOrientation, /* HEAD_ORIENTATION */ #ifdef REVERSE_ISM_PI_DATA - unpackPosition, /* LISTENER_POSITION */ + unpackPosition, /* LISTENER_POSITION */ #else - unpackListenerPosition, /* LISTENER_POSITION */ + unpackListenerPosition, /* LISTENER_POSITION */ #endif unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ @@ -992,7 +992,7 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #endif unpackUnsupportedData, /* PI_LATENCY */ #ifdef REVERSE_ISM_PI_DATA - unpackReverseISMID, /* R_ISM_ID */ + unpackReverseISMID, /* R_ISM_ID */ unpackReverseISMGain, /* R_ISM_GAIN */ #else unpackUnsupportedData, /* R_ISM_ID */ @@ -1004,7 +1004,7 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackUnsupportedData, /* R_ISM_ORIENTATION */ #endif #ifdef REVERSE_ISM_PI_DATA - unpackPosition, /* R_ISM_POSITION */ + unpackPosition, /* R_ISM_POSITION */ unpackReverseISMDirection, /* R_ISM_DIRECTION */ #else unpackUnsupportedData, /* R_ISM_POSITION */ diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index e9effd359..d29c0eea4 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -40,9 +40,9 @@ #define IVAS_PI_MAX_DATA_SIZE ( 32 + 2 ) /* max packed PI data bytes + pi header bytes */ #ifdef REVERSE_ISM_PI_DATA -#define REVERSE_ISM_DIRECTION_AZIMUTH_STEP 0.703125f -#define REVERSE_ISM_DIRECTION_ELEVATION_STEP 1.417322835f -#define REVERSE_ISM_DIRECTION_AZIMUTH_STEP_INV 1.4222222222f +#define REVERSE_ISM_DIRECTION_AZIMUTH_STEP 0.703125f +#define REVERSE_ISM_DIRECTION_ELEVATION_STEP 1.417322835f +#define REVERSE_ISM_DIRECTION_AZIMUTH_STEP_INV 1.4222222222f #define REVERSE_ISM_DIRECTION_ELEVATION_STEP_INV 0.7055555556f #endif -- GitLab From 3c3d6dc7cd84108b855401e097124c5a36c8b2a7 Mon Sep 17 00:00:00 2001 From: "@ragot" Date: Mon, 10 Nov 2025 14:20:34 +0100 Subject: [PATCH 23/34] fix clang --- apps/encoder_fmtsw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/encoder_fmtsw.c b/apps/encoder_fmtsw.c index ff04c87fd..74efb401f 100644 --- a/apps/encoder_fmtsw.c +++ b/apps/encoder_fmtsw.c @@ -56,10 +56,10 @@ rather than just defining _S_IFMT, _S_IFREG, and _S_IFDIR as it normally does. */ #include #if !defined( S_ISREG ) && defined( S_IFMT ) && defined( S_IFREG ) -#define S_ISREG( m ) ( ( ( m ) & S_IFMT ) == S_IFREG ) +#define S_ISREG( m ) ( ( (m) &S_IFMT ) == S_IFREG ) #endif #if !defined( S_ISDIR ) && defined( S_IFMT ) && defined( S_IFDIR ) -#define S_ISDIR( m ) ( ( ( m ) & S_IFMT ) == S_IFDIR ) +#define S_ISDIR( m ) ( ( (m) &S_IFMT ) == S_IFDIR ) #endif #endif -- GitLab From 4e8797267442a8927f3976cca8c809b28ab30211 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 15:27:00 +0200 Subject: [PATCH 24/34] Fix debug build issue --- lib_dec/lib_dec_fx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 44a8aa54f..13dd59cdc 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -6577,7 +6577,11 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi { IVAS_QUATERNION *quat = &piData->data.scene.orientation; #ifdef DEBUGGING - fprintf( stdout, "PI_SCENE_ORIENTATION : %f, %f, %f, %f\n", quat->w, quat->x, quat->y, quat->z ); + fprintf( stdout, "PI_SCENE_ORIENTATION : %f, %f, %f, %f\n", + fixedToFloat( quat->w_fx, Q15 ), + fixedToFloat( quat->x_fx, Q15 ), + fixedToFloat( quat->y_fx, Q15 ), + fixedToFloat( quat->z_fx, Q15 ) ); #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } @@ -6587,7 +6591,11 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi { IVAS_QUATERNION *quat = &piData->data.deviceCompensated.orientation; #ifdef DEBUGGING - fprintf( stdout, "PI_DEVICE_ORIENTATION : %f, %f, %f, %f\n", quat->w, quat->x, quat->y, quat->z ); + fprintf( stdout, "PI_DEVICE_ORIENTATION : %f, %f, %f, %f\n", + fixedToFloat( quat->w_fx, Q15 ), + fixedToFloat( quat->x_fx, Q15 ), + fixedToFloat( quat->y_fx, Q15 ), + fixedToFloat( quat->z_fx, Q15 ) ); #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } -- GitLab From 17586d3bca690eedad02354cc2040ff8cf264575 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 16:21:28 +0200 Subject: [PATCH 25/34] Clang format --- lib_dec/lib_dec_fx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 13dd59cdc..3ce7d68fc 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -6578,10 +6578,10 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi IVAS_QUATERNION *quat = &piData->data.scene.orientation; #ifdef DEBUGGING fprintf( stdout, "PI_SCENE_ORIENTATION : %f, %f, %f, %f\n", - fixedToFloat( quat->w_fx, Q15 ), - fixedToFloat( quat->x_fx, Q15 ), - fixedToFloat( quat->y_fx, Q15 ), - fixedToFloat( quat->z_fx, Q15 ) ); + fixedToFloat( quat->w_fx, Q15 ), + fixedToFloat( quat->x_fx, Q15 ), + fixedToFloat( quat->y_fx, Q15 ), + fixedToFloat( quat->z_fx, Q15 ) ); #endif error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } -- GitLab From b552db40b3caf18dd15bc1b5de020e1017aa0b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Toftg=C3=A5rd?= Date: Mon, 10 Nov 2025 17:09:31 +0100 Subject: [PATCH 26/34] Add porting of ISM_PI_DATA from float main, float MR !2329. Includes already updated range for ISM_GAIN PI data, float MR !2386. --- lib_com/options.h | 1 + lib_util/ivas_rtp_file.c | 116 ++++++- lib_util/ivas_rtp_pi_data.c | 614 +++++++++++++++++++++++++++++++++--- lib_util/ivas_rtp_pi_data.h | 18 ++ 4 files changed, 706 insertions(+), 43 deletions(-) diff --git a/lib_com/options.h b/lib_com/options.h index c6a4efa4b..249dbfe85 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -161,6 +161,7 @@ #define RTP_S4_251135_CR26253_0016_REV1 /* RTP Pack/Unpack API corresponding to CR 26253 */ #define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ #define FIXED_RTP_SEQUENCE_NUM /* Remove random sequence number initialization */ +#define ISM_PI_DATA /* Add reading and packing/unpacking of ISM PI data */ /* #################### End BASOP porting switches ############################ */ diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 82f198135..e3dfbde4d 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -153,16 +153,24 @@ void IVAS_RTP_LogPiData( uint32_t nPiDataPresent /* i : Number of valid elements in the piData array */ ) { +#ifdef ISM_PI_DATA + uint16_t n; +#endif uint32_t timestamp = ~0u; if ( f_piDataOut == NULL || piData == NULL || nPiDataPresent == 0 ) { return; } +#ifdef ISM_PI_DATA +#ifdef _WIN32 + if ( ftell( f_piDataOut ) > 3 ) +#else if ( ftell( f_piDataOut ) > 2 ) - { - fprintf( f_piDataOut, ",\n" ); - } +#endif +#else + if ( ftell( f_piDataOut ) > 2 ) +#endif while ( nPiDataPresent-- > 0 ) { @@ -334,6 +342,107 @@ void IVAS_RTP_LogPiData( fprintf( f_piDataOut, "{}" ); } break; +#ifdef ISM_PI_DATA + case IVAS_PI_ISM_ORIENTATION: + { + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismOrientation.numObjects; n++ ) + { + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"w\": %f,\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", + fixedToFloat( cur->data.ismOrientation.orientation[n].w_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[n].x_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[n].y_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[n].z_fx, Q15 ) ); + } + fprintf( f_piDataOut, "\n\t\t]" ); + } + break; + case IVAS_PI_ISM_NUM: + { + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"num\": %d", cur->data.ismNum.numObjects ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_ISM_ID: + { + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"ids\": [\n" ); + for ( n = 0; n < cur->data.ismId.numObjects; n++ ) + { + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t\t%d", cur->data.ismId.id[n] ); + } + fprintf( f_piDataOut, "\n\t\t\t]" ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_ISM_GAIN: + { + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"gains\": [\n" ); + for ( n = 0; n < cur->data.ismGain.numObjects; n++ ) + { + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t\t%d", cur->data.ismGain.dB[n] ); + } + fprintf( f_piDataOut, "\n\t\t\t]" ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_ISM_POSITION: + { + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismPosition.numObjects; n++ ) + { + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", cur->data.ismPosition.position[n].x, cur->data.ismPosition.position[n].y, cur->data.ismPosition.position[n].z ); + } + fprintf( f_piDataOut, "\n\t\t]" ); + } + break; + case IVAS_PI_ISM_DISTANCE_ATTENUATION: + { + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismAttenuation.numObjects; n++ ) + { + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"ref_dist\": %f,\n\t\t\t\t\"max_dist\": %f,\n\t\t\t\t\"roll_off\": %f \n\t\t\t}", cur->data.ismAttenuation.distAtten[n].ref_dist, cur->data.ismAttenuation.distAtten[n].max_dist, cur->data.ismAttenuation.distAtten[n].roll ); + } + fprintf( f_piDataOut, "\n\t\t]" ); + } + break; + case IVAS_PI_ISM_DIRECTIVITY: + { + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismDirectivity.numObjects; n++ ) + { + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"inner_ang\": %d,\n\t\t\t\t\"outer_ang\": %d,\n\t\t\t\t\"outer_att\": %f \n\t\t\t}", cur->data.ismDirectivity.directivity[n].innerConeAngle, cur->data.ismDirectivity.directivity[n].outerConeAngle, cur->data.ismDirectivity.directivity[n].outerAttenuationdB ); + } + fprintf( f_piDataOut, "\n\t\t]" ); + } + break; +#else case IVAS_PI_ISM_NUM: case IVAS_PI_ISM_ID: case IVAS_PI_ISM_GAIN: @@ -341,6 +450,7 @@ void IVAS_RTP_LogPiData( case IVAS_PI_ISM_POSITION: case IVAS_PI_ISM_DISTANCE_ATTENUATION: case IVAS_PI_ISM_DIRECTIVITY: +#endif case IVAS_PI_PI_LATENCY: case IVAS_PI_R_ISM_ID: case IVAS_PI_R_ISM_GAIN: diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index be2e9dd4d..fc4330db3 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -32,6 +32,18 @@ #include "ivas_error_utils.h" #include "ivas_rtp_internal.h" +#ifdef ISM_PI_DATA +#include + +#ifndef min +#define min( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) +#endif + +#ifndef max +#define max( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) ) +#endif + +#endif #ifdef IVAS_RTPDUMP @@ -154,6 +166,43 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error packISMOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ISM_ORIENTATION *orientation = (const IVAS_PIDATA_ISM_ORIENTATION *) piData; + uint16_t n; + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ISM_ORIENTATION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in Orientation PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_ORIENTATION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Orientation PI data" ); + } + /* Orientation data is 8 bytes, header is 2 bytes */ + if ( maxDataBytes < 8 * IVAS_MAX_NUM_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Orientation PI data" ); + } + + buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) orientation->numObjects * 8; + for ( n = 0; n < orientation->numObjects; n++ ) + { + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation[n].w_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation[n].x_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation[n].y_fx ) ); + nBytes = writeInt16( buffer, nBytes, round_fx( orientation->orientation[n].z_fx ) ); + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} +#endif + static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) { IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData; @@ -173,6 +222,40 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error unpackISMOrientation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ISM_ORIENTATION *ism_orientation = (IVAS_PIDATA_ISM_ORIENTATION *) piData; + + /* Orientation data is 8 bytes */ + uint16_t n; + if ( numDataBytes % 8 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + } + + ism_orientation->size = sizeof( IVAS_PIDATA_ISM_ORIENTATION ); + ism_orientation->numObjects = (uint16_t) numDataBytes / 8; + + for ( n = 0; n < ism_orientation->numObjects; n++ ) + { + ism_orientation->orientation[n].w_fx = L_deposit_l( readInt16( &buffer[8 * n] ) ); + ism_orientation->orientation[n].x_fx = L_deposit_l( readInt16( &buffer[8 * n + 2] ) ); + ism_orientation->orientation[n].y_fx = L_deposit_l( readInt16( &buffer[8 * n + 4] ) ); + ism_orientation->orientation[n].z_fx = L_deposit_l( readInt16( &buffer[8 * n + 6] ) ); + } + for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) + { + ism_orientation->orientation[n].w_fx = 0; + ism_orientation->orientation[n].x_fx = 0; + ism_orientation->orientation[n].y_fx = 0; + ism_orientation->orientation[n].z_fx = 0; + } + + return IVAS_ERR_OK; +} +#endif + static uint32_t getIndexTable( const float *table, uint32_t tableLength, float value ) { uint32_t idx = 0; @@ -477,6 +560,67 @@ static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDat return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error packISMPosition( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_POSITION *ism_position = (const IVAS_PIDATA_ISM_POSITION *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ISM_POSITION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM POSITION PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_POSITION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM POSITION PI data" ); + } + + /* Position data is 6 bytes, header is 2 bytes */ + if ( maxDataBytes < 6 * IVAS_MAX_NUM_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM POSITION PI data" ); + } + + buffer[nBytes++] = ( ism_position->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) ism_position->numObjects * 6; + for ( n = 0; n < ism_position->numObjects; n++ ) + { + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( ism_position->position[n].x / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( ism_position->position[n].y / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( ism_position->position[n].z / MAX_PI_POSITION_METERS ) ); + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMPosition( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint16_t n; + IVAS_PIDATA_ISM_POSITION *ism_position = (IVAS_PIDATA_ISM_POSITION *) piData; + + /* Position data is 6 bytes */ + if ( numDataBytes % 6 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack LISTENER POSITION PI data" ); + } + + ism_position->size = sizeof( IVAS_PIDATA_ISM_POSITION ); + ism_position->piDataType = IVAS_PI_ISM_POSITION; + ism_position->numObjects = (uint16_t) numDataBytes / 6; + + for ( n = 0; n < ism_position->numObjects; n++ ) + { + ism_position->position[n].x = FLOAT_FROM_Q15( readInt16( &buffer[6 * n] ) ) * MAX_PI_POSITION_METERS; + ism_position->position[n].y = FLOAT_FROM_Q15( readInt16( &buffer[6 * n + 2] ) ) * MAX_PI_POSITION_METERS; + ism_position->position[n].z = FLOAT_FROM_Q15( readInt16( &buffer[6 * n + 4] ) ) * MAX_PI_POSITION_METERS; + } + return IVAS_ERR_OK; +} +#endif + static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { uint32_t nBytes = 0, n; @@ -630,6 +774,376 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error packISMNum( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ISM_NUM *ism_num = (const IVAS_PIDATA_ISM_NUM *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ISM_NUM ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_NUM PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_NUM ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_NUM PI data" ); + } + + /* ISM_NUM data is 1 bytes, header is 2 bytes */ + if ( maxDataBytes < 1 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_NUM PI data" ); + } + + buffer[nBytes++] = ( ism_num->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 1; + buffer[nBytes++] = ( ( ism_num->numObjects - 1 ) & MASK_2BIT ) << 6; + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMNum( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ISM_NUM *ism_num = (IVAS_PIDATA_ISM_NUM *) piData; + uint8_t byte; + + /* ISM_NUM data is 1 bytes */ + if ( numDataBytes != 1 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_NUM PI data" ); + } + + ism_num->size = sizeof( IVAS_PIDATA_ISM_NUM ); + ism_num->piDataType = IVAS_PI_ISM_NUM; + + byte = buffer[0]; + ism_num->numObjects = ( ( byte >> 6 ) & MASK_2BIT ) + 1; + + return IVAS_ERR_OK; +} +static ivas_error packISMID( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_ID *ism_id = (const IVAS_PIDATA_ISM_ID *) piData; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_ID ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_ID PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_ID ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_ID PI data" ); + } + + /* ISM_ID data is 1 byte per object, header is 2 bytes */ + if ( maxDataBytes < 1 * IVAS_MAX_NUM_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_NUM PI data" ); + } + + buffer[nBytes++] = ( ism_id->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) ism_id->numObjects; + /* Pack ID for each object */ + for ( n = 0; n < ism_id->numObjects; n++ ) + { + buffer[nBytes++] = ( ism_id->id[n] & MASK_8BIT ); + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMID( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n; + IVAS_PIDATA_ISM_ID *ism_id = (IVAS_PIDATA_ISM_ID *) piData; + + /* ISM_ID data is 1 byte per object */ + if ( numDataBytes > IVAS_MAX_NUM_OBJECTS ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_ID PI data" ); + } + + ism_id->size = sizeof( IVAS_PIDATA_ISM_ID ); + ism_id->piDataType = IVAS_PI_ISM_ID; + ism_id->numObjects = (uint16_t) numDataBytes; + + /* Unpack ID for each object (1 byte each) */ + for ( n = 0; n < ism_id->numObjects; n++ ) + { + ism_id->id[n] = buffer[n]; + } + for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) + { + ism_id->id[n] = 0; /* Initializing to 0, although there might be another object with this ID */ + } + + return IVAS_ERR_OK; +} + +static ivas_error packISMGain( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n, idx; + int16_t gain; + const IVAS_PIDATA_ISM_GAIN *ism_gain = (const IVAS_PIDATA_ISM_GAIN *) piData; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_GAIN ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_GAIN PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_GAIN ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_GAIN PI data" ); + } + + /* ISM_GAIN data is 1 byte per object, header is 2 bytes */ + if ( maxDataBytes < 1 * IVAS_MAX_NUM_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_GAIN PI data" ); + } + + buffer[nBytes++] = ( ism_gain->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) ism_gain->numObjects; + /* Pack ID for each object */ + for ( n = 0; n < ism_gain->numObjects; n++ ) + { + gain = (int16_t) ism_gain->dB[n]; + idx = min( -gain, 25 ); + if ( gain > 0 ) + { + idx += 25; + } + + buffer[nBytes++] = ( idx & MASK_6BIT ) << 2; + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMGain( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n, idx; + IVAS_PIDATA_ISM_GAIN *ism_gain = (IVAS_PIDATA_ISM_GAIN *) piData; + + /* ISM_GAIN data is 1 byte per object */ + if ( numDataBytes > IVAS_MAX_NUM_OBJECTS ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_GAIN PI data" ); + } + + ism_gain->size = sizeof( IVAS_PIDATA_ISM_GAIN ); + ism_gain->piDataType = IVAS_PI_ISM_GAIN; + ism_gain->numObjects = (uint16_t) numDataBytes; + + /* Unpack ID for each object (1 byte each) */ + for ( n = 0; n < ism_gain->numObjects; n++ ) + { + idx = ( buffer[n] ) >> 2; + /* negative gains*/ + if ( idx < 25 ) + { + ism_gain->dB[n] = -(int8_t) ( idx ); + } + /* Set to min for muting, to be interpreted as -Inf */ + else if ( idx == 25 ) + { + ism_gain->dB[n] = -128; + } + /* postive gains */ + else if ( idx < 38 ) + { + ism_gain->dB[n] = (int8_t) idx - 25; + } + else + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect index for ISM_GAIN PI data" ); + } + } + for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) + { + ism_gain->dB[n] = 0; /* Set to default */ + } + return IVAS_ERR_OK; +} + +static ivas_error packISMDistanceAttenuation( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_ATTENUATION *ism_att = (const IVAS_PIDATA_ISM_ATTENUATION *) piData; + uint32_t lWord; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_ATTENUATION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_DISTANCE_ATTENUATION PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_DISTANCE_ATTENUATION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_DISTANCE_ATTENUATION PI data" ); + } + + /* ISM_DISTANCE_ATTENUATION data is 3 bytes per object, header is 2 bytes */ + if ( maxDataBytes > 3 * IVAS_MAX_NUM_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_DISTANCE_ATTENUATION PI data" ); + } + + buffer[nBytes++] = ( ism_att->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) ism_att->numObjects * 3; + /* Pack ID for each object */ + for ( n = 0; n < ism_att->numObjects; n++ ) + { + if ( ism_att->distAtten[n].ref_dist < 0 || ism_att->distAtten[n].max_dist < 0 || ism_att->distAtten[n].roll < 0 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect DISTANCE ATTENUATION data" ); + } + lWord = (uint32_t) ( min( (uint16_t) ( ism_att->distAtten[n].ref_dist * 10.0f + 0.5f ) - 1, 63 ) << 18 ); + lWord |= (uint32_t) ( min( (uint16_t) ( ism_att->distAtten[n].max_dist + 0.5f ) - 1, 63 ) << 12 ); + lWord |= (uint32_t) ( min( (uint16_t) ( ism_att->distAtten[n].roll * 10.0f + 0.5f ), 40 ) << 6 ); + + buffer[nBytes++] = ( lWord >> 16 ) & MASK_8BIT; + buffer[nBytes++] = ( lWord >> 8 ) & MASK_8BIT; + buffer[nBytes++] = lWord & MASK_8BIT; + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMDistanceAttenuation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n, lWord; + IVAS_PIDATA_ISM_ATTENUATION *ism_att = (IVAS_PIDATA_ISM_ATTENUATION *) piData; + + /* ISM_DISTANCE_ATTENUATION data is 3 bytes per object */ + if ( numDataBytes % 3 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_DISTANCE_ATTENUATION PI data" ); + } + + ism_att->size = sizeof( IVAS_PIDATA_ISM_ATTENUATION ); + ism_att->piDataType = IVAS_PI_ISM_DISTANCE_ATTENUATION; + ism_att->numObjects = (uint16_t) numDataBytes / 3; + + /* Unpack attenuation for each object (3 bytes each) */ + for ( n = 0; n < ism_att->numObjects; n++ ) + { + lWord = ( buffer[3 * n] ) << 16; + lWord |= ( buffer[3 * n + 1] ) << 8; + lWord |= buffer[3 * n + 2]; + + ism_att->distAtten[n].ref_dist = ( ( ( lWord >> 18 ) & MASK_6BIT ) + 1 ) / 10.0f; + ism_att->distAtten[n].max_dist = (float) ( ( lWord >> 12 ) & MASK_6BIT ) + 1; + ism_att->distAtten[n].roll = ( ( lWord >> 6 ) & MASK_6BIT ) / 10.0f; + } + for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) + { + ism_att->distAtten[n].ref_dist = 1.0f; /* Set to default */ + ism_att->distAtten[n].max_dist = 16.0f; /* Set to default */ + ism_att->distAtten[n].roll = 1.0f; /* Set to default */ + } + return IVAS_ERR_OK; +} +static ivas_error packISMDirectivity( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_DIRECTIVITY *ism_directivity = (const IVAS_PIDATA_ISM_DIRECTIVITY *) piData; + uint16_t word, idx; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_DIRECTIVITY ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_DIRECTIVITY PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_DIRECTIVITY ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_DIRECTIVITY PI data" ); + } + + /* ISM_DIRECTIVITY data is 2 bytes per object, header is 2 bytes */ + if ( maxDataBytes > 2 * IVAS_MAX_NUM_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_DIRECTIVITY PI data" ); + } + + buffer[nBytes++] = ( ism_directivity->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) ism_directivity->numObjects * 2; + /* Pack directivity for each object */ + for ( n = 0; n < ism_directivity->numObjects; n++ ) + { + word = (uint16_t) ( min( ism_directivity->directivity[n].innerConeAngle / 15, 24 ) << 11 ); + word |= (uint16_t) ( min( ism_directivity->directivity[n].outerConeAngle / 15, 24 ) << 6 ); + + idx = 0; + /* For outer attenuation < -90 dB, idx = 0, which corresponds to -Inf (muting) */ + if ( ism_directivity->directivity[n].outerAttenuationdB >= -90.0f ) + { + idx = 32 - (uint16_t) ( -ism_directivity->directivity[n].outerAttenuationdB / 3.0f + 0.5f ); + } + word |= (uint16_t) ( min( idx, 31 ) << 1 ); + + buffer[nBytes++] = ( word >> 8 ) & MASK_8BIT; + buffer[nBytes++] = word & MASK_8BIT; + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMDirectivity( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n; + uint16_t word, idx; + IVAS_PIDATA_ISM_DIRECTIVITY *ism_directivity = (IVAS_PIDATA_ISM_DIRECTIVITY *) piData; + + /* ISM_DIRECTIVITY data is 2 bytes per object */ + if ( numDataBytes % 2 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_DIRECTIVITY PI data" ); + } + + ism_directivity->size = sizeof( IVAS_PIDATA_ISM_DIRECTIVITY ); + ism_directivity->piDataType = IVAS_PI_ISM_DIRECTIVITY; + ism_directivity->numObjects = (uint16_t) numDataBytes / 2; + + /* Unpack directivity for each object (2 bytes each) */ + for ( n = 0; n < ism_directivity->numObjects; n++ ) + { + word = ( buffer[2 * n] ) << 8; + word |= ( buffer[2 * n + 1] ); + + ism_directivity->directivity[n].innerConeAngle = ( ( word >> 11 ) & MASK_5BIT ) * 15; + ism_directivity->directivity[n].outerConeAngle = ( ( word >> 6 ) & MASK_5BIT ) * 15; + idx = ( word >> 1 ) & MASK_5BIT; + + if ( idx == 0 ) + { + ism_directivity->directivity[n].outerAttenuationdB = -128.0f; /* corresponds to muting */ + } + else + { + ism_directivity->directivity[n].outerAttenuationdB = -3.0f * ( 31 - ( ( word >> 1 ) & MASK_5BIT ) ); + } + } + for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) + { + ism_directivity->directivity[n].innerConeAngle = 360; /* Set to default */ + ism_directivity->directivity[n].outerConeAngle = 360; /* Set to default */ + ism_directivity->directivity[n].outerAttenuationdB = 0; /* Set to default */ + } + return IVAS_ERR_OK; +} +#endif #endif /* RTP_S4_251135_CR26253_0016_REV1 */ @@ -641,25 +1155,35 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 packAudioDescription, /* AUDIO_DESCRIPTION */ #else - packUnsupportedData, /* AUDIO_DESCRIPTION */ -#endif /* RTP_S4_251135_CR26253_0016_REV1 */ - packUnsupportedData, /* ISM_NUM */ - packUnsupportedData, /* ISM_ID */ - packUnsupportedData, /* ISM_GAIN */ - packUnsupportedData, /* ISM_ORIENTATION */ - packUnsupportedData, /* ISM_POSITION */ - packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ - packUnsupportedData, /* ISM_DIRECTIVITY */ + packUnsupportedData, /* AUDIO_DESCRIPTION */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ +#ifdef ISM_PI_DATA + packISMNum, /* ISM_NUM */ + packISMID, /* ISM_ID */ + packISMGain, /* ISM_GAIN */ + packISMOrientation, /* ISM_ORIENTATION */ + packISMPosition, /* ISM_POSITION */ + packISMDistanceAttenuation, /* ISM_DISTANCE_ATTENUATION */ + packISMDirectivity, /* ISM_DIRECTIVITY */ +#else + packUnsupportedData, /* ISM_NUM */ + packUnsupportedData, /* ISM_ID */ + packUnsupportedData, /* ISM_GAIN */ + packUnsupportedData, /* ISM_ORIENTATION */ + packUnsupportedData, /* ISM_POSITION */ + packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + packUnsupportedData, /* ISM_DIRECTIVITY */ +#endif #ifdef RTP_S4_251135_CR26253_0016_REV1 packDiegetic, /* DIEGETIC_TYPE */ #else - packUnsupportedData, /* DIEGETIC_TYPE */ + packUnsupportedData, /* DIEGETIC_TYPE */ #endif packUnsupportedData, /* RESERVED13 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 packAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ #else - packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ + packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ #endif packUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 @@ -669,11 +1193,11 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ packAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ #else - packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ - packUnsupportedData, /* HEAD_ORIENTATION */ - packUnsupportedData, /* LISTENER_POSITION */ - packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ - packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ + packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ + packUnsupportedData, /* HEAD_ORIENTATION */ + packUnsupportedData, /* LISTENER_POSITION */ + packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ + packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif packUnsupportedData, /* PI_LATENCY */ packUnsupportedData, /* R_ISM_ID */ @@ -681,7 +1205,7 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 packOrientation, /* R_ISM_ORIENTATION */ #else - packUnsupportedData, /* R_ISM_ORIENTATION */ + packUnsupportedData, /* R_ISM_ORIENTATION */ #endif packUnsupportedData, /* R_ISM_POSITION */ packUnsupportedData, /* R_ISM_DIRECTION */ @@ -700,27 +1224,37 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackAudioDescription, /* AUDIO_DESCRIPTION */ #else - unpackUnsupportedData, /* AUDIO_DESCRIPTION */ + unpackUnsupportedData, /* AUDIO_DESCRIPTION */ +#endif +#ifdef ISM_PI_DATA + unpackISMNum, /* ISM_NUM */ + unpackISMID, /* ISM_ID */ + unpackISMGain, /* ISM_GAIN */ + unpackISMOrientation, /* ISM_ORIENTATION */ + unpackISMPosition, /* ISM_POSITION */ + unpackISMDistanceAttenuation, /* ISM_DISTANCE_ATTENUATION */ + unpackISMDirectivity, /* ISM_DIRECTIVITY */ +#else + unpackUnsupportedData, /* ISM_NUM */ + unpackUnsupportedData, /* ISM_ID */ + unpackUnsupportedData, /* ISM_GAIN */ + unpackUnsupportedData, /* ISM_ORIENTATION */ + unpackUnsupportedData, /* ISM_POSITION */ + unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + unpackUnsupportedData, /* ISM_DIRECTIVITY */ #endif - unpackUnsupportedData, /* ISM_NUM */ - unpackUnsupportedData, /* ISM_ID */ - unpackUnsupportedData, /* ISM_GAIN */ - unpackUnsupportedData, /* ISM_ORIENTATION */ - unpackUnsupportedData, /* ISM_POSITION */ - unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ - unpackUnsupportedData, /* ISM_DIRECTIVITY */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackDiegetic, /* DIEGETIC_TYPE */ + unpackDiegetic, /* DIEGETIC_TYPE */ #else unpackUnsupportedData, /* DIEGETIC_TYPE */ #endif - unpackUnsupportedData, /* RESERVED13 */ + unpackUnsupportedData, /* RESERVED13 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ + unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ #else unpackUnsupportedData, /* AUDIO_FOCUS_INDICATION */ #endif - unpackUnsupportedData, /* RESERVED15 */ + unpackUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ unpackOrientation, /* HEAD_ORIENTATION */ @@ -734,21 +1268,21 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif - unpackUnsupportedData, /* PI_LATENCY */ - unpackUnsupportedData, /* R_ISM_ID */ - unpackUnsupportedData, /* R_ISM_GAIN */ + unpackUnsupportedData, /* PI_LATENCY */ + unpackUnsupportedData, /* R_ISM_ID */ + unpackUnsupportedData, /* R_ISM_GAIN */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackOrientation, /* R_ISM_ORIENTATION */ + unpackOrientation, /* R_ISM_ORIENTATION */ #else unpackUnsupportedData, /* R_ISM_ORIENTATION */ #endif - unpackUnsupportedData, /* R_ISM_POSITION */ - unpackUnsupportedData, /* R_ISM_DIRECTION */ - unpackUnsupportedData, /* RESERVED27 */ - unpackUnsupportedData, /* RESERVED28 */ - unpackUnsupportedData, /* RESERVED29 */ - unpackUnsupportedData, /* RESERVED30 */ - unpackNoPiData /* NO_DATA */ + unpackUnsupportedData, /* R_ISM_POSITION */ + unpackUnsupportedData, /* R_ISM_DIRECTION */ + unpackUnsupportedData, /* RESERVED27 */ + unpackUnsupportedData, /* RESERVED28 */ + unpackUnsupportedData, /* RESERVED29 */ + unpackUnsupportedData, /* RESERVED30 */ + unpackNoPiData /* NO_DATA */ }; static const uint32_t maxPiDataSize[IVAS_PI_MAX_ID] = { diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index dc4c7f8ba..85e41ed37 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -207,6 +207,9 @@ typedef struct { size_t size; /* sizeof(IVAS_PIDATA_ISM_ID) */ uint32_t piDataType; /* IVAS_PI_ISM_ID */ +#ifdef ISM_PI_DATA + uint16_t numObjects; /* number of objects */ +#endif uint8_t id[IVAS_MAX_NUM_OBJECTS]; /* 8-bit ISM id of object */ } IVAS_PIDATA_ISM_ID; @@ -215,6 +218,9 @@ typedef struct { size_t size; /* sizeof(IVAS_PIDATA_ISM_GAIN) */ uint32_t piDataType; /* IVAS_PI_ISM_GAIN */ +#ifdef ISM_PI_DATA + uint16_t numObjects; /* number of objects */ +#endif int8_t dB[IVAS_MAX_NUM_OBJECTS]; /* ISM gain in dB per object [-96, +3] */ } IVAS_PIDATA_ISM_GAIN; @@ -223,6 +229,9 @@ typedef struct { size_t size; /* sizeof(IVAS_PIDATA_ISM_ORIENTATION) */ uint32_t piDataType; /* IVAS_PI_ISM_ORIENTATION */ +#ifdef ISM_PI_DATA + uint16_t numObjects; /* number of objects */ +#endif IVAS_QUATERNION orientation[IVAS_MAX_NUM_OBJECTS]; /* Orientation of audio objects in ISM(s) */ } IVAS_PIDATA_ISM_ORIENTATION; @@ -231,6 +240,9 @@ typedef struct { size_t size; /* sizeof(IVAS_PIDATA_ISM_POSITION) */ uint32_t piDataType; /* IVAS_PI_ISM_POSITION */ +#ifdef ISM_PI_DATA + uint16_t numObjects; /* number of objects */ +#endif IVAS_COORDINATE position[IVAS_MAX_NUM_OBJECTS]; /* Position of audio objects in ISM(s) */ } IVAS_PIDATA_ISM_POSITION; @@ -250,6 +262,9 @@ typedef struct { size_t size; /* sizeof(IVAS_PIDATA_ISM_ATTENUATION) */ uint32_t piDataType; /* IVAS_PI_ISM_DISTANCE_ATTENUATION */ +#ifdef ISM_PI_DATA + uint16_t numObjects; /* number of objects */ +#endif IVAS_DIST_ATTEN distAtten[IVAS_MAX_NUM_OBJECTS]; /* Distance attenuation of audio objects */ } IVAS_PIDATA_ISM_ATTENUATION; @@ -269,6 +284,9 @@ typedef struct { size_t size; /* sizeof(IVAS_PIDATA_ISM_DIRECTIVITY) */ uint32_t piDataType; /* IVAS_PI_ISM_DIRECTIVITY */ +#ifdef ISM_PI_DATA + uint16_t numObjects; /* number of objects */ +#endif IVAS_ISM_DIRECTIVITY directivity[IVAS_MAX_NUM_OBJECTS]; /* Directivity of audio objects */ } IVAS_PIDATA_ISM_DIRECTIVITY; -- GitLab From dc3803ad41f5232a1e9bb24c3e8e6fee550bd5b9 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 18:24:30 +0200 Subject: [PATCH 27/34] Fix cmake build --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0347d98a1..21bb3e738 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,7 +174,7 @@ file(GLOB libDecSrcs "lib_dec/*.c") file(GLOB libDecHeaders "lib_dec/*.h") add_library(lib_dec ${libDecSrcs} ${libDecHeaders}) target_link_libraries(lib_dec lib_com lib_basop lib_rend lib_debug lib_isar) -target_include_directories(lib_dec PUBLIC lib_dec lib_rend PRIVATE lib_basop lib_enc lib_isar) +target_include_directories(lib_dec PUBLIC lib_dec lib_rend PRIVATE lib_basop lib_enc lib_isar lib_util) file(GLOB libUtilSrcs "lib_util/*.c") file(GLOB libUtilHeaders "lib_util/*.h") -- GitLab From dcf7dd4d1a4710948e7a40f1dddeba3fb2d39595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Toftg=C3=A5rd?= Date: Mon, 10 Nov 2025 17:31:06 +0100 Subject: [PATCH 28/34] Clang formatting --- lib_util/ivas_rtp_file.c | 472 ++++++++++++++++++------------------ lib_util/ivas_rtp_pi_data.c | 78 +++--- lib_util/ivas_rtp_pi_data.h | 24 +- 3 files changed, 287 insertions(+), 287 deletions(-) diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index e3dfbde4d..0bf820df4 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -172,298 +172,298 @@ void IVAS_RTP_LogPiData( if ( ftell( f_piDataOut ) > 2 ) #endif - while ( nPiDataPresent-- > 0 ) - { - const PIDATA_TS *cur = piData++; - - if ( timestamp != ( ~0u ) && timestamp != cur->timestamp ) - { - fprintf( f_piDataOut, "\n\t},\n\t\"%d\": {\n", cur->timestamp ); - } - else if ( timestamp != cur->timestamp ) - { - fprintf( f_piDataOut, "\t\"%d\": {\n", cur->timestamp ); - } - else - { - fprintf( f_piDataOut, ",\n" ); - } - fprintf( f_piDataOut, "\t\t\"%s\" : ", PiDataNames[cur->data.noPiData.piDataType] ); - switch ( cur->data.noPiData.piDataType ) + while ( nPiDataPresent-- > 0 ) { - case IVAS_PI_SCENE_ORIENTATION: - case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: - case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: -#ifdef RTP_S4_251135_CR26253_0016_REV1 - case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: - case IVAS_PI_HEAD_ORIENTATION: - case IVAS_PI_R_ISM_ORIENTATION: -#endif + const PIDATA_TS *cur = piData++; + + if ( timestamp != ( ~0u ) && timestamp != cur->timestamp ) { - fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", - fixedToFloat( cur->data.scene.orientation.w_fx, Q15 ), - fixedToFloat( cur->data.scene.orientation.x_fx, Q15 ), - fixedToFloat( cur->data.scene.orientation.y_fx, Q15 ), - fixedToFloat( cur->data.scene.orientation.z_fx, Q15 ) ); + fprintf( f_piDataOut, "\n\t},\n\t\"%d\": {\n", cur->timestamp ); } - break; - - case IVAS_PI_ACOUSTIC_ENVIRONMENT: + else if ( timestamp != cur->timestamp ) { - fprintf( f_piDataOut, "{\n\t\t\t\"aeid\": %d", cur->data.acousticEnv.aeid ); - if ( cur->data.acousticEnv.availLateReverb ) + fprintf( f_piDataOut, "\t\"%d\": {\n", cur->timestamp ); + } + else + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\"%s\" : ", PiDataNames[cur->data.noPiData.piDataType] ); + switch ( cur->data.noPiData.piDataType ) + { + case IVAS_PI_SCENE_ORIENTATION: + case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: + case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: + case IVAS_PI_HEAD_ORIENTATION: + case IVAS_PI_R_ISM_ORIENTATION: +#endif { - fprintf( f_piDataOut, ",\n\t\t\t\"rt60\": [ %f, %f, %f ],\n", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] ); - fprintf( f_piDataOut, "\t\t\t\"dsr\": [ %f, %f, %f ]", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] ); + fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + fixedToFloat( cur->data.scene.orientation.w_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.x_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.y_fx, Q15 ), + fixedToFloat( cur->data.scene.orientation.z_fx, Q15 ) ); } - if ( cur->data.acousticEnv.availEarlyReflections ) + break; + + case IVAS_PI_ACOUSTIC_ENVIRONMENT: { - fprintf( f_piDataOut, ",\n\t\t\t\"dim\": [ %f, %f, %f ],\n", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z ); - fprintf( f_piDataOut, "\t\t\t\"abscoeff\": [ %f, %f, %f, %f, %f, %f ]", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] ); + fprintf( f_piDataOut, "{\n\t\t\t\"aeid\": %d", cur->data.acousticEnv.aeid ); + if ( cur->data.acousticEnv.availLateReverb ) + { + fprintf( f_piDataOut, ",\n\t\t\t\"rt60\": [ %f, %f, %f ],\n", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] ); + fprintf( f_piDataOut, "\t\t\t\"dsr\": [ %f, %f, %f ]", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] ); + } + if ( cur->data.acousticEnv.availEarlyReflections ) + { + fprintf( f_piDataOut, ",\n\t\t\t\"dim\": [ %f, %f, %f ],\n", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z ); + fprintf( f_piDataOut, "\t\t\t\"abscoeff\": [ %f, %f, %f, %f, %f, %f ]", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] ); + } + fprintf( f_piDataOut, "\n\t\t}" ); } - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; + break; #ifdef RTP_S4_251135_CR26253_0016_REV1 - case IVAS_PI_LISTENER_POSITION: - case IVAS_PI_R_ISM_POSITION: - { - fprintf( f_piDataOut, "{\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", - cur->data.listnerPosition.position.x, cur->data.listnerPosition.position.y, cur->data.listnerPosition.position.z ); - } - break; - case IVAS_PI_AUDIO_DESCRIPTION: - { - uint32_t nEntries = cur->data.audioDesc.nValidEntries; - const IVAS_AUDIO_ID *audioId = cur->data.audioDesc.audioId; + case IVAS_PI_LISTENER_POSITION: + case IVAS_PI_R_ISM_POSITION: + { + fprintf( f_piDataOut, "{\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}", + cur->data.listnerPosition.position.x, cur->data.listnerPosition.position.y, cur->data.listnerPosition.position.z ); + } + break; + case IVAS_PI_AUDIO_DESCRIPTION: + { + uint32_t nEntries = cur->data.audioDesc.nValidEntries; + const IVAS_AUDIO_ID *audioId = cur->data.audioDesc.audioId; - fprintf( f_piDataOut, "[\n" ); - while ( nEntries-- > 0 ) + fprintf( f_piDataOut, "[\n" ); + while ( nEntries-- > 0 ) + { + fprintf( f_piDataOut, "\t\t\t{\n" ); + fprintf( f_piDataOut, "\t\t\t\t\"isSpeech\": %s,\n", audioId->speech ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isMusic\": %s,\n", audioId->music ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isAmbiance\": %s,\n", audioId->ambiance ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isEditable\": %s,\n", audioId->editable ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t\"isBinaural\": %s\n", audioId->binaural ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t}%c\n", ( nEntries == 0 ) ? ' ' : ',' ); + audioId++; + } + fprintf( f_piDataOut, "\t\t]" ); + } + break; + case IVAS_PI_DIEGETIC_TYPE: { - fprintf( f_piDataOut, "\t\t\t{\n" ); - fprintf( f_piDataOut, "\t\t\t\t\"isSpeech\": %s,\n", audioId->speech ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t\"isMusic\": %s,\n", audioId->music ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t\"isAmbiance\": %s,\n", audioId->ambiance ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t\"isEditable\": %s,\n", audioId->editable ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t\"isBinaural\": %s\n", audioId->binaural ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t}%c\n", ( nEntries == 0 ) ? ' ' : ',' ); - audioId++; + const bool *isDiegetic = cur->data.digeticIndicator.isDiegetic; + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"isDigetic\": [\n" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[0] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[1] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[2] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[3] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\t%s\n", isDiegetic[4] ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t]\n\t\t}" ); } - fprintf( f_piDataOut, "\t\t]" ); - } - break; - case IVAS_PI_DIEGETIC_TYPE: - { - const bool *isDiegetic = cur->data.digeticIndicator.isDiegetic; - fprintf( f_piDataOut, "{\n" ); - fprintf( f_piDataOut, "\t\t\t\"isDigetic\": [\n" ); - fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[0] ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[1] ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[2] ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[3] ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\t%s\n", isDiegetic[4] ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t]\n\t\t}" ); - } - break; - case IVAS_PI_AUDIO_FOCUS_INDICATION: - { - fprintf( f_piDataOut, "{" ); - if ( cur->data.focusIndication.availDirection ) + break; + case IVAS_PI_AUDIO_FOCUS_INDICATION: { - fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); - fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", - fixedToFloat( cur->data.focusIndication.direction.w_fx, Q15 ), - fixedToFloat( cur->data.focusIndication.direction.x_fx, Q15 ), - fixedToFloat( cur->data.focusIndication.direction.y_fx, Q15 ), - fixedToFloat( cur->data.focusIndication.direction.z_fx, Q15 ) ); + fprintf( f_piDataOut, "{" ); + if ( cur->data.focusIndication.availDirection ) + { + fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", + fixedToFloat( cur->data.focusIndication.direction.w_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.x_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.y_fx, Q15 ), + fixedToFloat( cur->data.focusIndication.direction.z_fx, Q15 ) ); + if ( cur->data.focusIndication.availLevel ) + { + fprintf( f_piDataOut, "," ); + } + } if ( cur->data.focusIndication.availLevel ) { - fprintf( f_piDataOut, "," ); + fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusIndication.flvl ); } + fprintf( f_piDataOut, "\n\t\t}" ); } - if ( cur->data.focusIndication.availLevel ) + break; + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_REQUEST: { - fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusIndication.flvl ); + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionRequest; + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli ); + fprintf( f_piDataOut, "\n\t\t}" ); } - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_REQUEST: - { - const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionRequest; - fprintf( f_piDataOut, "{\n" ); - fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli ); - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_INDICATION: - { - const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionIndication; - fprintf( f_piDataOut, "{\n" ); - fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" ); - fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli ); - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_AUDIO_FOCUS_REQUEST: - { - fprintf( f_piDataOut, "{" ); - if ( cur->data.focusRequest.availDirection ) + break; + case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION_INDICATION: { - fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); - fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", - fixedToFloat( cur->data.focusRequest.direction.w_fx, Q15 ), - fixedToFloat( cur->data.focusRequest.direction.x_fx, Q15 ), - fixedToFloat( cur->data.focusRequest.direction.y_fx, Q15 ), - fixedToFloat( cur->data.focusRequest.direction.z_fx, Q15 ) ); + const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppressionIndication; + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" ); + fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_AUDIO_FOCUS_REQUEST: + { + fprintf( f_piDataOut, "{" ); + if ( cur->data.focusRequest.availDirection ) + { + fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" ); + fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}", + fixedToFloat( cur->data.focusRequest.direction.w_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.x_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.y_fx, Q15 ), + fixedToFloat( cur->data.focusRequest.direction.z_fx, Q15 ) ); + if ( cur->data.focusRequest.availLevel ) + { + fprintf( f_piDataOut, "," ); + } + } if ( cur->data.focusRequest.availLevel ) { - fprintf( f_piDataOut, "," ); + fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusRequest.flvl ); } + fprintf( f_piDataOut, "\n\t\t}" ); } - if ( cur->data.focusRequest.availLevel ) + break; + case IVAS_PI_RESERVED15: + case IVAS_PI_RESERVED27: + case IVAS_PI_RESERVED28: + case IVAS_PI_RESERVED29: + case IVAS_PI_RESERVED30: { - fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusRequest.flvl ); + fprintf( f_piDataOut, "{}" ); } - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_RESERVED15: - case IVAS_PI_RESERVED27: - case IVAS_PI_RESERVED28: - case IVAS_PI_RESERVED29: - case IVAS_PI_RESERVED30: - { - fprintf( f_piDataOut, "{}" ); - } - break; + break; #ifdef ISM_PI_DATA - case IVAS_PI_ISM_ORIENTATION: - { - fprintf( f_piDataOut, "[\n" ); - for ( n = 0; n < cur->data.ismOrientation.numObjects; n++ ) + case IVAS_PI_ISM_ORIENTATION: { - if ( n != 0 ) + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismOrientation.numObjects; n++ ) { - fprintf( f_piDataOut, ",\n" ); + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"w\": %f,\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", + fixedToFloat( cur->data.ismOrientation.orientation[n].w_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[n].x_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[n].y_fx, Q15 ), + fixedToFloat( cur->data.ismOrientation.orientation[n].z_fx, Q15 ) ); } - fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"w\": %f,\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", - fixedToFloat( cur->data.ismOrientation.orientation[n].w_fx, Q15 ), - fixedToFloat( cur->data.ismOrientation.orientation[n].x_fx, Q15 ), - fixedToFloat( cur->data.ismOrientation.orientation[n].y_fx, Q15 ), - fixedToFloat( cur->data.ismOrientation.orientation[n].z_fx, Q15 ) ); + fprintf( f_piDataOut, "\n\t\t]" ); } - fprintf( f_piDataOut, "\n\t\t]" ); - } - break; - case IVAS_PI_ISM_NUM: - { - fprintf( f_piDataOut, "{\n" ); - fprintf( f_piDataOut, "\t\t\t\"num\": %d", cur->data.ismNum.numObjects ); - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_ISM_ID: - { - fprintf( f_piDataOut, "{\n" ); - fprintf( f_piDataOut, "\t\t\t\"ids\": [\n" ); - for ( n = 0; n < cur->data.ismId.numObjects; n++ ) + break; + case IVAS_PI_ISM_NUM: + { + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"num\": %d", cur->data.ismNum.numObjects ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; + case IVAS_PI_ISM_ID: { - if ( n != 0 ) + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"ids\": [\n" ); + for ( n = 0; n < cur->data.ismId.numObjects; n++ ) { - fprintf( f_piDataOut, ",\n" ); + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t\t%d", cur->data.ismId.id[n] ); } - fprintf( f_piDataOut, "\t\t\t\t%d", cur->data.ismId.id[n] ); + fprintf( f_piDataOut, "\n\t\t\t]" ); + fprintf( f_piDataOut, "\n\t\t}" ); } - fprintf( f_piDataOut, "\n\t\t\t]" ); - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_ISM_GAIN: - { - fprintf( f_piDataOut, "{\n" ); - fprintf( f_piDataOut, "\t\t\t\"gains\": [\n" ); - for ( n = 0; n < cur->data.ismGain.numObjects; n++ ) + break; + case IVAS_PI_ISM_GAIN: { - if ( n != 0 ) + fprintf( f_piDataOut, "{\n" ); + fprintf( f_piDataOut, "\t\t\t\"gains\": [\n" ); + for ( n = 0; n < cur->data.ismGain.numObjects; n++ ) { - fprintf( f_piDataOut, ",\n" ); + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t\t%d", cur->data.ismGain.dB[n] ); } - fprintf( f_piDataOut, "\t\t\t\t%d", cur->data.ismGain.dB[n] ); + fprintf( f_piDataOut, "\n\t\t\t]" ); + fprintf( f_piDataOut, "\n\t\t}" ); } - fprintf( f_piDataOut, "\n\t\t\t]" ); - fprintf( f_piDataOut, "\n\t\t}" ); - } - break; - case IVAS_PI_ISM_POSITION: - { - fprintf( f_piDataOut, "[\n" ); - for ( n = 0; n < cur->data.ismPosition.numObjects; n++ ) + break; + case IVAS_PI_ISM_POSITION: { - if ( n != 0 ) + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismPosition.numObjects; n++ ) { - fprintf( f_piDataOut, ",\n" ); + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", cur->data.ismPosition.position[n].x, cur->data.ismPosition.position[n].y, cur->data.ismPosition.position[n].z ); } - fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", cur->data.ismPosition.position[n].x, cur->data.ismPosition.position[n].y, cur->data.ismPosition.position[n].z ); + fprintf( f_piDataOut, "\n\t\t]" ); } - fprintf( f_piDataOut, "\n\t\t]" ); - } - break; - case IVAS_PI_ISM_DISTANCE_ATTENUATION: - { - fprintf( f_piDataOut, "[\n" ); - for ( n = 0; n < cur->data.ismAttenuation.numObjects; n++ ) + break; + case IVAS_PI_ISM_DISTANCE_ATTENUATION: { - if ( n != 0 ) + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismAttenuation.numObjects; n++ ) { - fprintf( f_piDataOut, ",\n" ); + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"ref_dist\": %f,\n\t\t\t\t\"max_dist\": %f,\n\t\t\t\t\"roll_off\": %f \n\t\t\t}", cur->data.ismAttenuation.distAtten[n].ref_dist, cur->data.ismAttenuation.distAtten[n].max_dist, cur->data.ismAttenuation.distAtten[n].roll ); } - fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"ref_dist\": %f,\n\t\t\t\t\"max_dist\": %f,\n\t\t\t\t\"roll_off\": %f \n\t\t\t}", cur->data.ismAttenuation.distAtten[n].ref_dist, cur->data.ismAttenuation.distAtten[n].max_dist, cur->data.ismAttenuation.distAtten[n].roll ); + fprintf( f_piDataOut, "\n\t\t]" ); } - fprintf( f_piDataOut, "\n\t\t]" ); - } - break; - case IVAS_PI_ISM_DIRECTIVITY: - { - fprintf( f_piDataOut, "[\n" ); - for ( n = 0; n < cur->data.ismDirectivity.numObjects; n++ ) + break; + case IVAS_PI_ISM_DIRECTIVITY: { - if ( n != 0 ) + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismDirectivity.numObjects; n++ ) { - fprintf( f_piDataOut, ",\n" ); + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"inner_ang\": %d,\n\t\t\t\t\"outer_ang\": %d,\n\t\t\t\t\"outer_att\": %f \n\t\t\t}", cur->data.ismDirectivity.directivity[n].innerConeAngle, cur->data.ismDirectivity.directivity[n].outerConeAngle, cur->data.ismDirectivity.directivity[n].outerAttenuationdB ); } - fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"inner_ang\": %d,\n\t\t\t\t\"outer_ang\": %d,\n\t\t\t\t\"outer_att\": %f \n\t\t\t}", cur->data.ismDirectivity.directivity[n].innerConeAngle, cur->data.ismDirectivity.directivity[n].outerConeAngle, cur->data.ismDirectivity.directivity[n].outerAttenuationdB ); + fprintf( f_piDataOut, "\n\t\t]" ); } - fprintf( f_piDataOut, "\n\t\t]" ); - } - break; + break; #else - case IVAS_PI_ISM_NUM: - case IVAS_PI_ISM_ID: - case IVAS_PI_ISM_GAIN: - case IVAS_PI_ISM_ORIENTATION: - case IVAS_PI_ISM_POSITION: - case IVAS_PI_ISM_DISTANCE_ATTENUATION: - case IVAS_PI_ISM_DIRECTIVITY: + case IVAS_PI_ISM_NUM: + case IVAS_PI_ISM_ID: + case IVAS_PI_ISM_GAIN: + case IVAS_PI_ISM_ORIENTATION: + case IVAS_PI_ISM_POSITION: + case IVAS_PI_ISM_DISTANCE_ATTENUATION: + case IVAS_PI_ISM_DIRECTIVITY: #endif - case IVAS_PI_PI_LATENCY: - case IVAS_PI_R_ISM_ID: - case IVAS_PI_R_ISM_GAIN: - case IVAS_PI_R_ISM_DIRECTION: + case IVAS_PI_PI_LATENCY: + case IVAS_PI_R_ISM_ID: + case IVAS_PI_R_ISM_GAIN: + case IVAS_PI_R_ISM_DIRECTION: #endif /* RTP_S4_251135_CR26253_0016_REV1 */ - case IVAS_PI_NO_DATA: - { - fprintf( f_piDataOut, "{}" ); + case IVAS_PI_NO_DATA: + { + fprintf( f_piDataOut, "{}" ); + } + break; } - break; + timestamp = cur->timestamp; } - timestamp = cur->timestamp; - } fprintf( f_piDataOut, "\n\t}" ); } diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index fc4330db3..5281ba716 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -1155,7 +1155,7 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 packAudioDescription, /* AUDIO_DESCRIPTION */ #else - packUnsupportedData, /* AUDIO_DESCRIPTION */ + packUnsupportedData, /* AUDIO_DESCRIPTION */ #endif /* RTP_S4_251135_CR26253_0016_REV1 */ #ifdef ISM_PI_DATA packISMNum, /* ISM_NUM */ @@ -1166,24 +1166,24 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packISMDistanceAttenuation, /* ISM_DISTANCE_ATTENUATION */ packISMDirectivity, /* ISM_DIRECTIVITY */ #else - packUnsupportedData, /* ISM_NUM */ - packUnsupportedData, /* ISM_ID */ - packUnsupportedData, /* ISM_GAIN */ - packUnsupportedData, /* ISM_ORIENTATION */ - packUnsupportedData, /* ISM_POSITION */ - packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ - packUnsupportedData, /* ISM_DIRECTIVITY */ + packUnsupportedData, /* ISM_NUM */ + packUnsupportedData, /* ISM_ID */ + packUnsupportedData, /* ISM_GAIN */ + packUnsupportedData, /* ISM_ORIENTATION */ + packUnsupportedData, /* ISM_POSITION */ + packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + packUnsupportedData, /* ISM_DIRECTIVITY */ #endif #ifdef RTP_S4_251135_CR26253_0016_REV1 packDiegetic, /* DIEGETIC_TYPE */ #else - packUnsupportedData, /* DIEGETIC_TYPE */ + packUnsupportedData, /* DIEGETIC_TYPE */ #endif packUnsupportedData, /* RESERVED13 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 packAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ #else - packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ + packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ #endif packUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 @@ -1193,11 +1193,11 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ packAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ #else - packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ - packUnsupportedData, /* HEAD_ORIENTATION */ - packUnsupportedData, /* LISTENER_POSITION */ - packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ - packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ + packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ + packUnsupportedData, /* HEAD_ORIENTATION */ + packUnsupportedData, /* LISTENER_POSITION */ + packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ + packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif packUnsupportedData, /* PI_LATENCY */ packUnsupportedData, /* R_ISM_ID */ @@ -1205,7 +1205,7 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 packOrientation, /* R_ISM_ORIENTATION */ #else - packUnsupportedData, /* R_ISM_ORIENTATION */ + packUnsupportedData, /* R_ISM_ORIENTATION */ #endif packUnsupportedData, /* R_ISM_POSITION */ packUnsupportedData, /* R_ISM_DIRECTION */ @@ -1224,7 +1224,7 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackAudioDescription, /* AUDIO_DESCRIPTION */ #else - unpackUnsupportedData, /* AUDIO_DESCRIPTION */ + unpackUnsupportedData, /* AUDIO_DESCRIPTION */ #endif #ifdef ISM_PI_DATA unpackISMNum, /* ISM_NUM */ @@ -1235,26 +1235,26 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackISMDistanceAttenuation, /* ISM_DISTANCE_ATTENUATION */ unpackISMDirectivity, /* ISM_DIRECTIVITY */ #else - unpackUnsupportedData, /* ISM_NUM */ - unpackUnsupportedData, /* ISM_ID */ - unpackUnsupportedData, /* ISM_GAIN */ - unpackUnsupportedData, /* ISM_ORIENTATION */ - unpackUnsupportedData, /* ISM_POSITION */ - unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ - unpackUnsupportedData, /* ISM_DIRECTIVITY */ + unpackUnsupportedData, /* ISM_NUM */ + unpackUnsupportedData, /* ISM_ID */ + unpackUnsupportedData, /* ISM_GAIN */ + unpackUnsupportedData, /* ISM_ORIENTATION */ + unpackUnsupportedData, /* ISM_POSITION */ + unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + unpackUnsupportedData, /* ISM_DIRECTIVITY */ #endif #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackDiegetic, /* DIEGETIC_TYPE */ + unpackDiegetic, /* DIEGETIC_TYPE */ #else unpackUnsupportedData, /* DIEGETIC_TYPE */ #endif - unpackUnsupportedData, /* RESERVED13 */ + unpackUnsupportedData, /* RESERVED13 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ + unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ #else unpackUnsupportedData, /* AUDIO_FOCUS_INDICATION */ #endif - unpackUnsupportedData, /* RESERVED15 */ + unpackUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ unpackOrientation, /* HEAD_ORIENTATION */ @@ -1268,21 +1268,21 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif - unpackUnsupportedData, /* PI_LATENCY */ - unpackUnsupportedData, /* R_ISM_ID */ - unpackUnsupportedData, /* R_ISM_GAIN */ + unpackUnsupportedData, /* PI_LATENCY */ + unpackUnsupportedData, /* R_ISM_ID */ + unpackUnsupportedData, /* R_ISM_GAIN */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackOrientation, /* R_ISM_ORIENTATION */ + unpackOrientation, /* R_ISM_ORIENTATION */ #else unpackUnsupportedData, /* R_ISM_ORIENTATION */ #endif - unpackUnsupportedData, /* R_ISM_POSITION */ - unpackUnsupportedData, /* R_ISM_DIRECTION */ - unpackUnsupportedData, /* RESERVED27 */ - unpackUnsupportedData, /* RESERVED28 */ - unpackUnsupportedData, /* RESERVED29 */ - unpackUnsupportedData, /* RESERVED30 */ - unpackNoPiData /* NO_DATA */ + unpackUnsupportedData, /* R_ISM_POSITION */ + unpackUnsupportedData, /* R_ISM_DIRECTION */ + unpackUnsupportedData, /* RESERVED27 */ + unpackUnsupportedData, /* RESERVED28 */ + unpackUnsupportedData, /* RESERVED29 */ + unpackUnsupportedData, /* RESERVED30 */ + unpackNoPiData /* NO_DATA */ }; static const uint32_t maxPiDataSize[IVAS_PI_MAX_ID] = { diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index 85e41ed37..137434a15 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -205,8 +205,8 @@ typedef struct /* ISM ID */ typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_ISM_ID) */ - uint32_t piDataType; /* IVAS_PI_ISM_ID */ + size_t size; /* sizeof(IVAS_PIDATA_ISM_ID) */ + uint32_t piDataType; /* IVAS_PI_ISM_ID */ #ifdef ISM_PI_DATA uint16_t numObjects; /* number of objects */ #endif @@ -216,8 +216,8 @@ typedef struct /* ISM gain */ typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_ISM_GAIN) */ - uint32_t piDataType; /* IVAS_PI_ISM_GAIN */ + size_t size; /* sizeof(IVAS_PIDATA_ISM_GAIN) */ + uint32_t piDataType; /* IVAS_PI_ISM_GAIN */ #ifdef ISM_PI_DATA uint16_t numObjects; /* number of objects */ #endif @@ -227,8 +227,8 @@ typedef struct /* ISM orientation */ typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_ISM_ORIENTATION) */ - uint32_t piDataType; /* IVAS_PI_ISM_ORIENTATION */ + size_t size; /* sizeof(IVAS_PIDATA_ISM_ORIENTATION) */ + uint32_t piDataType; /* IVAS_PI_ISM_ORIENTATION */ #ifdef ISM_PI_DATA uint16_t numObjects; /* number of objects */ #endif @@ -238,8 +238,8 @@ typedef struct /* ISM position */ typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_ISM_POSITION) */ - uint32_t piDataType; /* IVAS_PI_ISM_POSITION */ + size_t size; /* sizeof(IVAS_PIDATA_ISM_POSITION) */ + uint32_t piDataType; /* IVAS_PI_ISM_POSITION */ #ifdef ISM_PI_DATA uint16_t numObjects; /* number of objects */ #endif @@ -260,8 +260,8 @@ typedef struct typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_ISM_ATTENUATION) */ - uint32_t piDataType; /* IVAS_PI_ISM_DISTANCE_ATTENUATION */ + size_t size; /* sizeof(IVAS_PIDATA_ISM_ATTENUATION) */ + uint32_t piDataType; /* IVAS_PI_ISM_DISTANCE_ATTENUATION */ #ifdef ISM_PI_DATA uint16_t numObjects; /* number of objects */ #endif @@ -282,8 +282,8 @@ typedef struct typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_ISM_DIRECTIVITY) */ - uint32_t piDataType; /* IVAS_PI_ISM_DIRECTIVITY */ + size_t size; /* sizeof(IVAS_PIDATA_ISM_DIRECTIVITY) */ + uint32_t piDataType; /* IVAS_PI_ISM_DIRECTIVITY */ #ifdef ISM_PI_DATA uint16_t numObjects; /* number of objects */ #endif -- GitLab From 1ac94db092b8795aebdb10d04e88dc751b759bd5 Mon Sep 17 00:00:00 2001 From: Stefan Doehla Date: Mon, 10 Nov 2025 17:39:54 +0100 Subject: [PATCH 29/34] added C sources as in float but without defines to avoid conflicts this time --- lib_com/options.h | 1 + lib_util/ivas_rtp_file.c | 13 ++++++- lib_util/ivas_rtp_pi_data.c | 71 +++++++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/lib_com/options.h b/lib_com/options.h index c6a4efa4b..f6c7dff18 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -161,6 +161,7 @@ #define RTP_S4_251135_CR26253_0016_REV1 /* RTP Pack/Unpack API corresponding to CR 26253 */ #define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ #define FIXED_RTP_SEQUENCE_NUM /* Remove random sequence number initialization */ +#define PI_LATENCY /* Support for PI latency */ /* #################### End BASOP porting switches ############################ */ diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 82f198135..5c10981e1 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -341,7 +341,18 @@ void IVAS_RTP_LogPiData( case IVAS_PI_ISM_POSITION: case IVAS_PI_ISM_DISTANCE_ATTENUATION: case IVAS_PI_ISM_DIRECTIVITY: + { + fprintf( f_piDataOut, "{}" ); + } + break; case IVAS_PI_PI_LATENCY: + { + fprintf( f_piDataOut, "{" ); + fprintf( f_piDataOut, "\n\t\t\t\"reverseType\": \"%s\",", PiDataNames[cur->data.piLatency.type] ); + fprintf( f_piDataOut, "\n\t\t\t\"latency\": %d", cur->data.piLatency.latency ); + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; case IVAS_PI_R_ISM_ID: case IVAS_PI_R_ISM_GAIN: case IVAS_PI_R_ISM_DIRECTION: @@ -600,7 +611,7 @@ void IVAS_RTP_WriteExtPiData( break; case IVAS_PI_PI_LATENCY: { - fprintf( f_piDataOut, "%d", cur->data.piLatency.latency ); + fprintf( f_piDataOut, "%s,%d", PiDataNames[cur->data.piLatency.type], cur->data.piLatency.latency ); } break; case IVAS_PI_R_ISM_ID: diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index be2e9dd4d..ede1f908a 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -630,6 +630,71 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat return IVAS_ERR_OK; } +static ivas_error packPiLatency( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t typeBits; + uint32_t latencyBits; + uint32_t word; + uint32_t nBytes = 0; + const IVAS_PIDATA_REVERSE_PI_LATENCY *p = (const IVAS_PIDATA_REVERSE_PI_LATENCY *) piData; + + *nBytesWritten = 0; + if ( piData->size != sizeof( IVAS_PIDATA_REVERSE_PI_LATENCY ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size for PI_LATENCY data" ); + } + if ( piData->piDataType != IVAS_PI_PI_LATENCY ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID for PI_LATENCY data" ); + } + if ( maxDataBytes < 2 + 4 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack PI_LATENCY data" ); + } + + buffer[nBytes++] = ( p->piDataType & MASK_5BIT ); + buffer[nBytes++] = 4; + + typeBits = (uint32_t) ( p->type & MASK_5BIT ); + latencyBits = (uint32_t) ( p->latency & 0x07FFFFFF ); + word = ( typeBits << 27 ) | latencyBits; + + buffer[nBytes++] = (uint8_t) ( word >> 24 ); + buffer[nBytes++] = (uint8_t) ( word >> 16 ); + buffer[nBytes++] = (uint8_t) ( word >> 8 ); + buffer[nBytes++] = (uint8_t) ( word ); + *nBytesWritten = nBytes; + + return IVAS_ERR_OK; +} + +static ivas_error unpackPiLatency( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t word; + uint32_t lat; + IVAS_PIDATA_REVERSE_PI_LATENCY *p = (IVAS_PIDATA_REVERSE_PI_LATENCY *) piData; + + if ( numDataBytes != 4 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack PI_LATENCY data" ); + } + + p->size = sizeof( IVAS_PIDATA_REVERSE_PI_LATENCY ); + p->piDataType = IVAS_PI_PI_LATENCY; + + word = ( (uint32_t) buffer[0] << 24 ) | ( (uint32_t) buffer[1] << 16 ) | + ( (uint32_t) buffer[2] << 8 ) | (uint32_t) buffer[3]; + p->type = (IVAS_PI_TYPE) ( ( word >> 27 ) & MASK_5BIT ); + lat = word & 0x07FFFFFF; + + /* Sign-extend 27-bit value */ + if ( lat & ( 1u << 26 ) ) + p->latency = (int32_t) ( lat | ~0x07FFFFFF ); + else + p->latency = (int32_t) lat; + + return IVAS_ERR_OK; +} #endif /* RTP_S4_251135_CR26253_0016_REV1 */ @@ -668,14 +733,15 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packListenerPosition, /* LISTENER_POSITION */ packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ packAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ + packPiLatency, /* PI_LATENCY */ #else packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ packUnsupportedData, /* HEAD_ORIENTATION */ packUnsupportedData, /* LISTENER_POSITION */ packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ + packUnsupportedData, /* PI_LATENCY */ #endif - packUnsupportedData, /* PI_LATENCY */ packUnsupportedData, /* R_ISM_ID */ packUnsupportedData, /* R_ISM_GAIN */ #ifdef RTP_S4_251135_CR26253_0016_REV1 @@ -727,14 +793,15 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackListenerPosition, /* LISTENER_POSITION */ unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */ + unpackPiLatency, /* PI_LATENCY */ #else unpackUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ unpackUnsupportedData, /* HEAD_ORIENTATION */ unpackUnsupportedData, /* LISTENER_POSITION */ unpackUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ -#endif unpackUnsupportedData, /* PI_LATENCY */ +#endif unpackUnsupportedData, /* R_ISM_ID */ unpackUnsupportedData, /* R_ISM_GAIN */ #ifdef RTP_S4_251135_CR26253_0016_REV1 -- GitLab From 3c9de80ac8df6b149a7a5a3f56e57aaf8fd4a63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Toftg=C3=A5rd?= Date: Mon, 10 Nov 2025 18:56:24 +0100 Subject: [PATCH 30/34] Bug fix for IVAS_RTP_LogPiData, add missing fprintf(). --- lib_util/ivas_rtp_file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index 0bf820df4..b3be95782 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -171,6 +171,9 @@ void IVAS_RTP_LogPiData( #else if ( ftell( f_piDataOut ) > 2 ) #endif + { + fprintf( f_piDataOut, ",\n" ); + } while ( nPiDataPresent-- > 0 ) { -- GitLab From 145155312d1ca24c46a15574e82a3a2169e06cc8 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 21:40:44 +0200 Subject: [PATCH 31/34] Fix gain ranges for reverse ISM gain --- lib_util/ivas_rtp_pi_data.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index c9583e048..e02e2023e 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -757,13 +757,13 @@ static ivas_error packReverseISMGain( const IVAS_PIDATA_GENERIC *piData, uint8_t buffer[nBytes++] = ( r_ism_gain->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ gain = (int16_t) r_ism_gain->dB; - idx = min( -gain, 97 ); + idx = min( -gain, 25 ); if ( gain > 0 ) { - idx += 97; + idx += 25; } - buffer[nBytes++] = ( idx & MASK_7BIT ) << 1; + buffer[nBytes++] = ( idx & MASK_6BIT ) << 2; *nBytesWritten = nBytes; return IVAS_ERR_OK; } @@ -785,19 +785,19 @@ static ivas_error unpackReverseISMGain( const uint8_t *buffer, uint32_t numDataB /* Unpack gain */ idx = ( *buffer ) >> 1; /* negative gains*/ - if ( idx < 97 ) + if ( idx < 25 ) { r_ism_gain->dB = -(int8_t) ( idx ); } /* Set to min for muting, to be interpreted as -Inf */ - else if ( idx == 97 ) + else if ( idx == 25 ) { r_ism_gain->dB = -128; } /* postive gains */ - else if ( idx < 101 ) + else if ( idx < 38 ) { - r_ism_gain->dB = (int8_t) idx - 97; + r_ism_gain->dB = (int8_t) idx - 25; } else { -- GitLab From 09777c860a7f4c330fa6ce5aa66db4f7bd698005 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 22:09:43 +0200 Subject: [PATCH 32/34] Change while loop to for loop --- lib_dec/lib_dec_fx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 6fe7006c7..f367927ee 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -6594,7 +6594,8 @@ ivas_error IVAS_RTP_FeedPiDataToDecoder( IVAS_DEC_HANDLE hIvasDec, PIDATA_TS *pi { ivas_error error = IVAS_ERR_OK; move32(); - WHILE( numPiData ) + UWord32 i; + FOR( i = 0; i < numPiData; i++ ) { UWord32 piDataType = piData->data.noPiData.piDataType; move32(); -- GitLab From a158757e9dfbfd42f1cd7cd995afaacc5b87d535 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 22:11:42 +0200 Subject: [PATCH 33/34] Clang format --- lib_util/ivas_rtp_file.c | 82 ++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index aca878b35..4ef3578f6 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -175,28 +175,28 @@ void IVAS_RTP_LogPiData( fprintf( f_piDataOut, ",\n" ); } - while ( nPiDataPresent-- > 0 ) - { - const PIDATA_TS *cur = piData++; + while ( nPiDataPresent-- > 0 ) + { + const PIDATA_TS *cur = piData++; - if ( timestamp != ( ~0u ) && timestamp != cur->timestamp ) - { - fprintf( f_piDataOut, "\n\t},\n\t\"%d\": {\n", cur->timestamp ); - } - else if ( timestamp != cur->timestamp ) - { - fprintf( f_piDataOut, "\t\"%d\": {\n", cur->timestamp ); - } - else - { - fprintf( f_piDataOut, ",\n" ); - } - fprintf( f_piDataOut, "\t\t\"%s\" : ", PiDataNames[cur->data.noPiData.piDataType] ); - switch ( cur->data.noPiData.piDataType ) - { - case IVAS_PI_SCENE_ORIENTATION: - case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: - case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: + if ( timestamp != ( ~0u ) && timestamp != cur->timestamp ) + { + fprintf( f_piDataOut, "\n\t},\n\t\"%d\": {\n", cur->timestamp ); + } + else if ( timestamp != cur->timestamp ) + { + fprintf( f_piDataOut, "\t\"%d\": {\n", cur->timestamp ); + } + else + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\"%s\" : ", PiDataNames[cur->data.noPiData.piDataType] ); + switch ( cur->data.noPiData.piDataType ) + { + case IVAS_PI_SCENE_ORIENTATION: + case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: + case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED: #ifdef RTP_S4_251135_CR26253_0016_REV1 case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION: case IVAS_PI_HEAD_ORIENTATION: @@ -213,22 +213,22 @@ void IVAS_RTP_LogPiData( } break; - case IVAS_PI_ACOUSTIC_ENVIRONMENT: + case IVAS_PI_ACOUSTIC_ENVIRONMENT: + { + fprintf( f_piDataOut, "{\n\t\t\t\"aeid\": %d", cur->data.acousticEnv.aeid ); + if ( cur->data.acousticEnv.availLateReverb ) { - fprintf( f_piDataOut, "{\n\t\t\t\"aeid\": %d", cur->data.acousticEnv.aeid ); - if ( cur->data.acousticEnv.availLateReverb ) - { - fprintf( f_piDataOut, ",\n\t\t\t\"rt60\": [ %f, %f, %f ],\n", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] ); - fprintf( f_piDataOut, "\t\t\t\"dsr\": [ %f, %f, %f ]", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] ); - } - if ( cur->data.acousticEnv.availEarlyReflections ) - { - fprintf( f_piDataOut, ",\n\t\t\t\"dim\": [ %f, %f, %f ],\n", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z ); - fprintf( f_piDataOut, "\t\t\t\"abscoeff\": [ %f, %f, %f, %f, %f, %f ]", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] ); - } - fprintf( f_piDataOut, "\n\t\t}" ); + fprintf( f_piDataOut, ",\n\t\t\t\"rt60\": [ %f, %f, %f ],\n", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] ); + fprintf( f_piDataOut, "\t\t\t\"dsr\": [ %f, %f, %f ]", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] ); } - break; + if ( cur->data.acousticEnv.availEarlyReflections ) + { + fprintf( f_piDataOut, ",\n\t\t\t\"dim\": [ %f, %f, %f ],\n", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z ); + fprintf( f_piDataOut, "\t\t\t\"abscoeff\": [ %f, %f, %f, %f, %f, %f ]", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] ); + } + fprintf( f_piDataOut, "\n\t\t}" ); + } + break; #ifdef RTP_S4_251135_CR26253_0016_REV1 case IVAS_PI_LISTENER_POSITION: #ifndef REVERSE_ISM_PI_DATA @@ -512,14 +512,14 @@ void IVAS_RTP_LogPiData( break; #endif #endif /* RTP_S4_251135_CR26253_0016_REV1 */ - case IVAS_PI_NO_DATA: - { - fprintf( f_piDataOut, "{}" ); - } - break; + case IVAS_PI_NO_DATA: + { + fprintf( f_piDataOut, "{}" ); } - timestamp = cur->timestamp; + break; } + timestamp = cur->timestamp; + } fprintf( f_piDataOut, "\n\t}" ); } -- GitLab From 9418eba8c3e3b190a4df169a3f81408ba0d9a915 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 10 Nov 2025 22:49:21 +0200 Subject: [PATCH 34/34] Fix unpacking for reverse direction ISM PI --- lib_util/ivas_rtp_pi_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index c0e9baa51..3817a8447 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -1298,7 +1298,7 @@ static ivas_error unpackReverseISMGain( const uint8_t *buffer, uint32_t numDataB r_ism_gain->piDataType = IVAS_PI_R_ISM_GAIN; /* Unpack gain */ - idx = ( *buffer ) >> 1; + idx = ( *buffer ) >> 2; /* negative gains*/ if ( idx < 25 ) { -- GitLab