From 10265cef5e7d1a1dcc0644018a0fa6bb3ecff687 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 2 Oct 2024 13:21:40 +0300 Subject: [PATCH 01/33] Add support for IVAS rtpdump reading and writing --- apps/decoder.c | 124 +++ apps/encoder.c | 282 ++++- lib_com/bitstream.c | 52 + lib_com/common_api_types.h | 25 + lib_com/ivas_cnst.h | 23 + lib_com/ivas_prot.h | 25 + lib_com/options.h | 2 + lib_dec/lib_dec.c | 153 +++ lib_dec/lib_dec.h | 28 + lib_enc/lib_enc.c | 20 + lib_enc/lib_enc.h | 7 + lib_rend/ivas_prot_rend.h | 8 + lib_rend/ivas_rotation.c | 76 +- lib_rend/ivas_stat_rend.h | 3 + lib_util/disable_headtracking_file_reader.c | 169 +++ lib_util/disable_headtracking_file_reader.h | 86 ++ lib_util/evs_rtp_payload.c | 5 + lib_util/evs_rtp_payload.h | 5 + lib_util/g192.c | 4 + lib_util/g192.h | 8 +- lib_util/ivas_rtp_payload.c | 1081 +++++++++++++++++++ lib_util/ivas_rtp_payload.h | 421 ++++++++ lib_util/rtpdump.c | 28 + lib_util/rtpdump.h | 6 + readme.txt | 12 +- 25 files changed, 2644 insertions(+), 9 deletions(-) create mode 100644 lib_util/disable_headtracking_file_reader.c create mode 100644 lib_util/disable_headtracking_file_reader.h create mode 100644 lib_util/ivas_rtp_payload.c create mode 100644 lib_util/ivas_rtp_payload.h diff --git a/apps/decoder.c b/apps/decoder.c index b317b9a539..d06c08239c 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -37,6 +37,9 @@ #include "bitstream_reader.h" #include "evs_rtp_payload.h" #include "ism_file_writer.h" +#ifdef IVAS_RTPDUMP +#include "ivas_rtp_payload.h" +#endif #include "jbm_file_writer.h" #include "hrtf_file_reader.h" #include "ls_custom_file_reader.h" @@ -1730,10 +1733,18 @@ 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" ); +#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\n" ); #endif @@ -2936,14 +2947,25 @@ static ivas_error printBitstreamInfoVoip( bool previewFailed = true; ivas_error error = IVAS_ERR_OK; FILE *f_rtpstream = NULL; +#ifdef IVAS_RTPDUMP + IVAS_RTPDUMP_DEPACKER rtpdumpDepacker; + IVAS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_NO_ERROR; +#else EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; +#endif uint8_t au[( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3]; int16_t auSizeBits; uint8_t *auPtr = NULL; +#ifdef IVAS_RTPDUMP + bool evsIvasModeBit; + uint16_t bitrateIndex; + bool ivasIndicatorOrQBit; +#else bool isAMRWB_IOmode; uint16_t frameTypeIndex; bool qBit; +#endif uint32_t nextPacketRcvTime_ms = 0; uint16_t rtpSequenceNumber; uint32_t rtpTimeStamp; @@ -2961,7 +2983,11 @@ static ivas_error printBitstreamInfoVoip( goto cleanup; } +#ifdef IVAS_RTPDUMP + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream ); +#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream, arg.inputFormat == IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF ); +#endif if ( rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) { fprintf( stderr, "error in EVS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError ); @@ -2982,12 +3008,20 @@ static ivas_error printBitstreamInfoVoip( if ( arg.inputFormat == IVAS_DEC_INPUT_FORMAT_G192 ) { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSizeBits, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); +#ifdef IVAS_RTPDUMP + ivasIndicatorOrQBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ +#else qBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ +#endif } else { auPtr = au; /* might have been set to RTP packet in prev call */ +#ifdef IVAS_RTPDUMP + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, &auPtr, (uint16_t *) &auSizeBits ); +#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSizeBits ); +#endif /* EVS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; @@ -2997,7 +3031,11 @@ static ivas_error printBitstreamInfoVoip( fprintf( stderr, "failed to read first RTP packet\n" ); goto cleanup; } +#ifdef IVAS_RTPDUMP + } while ( !ivasIndicatorOrQBit || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); +#else } while ( !qBit || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); +#endif BS_Reader_Rewind( hBsReader ); @@ -3011,7 +3049,11 @@ static ivas_error printBitstreamInfoVoip( cleanup: +#ifdef IVAS_RTPDUMP + IVAS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); +#else EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); +#endif if ( previewFailed && error == IVAS_ERR_OK ) { @@ -3076,12 +3118,23 @@ static ivas_error decodeVoIP( int32_t delayTimeScale = -1; int16_t i; FILE *f_rtpstream = NULL; +#ifdef IVAS_RTPDUMP + IVAS_RTPDUMP_DEPACKER rtpdumpDepacker; + IVAS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_NO_ERROR; +#else EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; +#endif uint8_t *auPtr = NULL; +#ifdef IVAS_RTPDUMP + bool evsIvasModeBit; + uint16_t bitrateIndex; + bool ivasIndicatorOrQBit; +#else bool isAMRWB_IOmode; uint16_t frameTypeIndex; bool qBit; +#endif IVAS_DEC_BS_FORMAT bsFormat = IVAS_DEC_BS_UNKOWN; IsmFileWriter *ismWriters[IVAS_MAX_NUM_OBJECTS]; @@ -3131,12 +3184,21 @@ static ivas_error decodeVoIP( goto cleanup; } +#ifdef IVAS_RTPDUMP + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream ); + if ( rtpdumpDepackerError != IVAS_RTPDUMP_DEPACKER_NO_ERROR ) + { + fprintf( stderr, "error in IVAS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError ); + goto cleanup; + } +#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream, arg.inputFormat == IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF ); if ( rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) { fprintf( stderr, "error in EVS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError ); goto cleanup; } +#endif break; case IVAS_DEC_INPUT_FORMAT_G192: auPtr = au; @@ -3173,17 +3235,29 @@ static ivas_error decodeVoIP( if ( arg.inputFormat == IVAS_DEC_INPUT_FORMAT_G192 ) { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSize, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); +#ifdef IVAS_RTPDUMP + ivasIndicatorOrQBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ +#else qBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ +#endif } else { auPtr = au; /* might have been set to RTP packet in prev call */ +#ifdef IVAS_RTPDUMP + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame(&rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, &auPtr, (uint16_t *) &auSize ); +#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 || rtpdumpDepackerError != IVAS_RTPDUMP_DEPACKER_NO_ERROR ) +#else if ( error != IVAS_ERR_OK || rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) +#endif { fprintf( stderr, "failed to read first RTP packet\n" ); goto cleanup; @@ -3328,7 +3402,11 @@ static ivas_error decodeVoIP( while ( nextPacketRcvTime_ms <= systemTime_ms ) { /* feed the previous read packet into the receiver now */ +#ifdef IVAS_RTPDUMP + error = IVAS_DEC_VoIP_FeedFrame(hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, ivasIndicatorOrQBit ); +#else error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, qBit ); +#endif if ( error != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_VoIP_FeedFrame: %s\n", IVAS_DEC_GetErrorMessage( error ) ); @@ -3341,28 +3419,66 @@ static ivas_error decodeVoIP( { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSize, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); +#ifdef IVAS_RTPDUMP + ivasIndicatorOrQBit = 1; /* good q_bit for VOIP_G192_RTP */ +#else qBit = 1; /* good q_bit for VOIP_G192_RTP */ +#endif } else { auPtr = au; /* might have been set to RTP packet in prev call */ +#ifdef IVAS_RTPDUMP + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, + &nextPacketRcvTime_ms, + &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, + &auPtr, (uint16_t *) &auSize ); + /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ + rtpTimeStamp = rtpTimeStamp / 16; + + /* parse PI data */ + error = IVAS_DEC_parsePIdata( hIvasDec, &rtpdumpDepacker.PIdataCurrentFrame, &rtpdumpDepacker.PIdataDepackerState ); + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_parsePIdata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + IVAS_DEC_resetPIdataCurrentFrame( &rtpdumpDepacker.PIdataCurrentFrame ); +#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 || rtpdumpDepackerError == IVAS_RTPDUMP_DEPACKER_EOF ) +#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; } +#ifdef IVAS_RTPDUMP + else if ( rtpdumpDepackerError != IVAS_RTPDUMP_DEPACKER_NO_ERROR ) + { + fprintf( stderr, "\nError in IVAS_RTPDUMP_DEPACKER_readNextFrame, error code: %d\n", error ); + goto cleanup; + } +#endif } /* we are finished when all packets have been received and jitter buffer is empty */ @@ -3524,6 +3640,10 @@ static ivas_error decodeVoIP( } } +#ifdef IVAS_RTPDUMP + IVAS_DEC_resetExternalOrientations(hIvasDec); +#endif + if ( !arg.quietModeEnabled ) { fprintf( stdout, "%-8d\b\b\b\b\b\b\b\b", frame ); @@ -3668,7 +3788,11 @@ static ivas_error decodeVoIP( cleanup: +#ifdef IVAS_RTPDUMP + IVAS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); +#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 f64986ec84..258a016540 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -38,6 +38,12 @@ #include "ism_file_reader.h" #include "jbm_file_reader.h" #include "masa_file_reader.h" +#ifdef IVAS_RTPDUMP +#include "disable_headtracking_file_reader.h" +#include "evs_rtp_payload.h" +#include "ivas_rtp_payload.h" +#include "rotation_file_reader.h" +#endif #ifdef DEBUGGING #include "debug.h" #endif @@ -146,6 +152,12 @@ typedef struct #endif bool pca; bool ism_extended_metadata; +#ifdef IVAS_RTPDUMP + bool rtpdumpOutput; + char *sceneOrientationTrajFileName; + char *deviceOrientationTrajFileName; + char *disableHeadtrackingFileName; +#endif } EncArguments; @@ -190,6 +202,11 @@ 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; + DisableHeadtrackingFileReader *disableHeadtrackingFileReader = NULL; +#endif #ifdef DEBUGGING FILE *f_forcedModeProfile = NULL; #ifdef DEBUG_SBA @@ -205,6 +222,12 @@ int main( reset_mem( USE_BYTES ); #endif +#ifdef IVAS_RTPDUMP + FILE *f_rtpstream = NULL; + IVAS_RTPDUMP_PACKER *rtpdumpPacker = NULL; + IVAS_RTPDUMP_PACKER_ERROR rtpdumpPackerError = IVAS_RTPDUMP_PACKER_NO_ERROR; +#endif + initArgStruct( &arg ); /*------------------------------------------------------------------------------------------* @@ -235,7 +258,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; @@ -593,6 +620,70 @@ int main( } } +#ifdef IVAS_RTPDUMP + /*------------------------------------------------------------------------------------------* + * RTPDump + *------------------------------------------------------------------------------------------*/ + + if ( arg.rtpdumpOutput ) + { + /* Open the output file for RTPDump writing */ + f_rtpstream = fopen( arg.outputBitstreamFilename, "wb" ); + + if ( f_rtpstream == NULL ) + { + fprintf( stderr, "could not open: %s\n", arg.outputBitstreamFilename ); + goto cleanup; + } + + rtpdumpPackerError = IVAS_RTPDUMP_PACKER_open( &rtpdumpPacker, f_rtpstream ); + if ( rtpdumpPackerError != IVAS_RTPDUMP_PACKER_NO_ERROR ) + { + fprintf( stderr, "error in IVAS_RTPDUMP_PACKER_open(): %d\n", rtpdumpPackerError ); + 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; + } + } + + /*------------------------------------------------------------------------------------------* + * Open disable headtracking file + *------------------------------------------------------------------------------------------*/ + + if (arg.disableHeadtrackingFileName != NULL ) + { + if (( error = DisableHeadtrackingFileReader_open(arg.disableHeadtrackingFileName, &disableHeadtrackingFileReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open disable headtracking file %s \n\n", arg.disableHeadtrackingFileName ); + goto cleanup; + } + } +#endif + int16_t numSamplesRead = 0; uint16_t bitStream[IVAS_MAX_BITS_PER_FRAME]; uint16_t numBits = 0; @@ -763,12 +854,70 @@ int main( goto cleanup; } - /* write bitstream */ - if ( ( error = BS_Writer_WriteFrame_short( hBsWriter, bitStream, numBits, totalBitrate ) ) != IVAS_ERR_OK ) +#ifdef IVAS_RTPDUMP + if ( rtpdumpPacker->rtpdump ) { - fprintf( stderr, "\nBS_Writer_WriteFrame_short failed, error code %d\n\n", error ); - goto cleanup; + /* scene orientation */ + if ( sceneOrientationFileReader ) + { + IVAS_QUATERNION sceneOrientationQuat; + if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &sceneOrientationQuat, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading scene orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( sceneOrientationFileReader ) ); + goto cleanup; + } + rtpdumpPacker->piDataPacker.sceneOrientationQuat = &sceneOrientationQuat; + } + + /* device orientation */ + if ( deviceOrientationFileReader ) + { + IVAS_QUATERNION deviceOrientationQuat; + if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &deviceOrientationQuat, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading device orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( deviceOrientationFileReader ) ); + goto cleanup; + } + rtpdumpPacker->piDataPacker.deviceOrientationQuat = &deviceOrientationQuat; + } + + /* disable headtracking */ + if ( disableHeadtrackingFileReader ) + { + if ( ( error = DisableHeadtrackingFileReading( disableHeadtrackingFileReader, &rtpdumpPacker->piDataPacker.disableHeadtracking ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading disable headtracking data from %s\n", IVAS_ENC_GetErrorMessage( error ), DisableHeadtrackingFileReader_getFilePath( disableHeadtrackingFileReader ) ); + goto cleanup; + } + IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( rtpdumpPacker ); + } + + /* PI presence */ + IVAS_RTPDUMP_PACKER_determinePIpresence( rtpdumpPacker ); + + /* write rtpdump */ + rtpdumpPackerError = IVAS_RTPDUMP_PACKER_writeNextFrame( rtpdumpPacker, bitStream, numBits, totalBitrate, + IVAS_isImmersiveFormat( hIvasEnc ), 0, false, NO_BANDWIDTH_REQUEST, NO_FORMAT_REQUEST ); + if ( rtpdumpPackerError != IVAS_RTPDUMP_PACKER_NO_ERROR ) + { + fprintf( stderr, "IVAS_RTPDUMP_PACKER_writeNextFrame() failed, error code: %d\n", rtpdumpPackerError ); + goto cleanup; + } + + IVAS_RTPDUMP_PACKER_resetPIdata( rtpdumpPacker ); } + else + { +#endif + /* 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 ) @@ -840,6 +989,28 @@ cleanup: fclose( f_bitrateProfile ); } +#ifdef IVAS_RTPDUMP + if ( rtpdumpPacker ) + { + IVAS_RTPDUMP_PACKER_close( &rtpdumpPacker ); + } + + if ( sceneOrientationFileReader ) + { + RotationFileReader_close( &sceneOrientationFileReader ); + } + + if ( deviceOrientationFileReader ) + { + RotationFileReader_close( &deviceOrientationFileReader ); + } + + if ( disableHeadtrackingFileReader ) + { + DisableHeadtrackingFileReader_close( &disableHeadtrackingFileReader ); + } +#endif + IVAS_ENC_Close( &hIvasEnc ); #ifdef WMOPS @@ -895,6 +1066,12 @@ static void initArgStruct( EncArguments *arg ) 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; + arg->disableHeadtrackingFileName = NULL; +#endif #ifdef DEBUGGING arg->forcedMode = IVAS_ENC_FORCE_UNFORCED; @@ -1705,6 +1882,73 @@ static bool parseCmdlIVAS_enc( i++; } +#ifdef IVAS_RTPDUMP + /*-----------------------------------------------------------------* + * RTPDump output + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-RTPDUMP" ) == 0 ) + { + arg->rtpdumpOutput = true; + fprintf( stdout, "Output format: RTPDump\n" ); + ++i; + } + + /*-----------------------------------------------------------------* + * 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++; + } + + /*-----------------------------------------------------------------* + * Disable headtracking file reading + *-----------------------------------------------------------------*/ + + else if ( strcmp( argv_to_upper, "-DISABLE_HEADTRACKING_FILE" ) == 0 ) + { + i++; + if ( argc - i <= 4 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: Disable headtracking input file name not specified!\n\n" ); + usage_enc(); + return false; + } + + arg->disableHeadtrackingFileName = argv[i]; + i++; + } + +#endif /*-----------------------------------------------------------------* * Option not recognized *-----------------------------------------------------------------*/ @@ -1716,6 +1960,27 @@ static bool parseCmdlIVAS_enc( } } /* end of while */ +#ifdef IVAS_RTPDUMP + if ( arg->sceneOrientationTrajFileName != NULL && arg->rtpdumpOutput == false ) + { + fprintf( stderr, "Error: Scene orientations are only enabled with rtpdump output!\n\n" ); + usage_enc(); + return false; + } + if ( arg->deviceOrientationTrajFileName != NULL && arg->rtpdumpOutput == false ) + { + fprintf( stderr, "Error: Device orientations are only enabled with rtpdump output!\n\n" ); + usage_enc(); + return false; + } + if ( arg->disableHeadtrackingFileName != NULL && arg->rtpdumpOutput == false ) + { + fprintf( stderr, "Error: Disable headtracking file reading is only enabled with rtpdump output!\n\n" ); + usage_enc(); + return false; + } + +#endif /*-----------------------------------------------------------------* * Mandatory input arguments *-----------------------------------------------------------------*/ @@ -1922,6 +2187,15 @@ 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. \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" ); + fprintf( stdout, "-disable_headtracking_file : Disable headtracking input file. (1) to disable and (0) to enable headtracking. Only used with rtpdump output.\n" ); +#endif fprintf( stdout, "\n" ); return; diff --git a/lib_com/bitstream.c b/lib_com/bitstream.c index 47fbbb9db2..f5a7fbd480 100644 --- a/lib_com/bitstream.c +++ b/lib_com/bitstream.c @@ -163,6 +163,58 @@ Word16 rate2EVSmode( return rate2AMRWB_IOmode( brate ); } +#ifdef IVAS_RTPDUMP +/*-------------------------------------------------------------------* + * rate2IVASmode() + * + * Lookup IVAS mode. Note: FRAME_NO_DATA frames should be looked up with rate2EVSmode(). + *-------------------------------------------------------------------*/ +Word16 rate2IVASmode( + const Word32 brate /* i : bitrate */ +) +{ + switch ( brate ) + { + /* IVAS modes */ + case IVAS_SID_5k2: + return IVAS_TOC_SID; + case IVAS_13k2: + return IVAS_TOC_13200; + case IVAS_16k4: + return IVAS_TOC_16400; + case IVAS_24k4: + return IVAS_TOC_24400; + case IVAS_32k: + return IVAS_TOC_32000; + case IVAS_48k: + return IVAS_TOC_48000; + case IVAS_64k: + return IVAS_TOC_64000; + case IVAS_80k: + return IVAS_TOC_80000; + case IVAS_96k: + return IVAS_TOC_96000; + case IVAS_128k: + return IVAS_TOC_128000; + case IVAS_160k: + return IVAS_TOC_160000; + case IVAS_192k: + return IVAS_TOC_192000; + case IVAS_256k: + return IVAS_TOC_256000; + case IVAS_384k: + return IVAS_TOC_384000; + case IVAS_512k: + return IVAS_TOC_512000; + default: + break; + } + + return -1; +} + +#endif + /*-------------------------------------------------------------------* * ind_list_realloc() * diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index 8cbdfcb3cd..251e4f9003 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -36,6 +36,9 @@ /* options.h needed for debugging/development features * It should be stripped for delivery along with debugging switches */ #include "options.h" +#ifdef IVAS_RTPDUMP +#include +#endif #include #include #include "ivas_error.h" @@ -213,6 +216,28 @@ typedef struct _IVAS_JBM_TRACE_DATA } IVAS_JBM_TRACE_DATA; +#ifdef IVAS_RTPDUMP +typedef struct +{ + bool PIdataPresent; + char *sceneOrientation; + char *deviceOrientationCompensated; + char *deviceOrientationUncompensated; + char *acousticEnvironmentId; + char *acousticEnvironmentOnlyLateReverb; + char *acousticEnvironmentLateReverbAndEarlyReflections; + bool enableHeadTracking; + bool disableHeadTracking; +} PI_DATA_CURRENT_FRAME; + +typedef struct +{ + bool sceneOrientationSaved; + IVAS_QUATERNION sceneOrientationQuat; + bool deviceOrientationSaved; + IVAS_QUATERNION deviceOrientationQuat; +} PI_DATA_DEPACKER_STATE; +#endif /*----------------------------------------------------------------------------------* * Split rendering API constants, structures, and enums diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index 105c0e8057..e4dc8f8b88 100755 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -1772,6 +1772,29 @@ typedef enum } STEREO_DMX_EVS_PRC; +#ifdef IVAS_RTPDUMP +/* "IVAS bit rate" column in table A.3.3.3.2-1 of TS26.253 Annex A */ +typedef enum +{ + IVAS_TOC_13200 = 0x0, // 0000 + IVAS_TOC_16400 = 0x1, // 0001 + IVAS_TOC_24400 = 0x2, // 0010 + IVAS_TOC_32000 = 0x3, // 0011 + IVAS_TOC_48000 = 0x4, // 0100 + IVAS_TOC_64000 = 0x5, // 0101 + IVAS_TOC_80000 = 0x6, // 0110 + IVAS_TOC_96000 = 0x7, // 0111 + IVAS_TOC_128000 = 0x8, // 1000 + IVAS_TOC_160000 = 0x9, // 1001 + IVAS_TOC_192000 = 0xA, // 1010 + IVAS_TOC_256000 = 0xB, // 1011 + IVAS_TOC_384000 = 0xC, // 1100 + IVAS_TOC_512000 = 0xD, // 1101 + IVAS_TOC_RESERVED = 0xE, // 1110 + IVAS_TOC_SID = 0xF // 1111 +} IVAS_TOC_BITRATE_INDEX; + +#endif #endif /* clang-format on */ /* IVAS_CNST_H */ diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 700a9cc75c..6c3bf7f309 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -770,7 +770,32 @@ void ivas_apply_non_diegetic_panning( const int16_t output_frame /* i : output frame length per channel */ ); +#ifdef IVAS_RTPDUMP +Word16 rate2IVASmode( + const Word32 brate /* i : bitrate */ +); + +void QuaternionProduct( + const IVAS_QUATERNION q1, + const IVAS_QUATERNION q2, + IVAS_QUATERNION *const r +); + +void QuaternionInverse( + const IVAS_QUATERNION q, + IVAS_QUATERNION *const r +); +void resetPIdataCurrentFrame( + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ +); + +bool ivasPayload_parseOrientationPIdata( + char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ + IVAS_QUATERNION *q /* o : Parsed quaternion value */ +); + +#endif /*----------------------------------------------------------------------------------* * JBM prototypes *----------------------------------------------------------------------------------*/ diff --git a/lib_com/options.h b/lib_com/options.h index 367583eb90..e66a459089 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -162,6 +162,8 @@ #define OBJ_EDITING_PARAMISM_BIN /* Nokia: object editing for ParamISM to binaural */ #endif +#define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ + /* ################### Start BE switches ################################# */ /* only BE switches wrt selection floating point code */ diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 900b879cb6..4187a7d10e 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3582,6 +3582,159 @@ ivas_error IVAS_DEC_Flush( } +#ifdef IVAS_RTPDUMP +/*---------------------------------------------------------------------* + * IVAS_DEC_parseSinglePIorientation( ) + * + * Parse a single orientation from PI data and feed to external orientation handle. + * Save the parsed (inverted) orientation value and use in processing in future frames, if no new PI orientation is received. + *---------------------------------------------------------------------*/ + +ivas_error IVAS_DEC_parseSinglePIorientation( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + char *orientation, /* i : input PI orientation */ + bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ + IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ +) +{ + int16_t i; + ivas_error error = IVAS_ERR_OK; + if ( orientation ) + { + IVAS_QUATERNION orientationQuat, orientationQuatInv; + if ( !hIvasDec->st_ivas->hExtOrientationData ) + { + if ( ( error = ivas_external_orientation_open( &( 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( &( hIvasDec->st_ivas->hCombinedOrientationData ), hIvasDec->st_ivas->hDecoderConfig->output_Fs, hIvasDec->st_ivas->hDecoderConfig->render_framesize ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + /* read the orientation PI value */ + if ( !ivasPayload_parseOrientationPIdata( orientation, &orientationQuat ) ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "Parsing PI orientation failed" ); + } + QuaternionInverse( orientationQuat, &orientationQuatInv ); + + /* update the saved orientation value */ + *isOrientationSaved = true; + *savedInvOrientation = orientationQuatInv; + } + + if ( *isOrientationSaved ) + { + /* use the new PI orientation or the previously saved orientation in processing */ + for ( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) + { + QuaternionProduct(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; +} + + +/*---------------------------------------------------------------------* + * IVAS_DEC_parsePIenableDisableHeadtracking( ) + * + * Parse enable/disable headtracking from PI data + *---------------------------------------------------------------------*/ + +void IVAS_DEC_parsePIenableDisableHeadtracking( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* i : PI data handle for the current frame */ +) +{ + if ( PIdataCurrentFrame->enableHeadTracking ) + { + if ( hIvasDec->st_ivas->hCombinedOrientationData ) + { + hIvasDec->st_ivas->hCombinedOrientationData->enableHeadTrackingPI = 1; + } + } + if ( PIdataCurrentFrame->disableHeadTracking ) + { + if ( hIvasDec->st_ivas->hCombinedOrientationData ) + { + hIvasDec->st_ivas->hCombinedOrientationData->enableHeadTrackingPI = 0; + } + } +} + + +/*---------------------------------------------------------------------* + * IVAS_DEC_parsePIdata( ) + * + * Parse PI data for a single frame + *---------------------------------------------------------------------*/ + +ivas_error IVAS_DEC_parsePIdata( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* i : PI data handle for the current frame */ + PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ +) +{ + ivas_error error = IVAS_ERR_OK; + + /* scene orientation */ + if (( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->sceneOrientation, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* device orientation */ + if (( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->deviceOrientationUncompensated, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* enable/disable headtracking */ + IVAS_DEC_parsePIenableDisableHeadtracking( hIvasDec, PIdataCurrentFrame ); + + return error; +} + + +/*---------------------------------------------------------------------* + * IVAS_DEC_resetExternalOrientations( ) + * + * Reset external orientations + *---------------------------------------------------------------------*/ + +void IVAS_DEC_resetExternalOrientations( + IVAS_DEC_HANDLE hIvasDec /* i/o: IVAS decoder handle */ +) +{ + ivas_external_orientation_reset( &( hIvasDec->st_ivas->hExtOrientationData ) ); +} + + +/*---------------------------------------------------------------------* + * IVAS_DEC_resetPIdataCurrentFrame( ) + * + * Reset current PI frame struct + *---------------------------------------------------------------------*/ + +void IVAS_DEC_resetPIdataCurrentFrame( + PI_DATA_CURRENT_FRAME *piDataCurrentFrame /* i/o: PI data handle for the current frame */ +) +{ + resetPIdataCurrentFrame( piDataCurrentFrame ); +} + + +#endif /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_IsEmpty( ) * diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 50476c964b..3d3e41e6a8 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -319,6 +319,34 @@ ivas_error IVAS_DEC_Flush( int16_t *nSamplesFlushed /* o : number of samples flushed */ ); +#ifdef IVAS_RTPDUMP +ivas_error IVAS_DEC_parseSinglePIorientation( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + char *orientation, /* i : input PI orientation */ + bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ + IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ +); + +void IVAS_DEC_parsePIenableDisableHeadtracking( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* i : PI data handle for the current frame */ +); + +ivas_error IVAS_DEC_parsePIdata( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* i : PI data handle for the current frame */ + PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ +); + +void IVAS_DEC_resetExternalOrientations( + IVAS_DEC_HANDLE hIvasDec /* i/o: IVAS decoder handle */ +); + +void IVAS_DEC_resetPIdataCurrentFrame( + PI_DATA_CURRENT_FRAME *piDataCurrentFrame /* i/o: PI data handle for the current frame */ +); + +#endif /* Setter functions - apply changes to decoder configuration */ /*! r: error code */ diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index 23e666a7f0..b934b5c8f2 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -2417,3 +2417,23 @@ static void init_encoder_config( return; } +#ifdef IVAS_RTPDUMP + + +/*---------------------------------------------------------------------* + * IVAS_isImmersiveFormat() + * + * Check if the used format is immersive or mono + *---------------------------------------------------------------------*/ + +bool IVAS_isImmersiveFormat( + const IVAS_ENC_HANDLE hIvasEnc +) +{ + if ( hIvasEnc->st_ivas->hEncoderConfig->ivas_format == MONO_FORMAT ) + { + return false; + } + return true; +} +#endif diff --git a/lib_enc/lib_enc.h b/lib_enc/lib_enc.h index 2f40c1ab1b..ba0debf662 100644 --- a/lib_enc/lib_enc.h +++ b/lib_enc/lib_enc.h @@ -383,6 +383,13 @@ void IVAS_ENC_PrintDisclaimer( void ); +#ifdef IVAS_RTPDUMP +/*! r: true if ivas format is not mono */ +bool IVAS_isImmersiveFormat( + const IVAS_ENC_HANDLE hIvasEnc /* i : IVAS encoder handle */ +); + +#endif /* clang-format on */ #endif /* LIB_ENC_H */ diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 8e6980b054..3ddb3a68f9 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -1292,6 +1292,12 @@ ivas_error ivas_external_orientation_open( const int16_t num_subframes /* i : number of subframes */ ); +#ifdef IVAS_RTPDUMP +void ivas_external_orientation_reset( + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o : external orientation handle */ +); + +#endif void ivas_external_orientation_close( EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o: external orientation handle */ ); @@ -1339,6 +1345,7 @@ ivas_error ivas_render_config_init_from_rom( * Quaternion operations *----------------------------------------------------------------------------------*/ +#ifndef IVAS_RTPDUMP void QuaternionProduct( const IVAS_QUATERNION q1, const IVAS_QUATERNION q2, @@ -1350,6 +1357,7 @@ void QuaternionInverse( IVAS_QUATERNION *const r ); +#endif void QuaternionSlerp( const IVAS_QUATERNION q1, const IVAS_QUATERNION q2, diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index dc5136cd00..d11e2b6b6e 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -693,6 +693,7 @@ ivas_error ivas_external_orientation_open( const int16_t num_subframes /* i : number of subframes */ ) { +#ifndef IVAS_RTPDUMP int16_t i; IVAS_QUATERNION identity; @@ -700,12 +701,16 @@ ivas_error ivas_external_orientation_open( identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; +#endif /* Allocate handle */ if ( ( *hExtOrientationData = (EXTERNAL_ORIENTATION_HANDLE) malloc( sizeof( EXTERNAL_ORIENTATION_DATA ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for external orientation memory\n" ) ); } ( *hExtOrientationData )->num_subframes = num_subframes; +#ifdef IVAS_RTPDUMP + ivas_external_orientation_reset( hExtOrientationData ); +#else /* Enable head rotation and disable external orientation as default */ for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { @@ -715,10 +720,42 @@ ivas_error ivas_external_orientation_open( ( *hExtOrientationData )->numFramesToTargetOrientation[i] = 0; ( *hExtOrientationData )->Quaternions[i] = identity; } +#endif return IVAS_ERR_OK; } +#ifdef IVAS_RTPDUMP +/*-----------------------------------------------------------------------* + * ivas_external_orientation_reset() + * + * Reset external orientation values + *-----------------------------------------------------------------------*/ + +void ivas_external_orientation_reset( + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o : external orientation handle */ +) +{ + if ( *hExtOrientationData != NULL ) + { + int16_t i; + IVAS_QUATERNION identity; + + identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; + /* Enable head rotation and disable external orientation as default */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + ( *hExtOrientationData )->enableHeadRotation[i] = 1; + ( *hExtOrientationData )->enableExternalOrientation[i] = 0; + ( *hExtOrientationData )->enableRotationInterpolation[i] = 0; + ( *hExtOrientationData )->numFramesToTargetOrientation[i] = 0; + ( *hExtOrientationData )->Quaternions[i] = identity; + } + } +} + + +#endif /*-----------------------------------------------------------------------* * ivas_external_orientation_close() * @@ -759,9 +796,14 @@ ivas_error ivas_combined_orientation_open( IVAS_VECTOR3 origo; int16_t pos_idx; +#ifdef IVAS_RTPDUMP + identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; + origo = (IVAS_VECTOR3) { .x = 0.0f, .y = 0.0f, .z = 0.0f }; +#else identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; origo.x = origo.y = origo.z = 0.0f; +#endif /* Allocate handle */ if ( ( *hCombinedOrientationData = (COMBINED_ORIENTATION_HANDLE) malloc( sizeof( COMBINED_ORIENTATION_DATA ) ) ) == NULL ) @@ -822,6 +864,9 @@ ivas_error ivas_combined_orientation_open( ( *hCombinedOrientationData )->subframe_idx = 0; ( *hCombinedOrientationData )->subframe_size = (int16_t) ( fs / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ); ( *hCombinedOrientationData )->cur_subframe_samples_rendered = 0; +#ifdef IVAS_RTPDUMP + ( *hCombinedOrientationData )->enableHeadTrackingPI = 1; +#endif return IVAS_ERR_OK; } @@ -943,9 +988,14 @@ ivas_error combine_external_and_head_orientations( IVAS_QUATERNION identity; IVAS_VECTOR3 origo; +#ifdef IVAS_RTPDUMP + identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; + origo = (IVAS_VECTOR3) { .x = 0.0f, .y = 0.0f, .z = 0.0f }; +#else identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; origo.x = origo.y = origo.z = 0.0f; +#endif /* Form combined orientations or return if no data available */ if ( hCombinedOrientationData == NULL ) @@ -983,10 +1033,24 @@ ivas_error combine_external_and_head_orientations( else if ( hExtOrientationData == NULL && headRotQuaternions != NULL ) { /* Head rotation only */ - for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) +#ifdef IVAS_RTPDUMP + if ( hCombinedOrientationData->enableHeadTrackingPI == 1 ) + { +#endif + for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) + { + hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + } +#ifdef IVAS_RTPDUMP + } + else { - hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) + { + hCombinedOrientationData->Quaternions[i] = identity; + } } +#endif } if ( hExtOrientationData != NULL ) @@ -1064,7 +1128,11 @@ ivas_error combine_external_and_head_orientations( hCombinedOrientationData->isHeadRotationFrozen = 0; } /* Use the most recent head rotation */ +#ifdef IVAS_RTPDUMP + if ( hExtOrientationData->enableHeadRotation[i] == 1 && hCombinedOrientationData->enableHeadTrackingPI == 1 ) +#else if ( hExtOrientationData->enableHeadRotation[i] == 1 ) +#endif { if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) { @@ -1223,8 +1291,12 @@ static void external_target_interpolation( if ( hExtOrientationData->enableExternalOrientation[i - 1] == 0 ) { IVAS_QUATERNION identity; +#ifdef IVAS_RTPDUMP + identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; +#else identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; +#endif hCombinedOrientationData->Quaternions_ext_interpolation_start = identity; } else if ( hExtOrientationData->enableExternalOrientation[i - 1] == 2 ) diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index f1d777699c..64a56e85fa 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -710,6 +710,9 @@ typedef struct ivas_combined_orientation_struct int16_t cur_subframe_samples_rendered; int16_t subframe_idx_start; int16_t cur_subframe_samples_rendered_start; +#ifdef IVAS_RTPDUMP + int8_t enableHeadTrackingPI; +#endif } COMBINED_ORIENTATION_DATA, *COMBINED_ORIENTATION_HANDLE; /*----------------------------------------------------------------------------------* diff --git a/lib_util/disable_headtracking_file_reader.c b/lib_util/disable_headtracking_file_reader.c new file mode 100644 index 0000000000..985733dc83 --- /dev/null +++ b/lib_util/disable_headtracking_file_reader.c @@ -0,0 +1,169 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + + +#include "disable_headtracking_file_reader.h" +#include +#include +#include +#include "prot.h" + +#ifdef IVAS_RTPDUMP + +struct DisableHeadtrackingFileReader +{ + FILE *inputFile; + int32_t frameCounter; + char *file_path; + bool fileRewind; +}; + + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReader_open() + * + * Allocate and initialize file reader + *-----------------------------------------------------------------------*/ + +ivas_error DisableHeadtrackingFileReader_open( + char *filePath, /* i : disable-headtracking input file name */ + DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ +) +{ + DisableHeadtrackingFileReader *self; + FILE *inputFile; + + /* Open trajectory file */ + if ( strlen( filePath ) < 1 ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + inputFile = fopen(filePath, "r" ); + + if ( !inputFile ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + self = calloc( sizeof( DisableHeadtrackingFileReader ), 1 ); + self->inputFile = inputFile; + self->frameCounter = 0; + self->file_path = calloc( sizeof( char ), strlen( filePath ) + 1 ); + strcpy( self->file_path, filePath ); + self->fileRewind = false; + + *fileReader = self; + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReading() + * + * Read values from the input file. (1) to disable and (0) to enable headtracking. + *-----------------------------------------------------------------------*/ + +ivas_error DisableHeadtrackingFileReading( + DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ + bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ +) +{ + float disableHeadTrackingFlag; + int32_t read_values; + + /* Initial values, if they are not read from the file (enable headtracking by default) */ + disableHeadTrackingFlag = 0; + + read_values = fscanf(fileReader->inputFile, "%f", &disableHeadTrackingFlag ); + if ( ( read_values != 1 ) ) + { + if ( feof( fileReader->inputFile ) ) + { + rewind( fileReader->inputFile ); + fileReader->fileRewind = true; + return DisableHeadtrackingFileReading( fileReader, pHeadTrackingDisabled ); + } + return IVAS_ERR_FAILED_FILE_PARSE; + } + + ( fileReader->frameCounter )++; + + *pHeadTrackingDisabled = (int8_t) disableHeadTrackingFlag == 1 ? true : false; + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReader_close() + * + * Deallocates memory for the file reader + *-----------------------------------------------------------------------*/ + +void DisableHeadtrackingFileReader_close( + DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ +) +{ + if ( fileReader == NULL || *fileReader == NULL ) + { + return; + } + + fclose( ( *fileReader )->inputFile ); + free( ( *fileReader )->file_path ); + free( *fileReader ); + *fileReader = NULL; + + return; +} + + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReader_getFilePath() + * + * + *-----------------------------------------------------------------------*/ + +const char *DisableHeadtrackingFileReader_getFilePath( + DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ +) +{ + if ( fileReader == NULL ) + { + return NULL; + } + + return fileReader->file_path; +} +#endif diff --git a/lib_util/disable_headtracking_file_reader.h b/lib_util/disable_headtracking_file_reader.h new file mode 100644 index 0000000000..4d413b442c --- /dev/null +++ b/lib_util/disable_headtracking_file_reader.h @@ -0,0 +1,86 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_DISABLE_HEADTRACKING_FILE_READER_H +#define IVAS_DISABLE_HEADTRACKING_FILE_READER_H + +#include +#include "common_api_types.h" + +#ifdef IVAS_RTPDUMP + +typedef struct DisableHeadtrackingFileReader DisableHeadtrackingFileReader; + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReader_open() + * + * Allocate and initialize reader handle + *-----------------------------------------------------------------------*/ + +ivas_error DisableHeadtrackingFileReader_open( + char *filePath, /* i : disable-headtracking input file name */ + DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ +); + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReading() + * + * Read values from the input file. (1) to disable and (0) to enable headtracking. + *-----------------------------------------------------------------------*/ + +ivas_error DisableHeadtrackingFileReading( + DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ + bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ +); + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReader_close() + * + * Deallocates memory for the reader handle + *-----------------------------------------------------------------------*/ + +void DisableHeadtrackingFileReader_close( + DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ +); + +/*-----------------------------------------------------------------------* + * DisableHeadtrackingFileReader_getFilePath() + * + * + *-----------------------------------------------------------------------*/ + +const char *DisableHeadtrackingFileReader_getFilePath( + DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ +); +#endif + +#endif /* IVAS_DISABLE_HEADTRACKING_FILE_READER_H */ diff --git a/lib_util/evs_rtp_payload.c b/lib_util/evs_rtp_payload.c index c122716f31..c32c77e22a 100644 --- a/lib_util/evs_rtp_payload.c +++ b/lib_util/evs_rtp_payload.c @@ -37,6 +37,7 @@ #include #include #include "evs_rtp_payload.h" +#include "options.h" static void evsPayload_unpackFrame_compact_amrWbIo( const char *payload, uint16_t payloadSizeBits, uint16_t iProtectedSize, unsigned char **framePtr, uint16_t *frameSizeInBits ) { @@ -123,7 +124,11 @@ bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBy frameFollowing, frameTypeIndex, qBit, framePtr, frameSizeInBits ); } +#ifdef IVAS_RTPDUMP +void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ) +#else static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ) +#endif { bool evsModeBit = ( toc & 0x20 ) != 0; *isAMRWB_IOmode = evsModeBit; diff --git a/lib_util/evs_rtp_payload.h b/lib_util/evs_rtp_payload.h index 004ecf79b6..1ea8ad16d4 100644 --- a/lib_util/evs_rtp_payload.h +++ b/lib_util/evs_rtp_payload.h @@ -161,6 +161,11 @@ extern "C" bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **framePtr, uint16_t *frameSizeBits ); +#ifdef IVAS_RTPDUMP + void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); +#else + static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); +#endif bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); typedef struct diff --git a/lib_util/g192.c b/lib_util/g192.c index 09ce7248d9..7cd222e241 100644 --- a/lib_util/g192.c +++ b/lib_util/g192.c @@ -483,7 +483,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 6d6104d453..d24e409cae 100644 --- a/lib_util/g192.h +++ b/lib_util/g192.h @@ -93,7 +93,13 @@ 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 ); -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 ); +G192_ERROR G192_WriteVoipFrame_short( G192_HANDLE const hG192, const uint16_t *serial, const int16_t num_bits, uint16_t const rtpSequenceNumber, +#ifdef IVAS_RTPDUMP + uint32_t const rtpTimeStamp, +#else + uint16_t const rtpTimeStamp, +#endif + uint32_t const rcvTime_ms ); G192_ERROR G192_Writer_Close( G192_HANDLE *phG192 ); diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c new file mode 100644 index 0000000000..9700d47c23 --- /dev/null +++ b/lib_util/ivas_rtp_payload.c @@ -0,0 +1,1081 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include +#include "evs_rtp_payload.h" +#include "ivas_rtp_payload.h" +#include "ivas_prot.h" +#include "prot.h" + +#ifdef IVAS_RTPDUMP + + +/*-----------------------------------------------------------------------* + * writeByteToRtp() + * + * Write a single byte (value) to RTP packet. + *-----------------------------------------------------------------------*/ + +static void writeByteToRtp( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + char value /* i : Value to be written to the RTP packet */ +) +{ + self->rtpPacket.data[self->writingIndex] = value; + ++self->writingIndex; + self->rtpPacket.payloadSize += 1; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parseToc() + * + * Parse a single ToC byte for an IVAS payload. + *-----------------------------------------------------------------------*/ + +static void ivasPayload_parseToc( + uint8_t toc, /* i : ToC byte to be parsed */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + int32_t *bitrate /* o : Bitrate of the data frame indicated in the ToC byte */ +) +{ + bool isIvasToc = ( toc & 0x30 ) == 0x10; // xx01 xxxx + if ( !isIvasToc ) + { + evsHeaderFullPayload_parseToc(toc, evsIvasModeBit, frameFollowing, bitrateIndex, ivasIndicatorBit, bitrate ); + } + else + { + *evsIvasModeBit = false; + *ivasIndicatorBit = true; + *frameFollowing = ( toc & 0x40 ) != 0; + *bitrateIndex = toc & 0x0f; + *bitrate = IVASmode2rate[*bitrateIndex]; + } +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parsePItype() + * + * Parse a single PI type and set the PIdataCurrentFrame handle accordingly. + *-----------------------------------------------------------------------*/ + +static void ivasPayload_parsePItype( + char *PIframeDataBeginning, /* i : Pointer to the beginning of the PI data section in the RTP packet */ + uint16_t PIframeSizeBytes, /* i : PI data frame size in bytes */ + uint16_t parsedPIframeSizeBytes, /* i : Size of previously parsed PI frame data section in bytes */ + uint16_t PIframeType, /* i : Type of the PI data frame */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ +) +{ + if ( PIframeType == PI_SCENE_ORIENTATION ) + { + PIdataCurrentFrame->sceneOrientation = PIframeDataBeginning + parsedPIframeSizeBytes; + } + else if ( PIframeType == PI_DEVICE_ORIENTATION_COMPENSATED ) + { + PIdataCurrentFrame->deviceOrientationCompensated = PIframeDataBeginning + parsedPIframeSizeBytes; + } + else if ( PIframeType == PI_DEVICE_ORIENTATION_UNCOMPENSATED ) + { + PIdataCurrentFrame->deviceOrientationUncompensated = PIframeDataBeginning + parsedPIframeSizeBytes; + } + else if ( PIframeType == PI_ACOUSTIC_ENVIRONMENT ) + { + if ( PIframeSizeBytes == PI_ACOUSTIC_ENVIRONMENT_ID_SIZE_BYTES ) + { + PIdataCurrentFrame->acousticEnvironmentId = PIframeDataBeginning + parsedPIframeSizeBytes; + } + else if ( PIframeSizeBytes == PI_ACOUSTIC_ENVIRONMENT_ONLY_LATE_REVERB_SIZE_BYTES ) + { + PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb = PIframeDataBeginning + parsedPIframeSizeBytes; + } + else if ( PIframeSizeBytes == PI_ACOUSTIC_ENVIRONMENT_LATE_REVERB_AND_EARLY_REFLECTIONS_SIZE_BYTES ) + { + PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections = PIframeDataBeginning + parsedPIframeSizeBytes; + } + } + else if ( PIframeType == PI_ENABLE_HEADTRACKING ) + { + PIdataCurrentFrame->enableHeadTracking = true; + } + else if ( PIframeType == PI_DISABLE_HEADTRACKING ) + { + PIdataCurrentFrame->disableHeadTracking = true; + } + else if ( PIframeType == PI_NO_DATA ) + { + /* no data */ + } + else + { + /* reserved */ + } +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_PIaddHeaderBytes() + * + * Add PI header section bytes to the PI data pointers for the current audio frame. + *-----------------------------------------------------------------------*/ + +static void ivasPayload_PIaddHeaderBytes( + uint16_t PIheaderSizeBytes, /* i : Size of the PI header section in bytes */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ +) +{ + if ( PIdataCurrentFrame->sceneOrientation != NULL ) + { + PIdataCurrentFrame->sceneOrientation += PIheaderSizeBytes; + } + if ( PIdataCurrentFrame->deviceOrientationCompensated != NULL ) + { + PIdataCurrentFrame->deviceOrientationCompensated += PIheaderSizeBytes; + } + if ( PIdataCurrentFrame->deviceOrientationUncompensated != NULL ) + { + PIdataCurrentFrame->deviceOrientationUncompensated += PIheaderSizeBytes; + } + if ( PIdataCurrentFrame->acousticEnvironmentId != NULL ) + { + PIdataCurrentFrame->acousticEnvironmentId += PIheaderSizeBytes; + } + if ( PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb != NULL ) + { + PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb += PIheaderSizeBytes; + } + if ( PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections != NULL ) + { + PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections += PIheaderSizeBytes; + } +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parsePIdata() + * + * Parse PI data for the current audio frame. + *-----------------------------------------------------------------------*/ + +static bool ivasPayload_parsePIdata( + char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ + uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ + uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ +) +{ + // TODO(pajunen): can this accidentally include zero padding bits? + + bool somePIframeFollowing; + char *PIframeDataBeginning; + uint16_t PIframeMarker, PIframeType, tempPIframeSizeBytes, PIframeSizeBytes, totalPIframeSizeBytes, totalPIheaderSizeBytes, count_audio; + PIframeDataBeginning = PIdataPayload; + somePIframeFollowing = true; + totalPIframeSizeBytes = 0; + totalPIheaderSizeBytes = 0; + count_audio = 0; + + while ( somePIframeFollowing ) + { + if ( (int16_t) PIdataPayloadSizeBytes <= 0 ) + { + fprintf( stderr, "Error: PI payload too small\n" ); + return false; + } + + /* parse PI data header */ + somePIframeFollowing = ( *PIdataPayload & 0x80 ) != 0; + PIframeMarker = ( *PIdataPayload & 0x60 ) >> 5; + PIframeType = ( *PIdataPayload & 0x1F ); + ++PIdataPayload; + ++totalPIheaderSizeBytes; + --PIdataPayloadSizeBytes; + tempPIframeSizeBytes = ( *PIdataPayload & 0xFF ); + PIframeSizeBytes = tempPIframeSizeBytes; + while ( tempPIframeSizeBytes == 255 ) + { + ++PIdataPayload; + ++totalPIheaderSizeBytes; + --PIdataPayloadSizeBytes; + tempPIframeSizeBytes = ( *PIdataPayload & 0xFF ); + PIframeSizeBytes += tempPIframeSizeBytes; + } + ++PIdataPayload; + ++totalPIheaderSizeBytes; + --PIdataPayloadSizeBytes; + PIdataPayloadSizeBytes -= PIframeSizeBytes; + + /* general PI data for all frames */ + if ( PIframeMarker == PM_GENERAL ) + { + ivasPayload_parsePItype(PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); + } + else + { + /* current frame */ + if ( ( PIframeMarker > 0 ) & ( count_audio == frameIndex ) ) + { + ivasPayload_parsePItype(PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); + } + + /* increase audio frame counter */ + if ( PIframeMarker == PM_LAST ) + { + ++count_audio; + } + } + totalPIframeSizeBytes += PIframeSizeBytes; + } + ivasPayload_PIaddHeaderBytes( totalPIheaderSizeBytes, PIdataCurrentFrame ); + + return true; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_convertFromQ15() + * + * Convert a Q15 encoded value to a float value. + *-----------------------------------------------------------------------*/ + +static float ivasPayload_convertFromQ15( uint16_t Q15Value ) +{ + float temp; + temp = (float)( Q15Value & 0x7FFF ) / 0x7FFF; + return ( Q15Value & 0x8000 ) ? -temp : temp; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_convertToQ15() + * + * Convert a float value into a Q15 encoded value. + *-----------------------------------------------------------------------*/ + +static uint16_t ivasPayload_convertToQ15( float value ) +{ + uint16_t temp; + temp = (uint16_t)( fabsf( value ) * 0x7FFF ); + if ( value >= 0.0f ) + { + temp = temp & 0x7FFF; + } + else + { + temp = temp | 0x8000; + } + return temp; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_convertOrientationToQ15() + * + * Convert a float quaternion into a Q15 encoded quaternion. + *-----------------------------------------------------------------------*/ + +static void ivasPayload_convertOrientationToQ15( + IVAS_QUATERNION *orientation, /* i : Input orientation in quaternion to be converted to Q15 */ + IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ +) +{ + orientationQ15->w = ivasPayload_convertToQ15( orientation->w ); + orientationQ15->x = ivasPayload_convertToQ15( orientation->x ); + orientationQ15->y = ivasPayload_convertToQ15( orientation->y ); + orientationQ15->z = ivasPayload_convertToQ15( orientation->z ); +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parseQuaternionValue() + * + * Parse a single Q15 encoded quaternion component from the RTP packet and convert it to float. + *-----------------------------------------------------------------------*/ + +static float ivasPayload_parseQuaternionComponent( + char **PIorientationData /* i/o: Pointer to the PI data frame containing a single quaternion component */ +) +{ + uint16_t tempQ15value; + tempQ15value = (uint16_t) **PIorientationData; + tempQ15value = ( tempQ15value << 8 ) | (uint16_t) *( *PIorientationData + 1 ); + *PIorientationData += 2; + return ivasPayload_convertFromQ15( tempQ15value ); +} + + +/*-----------------------------------------------------------------------* + * resetPIdataCurrentFrame() + * + * Reset the PI data handle for the current audio frame. + *-----------------------------------------------------------------------*/ + +void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) +{ + PIdataCurrentFrame->PIdataPresent = false; + PIdataCurrentFrame->sceneOrientation = NULL; + PIdataCurrentFrame->deviceOrientationCompensated = NULL; + PIdataCurrentFrame->deviceOrientationUncompensated = NULL; + PIdataCurrentFrame->acousticEnvironmentId = NULL; + PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb = NULL; + PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections = NULL; + PIdataCurrentFrame->enableHeadTracking = false; + PIdataCurrentFrame->disableHeadTracking = false; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parseOrientationPIdata() + * + * Parse a single orientation in quaternions from the PI data. + *-----------------------------------------------------------------------*/ + +bool ivasPayload_parseOrientationPIdata( + char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ + IVAS_QUATERNION *q /* o : Parsed quaternion value */ +) +{ + q->w = ivasPayload_parseQuaternionComponent(&PIorientationData); + q->x = ivasPayload_parseQuaternionComponent(&PIorientationData); + q->y = ivasPayload_parseQuaternionComponent(&PIorientationData); + q->z = ivasPayload_parseQuaternionComponent(&PIorientationData); + + if ( q->w > 1.0f || q->w < -1.0f || + q->x > 1.0f || q->x < -1.0f || + q->y > 1.0f || q->y < -1.0f || + q->z > 1.0f || q->z < -1.0f ) + { + fprintf( stderr, "Error: invalid orientation PI data\n" ); + return false; + } + return true; +} + +bool ivasPayload_unpackFrame( + char *payload, /* i : RTP payload data */ + uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ + uint16_t frameIndex, /* i : Index for the data frame in the payload */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeInBits, /* o : Data frame size in bits */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ +) +{ + bool someEvsIvasModeBit, someFrameFollowing, someIvasIndicatorBit; + uint16_t someBitrateIndex, someFrameSizeInBits, fullPayloadSizeBytes, PIdataPayloadSizeBytes; + int32_t bitrate; + uint16_t iFrame; + char *PIdataPayload; + fullPayloadSizeBytes = payloadSizeBytes; + PIdataPayload = payload; + someFrameFollowing = true; + if ( payloadSizeBytes < 1 ) + { + fprintf( stderr, "Error: payload too small to parse ToC\n" ); + return false; + } + /* parse CMR/E-bytes */ + if ( *payload & E_BYTE ) // 1xxx xxxx + { + PIdataCurrentFrame->PIdataPresent = false; + while (1) + { + if ( ( *payload & 0xF0 ) == IVAS_E_CMR ) // 1111 xxxx + { + /* IVAS CMR/E-byte */ + while (1) + { + /* parse subsequent E-bytes */ + ++payload; + --payloadSizeBytes; + if ( ( *payload & 0xE0 ) == IVAS_E_BW_REQUEST ) // 100x xxxx + { + /* IVAS bandwidth request */ + if ( ( *payload & 0xFF ) == IVAS_BW_REQ_WB ) // 1000 0000 + { + /* Wideband request */ + } + else if ( ( *payload & 0xFF ) == IVAS_BW_REQ_SWB ) // 1000 0001 + { + /* Super-wideband request */ + } + else if ( ( *payload & 0xFF ) == IVAS_BW_REQ_FB ) // 1000 0010 + { + /* Fullband request */ + } + } + else if ( ( *payload & 0xE0 ) == IVAS_E_FMT_REQUEST ) // 101x xxxx + { + /* IVAS coded format request */ + if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_STEREO ) // 1010 0000 + { + /* Stereo request */ + } + else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_SBA ) // 1010 0001 + { + /* SBA request */ + } + else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_MASA ) // 1010 0010 + { + /* MASA request */ + } + else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_ISM ) // 1010 0011 + { + /* ISM request */ + } + else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_MC ) // 1010 0100 + { + /* MC request */ + } + else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_OMASA ) // 1010 0101 + { + /* OMASA request */ + } + else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_OSBA ) // 1010 0110 + { + /* OSBA request */ + } + } + else if ( ( *payload & 0xE0 ) == IVAS_E_PI_INDICATION ) // 110x xxxx + { + /* IVAS PI presence */ + PIdataCurrentFrame->PIdataPresent = true; + } + else if ( ( *payload & 0xE0 ) == IVAS_E_RESERVED ) // 111x xxxx + { + /* Reserved IVAS subsequent E-byte */ + } + else + { + break; + } + + if ( payloadSizeBytes < 1 ) + { + fprintf( stderr, "Error: payload too small to parse subsequent E-bytes\n" ); + return false; + } + } + break; + } + else + { + /* EVS CMR */ + ++payload; + --payloadSizeBytes; + if ( *payload & E_BYTE ) // 1xxx xxxx + { + continue; + } + else + { + break; + } + } + } + } + + /* parse all ToC entries */ + *frame = (unsigned char *) payload; /* no need to copy frame bytes */ + for ( iFrame = 0; someFrameFollowing; ++iFrame ) + { + if ( (int16_t) payloadSizeBytes <= 0 ) + { + fprintf( stderr, "Error: payload too small\n" ); + return false; + } + if ( *payload & E_BYTE ) // 1xxx xxxx + { + fprintf( stderr, "Error: expected ToC, found CMR/E-byte\n" ); + return false; + } + ivasPayload_parseToc(*payload, &someEvsIvasModeBit, &someFrameFollowing, &someBitrateIndex, &someIvasIndicatorBit, &bitrate ); + if ( bitrate < 0 ) + { + fprintf( stderr, "Error: unexpected frameTypeIndex in ToC\n" ); + return false; + } + ++payload; + ++*frame; + someFrameSizeInBits = (uint16_t) ( bitrate / 50 ); + /* just keep/copy zero padding bits + * in case of AMRWB_IO_SID the STI bit and CMI bits following the SID_1k75 frame are also kept (A.2.2.1.3 of TS 26.445) */ + payloadSizeBytes -= 1 + ( someFrameSizeInBits + 7 ) / 8; + if ( iFrame < frameIndex ) + { + *frame += ( someFrameSizeInBits + 7 ) / 8; + if ( !someFrameFollowing ) + { + fprintf( stderr, "Error: expected ToC with F bit set\n" ); + return false; + } + } + else if ( iFrame == frameIndex ) + { + *evsIvasModeBit = someEvsIvasModeBit; + *frameFollowing = someFrameFollowing; + *bitrateIndex = someBitrateIndex; + *ivasIndicatorBit = someIvasIndicatorBit; + *frameSizeInBits = someFrameSizeInBits; + } + if ( (int16_t) payloadSizeBytes < 0 ) + { + fprintf( stderr, "Error: payload too small for frame %u data\n", frameIndex ); + return false; + } + } + + /* parse PI data */ + if ( PIdataCurrentFrame->PIdataPresent ) + { + PIdataPayloadSizeBytes = payloadSizeBytes; + PIdataPayload += ( fullPayloadSizeBytes - PIdataPayloadSizeBytes ); + if ( !ivasPayload_parsePIdata( PIdataPayload, PIdataPayloadSizeBytes, frameIndex, PIdataCurrentFrame ) ) + { + fprintf( stderr, "Error while parsing PI data\n" ); + return false; + } + } + + return true; +} + +IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( + IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ + FILE *file /* i : Input file containing the rtpdump */ +) +{ + RTPDUMP_ERROR rtpdumpError; + self->frameFollowing = false; + rtpdumpError = RTPDUMP_OpenWithFileToRead( &self->rtpdump, file ); + if ( rtpdumpError != RTPDUMP_NO_ERROR ) + { + return IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR; + } + resetPIdataCurrentFrame( &self->PIdataCurrentFrame ); + self->PIdataDepackerState.sceneOrientationSaved = false; + self->PIdataDepackerState.deviceOrientationSaved = false; + return IVAS_RTPDUMP_DEPACKER_NO_ERROR; +} + +IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( + IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ + uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ + uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ + uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeBits /* o : Data frame size in bits */ +) +{ + /* read next RTP packet from rtpdump */ + if ( !self->frameFollowing ) + { + RTPDUMP_ERROR rtpdumpError = RTPDUMP_ReadPacket( self->rtpdump, &self->rtpPacket, &self->timeoffset_ms ); + if ( rtpdumpError == RTPDUMP_READ_ENDOFFILE ) + { + return IVAS_RTPDUMP_DEPACKER_EOF; + } + else if ( rtpdumpError != RTPDUMP_NO_ERROR ) + { + return IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR; + } + self->frameIndex = 0; + } + /* unpack next frame from RTP packet */ + if ( !ivasPayload_unpackFrame( self->rtpPacket.data + self->rtpPacket.headerSize, + self->rtpPacket.payloadSize, self->frameIndex, + evsIvasModeBit, &self->frameFollowing, bitrateIndex, ivasIndicatorBit, + frame, frameSizeBits, &self->PIdataCurrentFrame ) ) + { + return IVAS_RTPDUMP_DEPACKER_PAYLOAD_ERROR; + } + + /* return frame */ + *rtpSequenceNumber = self->rtpPacket.sequenceNumber; + *rtpTimeStamp = self->rtpPacket.timeStamp + self->frameIndex * 16000 / 50; + *rcvTime_ms = self->timeoffset_ms + self->frameIndex * 20; + ++self->frameIndex; + return IVAS_RTPDUMP_DEPACKER_NO_ERROR; +} + +void IVAS_RTPDUMP_DEPACKER_close( + IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ +) +{ + if ( !self ) + { + return; + } + RTPDUMP_Close( &self->rtpdump, 0 ); +} + +IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( + IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ + FILE *file /* i : Output file for the rtpdump stream */ +) +{ + IVAS_RTPDUMP_PACKER *self; + RTPDUMP_ERROR rtpdumpError; + self = calloc( sizeof( IVAS_RTPDUMP_PACKER ), 1 ); + rtpdumpError = RTPDUMP_OpenWithFileToWrite( &self->rtpdump, file ); + if ( rtpdumpError != RTPDUMP_NO_ERROR ) + { + return IVAS_RTPDUMP_PACKER_RTPDUMP_ERROR; + } + RTPDUMP_SetDefaultRtpPacketHeader( &self->rtpPacket ); + memset( self->rtpPacket.data, 0, sizeof( self->rtpPacket.data ) ); + self->piDataPacker.sceneOrientationQuat = NULL; + self->piDataPacker.deviceOrientationQuat = NULL; + self->piDataPacker.enableHeadtracking = false; + self->piDataPacker.disableHeadtracking = false; + self->piDataPackerState.previousDisableHeadtrackingState = false; + self->piDataPresent = false; + *rtpdumpPacker = self; + return IVAS_RTPDUMP_PACKER_NO_ERROR; +} + +void IVAS_RTPDUMP_PACKER_writeEbytes( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). + * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ +) +{ + UWord8 initialEbyte, subsequentEbyte; + bool initialEbyteWritten; + + /* determine E-bytes */ + initialEbyte = 0; + subsequentEbyte = 0; + initialEbyteWritten = false; + if ( requestImmersiveFormatBitrate ) + { + switch ( requestedBitrate ) + { + case IVAS_13k2: + initialEbyte = IVAS_CMR_13k2; + break; + case IVAS_16k4: + initialEbyte = IVAS_CMR_16k4; + break; + case IVAS_24k4: + initialEbyte = IVAS_CMR_24k4; + break; + case IVAS_32k: + initialEbyte = IVAS_CMR_32k; + break; + case IVAS_48k: + initialEbyte = IVAS_CMR_48k; + break; + case IVAS_64k: + initialEbyte = IVAS_CMR_64k; + break; + case IVAS_80k: + initialEbyte = IVAS_CMR_80k; + break; + case IVAS_96k: + initialEbyte = IVAS_CMR_96k; + break; + case IVAS_128k: + initialEbyte = IVAS_CMR_128k; + break; + case IVAS_160k: + initialEbyte = IVAS_CMR_160k; + break; + case IVAS_192k: + initialEbyte = IVAS_CMR_192k; + break; + case IVAS_256k: + initialEbyte = IVAS_CMR_256k; + break; + case IVAS_384k: + initialEbyte = IVAS_CMR_384k; + break; + case IVAS_512k: + initialEbyte = IVAS_CMR_512k; + break; + default: + initialEbyte = IVAS_CMR_NO_REQ; + break; + } + writeByteToRtp( self, (char) initialEbyte ); + initialEbyteWritten = true; + } + else + { + /* EVS CMR */ + initialEbyteWritten = false; + } + + if ( ivasBandwidthRequest != NO_BANDWIDTH_REQUEST ) + { + if ( !initialEbyteWritten ) + { + initialEbyte = IVAS_CMR_NO_REQ; + writeByteToRtp( self, (char) initialEbyte ); + initialEbyteWritten = true; + } + + switch ( ivasBandwidthRequest ) + { + case WB_REQUEST: + subsequentEbyte = IVAS_BW_REQ_WB; + break; + case SWB_REQUEST: + subsequentEbyte = IVAS_BW_REQ_SWB; + break; + case FB_REQUEST: + subsequentEbyte = IVAS_BW_REQ_FB; + break; + default: + subsequentEbyte = IVAS_BW_NO_REQ; + break; + } + writeByteToRtp( self, (char) subsequentEbyte ); + } + + if ( ivasFormatRequest != NO_FORMAT_REQUEST ) + { + if ( !initialEbyteWritten ) + { + initialEbyte = IVAS_CMR_NO_REQ; + writeByteToRtp( self, (char) initialEbyte ); + initialEbyteWritten = true; + } + + switch ( ivasFormatRequest ) + { + case STEREO_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_STEREO; + break; + case SBA_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_SBA; + break; + case MASA_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_MASA; + break; + case ISM_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_ISM; + break; + case MC_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_MC; + break; + case OMASA_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_OMASA; + break; + case OSBA_REQUEST: + subsequentEbyte = IVAS_FMT_REQ_OSBA; + break; + default: + subsequentEbyte = IVAS_FMT_NO_REQ; + break; + } + writeByteToRtp( self, (char) subsequentEbyte ); + } + + if ( self->piDataPresent ) + { + if ( !initialEbyteWritten ) + { + initialEbyte = IVAS_CMR_NO_REQ; + writeByteToRtp( self, (char) initialEbyte ); + initialEbyteWritten = true; + } + subsequentEbyte = IVAS_PI_INDICATION; + writeByteToRtp( self, (char) subsequentEbyte ); + } +} + +void IVAS_RTPDUMP_PACKER_writeToc( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t frameBitrate, /* i : Bitrate of the written frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). + * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ + bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ +) +{ + UWord8 H_bit, F_bit, EVS_IVAS_mode_bit, Q_bit, toc; + int16_t is_amr_wb; + + is_amr_wb = 0; + H_bit = 0; + F_bit = someFrameFollowing ? 1 : 0; + /* FRAME_NO_DATA frames are written as in TS26.445 */ + if ( isImmersiveFormat && frameBitrate != FRAME_NO_DATA ) + { + toc = (UWord8)( rate2IVASmode( frameBitrate ) ); + EVS_IVAS_mode_bit = 0; + Q_bit = 1; + } + else + { + toc = (UWord8)( rate2EVSmode( frameBitrate, &is_amr_wb ) ); + EVS_IVAS_mode_bit = (UWord8) is_amr_wb; + Q_bit = 0; + } + toc = ( H_bit << 7 ) | ( F_bit << 6 ) | ( EVS_IVAS_mode_bit << 5 ) | ( Q_bit << 4 ) | toc; + writeByteToRtp( self, (char) toc ); +} + +IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ + int32_t numBits, /* i : Number of bits contained in the data frame */ + int32_t frameBitrate, /* i : Bitrate of the data frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ +) +{ + + RTPDUMP_ERROR rtpdumpError; + int32_t i, k; + char tempData; + + self->writingIndex = self->rtpPacket.headerSize; + self->rtpPacket.payloadSize = 0; + memset( self->rtpPacket.data, 0, sizeof( self->rtpPacket.data ) ); + + /* payload header */ + IVAS_RTPDUMP_PACKER_writeEbytes(self, requestedBitrate, requestImmersiveFormatBitrate, ivasBandwidthRequest, ivasFormatRequest ); + IVAS_RTPDUMP_PACKER_writeToc( self, frameBitrate, isImmersiveFormat, false ); + + /* frame data */ + for (i = 0; i < numBits; i += 8) { + tempData = 0; + for (k = 0; k < 8; ++k) { + tempData = ( tempData << 1 ) | (char) bitStream[i + k]; + } + writeByteToRtp( self, tempData ); + } + + /* PI data */ + IVAS_RTPDUMP_PACKER_writePIdata( self ); + + /* write packet */ + rtpdumpError = RTPDUMP_WritePacket( self->rtpdump, &self->rtpPacket, self->timeoffset_ms ); + if ( rtpdumpError != RTPDUMP_NO_ERROR ) + { + return IVAS_RTPDUMP_PACKER_RTPDUMP_ERROR; + } + + /* adjust packetizer values */ + self->rtpPacket.sequenceNumber += 1; + self->rtpPacket.timeStamp += 320; + self->timeoffset_ms += 20; + + return IVAS_RTPDUMP_PACKER_NO_ERROR; +} + +void IVAS_RTPDUMP_PACKER_writePIdata( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +) +{ + if ( !self->piDataPresent ) + { + return; + } + + UWord8 PIheaderByte; + IVAS_QUATERNION_Q15 sceneOrientationQ15, deviceOrientationQ15; + bool somePIfollowing = false; + + /* PI header section */ + + /* scene orientation */ + if ( self->piDataPacker.sceneOrientationQuat ) + { + if ( self->piDataPacker.deviceOrientationQuat || self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) + { + somePIfollowing = true; + } + if ( somePIfollowing ) + { + PIheaderByte = ( PF1 << 7 ) | ( PM_NOT_LAST << 5 ) | PI_SCENE_ORIENTATION; + } + else + { + PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_SCENE_ORIENTATION; + } + writeByteToRtp( self, (char) PIheaderByte ); + writeByteToRtp( self, PI_SCENE_ORIENTATION_SIZE_BYTES ); + } + + /* device orientation */ + if ( self->piDataPacker.deviceOrientationQuat ) + { + if ( self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) + { + somePIfollowing = true; + } + else + { + somePIfollowing = false; + } + if ( somePIfollowing ) + { + PIheaderByte = ( PF0 << 7 ) | ( PM_NOT_LAST << 5 ) | PI_DEVICE_ORIENTATION_UNCOMPENSATED; + } + else + { + PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_DEVICE_ORIENTATION_UNCOMPENSATED; + } + writeByteToRtp( self, (char) PIheaderByte ); + writeByteToRtp( self, PI_DEVICE_ORIENTATION_UNCOMPENSATED_SIZE_BYTES ); + } + + /* enable/disable headtracking */ + if ( self->piDataPacker.enableHeadtracking && !self->piDataPacker.disableHeadtracking ) + { + PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_ENABLE_HEADTRACKING; + writeByteToRtp( self, (char) PIheaderByte ); + writeByteToRtp( self, PI_ENABLE_HEADTRACKING_SIZE_BYTES ); + } + if ( self->piDataPacker.disableHeadtracking ) + { + PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_DISABLE_HEADTRACKING; + writeByteToRtp( self, (char) PIheaderByte ); + writeByteToRtp( self, PI_DISABLE_HEADTRACKING_SIZE_BYTES ); + } + + /* PI frame data section */ + + if ( self->piDataPacker.sceneOrientationQuat ) + { + ivasPayload_convertOrientationToQ15( self->piDataPacker.sceneOrientationQuat, &sceneOrientationQ15 ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.w >> 8 ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.w & 0x00FF ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.x >> 8 ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.x & 0x00FF ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.y >> 8 ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.y & 0x00FF ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.z >> 8 ) ); + writeByteToRtp( self, (char) ( sceneOrientationQ15.z & 0x00FF ) ); + } + + if ( self->piDataPacker.deviceOrientationQuat ) + { + ivasPayload_convertOrientationToQ15( self->piDataPacker.deviceOrientationQuat, &deviceOrientationQ15 ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.w >> 8 ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.w & 0x00FF ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.x >> 8 ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.x & 0x00FF ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.y >> 8 ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.y & 0x00FF ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.z >> 8 ) ); + writeByteToRtp( self, (char) ( deviceOrientationQ15.z & 0x00FF ) ); + } +} + +void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +) +{ + if ( self->piDataPacker.disableHeadtracking == self->piDataPackerState.previousDisableHeadtrackingState ) + { + /* same state as before, do not send PI data */ + self->piDataPacker.disableHeadtracking = false; + } + else if ( self->piDataPacker.disableHeadtracking && self->piDataPackerState.previousDisableHeadtrackingState == false ) + { + /* headtracking was enabled, send disable headtracking PI data */ + self->piDataPackerState.previousDisableHeadtrackingState = true; + } + else if ( !self->piDataPacker.disableHeadtracking && self->piDataPackerState.previousDisableHeadtrackingState == true ) + { + /* headtracking was disabled, send enable headtracking PI data */ + self->piDataPackerState.previousDisableHeadtrackingState = false; + self->piDataPacker.enableHeadtracking = true; + } +} + +void IVAS_RTPDUMP_PACKER_determinePIpresence( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +) +{ + self->piDataPresent = false; + if ( self->piDataPacker.sceneOrientationQuat || + self->piDataPacker.deviceOrientationQuat || + self->piDataPacker.enableHeadtracking || + self->piDataPacker.disableHeadtracking ) + { + self->piDataPresent = true; + } +} + +void IVAS_RTPDUMP_PACKER_resetPIdata( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +) +{ + self->piDataPresent = false; + self->piDataPacker.sceneOrientationQuat = NULL; + self->piDataPacker.deviceOrientationQuat = NULL; + self->piDataPacker.enableHeadtracking = false; + self->piDataPacker.disableHeadtracking = false; +} + +void IVAS_RTPDUMP_PACKER_close( + IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ +) +{ + if ( !self || !( *self ) ) + { + return; + } + RTPDUMP_Close( &( *self )->rtpdump, 0 ); + free( *self ); + *self = NULL; +} +#endif diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h new file mode 100644 index 0000000000..7adf4eb4b2 --- /dev/null +++ b/lib_util/ivas_rtp_payload.h @@ -0,0 +1,421 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_PAYLOAD_H +#define IVAS_RTP_PAYLOAD_H + +#pragma once +#include +#include +#include +#include "common_api_types.h" +#include "ivas_cnst.h" +#include "rtpdump.h" + +#ifdef IVAS_RTPDUMP + +#ifdef __cplusplus +extern "C" +{ +#endif + + +static const int32_t IVASmode2rate[16] = { + 13200, + 16400, + 24400, + 32000, + 48000, + 64000, + 80000, + 96000, + 128000, + 160000, + 192000, + 256000, + 384000, + 512000, + -1, /* Reserved */ + 5200 /* SID */ +}; + +typedef enum +{ + PF0 = 0, + PF1 = 1 +} PI_PF; + +typedef enum +{ + PM_RESERVED = 0, + PM_NOT_LAST = 1, + PM_LAST = 2, + PM_GENERAL = 3 +} PI_PM; + +typedef enum +{ + PI_SCENE_ORIENTATION = 0, + PI_DEVICE_ORIENTATION_COMPENSATED = 1, + PI_DEVICE_ORIENTATION_UNCOMPENSATED = 2, + PI_ACOUSTIC_ENVIRONMENT = 3, + PI_ENABLE_HEADTRACKING = 4, + PI_DISABLE_HEADTRACKING = 5, + PI_NO_DATA = 31 +} PI_TYPE; + +typedef enum +{ + PI_SCENE_ORIENTATION_SIZE_BYTES = 8, + PI_DEVICE_ORIENTATION_COMPENSATED_SIZE_BYTES = 8, + PI_DEVICE_ORIENTATION_UNCOMPENSATED_SIZE_BYTES = 8, + PI_ACOUSTIC_ENVIRONMENT_ID_SIZE_BYTES = 1, + PI_ACOUSTIC_ENVIRONMENT_ONLY_LATE_REVERB_SIZE_BYTES = 5, + PI_ACOUSTIC_ENVIRONMENT_LATE_REVERB_AND_EARLY_REFLECTIONS_SIZE_BYTES = 8, + PI_ENABLE_HEADTRACKING_SIZE_BYTES = 0, + PI_DISABLE_HEADTRACKING_SIZE_BYTES = 0, + PI_NO_DATA_SIZE_BYTES = 0 +} PI_SIZE_BYTES; + +typedef struct +{ + IVAS_QUATERNION *sceneOrientationQuat; + IVAS_QUATERNION *deviceOrientationQuat; + bool enableHeadtracking; + bool disableHeadtracking; +} PI_DATA_PACKER; + +typedef struct +{ + bool previousDisableHeadtrackingState; +} PI_DATA_PACKER_STATE; + +typedef struct +{ + uint16_t w, x, y, z; +} IVAS_QUATERNION_Q15; + +typedef enum +{ + IVAS_CMR_13k2 = 0xF0, // 1111 0000 + IVAS_CMR_16k4 = 0xF1, // 1111 0001 + IVAS_CMR_24k4 = 0xF2, // 1111 0010 + IVAS_CMR_32k = 0xF3, // 1111 0011 + IVAS_CMR_48k = 0xF4, // 1111 0100 + IVAS_CMR_64k = 0xF5, // 1111 0101 + IVAS_CMR_80k = 0xF6, // 1111 0110 + IVAS_CMR_96k = 0xF7, // 1111 0111 + IVAS_CMR_128k = 0xF8, // 1111 1000 + IVAS_CMR_160k = 0xF9, // 1111 1001 + IVAS_CMR_192k = 0xFA, // 1111 1010 + IVAS_CMR_256k = 0xFB, // 1111 1011 + IVAS_CMR_384k = 0xFC, // 1111 1100 + IVAS_CMR_512k = 0xFD, // 1111 1101 + IVAS_CMR_RESERVED = 0xFE, // 1111 1110 + IVAS_CMR_NO_REQ = 0xFF // 1111 1111 +} IVAS_INITIAL_E_BYTE; + +typedef enum +{ + IVAS_BW_REQ_WB = 0x80, // 1000 0000 + IVAS_BW_REQ_SWB = 0x81, // 1000 0001 + IVAS_BW_REQ_FB = 0x82, // 1000 0010 + IVAS_BW_NO_REQ = 0x83, // 1000 0011 + IVAS_FMT_REQ_STEREO = 0xA0, // 1010 0000 + IVAS_FMT_REQ_SBA = 0xA1, // 1010 0001 + IVAS_FMT_REQ_MASA = 0xA2, // 1010 0010 + IVAS_FMT_REQ_ISM = 0xA3, // 1010 0011 + IVAS_FMT_REQ_MC = 0xA4, // 1010 0100 + IVAS_FMT_REQ_OMASA = 0xA5, // 1010 0101 + IVAS_FMT_REQ_OSBA = 0xA6, // 1010 0110 + IVAS_FMT_NO_REQ = 0xA7, // 1010 0111 + IVAS_PI_INDICATION = 0xC0 // 1100 0000 +} IVAS_SUBSEQUENT_E_BYTE; + +typedef enum +{ + WB_REQUEST, + SWB_REQUEST, + FB_REQUEST, + NO_BANDWIDTH_REQUEST +} IVAS_BANDWIDTH_REQUEST; + +typedef enum +{ + STEREO_REQUEST, + SBA_REQUEST, + MASA_REQUEST, + ISM_REQUEST, + MC_REQUEST, + OMASA_REQUEST, + OSBA_REQUEST, + NO_FORMAT_REQUEST +} IVAS_FORMAT_REQUEST; + +typedef enum +{ + E_BYTE = 0x80, // 1xxx xxxx + IVAS_E_CMR = 0xF0, // 1111 xxxx + IVAS_E_BW_REQUEST = 0x80, // 100x xxxx + IVAS_E_FMT_REQUEST = 0xA0, // 101x xxxx + IVAS_E_PI_INDICATION = 0xC0, // 110x xxxx + IVAS_E_RESERVED = 0xE0 // 111x xxxx +} IVAS_E_BYTE_INDICATIONS; + +typedef struct +{ + RTPDUMP_HANDLE rtpdump; + RTPDUMP_RTPPACKET rtpPacket; + uint32_t timeoffset_ms; + uint16_t frameIndex; + bool frameFollowing; + PI_DATA_CURRENT_FRAME PIdataCurrentFrame; + PI_DATA_DEPACKER_STATE PIdataDepackerState; +} IVAS_RTPDUMP_DEPACKER; + +typedef struct +{ + RTPDUMP_HANDLE rtpdump; + RTPDUMP_RTPPACKET rtpPacket; + uint32_t timeoffset_ms; + PI_DATA_PACKER piDataPacker; + PI_DATA_PACKER_STATE piDataPackerState; + bool piDataPresent; + int32_t writingIndex; +} IVAS_RTPDUMP_PACKER; + +typedef enum +{ + IVAS_RTPDUMP_DEPACKER_NO_ERROR = 0, + IVAS_RTPDUMP_DEPACKER_EOF = -1, + IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR = 1, + IVAS_RTPDUMP_DEPACKER_PAYLOAD_ERROR +} IVAS_RTPDUMP_DEPACKER_ERROR; + +typedef enum +{ + IVAS_RTPDUMP_PACKER_NO_ERROR = 0, + IVAS_RTPDUMP_PACKER_RTPDUMP_ERROR = 1 +} IVAS_RTPDUMP_PACKER_ERROR; + + +/*-----------------------------------------------------------------------* + * ivasPayload_unpackFrame() + * + * Parse a single IVAS frame from the payload. Also read the IVAS payload header + * and parse the PI data associated with the IVAS frame. + *-----------------------------------------------------------------------*/ + +bool ivasPayload_unpackFrame( + char *payload, /* i : RTP payload data */ + uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ + uint16_t frameIndex, /* i : Index for the data frame in the payload */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeInBits, /* o : Data frame size in bits */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_DEPACKER_open() + * + * Open IVAS rtpdump depacker. + *-----------------------------------------------------------------------*/ + +IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( + IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ + FILE *file /* i : Input file containing the rtpdump */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_DEPACKER_readNextFrame() + * + * Unpack next frame from the RTP packet. If the packet is depleted, read the next RTP packet from the rtpdump. + *-----------------------------------------------------------------------*/ + +IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( + IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ + uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ + uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ + uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeBits /* o : Data frame size in bits */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_DEPACKER_close() + * + * Close IVAS rtpdump depacker. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_DEPACKER_close( + IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_open() + * + * Open IVAS rtpdump packer. + *-----------------------------------------------------------------------*/ + +IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( + IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ + FILE *file /* i : Output file for the rtpdump stream */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_writeEbytes() + * + * Write E-bytes (CMR and subsequent E-bytes) to the RTP packet. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_writeEbytes( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). + * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_writeToc() + * + * Write a single ToC byte to the RTP packet. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_writeToc( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t frameBitrate, /* i : Bitrate of the written frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). + * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ + bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_writeNextFrame() + * + * Write IVAS payload header, a single frame data and optional PI data to an RTP packet. + *-----------------------------------------------------------------------*/ + +IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ + int32_t numBits, /* i : Number of bits contained in the data frame */ + int32_t frameBitrate, /* i : Bitrate of the data frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_writePIdata() + * + * Write PI data section (PI headers and PI frame data) to the RTP packet. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_writePIdata( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState() + * + * Check for disable headtracking input and previously set disable/enable headtracking state. + * Set the current PI headtracking state accordingly. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_determinePIpresence() + * + * Check if there is PI data present for the current frame. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_determinePIpresence( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_resetPIdata() + * + * Reset PI data packer handle. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_resetPIdata( + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +); + + +/*-----------------------------------------------------------------------* + * IVAS_RTPDUMP_PACKER_close() + * + * Close IVAS rtpdump packer. + *-----------------------------------------------------------------------*/ + +void IVAS_RTPDUMP_PACKER_close( + IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ +); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif /* IVAS_RTP_PAYLOAD_H */ diff --git a/lib_util/rtpdump.c b/lib_util/rtpdump.c index 9f87849473..ad2345d236 100644 --- a/lib_util/rtpdump.c +++ b/lib_util/rtpdump.c @@ -264,6 +264,34 @@ RTPDUMP_OpenForWriting( RTPDUMP_HANDLE *phRTPDUMP, const char *filename ) return RTPDUMP_NO_ERROR; } + +#ifdef IVAS_RTPDUMP +RTPDUMP_ERROR +RTPDUMP_OpenWithFileToWrite( RTPDUMP_HANDLE *phRTPDUMP, FILE *file ) +{ + *phRTPDUMP = (RTPDUMP_HANDLE) calloc( 1, sizeof( struct RTPDUMP ) ); + if ( !phRTPDUMP || !( *phRTPDUMP ) ) + { + return RTPDUMP_MEMORY_ERROR; + } + + /* open file stream */ + ( *phRTPDUMP )->file = file; + if ( ( *phRTPDUMP )->file == NULL ) + { + return RTPDUMP_FILE_NOT_FOUND; + } + + if ( writeHeader( *phRTPDUMP ) != 0 ) + { + return RTPDUMP_INIT_ERROR; + } + + return RTPDUMP_NO_ERROR; +} + + +#endif RTPDUMP_ERROR RTPDUMP_ReadPacket( RTPDUMP_HANDLE hRTPDUMP, RTPDUMP_RTPPACKET *packet, diff --git a/lib_util/rtpdump.h b/lib_util/rtpdump.h index b97ec97d83..fa59bc9e6b 100644 --- a/lib_util/rtpdump.h +++ b/lib_util/rtpdump.h @@ -37,6 +37,7 @@ #pragma once #include #include +#include "options.h" #ifdef __cplusplus extern "C" @@ -83,6 +84,11 @@ extern "C" RTPDUMP_ERROR RTPDUMP_OpenForWriting( RTPDUMP_HANDLE *phRTPDUMP, const char *filename ); +#ifdef IVAS_RTPDUMP + RTPDUMP_ERROR + RTPDUMP_OpenWithFileToWrite( RTPDUMP_HANDLE *phRTPDUMP, FILE *file ); + +#endif RTPDUMP_ERROR RTPDUMP_ReadPacket( RTPDUMP_HANDLE hRTPDUMP, RTPDUMP_RTPPACKET *packet, diff --git a/readme.txt b/readme.txt index e6fbd729ea..d3e4a122b3 100644 --- a/readme.txt +++ b/readme.txt @@ -249,6 +249,13 @@ 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. +-scene_orientation : Scene orientation trajectory file. Only used with rtpdump output. +-device_orientation : Device orientation trajectory file. Only used with rtpdump output. +-disable_headtracking_file : Disable headtracking input file. (1) to disable and (0) to enable headtracking. Only used with rtpdump output. The usage of the "IVAS_dec" program is as follows: @@ -274,9 +281,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 -fec_cfg_file : Optimal channel aware configuration computed by the JBM -- GitLab From 8f8e5ba3be1ea10ee0e88c21d9c7d423c01ba5f8 Mon Sep 17 00:00:00 2001 From: Stefan Doehla Date: Mon, 17 Feb 2025 14:19:10 +0100 Subject: [PATCH 02/33] [fix] merge conflicts --- lib_com/common_api_types.h | 3 --- lib_enc/lib_enc.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index ade2a44ab1..443963c364 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -213,7 +213,6 @@ typedef struct _IVAS_JBM_TRACE_DATA } IVAS_JBM_TRACE_DATA; -<<<<<<< HEAD #ifdef IVAS_RTPDUMP typedef struct { @@ -236,7 +235,6 @@ typedef struct IVAS_QUATERNION deviceOrientationQuat; } PI_DATA_DEPACKER_STATE; #endif -======= typedef enum _ivas_binaural_renderer_type { IVAS_BIN_RENDERER_TYPE_NONE, @@ -247,7 +245,6 @@ typedef enum _ivas_binaural_renderer_type IVAS_BIN_RENDERER_TYPE_DEFAULT, } IVAS_BIN_RENDERER_TYPE; ->>>>>>> main /*----------------------------------------------------------------------------------* * Split rendering API constants, structures, and enums diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index 2cd3bcc3e5..167dcfb7e4 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -2435,7 +2435,7 @@ bool IVAS_isImmersiveFormat( return false; } return true; - +} #endif #ifdef DEBUGGING -- GitLab From c4ca71cb7cd579354242e3b41b08ece8dff27bc3 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 27 Feb 2025 16:12:30 +0200 Subject: [PATCH 03/33] Update MSVC project with RTPdump files --- Workspace_msvc/lib_util.vcxproj | 4 ++++ Workspace_msvc/lib_util.vcxproj.filters | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index bead7110f3..28832eb4f0 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -108,8 +108,10 @@ + + @@ -137,8 +139,10 @@ + + diff --git a/Workspace_msvc/lib_util.vcxproj.filters b/Workspace_msvc/lib_util.vcxproj.filters index 8fc8082d1a..f3824f1fe4 100644 --- a/Workspace_msvc/lib_util.vcxproj.filters +++ b/Workspace_msvc/lib_util.vcxproj.filters @@ -82,6 +82,12 @@ util_c + + util_c + + + util_c + @@ -171,6 +177,12 @@ util_h + + util_h + + + util_h + -- GitLab From ce724717a4c44abe5007a320bd18d5bfeabd1333 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Tue, 4 Mar 2025 16:47:19 +0200 Subject: [PATCH 04/33] Use 'rb' for opening bitstream file for RTPdump reading --- apps/decoder.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/decoder.c b/apps/decoder.c index b9191c5ed7..1e2de7189e 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3096,7 +3096,11 @@ static ivas_error decodeVoIP( { case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: +#ifdef IVAS_RTPDUMP + f_rtpstream = fopen( arg.inputBitstreamFilename, "rb" ); +#else f_rtpstream = fopen( arg.inputBitstreamFilename, "r" ); +#endif if ( f_rtpstream == NULL ) { -- GitLab From 3ad4e261bff94a4dd7831642f063a493e97f58f1 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Tue, 8 Apr 2025 14:19:58 +0300 Subject: [PATCH 05/33] Check also rptdumpPacker presence in if-statement --- apps/encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/encoder.c b/apps/encoder.c index 5aff394659..5e975ab21b 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -857,7 +857,7 @@ int main( } #ifdef IVAS_RTPDUMP - if ( rtpdumpPacker->rtpdump ) + if ( rtpdumpPacker && rtpdumpPacker->rtpdump ) { /* scene orientation */ if ( sceneOrientationFileReader ) -- GitLab From fb4b45b83722751467978fc2746e931ef7c61576 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Tue, 8 Apr 2025 16:01:16 +0300 Subject: [PATCH 06/33] Determine bitrate for rtpdump based on the number of encoded bits --- apps/encoder.c | 2 +- lib_util/ivas_rtp_payload.c | 20 ++++++++++++++++++-- lib_util/ivas_rtp_payload.h | 1 - 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/encoder.c b/apps/encoder.c index 5e975ab21b..c0966533e5 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -898,7 +898,7 @@ int main( IVAS_RTPDUMP_PACKER_determinePIpresence( rtpdumpPacker ); /* write rtpdump */ - rtpdumpPackerError = IVAS_RTPDUMP_PACKER_writeNextFrame( rtpdumpPacker, bitStream, numBits, totalBitrate, + rtpdumpPackerError = IVAS_RTPDUMP_PACKER_writeNextFrame( rtpdumpPacker, bitStream, numBits, IVAS_isImmersiveFormat( hIvasEnc ), 0, false, NO_BANDWIDTH_REQUEST, NO_FORMAT_REQUEST ); if ( rtpdumpPackerError != IVAS_RTPDUMP_PACKER_NO_ERROR ) { diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 9700d47c23..2366c65698 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -58,6 +58,21 @@ static void writeByteToRtp( } +/*-----------------------------------------------------------------------* + * determineBitrate() + * + * Determine bitrate based on the number of encoded bits. + *-----------------------------------------------------------------------*/ + +static void determineBitrate( + const int32_t numBits, /* i : Number of bits contained in the data frame */ + int32_t *frameBitrate /* o : Bitrate of the data frame */ +) +{ + *frameBitrate = numBits * IVAS_NUM_FRAMES_PER_SEC; +} + + /*-----------------------------------------------------------------------* * ivasPayload_parseToc() * @@ -871,7 +886,6 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ int32_t numBits, /* i : Number of bits contained in the data frame */ - int32_t frameBitrate, /* i : Bitrate of the data frame */ bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ @@ -881,13 +895,15 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( { RTPDUMP_ERROR rtpdumpError; - int32_t i, k; + int32_t i, k, frameBitrate; char tempData; self->writingIndex = self->rtpPacket.headerSize; self->rtpPacket.payloadSize = 0; memset( self->rtpPacket.data, 0, sizeof( self->rtpPacket.data ) ); + determineBitrate( numBits, &frameBitrate ); + /* payload header */ IVAS_RTPDUMP_PACKER_writeEbytes(self, requestedBitrate, requestImmersiveFormatBitrate, ivasBandwidthRequest, ivasFormatRequest ); IVAS_RTPDUMP_PACKER_writeToc( self, frameBitrate, isImmersiveFormat, false ); diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index 7adf4eb4b2..159e18a384 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -348,7 +348,6 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ int32_t numBits, /* i : Number of bits contained in the data frame */ - int32_t frameBitrate, /* i : Bitrate of the data frame */ bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ -- GitLab From 6a4215f7faa1156c8b26467538cd9c45a446d257 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Tue, 22 Apr 2025 13:01:23 +0300 Subject: [PATCH 07/33] Add rtpdump tests to self_test parameter file --- scripts/config/self_test.prm | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/scripts/config/self_test.prm b/scripts/config/self_test.prm index 7db62aef58..7dd2d2e301 100644 --- a/scripts/config/self_test.prm +++ b/scripts/config/self_test.prm @@ -306,6 +306,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -dtx -stereo ../scripts/switchPaths/sw_13k2_to_128k_10fr.bin 48 testv/stvST48c.wav bit ../IVAS_dec EXT 48 bit testv/stvST48c.wav_stereo_sw_48-48_DTX_EXT.tst +// stereo bitrate switching from 13.2 kbps to 128 kbps, 48kHz in, 48kHz out, DTX on, EXT out, rtpdump +../IVAS_cod -rtpdump -dtx -stereo ../scripts/switchPaths/sw_13k2_to_128k_10fr.bin 48 testv/stvST48c.wav bit +../IVAS_dec -VOIP_hf_only=1 EXT 48 bit testv/stvST48c.wav_stereo_sw_48-48_DTX_EXT_rtpdump.tst // 1 ISM with metadata at 13.2 kbps, 48 kHz in, 48 kHz out, EXT out @@ -580,6 +583,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -ism +4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv 128000 48 testv/stv4ISM48n.wav bit ../IVAS_dec BINAURAL_ROOM_REVERB 48 bit testv/stv4ISM48n.wav_BINAURAL_ROOM_REVERB_128000_48-48.tst +// 4 ISM with metadata bitrate switching from 24.4 kbps to 512 kbps, 48 kHz in, 48 kHz out, DTX on, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case00_3000_q.csv -dtx -ism 4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv ../scripts/switchPaths/sw_24k4_512k.bin 48 testv/stv4ISM48s.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv4ISM48s.wav_brate_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst // SBA at 13.2 kbps, 32kHz in, 32kHz out, HOA3 out, bandwidth switching @@ -958,6 +964,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -sba 3 96000 48 testv/stv3OA48c.wav bit ../IVAS_dec -render_config testv/rend_config_recreation.cfg BINAURAL_ROOM_REVERB 48 bit testv/stv3OA48c.wav_BINAURAL_ROOM_REVERB_96000_48-48_custom_configuration.tst +// SBA FOA bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, DTX on, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot_case01_3000_q.csv -device_orientation testv/headrot_case02_3000_q.csv -dtx -sba 1 -max_band fb ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvFOA48c.wav bit +../IVAS_dec -VOIP_hf_only=1 FOA 48 bit testv/stvFOA48c.wav_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst // MASA 1dir 1TC at 13.2 kbps, 48kHz in, 48kHz out, BINAURAL out, bandwidth switching @@ -1238,6 +1247,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -masa 1 testv/stv1MASA1TC48c.met 256000 48 testv/stv1MASA1TC48c.wav bit ../IVAS_dec -render_config testv/rend_config_combined.cfg -t testv/headrot.csv BINAURAL_ROOM_REVERB 48 bit testv/stv1MASA1TC48c.wav_BINAURAL_ROOM_REVERB_256000_48-48_Headrot_custom_config.tst +// MASA 2dir 2TC bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, DTX on, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot_case03_3000_q.csv -device_orientation testv/headrot.csv -dtx -masa 2 testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stv2MASA2TC48c.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv2MASA2TC48c.wav_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst // Multi-channel 5_1 at 13.2 kbps, 48kHz in, 48kHz out @@ -1561,6 +1573,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -mc 7_1_4 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv714MC48c.wav bit ../IVAS_dec EXT 48 bit testv/stv714MC48c.wav_sw_48-48_EXT.tst +// Multi-channel 5_1 bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, DTX on, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case02_3000_q.csv -dtx -mc 5_1 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv51MC48c.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv51MC48c.wav_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst // Stereo downmix to bit-exact EVS at 13200 kbps, 32kHz in, 32kHz out @@ -1571,6 +1586,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -stereo_dmx_evs 24400 48 testv/stvST48c.wav bit ../IVAS_dec 48 bit testv/stvST48c.wav_StereoDmxEVS_24400_48-48.tst +// Stereo downmix to bit-exact EVS at 24400 kbps, 48kHz in, 48kHz out, rtpdump +../IVAS_cod -rtpdump -stereo_dmx_evs 24400 48 testv/stvST48c.wav bit +../IVAS_dec -VOIP_hf_only=1 48 bit testv/stvST48c.wav_StereoDmxEVS_24400_48-48_rtpdump.tst // EVS non-diegetic panning at 64 kbps, 48kHz in, 48kHz out, STEREO out @@ -1581,6 +1599,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -ism 1 testv/stvISM1.csv 32000 48 testv/stv1ISM48s.wav bit ../IVAS_dec -non_diegetic_pan 80 STEREO 48 bit testv/stv1ISM48s.pcm_ISM_32000_48-48_STEREO_NON-DIEGETIC-PAN_80.tst +// EVS at 13.2 kbps, 48kHz in, 48kHz out, STEREO out, rtpdump +../IVAS_cod -rtpdump 13200 48 testv/stv48c.wav bit +../IVAS_dec -VOIP_hf_only=1 48 bit testv/stv48c.pcm_EVS_13200_48-48_STEREO_rtpdump.tst // stereo at 32 kbps, 48 kHz in, 32 kHz out, DTX on, JBM Prof 0 ../IVAS_cod -stereo -dtx 32000 48 testv/stvST48n.wav bit @@ -1857,6 +1878,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -ism_masa 4 2 testv/stvISM1.csv NULL testv/stvISM3.csv testv/stvISM4.csv testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k_2fr_start_80k_omasatechs_4ism.bin 48 testv/stvOMASA_4ISM_2MASA2TC48c.wav bit ../IVAS_dec EXT 48 bit testv/stvOMASA_4ISM_2MASA2TC48c.wav_EXT_sw_48-48.tst +// OMASA 2Dir2TC 3ISM at br sw techs 13.2 to 512 kbps start 160 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot_case01_3000_q.csv -device_orientation testv/headrot_case00_3000_q.csv -ism_masa 3 2 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k_2fr_start_160k_omasatechs_3ism.bin 48 testv/stvOMASA_3ISM_2MASA2TC48c.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stvOMASA_3ISM_2MASA2TC48c.wav_BINAURAL_sw_48-48_rtpdump_PIdata.tst // OSBA FOA 1ISM at 32 kbps, 48kHz in, 48kHz out, BINAURAL out @@ -2056,3 +2080,7 @@ networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit ../IVAS_cod -ism 4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv ../scripts/switchPaths/sw_48-32k_10fr.bin 48 testv/stv4ISM48s.wav bit networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit netsimoutput tracefile_sim 2 0 ../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt -Tracefile tracefile_dec -VOIP BINAURAL 48 netsimoutput testv/stv4ISM48s.wav_sw_48-48_BINAURAL_OE_JBM5.tst + +// OSBA 2ISM 2OA at bitrate switching 13.2 to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot_case00_3000_q.csv -device_orientation testv/headrot_case03_3000_q.csv -ism_sba 2 2 testv/stvISM1.csv testv/stvISM2.csv ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvOSBA_2ISM_2OA48c.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stvOSBA_2ISM_2OA48c.wav_BINAURAL_sw_48-48_rtpdump_PIdata.tst -- GitLab From 9b6129e1c6807a5daf55243051ccf9190c625a40 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Tue, 22 Apr 2025 14:32:37 +0300 Subject: [PATCH 08/33] Assign identity vector components separately --- lib_rend/ivas_rotation.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index bc87251a4d..34215225a2 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -741,7 +741,10 @@ void ivas_external_orientation_reset( int16_t i; IVAS_QUATERNION identity; - identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; + identity.w = 1.0f; + identity.x = 0.0f; + identity.y = 0.0f; + identity.z = 0.0f; /* Enable head rotation and disable external orientation as default */ for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { @@ -796,14 +799,9 @@ ivas_error ivas_combined_orientation_open( IVAS_VECTOR3 origo; int16_t pos_idx; -#ifdef IVAS_RTPDUMP - identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; - origo = (IVAS_VECTOR3) { .x = 0.0f, .y = 0.0f, .z = 0.0f }; -#else identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; origo.x = origo.y = origo.z = 0.0f; -#endif /* Allocate handle */ if ( ( *hCombinedOrientationData = (COMBINED_ORIENTATION_HANDLE) malloc( sizeof( COMBINED_ORIENTATION_DATA ) ) ) == NULL ) @@ -988,14 +986,9 @@ ivas_error combine_external_and_head_orientations( IVAS_QUATERNION identity; IVAS_VECTOR3 origo; -#ifdef IVAS_RTPDUMP - identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; - origo = (IVAS_VECTOR3) { .x = 0.0f, .y = 0.0f, .z = 0.0f }; -#else identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; origo.x = origo.y = origo.z = 0.0f; -#endif /* Form combined orientations or return if no data available */ if ( hCombinedOrientationData == NULL ) @@ -1291,12 +1284,8 @@ static void external_target_interpolation( if ( hExtOrientationData->enableExternalOrientation[i - 1] == 0 ) { IVAS_QUATERNION identity; -#ifdef IVAS_RTPDUMP - identity = (IVAS_QUATERNION) { .w = 1.0f, .x = 0.0f, .y = 0.0f, .z = 0.0f }; -#else identity.w = 1.0f; identity.x = identity.y = identity.z = 0.0f; -#endif hCombinedOrientationData->Quaternions_ext_interpolation_start = identity; } else if ( hExtOrientationData->enableExternalOrientation[i - 1] == 2 ) -- GitLab From c1595ad357432c1ffd45205c39360c6a8fa9afef Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 23 Apr 2025 13:32:53 +0300 Subject: [PATCH 09/33] Edit test cases, check also for combined orientation handle when checking orientation input --- lib_dec/ivas_binRenderer_internal.c | 4 ++++ lib_dec/ivas_dirac_dec.c | 4 ++++ lib_dec/ivas_init_dec.c | 4 ++++ lib_dec/ivas_mc_param_dec.c | 4 ++++ lib_dec/ivas_mc_paramupmix_dec.c | 4 ++++ lib_dec/ivas_mct_dec.c | 4 ++++ lib_dec/ivas_output_config.c | 21 ++++++++++++++++++++- scripts/config/self_test.prm | 14 +++++++------- 8 files changed, 51 insertions(+), 8 deletions(-) diff --git a/lib_dec/ivas_binRenderer_internal.c b/lib_dec/ivas_binRenderer_internal.c index 4b2c4c7d07..8258a47c20 100644 --- a/lib_dec/ivas_binRenderer_internal.c +++ b/lib_dec/ivas_binRenderer_internal.c @@ -1028,7 +1028,11 @@ ivas_error ivas_binRenderer_open( ivas_dirac_dec_get_response( (int16_t) ls_azimuth_CICP19[k], (int16_t) ls_elevation_CICP19[k], hBinRenderer->hReverb->foa_enc[k], 1 ); } } +#ifdef IVAS_RTPDUMP + else if ( st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else else if ( st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { if ( ( error = efap_init_data( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth, st_ivas->hIntSetup.ls_elevation, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK ) { diff --git a/lib_dec/ivas_dirac_dec.c b/lib_dec/ivas_dirac_dec.c index 6ce9439d4b..c8136ad4e1 100644 --- a/lib_dec/ivas_dirac_dec.c +++ b/lib_dec/ivas_dirac_dec.c @@ -1999,7 +1999,11 @@ void ivas_dirac_dec_render_sf( { mvs2s( &hSpatParamRendCom->azimuth[md_idx][hDirAC->hConfig->enc_param_start_band], &azimuth[hDirAC->hConfig->enc_param_start_band], hSpatParamRendCom->num_freq_bands - hDirAC->hConfig->enc_param_start_band ); mvs2s( &hSpatParamRendCom->elevation[md_idx][hDirAC->hConfig->enc_param_start_band], &elevation[hDirAC->hConfig->enc_param_start_band], hSpatParamRendCom->num_freq_bands - hDirAC->hConfig->enc_param_start_band ); +#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]; rotateAziEle_DirAC( azimuth, elevation, num_freq_bands, hSpatParamRendCom->num_freq_bands, p_Rmat ); diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index aac6720870..e4fe450a4e 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -2153,7 +2153,11 @@ ivas_error ivas_init_decoder( } else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { +#ifdef IVAS_RTPDUMP + if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM && st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM && st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { if ( ( error = efap_init_data( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth, st_ivas->hIntSetup.ls_elevation, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK ) { diff --git a/lib_dec/ivas_mc_param_dec.c b/lib_dec/ivas_mc_param_dec.c index 048f26e379..49c1b8a033 100644 --- a/lib_dec/ivas_mc_param_dec.c +++ b/lib_dec/ivas_mc_param_dec.c @@ -401,7 +401,11 @@ ivas_error ivas_param_mc_dec_open( ivas_param_mc_dec_compute_interpolator( 0, 0, DEFAULT_JBM_CLDFB_TIMESLOTS, hParamMC->h_output_synthesis_params.interpolator ); /* Head or external rotation */ +#ifdef IVAS_RTPDUMP + if ( ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else if ( ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { if ( ( hParamMC->hoa_encoder = (float *) malloc( st_ivas->hTransSetup.nchan_out_woLFE * MAX_INTERN_CHANNELS * sizeof( float ) ) ) == NULL ) { diff --git a/lib_dec/ivas_mc_paramupmix_dec.c b/lib_dec/ivas_mc_paramupmix_dec.c index 81bd4023a4..3d5353130c 100644 --- a/lib_dec/ivas_mc_paramupmix_dec.c +++ b/lib_dec/ivas_mc_paramupmix_dec.c @@ -349,7 +349,11 @@ ivas_error ivas_mc_paramupmix_dec_open( } /* Head or external rotation */ +#ifdef IVAS_RTPDUMP + if ( ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) +#else if ( ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { if ( ( hMCParamUpmix->hoa_encoder = (float *) malloc( st_ivas->hTransSetup.nchan_out_woLFE * MAX_INTERN_CHANNELS * sizeof( float ) ) ) == NULL ) { diff --git a/lib_dec/ivas_mct_dec.c b/lib_dec/ivas_mct_dec.c index 4c2ace3908..9bf9c9098e 100644 --- a/lib_dec/ivas_mct_dec.c +++ b/lib_dec/ivas_mct_dec.c @@ -1179,7 +1179,11 @@ static ivas_error ivas_mc_dec_reconfig( if ( st_ivas->hBinRenderer != NULL && ( st_ivas->renderer_type != RENDERER_BINAURAL_FASTCONV && st_ivas->renderer_type != RENDERER_BINAURAL_FASTCONV_ROOM ) ) { ivas_binRenderer_close( &st_ivas->hBinRenderer ); +#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( &st_ivas->hEFAPdata ); } diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index 305d99ef99..2c6bce7cc1 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -70,8 +70,11 @@ void ivas_renderer_select( /*-----------------------------------------------------------------* * Binaural rendering configurations *-----------------------------------------------------------------*/ - +#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; } @@ -155,7 +158,11 @@ void ivas_renderer_select( *internal_config = IVAS_AUDIO_CONFIG_7_1_4; } +#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( st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); @@ -199,9 +206,17 @@ void ivas_renderer_select( if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) { #ifdef DEBUGGING +#ifdef IVAS_RTPDUMP + if ( ( ( ( st_ivas->transport_config == IVAS_AUDIO_CONFIG_5_1 || st_ivas->transport_config == IVAS_AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) ) || ( st_ivas->hDecoderConfig->force_rend == FORCE_TD_RENDERER ) ) && st_ivas->mc_mode == MC_MODE_MCT && st_ivas->hDecoderConfig->force_rend != FORCE_CLDFB_RENDERER ) +#else if ( ( ( ( st_ivas->transport_config == IVAS_AUDIO_CONFIG_5_1 || st_ivas->transport_config == IVAS_AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) || ( st_ivas->hDecoderConfig->force_rend == FORCE_TD_RENDERER ) ) && st_ivas->mc_mode == MC_MODE_MCT && st_ivas->hDecoderConfig->force_rend != FORCE_CLDFB_RENDERER ) +#endif +#else +#ifdef IVAS_RTPDUMP + if ( ( st_ivas->transport_config == IVAS_AUDIO_CONFIG_5_1 || st_ivas->transport_config == IVAS_AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation || st_ivas->hCombinedOrientationData ) && st_ivas->mc_mode == MC_MODE_MCT ) #else if ( ( st_ivas->transport_config == IVAS_AUDIO_CONFIG_5_1 || st_ivas->transport_config == IVAS_AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && st_ivas->mc_mode == MC_MODE_MCT ) +#endif #endif { *renderer_type = RENDERER_BINAURAL_OBJECTS_TD; @@ -217,7 +232,11 @@ void ivas_renderer_select( *renderer_type = RENDERER_BINAURAL_FASTCONV; } +#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/scripts/config/self_test.prm b/scripts/config/self_test.prm index 7dd2d2e301..ebe07a3101 100644 --- a/scripts/config/self_test.prm +++ b/scripts/config/self_test.prm @@ -1573,9 +1573,9 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_cod -mc 7_1_4 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv714MC48c.wav bit ../IVAS_dec EXT 48 bit testv/stv714MC48c.wav_sw_48-48_EXT.tst -// Multi-channel 5_1 bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, DTX on, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case02_3000_q.csv -dtx -mc 5_1 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv51MC48c.wav bit -../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv51MC48c.wav_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst +// Multi-channel 5_1 bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case02_3000_q.csv -mc 5_1 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv51MC48c.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv51MC48c.wav_sw_48-48_BINAURAL_rtpdump_PIdata.tst // Stereo downmix to bit-exact EVS at 13200 kbps, 32kHz in, 32kHz out @@ -2022,6 +2022,10 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_10pct.g networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit netsimoutput tracefile_sim 2 0 ../IVAS_dec -Tracefile tracefile_dec -VOIP BINAURAL_ROOM_REVERB 48 netsimoutput testv/stvOSBA_2ISM_2OA32c.wav_BINAURAL_brsw_32-48_JBM5.tst +// OSBA 2ISM 2OA at bitrate switching 13.2 to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data +../IVAS_cod -rtpdump -scene_orientation testv/headrot_case00_3000_q.csv -device_orientation testv/headrot_case03_3000_q.csv -ism_sba 2 2 testv/stvISM1.csv testv/stvISM2.csv ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvOSBA_2ISM_2OA48c.wav bit +../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stvOSBA_2ISM_2OA48c.wav_BINAURAL_sw_48-48_rtpdump_PIdata.tst + // OMASA 2Dir2TC 4ISM at 80 kbps, 48kHz in, 48kHz out, BINAURAL out, default object editing, 1SEP-PARAM ../IVAS_cod -ism_masa 4 2 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv testv/stv2MASA2TC48c.met 80000 48 testv/stvOMASA_4ISM_2MASA2TC48c.wav bit @@ -2080,7 +2084,3 @@ networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit ../IVAS_cod -ism 4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv ../scripts/switchPaths/sw_48-32k_10fr.bin 48 testv/stv4ISM48s.wav bit networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit netsimoutput tracefile_sim 2 0 ../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt -Tracefile tracefile_dec -VOIP BINAURAL 48 netsimoutput testv/stv4ISM48s.wav_sw_48-48_BINAURAL_OE_JBM5.tst - -// OSBA 2ISM 2OA at bitrate switching 13.2 to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot_case00_3000_q.csv -device_orientation testv/headrot_case03_3000_q.csv -ism_sba 2 2 testv/stvISM1.csv testv/stvISM2.csv ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvOSBA_2ISM_2OA48c.wav bit -../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stvOSBA_2ISM_2OA48c.wav_BINAURAL_sw_48-48_rtpdump_PIdata.tst -- GitLab From 360eef8c4cda1219c9df7a9b4dd7072aeff5121f Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 23 Apr 2025 14:47:48 +0300 Subject: [PATCH 10/33] Clang format --- apps/decoder.c | 7 +- apps/encoder.c | 4 +- lib_com/bitstream.c | 2 +- lib_dec/lib_dec.c | 24 +- lib_enc/lib_enc.c | 3 +- lib_rend/ivas_rotation.c | 2 +- lib_util/disable_headtracking_file_reader.c | 16 +- lib_util/disable_headtracking_file_reader.h | 12 +- lib_util/evs_rtp_payload.h | 304 ++++++++++---------- lib_util/ivas_rtp_payload.c | 200 ++++++------- lib_util/ivas_rtp_payload.h | 220 +++++++------- 11 files changed, 401 insertions(+), 393 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 020510f928..61a540e9f2 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3186,7 +3186,7 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame(&rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, &auPtr, (uint16_t *) &auSize ); + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, &auPtr, (uint16_t *) &auSize ); #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSize ); #endif @@ -3351,7 +3351,7 @@ static ivas_error decodeVoIP( { /* feed the previous read packet into the receiver now */ #ifdef IVAS_RTPDUMP - error = IVAS_DEC_VoIP_FeedFrame(hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, ivasIndicatorOrQBit ); + error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, ivasIndicatorOrQBit ); #else error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, qBit ); #endif @@ -3400,7 +3400,6 @@ static ivas_error decodeVoIP( /* 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 || rtpdumpDepackerError == IVAS_RTPDUMP_DEPACKER_EOF ) @@ -3618,7 +3617,7 @@ static ivas_error decodeVoIP( } #ifdef IVAS_RTPDUMP - IVAS_DEC_resetExternalOrientations(hIvasDec); + IVAS_DEC_resetExternalOrientations( hIvasDec ); #endif vec_pos_update = ( vec_pos_update + 1 ) % vec_pos_len; diff --git a/apps/encoder.c b/apps/encoder.c index 01f153959c..3d1e160f7d 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -673,9 +673,9 @@ int main( * Open disable headtracking file *------------------------------------------------------------------------------------------*/ - if (arg.disableHeadtrackingFileName != NULL ) + if ( arg.disableHeadtrackingFileName != NULL ) { - if (( error = DisableHeadtrackingFileReader_open(arg.disableHeadtrackingFileName, &disableHeadtrackingFileReader ) ) != IVAS_ERR_OK ) + if ( ( error = DisableHeadtrackingFileReader_open( arg.disableHeadtrackingFileName, &disableHeadtrackingFileReader ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError: Can't open disable headtracking file %s \n\n", arg.disableHeadtrackingFileName ); goto cleanup; diff --git a/lib_com/bitstream.c b/lib_com/bitstream.c index c281da1a0a..22fbcde10e 100644 --- a/lib_com/bitstream.c +++ b/lib_com/bitstream.c @@ -170,7 +170,7 @@ Word16 rate2EVSmode( * Lookup IVAS mode. Note: FRAME_NO_DATA frames should be looked up with rate2EVSmode(). *-------------------------------------------------------------------*/ Word16 rate2IVASmode( - const Word32 brate /* i : bitrate */ + const Word32 brate /* i : bitrate */ ) { switch ( brate ) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 786f911ada..072f274506 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3736,10 +3736,10 @@ ivas_error IVAS_DEC_Flush( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_parseSinglePIorientation( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - char *orientation, /* i : input PI orientation */ - bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ - IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + char *orientation, /* i : input PI orientation */ + bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ + IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ ) { int16_t i; @@ -3780,8 +3780,8 @@ ivas_error IVAS_DEC_parseSinglePIorientation( /* use the new PI orientation or the previously saved orientation in processing */ for ( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) { - QuaternionProduct(hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], *savedInvOrientation, - &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i]); + QuaternionProduct( hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], *savedInvOrientation, + &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i] ); hIvasDec->st_ivas->hExtOrientationData->enableExternalOrientation[i] = true; } hIvasDec->updateOrientation = true; @@ -3797,8 +3797,8 @@ ivas_error IVAS_DEC_parseSinglePIorientation( *---------------------------------------------------------------------*/ void IVAS_DEC_parsePIenableDisableHeadtracking( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* i : PI data handle for the current frame */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* i : PI data handle for the current frame */ ) { if ( PIdataCurrentFrame->enableHeadTracking ) @@ -3833,13 +3833,13 @@ ivas_error IVAS_DEC_parsePIdata( ivas_error error = IVAS_ERR_OK; /* scene orientation */ - if (( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->sceneOrientation, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->sceneOrientation, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) { return error; } /* device orientation */ - if (( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->deviceOrientationUncompensated, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->deviceOrientationUncompensated, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) { return error; } @@ -3858,7 +3858,7 @@ ivas_error IVAS_DEC_parsePIdata( *---------------------------------------------------------------------*/ void IVAS_DEC_resetExternalOrientations( - IVAS_DEC_HANDLE hIvasDec /* i/o: IVAS decoder handle */ + IVAS_DEC_HANDLE hIvasDec /* i/o: IVAS decoder handle */ ) { ivas_external_orientation_reset( &( hIvasDec->st_ivas->hExtOrientationData ) ); @@ -3872,7 +3872,7 @@ void IVAS_DEC_resetExternalOrientations( *---------------------------------------------------------------------*/ void IVAS_DEC_resetPIdataCurrentFrame( - PI_DATA_CURRENT_FRAME *piDataCurrentFrame /* i/o: PI data handle for the current frame */ + PI_DATA_CURRENT_FRAME *piDataCurrentFrame /* i/o: PI data handle for the current frame */ ) { resetPIdataCurrentFrame( piDataCurrentFrame ); diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index 993e2773fd..b2ea192118 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -2427,8 +2427,7 @@ static void init_encoder_config( *---------------------------------------------------------------------*/ bool IVAS_isImmersiveFormat( - const IVAS_ENC_HANDLE hIvasEnc -) + const IVAS_ENC_HANDLE hIvasEnc ) { if ( hIvasEnc->st_ivas->hEncoderConfig->ivas_format == MONO_FORMAT ) { diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index 34215225a2..93c0cd0996 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -733,7 +733,7 @@ ivas_error ivas_external_orientation_open( *-----------------------------------------------------------------------*/ void ivas_external_orientation_reset( - EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o : external orientation handle */ + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o : external orientation handle */ ) { if ( *hExtOrientationData != NULL ) diff --git a/lib_util/disable_headtracking_file_reader.c b/lib_util/disable_headtracking_file_reader.c index 985733dc83..992464a6f9 100644 --- a/lib_util/disable_headtracking_file_reader.c +++ b/lib_util/disable_headtracking_file_reader.c @@ -55,8 +55,8 @@ struct DisableHeadtrackingFileReader *-----------------------------------------------------------------------*/ ivas_error DisableHeadtrackingFileReader_open( - char *filePath, /* i : disable-headtracking input file name */ - DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ + char *filePath, /* i : disable-headtracking input file name */ + DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ ) { DisableHeadtrackingFileReader *self; @@ -68,7 +68,7 @@ ivas_error DisableHeadtrackingFileReader_open( return IVAS_ERR_FAILED_FILE_OPEN; } - inputFile = fopen(filePath, "r" ); + inputFile = fopen( filePath, "r" ); if ( !inputFile ) { @@ -95,8 +95,8 @@ ivas_error DisableHeadtrackingFileReader_open( *-----------------------------------------------------------------------*/ ivas_error DisableHeadtrackingFileReading( - DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ - bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ + DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ + bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ ) { float disableHeadTrackingFlag; @@ -105,7 +105,7 @@ ivas_error DisableHeadtrackingFileReading( /* Initial values, if they are not read from the file (enable headtracking by default) */ disableHeadTrackingFlag = 0; - read_values = fscanf(fileReader->inputFile, "%f", &disableHeadTrackingFlag ); + read_values = fscanf( fileReader->inputFile, "%f", &disableHeadTrackingFlag ); if ( ( read_values != 1 ) ) { if ( feof( fileReader->inputFile ) ) @@ -132,7 +132,7 @@ ivas_error DisableHeadtrackingFileReading( *-----------------------------------------------------------------------*/ void DisableHeadtrackingFileReader_close( - DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ + DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ ) { if ( fileReader == NULL || *fileReader == NULL ) @@ -156,7 +156,7 @@ void DisableHeadtrackingFileReader_close( *-----------------------------------------------------------------------*/ const char *DisableHeadtrackingFileReader_getFilePath( - DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ + DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ ) { if ( fileReader == NULL ) diff --git a/lib_util/disable_headtracking_file_reader.h b/lib_util/disable_headtracking_file_reader.h index 4d413b442c..1dda351565 100644 --- a/lib_util/disable_headtracking_file_reader.h +++ b/lib_util/disable_headtracking_file_reader.h @@ -47,8 +47,8 @@ typedef struct DisableHeadtrackingFileReader DisableHeadtrackingFileReader; *-----------------------------------------------------------------------*/ ivas_error DisableHeadtrackingFileReader_open( - char *filePath, /* i : disable-headtracking input file name */ - DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ + char *filePath, /* i : disable-headtracking input file name */ + DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ ); /*-----------------------------------------------------------------------* @@ -58,8 +58,8 @@ ivas_error DisableHeadtrackingFileReader_open( *-----------------------------------------------------------------------*/ ivas_error DisableHeadtrackingFileReading( - DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ - bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ + DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ + bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ ); /*-----------------------------------------------------------------------* @@ -69,7 +69,7 @@ ivas_error DisableHeadtrackingFileReading( *-----------------------------------------------------------------------*/ void DisableHeadtrackingFileReader_close( - DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ + DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ ); /*-----------------------------------------------------------------------* @@ -79,7 +79,7 @@ void DisableHeadtrackingFileReader_close( *-----------------------------------------------------------------------*/ const char *DisableHeadtrackingFileReader_getFilePath( - DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ + DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ ); #endif diff --git a/lib_util/evs_rtp_payload.h b/lib_util/evs_rtp_payload.h index 74c4a56a56..490f9560ff 100644 --- a/lib_util/evs_rtp_payload.h +++ b/lib_util/evs_rtp_payload.h @@ -45,161 +45,165 @@ extern "C" { #endif - static const int32_t AMRWB_IOmode2rate[16] = { - 6600, /* AMRWB_IO_6600 */ - 8850, /* AMRWB_IO_8850 */ - 12650, /* AMRWB_IO_1265 */ - 14250, /* AMRWB_IO_1425 */ - 15850, /* AMRWB_IO_1585 */ - 18250, /* AMRWB_IO_1825 */ - 19850, /* AMRWB_IO_1985 */ - 23050, /* AMRWB_IO_2305 */ - 23850, /* AMRWB_IO_2385 */ - 1750, /* AMRWB_IO_SID: SID_1k75 followed by STI bit and CMI bits (A.2.2.1.3) */ - -1, /* AMRWB_IO_FUT1 */ - -1, /* AMRWB_IO_FUT2 */ - -1, /* AMRWB_IO_FUT3 */ - -1, /* AMRWB_IO_FUT4 */ - 0, /* SPEECH_LOST */ - 0 /* NO_DATA */ - }; - - static const int32_t PRIMARYmode2rate[16] = { - 2800, /* PRIMARY_2800 */ - 7200, /* PRIMARY_7200 */ - 8000, /* PRIMARY_8000 */ - 9600, /* PRIMARY_9600 */ - 13200, /* PRIMARY_13200 */ - 16400, /* PRIMARY_16400 */ - 24400, /* PRIMARY_24400 */ - 32000, /* PRIMARY_32000 */ - 48000, /* PRIMARY_48000 */ - 64000, /* PRIMARY_64000 */ - 96000, /* PRIMARY_96000 */ - 128000, /* PRIMARY_128000 */ - 2400, /* PRIMARY_SID */ - -1, /* PRIMARY_FUT1 */ - 0, /* SPEECH_LOST */ - 0 /* NO_DATA */ - }; - - static const uint16_t evsPayloadProtectedSizes[22] = { - 48, - 56, - 136, - 144, - 160, - 184, - 192, - 256, - 264, - 288, - 320, - 328, - 368, - 400, - 464, - 480, - 488, - 640, - 960, - 1280, - 1920, - 2560 - }; - - static const bool evsPayloadProtectedSizes_isAMRWB_IOmode[22] = { - 0, - 0, /* Special case (see clause A.2.1.3) */ - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0 - }; - - static const uint16_t evsPayloadProtectedSizes_frameTypeIndex[22] = { - 12, /* PRIMARY_SID */ - 0, /* Special case (see clause A.2.1.3) */ - 0, /* AMRWB_IO_6600 */ - 1, /* PRIMARY_7200 */ - 2, /* PRIMARY_8000 */ - 1, /* AMRWB_IO_8850 */ - 3, /* PRIMARY_9600 */ - 2, /* AMRWB_IO_1265 */ - 4, /* PRIMARY_13200 */ - 3, /* AMRWB_IO_1425 */ - 4, /* AMRWB_IO_1585 */ - 5, /* PRIMARY_16400 */ - 5, /* AMRWB_IO_1825 */ - 6, /* AMRWB_IO_1985 */ - 7, /* AMRWB_IO_2305 */ - 8, /* AMRWB_IO_2385 */ - 6, /* PRIMARY_24400 */ - 7, /* PRIMARY_32000 */ - 8, /* PRIMARY_48000 */ - 9, /* PRIMARY_64000 */ - 10, /* PRIMARY_96000 */ - 11 /* PRIMARY_128000 */ - }; - - bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **framePtr, uint16_t *frameSizeBits ); + /* clang-format off */ + +static const int32_t AMRWB_IOmode2rate[16] = { + 6600, /* AMRWB_IO_6600 */ + 8850, /* AMRWB_IO_8850 */ + 12650, /* AMRWB_IO_1265 */ + 14250, /* AMRWB_IO_1425 */ + 15850, /* AMRWB_IO_1585 */ + 18250, /* AMRWB_IO_1825 */ + 19850, /* AMRWB_IO_1985 */ + 23050, /* AMRWB_IO_2305 */ + 23850, /* AMRWB_IO_2385 */ + 1750, /* AMRWB_IO_SID: SID_1k75 followed by STI bit and CMI bits (A.2.2.1.3) */ + -1, /* AMRWB_IO_FUT1 */ + -1, /* AMRWB_IO_FUT2 */ + -1, /* AMRWB_IO_FUT3 */ + -1, /* AMRWB_IO_FUT4 */ + 0, /* SPEECH_LOST */ + 0 /* NO_DATA */ +}; + +static const int32_t PRIMARYmode2rate[16] = { + 2800, /* PRIMARY_2800 */ + 7200, /* PRIMARY_7200 */ + 8000, /* PRIMARY_8000 */ + 9600, /* PRIMARY_9600 */ + 13200, /* PRIMARY_13200 */ + 16400, /* PRIMARY_16400 */ + 24400, /* PRIMARY_24400 */ + 32000, /* PRIMARY_32000 */ + 48000, /* PRIMARY_48000 */ + 64000, /* PRIMARY_64000 */ + 96000, /* PRIMARY_96000 */ + 128000, /* PRIMARY_128000 */ + 2400, /* PRIMARY_SID */ + -1, /* PRIMARY_FUT1 */ + 0, /* SPEECH_LOST */ + 0 /* NO_DATA */ +}; + +static const uint16_t evsPayloadProtectedSizes[22] = { + 48, + 56, + 136, + 144, + 160, + 184, + 192, + 256, + 264, + 288, + 320, + 328, + 368, + 400, + 464, + 480, + 488, + 640, + 960, + 1280, + 1920, + 2560 +}; + +static const bool evsPayloadProtectedSizes_isAMRWB_IOmode[22] = { + 0, + 0, /* Special case (see clause A.2.1.3) */ + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +static const uint16_t evsPayloadProtectedSizes_frameTypeIndex[22] = { + 12, /* PRIMARY_SID */ + 0, /* Special case (see clause A.2.1.3) */ + 0, /* AMRWB_IO_6600 */ + 1, /* PRIMARY_7200 */ + 2, /* PRIMARY_8000 */ + 1, /* AMRWB_IO_8850 */ + 3, /* PRIMARY_9600 */ + 2, /* AMRWB_IO_1265 */ + 4, /* PRIMARY_13200 */ + 3, /* AMRWB_IO_1425 */ + 4, /* AMRWB_IO_1585 */ + 5, /* PRIMARY_16400 */ + 5, /* AMRWB_IO_1825 */ + 6, /* AMRWB_IO_1985 */ + 7, /* AMRWB_IO_2305 */ + 8, /* AMRWB_IO_2385 */ + 6, /* PRIMARY_24400 */ + 7, /* PRIMARY_32000 */ + 8, /* PRIMARY_48000 */ + 9, /* PRIMARY_64000 */ + 10, /* PRIMARY_96000 */ + 11 /* PRIMARY_128000 */ +}; + +bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **framePtr, uint16_t *frameSizeBits ); #ifdef IVAS_RTPDUMP - void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); +void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #else - static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); +static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #endif - bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); - - typedef struct - { - RTPDUMP_HANDLE rtpdump; - bool hf_only; - RTPDUMP_RTPPACKET rtpPacket; - uint32_t timeoffset_ms; - uint16_t frameIndex; - bool frameFollowing; - } EVS_RTPDUMP_DEPACKER; - - typedef enum - { - EVS_RTPDUMP_DEPACKER_NO_ERROR = 0, - EVS_RTPDUMP_DEPACKER_EOF = -1, - EVS_RTPDUMP_DEPACKER_RTPDUMP_ERROR = 1, - EVS_RTPDUMP_DEPACKER_PAYLOAD_ERROR - } EVS_RTPDUMP_DEPACKER_ERROR; - - EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_open( EVS_RTPDUMP_DEPACKER *self, FILE *file, bool hf_only ); - - EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_readNextFrame( - EVS_RTPDUMP_DEPACKER *self, - uint16_t *rtpSequenceNumber, - uint32_t *rtpTimeStamp, - uint32_t *rcvTime_ms, - bool *isAMRWB_IOmode, - uint16_t *frameTypeIndex, - bool *qBit, - unsigned char **frame, - uint16_t *frameSizeBits ); - - void EVS_RTPDUMP_DEPACKER_close( EVS_RTPDUMP_DEPACKER *self ); +bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); + +typedef struct +{ + RTPDUMP_HANDLE rtpdump; + bool hf_only; + RTPDUMP_RTPPACKET rtpPacket; + uint32_t timeoffset_ms; + uint16_t frameIndex; + bool frameFollowing; +} EVS_RTPDUMP_DEPACKER; + +typedef enum +{ + EVS_RTPDUMP_DEPACKER_NO_ERROR = 0, + EVS_RTPDUMP_DEPACKER_EOF = -1, + EVS_RTPDUMP_DEPACKER_RTPDUMP_ERROR = 1, + EVS_RTPDUMP_DEPACKER_PAYLOAD_ERROR +} EVS_RTPDUMP_DEPACKER_ERROR; + +EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_open( EVS_RTPDUMP_DEPACKER *self, FILE *file, bool hf_only ); + +EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_readNextFrame( + EVS_RTPDUMP_DEPACKER *self, + uint16_t *rtpSequenceNumber, + uint32_t *rtpTimeStamp, + uint32_t *rcvTime_ms, + bool *isAMRWB_IOmode, + uint16_t *frameTypeIndex, + bool *qBit, + unsigned char **frame, + uint16_t *frameSizeBits ); + +void EVS_RTPDUMP_DEPACKER_close( EVS_RTPDUMP_DEPACKER *self ); + + /* clang-format on */ #ifdef __cplusplus } diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 2366c65698..132e4d23e2 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -48,8 +48,8 @@ *-----------------------------------------------------------------------*/ static void writeByteToRtp( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - char value /* i : Value to be written to the RTP packet */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + char value /* i : Value to be written to the RTP packet */ ) { self->rtpPacket.data[self->writingIndex] = value; @@ -65,8 +65,8 @@ static void writeByteToRtp( *-----------------------------------------------------------------------*/ static void determineBitrate( - const int32_t numBits, /* i : Number of bits contained in the data frame */ - int32_t *frameBitrate /* o : Bitrate of the data frame */ + const int32_t numBits, /* i : Number of bits contained in the data frame */ + int32_t *frameBitrate /* o : Bitrate of the data frame */ ) { *frameBitrate = numBits * IVAS_NUM_FRAMES_PER_SEC; @@ -80,20 +80,20 @@ static void determineBitrate( *-----------------------------------------------------------------------*/ static void ivasPayload_parseToc( - uint8_t toc, /* i : ToC byte to be parsed */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - int32_t *bitrate /* o : Bitrate of the data frame indicated in the ToC byte */ + uint8_t toc, /* i : ToC byte to be parsed */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + int32_t *bitrate /* o : Bitrate of the data frame indicated in the ToC byte */ ) { bool isIvasToc = ( toc & 0x30 ) == 0x10; // xx01 xxxx if ( !isIvasToc ) { - evsHeaderFullPayload_parseToc(toc, evsIvasModeBit, frameFollowing, bitrateIndex, ivasIndicatorBit, bitrate ); + evsHeaderFullPayload_parseToc( toc, evsIvasModeBit, frameFollowing, bitrateIndex, ivasIndicatorBit, bitrate ); } else { @@ -113,11 +113,11 @@ static void ivasPayload_parseToc( *-----------------------------------------------------------------------*/ static void ivasPayload_parsePItype( - char *PIframeDataBeginning, /* i : Pointer to the beginning of the PI data section in the RTP packet */ - uint16_t PIframeSizeBytes, /* i : PI data frame size in bytes */ - uint16_t parsedPIframeSizeBytes, /* i : Size of previously parsed PI frame data section in bytes */ - uint16_t PIframeType, /* i : Type of the PI data frame */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ + char *PIframeDataBeginning, /* i : Pointer to the beginning of the PI data section in the RTP packet */ + uint16_t PIframeSizeBytes, /* i : PI data frame size in bytes */ + uint16_t parsedPIframeSizeBytes, /* i : Size of previously parsed PI frame data section in bytes */ + uint16_t PIframeType, /* i : Type of the PI data frame */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ ) { if ( PIframeType == PI_SCENE_ORIENTATION ) @@ -173,8 +173,8 @@ static void ivasPayload_parsePItype( *-----------------------------------------------------------------------*/ static void ivasPayload_PIaddHeaderBytes( - uint16_t PIheaderSizeBytes, /* i : Size of the PI header section in bytes */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ + uint16_t PIheaderSizeBytes, /* i : Size of the PI header section in bytes */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ ) { if ( PIdataCurrentFrame->sceneOrientation != NULL ) @@ -211,10 +211,10 @@ static void ivasPayload_PIaddHeaderBytes( *-----------------------------------------------------------------------*/ static bool ivasPayload_parsePIdata( - char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ - uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ - uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ + char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ + uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ + uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ ) { // TODO(pajunen): can this accidentally include zero padding bits? @@ -261,14 +261,14 @@ static bool ivasPayload_parsePIdata( /* general PI data for all frames */ if ( PIframeMarker == PM_GENERAL ) { - ivasPayload_parsePItype(PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); + ivasPayload_parsePItype( PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); } else { /* current frame */ if ( ( PIframeMarker > 0 ) & ( count_audio == frameIndex ) ) { - ivasPayload_parsePItype(PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); + ivasPayload_parsePItype( PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); } /* increase audio frame counter */ @@ -294,7 +294,7 @@ static bool ivasPayload_parsePIdata( static float ivasPayload_convertFromQ15( uint16_t Q15Value ) { float temp; - temp = (float)( Q15Value & 0x7FFF ) / 0x7FFF; + temp = (float) ( Q15Value & 0x7FFF ) / 0x7FFF; return ( Q15Value & 0x8000 ) ? -temp : temp; } @@ -308,7 +308,7 @@ static float ivasPayload_convertFromQ15( uint16_t Q15Value ) static uint16_t ivasPayload_convertToQ15( float value ) { uint16_t temp; - temp = (uint16_t)( fabsf( value ) * 0x7FFF ); + temp = (uint16_t) ( fabsf( value ) * 0x7FFF ); if ( value >= 0.0f ) { temp = temp & 0x7FFF; @@ -328,8 +328,8 @@ static uint16_t ivasPayload_convertToQ15( float value ) *-----------------------------------------------------------------------*/ static void ivasPayload_convertOrientationToQ15( - IVAS_QUATERNION *orientation, /* i : Input orientation in quaternion to be converted to Q15 */ - IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ + IVAS_QUATERNION *orientation, /* i : Input orientation in quaternion to be converted to Q15 */ + IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ ) { orientationQ15->w = ivasPayload_convertToQ15( orientation->w ); @@ -346,12 +346,12 @@ static void ivasPayload_convertOrientationToQ15( *-----------------------------------------------------------------------*/ static float ivasPayload_parseQuaternionComponent( - char **PIorientationData /* i/o: Pointer to the PI data frame containing a single quaternion component */ + char **PIorientationData /* i/o: Pointer to the PI data frame containing a single quaternion component */ ) { uint16_t tempQ15value; - tempQ15value = (uint16_t) **PIorientationData; - tempQ15value = ( tempQ15value << 8 ) | (uint16_t) *( *PIorientationData + 1 ); + tempQ15value = ( uint16_t ) * *PIorientationData; + tempQ15value = ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ); *PIorientationData += 2; return ivasPayload_convertFromQ15( tempQ15value ); } @@ -384,14 +384,14 @@ void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) *-----------------------------------------------------------------------*/ bool ivasPayload_parseOrientationPIdata( - char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ - IVAS_QUATERNION *q /* o : Parsed quaternion value */ + char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ + IVAS_QUATERNION *q /* o : Parsed quaternion value */ ) { - q->w = ivasPayload_parseQuaternionComponent(&PIorientationData); - q->x = ivasPayload_parseQuaternionComponent(&PIorientationData); - q->y = ivasPayload_parseQuaternionComponent(&PIorientationData); - q->z = ivasPayload_parseQuaternionComponent(&PIorientationData); + q->w = ivasPayload_parseQuaternionComponent( &PIorientationData ); + q->x = ivasPayload_parseQuaternionComponent( &PIorientationData ); + q->y = ivasPayload_parseQuaternionComponent( &PIorientationData ); + q->z = ivasPayload_parseQuaternionComponent( &PIorientationData ); if ( q->w > 1.0f || q->w < -1.0f || q->x > 1.0f || q->x < -1.0f || @@ -405,18 +405,18 @@ bool ivasPayload_parseOrientationPIdata( } bool ivasPayload_unpackFrame( - char *payload, /* i : RTP payload data */ - uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ - uint16_t frameIndex, /* i : Index for the data frame in the payload */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeInBits, /* o : Data frame size in bits */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ + char *payload, /* i : RTP payload data */ + uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ + uint16_t frameIndex, /* i : Index for the data frame in the payload */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeInBits, /* o : Data frame size in bits */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ ) { bool someEvsIvasModeBit, someFrameFollowing, someIvasIndicatorBit; @@ -436,12 +436,12 @@ bool ivasPayload_unpackFrame( if ( *payload & E_BYTE ) // 1xxx xxxx { PIdataCurrentFrame->PIdataPresent = false; - while (1) + while ( 1 ) { if ( ( *payload & 0xF0 ) == IVAS_E_CMR ) // 1111 xxxx { /* IVAS CMR/E-byte */ - while (1) + while ( 1 ) { /* parse subsequent E-bytes */ ++payload; @@ -547,7 +547,7 @@ bool ivasPayload_unpackFrame( fprintf( stderr, "Error: expected ToC, found CMR/E-byte\n" ); return false; } - ivasPayload_parseToc(*payload, &someEvsIvasModeBit, &someFrameFollowing, &someBitrateIndex, &someIvasIndicatorBit, &bitrate ); + ivasPayload_parseToc( *payload, &someEvsIvasModeBit, &someFrameFollowing, &someBitrateIndex, &someIvasIndicatorBit, &bitrate ); if ( bitrate < 0 ) { fprintf( stderr, "Error: unexpected frameTypeIndex in ToC\n" ); @@ -599,8 +599,8 @@ bool ivasPayload_unpackFrame( } IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( - IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ - FILE *file /* i : Input file containing the rtpdump */ + IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ + FILE *file /* i : Input file containing the rtpdump */ ) { RTPDUMP_ERROR rtpdumpError; @@ -617,17 +617,17 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( } IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( - IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ - uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ - uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ - uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeBits /* o : Data frame size in bits */ + IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ + uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ + uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ + uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeBits /* o : Data frame size in bits */ ) { /* read next RTP packet from rtpdump */ @@ -662,7 +662,7 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( } void IVAS_RTPDUMP_DEPACKER_close( - IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ + IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ ) { if ( !self ) @@ -673,8 +673,8 @@ void IVAS_RTPDUMP_DEPACKER_close( } IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( - IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ - FILE *file /* i : Output file for the rtpdump stream */ + IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ + FILE *file /* i : Output file for the rtpdump stream */ ) { IVAS_RTPDUMP_PACKER *self; @@ -698,12 +698,12 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( } void IVAS_RTPDUMP_PACKER_writeEbytes( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). - * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). + * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ ) { UWord8 initialEbyte, subsequentEbyte; @@ -852,11 +852,11 @@ void IVAS_RTPDUMP_PACKER_writeEbytes( } void IVAS_RTPDUMP_PACKER_writeToc( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t frameBitrate, /* i : Bitrate of the written frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). - * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ - bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t frameBitrate, /* i : Bitrate of the written frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). + * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ + bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ ) { UWord8 H_bit, F_bit, EVS_IVAS_mode_bit, Q_bit, toc; @@ -868,13 +868,13 @@ void IVAS_RTPDUMP_PACKER_writeToc( /* FRAME_NO_DATA frames are written as in TS26.445 */ if ( isImmersiveFormat && frameBitrate != FRAME_NO_DATA ) { - toc = (UWord8)( rate2IVASmode( frameBitrate ) ); + toc = (UWord8) ( rate2IVASmode( frameBitrate ) ); EVS_IVAS_mode_bit = 0; Q_bit = 1; } else { - toc = (UWord8)( rate2EVSmode( frameBitrate, &is_amr_wb ) ); + toc = (UWord8) ( rate2EVSmode( frameBitrate, &is_amr_wb ) ); EVS_IVAS_mode_bit = (UWord8) is_amr_wb; Q_bit = 0; } @@ -883,14 +883,14 @@ void IVAS_RTPDUMP_PACKER_writeToc( } IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ - int32_t numBits, /* i : Number of bits contained in the data frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ + int32_t numBits, /* i : Number of bits contained in the data frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ ) { @@ -905,13 +905,15 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( determineBitrate( numBits, &frameBitrate ); /* payload header */ - IVAS_RTPDUMP_PACKER_writeEbytes(self, requestedBitrate, requestImmersiveFormatBitrate, ivasBandwidthRequest, ivasFormatRequest ); + IVAS_RTPDUMP_PACKER_writeEbytes( self, requestedBitrate, requestImmersiveFormatBitrate, ivasBandwidthRequest, ivasFormatRequest ); IVAS_RTPDUMP_PACKER_writeToc( self, frameBitrate, isImmersiveFormat, false ); /* frame data */ - for (i = 0; i < numBits; i += 8) { + for ( i = 0; i < numBits; i += 8 ) + { tempData = 0; - for (k = 0; k < 8; ++k) { + for ( k = 0; k < 8; ++k ) + { tempData = ( tempData << 1 ) | (char) bitStream[i + k]; } writeByteToRtp( self, tempData ); @@ -936,7 +938,7 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( } void IVAS_RTPDUMP_PACKER_writePIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ) { if ( !self->piDataPresent ) @@ -1036,7 +1038,7 @@ void IVAS_RTPDUMP_PACKER_writePIdata( } void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ) { if ( self->piDataPacker.disableHeadtracking == self->piDataPackerState.previousDisableHeadtrackingState ) @@ -1058,7 +1060,7 @@ void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( } void IVAS_RTPDUMP_PACKER_determinePIpresence( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ) { self->piDataPresent = false; @@ -1072,7 +1074,7 @@ void IVAS_RTPDUMP_PACKER_determinePIpresence( } void IVAS_RTPDUMP_PACKER_resetPIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ) { self->piDataPresent = false; @@ -1083,7 +1085,7 @@ void IVAS_RTPDUMP_PACKER_resetPIdata( } void IVAS_RTPDUMP_PACKER_close( - IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ ) { if ( !self || !( *self ) ) diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index 159e18a384..101a7805dd 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -48,6 +48,7 @@ extern "C" { #endif + /* clang-format off */ static const int32_t IVASmode2rate[16] = { 13200, @@ -64,8 +65,8 @@ static const int32_t IVASmode2rate[16] = { 256000, 384000, 512000, - -1, /* Reserved */ - 5200 /* SID */ + -1, /* Reserved */ + 5200 /* SID */ }; typedef enum @@ -229,188 +230,191 @@ typedef enum /*-----------------------------------------------------------------------* - * ivasPayload_unpackFrame() - * - * Parse a single IVAS frame from the payload. Also read the IVAS payload header - * and parse the PI data associated with the IVAS frame. - *-----------------------------------------------------------------------*/ + * ivasPayload_unpackFrame() + * + * Parse a single IVAS frame from the payload. Also read the IVAS payload header + * and parse the PI data associated with the IVAS frame. + *-----------------------------------------------------------------------*/ bool ivasPayload_unpackFrame( - char *payload, /* i : RTP payload data */ - uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ - uint16_t frameIndex, /* i : Index for the data frame in the payload */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeInBits, /* o : Data frame size in bits */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ + char *payload, /* i : RTP payload data */ + uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ + uint16_t frameIndex, /* i : Index for the data frame in the payload */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeInBits, /* o : Data frame size in bits */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_DEPACKER_open() - * - * Open IVAS rtpdump depacker. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_DEPACKER_open() + * + * Open IVAS rtpdump depacker. + *-----------------------------------------------------------------------*/ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( - IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ - FILE *file /* i : Input file containing the rtpdump */ + IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ + FILE *file /* i : Input file containing the rtpdump */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_DEPACKER_readNextFrame() - * - * Unpack next frame from the RTP packet. If the packet is depleted, read the next RTP packet from the rtpdump. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_DEPACKER_readNextFrame() + * + * Unpack next frame from the RTP packet. If the packet is depleted, read the next RTP packet from the rtpdump. + *-----------------------------------------------------------------------*/ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( - IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ - uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ - uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ - uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeBits /* o : Data frame size in bits */ + IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ + uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ + uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ + uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeBits /* o : Data frame size in bits */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_DEPACKER_close() - * - * Close IVAS rtpdump depacker. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_DEPACKER_close() + * + * Close IVAS rtpdump depacker. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_DEPACKER_close( - IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ + IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_open() - * - * Open IVAS rtpdump packer. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_open() + * + * Open IVAS rtpdump packer. + *-----------------------------------------------------------------------*/ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( - IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ - FILE *file /* i : Output file for the rtpdump stream */ + IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ + FILE *file /* i : Output file for the rtpdump stream */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writeEbytes() - * - * Write E-bytes (CMR and subsequent E-bytes) to the RTP packet. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_writeEbytes() + * + * Write E-bytes (CMR and subsequent E-bytes) to the RTP packet. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_writeEbytes( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). - * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). + * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writeToc() - * - * Write a single ToC byte to the RTP packet. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_writeToc() + * + * Write a single ToC byte to the RTP packet. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_writeToc( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t frameBitrate, /* i : Bitrate of the written frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). - * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ - bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + int32_t frameBitrate, /* i : Bitrate of the written frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). + * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ + bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writeNextFrame() - * - * Write IVAS payload header, a single frame data and optional PI data to an RTP packet. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_writeNextFrame() + * + * Write IVAS payload header, a single frame data and optional PI data to an RTP packet. + *-----------------------------------------------------------------------*/ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ - int32_t numBits, /* i : Number of bits contained in the data frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ + IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ + const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ + int32_t numBits, /* i : Number of bits contained in the data frame */ + bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ + int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ + bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ + IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ + IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writePIdata() - * - * Write PI data section (PI headers and PI frame data) to the RTP packet. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_writePIdata() + * + * Write PI data section (PI headers and PI frame data) to the RTP packet. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_writePIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState() - * - * Check for disable headtracking input and previously set disable/enable headtracking state. - * Set the current PI headtracking state accordingly. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState() + * + * Check for disable headtracking input and previously set disable/enable headtracking state. + * Set the current PI headtracking state accordingly. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_determinePIpresence() - * - * Check if there is PI data present for the current frame. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_determinePIpresence() + * + * Check if there is PI data present for the current frame. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_determinePIpresence( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_resetPIdata() - * - * Reset PI data packer handle. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_resetPIdata() + * + * Reset PI data packer handle. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_resetPIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ); /*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_close() - * - * Close IVAS rtpdump packer. - *-----------------------------------------------------------------------*/ + * IVAS_RTPDUMP_PACKER_close() + * + * Close IVAS rtpdump packer. + *-----------------------------------------------------------------------*/ void IVAS_RTPDUMP_PACKER_close( - IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ + IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ ); + + /* clang-format on */ + #ifdef __cplusplus } #endif -- GitLab From 5b2068a77deceb65003ac7c03ea62c75bb25450e Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 23 Apr 2025 14:59:26 +0300 Subject: [PATCH 11/33] Revert clang format changes to evs_rtp_payload.h --- lib_util/evs_rtp_payload.h | 304 ++++++++++++++++++------------------- 1 file changed, 150 insertions(+), 154 deletions(-) diff --git a/lib_util/evs_rtp_payload.h b/lib_util/evs_rtp_payload.h index 490f9560ff..74c4a56a56 100644 --- a/lib_util/evs_rtp_payload.h +++ b/lib_util/evs_rtp_payload.h @@ -45,165 +45,161 @@ extern "C" { #endif - /* clang-format off */ - -static const int32_t AMRWB_IOmode2rate[16] = { - 6600, /* AMRWB_IO_6600 */ - 8850, /* AMRWB_IO_8850 */ - 12650, /* AMRWB_IO_1265 */ - 14250, /* AMRWB_IO_1425 */ - 15850, /* AMRWB_IO_1585 */ - 18250, /* AMRWB_IO_1825 */ - 19850, /* AMRWB_IO_1985 */ - 23050, /* AMRWB_IO_2305 */ - 23850, /* AMRWB_IO_2385 */ - 1750, /* AMRWB_IO_SID: SID_1k75 followed by STI bit and CMI bits (A.2.2.1.3) */ - -1, /* AMRWB_IO_FUT1 */ - -1, /* AMRWB_IO_FUT2 */ - -1, /* AMRWB_IO_FUT3 */ - -1, /* AMRWB_IO_FUT4 */ - 0, /* SPEECH_LOST */ - 0 /* NO_DATA */ -}; - -static const int32_t PRIMARYmode2rate[16] = { - 2800, /* PRIMARY_2800 */ - 7200, /* PRIMARY_7200 */ - 8000, /* PRIMARY_8000 */ - 9600, /* PRIMARY_9600 */ - 13200, /* PRIMARY_13200 */ - 16400, /* PRIMARY_16400 */ - 24400, /* PRIMARY_24400 */ - 32000, /* PRIMARY_32000 */ - 48000, /* PRIMARY_48000 */ - 64000, /* PRIMARY_64000 */ - 96000, /* PRIMARY_96000 */ - 128000, /* PRIMARY_128000 */ - 2400, /* PRIMARY_SID */ - -1, /* PRIMARY_FUT1 */ - 0, /* SPEECH_LOST */ - 0 /* NO_DATA */ -}; - -static const uint16_t evsPayloadProtectedSizes[22] = { - 48, - 56, - 136, - 144, - 160, - 184, - 192, - 256, - 264, - 288, - 320, - 328, - 368, - 400, - 464, - 480, - 488, - 640, - 960, - 1280, - 1920, - 2560 -}; - -static const bool evsPayloadProtectedSizes_isAMRWB_IOmode[22] = { - 0, - 0, /* Special case (see clause A.2.1.3) */ - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 1, - 1, - 0, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0 -}; - -static const uint16_t evsPayloadProtectedSizes_frameTypeIndex[22] = { - 12, /* PRIMARY_SID */ - 0, /* Special case (see clause A.2.1.3) */ - 0, /* AMRWB_IO_6600 */ - 1, /* PRIMARY_7200 */ - 2, /* PRIMARY_8000 */ - 1, /* AMRWB_IO_8850 */ - 3, /* PRIMARY_9600 */ - 2, /* AMRWB_IO_1265 */ - 4, /* PRIMARY_13200 */ - 3, /* AMRWB_IO_1425 */ - 4, /* AMRWB_IO_1585 */ - 5, /* PRIMARY_16400 */ - 5, /* AMRWB_IO_1825 */ - 6, /* AMRWB_IO_1985 */ - 7, /* AMRWB_IO_2305 */ - 8, /* AMRWB_IO_2385 */ - 6, /* PRIMARY_24400 */ - 7, /* PRIMARY_32000 */ - 8, /* PRIMARY_48000 */ - 9, /* PRIMARY_64000 */ - 10, /* PRIMARY_96000 */ - 11 /* PRIMARY_128000 */ -}; - -bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **framePtr, uint16_t *frameSizeBits ); + static const int32_t AMRWB_IOmode2rate[16] = { + 6600, /* AMRWB_IO_6600 */ + 8850, /* AMRWB_IO_8850 */ + 12650, /* AMRWB_IO_1265 */ + 14250, /* AMRWB_IO_1425 */ + 15850, /* AMRWB_IO_1585 */ + 18250, /* AMRWB_IO_1825 */ + 19850, /* AMRWB_IO_1985 */ + 23050, /* AMRWB_IO_2305 */ + 23850, /* AMRWB_IO_2385 */ + 1750, /* AMRWB_IO_SID: SID_1k75 followed by STI bit and CMI bits (A.2.2.1.3) */ + -1, /* AMRWB_IO_FUT1 */ + -1, /* AMRWB_IO_FUT2 */ + -1, /* AMRWB_IO_FUT3 */ + -1, /* AMRWB_IO_FUT4 */ + 0, /* SPEECH_LOST */ + 0 /* NO_DATA */ + }; + + static const int32_t PRIMARYmode2rate[16] = { + 2800, /* PRIMARY_2800 */ + 7200, /* PRIMARY_7200 */ + 8000, /* PRIMARY_8000 */ + 9600, /* PRIMARY_9600 */ + 13200, /* PRIMARY_13200 */ + 16400, /* PRIMARY_16400 */ + 24400, /* PRIMARY_24400 */ + 32000, /* PRIMARY_32000 */ + 48000, /* PRIMARY_48000 */ + 64000, /* PRIMARY_64000 */ + 96000, /* PRIMARY_96000 */ + 128000, /* PRIMARY_128000 */ + 2400, /* PRIMARY_SID */ + -1, /* PRIMARY_FUT1 */ + 0, /* SPEECH_LOST */ + 0 /* NO_DATA */ + }; + + static const uint16_t evsPayloadProtectedSizes[22] = { + 48, + 56, + 136, + 144, + 160, + 184, + 192, + 256, + 264, + 288, + 320, + 328, + 368, + 400, + 464, + 480, + 488, + 640, + 960, + 1280, + 1920, + 2560 + }; + + static const bool evsPayloadProtectedSizes_isAMRWB_IOmode[22] = { + 0, + 0, /* Special case (see clause A.2.1.3) */ + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0 + }; + + static const uint16_t evsPayloadProtectedSizes_frameTypeIndex[22] = { + 12, /* PRIMARY_SID */ + 0, /* Special case (see clause A.2.1.3) */ + 0, /* AMRWB_IO_6600 */ + 1, /* PRIMARY_7200 */ + 2, /* PRIMARY_8000 */ + 1, /* AMRWB_IO_8850 */ + 3, /* PRIMARY_9600 */ + 2, /* AMRWB_IO_1265 */ + 4, /* PRIMARY_13200 */ + 3, /* AMRWB_IO_1425 */ + 4, /* AMRWB_IO_1585 */ + 5, /* PRIMARY_16400 */ + 5, /* AMRWB_IO_1825 */ + 6, /* AMRWB_IO_1985 */ + 7, /* AMRWB_IO_2305 */ + 8, /* AMRWB_IO_2385 */ + 6, /* PRIMARY_24400 */ + 7, /* PRIMARY_32000 */ + 8, /* PRIMARY_48000 */ + 9, /* PRIMARY_64000 */ + 10, /* PRIMARY_96000 */ + 11 /* PRIMARY_128000 */ + }; + + bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **framePtr, uint16_t *frameSizeBits ); #ifdef IVAS_RTPDUMP -void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); + void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #else -static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); + static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #endif -bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); - -typedef struct -{ - RTPDUMP_HANDLE rtpdump; - bool hf_only; - RTPDUMP_RTPPACKET rtpPacket; - uint32_t timeoffset_ms; - uint16_t frameIndex; - bool frameFollowing; -} EVS_RTPDUMP_DEPACKER; - -typedef enum -{ - EVS_RTPDUMP_DEPACKER_NO_ERROR = 0, - EVS_RTPDUMP_DEPACKER_EOF = -1, - EVS_RTPDUMP_DEPACKER_RTPDUMP_ERROR = 1, - EVS_RTPDUMP_DEPACKER_PAYLOAD_ERROR -} EVS_RTPDUMP_DEPACKER_ERROR; - -EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_open( EVS_RTPDUMP_DEPACKER *self, FILE *file, bool hf_only ); - -EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_readNextFrame( - EVS_RTPDUMP_DEPACKER *self, - uint16_t *rtpSequenceNumber, - uint32_t *rtpTimeStamp, - uint32_t *rcvTime_ms, - bool *isAMRWB_IOmode, - uint16_t *frameTypeIndex, - bool *qBit, - unsigned char **frame, - uint16_t *frameSizeBits ); - -void EVS_RTPDUMP_DEPACKER_close( EVS_RTPDUMP_DEPACKER *self ); - - /* clang-format on */ + bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); + + typedef struct + { + RTPDUMP_HANDLE rtpdump; + bool hf_only; + RTPDUMP_RTPPACKET rtpPacket; + uint32_t timeoffset_ms; + uint16_t frameIndex; + bool frameFollowing; + } EVS_RTPDUMP_DEPACKER; + + typedef enum + { + EVS_RTPDUMP_DEPACKER_NO_ERROR = 0, + EVS_RTPDUMP_DEPACKER_EOF = -1, + EVS_RTPDUMP_DEPACKER_RTPDUMP_ERROR = 1, + EVS_RTPDUMP_DEPACKER_PAYLOAD_ERROR + } EVS_RTPDUMP_DEPACKER_ERROR; + + EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_open( EVS_RTPDUMP_DEPACKER *self, FILE *file, bool hf_only ); + + EVS_RTPDUMP_DEPACKER_ERROR EVS_RTPDUMP_DEPACKER_readNextFrame( + EVS_RTPDUMP_DEPACKER *self, + uint16_t *rtpSequenceNumber, + uint32_t *rtpTimeStamp, + uint32_t *rcvTime_ms, + bool *isAMRWB_IOmode, + uint16_t *frameTypeIndex, + bool *qBit, + unsigned char **frame, + uint16_t *frameSizeBits ); + + void EVS_RTPDUMP_DEPACKER_close( EVS_RTPDUMP_DEPACKER *self ); #ifdef __cplusplus } -- GitLab From fe17179440d9dc362143313a1cf746fff54d036b Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 23 Apr 2025 15:00:51 +0300 Subject: [PATCH 12/33] Clang format --- lib_util/evs_rtp_payload.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_util/evs_rtp_payload.h b/lib_util/evs_rtp_payload.h index 74c4a56a56..21bb10f3f3 100644 --- a/lib_util/evs_rtp_payload.h +++ b/lib_util/evs_rtp_payload.h @@ -164,7 +164,7 @@ extern "C" #ifdef IVAS_RTPDUMP void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #else - static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); +static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #endif bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); -- GitLab From f40f758fd02d391ea57d205b86b53262b4f3b4fd Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 24 Apr 2025 11:00:31 +0300 Subject: [PATCH 13/33] Change PI data pointers to variables --- apps/encoder.c | 10 ++++---- lib_util/ivas_rtp_payload.c | 47 ++++++++++++++++++++++++------------- lib_util/ivas_rtp_payload.h | 6 +++-- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/apps/encoder.c b/apps/encoder.c index 3d1e160f7d..13dd477363 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -859,25 +859,23 @@ int main( /* scene orientation */ if ( sceneOrientationFileReader ) { - IVAS_QUATERNION sceneOrientationQuat; - if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &sceneOrientationQuat, NULL ) ) != IVAS_ERR_OK ) + if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &rtpdumpPacker->piDataPacker.sceneOrientationQuat, NULL ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError %s while reading scene orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( sceneOrientationFileReader ) ); goto cleanup; } - rtpdumpPacker->piDataPacker.sceneOrientationQuat = &sceneOrientationQuat; + rtpdumpPacker->piDataPacker.sceneOrientationPresent = true; } /* device orientation */ if ( deviceOrientationFileReader ) { - IVAS_QUATERNION deviceOrientationQuat; - if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &deviceOrientationQuat, NULL ) ) != IVAS_ERR_OK ) + if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &rtpdumpPacker->piDataPacker.deviceOrientationQuat, NULL ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError %s while reading device orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( deviceOrientationFileReader ) ); goto cleanup; } - rtpdumpPacker->piDataPacker.deviceOrientationQuat = &deviceOrientationQuat; + rtpdumpPacker->piDataPacker.deviceOrientationPresent = true; } /* disable headtracking */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 132e4d23e2..6bac9a066d 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -328,14 +328,14 @@ static uint16_t ivasPayload_convertToQ15( float value ) *-----------------------------------------------------------------------*/ static void ivasPayload_convertOrientationToQ15( - IVAS_QUATERNION *orientation, /* i : Input orientation in quaternion to be converted to Q15 */ + IVAS_QUATERNION orientation, /* i : Input orientation in quaternion to be converted to Q15 */ IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ ) { - orientationQ15->w = ivasPayload_convertToQ15( orientation->w ); - orientationQ15->x = ivasPayload_convertToQ15( orientation->x ); - orientationQ15->y = ivasPayload_convertToQ15( orientation->y ); - orientationQ15->z = ivasPayload_convertToQ15( orientation->z ); + orientationQ15->w = ivasPayload_convertToQ15( orientation.w ); + orientationQ15->x = ivasPayload_convertToQ15( orientation.x ); + orientationQ15->y = ivasPayload_convertToQ15( orientation.y ); + orientationQ15->z = ivasPayload_convertToQ15( orientation.z ); } @@ -679,6 +679,11 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( { IVAS_RTPDUMP_PACKER *self; RTPDUMP_ERROR rtpdumpError; + IVAS_QUATERNION identity; + identity.w = 1.0f; + identity.x = 0.0f; + identity.y = 0.0f; + identity.z = 0.0f; self = calloc( sizeof( IVAS_RTPDUMP_PACKER ), 1 ); rtpdumpError = RTPDUMP_OpenWithFileToWrite( &self->rtpdump, file ); if ( rtpdumpError != RTPDUMP_NO_ERROR ) @@ -687,8 +692,10 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( } RTPDUMP_SetDefaultRtpPacketHeader( &self->rtpPacket ); memset( self->rtpPacket.data, 0, sizeof( self->rtpPacket.data ) ); - self->piDataPacker.sceneOrientationQuat = NULL; - self->piDataPacker.deviceOrientationQuat = NULL; + self->piDataPacker.sceneOrientationQuat = identity; + self->piDataPacker.deviceOrientationQuat = identity; + self->piDataPacker.sceneOrientationPresent = false; + self->piDataPacker.deviceOrientationPresent = false; self->piDataPacker.enableHeadtracking = false; self->piDataPacker.disableHeadtracking = false; self->piDataPackerState.previousDisableHeadtrackingState = false; @@ -953,9 +960,9 @@ void IVAS_RTPDUMP_PACKER_writePIdata( /* PI header section */ /* scene orientation */ - if ( self->piDataPacker.sceneOrientationQuat ) + if ( self->piDataPacker.sceneOrientationPresent ) { - if ( self->piDataPacker.deviceOrientationQuat || self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) + if ( self->piDataPacker.deviceOrientationPresent || self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) { somePIfollowing = true; } @@ -972,7 +979,7 @@ void IVAS_RTPDUMP_PACKER_writePIdata( } /* device orientation */ - if ( self->piDataPacker.deviceOrientationQuat ) + if ( self->piDataPacker.deviceOrientationPresent ) { if ( self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) { @@ -1010,7 +1017,7 @@ void IVAS_RTPDUMP_PACKER_writePIdata( /* PI frame data section */ - if ( self->piDataPacker.sceneOrientationQuat ) + if ( self->piDataPacker.sceneOrientationPresent ) { ivasPayload_convertOrientationToQ15( self->piDataPacker.sceneOrientationQuat, &sceneOrientationQ15 ); writeByteToRtp( self, (char) ( sceneOrientationQ15.w >> 8 ) ); @@ -1023,7 +1030,7 @@ void IVAS_RTPDUMP_PACKER_writePIdata( writeByteToRtp( self, (char) ( sceneOrientationQ15.z & 0x00FF ) ); } - if ( self->piDataPacker.deviceOrientationQuat ) + if ( self->piDataPacker.deviceOrientationPresent ) { ivasPayload_convertOrientationToQ15( self->piDataPacker.deviceOrientationQuat, &deviceOrientationQ15 ); writeByteToRtp( self, (char) ( deviceOrientationQ15.w >> 8 ) ); @@ -1064,8 +1071,8 @@ void IVAS_RTPDUMP_PACKER_determinePIpresence( ) { self->piDataPresent = false; - if ( self->piDataPacker.sceneOrientationQuat || - self->piDataPacker.deviceOrientationQuat || + if ( self->piDataPacker.sceneOrientationPresent || + self->piDataPacker.deviceOrientationPresent || self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) { @@ -1077,9 +1084,17 @@ void IVAS_RTPDUMP_PACKER_resetPIdata( IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ) { + IVAS_QUATERNION identity; + identity.w = 1.0f; + identity.x = 0.0f; + identity.y = 0.0f; + identity.z = 0.0f; + self->piDataPresent = false; - self->piDataPacker.sceneOrientationQuat = NULL; - self->piDataPacker.deviceOrientationQuat = NULL; + self->piDataPacker.sceneOrientationQuat = identity; + self->piDataPacker.deviceOrientationQuat = identity; + self->piDataPacker.sceneOrientationPresent = false; + self->piDataPacker.deviceOrientationPresent = false; self->piDataPacker.enableHeadtracking = false; self->piDataPacker.disableHeadtracking = false; } diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index 101a7805dd..bbe939e036 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -109,8 +109,10 @@ typedef enum typedef struct { - IVAS_QUATERNION *sceneOrientationQuat; - IVAS_QUATERNION *deviceOrientationQuat; + IVAS_QUATERNION sceneOrientationQuat; + IVAS_QUATERNION deviceOrientationQuat; + bool sceneOrientationPresent; + bool deviceOrientationPresent; bool enableHeadtracking; bool disableHeadtracking; } PI_DATA_PACKER; -- GitLab From cb4ca3744617e8456327b4546429b605c6ff8a89 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 24 Apr 2025 11:41:04 +0300 Subject: [PATCH 14/33] Clang format --- lib_util/ivas_rtp_payload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 6bac9a066d..12c37b4d57 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -328,7 +328,7 @@ static uint16_t ivasPayload_convertToQ15( float value ) *-----------------------------------------------------------------------*/ static void ivasPayload_convertOrientationToQ15( - IVAS_QUATERNION orientation, /* i : Input orientation in quaternion to be converted to Q15 */ + IVAS_QUATERNION orientation, /* i : Input orientation in quaternion to be converted to Q15 */ IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ ) { -- GitLab From aaf31eb2cc9068714ef39a47918062b7ec176656 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 24 Apr 2025 13:59:43 +0300 Subject: [PATCH 15/33] Fix usan errors --- lib_util/ivas_rtp_payload.c | 2 +- lib_util/rtpdump.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 12c37b4d57..dfa2ffd901 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -921,7 +921,7 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( tempData = 0; for ( k = 0; k < 8; ++k ) { - tempData = ( tempData << 1 ) | (char) bitStream[i + k]; + tempData = (char) ( ( tempData << 1 ) | (char) bitStream[i + k] ); } writeByteToRtp( self, tempData ); } diff --git a/lib_util/rtpdump.c b/lib_util/rtpdump.c index a01bc112a3..2ce8580a86 100644 --- a/lib_util/rtpdump.c +++ b/lib_util/rtpdump.c @@ -110,10 +110,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; @@ -125,8 +132,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; -- GitLab From 02626ffa5e7b885ccc55e8844ac8666b750b33d1 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 24 Apr 2025 15:31:02 +0300 Subject: [PATCH 16/33] Fix usan errors --- lib_util/ivas_rtp_payload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index dfa2ffd901..3e9fd71532 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -351,7 +351,7 @@ static float ivasPayload_parseQuaternionComponent( { uint16_t tempQ15value; tempQ15value = ( uint16_t ) * *PIorientationData; - tempQ15value = ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ); + tempQ15value = ( uint16_t ) ( ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ) ); *PIorientationData += 2; return ivasPayload_convertFromQ15( tempQ15value ); } -- GitLab From 1b89fe7eb4bbe1694dabe1d40ed5c03d2863314c Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 24 Apr 2025 15:34:26 +0300 Subject: [PATCH 17/33] Clang format --- lib_util/ivas_rtp_payload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 3e9fd71532..22d160cebd 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -351,7 +351,7 @@ static float ivasPayload_parseQuaternionComponent( { uint16_t tempQ15value; tempQ15value = ( uint16_t ) * *PIorientationData; - tempQ15value = ( uint16_t ) ( ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ) ); + tempQ15value = (uint16_t) ( ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ) ); *PIorientationData += 2; return ivasPayload_convertFromQ15( tempQ15value ); } -- GitLab From c7da622a031463cd16759d5a8e99285f3c4659a9 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 12 Jun 2025 15:02:22 +0300 Subject: [PATCH 18/33] Remove disable headtracking reader files from MSVC project --- Workspace_msvc/lib_util.vcxproj | 2 -- Workspace_msvc/lib_util.vcxproj.filters | 6 ------ 2 files changed, 8 deletions(-) diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 28832eb4f0..94561b175a 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -108,7 +108,6 @@ - @@ -139,7 +138,6 @@ - diff --git a/Workspace_msvc/lib_util.vcxproj.filters b/Workspace_msvc/lib_util.vcxproj.filters index f3824f1fe4..afaedfb5da 100644 --- a/Workspace_msvc/lib_util.vcxproj.filters +++ b/Workspace_msvc/lib_util.vcxproj.filters @@ -82,9 +82,6 @@ util_c - - util_c - util_c @@ -177,9 +174,6 @@ util_h - - util_h - util_h -- GitLab From d8f66c1b4ecc0068970c4395df23da166f0ca08a Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 12 Jun 2025 15:33:38 +0300 Subject: [PATCH 19/33] Remove enable/disable headtracking PI data --- apps/encoder.c | 58 ------- lib_com/common_api_types.h | 2 - lib_dec/lib_dec.c | 31 ---- lib_dec/lib_dec.h | 5 - lib_rend/ivas_rotation.c | 25 +-- lib_rend/ivas_stat_rend.h | 3 - lib_util/disable_headtracking_file_reader.c | 169 -------------------- lib_util/disable_headtracking_file_reader.h | 86 ---------- lib_util/ivas_rtp_payload.c | 74 +-------- lib_util/ivas_rtp_payload.h | 24 --- readme.txt | 1 - 11 files changed, 5 insertions(+), 473 deletions(-) delete mode 100644 lib_util/disable_headtracking_file_reader.c delete mode 100644 lib_util/disable_headtracking_file_reader.h diff --git a/apps/encoder.c b/apps/encoder.c index 13dd477363..fe444c4d11 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -39,7 +39,6 @@ #include "jbm_file_reader.h" #include "masa_file_reader.h" #ifdef IVAS_RTPDUMP -#include "disable_headtracking_file_reader.h" #include "evs_rtp_payload.h" #include "ivas_rtp_payload.h" #include "rotation_file_reader.h" @@ -156,7 +155,6 @@ typedef struct bool rtpdumpOutput; char *sceneOrientationTrajFileName; char *deviceOrientationTrajFileName; - char *disableHeadtrackingFileName; #endif } EncArguments; @@ -204,7 +202,6 @@ int main( #ifdef IVAS_RTPDUMP RotFileReader *sceneOrientationFileReader = NULL; RotFileReader *deviceOrientationFileReader = NULL; - DisableHeadtrackingFileReader *disableHeadtrackingFileReader = NULL; #endif #ifdef DEBUGGING FILE *f_forcedModeProfile = NULL; @@ -668,19 +665,6 @@ int main( goto cleanup; } } - - /*------------------------------------------------------------------------------------------* - * Open disable headtracking file - *------------------------------------------------------------------------------------------*/ - - if ( arg.disableHeadtrackingFileName != NULL ) - { - if ( ( error = DisableHeadtrackingFileReader_open( arg.disableHeadtrackingFileName, &disableHeadtrackingFileReader ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError: Can't open disable headtracking file %s \n\n", arg.disableHeadtrackingFileName ); - goto cleanup; - } - } #endif int16_t numSamplesRead = 0; @@ -878,17 +862,6 @@ int main( rtpdumpPacker->piDataPacker.deviceOrientationPresent = true; } - /* disable headtracking */ - if ( disableHeadtrackingFileReader ) - { - if ( ( error = DisableHeadtrackingFileReading( disableHeadtrackingFileReader, &rtpdumpPacker->piDataPacker.disableHeadtracking ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError %s while reading disable headtracking data from %s\n", IVAS_ENC_GetErrorMessage( error ), DisableHeadtrackingFileReader_getFilePath( disableHeadtrackingFileReader ) ); - goto cleanup; - } - IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( rtpdumpPacker ); - } - /* PI presence */ IVAS_RTPDUMP_PACKER_determinePIpresence( rtpdumpPacker ); @@ -1007,11 +980,6 @@ cleanup: { RotationFileReader_close( &deviceOrientationFileReader ); } - - if ( disableHeadtrackingFileReader ) - { - DisableHeadtrackingFileReader_close( &disableHeadtrackingFileReader ); - } #endif IVAS_ENC_Close( &hIvasEnc ); @@ -1088,7 +1056,6 @@ static bool parseCmdlIVAS_enc( arg->rtpdumpOutput = false; arg->sceneOrientationTrajFileName = NULL; arg->deviceOrientationTrajFileName = NULL; - arg->disableHeadtrackingFileName = NULL; #endif #ifdef DEBUGGING @@ -1932,24 +1899,6 @@ static bool parseCmdlIVAS_enc( i++; } - /*-----------------------------------------------------------------* - * Disable headtracking file reading - *-----------------------------------------------------------------*/ - - else if ( strcmp( argv_to_upper, "-DISABLE_HEADTRACKING_FILE" ) == 0 ) - { - i++; - if ( argc - i <= 4 || argv[i][0] == '-' ) - { - fprintf( stderr, "Error: Disable headtracking input file name not specified!\n\n" ); - usage_enc(); - return false; - } - - arg->disableHeadtrackingFileName = argv[i]; - i++; - } - #endif /*-----------------------------------------------------------------* * Option not recognized @@ -1975,12 +1924,6 @@ static bool parseCmdlIVAS_enc( usage_enc(); return false; } - if ( arg->disableHeadtrackingFileName != NULL && arg->rtpdumpOutput == false ) - { - fprintf( stderr, "Error: Disable headtracking file reading is only enabled with rtpdump output!\n\n" ); - usage_enc(); - return false; - } #endif /*-----------------------------------------------------------------* @@ -2196,7 +2139,6 @@ static void usage_enc( void ) fprintf( stdout, " EVS RTP Payload Format is used. \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" ); - fprintf( stdout, "-disable_headtracking_file : Disable headtracking input file. (1) to disable and (0) to enable headtracking. Only used with rtpdump output.\n" ); #endif fprintf( stdout, "\n" ); diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index 866229f11c..d711365703 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -226,8 +226,6 @@ typedef struct char *acousticEnvironmentId; char *acousticEnvironmentOnlyLateReverb; char *acousticEnvironmentLateReverbAndEarlyReflections; - bool enableHeadTracking; - bool disableHeadTracking; } PI_DATA_CURRENT_FRAME; typedef struct diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index aeaf61caa3..0ef490fcc7 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3784,34 +3784,6 @@ ivas_error IVAS_DEC_parseSinglePIorientation( } -/*---------------------------------------------------------------------* - * IVAS_DEC_parsePIenableDisableHeadtracking( ) - * - * Parse enable/disable headtracking from PI data - *---------------------------------------------------------------------*/ - -void IVAS_DEC_parsePIenableDisableHeadtracking( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* i : PI data handle for the current frame */ -) -{ - if ( PIdataCurrentFrame->enableHeadTracking ) - { - if ( hIvasDec->st_ivas->hCombinedOrientationData ) - { - hIvasDec->st_ivas->hCombinedOrientationData->enableHeadTrackingPI = 1; - } - } - if ( PIdataCurrentFrame->disableHeadTracking ) - { - if ( hIvasDec->st_ivas->hCombinedOrientationData ) - { - hIvasDec->st_ivas->hCombinedOrientationData->enableHeadTrackingPI = 0; - } - } -} - - /*---------------------------------------------------------------------* * IVAS_DEC_parsePIdata( ) * @@ -3838,9 +3810,6 @@ ivas_error IVAS_DEC_parsePIdata( return error; } - /* enable/disable headtracking */ - IVAS_DEC_parsePIenableDisableHeadtracking( hIvasDec, PIdataCurrentFrame ); - return error; } diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 2170cd94a7..f71ff96e7c 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -337,11 +337,6 @@ ivas_error IVAS_DEC_parseSinglePIorientation( IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ ); -void IVAS_DEC_parsePIenableDisableHeadtracking( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* i : PI data handle for the current frame */ -); - ivas_error IVAS_DEC_parsePIdata( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* i : PI data handle for the current frame */ diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index 93c0cd0996..378736e650 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -862,9 +862,6 @@ ivas_error ivas_combined_orientation_open( ( *hCombinedOrientationData )->subframe_idx = 0; ( *hCombinedOrientationData )->subframe_size = (int16_t) ( fs / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ); ( *hCombinedOrientationData )->cur_subframe_samples_rendered = 0; -#ifdef IVAS_RTPDUMP - ( *hCombinedOrientationData )->enableHeadTrackingPI = 1; -#endif return IVAS_ERR_OK; } @@ -1026,24 +1023,10 @@ ivas_error combine_external_and_head_orientations( else if ( hExtOrientationData == NULL && headRotQuaternions != NULL ) { /* Head rotation only */ -#ifdef IVAS_RTPDUMP - if ( hCombinedOrientationData->enableHeadTrackingPI == 1 ) - { -#endif - for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) - { - hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; - } -#ifdef IVAS_RTPDUMP - } - else + for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) { - for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ ) - { - hCombinedOrientationData->Quaternions[i] = identity; - } + hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; } -#endif } if ( hExtOrientationData != NULL ) @@ -1121,11 +1104,7 @@ ivas_error combine_external_and_head_orientations( hCombinedOrientationData->isHeadRotationFrozen = 0; } /* Use the most recent head rotation */ -#ifdef IVAS_RTPDUMP - if ( hExtOrientationData->enableHeadRotation[i] == 1 && hCombinedOrientationData->enableHeadTrackingPI == 1 ) -#else if ( hExtOrientationData->enableHeadRotation[i] == 1 ) -#endif { if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) { diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 906f5e157d..e990c336f6 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -710,9 +710,6 @@ typedef struct ivas_combined_orientation_struct int16_t cur_subframe_samples_rendered; int16_t subframe_idx_start; int16_t cur_subframe_samples_rendered_start; -#ifdef IVAS_RTPDUMP - int8_t enableHeadTrackingPI; -#endif } COMBINED_ORIENTATION_DATA, *COMBINED_ORIENTATION_HANDLE; /*----------------------------------------------------------------------------------* diff --git a/lib_util/disable_headtracking_file_reader.c b/lib_util/disable_headtracking_file_reader.c deleted file mode 100644 index 992464a6f9..0000000000 --- a/lib_util/disable_headtracking_file_reader.c +++ /dev/null @@ -1,169 +0,0 @@ -/****************************************************************************************************** - - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository. All Rights Reserved. - - This software is protected by copyright law and by international treaties. - The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository retain full ownership rights in their respective contributions in - the software. This notice grants no license of any kind, including but not limited to patent - license, nor is any license granted by implication, estoppel or otherwise. - - Contributors are required to enter into the IVAS codec Public Collaboration agreement before making - contributions. - - This software is provided "AS IS", without any express or implied warranties. The software is in the - development stage. It is intended exclusively for experts who have experience with such software and - solely for the purpose of inspection. All implied warranties of non-infringement, merchantability - and fitness for a particular purpose are hereby disclaimed and excluded. - - Any dispute, controversy or claim arising under or in relation to providing this software shall be - submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in - accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and - the United Nations Convention on Contracts on the International Sales of Goods. - -*******************************************************************************************************/ - - -#include "disable_headtracking_file_reader.h" -#include -#include -#include -#include "prot.h" - -#ifdef IVAS_RTPDUMP - -struct DisableHeadtrackingFileReader -{ - FILE *inputFile; - int32_t frameCounter; - char *file_path; - bool fileRewind; -}; - - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReader_open() - * - * Allocate and initialize file reader - *-----------------------------------------------------------------------*/ - -ivas_error DisableHeadtrackingFileReader_open( - char *filePath, /* i : disable-headtracking input file name */ - DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ -) -{ - DisableHeadtrackingFileReader *self; - FILE *inputFile; - - /* Open trajectory file */ - if ( strlen( filePath ) < 1 ) - { - return IVAS_ERR_FAILED_FILE_OPEN; - } - - inputFile = fopen( filePath, "r" ); - - if ( !inputFile ) - { - return IVAS_ERR_FAILED_FILE_OPEN; - } - - self = calloc( sizeof( DisableHeadtrackingFileReader ), 1 ); - self->inputFile = inputFile; - self->frameCounter = 0; - self->file_path = calloc( sizeof( char ), strlen( filePath ) + 1 ); - strcpy( self->file_path, filePath ); - self->fileRewind = false; - - *fileReader = self; - - return IVAS_ERR_OK; -} - - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReading() - * - * Read values from the input file. (1) to disable and (0) to enable headtracking. - *-----------------------------------------------------------------------*/ - -ivas_error DisableHeadtrackingFileReading( - DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ - bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ -) -{ - float disableHeadTrackingFlag; - int32_t read_values; - - /* Initial values, if they are not read from the file (enable headtracking by default) */ - disableHeadTrackingFlag = 0; - - read_values = fscanf( fileReader->inputFile, "%f", &disableHeadTrackingFlag ); - if ( ( read_values != 1 ) ) - { - if ( feof( fileReader->inputFile ) ) - { - rewind( fileReader->inputFile ); - fileReader->fileRewind = true; - return DisableHeadtrackingFileReading( fileReader, pHeadTrackingDisabled ); - } - return IVAS_ERR_FAILED_FILE_PARSE; - } - - ( fileReader->frameCounter )++; - - *pHeadTrackingDisabled = (int8_t) disableHeadTrackingFlag == 1 ? true : false; - - return IVAS_ERR_OK; -} - - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReader_close() - * - * Deallocates memory for the file reader - *-----------------------------------------------------------------------*/ - -void DisableHeadtrackingFileReader_close( - DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ -) -{ - if ( fileReader == NULL || *fileReader == NULL ) - { - return; - } - - fclose( ( *fileReader )->inputFile ); - free( ( *fileReader )->file_path ); - free( *fileReader ); - *fileReader = NULL; - - return; -} - - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReader_getFilePath() - * - * - *-----------------------------------------------------------------------*/ - -const char *DisableHeadtrackingFileReader_getFilePath( - DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ -) -{ - if ( fileReader == NULL ) - { - return NULL; - } - - return fileReader->file_path; -} -#endif diff --git a/lib_util/disable_headtracking_file_reader.h b/lib_util/disable_headtracking_file_reader.h deleted file mode 100644 index 1dda351565..0000000000 --- a/lib_util/disable_headtracking_file_reader.h +++ /dev/null @@ -1,86 +0,0 @@ -/****************************************************************************************************** - - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository. All Rights Reserved. - - This software is protected by copyright law and by international treaties. - The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository retain full ownership rights in their respective contributions in - the software. This notice grants no license of any kind, including but not limited to patent - license, nor is any license granted by implication, estoppel or otherwise. - - Contributors are required to enter into the IVAS codec Public Collaboration agreement before making - contributions. - - This software is provided "AS IS", without any express or implied warranties. The software is in the - development stage. It is intended exclusively for experts who have experience with such software and - solely for the purpose of inspection. All implied warranties of non-infringement, merchantability - and fitness for a particular purpose are hereby disclaimed and excluded. - - Any dispute, controversy or claim arising under or in relation to providing this software shall be - submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in - accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and - the United Nations Convention on Contracts on the International Sales of Goods. - -*******************************************************************************************************/ - -#ifndef IVAS_DISABLE_HEADTRACKING_FILE_READER_H -#define IVAS_DISABLE_HEADTRACKING_FILE_READER_H - -#include -#include "common_api_types.h" - -#ifdef IVAS_RTPDUMP - -typedef struct DisableHeadtrackingFileReader DisableHeadtrackingFileReader; - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReader_open() - * - * Allocate and initialize reader handle - *-----------------------------------------------------------------------*/ - -ivas_error DisableHeadtrackingFileReader_open( - char *filePath, /* i : disable-headtracking input file name */ - DisableHeadtrackingFileReader **fileReader /* o : DisableHeadtrackingFileReader handle */ -); - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReading() - * - * Read values from the input file. (1) to disable and (0) to enable headtracking. - *-----------------------------------------------------------------------*/ - -ivas_error DisableHeadtrackingFileReading( - DisableHeadtrackingFileReader *fileReader, /* i/o: DisableHeadtrackingFileReader handle */ - bool *pHeadTrackingDisabled /* o : enable/disable headtracking data */ -); - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReader_close() - * - * Deallocates memory for the reader handle - *-----------------------------------------------------------------------*/ - -void DisableHeadtrackingFileReader_close( - DisableHeadtrackingFileReader **fileReader /* i/o: DisableHeadtrackingFileReader handle */ -); - -/*-----------------------------------------------------------------------* - * DisableHeadtrackingFileReader_getFilePath() - * - * - *-----------------------------------------------------------------------*/ - -const char *DisableHeadtrackingFileReader_getFilePath( - DisableHeadtrackingFileReader *fileReader /* i/o: DisableHeadtrackingFileReader handle */ -); -#endif - -#endif /* IVAS_DISABLE_HEADTRACKING_FILE_READER_H */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 22d160cebd..467de66eb9 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -147,14 +147,6 @@ static void ivasPayload_parsePItype( PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections = PIframeDataBeginning + parsedPIframeSizeBytes; } } - else if ( PIframeType == PI_ENABLE_HEADTRACKING ) - { - PIdataCurrentFrame->enableHeadTracking = true; - } - else if ( PIframeType == PI_DISABLE_HEADTRACKING ) - { - PIdataCurrentFrame->disableHeadTracking = true; - } else if ( PIframeType == PI_NO_DATA ) { /* no data */ @@ -372,8 +364,6 @@ void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) PIdataCurrentFrame->acousticEnvironmentId = NULL; PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb = NULL; PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections = NULL; - PIdataCurrentFrame->enableHeadTracking = false; - PIdataCurrentFrame->disableHeadTracking = false; } @@ -696,9 +686,6 @@ IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( self->piDataPacker.deviceOrientationQuat = identity; self->piDataPacker.sceneOrientationPresent = false; self->piDataPacker.deviceOrientationPresent = false; - self->piDataPacker.enableHeadtracking = false; - self->piDataPacker.disableHeadtracking = false; - self->piDataPackerState.previousDisableHeadtrackingState = false; self->piDataPresent = false; *rtpdumpPacker = self; return IVAS_RTPDUMP_PACKER_NO_ERROR; @@ -962,7 +949,7 @@ void IVAS_RTPDUMP_PACKER_writePIdata( /* scene orientation */ if ( self->piDataPacker.sceneOrientationPresent ) { - if ( self->piDataPacker.deviceOrientationPresent || self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) + if ( self->piDataPacker.deviceOrientationPresent ) { somePIfollowing = true; } @@ -981,40 +968,11 @@ void IVAS_RTPDUMP_PACKER_writePIdata( /* device orientation */ if ( self->piDataPacker.deviceOrientationPresent ) { - if ( self->piDataPacker.enableHeadtracking || self->piDataPacker.disableHeadtracking ) - { - somePIfollowing = true; - } - else - { - somePIfollowing = false; - } - if ( somePIfollowing ) - { - PIheaderByte = ( PF0 << 7 ) | ( PM_NOT_LAST << 5 ) | PI_DEVICE_ORIENTATION_UNCOMPENSATED; - } - else - { - PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_DEVICE_ORIENTATION_UNCOMPENSATED; - } + PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_DEVICE_ORIENTATION_UNCOMPENSATED; writeByteToRtp( self, (char) PIheaderByte ); writeByteToRtp( self, PI_DEVICE_ORIENTATION_UNCOMPENSATED_SIZE_BYTES ); } - /* enable/disable headtracking */ - if ( self->piDataPacker.enableHeadtracking && !self->piDataPacker.disableHeadtracking ) - { - PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_ENABLE_HEADTRACKING; - writeByteToRtp( self, (char) PIheaderByte ); - writeByteToRtp( self, PI_ENABLE_HEADTRACKING_SIZE_BYTES ); - } - if ( self->piDataPacker.disableHeadtracking ) - { - PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_DISABLE_HEADTRACKING; - writeByteToRtp( self, (char) PIheaderByte ); - writeByteToRtp( self, PI_DISABLE_HEADTRACKING_SIZE_BYTES ); - } - /* PI frame data section */ if ( self->piDataPacker.sceneOrientationPresent ) @@ -1044,37 +1002,13 @@ void IVAS_RTPDUMP_PACKER_writePIdata( } } -void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ -) -{ - if ( self->piDataPacker.disableHeadtracking == self->piDataPackerState.previousDisableHeadtrackingState ) - { - /* same state as before, do not send PI data */ - self->piDataPacker.disableHeadtracking = false; - } - else if ( self->piDataPacker.disableHeadtracking && self->piDataPackerState.previousDisableHeadtrackingState == false ) - { - /* headtracking was enabled, send disable headtracking PI data */ - self->piDataPackerState.previousDisableHeadtrackingState = true; - } - else if ( !self->piDataPacker.disableHeadtracking && self->piDataPackerState.previousDisableHeadtrackingState == true ) - { - /* headtracking was disabled, send enable headtracking PI data */ - self->piDataPackerState.previousDisableHeadtrackingState = false; - self->piDataPacker.enableHeadtracking = true; - } -} - void IVAS_RTPDUMP_PACKER_determinePIpresence( IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ ) { self->piDataPresent = false; if ( self->piDataPacker.sceneOrientationPresent || - self->piDataPacker.deviceOrientationPresent || - self->piDataPacker.enableHeadtracking || - self->piDataPacker.disableHeadtracking ) + self->piDataPacker.deviceOrientationPresent ) { self->piDataPresent = true; } @@ -1095,8 +1029,6 @@ void IVAS_RTPDUMP_PACKER_resetPIdata( self->piDataPacker.deviceOrientationQuat = identity; self->piDataPacker.sceneOrientationPresent = false; self->piDataPacker.deviceOrientationPresent = false; - self->piDataPacker.enableHeadtracking = false; - self->piDataPacker.disableHeadtracking = false; } void IVAS_RTPDUMP_PACKER_close( diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index bbe939e036..9d8bad958f 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -89,8 +89,6 @@ typedef enum PI_DEVICE_ORIENTATION_COMPENSATED = 1, PI_DEVICE_ORIENTATION_UNCOMPENSATED = 2, PI_ACOUSTIC_ENVIRONMENT = 3, - PI_ENABLE_HEADTRACKING = 4, - PI_DISABLE_HEADTRACKING = 5, PI_NO_DATA = 31 } PI_TYPE; @@ -102,8 +100,6 @@ typedef enum PI_ACOUSTIC_ENVIRONMENT_ID_SIZE_BYTES = 1, PI_ACOUSTIC_ENVIRONMENT_ONLY_LATE_REVERB_SIZE_BYTES = 5, PI_ACOUSTIC_ENVIRONMENT_LATE_REVERB_AND_EARLY_REFLECTIONS_SIZE_BYTES = 8, - PI_ENABLE_HEADTRACKING_SIZE_BYTES = 0, - PI_DISABLE_HEADTRACKING_SIZE_BYTES = 0, PI_NO_DATA_SIZE_BYTES = 0 } PI_SIZE_BYTES; @@ -113,15 +109,8 @@ typedef struct IVAS_QUATERNION deviceOrientationQuat; bool sceneOrientationPresent; bool deviceOrientationPresent; - bool enableHeadtracking; - bool disableHeadtracking; } PI_DATA_PACKER; -typedef struct -{ - bool previousDisableHeadtrackingState; -} PI_DATA_PACKER_STATE; - typedef struct { uint16_t w, x, y, z; @@ -211,7 +200,6 @@ typedef struct RTPDUMP_RTPPACKET rtpPacket; uint32_t timeoffset_ms; PI_DATA_PACKER piDataPacker; - PI_DATA_PACKER_STATE piDataPackerState; bool piDataPresent; int32_t writingIndex; } IVAS_RTPDUMP_PACKER; @@ -370,18 +358,6 @@ void IVAS_RTPDUMP_PACKER_writePIdata( ); -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState() - * - * Check for disable headtracking input and previously set disable/enable headtracking state. - * Set the current PI headtracking state accordingly. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_checkPIdisableHeadtrackingState( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ -); - - /*-----------------------------------------------------------------------* * IVAS_RTPDUMP_PACKER_determinePIpresence() * diff --git a/readme.txt b/readme.txt index a4bdba47c7..d9a8e5b414 100644 --- a/readme.txt +++ b/readme.txt @@ -255,7 +255,6 @@ EVS mono is default, for IVAS choose one of the following: -stereo, -ism, -sba, EVS RTP Payload Format is used. -scene_orientation : Scene orientation trajectory file. Only used with rtpdump output. -device_orientation : Device orientation trajectory file. Only used with rtpdump output. --disable_headtracking_file : Disable headtracking input file. (1) to disable and (0) to enable headtracking. Only used with rtpdump output. The usage of the "IVAS_dec" program is as follows: -- GitLab From 290e40eac6ba866e0df9458371b1f01dbbbe6eb3 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Fri, 13 Jun 2025 14:04:59 +0300 Subject: [PATCH 20/33] Restructure code, move PI data parsing to utils from lib_dec --- apps/decoder.c | 7 +- lib_com/ivas_prot.h | 9 -- lib_dec/lib_dec.c | 58 +++------ lib_dec/lib_dec.h | 14 +- lib_util/ivas_rtp_payload.c | 252 +++++++++++++++++++++--------------- lib_util/ivas_rtp_payload.h | 3 +- 6 files changed, 171 insertions(+), 172 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 61f72dd493..cb2e08233f 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3384,14 +3384,13 @@ static ivas_error decodeVoIP( /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; - /* parse PI data */ - error = IVAS_DEC_parsePIdata( hIvasDec, &rtpdumpDepacker.PIdataCurrentFrame, &rtpdumpDepacker.PIdataDepackerState ); + /* feed PI data to decoder handle */ + error = IVAS_DEC_feedPIdata( hIvasDec, &rtpdumpDepacker.PIdataDepackerState ); if ( error != IVAS_ERR_OK ) { - fprintf( stderr, "\nError in IVAS_DEC_parsePIdata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + fprintf( stderr, "\nError in IVAS_DEC_feedPIdata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } - IVAS_DEC_resetPIdataCurrentFrame( &rtpdumpDepacker.PIdataCurrentFrame ); #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 983f75e8f0..80232e5800 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -821,15 +821,6 @@ void QuaternionInverse( IVAS_QUATERNION *const r ); -void resetPIdataCurrentFrame( - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ -); - -bool ivasPayload_parseOrientationPIdata( - char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ - IVAS_QUATERNION *q /* o : Parsed quaternion value */ -); - #endif /*----------------------------------------------------------------------------------* * JBM prototypes diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 0ef490fcc7..d3ada6dd9c 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3723,24 +3723,23 @@ ivas_error IVAS_DEC_Flush( #ifdef IVAS_RTPDUMP /*---------------------------------------------------------------------* - * IVAS_DEC_parseSinglePIorientation( ) + * IVAS_DEC_feedSinglePIorientation( ) * - * Parse a single orientation from PI data and feed to external orientation handle. - * Save the parsed (inverted) orientation value and use in processing in future frames, if no new PI orientation is received. + * Feed a single orientation PI data to external orientation handle. *---------------------------------------------------------------------*/ -ivas_error IVAS_DEC_parseSinglePIorientation( +ivas_error IVAS_DEC_feedSinglePIorientation( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - char *orientation, /* i : input PI orientation */ - bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ - IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ + const 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; - if ( orientation ) + IVAS_QUATERNION savedInvOrientation; + + if ( *isOrientationSaved ) { - IVAS_QUATERNION orientationQuat, orientationQuatInv; if ( !hIvasDec->st_ivas->hExtOrientationData ) { if ( ( error = ivas_external_orientation_open( &( hIvasDec->st_ivas->hExtOrientationData ), hIvasDec->st_ivas->hDecoderConfig->render_framesize ) ) != IVAS_ERR_OK ) @@ -3757,24 +3756,12 @@ ivas_error IVAS_DEC_parseSinglePIorientation( } } - /* read the orientation PI value */ - if ( !ivasPayload_parseOrientationPIdata( orientation, &orientationQuat ) ) - { - return IVAS_ERROR( IVAS_ERR_INTERNAL, "Parsing PI orientation failed" ); - } - QuaternionInverse( orientationQuat, &orientationQuatInv ); + QuaternionInverse( *savedOrientation, &savedInvOrientation ); - /* update the saved orientation value */ - *isOrientationSaved = true; - *savedInvOrientation = orientationQuatInv; - } - - if ( *isOrientationSaved ) - { /* use the new PI orientation or the previously saved orientation in processing */ for ( i = 0; i < hIvasDec->st_ivas->hExtOrientationData->num_subframes; i++ ) { - QuaternionProduct( hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], *savedInvOrientation, + QuaternionProduct( hIvasDec->st_ivas->hExtOrientationData->Quaternions[i], savedInvOrientation, &hIvasDec->st_ivas->hExtOrientationData->Quaternions[i] ); hIvasDec->st_ivas->hExtOrientationData->enableExternalOrientation[i] = true; } @@ -3785,27 +3772,26 @@ ivas_error IVAS_DEC_parseSinglePIorientation( /*---------------------------------------------------------------------* - * IVAS_DEC_parsePIdata( ) + * IVAS_DEC_feedPIdata( ) * - * Parse PI data for a single frame + * Feed PI data to the decoder handle *---------------------------------------------------------------------*/ -ivas_error IVAS_DEC_parsePIdata( +ivas_error IVAS_DEC_feedPIdata( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* i : PI data handle for the current frame */ PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ) { ivas_error error = IVAS_ERR_OK; /* scene orientation */ - if ( ( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->sceneOrientation, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_feedSinglePIorientation( hIvasDec, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) { return error; } /* device orientation */ - if ( ( error = IVAS_DEC_parseSinglePIorientation( hIvasDec, PIdataCurrentFrame->deviceOrientationUncompensated, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_feedSinglePIorientation( hIvasDec, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) { return error; } @@ -3828,20 +3814,6 @@ void IVAS_DEC_resetExternalOrientations( } -/*---------------------------------------------------------------------* - * IVAS_DEC_resetPIdataCurrentFrame( ) - * - * Reset current PI frame struct - *---------------------------------------------------------------------*/ - -void IVAS_DEC_resetPIdataCurrentFrame( - PI_DATA_CURRENT_FRAME *piDataCurrentFrame /* i/o: PI data handle for the current frame */ -) -{ - resetPIdataCurrentFrame( piDataCurrentFrame ); -} - - #endif /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_IsEmpty( ) diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index f71ff96e7c..f20d6a9eb2 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -330,16 +330,14 @@ ivas_error IVAS_DEC_Flush( ); #ifdef IVAS_RTPDUMP -ivas_error IVAS_DEC_parseSinglePIorientation( +ivas_error IVAS_DEC_feedSinglePIorientation( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - char *orientation, /* i : input PI orientation */ - bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ - IVAS_QUATERNION *savedInvOrientation /* i : previously saved (inverted) orientation for this PI type */ + const 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 */ ); -ivas_error IVAS_DEC_parsePIdata( +ivas_error IVAS_DEC_feedPIdata( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* i : PI data handle for the current frame */ PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ); @@ -347,10 +345,6 @@ void IVAS_DEC_resetExternalOrientations( IVAS_DEC_HANDLE hIvasDec /* i/o: IVAS decoder handle */ ); -void IVAS_DEC_resetPIdataCurrentFrame( - PI_DATA_CURRENT_FRAME *piDataCurrentFrame /* i/o: PI data handle for the current frame */ -); - #endif /* Setter functions - apply changes to decoder configuration */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 467de66eb9..e9d65ea0b1 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -196,6 +196,133 @@ static void ivasPayload_PIaddHeaderBytes( } +/*-----------------------------------------------------------------------* + * ivasPayload_convertFromQ15() + * + * Convert a Q15 encoded value to a float value. + *-----------------------------------------------------------------------*/ + +static float ivasPayload_convertFromQ15( uint16_t Q15Value ) +{ + float temp; + temp = (float) ( Q15Value & 0x7FFF ) / 0x7FFF; + return ( Q15Value & 0x8000 ) ? -temp : temp; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_convertToQ15() + * + * Convert a float value into a Q15 encoded value. + *-----------------------------------------------------------------------*/ + +static uint16_t ivasPayload_convertToQ15( float value ) +{ + uint16_t temp; + temp = (uint16_t) ( fabsf( value ) * 0x7FFF ); + if ( value >= 0.0f ) + { + temp = temp & 0x7FFF; + } + else + { + temp = temp | 0x8000; + } + return temp; +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_convertOrientationToQ15() + * + * Convert a float quaternion into a Q15 encoded quaternion. + *-----------------------------------------------------------------------*/ + +static void ivasPayload_convertOrientationToQ15( + IVAS_QUATERNION orientation, /* i : Input orientation in quaternion to be converted to Q15 */ + IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ +) +{ + orientationQ15->w = ivasPayload_convertToQ15( orientation.w ); + orientationQ15->x = ivasPayload_convertToQ15( orientation.x ); + orientationQ15->y = ivasPayload_convertToQ15( orientation.y ); + orientationQ15->z = ivasPayload_convertToQ15( orientation.z ); +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parseQuaternionValue() + * + * Parse a single Q15 encoded quaternion component from the RTP packet and convert it to float. + *-----------------------------------------------------------------------*/ + +static float ivasPayload_parseQuaternionComponent( + char **PIorientationData /* i/o: Pointer to the PI data frame containing a single quaternion component */ +) +{ + uint16_t tempQ15value; + tempQ15value = ( uint16_t ) * *PIorientationData; + tempQ15value = (uint16_t) ( ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ) ); + *PIorientationData += 2; + return ivasPayload_convertFromQ15( tempQ15value ); +} + + +/*-----------------------------------------------------------------------* + * ivasPayload_parseOrientationPIdata() + * + * Parse a single orientation in quaternions from the PI data. + *-----------------------------------------------------------------------*/ + +static bool ivasPayload_parseOrientationPIdata( + char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ + IVAS_QUATERNION *q /* o : Parsed quaternion value */ +) +{ + q->w = ivasPayload_parseQuaternionComponent( &PIorientationData ); + q->x = ivasPayload_parseQuaternionComponent( &PIorientationData ); + q->y = ivasPayload_parseQuaternionComponent( &PIorientationData ); + q->z = ivasPayload_parseQuaternionComponent( &PIorientationData ); + + if ( q->w > 1.0f || q->w < -1.0f || + q->x > 1.0f || q->x < -1.0f || + q->y > 1.0f || q->y < -1.0f || + q->z > 1.0f || q->z < -1.0f ) + { + fprintf( stderr, "Error: invalid orientation PI data\n" ); + return false; + } + return true; +} + + +/*---------------------------------------------------------------------* + * ivasPayload_parseSinglePIorientation( ) + * + * Parse a single orientation from PI data. + * Save the parsed orientation value and use in processing in future frames, if no new PI orientation is received. + *---------------------------------------------------------------------*/ + +static bool ivasPayload_parseSinglePIorientation( + char *orientation, /* i : input PI orientation */ + bool *isOrientationSaved, /* o : flag to indicate if an orientation for this PI type was previously saved */ + IVAS_QUATERNION *savedOrientation /* o : saved orientation value for this PI type */ +) +{ + if ( orientation ) + { + /* read the orientation PI value */ + if ( !ivasPayload_parseOrientationPIdata( orientation, savedOrientation ) ) + { + fprintf( stderr, "Error: parsing PI orientation failed\n" ); + return false; + } + *isOrientationSaved = true; + } + return true; +} + + /*-----------------------------------------------------------------------* * ivasPayload_parsePIdata() * @@ -206,7 +333,8 @@ static bool ivasPayload_parsePIdata( char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame,/* o : PI data handle for the current audio frame */ + PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ) { // TODO(pajunen): can this accidentally include zero padding bits? @@ -273,79 +401,21 @@ static bool ivasPayload_parsePIdata( } ivasPayload_PIaddHeaderBytes( totalPIheaderSizeBytes, PIdataCurrentFrame ); - return true; -} - - -/*-----------------------------------------------------------------------* - * ivasPayload_convertFromQ15() - * - * Convert a Q15 encoded value to a float value. - *-----------------------------------------------------------------------*/ - -static float ivasPayload_convertFromQ15( uint16_t Q15Value ) -{ - float temp; - temp = (float) ( Q15Value & 0x7FFF ) / 0x7FFF; - return ( Q15Value & 0x8000 ) ? -temp : temp; -} - - -/*-----------------------------------------------------------------------* - * ivasPayload_convertToQ15() - * - * Convert a float value into a Q15 encoded value. - *-----------------------------------------------------------------------*/ - -static uint16_t ivasPayload_convertToQ15( float value ) -{ - uint16_t temp; - temp = (uint16_t) ( fabsf( value ) * 0x7FFF ); - if ( value >= 0.0f ) + /* scene orientation */ + if ( !ivasPayload_parseSinglePIorientation( PIdataCurrentFrame->sceneOrientation, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) { - temp = temp & 0x7FFF; + fprintf( stderr, "Error: parsing scene orientation PI data failed.\n" ); + return false; } - else + + /* device orientation */ + if ( !ivasPayload_parseSinglePIorientation( PIdataCurrentFrame->deviceOrientationUncompensated, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) { - temp = temp | 0x8000; + fprintf( stderr, "Error: parsing device orientation PI data failed.\n" ); + return false; } - return temp; -} - - -/*-----------------------------------------------------------------------* - * ivasPayload_convertOrientationToQ15() - * - * Convert a float quaternion into a Q15 encoded quaternion. - *-----------------------------------------------------------------------*/ - -static void ivasPayload_convertOrientationToQ15( - IVAS_QUATERNION orientation, /* i : Input orientation in quaternion to be converted to Q15 */ - IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ -) -{ - orientationQ15->w = ivasPayload_convertToQ15( orientation.w ); - orientationQ15->x = ivasPayload_convertToQ15( orientation.x ); - orientationQ15->y = ivasPayload_convertToQ15( orientation.y ); - orientationQ15->z = ivasPayload_convertToQ15( orientation.z ); -} - -/*-----------------------------------------------------------------------* - * ivasPayload_parseQuaternionValue() - * - * Parse a single Q15 encoded quaternion component from the RTP packet and convert it to float. - *-----------------------------------------------------------------------*/ - -static float ivasPayload_parseQuaternionComponent( - char **PIorientationData /* i/o: Pointer to the PI data frame containing a single quaternion component */ -) -{ - uint16_t tempQ15value; - tempQ15value = ( uint16_t ) * *PIorientationData; - tempQ15value = (uint16_t) ( ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ) ); - *PIorientationData += 2; - return ivasPayload_convertFromQ15( tempQ15value ); + return true; } @@ -355,7 +425,7 @@ static float ivasPayload_parseQuaternionComponent( * Reset the PI data handle for the current audio frame. *-----------------------------------------------------------------------*/ -void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) +static void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) { PIdataCurrentFrame->PIdataPresent = false; PIdataCurrentFrame->sceneOrientation = NULL; @@ -367,33 +437,6 @@ void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) } -/*-----------------------------------------------------------------------* - * ivasPayload_parseOrientationPIdata() - * - * Parse a single orientation in quaternions from the PI data. - *-----------------------------------------------------------------------*/ - -bool ivasPayload_parseOrientationPIdata( - char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ - IVAS_QUATERNION *q /* o : Parsed quaternion value */ -) -{ - q->w = ivasPayload_parseQuaternionComponent( &PIorientationData ); - q->x = ivasPayload_parseQuaternionComponent( &PIorientationData ); - q->y = ivasPayload_parseQuaternionComponent( &PIorientationData ); - q->z = ivasPayload_parseQuaternionComponent( &PIorientationData ); - - if ( q->w > 1.0f || q->w < -1.0f || - q->x > 1.0f || q->x < -1.0f || - q->y > 1.0f || q->y < -1.0f || - q->z > 1.0f || q->z < -1.0f ) - { - fprintf( stderr, "Error: invalid orientation PI data\n" ); - return false; - } - return true; -} - bool ivasPayload_unpackFrame( char *payload, /* i : RTP payload data */ uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ @@ -406,7 +449,7 @@ bool ivasPayload_unpackFrame( * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ unsigned char **frame, /* o : Data frame indicated by frameIndex */ uint16_t *frameSizeInBits, /* o : Data frame size in bits */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ + PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ) { bool someEvsIvasModeBit, someFrameFollowing, someIvasIndicatorBit; @@ -417,6 +460,8 @@ bool ivasPayload_unpackFrame( fullPayloadSizeBytes = payloadSizeBytes; PIdataPayload = payload; someFrameFollowing = true; + PI_DATA_CURRENT_FRAME PIdataCurrentFrame; + resetPIdataCurrentFrame( &PIdataCurrentFrame ); if ( payloadSizeBytes < 1 ) { fprintf( stderr, "Error: payload too small to parse ToC\n" ); @@ -425,7 +470,7 @@ bool ivasPayload_unpackFrame( /* parse CMR/E-bytes */ if ( *payload & E_BYTE ) // 1xxx xxxx { - PIdataCurrentFrame->PIdataPresent = false; + PIdataCurrentFrame.PIdataPresent = false; while ( 1 ) { if ( ( *payload & 0xF0 ) == IVAS_E_CMR ) // 1111 xxxx @@ -487,7 +532,7 @@ bool ivasPayload_unpackFrame( else if ( ( *payload & 0xE0 ) == IVAS_E_PI_INDICATION ) // 110x xxxx { /* IVAS PI presence */ - PIdataCurrentFrame->PIdataPresent = true; + PIdataCurrentFrame.PIdataPresent = true; } else if ( ( *payload & 0xE0 ) == IVAS_E_RESERVED ) // 111x xxxx { @@ -574,11 +619,11 @@ bool ivasPayload_unpackFrame( } /* parse PI data */ - if ( PIdataCurrentFrame->PIdataPresent ) + if ( PIdataCurrentFrame.PIdataPresent ) { PIdataPayloadSizeBytes = payloadSizeBytes; PIdataPayload += ( fullPayloadSizeBytes - PIdataPayloadSizeBytes ); - if ( !ivasPayload_parsePIdata( PIdataPayload, PIdataPayloadSizeBytes, frameIndex, PIdataCurrentFrame ) ) + if ( !ivasPayload_parsePIdata( PIdataPayload, PIdataPayloadSizeBytes, frameIndex, &PIdataCurrentFrame, PIdataDepackerState ) ) { fprintf( stderr, "Error while parsing PI data\n" ); return false; @@ -600,7 +645,6 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( { return IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR; } - resetPIdataCurrentFrame( &self->PIdataCurrentFrame ); self->PIdataDepackerState.sceneOrientationSaved = false; self->PIdataDepackerState.deviceOrientationSaved = false; return IVAS_RTPDUMP_DEPACKER_NO_ERROR; @@ -638,7 +682,7 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( if ( !ivasPayload_unpackFrame( self->rtpPacket.data + self->rtpPacket.headerSize, self->rtpPacket.payloadSize, self->frameIndex, evsIvasModeBit, &self->frameFollowing, bitrateIndex, ivasIndicatorBit, - frame, frameSizeBits, &self->PIdataCurrentFrame ) ) + frame, frameSizeBits, &self->PIdataDepackerState ) ) { return IVAS_RTPDUMP_DEPACKER_PAYLOAD_ERROR; } diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index 9d8bad958f..d1ec02d200 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -190,7 +190,6 @@ typedef struct uint32_t timeoffset_ms; uint16_t frameIndex; bool frameFollowing; - PI_DATA_CURRENT_FRAME PIdataCurrentFrame; PI_DATA_DEPACKER_STATE PIdataDepackerState; } IVAS_RTPDUMP_DEPACKER; @@ -238,7 +237,7 @@ bool ivasPayload_unpackFrame( * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ unsigned char **frame, /* o : Data frame indicated by frameIndex */ uint16_t *frameSizeInBits, /* o : Data frame size in bits */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data for frame indicated by frameIndex */ + PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ); -- GitLab From a2e78779843651bbd9df3c30732863da265330f2 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Fri, 13 Jun 2025 15:58:40 +0300 Subject: [PATCH 21/33] Clang format --- lib_dec/lib_dec.c | 6 +++--- lib_util/ivas_rtp_payload.c | 36 ++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index d3ada6dd9c..7bf5401729 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3729,9 +3729,9 @@ ivas_error IVAS_DEC_Flush( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_feedSinglePIorientation( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const 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 */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const 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; diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index e9d65ea0b1..951c9a9a0c 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -304,9 +304,9 @@ static bool ivasPayload_parseOrientationPIdata( *---------------------------------------------------------------------*/ static bool ivasPayload_parseSinglePIorientation( - char *orientation, /* i : input PI orientation */ - bool *isOrientationSaved, /* o : flag to indicate if an orientation for this PI type was previously saved */ - IVAS_QUATERNION *savedOrientation /* o : saved orientation value for this PI type */ + char *orientation, /* i : input PI orientation */ + bool *isOrientationSaved, /* o : flag to indicate if an orientation for this PI type was previously saved */ + IVAS_QUATERNION *savedOrientation /* o : saved orientation value for this PI type */ ) { if ( orientation ) @@ -330,10 +330,10 @@ static bool ivasPayload_parseSinglePIorientation( *-----------------------------------------------------------------------*/ static bool ivasPayload_parsePIdata( - char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ - uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ - uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame,/* o : PI data handle for the current audio frame */ + char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ + uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ + uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ + PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* o : PI data handle for the current audio frame */ PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ) { @@ -438,17 +438,17 @@ static void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) bool ivasPayload_unpackFrame( - char *payload, /* i : RTP payload data */ - uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ - uint16_t frameIndex, /* i : Index for the data frame in the payload */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeInBits, /* o : Data frame size in bits */ + char *payload, /* i : RTP payload data */ + uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ + uint16_t frameIndex, /* i : Index for the data frame in the payload */ + bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ + bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + unsigned char **frame, /* o : Data frame indicated by frameIndex */ + uint16_t *frameSizeInBits, /* o : Data frame size in bits */ PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ) { -- GitLab From c0bf68fbe73762197f98ce62a5045c98f700b256 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 18 Jun 2025 16:20:30 +0300 Subject: [PATCH 22/33] Fix Q-bit parsing, add good frame indication, remove unused evs payload parsing functions --- apps/decoder.c | 24 +++++++++++++----------- lib_dec/jbm_jb4sb.h | 5 +++++ lib_dec/lib_dec.c | 12 ++++++++++++ lib_dec/lib_dec.h | 6 +++++- lib_util/evs_rtp_payload.c | 27 ++++++++++++++++++++++++--- lib_util/evs_rtp_payload.h | 7 +++++-- lib_util/ivas_rtp_payload.c | 11 ++++++++--- lib_util/ivas_rtp_payload.h | 8 +++++--- 8 files changed, 77 insertions(+), 23 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index cb2e08233f..213b77985a 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -2895,7 +2895,8 @@ static ivas_error printBitstreamInfoVoip( #ifdef IVAS_RTPDUMP bool evsIvasModeBit; uint16_t bitrateIndex; - bool ivasIndicatorOrQBit; + bool ivasIndicatorBit; + bool isGoodFrame; #else bool isAMRWB_IOmode; uint16_t frameTypeIndex; @@ -2944,7 +2945,7 @@ static ivas_error printBitstreamInfoVoip( { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSizeBits, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); #ifdef IVAS_RTPDUMP - ivasIndicatorOrQBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ + isGoodFrame = 1; /* good frame for INPUT_FORMAT_G192 */ #else qBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ #endif @@ -2953,7 +2954,7 @@ static ivas_error printBitstreamInfoVoip( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, &auPtr, (uint16_t *) &auSizeBits ); + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorBit, &isGoodFrame, &auPtr, (uint16_t *) &auSizeBits ); #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSizeBits ); #endif @@ -2967,7 +2968,7 @@ static ivas_error printBitstreamInfoVoip( goto cleanup; } #ifdef IVAS_RTPDUMP - } while ( !ivasIndicatorOrQBit || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); + } while ( !isGoodFrame || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); #else } while ( !qBit || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); #endif @@ -3066,7 +3067,8 @@ static ivas_error decodeVoIP( #ifdef IVAS_RTPDUMP bool evsIvasModeBit; uint16_t bitrateIndex; - bool ivasIndicatorOrQBit; + bool ivasIndicatorBit; + bool isGoodFrame; #else bool isAMRWB_IOmode; uint16_t frameTypeIndex; @@ -3177,7 +3179,7 @@ static ivas_error decodeVoIP( { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSize, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); #ifdef IVAS_RTPDUMP - ivasIndicatorOrQBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ + isGoodFrame = 1; /* good frame for INPUT_FORMAT_G192 */ #else qBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ #endif @@ -3186,7 +3188,7 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, &auPtr, (uint16_t *) &auSize ); + rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorBit, &isGoodFrame, &auPtr, (uint16_t *) &auSize ); #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSize ); #endif @@ -3351,7 +3353,7 @@ static ivas_error decodeVoIP( { /* feed the previous read packet into the receiver now */ #ifdef IVAS_RTPDUMP - error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, ivasIndicatorOrQBit ); + error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, isGoodFrame ); #else error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, qBit ); #endif @@ -3368,7 +3370,7 @@ static ivas_error decodeVoIP( error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSize, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); #ifdef IVAS_RTPDUMP - ivasIndicatorOrQBit = 1; /* good q_bit for VOIP_G192_RTP */ + isGoodFrame = 1; /* good frame for VOIP_G192_RTP */ #else qBit = 1; /* good q_bit for VOIP_G192_RTP */ #endif @@ -3379,8 +3381,8 @@ static ivas_error decodeVoIP( #ifdef IVAS_RTPDUMP rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, - &evsIvasModeBit, &bitrateIndex, &ivasIndicatorOrQBit, - &auPtr, (uint16_t *) &auSize ); + &evsIvasModeBit, &bitrateIndex, &ivasIndicatorBit, + &isGoodFrame, &auPtr, (uint16_t *) &auSize ); /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; diff --git a/lib_dec/jbm_jb4sb.h b/lib_dec/jbm_jb4sb.h index 8155d66ae9..2ef48dbfb3 100644 --- a/lib_dec/jbm_jb4sb.h +++ b/lib_dec/jbm_jb4sb.h @@ -63,8 +63,13 @@ struct JB4_DATAUNIT uint32_t rcvTime; /** true, if the data unit contains only silence */ bool silenceIndicator; +#ifdef IVAS_RTPDUMP + /** good frame indicator (Q bit for AMR-WB IO, otherwise set to true) */ + Word16 isGoodFrame; +#else /** Q bit for AMR-WB IO */ Word16 qBit; +#endif /** the binary encoded access unit */ uint8_t *data; diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 7bf5401729..91959047ce 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3232,7 +3232,11 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( const uint16_t rtpSequenceNumber, /* i : RTP sequence number (16 bits) */ const uint32_t rtpTimeStamp, /* i : RTP timestamp (32 bits) */ const uint32_t rcvTime_ms, /* i : receive time of the RTP packet in milliseconds */ +#ifdef IVAS_RTPDUMP + const bool isGoodFrame /* i : Good frame indicator (Q bit for AMR-WB IO, otherwise set to true) */ +#else const bool qBit /* i : Q bit for AMR-WB IO */ +#endif ) { JB4_DATAUNIT_HANDLE dataUnit; @@ -3274,7 +3278,11 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( dataUnit->timeStamp = rtpTimeStamp; dataUnit->partial_frame = 0; dataUnit->partialCopyOffset = partialCopyOffset; +#ifdef IVAS_RTPDUMP + dataUnit->isGoodFrame = isGoodFrame; +#else dataUnit->qBit = qBit; +#endif /* add the frame to the JBM */ result = JB4_PushDataUnit( hIvasDec->hVoIP->hJBM, dataUnit, rcvTime_ms ); @@ -3297,7 +3305,11 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( dataUnit->timeStamp = rtpTimeStamp - partialCopyOffset * dataUnit->duration; dataUnit->partial_frame = 1; dataUnit->partialCopyOffset = partialCopyOffset; +#ifdef IVAS_RTPDUMP + dataUnit->isGoodFrame = isGoodFrame; +#else dataUnit->qBit = qBit; +#endif /* add the frame to the JBM */ result = JB4_PushDataUnit( hIvasDec->hVoIP->hJBM, dataUnit, rcvTime_ms ); diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index f20d6a9eb2..40a5403373 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -285,7 +285,11 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( const uint16_t rtpSequenceNumber, /* i : RTP sequence number (16 bits) */ const uint32_t rtpTimeStamp, /* i : RTP timestamp (32 bits) */ const uint32_t rcvTime_ms, /* i : receive time of the RTP packet in milliseconds */ - const bool qBit /* i : Q bit for AMR-WB IO */ +#ifdef IVAS_RTPDUMP + const bool isGoodFrame /* i : Good frame indicator (Q bit for AMR-WB IO, otherwise set to true) */ +#else +const bool qBit /* i : Q bit for AMR-WB IO */ +#endif ); ivas_error IVAS_DEC_VoIP_SetScale( diff --git a/lib_util/evs_rtp_payload.c b/lib_util/evs_rtp_payload.c index 89a3bdf51d..9c1f71be48 100644 --- a/lib_util/evs_rtp_payload.c +++ b/lib_util/evs_rtp_payload.c @@ -39,6 +39,7 @@ #include "evs_rtp_payload.h" #include "options.h" +#ifndef IVAS_RTPDUMP static void evsPayload_unpackFrame_compact_amrWbIo( const char *payload, uint16_t payloadSizeBits, uint16_t iProtectedSize, unsigned char **framePtr, uint16_t *frameSizeInBits ) { uint16_t i, iBit0; @@ -123,12 +124,30 @@ bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBy return evsHeaderFullPayload_unpackFrame( payload, payloadSizeBytes, frameIndex, isAMRWB_IOmode, frameFollowing, frameTypeIndex, qBit, framePtr, frameSizeInBits ); } +#endif #ifdef IVAS_RTPDUMP -void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ) +void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, bool *isGoodFrame, int32_t *bitrate ) +{ + bool evsModeBit = ( toc & 0x20 ) != 0; + *isAMRWB_IOmode = evsModeBit; + *frameFollowing = ( toc & 0x40 ) != 0; + *frameTypeIndex = toc & 0x0f; + if ( *isAMRWB_IOmode ) + { + *qBit = ( toc & 0x10 ) != 0; + *isGoodFrame = *qBit; + *bitrate = AMRWB_IOmode2rate[*frameTypeIndex]; + } + else + { + *qBit = false; /* Q-bit is unused in EVS Primary mode */ + *isGoodFrame = true; /* assume good frame for EVS Primary */ + *bitrate = PRIMARYmode2rate[*frameTypeIndex]; + } +} #else static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ) -#endif { bool evsModeBit = ( toc & 0x20 ) != 0; *isAMRWB_IOmode = evsModeBit; @@ -145,8 +164,9 @@ static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bo *bitrate = AMRWB_IOmode2rate[*frameTypeIndex]; } } +#endif - +#ifndef IVAS_RTPDUMP bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeInBits ) { bool someIsAMRWB_IOmode, someFrameFollowing = true, someQBit; @@ -278,3 +298,4 @@ void EVS_RTPDUMP_DEPACKER_close( EVS_RTPDUMP_DEPACKER *self ) } RTPDUMP_Close( &self->rtpdump, 0 ); } +#endif diff --git a/lib_util/evs_rtp_payload.h b/lib_util/evs_rtp_payload.h index 21bb10f3f3..aea968ddff 100644 --- a/lib_util/evs_rtp_payload.h +++ b/lib_util/evs_rtp_payload.h @@ -83,6 +83,7 @@ extern "C" 0 /* NO_DATA */ }; +#ifndef IVAS_RTPDUMP static const uint16_t evsPayloadProtectedSizes[22] = { 48, 56, @@ -159,13 +160,14 @@ extern "C" }; bool evsPayload_unpackFrame( bool hf_only, char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **framePtr, uint16_t *frameSizeBits ); - +#endif #ifdef IVAS_RTPDUMP - void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); + void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, bool *isGoodFrame, int32_t *bitrate ); #else static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, int32_t *bitrate ); #endif +#ifndef IVAS_RTPDUMP bool evsHeaderFullPayload_unpackFrame( char *payload, uint16_t payloadSizeBytes, uint16_t frameIndex, bool *isAMRWB_IOmode, bool *frameFollowing, uint16_t *frameTypeIndex, bool *qBit, unsigned char **frame, uint16_t *frameSizeBits ); typedef struct @@ -200,6 +202,7 @@ static void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bo uint16_t *frameSizeBits ); void EVS_RTPDUMP_DEPACKER_close( EVS_RTPDUMP_DEPACKER *self ); +#endif #ifdef __cplusplus } diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 951c9a9a0c..e99ff585d6 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -87,18 +87,20 @@ static void ivasPayload_parseToc( uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ int32_t *bitrate /* o : Bitrate of the data frame indicated in the ToC byte */ ) { bool isIvasToc = ( toc & 0x30 ) == 0x10; // xx01 xxxx if ( !isIvasToc ) { - evsHeaderFullPayload_parseToc( toc, evsIvasModeBit, frameFollowing, bitrateIndex, ivasIndicatorBit, bitrate ); + evsHeaderFullPayload_parseToc( toc, evsIvasModeBit, frameFollowing, bitrateIndex, ivasIndicatorBit, isGoodFrame, bitrate ); } else { *evsIvasModeBit = false; *ivasIndicatorBit = true; + *isGoodFrame = true; /* assume good frame for IVAS */ *frameFollowing = ( toc & 0x40 ) != 0; *bitrateIndex = toc & 0x0f; *bitrate = IVASmode2rate[*bitrateIndex]; @@ -447,12 +449,13 @@ bool ivasPayload_unpackFrame( uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ unsigned char **frame, /* o : Data frame indicated by frameIndex */ uint16_t *frameSizeInBits, /* o : Data frame size in bits */ PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ ) { - bool someEvsIvasModeBit, someFrameFollowing, someIvasIndicatorBit; + bool someEvsIvasModeBit, someFrameFollowing, someIvasIndicatorBit, someGoodFrameIndication; uint16_t someBitrateIndex, someFrameSizeInBits, fullPayloadSizeBytes, PIdataPayloadSizeBytes; int32_t bitrate; uint16_t iFrame; @@ -582,7 +585,7 @@ bool ivasPayload_unpackFrame( fprintf( stderr, "Error: expected ToC, found CMR/E-byte\n" ); return false; } - ivasPayload_parseToc( *payload, &someEvsIvasModeBit, &someFrameFollowing, &someBitrateIndex, &someIvasIndicatorBit, &bitrate ); + ivasPayload_parseToc( *payload, &someEvsIvasModeBit, &someFrameFollowing, &someBitrateIndex, &someIvasIndicatorBit, &someGoodFrameIndication, &bitrate ); if ( bitrate < 0 ) { fprintf( stderr, "Error: unexpected frameTypeIndex in ToC\n" ); @@ -609,6 +612,7 @@ bool ivasPayload_unpackFrame( *frameFollowing = someFrameFollowing; *bitrateIndex = someBitrateIndex; *ivasIndicatorBit = someIvasIndicatorBit; + *isGoodFrame = someGoodFrameIndication; *frameSizeInBits = someFrameSizeInBits; } if ( (int16_t) payloadSizeBytes < 0 ) @@ -660,6 +664,7 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ unsigned char **frame, /* o : Data frame indicated by frameIndex */ uint16_t *frameSizeBits /* o : Data frame size in bits */ ) diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index d1ec02d200..8529de51b7 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -230,11 +230,12 @@ bool ivasPayload_unpackFrame( uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ uint16_t frameIndex, /* i : Index for the data frame in the payload */ bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ + * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ unsigned char **frame, /* o : Data frame indicated by frameIndex */ uint16_t *frameSizeInBits, /* o : Data frame size in bits */ PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ @@ -268,7 +269,8 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ + bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ unsigned char **frame, /* o : Data frame indicated by frameIndex */ uint16_t *frameSizeBits /* o : Data frame size in bits */ ); -- GitLab From d98442d375f228d7fd8dc9d910c4333ce758c59c Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Wed, 18 Jun 2025 16:30:03 +0300 Subject: [PATCH 23/33] Clang format --- lib_dec/lib_dec.c | 4 ++-- lib_util/evs_rtp_payload.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 91959047ce..a476430478 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3233,9 +3233,9 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( const uint32_t rtpTimeStamp, /* i : RTP timestamp (32 bits) */ const uint32_t rcvTime_ms, /* i : receive time of the RTP packet in milliseconds */ #ifdef IVAS_RTPDUMP - const bool isGoodFrame /* i : Good frame indicator (Q bit for AMR-WB IO, otherwise set to true) */ + const bool isGoodFrame /* i : Good frame indicator (Q bit for AMR-WB IO, otherwise set to true) */ #else - const bool qBit /* i : Q bit for AMR-WB IO */ + const bool qBit /* i : Q bit for AMR-WB IO */ #endif ) { diff --git a/lib_util/evs_rtp_payload.c b/lib_util/evs_rtp_payload.c index 9c1f71be48..7fc0914892 100644 --- a/lib_util/evs_rtp_payload.c +++ b/lib_util/evs_rtp_payload.c @@ -141,7 +141,7 @@ void evsHeaderFullPayload_parseToc( uint8_t toc, bool *isAMRWB_IOmode, bool *fra } else { - *qBit = false; /* Q-bit is unused in EVS Primary mode */ + *qBit = false; /* Q-bit is unused in EVS Primary mode */ *isGoodFrame = true; /* assume good frame for EVS Primary */ *bitrate = PRIMARYmode2rate[*frameTypeIndex]; } -- GitLab From ba624cf8f74ed0b32a175bab627ef05a92dfdef0 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 30 Jun 2025 10:05:51 +0300 Subject: [PATCH 24/33] Add isGoodFrame parameter to function call --- lib_util/ivas_rtp_payload.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index e99ff585d6..d952450b52 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -687,7 +687,7 @@ IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( if ( !ivasPayload_unpackFrame( self->rtpPacket.data + self->rtpPacket.headerSize, self->rtpPacket.payloadSize, self->frameIndex, evsIvasModeBit, &self->frameFollowing, bitrateIndex, ivasIndicatorBit, - frame, frameSizeBits, &self->PIdataDepackerState ) ) + isGoodFrame, frame, frameSizeBits, &self->PIdataDepackerState ) ) { return IVAS_RTPDUMP_DEPACKER_PAYLOAD_ERROR; } @@ -811,6 +811,7 @@ void IVAS_RTPDUMP_PACKER_writeEbytes( } else { + // TODO(pajunen): add EVS CMRs here /* EVS CMR */ initialEbyteWritten = false; } -- GitLab From e568f54d6d6f05ec232fd6d3d5eb1b64fe8e7629 Mon Sep 17 00:00:00 2001 From: "Singh, Ripinder" Date: Thu, 3 Jul 2025 12:01:55 +1000 Subject: [PATCH 25/33] Introduce an ivas rtp api for pack/unpack * Add support for pack/unpack of ivas and evs frames * Support for pi data * Support for remote requests and frame info Signed-off-by: Singh, Ripinder --- lib_util/ivas_rtp_api.h | 470 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 lib_util/ivas_rtp_api.h diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h new file mode 100644 index 0000000000..7581b183a2 --- /dev/null +++ b/lib_util/ivas_rtp_api.h @@ -0,0 +1,470 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_API_H +#define IVAS_RTP_API_H + +#pragma once +#include +#include +#include "ivas_error.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * +-----------------------+---------------------+--------------------+----------+ + * | 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 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_CODECS; + + /* 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; + + /* 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 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: 28; /* reserved */ + } IVAS_RTP_SPLITRENDER; + + /* Remote Requests Types (Keys) */ + typedef enum + { + IVAS_REQUEST_CODEC, /* Request codec type, value of type IVAS_RTP_CODECS */ + 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_SUBFORMAT, /* Request subFormat, value of type IVAS_RTP_SUBFORMAT */ + IVAS_REQUEST_CA_MODE, /* Request channel awareness, value of type IVAS_RTP_CA_MODE */ + IVAS_REQUEST_SR_CONFIG, /* Request spit rendering, value of type IVAS_RTP_SPLITRENDER */ + 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_CODECS 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_SUBFORMAT subFormatType; /* sub-format type when request type is IVAS_REQUEST_SUBFORMAT */ + IVAS_RTP_CA_MODE caMode; /* channel aware mode when request type is IVAS_REQUEST_CA_MODE */ + IVAS_RTP_SPLITRENDER srConfig; /* split rendering config when request type is IVAS_REQUEST_SR_CONFIG */ + } 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 { + * uint32_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 + { + uint32_t size; /* size of this structure */ + uint32_t piDataType; /* IVAS PI data type */ + uint8_t data[1]; /* Variable length array (length calculated as size - 2*sizeof(uint32_t))*/ + } IVAS_PIDATA_GENERIC; + + /* Generic data buffer for sending/receiving coded frames / rtp packets + * data buffer is owned and initialized by caller, rtp api will ensure + * buffer write does not exceed allocSize. + */ + typedef struct + { + uint32_t allocSize; /* allocated size of the data buffer */ + uint32_t length; /* length of the initialized data in the buffer */ + uint8_t *buffer; /* pointer to the packet buffer */ + } IVAS_DATA_BUFFER; + + /**********************************************/ + /* 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. + * + * - piDataRepeatIntervalMs is used to define pi data repetition interval + * + */ + typedef struct + { + uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */ + uint32_t piDataRepeatIntervalMs; /* period for pi data repeat 0 = each frame, UINT_MAX=never */ + } 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 */ + ); + + /* 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_RemoteRequest( + 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_GetPacket to generate a rtp packet. + * + * It is possible to have variable frames per packet until maxFramesPerPacket frames + * if IVAS_RTP_PACK_GetPacket 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_CODECS codecId, /* i : Codec type (IVAS/EVS) */ + const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */ + ); + + /* 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 packet with policy defined in initial configuration during call to + * IVAS_RTP_PACK_GetPacket. + * + */ + 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 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 + * + */ + 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 */ + ); + + + /**********************************************/ + /* 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 */ + typedef struct + { + uint32_t maxNumberOfPacketInFifo; /* input packet fifo 's max length */ + } 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 packet. Caller must extract RTP header and header + * extension and feed Ivas Payload alongwith RTP Timestamp and sequence number. + * + * Example usage : - + * ================== + * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, payload, rtpTs, seqNum, + * &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, &frame, &frameTs, &seqNum); + * 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_GetNextPiData(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 timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */ + uint16_t sequenceNumbers, /* 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 extension header to unpacker to extract pi data + * Caller must feed rtp extension header alongwith RTP Timestamp and sequence number. + */ + ivas_error IVAS_RTP_UNPACK_HeaderExtension ( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + const IVAS_DATA_BUFFER *hdrExtnBuffer, /* i : received rtp header extension buffer */ + uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */ + uint16_t sequenceNumbers, /* i : sequence number from rtp header */ + uint32_t *numPiDataInPacket /* o : number of PI data received in rtp 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_PushPacket(), 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 packet alongwith rtp timestamp + * and sequence number + * + * If multiple frames per RTP packet are available, multiple calls to IVAS_RTP_UNPACK_PullFrame + * are needed. A frameBuffer.length == 0 indicates NO_DATA_FRAME + * + */ + ivas_error IVAS_RTP_UNPACK_PullFrame( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + IVAS_RTP_CODECS *receivedCodecId, /* i : Codec type (IVAS/EVS) */ + IVAS_DATA_BUFFER *frameBuffer, /* o : packed frame bitstream for IVAS/EVS */ + uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */ + uint16_t *sequenceNumbers /* o : sequence number from rtp header */ + ); + + /* 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_GetNextPiData( + IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ + IVAS_PIDATA_GENERIC *data, /* o : output data buffer for the Pi data */ + uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */ + ); + +#ifdef __cplusplus +} +#endif + +#endif /* IVAS_RTP_API_H */ -- GitLab From 1d0f51e9373271ef5ea3cc6feafe359ed39d8f8d Mon Sep 17 00:00:00 2001 From: "Singh, Ripinder" Date: Thu, 10 Jul 2025 14:45:38 +1000 Subject: [PATCH 26/33] Code review comments #1 Signed-off-by: Singh, Ripinder --- lib_com/options.h | 1 + lib_util/ivas_rtp_api.h | 104 +++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/lib_com/options.h b/lib_com/options.h index 941685105c..1f6e493889 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -155,6 +155,7 @@ /* ################## Start DEVELOPMENT switches ######################### */ +//#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 */ /* ################### Start BE switches ################################# */ diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 7581b183a2..5b008a04ca 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -34,8 +34,10 @@ #define IVAS_RTP_API_H #pragma once +#include #include #include +#include "options.h" #include "ivas_error.h" #ifdef __cplusplus @@ -80,7 +82,7 @@ extern "C" { IVAS_RTP_EVS, /* EVS */ IVAS_RTP_IVAS /* IVAS */ - } IVAS_RTP_CODECS; + } IVAS_RTP_CODEC; /* IVAS Bandwidth Requests */ typedef enum @@ -119,6 +121,7 @@ extern "C" IVAS_FMT_NO_REQ, /* No preference */ } IVAS_RTP_FORMAT; +#ifdef RTP_S4_251135_CR26253_0016_REV1 /* Coded Subformat Requests */ typedef enum { @@ -197,36 +200,41 @@ extern "C" uint32_t roll: 1; /* transmission metadata for correction around roll axis */ uint32_t reserved: 28; /* 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_CODECS */ + 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_SUBFORMAT, /* Request subFormat, value of type IVAS_RTP_SUBFORMAT */ 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_CODECS codec; /* codec id when request type is IVAS_REQUEST_CODEC */ + 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_SUBFORMAT subFormatType; /* sub-format type when request type is IVAS_REQUEST_SUBFORMAT */ 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 { - * uint32_t size; // sizeof(IVAS_PIDATA_SCENE_ORIENTATION) + * 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; @@ -234,20 +242,20 @@ extern "C" */ typedef struct { - uint32_t size; /* size of this structure */ + size_t size; /* size of this structure */ uint32_t piDataType; /* IVAS PI data type */ - uint8_t data[1]; /* Variable length array (length calculated as size - 2*sizeof(uint32_t))*/ + uint8_t data[1]; /* Variable length array */ } IVAS_PIDATA_GENERIC; - /* Generic data buffer for sending/receiving coded frames / rtp packets + /* 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 allocSize. + * buffer write does not exceed capacity. */ typedef struct { - uint32_t allocSize; /* allocated size of the data buffer */ - uint32_t length; /* length of the initialized data in the buffer */ - uint8_t *buffer; /* pointer to the packet buffer */ + 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; /**********************************************/ @@ -260,14 +268,10 @@ extern "C" /* Initial configuration for rtp packer * - maxFramesPerPacket is used to define if more than one frame should be packed * in the same rtp packet. - * - * - piDataRepeatIntervalMs is used to define pi data repetition interval - * */ typedef struct { uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */ - uint32_t piDataRepeatIntervalMs; /* period for pi data repeat 0 = each frame, UINT_MAX=never */ } IVAS_RTP_PACK_CONFIG; /* Open an instance of the RTP packer and return a handle to rtp packer on success @@ -290,7 +294,7 @@ extern "C" * in this API. E.g. Codec ID and supported bitrates/bandwidths * will not be performed at this level. */ - ivas_error IVAS_RTP_PACK_RemoteRequest( + 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 */ @@ -299,23 +303,23 @@ extern "C" /* 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_GetPacket to generate a rtp packet. + * 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_GetPacket is invoked asyncronously w.r.t this api. + * 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_CODECS codecId, /* i : Codec type (IVAS/EVS) */ + IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */ const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */ ); /* 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 packet with policy defined in initial configuration during call to - * IVAS_RTP_PACK_GetPacket. + * 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( @@ -323,15 +327,15 @@ extern "C" const IVAS_PIDATA_GENERIC *data /* i : pointer to the PIData stucture */ ); - /* Generate a rtp packet using available pushed frames + /* Generate a rtp payload using available pushed frames * - * Available remote requests, pi data and frames will be packed into a rtp packet. If no + * Available remote requests, pi data and frames will be packed into a rtp payload. If no * frame is pushed before call to this api, NO_DATA_FRAME will be generated * */ - ivas_error IVAS_RTP_PACK_GetPacket( + ivas_error IVAS_RTP_PACK_GetPayload( IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */ - IVAS_DATA_BUFFER *packet /* o : encapsulated rtp packet */ + IVAS_DATA_BUFFER *payload /* o : encapsulated rtp payload */ ); @@ -345,7 +349,7 @@ extern "C" /* Initial configuration for rtp unpacker */ typedef struct { - uint32_t maxNumberOfPacketInFifo; /* input packet fifo 's max length */ + uint32_t maxNumberOfPayloadsInFifo; /* input payload fifo 's max length */ } IVAS_RTP_UNPACK_CONFIG; /* Open an instance of the RTP unpacker and return a handle to rtp unpacker on success @@ -362,16 +366,20 @@ extern "C" ); /* Push a received rtp Ivas Payload to unpacker to extract number of frames, pi data and - * any remote request present in the packet. Caller must extract RTP header and header + * 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. + * * Example usage : - * ================== - * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, payload, rtpTs, seqNum, - * &nFrames, &nPiData, &reqBitmap); + * err = IVAS_RTP_UNPACK_PushPayload(hIvasUnpack, payload, rtpTs, seqNum, + * &nFrames, &nPiData, &reqBitmap); * if (err != IVAS_ERR_OK) { return err; } * - * // Read the frames in packet and feed to decoder + * // Read the frames in payload and feed to decoder * while (nFrames-- > 0) { * err = IVAS_RTP_UNPACK_PullFrame(hIvasUnpack, &recCodecId, &frame, &frameTs, &seqNum); * if (err != IVAS_ERR_OK) { return err; } @@ -381,7 +389,7 @@ extern "C" * * // Read PI Data * while (nPiData-- > 0) { - * err = IVAS_RTP_UNPACK_GetNextPiData(hIvasUnpack, &piData, &piTs); + * 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) @@ -405,31 +413,20 @@ extern "C" * } * */ - ivas_error IVAS_RTP_UNPACK_PushPacket( + ivas_error IVAS_RTP_UNPACK_PushPayload( IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ - const IVAS_DATA_BUFFER *packet, /* i : received rtp packet */ + const IVAS_DATA_BUFFER *payload, /* i : received rtp payload */ uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */ - uint16_t sequenceNumbers, /* i : sequence number 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 extension header to unpacker to extract pi data - * Caller must feed rtp extension header alongwith RTP Timestamp and sequence number. - */ - ivas_error IVAS_RTP_UNPACK_HeaderExtension ( - IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ - const IVAS_DATA_BUFFER *hdrExtnBuffer, /* i : received rtp header extension buffer */ - uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */ - uint16_t sequenceNumbers, /* i : sequence number from rtp header */ - uint32_t *numPiDataInPacket /* o : number of PI data received in rtp 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_PushPacket(), remoteRequestBitmap can be used + * On call to IVAS_RTP_UNPACK_PushPayload(), remoteRequestBitmap can be used * an indicator of new request available this frame * */ @@ -439,25 +436,24 @@ extern "C" IVAS_RTP_REQUEST_VALUE *value /* o : pointer of the requested type */ ); - /* Extract a single IVAS/EVS frame from provided rtp packet alongwith rtp timestamp + /* 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. A frameBuffer.length == 0 indicates NO_DATA_FRAME - * + * are needed. */ ivas_error IVAS_RTP_UNPACK_PullFrame( IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ - IVAS_RTP_CODECS *receivedCodecId, /* i : Codec type (IVAS/EVS) */ + IVAS_RTP_CODEC *receivedCodecId, /* i : Codec type (IVAS/EVS) */ IVAS_DATA_BUFFER *frameBuffer, /* o : packed frame bitstream for IVAS/EVS */ uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */ - uint16_t *sequenceNumbers /* o : sequence number from rtp header */ + uint16_t *sequenceNumber /* o : sequence number from rtp header */ ); /* 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_GetNextPiData( + 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 */ uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */ -- GitLab From 5aa659573e23e6308fdad18c5b719f93d3d2c9b9 Mon Sep 17 00:00:00 2001 From: "Singh, Ripinder" Date: Thu, 10 Jul 2025 15:26:39 +1000 Subject: [PATCH 27/33] First draft of the RTP Pack API * Introduce RTP Packet and Payload API implementation for Pack and Unpack * Introduce general handling of PI data and data type structures * Introduce the mutex encapsulation * Introduce a buffer pool manager * Example pack implementation in Encoder wrapper * Code Review comments Signed-off-by: Singh, Ripinder --- apps/decoder.c | 259 +++- apps/encoder.c | 174 ++- lib_com/ivas_error.h | 9 + lib_dec/lib_dec.c | 8 +- lib_dec/lib_dec.h | 6 +- lib_util/ivas_bpool.c | 154 +++ lib_util/ivas_bpool.h | 58 + lib_util/ivas_queue.c | 126 ++ lib_util/ivas_queue.h | 68 + lib_util/ivas_rtp_api.h | 251 +++- lib_util/ivas_rtp_internal.h | 136 ++ lib_util/ivas_rtp_payload.c | 2387 ++++++++++++++++++++++------------ lib_util/ivas_rtp_pi_data.c | 601 +++++++++ lib_util/ivas_rtp_pi_data.h | 441 +++++++ lib_util/ivas_rtp_rom.c | 64 + lib_util/mutex.h | 104 ++ 16 files changed, 3829 insertions(+), 1017 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_internal.h 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/ivas_rtp_rom.c create mode 100644 lib_util/mutex.h diff --git a/apps/decoder.c b/apps/decoder.c index 213b77985a..39c4f19824 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -39,7 +39,8 @@ #include "evs_rtp_payload.h" #include "ism_file_writer.h" #ifdef IVAS_RTPDUMP -#include "ivas_rtp_payload.h" +#include "ivas_rtp_api.h" +#include "ivas_rtp_pi_data.h" #endif #include "jbm_file_writer.h" #include "hrtf_file_reader.h" @@ -166,6 +167,170 @@ typedef struct } IVAS_DEC_HRTF_BINARY_WRAPPER; +#ifdef IVAS_RTPDUMP + +typedef struct +{ + PIDATA data; + uint32_t timestamp; +} PIDATA_TS; + +typedef struct +{ + uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * MAX_FRAMES_PER_RTP_PACKET]; + PIDATA_TS piData[IVAS_PI_MAX_ID * MAX_FRAMES_PER_RTP_PACKET]; + + FILE *f_rtpstream; + IVAS_RTP_CODEC codecId; + uint32_t nReadPiData; + uint32_t nProcPiData; + uint32_t numFramesInPacket; + uint32_t numPiDataInPacket; + uint32_t remoteRequestBitmap; + + IVAS_DATA_BUFFER rtpPacket; + IVAS_RTP_UNPACK_HANDLE hUnpack; + IVAS_RTP_UNPACK_CONFIG unpackCfg; + PI_DATA_DEPACKER_STATE piDataDepackerState; +} IVAS_RTP; + +static void IVAS_RTP_Term( IVAS_RTP *rtp ) +{ + if ( rtp->f_rtpstream ) + { + fclose( rtp->f_rtpstream ); + rtp->f_rtpstream = NULL; + } + IVAS_RTP_UNPACK_Close( &rtp->hUnpack ); +} + +static ivas_error IVAS_RTP_Init( IVAS_RTP *rtp, FILE *f_rtpstream ) +{ + ivas_error error = IVAS_ERR_OK; + + memset( rtp, 0, sizeof( IVAS_RTP ) ); + + error = IVAS_RTP_UNPACK_Open( &rtp->hUnpack, &rtp->unpackCfg ); + + rtp->f_rtpstream = f_rtpstream; + rtp->rtpPacket.buffer = rtp->packet; + rtp->rtpPacket.capacity = sizeof( rtp->packet ); + + return error; +} + +static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit ) +{ + ivas_error error = IVAS_ERR_OK; + IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; + uint32_t packetLen = 0u; + bool speechLostIndicated = false; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO srInfo; +#endif + + packedFrame.buffer = au; + packedFrame.capacity = ( IVAS_MAX_BITS_PER_FRAME / 8 ); + if ( rtp->numFramesInPacket == 0 ) + { + size_t nread = fread( &packetLen, sizeof( uint32_t ), 1, rtp->f_rtpstream ); /* Read Packet Length */ + if ( nread == 0 ) + { + return IVAS_ERR_END_OF_FILE; + } + if ( packetLen > sizeof( rtp->packet ) ) + { + fprintf( stderr, "RTP packet > buffer capacity %lu bytes\n", sizeof( rtp->packet ) ); + return IVAS_ERR_INVALID_OUTPUT_BUFFER_SIZE; + } + + nread = fread( rtp->packet, sizeof( uint8_t ), packetLen, rtp->f_rtpstream ); /* Read Packet */ + if ( nread == 0 ) + { + return IVAS_ERR_END_OF_FILE; + } + + rtp->rtpPacket.buffer = rtp->packet; + rtp->rtpPacket.length = packetLen; + + 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\n" ); + 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--; + } + } + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &rtp->codecId, &srInfo, &packedFrame, rtpTimeStamp, rtpSequenceNumber, &speechLostIndicated ); +#else + error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &rtp->codecId, &packedFrame, rtpTimeStamp, rtpSequenceNumber, &speechLostIndicated ); +#endif + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "failed to pull frame after unpack\n" ); + return error; + } + + *auSizeBits = (int16_t) ( packedFrame.length * 8 ); + *qBit = !speechLostIndicated; + rtp->numFramesInPacket--; + *nextPacketRcvTime_ms += 20; + + while ( rtp->nProcPiData < rtp->nReadPiData && + rtp->piData[rtp->nProcPiData].timestamp <= *rtpTimeStamp ) + { + PIDATA_TS *piData = &rtp->piData[rtp->nProcPiData++]; + if ( hIvasDec ) + { + uint32_t piDataType = ( (IVAS_PIDATA_GENERIC *) &piData->data )->piDataType; + switch ( piDataType ) + { + case IVAS_PI_SCENE_ORIENTATION: + { + error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, &piData->data.scene.orientation ); + } + break; + + case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: + { + error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, &piData->data.deviceCompensated.orientation ); + } + break; + + default: + { + fprintf( stderr, "Unhandled PI data of type : %d\n", piDataType ); + } + break; + } + if ( error != IVAS_ERR_OK ) + { + return error; + } + } + } + + return IVAS_ERR_OK; +} +#endif /* IVAS_RTPDUMP */ /*------------------------------------------------------------------------------------------* * Local functions prototypes @@ -2883,8 +3048,7 @@ static ivas_error printBitstreamInfoVoip( ivas_error error = IVAS_ERR_OK; FILE *f_rtpstream = NULL; #ifdef IVAS_RTPDUMP - IVAS_RTPDUMP_DEPACKER rtpdumpDepacker; - IVAS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_NO_ERROR; + IVAS_RTP ivasRtp; #else EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; @@ -2892,21 +3056,16 @@ static ivas_error printBitstreamInfoVoip( uint8_t au[( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3]; int16_t auSizeBits; uint8_t *auPtr = NULL; -#ifdef IVAS_RTPDUMP - bool evsIvasModeBit; - uint16_t bitrateIndex; - bool ivasIndicatorBit; - bool isGoodFrame; -#else bool isAMRWB_IOmode; uint16_t frameTypeIndex; bool qBit; -#endif uint32_t nextPacketRcvTime_ms = 0; uint16_t rtpSequenceNumber; uint32_t rtpTimeStamp; +#ifndef IVAS_RTPDUMP rtpdumpDepacker.rtpdump = NULL; +#endif switch ( arg.inputFormat ) { case IVAS_DEC_INPUT_FORMAT_RTPDUMP: @@ -2920,15 +3079,19 @@ static ivas_error printBitstreamInfoVoip( } #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream ); + if ( ( error = IVAS_RTP_Init( &ivasRtp, f_rtpstream ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); + goto cleanup; + } #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream, arg.inputFormat == IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF ); -#endif if ( rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) { fprintf( stderr, "error in EVS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError ); goto cleanup; } +#endif break; case IVAS_DEC_INPUT_FORMAT_G192: auPtr = au; @@ -2944,17 +3107,13 @@ static ivas_error printBitstreamInfoVoip( if ( arg.inputFormat == IVAS_DEC_INPUT_FORMAT_G192 ) { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSizeBits, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); -#ifdef IVAS_RTPDUMP - isGoodFrame = 1; /* good frame for INPUT_FORMAT_G192 */ -#else qBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ -#endif } else { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorBit, &isGoodFrame, &auPtr, (uint16_t *) &auSizeBits ); + error = readNextFrame( &ivasRtp, NULL, auPtr, &auSizeBits, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSizeBits ); #endif @@ -2967,11 +3126,7 @@ static ivas_error printBitstreamInfoVoip( fprintf( stderr, "failed to read first RTP packet\n" ); goto cleanup; } -#ifdef IVAS_RTPDUMP - } while ( !isGoodFrame || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); -#else } while ( !qBit || auSizeBits < MIN_NUM_BITS_ACTIVE_FRAME || auSizeBits == NUM_BITS_SID_IVAS_5K2 ); -#endif BS_Reader_Rewind( hBsReader ); @@ -2986,7 +3141,7 @@ static ivas_error printBitstreamInfoVoip( cleanup: #ifdef IVAS_RTPDUMP - IVAS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); + IVAS_RTP_Term( &ivasRtp ); #else EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); #endif @@ -3057,23 +3212,17 @@ static ivas_error decodeVoIP( int16_t i; FILE *f_rtpstream = NULL; #ifdef IVAS_RTPDUMP - IVAS_RTPDUMP_DEPACKER rtpdumpDepacker; - IVAS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_NO_ERROR; + IVAS_RTP ivasRtp; #else EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; #endif uint8_t *auPtr = NULL; -#ifdef IVAS_RTPDUMP - bool evsIvasModeBit; - uint16_t bitrateIndex; - bool ivasIndicatorBit; - bool isGoodFrame; -#else +#ifndef IVAS_RTPDUMP bool isAMRWB_IOmode; uint16_t frameTypeIndex; - bool qBit; #endif + bool qBit; IVAS_DEC_BS_FORMAT bsFormat = IVAS_DEC_BS_UNKOWN; IsmFileWriter *ismWriters[IVAS_MAX_NUM_OBJECTS]; @@ -3110,7 +3259,9 @@ static ivas_error decodeVoIP( delayNumSamples_orig[0] = -1; +#ifndef IVAS_RTPDUMP rtpdumpDepacker.rtpdump = NULL; +#endif switch ( arg.inputFormat ) { case IVAS_DEC_INPUT_FORMAT_RTPDUMP: @@ -3128,10 +3279,9 @@ static ivas_error decodeVoIP( } #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream ); - if ( rtpdumpDepackerError != IVAS_RTPDUMP_DEPACKER_NO_ERROR ) + if ( ( error = IVAS_RTP_Init( &ivasRtp, f_rtpstream ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "error in IVAS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError ); + fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); goto cleanup; } #else @@ -3178,17 +3328,13 @@ static ivas_error decodeVoIP( if ( arg.inputFormat == IVAS_DEC_INPUT_FORMAT_G192 ) { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSize, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); -#ifdef IVAS_RTPDUMP - isGoodFrame = 1; /* good frame for INPUT_FORMAT_G192 */ -#else qBit = 1; /* good q_bit for INPUT_FORMAT_G192 */ -#endif } else { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &evsIvasModeBit, &bitrateIndex, &ivasIndicatorBit, &isGoodFrame, &auPtr, (uint16_t *) &auSize ); + error = readNextFrame( &ivasRtp, hIvasDec, 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 @@ -3197,7 +3343,7 @@ static ivas_error decodeVoIP( rtpTimeStamp = rtpTimeStamp / 16; } #ifdef IVAS_RTPDUMP - if ( error != IVAS_ERR_OK || rtpdumpDepackerError != IVAS_RTPDUMP_DEPACKER_NO_ERROR ) + if ( error != IVAS_ERR_OK ) #else if ( error != IVAS_ERR_OK || rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) #endif @@ -3352,11 +3498,7 @@ static ivas_error decodeVoIP( while ( nextPacketRcvTime_ms <= systemTime_ms ) { /* feed the previous read packet into the receiver now */ -#ifdef IVAS_RTPDUMP - error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, isGoodFrame ); -#else error = IVAS_DEC_VoIP_FeedFrame( hIvasDec, auPtr, auSize, rtpSequenceNumber, rtpTimeStamp, nextPacketRcvTime_ms, qBit ); -#endif if ( error != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_VoIP_FeedFrame: %s\n", IVAS_DEC_GetErrorMessage( error ) ); @@ -3369,30 +3511,16 @@ static ivas_error decodeVoIP( { error = BS_Reader_ReadVoipFrame_compact( hBsReader, au, &auSize, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms ); -#ifdef IVAS_RTPDUMP - isGoodFrame = 1; /* good frame for VOIP_G192_RTP */ -#else qBit = 1; /* good q_bit for VOIP_G192_RTP */ -#endif } else { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - rtpdumpDepackerError = IVAS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, - &nextPacketRcvTime_ms, - &evsIvasModeBit, &bitrateIndex, &ivasIndicatorBit, - &isGoodFrame, &auPtr, (uint16_t *) &auSize ); + error = readNextFrame( &ivasRtp, hIvasDec, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; - - /* feed PI data to decoder handle */ - error = IVAS_DEC_feedPIdata( hIvasDec, &rtpdumpDepacker.PIdataDepackerState ); - if ( error != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError in IVAS_DEC_feedPIdata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); - goto cleanup; - } #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, @@ -3403,7 +3531,7 @@ static ivas_error decodeVoIP( #endif } #ifdef IVAS_RTPDUMP - if ( error == IVAS_ERR_END_OF_FILE || rtpdumpDepackerError == IVAS_RTPDUMP_DEPACKER_EOF ) + if ( error == IVAS_ERR_END_OF_FILE ) #else if ( error == IVAS_ERR_END_OF_FILE || rtpdumpDepackerError == EVS_RTPDUMP_DEPACKER_EOF ) #endif @@ -3420,13 +3548,6 @@ static ivas_error decodeVoIP( fprintf( stderr, "\nError in BS_Reader_ReadVoipFrame_compact, error code: %d\n", error ); goto cleanup; } -#ifdef IVAS_RTPDUMP - else if ( rtpdumpDepackerError != IVAS_RTPDUMP_DEPACKER_NO_ERROR ) - { - fprintf( stderr, "\nError in IVAS_RTPDUMP_DEPACKER_readNextFrame, error code: %d\n", error ); - goto cleanup; - } -#endif } /* we are finished when all packets have been received and jitter buffer is empty */ @@ -3770,7 +3891,7 @@ static ivas_error decodeVoIP( cleanup: #ifdef IVAS_RTPDUMP - IVAS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); + IVAS_RTP_Term( &ivasRtp ); #else EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); #endif diff --git a/apps/encoder.c b/apps/encoder.c index fe444c4d11..861250a5a0 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -39,8 +39,8 @@ #include "jbm_file_reader.h" #include "masa_file_reader.h" #ifdef IVAS_RTPDUMP -#include "evs_rtp_payload.h" -#include "ivas_rtp_payload.h" +#include "ivas_rtp_api.h" +#include "ivas_rtp_pi_data.h" #include "rotation_file_reader.h" #endif #ifdef DEBUGGING @@ -48,7 +48,6 @@ #endif #include "wmc_auto.h" - #define WMC_TOOL_SKIP /*------------------------------------------------------------------------------------------* @@ -153,6 +152,7 @@ typedef struct bool ism_extended_metadata; #ifdef IVAS_RTPDUMP bool rtpdumpOutput; + uint32_t numFramesPerPacket; char *sceneOrientationTrajFileName; char *deviceOrientationTrajFileName; #endif @@ -222,8 +222,7 @@ int main( #ifdef IVAS_RTPDUMP FILE *f_rtpstream = NULL; - IVAS_RTPDUMP_PACKER *rtpdumpPacker = NULL; - IVAS_RTPDUMP_PACKER_ERROR rtpdumpPackerError = IVAS_RTPDUMP_PACKER_NO_ERROR; + IVAS_RTP_PACK_HANDLE hPack = NULL; #endif /*------------------------------------------------------------------------------------------* @@ -623,19 +622,38 @@ int main( if ( arg.rtpdumpOutput ) { + IVAS_RTP_PACK_CONFIG packCfg; + uint32_t SSRC = ( rand() & 0xFFFF ) | ( (uint32_t) rand() << 16 ); + + packCfg.maxFramesPerPacket = arg.numFramesPerPacket; + /* Open the output file for RTPDump writing */ f_rtpstream = fopen( arg.outputBitstreamFilename, "wb" ); - if ( f_rtpstream == NULL ) { fprintf( stderr, "could not open: %s\n", arg.outputBitstreamFilename ); goto cleanup; } - rtpdumpPackerError = IVAS_RTPDUMP_PACKER_open( &rtpdumpPacker, f_rtpstream ); - if ( rtpdumpPackerError != IVAS_RTPDUMP_PACKER_NO_ERROR ) + error = IVAS_RTP_PACK_Open( &hPack, &packCfg ); + if ( error != IVAS_ERR_OK ) { - fprintf( stderr, "error in IVAS_RTPDUMP_PACKER_open(): %d\n", rtpdumpPackerError ); + fprintf( stderr, "error in IVAS_RTP_PACK_Open(): %d\n", error ); + goto cleanup; + } + + + error = IVAS_RTP_PACK_UpdateHeader( + hPack, + SSRC, + 0, + NULL, + 0, + 0, + NULL ); + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_PACK_UpdateHeader(): %d\n", error ); goto cleanup; } } @@ -669,6 +687,7 @@ int main( int16_t numSamplesRead = 0; uint16_t bitStream[IVAS_MAX_BITS_PER_FRAME]; + uint16_t numBits = 0; #ifdef DEBUG_SBA #ifdef DEBUG_AGC @@ -710,7 +729,11 @@ int main( goto cleanup; } +#ifdef IVAS_RTPDUMP + if ( ( numSamplesRead == 0 ) && ( IVAS_RTP_PACK_GetNumFrames( hPack ) == 0 ) ) +#else if ( numSamplesRead == 0 ) +#endif { /* end of input data */ break; @@ -838,43 +861,111 @@ int main( } #ifdef IVAS_RTPDUMP - if ( rtpdumpPacker && rtpdumpPacker->rtpdump ) + if ( hPack ) { + uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; + uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * MAX_FRAMES_PER_RTP_PACKET]; + uint32_t n = numBits / 8, x = 0, numFramesInPayload = 0, packetLength = 0; + uint16_t *bitstrm = bitStream; + IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; + IVAS_DATA_BUFFER rtpPacket = { 0, 0, NULL }; + + packedFrame.capacity = sizeof( au ); + packedFrame.buffer = au; + rtpPacket.capacity = sizeof( packet ); + rtpPacket.buffer = packet; + + /* Pack Encoded Stream */ + while ( n ) + { + x = ( ( bitstrm[0] << 7 ) | ( bitstrm[1] << 6 ) | ( bitstrm[2] << 5 ) | ( bitstrm[3] << 4 ) | + ( bitstrm[4] << 3 ) | ( bitstrm[5] << 2 ) | ( bitstrm[6] << 1 ) | ( bitstrm[7] << 0 ) ); + packedFrame.buffer[packedFrame.length++] = (uint8_t) x; + bitstrm += 8; + n--; + } + + /* AMWWB-IO has non octet sized bitstream */ + if ( numBits & 0x7 ) + { + x = 0; + for ( n = 0; n < (uint32_t) ( numBits & 0x7 ); n++ ) + { + x |= (uint8_t) ( bitstrm[n] << ( 7 - n ) ); + } + packedFrame.buffer[packedFrame.length++] = (uint8_t) x; + } + + /* Push Encoded Stream to */ + if ( ( error = IVAS_RTP_PACK_PushFrame( hPack, + IVAS_isImmersiveFormat( hIvasEnc ) ? IVAS_RTP_IVAS : IVAS_RTP_EVS, +#ifdef RTP_S4_251135_CR26253_0016_REV1 + NULL, +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ + &packedFrame ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while pushing audio frame to RTP pack\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + /* scene orientation */ if ( sceneOrientationFileReader ) { - if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &rtpdumpPacker->piDataPacker.sceneOrientationQuat, NULL ) ) != IVAS_ERR_OK ) + IVAS_PIDATA_ORIENTATION sceneOrientation = { + .size = sizeof( IVAS_PIDATA_ORIENTATION ), + .piDataType = IVAS_PI_SCENE_ORIENTATION, + .orientation = { 0.0f, 0.0f, 0.0f, 0.0f } + }; + + if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &sceneOrientation.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; } - rtpdumpPacker->piDataPacker.sceneOrientationPresent = true; + + if ( ( error = IVAS_RTP_PACK_PushPiData( hPack, (const IVAS_PIDATA_GENERIC *) &sceneOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while pushing scene orientation\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } } /* device orientation */ if ( deviceOrientationFileReader ) { - if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &rtpdumpPacker->piDataPacker.deviceOrientationQuat, NULL ) ) != IVAS_ERR_OK ) + IVAS_PIDATA_ORIENTATION deviceOrientation = { + .size = sizeof( IVAS_PIDATA_ORIENTATION ), + .piDataType = IVAS_PI_DEVICE_ORIENTATION_COMPENSATED, + .orientation = { 0.0f, 0.0f, 0.0f, 0.0f } + }; + + if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &deviceOrientation.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; } - rtpdumpPacker->piDataPacker.deviceOrientationPresent = true; - } - /* PI presence */ - IVAS_RTPDUMP_PACKER_determinePIpresence( rtpdumpPacker ); + if ( ( error = IVAS_RTP_PACK_PushPiData( hPack, (const IVAS_PIDATA_GENERIC *) &deviceOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while pushing scene orientation\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + } - /* write rtpdump */ - rtpdumpPackerError = IVAS_RTPDUMP_PACKER_writeNextFrame( rtpdumpPacker, bitStream, numBits, - IVAS_isImmersiveFormat( hIvasEnc ), 0, false, NO_BANDWIDTH_REQUEST, NO_FORMAT_REQUEST ); - if ( rtpdumpPackerError != IVAS_RTPDUMP_PACKER_NO_ERROR ) + if ( ( numSamplesRead < pcmBufSize ) || IVAS_RTP_PACK_GetNumFrames( hPack ) == arg.numFramesPerPacket ) { - fprintf( stderr, "IVAS_RTPDUMP_PACKER_writeNextFrame() failed, error code: %d\n", rtpdumpPackerError ); - goto cleanup; - } + /* Generate RTP Packet */ + if ( ( error = IVAS_RTP_PACK_GetPacket( hPack, &rtpPacket, &numFramesInPayload ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while packing RTP Header\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } - IVAS_RTPDUMP_PACKER_resetPIdata( rtpdumpPacker ); + /* File Format = Packet Length (uint32_t) + Packet bytes */ + packetLength = (uint32_t) rtpPacket.length; + fwrite( &packetLength, sizeof( packetLength ), 1, f_rtpstream ); + fwrite( rtpPacket.buffer, sizeof( uint8_t ), packetLength, f_rtpstream ); + } } else { @@ -966,9 +1057,9 @@ cleanup: } #ifdef IVAS_RTPDUMP - if ( rtpdumpPacker ) + if ( hPack ) { - IVAS_RTPDUMP_PACKER_close( &rtpdumpPacker ); + IVAS_RTP_PACK_Close( &hPack ); } if ( sceneOrientationFileReader ) @@ -980,6 +1071,11 @@ cleanup: { RotationFileReader_close( &deviceOrientationFileReader ); } + + if ( f_rtpstream ) + { + fclose( f_rtpstream ); + } #endif IVAS_ENC_Close( &hIvasEnc ); @@ -1858,9 +1954,25 @@ static bool parseCmdlIVAS_enc( else if ( strcmp( argv_to_upper, "-RTPDUMP" ) == 0 ) { + i++; arg->rtpdumpOutput = true; - fprintf( stdout, "Output format: RTPDump\n" ); - ++i; + 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 > MAX_FRAMES_PER_RTP_PACKET ) + { + fprintf( stderr, "numFramesPerPacket(%d) exceeds max frames per packet (%d) \n", arg->numFramesPerPacket, MAX_FRAMES_PER_RTP_PACKET ); + arg->numFramesPerPacket = 1; + } + } + } + fprintf( stdout, "Output format: RTPDump using %d frames/packet \n", arg->numFramesPerPacket ); } /*-----------------------------------------------------------------* @@ -2133,10 +2245,10 @@ static void usage_enc( void ) 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, "-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. \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 diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index a2f893ed78..24b576d696 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -150,6 +150,15 @@ typedef enum IVAS_ERR_LC3PLUS_INVALID_BITRATE, IVAS_ERR_INVALID_SPLIT_REND_CONFIG, + /*----------------------------------------* + * rtp errors * + *----------------------------------------*/ + IVAS_ERR_UNDERFLOW = 0x7000, + IVAS_ERR_PI_DATA_WITH_NO_INPUT_FRAME, + IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, + IVAS_ERR_UNPACK_PI_DATA, + IVAS_ERR_RTP_UNSUPPORTED_FRAME, + /*----------------------------------------* * unknown error * *----------------------------------------*/ diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index a476430478..f9c9646c9f 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3742,7 +3742,7 @@ ivas_error IVAS_DEC_Flush( ivas_error IVAS_DEC_feedSinglePIorientation( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const bool *isOrientationSaved, /* i : flag to indicate if an orientation for this PI type was previously saved */ + 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 */ ) { @@ -3750,7 +3750,7 @@ ivas_error IVAS_DEC_feedSinglePIorientation( ivas_error error = IVAS_ERR_OK; IVAS_QUATERNION savedInvOrientation; - if ( *isOrientationSaved ) + if ( isOrientationSaved ) { if ( !hIvasDec->st_ivas->hExtOrientationData ) { @@ -3797,13 +3797,13 @@ ivas_error IVAS_DEC_feedPIdata( ivas_error error = IVAS_ERR_OK; /* scene orientation */ - if ( ( error = IVAS_DEC_feedSinglePIorientation( hIvasDec, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_feedSinglePIorientation( hIvasDec, PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) != IVAS_ERR_OK ) { return error; } /* device orientation */ - if ( ( error = IVAS_DEC_feedSinglePIorientation( hIvasDec, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_feedSinglePIorientation( hIvasDec, PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) != IVAS_ERR_OK ) { return error; } diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 40a5403373..2e98d9e0f1 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -335,9 +335,9 @@ ivas_error IVAS_DEC_Flush( #ifdef IVAS_RTPDUMP ivas_error IVAS_DEC_feedSinglePIorientation( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const 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 */ + 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 */ ); ivas_error IVAS_DEC_feedPIdata( diff --git a/lib_util/ivas_bpool.c b/lib_util/ivas_bpool.c new file mode 100644 index 0000000000..cea33509ff --- /dev/null +++ b/lib_util/ivas_bpool.c @@ -0,0 +1,154 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ +#include +#include +#include +#include "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 ) + { + 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_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 idx; + mtx_lock( &handle->lock ); + idx = handle->numFreeBuffers; + mtx_unlock( &handle->lock ); + return idx; +} diff --git a/lib_util/ivas_bpool.h b/lib_util/ivas_bpool.h new file mode 100644 index 0000000000..c4cd45a736 --- /dev/null +++ b/lib_util/ivas_bpool.h @@ -0,0 +1,58 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_BPOOL_H +#define IVAS_BPOOL_H + +#include +#include +#include "ivas_error.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 0000000000..db038938a5 --- /dev/null +++ b/lib_util/ivas_queue.c @@ -0,0 +1,126 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include "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 all free-up all allocated memory */ +void QUEUE_Destroy( QUEUE_HANDLE *pHandle ) +{ + if ( 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 ) +{ + return handle->front; +} + +/* returns the last element in the queue */ +NODE *QUEUE_Back( QUEUE_HANDLE handle ) +{ + return handle->back; +} + +/* return the number of elements in the queue */ +size_t QUEUE_Size( QUEUE_HANDLE handle ) +{ + return handle->size; +} diff --git a/lib_util/ivas_queue.h b/lib_util/ivas_queue.h new file mode 100644 index 0000000000..8a5d4d1017 --- /dev/null +++ b/lib_util/ivas_queue.h @@ -0,0 +1,68 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_QUEUE_H +#define IVAS_QUEUE_H + +#include +#include "ivas_error.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 index 5b008a04ca..6b8ebb470a 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -45,37 +45,46 @@ extern "C" { #endif -/* - * +-----------------------+---------------------+--------------------+----------+ - * | 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 - * + /* + * +-----------------------+---------------------+--------------------+----------+ + * | 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 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 IVAS_NOMINAL_RTP_BYTES_PER_FRAME ( ( IVAS_MAX_BITS_PER_FRAME + ( IVAS_MAX_BITS_PER_FRAME / 5 ) ) / 8 ) -#define NO_BITRATE_REQ ( 0u ) /* If no bitrate is requested from remote */ +#define NO_BITRATE_REQ ( 0u ) /* If no bitrate is requested from remote */ /* IVAS Codec Types */ typedef enum @@ -193,41 +202,44 @@ extern "C" } IVAS_RTP_SUBFORMAT; /* Split Rendering Requests */ - typedef struct { - 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: 28; /* reserved */ + 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 */ + 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_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 */ + 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 */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ } IVAS_RTP_REQUEST_VALUE; /* Template for pi data types, all defined pi data follow this template @@ -258,12 +270,27 @@ extern "C" 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 */ + 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 @@ -271,9 +298,20 @@ extern "C" */ typedef struct { - uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */ + uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */ } IVAS_RTP_PACK_CONFIG; + /* 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 */ + ); + /* 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 */ @@ -310,11 +348,19 @@ extern "C" * */ 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) */ + 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 @@ -334,10 +380,23 @@ extern "C" * */ 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 */ + 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 */ @@ -381,7 +440,7 @@ extern "C" * * // Read the frames in payload and feed to decoder * while (nFrames-- > 0) { - * err = IVAS_RTP_UNPACK_PullFrame(hIvasUnpack, &recCodecId, &frame, &frameTs, &seqNum); + * 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; } @@ -415,14 +474,69 @@ extern "C" */ 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 */ + 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. Caller must extract RTP header and header + * extension and feed Ivas Packet 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. + * + * Example usage : - + * ================== + * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, packet, rtpTs, seqNum, + * &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 * @@ -444,19 +558,24 @@ extern "C" */ ivas_error IVAS_RTP_UNPACK_PullFrame( IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */ - IVAS_RTP_CODEC *receivedCodecId, /* i : Codec type (IVAS/EVS) */ + 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 */ uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */ - uint16_t *sequenceNumber /* o : sequence number from rtp header */ + uint16_t *sequenceNumber, /* o : sequence number from rtp header */ + bool *speechLostIndicated /* o : Is current frame indicated as Lost */ ); /* 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 */ - uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */ + 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 */ ); #ifdef __cplusplus diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h new file mode 100644 index 0000000000..b74bdbe8d5 --- /dev/null +++ b/lib_util/ivas_rtp_internal.h @@ -0,0 +1,136 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef 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 ) + +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 = 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 index d952450b52..7bbc86171d 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -29,1068 +29,1767 @@ the United Nations Convention on Contracts on the International Sales of Goods. *******************************************************************************************************/ - -#include #include +#include #include -#include "evs_rtp_payload.h" -#include "ivas_rtp_payload.h" -#include "ivas_prot.h" -#include "prot.h" +#include +#include "common_api_types.h" #ifdef IVAS_RTPDUMP +#include "ivas_rtp_api.h" +#include "ivas_rtp_pi_data.h" +#include "ivas_rtp_internal.h" +#include "ivas_bpool.h" +#include "ivas_queue.h" +#include "ivas_error_utils.h" +#include "mutex.h" + +#define IVAS_MAX_FRAMES_IN_QUEUE ( 32 ) +#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 */ + +/* Heuristically defined max values for no of frames per packet and no of pi data per packet */ +#define MAX_SUPPORTED_PI_DATA_SIZE ( 32 ) /* Currently no PI data exceeds 32 bytes */ +#define MAX_SUPPORTED_IVAS_FRAMES_PER_PACKET ( 25u ) +#define MAX_SUPPORTED_PI_FRAMES_PER_PACKET ( 150u ) + +/* 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; -/*-----------------------------------------------------------------------* - * writeByteToRtp() - * - * Write a single byte (value) to RTP packet. - *-----------------------------------------------------------------------*/ - -static void writeByteToRtp( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - char value /* i : Value to be written to the RTP packet */ -) +static void initRequests( IVAS_RTP_REQUEST_VALUE *requests ) { - self->rtpPacket.data[self->writingIndex] = value; - ++self->writingIndex; - self->rtpPacket.payloadSize += 1; + 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 */ } - -/*-----------------------------------------------------------------------* - * determineBitrate() - * - * Determine bitrate based on the number of encoded bits. - *-----------------------------------------------------------------------*/ - -static void determineBitrate( - const int32_t numBits, /* i : Number of bits contained in the data frame */ - int32_t *frameBitrate /* o : Bitrate of the data frame */ -) +static void initPiDataFrame( PIDATA_FRAME *piDataFrm ) { - *frameBitrate = numBits * IVAS_NUM_FRAMES_PER_SEC; + /* 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; + +struct IVAS_RTP_PACK +{ + mtx_t lock; /* Lock to handle concurrent API invocation */ + RTP_HEADER header; + BPOOL_HANDLE nodePool; + IVAS_RTP_PACK_CONFIG initConfig; + IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX]; + QUEUE_HANDLE frameQ; /* frames queue */ +}; + +typedef struct +{ + IVAS_RTP_CODEC codecId; /* Coded frame type (IVAS/EVS) */ + uint32_t auNumBits; /* Actual frame size in bits */ + bool speechLostIndicated; /* Speech Lost indicated */ +#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; -/*-----------------------------------------------------------------------* - * ivasPayload_parseToc() - * - * Parse a single ToC byte for an IVAS payload. - *-----------------------------------------------------------------------*/ - -static void ivasPayload_parseToc( - uint8_t toc, /* i : ToC byte to be parsed */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ - int32_t *bitrate /* o : Bitrate of the data frame indicated in the ToC byte */ +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 lock; /* Lock to handle concurrent API invocation */ + RTP_HEADER header; + BPOOL_HANDLE nodePool; + 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, 40 +}; + + +/* 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 */ ) { - bool isIvasToc = ( toc & 0x30 ) == 0x10; // xx01 xxxx - if ( !isIvasToc ) - { - evsHeaderFullPayload_parseToc( toc, evsIvasModeBit, frameFollowing, bitrateIndex, ivasIndicatorBit, isGoodFrame, bitrate ); - } - else + RTP_HEADER *header = &hPack->header; + + if ( numCC > 15 ) { - *evsIvasModeBit = false; - *ivasIndicatorBit = true; - *isGoodFrame = true; /* assume good frame for IVAS */ - *frameFollowing = ( toc & 0x40 ) != 0; - *bitrateIndex = toc & 0x0f; - *bitrate = IVASmode2rate[*bitrateIndex]; + 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 ); -/*-----------------------------------------------------------------------* - * ivasPayload_parsePItype() - * - * Parse a single PI type and set the PIdataCurrentFrame handle accordingly. - *-----------------------------------------------------------------------*/ - -static void ivasPayload_parsePItype( - char *PIframeDataBeginning, /* i : Pointer to the beginning of the PI data section in the RTP packet */ - uint16_t PIframeSizeBytes, /* i : PI data frame size in bytes */ - uint16_t parsedPIframeSizeBytes, /* i : Size of previously parsed PI frame data section in bytes */ - uint16_t PIframeType, /* i : Type of the PI data frame */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ -) -{ - if ( PIframeType == PI_SCENE_ORIENTATION ) - { - PIdataCurrentFrame->sceneOrientation = PIframeDataBeginning + parsedPIframeSizeBytes; - } - else if ( PIframeType == PI_DEVICE_ORIENTATION_COMPENSATED ) - { - PIdataCurrentFrame->deviceOrientationCompensated = PIframeDataBeginning + parsedPIframeSizeBytes; - } - else if ( PIframeType == PI_DEVICE_ORIENTATION_UNCOMPENSATED ) - { - PIdataCurrentFrame->deviceOrientationUncompensated = PIframeDataBeginning + parsedPIframeSizeBytes; - } - else if ( PIframeType == PI_ACOUSTIC_ENVIRONMENT ) + if ( ( numExtensionBytes > 0 ) && ( extData != NULL ) ) { - if ( PIframeSizeBytes == PI_ACOUSTIC_ENVIRONMENT_ID_SIZE_BYTES ) - { - PIdataCurrentFrame->acousticEnvironmentId = PIframeDataBeginning + parsedPIframeSizeBytes; - } - else if ( PIframeSizeBytes == PI_ACOUSTIC_ENVIRONMENT_ONLY_LATE_REVERB_SIZE_BYTES ) - { - PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb = PIframeDataBeginning + parsedPIframeSizeBytes; - } - else if ( PIframeSizeBytes == PI_ACOUSTIC_ENVIRONMENT_LATE_REVERB_AND_EARLY_REFLECTIONS_SIZE_BYTES ) + header->extHeaderId = extHeaderId; + header->extData = realloc( header->extData, numExtensionBytes ); + if ( header->extData == NULL ) { - PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections = PIframeDataBeginning + parsedPIframeSizeBytes; + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" ); } - } - else if ( PIframeType == PI_NO_DATA ) - { - /* no data */ + memcpy( header->extData, extData, numExtensionBytes ); + header->extension = true; + header->numExtUnits = numExtensionBytes / sizeof( uint32_t ); } else { - /* reserved */ + header->numExtUnits = 0; + header->extension = false; } -} - - -/*-----------------------------------------------------------------------* - * ivasPayload_PIaddHeaderBytes() - * - * Add PI header section bytes to the PI data pointers for the current audio frame. - *-----------------------------------------------------------------------*/ -static void ivasPayload_PIaddHeaderBytes( - uint16_t PIheaderSizeBytes, /* i : Size of the PI header section in bytes */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame /* o : PI data handle for the current audio frame */ -) -{ - if ( PIdataCurrentFrame->sceneOrientation != NULL ) - { - PIdataCurrentFrame->sceneOrientation += PIheaderSizeBytes; - } - if ( PIdataCurrentFrame->deviceOrientationCompensated != NULL ) - { - PIdataCurrentFrame->deviceOrientationCompensated += PIheaderSizeBytes; - } - if ( PIdataCurrentFrame->deviceOrientationUncompensated != NULL ) - { - PIdataCurrentFrame->deviceOrientationUncompensated += PIheaderSizeBytes; - } - if ( PIdataCurrentFrame->acousticEnvironmentId != NULL ) - { - PIdataCurrentFrame->acousticEnvironmentId += PIheaderSizeBytes; - } - if ( PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb != NULL ) - { - PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb += PIheaderSizeBytes; - } - if ( PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections != NULL ) - { - PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections += PIheaderSizeBytes; - } + return IVAS_ERR_OK; } - -/*-----------------------------------------------------------------------* - * ivasPayload_convertFromQ15() - * - * Convert a Q15 encoded value to a float value. - *-----------------------------------------------------------------------*/ - -static float ivasPayload_convertFromQ15( uint16_t Q15Value ) +static void InitRtpHeader( + RTP_HEADER *header /* RTP header structure */ +) { - float temp; - temp = (float) ( Q15Value & 0x7FFF ) / 0x7FFF; - return ( Q15Value & 0x8000 ) ? -temp : temp; + time_t t; + memset( header, 0, sizeof( *header ) ); + srand( (uint32_t) time( &t ) ); + header->version = 2; + header->seqNumber = rand() & 0xFFFF; } - -/*-----------------------------------------------------------------------* - * ivasPayload_convertToQ15() - * - * Convert a float value into a Q15 encoded value. - *-----------------------------------------------------------------------*/ - -static uint16_t ivasPayload_convertToQ15( float value ) +static ivas_error PackRtpHeader( + RTP_HEADER *header, + IVAS_DATA_BUFFER *buf ) { - uint16_t temp; - temp = (uint16_t) ( fabsf( value ) * 0x7FFF ); - if ( value >= 0.0f ) + 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 ) { - temp = temp & 0x7FFF; + return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient output buffer for RTP header packing" ); } - else + + /* + +---+---+---+---+---+---+---+---+ + | 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 ) { - temp = temp | 0x8000; + /* 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--; } - return temp; -} + 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 ); -/*-----------------------------------------------------------------------* - * ivasPayload_convertOrientationToQ15() - * - * Convert a float quaternion into a Q15 encoded quaternion. - *-----------------------------------------------------------------------*/ + memcpy( &buf->buffer[nBytes], header->extData, header->numExtUnits * 4 ); + nBytes += header->numExtUnits; + } -static void ivasPayload_convertOrientationToQ15( - IVAS_QUATERNION orientation, /* i : Input orientation in quaternion to be converted to Q15 */ - IVAS_QUATERNION_Q15 *orientationQ15 /* o : Ouput orientation in Q15 quaternion */ -) -{ - orientationQ15->w = ivasPayload_convertToQ15( orientation.w ); - orientationQ15->x = ivasPayload_convertToQ15( orientation.x ); - orientationQ15->y = ivasPayload_convertToQ15( orientation.y ); - orientationQ15->z = ivasPayload_convertToQ15( orientation.z ); + buf->length = nBytes; + return IVAS_ERR_OK; } - -/*-----------------------------------------------------------------------* - * ivasPayload_parseQuaternionValue() - * - * Parse a single Q15 encoded quaternion component from the RTP packet and convert it to float. - *-----------------------------------------------------------------------*/ - -static float ivasPayload_parseQuaternionComponent( - char **PIorientationData /* i/o: Pointer to the PI data frame containing a single quaternion component */ +static void UpdateRtpHeader( + RTP_HEADER *header, /* RTP header structure */ + uint32_t timestampOffset /* Timestamp offset @ 16KHz clock for next frame */ ) { - uint16_t tempQ15value; - tempQ15value = ( uint16_t ) * *PIorientationData; - tempQ15value = (uint16_t) ( ( tempQ15value << 8 ) | ( uint16_t ) * ( *PIorientationData + 1 ) ); - *PIorientationData += 2; - return ivasPayload_convertFromQ15( tempQ15value ); + header->seqNumber++; + header->timestamp += timestampOffset; } - -/*-----------------------------------------------------------------------* - * ivasPayload_parseOrientationPIdata() - * - * Parse a single orientation in quaternions from the PI data. - *-----------------------------------------------------------------------*/ - -static bool ivasPayload_parseOrientationPIdata( - char *PIorientationData, /* i/o: Pointer to the PI data frame containing a single quaternion orientation */ - IVAS_QUATERNION *q /* o : Parsed quaternion value */ +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 */ ) { - q->w = ivasPayload_parseQuaternionComponent( &PIorientationData ); - q->x = ivasPayload_parseQuaternionComponent( &PIorientationData ); - q->y = ivasPayload_parseQuaternionComponent( &PIorientationData ); - q->z = ivasPayload_parseQuaternionComponent( &PIorientationData ); - - if ( q->w > 1.0f || q->w < -1.0f || - q->x > 1.0f || q->x < -1.0f || - q->y > 1.0f || q->y < -1.0f || - q->z > 1.0f || q->z < -1.0f ) + uint32_t n = 0, nByte = 0, expectedSize = 12; + uint8_t byte; + + if ( packet->length < expectedSize ) { - fprintf( stderr, "Error: invalid orientation PI data\n" ); - return false; + return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Insufficient input buffer for RTP header unpacking" ); } - return true; -} - -/*---------------------------------------------------------------------* - * ivasPayload_parseSinglePIorientation( ) - * - * Parse a single orientation from PI data. - * Save the parsed orientation value and use in processing in future frames, if no new PI orientation is received. - *---------------------------------------------------------------------*/ - -static bool ivasPayload_parseSinglePIorientation( - char *orientation, /* i : input PI orientation */ - bool *isOrientationSaved, /* o : flag to indicate if an orientation for this PI type was previously saved */ - IVAS_QUATERNION *savedOrientation /* o : saved orientation value for this PI type */ -) -{ - if ( orientation ) + /* + +---+---+---+---+---+---+---+---+ + | 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 ) { - /* read the orientation PI value */ - if ( !ivasPayload_parseOrientationPIdata( orientation, savedOrientation ) ) - { - fprintf( stderr, "Error: parsing PI orientation failed\n" ); - return false; - } - *isOrientationSaved = true; + return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "CC indicated but insufficient input buffer" ); } - return true; -} + /* 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++] ); + } -/*-----------------------------------------------------------------------* - * ivasPayload_parsePIdata() - * - * Parse PI data for the current audio frame. - *-----------------------------------------------------------------------*/ - -static bool ivasPayload_parsePIdata( - char *PIdataPayload, /* i : Pointer to the beginning of the PI data section in the RTP packet */ - uint16_t PIdataPayloadSizeBytes, /* i : Size of the PI data section in bytes */ - uint16_t frameIndex, /* i : Index to the current audio frame in the RTP packet */ - PI_DATA_CURRENT_FRAME *PIdataCurrentFrame, /* o : PI data handle for the current audio frame */ - PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ -) -{ - // TODO(pajunen): can this accidentally include zero padding bits? - - bool somePIframeFollowing; - char *PIframeDataBeginning; - uint16_t PIframeMarker, PIframeType, tempPIframeSizeBytes, PIframeSizeBytes, totalPIframeSizeBytes, totalPIheaderSizeBytes, count_audio; - PIframeDataBeginning = PIdataPayload; - somePIframeFollowing = true; - totalPIframeSizeBytes = 0; - totalPIheaderSizeBytes = 0; - count_audio = 0; - - while ( somePIframeFollowing ) + if ( header->extension ) { - if ( (int16_t) PIdataPayloadSizeBytes <= 0 ) + 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 ) { - fprintf( stderr, "Error: PI payload too small\n" ); - return false; + return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Extension Header indicated but insufficient input buffer" ); } - /* parse PI data header */ - somePIframeFollowing = ( *PIdataPayload & 0x80 ) != 0; - PIframeMarker = ( *PIdataPayload & 0x60 ) >> 5; - PIframeType = ( *PIdataPayload & 0x1F ); - ++PIdataPayload; - ++totalPIheaderSizeBytes; - --PIdataPayloadSizeBytes; - tempPIframeSizeBytes = ( *PIdataPayload & 0xFF ); - PIframeSizeBytes = tempPIframeSizeBytes; - while ( tempPIframeSizeBytes == 255 ) + header->extData = realloc( header->extData, header->numExtUnits * 4 ); + if ( header->extData == NULL ) { - ++PIdataPayload; - ++totalPIheaderSizeBytes; - --PIdataPayloadSizeBytes; - tempPIframeSizeBytes = ( *PIdataPayload & 0xFF ); - PIframeSizeBytes += tempPIframeSizeBytes; + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" ); } - ++PIdataPayload; - ++totalPIheaderSizeBytes; - --PIdataPayloadSizeBytes; - PIdataPayloadSizeBytes -= PIframeSizeBytes; + memcpy( header->extData, &packet->buffer[nByte], header->numExtUnits * 4 ); + nByte += header->numExtUnits * 4; + } - /* general PI data for all frames */ - if ( PIframeMarker == PM_GENERAL ) + *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 ) +{ + 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++ ) { - ivasPayload_parsePItype( PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); + 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; + } } - else + 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++ ) { - /* current frame */ - if ( ( PIframeMarker > 0 ) & ( count_audio == frameIndex ) ) + if ( evsFrameSizeInBits[n] == frameLengthBytes * 8 ) { - ivasPayload_parsePItype( PIframeDataBeginning, PIframeSizeBytes, totalPIframeSizeBytes, PIframeType, PIdataCurrentFrame ); + *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; } - - /* increase audio frame counter */ - if ( PIframeMarker == PM_LAST ) + } + /* 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 ) { - ++count_audio; + *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; } } - totalPIframeSizeBytes += PIframeSizeBytes; + return IVAS_ERR_INVALID_BITRATE; } - ivasPayload_PIaddHeaderBytes( totalPIheaderSizeBytes, PIdataCurrentFrame ); +} + +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; - /* scene orientation */ - if ( !ivasPayload_parseSinglePIorientation( PIdataCurrentFrame->sceneOrientation, &PIdataDepackerState->sceneOrientationSaved, &PIdataDepackerState->sceneOrientationQuat ) ) + if ( phPack == NULL ) { - fprintf( stderr, "Error: parsing scene orientation PI data failed.\n" ); - return false; + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - /* device orientation */ - if ( !ivasPayload_parseSinglePIorientation( PIdataCurrentFrame->deviceOrientationUncompensated, &PIdataDepackerState->deviceOrientationSaved, &PIdataDepackerState->deviceOrientationQuat ) ) + *phPack = NULL; + if ( ( hPack = (IVAS_RTP_PACK_HANDLE) calloc( 1, sizeof( struct IVAS_RTP_PACK ) ) ) == NULL ) { - fprintf( stderr, "Error: parsing device orientation PI data failed.\n" ); - return false; + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtppack handle" ); } - return true; -} + error = BPOOL_Create( &hPack->nodePool, sizeof( FRAME_NODE ), IVAS_MAX_FRAMES_IN_QUEUE ); + ERR_CHECK_RETURN( error ); + error = QUEUE_Create( &hPack->frameQ ); + ERR_CHECK_RETURN( error ); -/*-----------------------------------------------------------------------* - * resetPIdataCurrentFrame() - * - * Reset the PI data handle for the current audio frame. - *-----------------------------------------------------------------------*/ + mtx_init( &hPack->lock, 0 ); + hPack->initConfig = *config; + initRequests( hPack->requests ); + InitRtpHeader( &hPack->header ); + *phPack = hPack; + return IVAS_ERR_OK; +} -static void resetPIdataCurrentFrame( PI_DATA_CURRENT_FRAME *PIdataCurrentFrame ) +/* 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 */ +) { - PIdataCurrentFrame->PIdataPresent = false; - PIdataCurrentFrame->sceneOrientation = NULL; - PIdataCurrentFrame->deviceOrientationCompensated = NULL; - PIdataCurrentFrame->deviceOrientationUncompensated = NULL; - PIdataCurrentFrame->acousticEnvironmentId = NULL; - PIdataCurrentFrame->acousticEnvironmentOnlyLateReverb = NULL; - PIdataCurrentFrame->acousticEnvironmentLateReverbAndEarlyReflections = NULL; -} + IVAS_RTP_PACK_HANDLE hPack; + + /* Free all memory */ + if ( phPack == NULL || *phPack == NULL ) + { + return; + } + hPack = *phPack; + QUEUE_Destroy( &hPack->frameQ ); + mtx_destroy( &hPack->lock ); + BPOOL_Destroy( &hPack->nodePool ); + free ( hPack->header.extData ); + free( hPack ); + *phPack = NULL; +} -bool ivasPayload_unpackFrame( - char *payload, /* i : RTP payload data */ - uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ - uint16_t frameIndex, /* i : Index for the data frame in the payload */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeInBits, /* o : Data frame size in bits */ - PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ +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 */ ) { - bool someEvsIvasModeBit, someFrameFollowing, someIvasIndicatorBit, someGoodFrameIndication; - uint16_t someBitrateIndex, someFrameSizeInBits, fullPayloadSizeBytes, PIdataPayloadSizeBytes; - int32_t bitrate; - uint16_t iFrame; - char *PIdataPayload; - fullPayloadSizeBytes = payloadSizeBytes; - PIdataPayload = payload; - someFrameFollowing = true; - PI_DATA_CURRENT_FRAME PIdataCurrentFrame; - resetPIdataCurrentFrame( &PIdataCurrentFrame ); - if ( payloadSizeBytes < 1 ) + if ( reqType < 0 || reqType >= IVAS_REQUEST_MAX ) { - fprintf( stderr, "Error: payload too small to parse ToC\n" ); - return false; + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid request key provided" ); } - /* parse CMR/E-bytes */ - if ( *payload & E_BYTE ) // 1xxx xxxx + + /* Sanity on API */ + switch ( reqType ) { - PIdataCurrentFrame.PIdataPresent = false; - while ( 1 ) + case IVAS_REQUEST_CODEC: { - if ( ( *payload & 0xF0 ) == IVAS_E_CMR ) // 1111 xxxx - { - /* IVAS CMR/E-byte */ - while ( 1 ) - { - /* parse subsequent E-bytes */ - ++payload; - --payloadSizeBytes; - if ( ( *payload & 0xE0 ) == IVAS_E_BW_REQUEST ) // 100x xxxx - { - /* IVAS bandwidth request */ - if ( ( *payload & 0xFF ) == IVAS_BW_REQ_WB ) // 1000 0000 - { - /* Wideband request */ - } - else if ( ( *payload & 0xFF ) == IVAS_BW_REQ_SWB ) // 1000 0001 - { - /* Super-wideband request */ - } - else if ( ( *payload & 0xFF ) == IVAS_BW_REQ_FB ) // 1000 0010 - { - /* Fullband request */ - } - } - else if ( ( *payload & 0xE0 ) == IVAS_E_FMT_REQUEST ) // 101x xxxx - { - /* IVAS coded format request */ - if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_STEREO ) // 1010 0000 - { - /* Stereo request */ - } - else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_SBA ) // 1010 0001 - { - /* SBA request */ - } - else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_MASA ) // 1010 0010 - { - /* MASA request */ - } - else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_ISM ) // 1010 0011 - { - /* ISM request */ - } - else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_MC ) // 1010 0100 - { - /* MC request */ - } - else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_OMASA ) // 1010 0101 - { - /* OMASA request */ - } - else if ( ( *payload & 0xFF ) == IVAS_FMT_REQ_OSBA ) // 1010 0110 - { - /* OSBA request */ - } - } - else if ( ( *payload & 0xE0 ) == IVAS_E_PI_INDICATION ) // 110x xxxx - { - /* IVAS PI presence */ - PIdataCurrentFrame.PIdataPresent = true; - } - else if ( ( *payload & 0xE0 ) == IVAS_E_RESERVED ) // 111x xxxx - { - /* Reserved IVAS subsequent E-byte */ - } - else - { - break; - } - - if ( payloadSizeBytes < 1 ) - { - fprintf( stderr, "Error: payload too small to parse subsequent E-bytes\n" ); - return false; - } - } - break; - } - else + uint32_t codec = reqValue.codec; + if ( codec != IVAS_RTP_IVAS && codec != IVAS_RTP_EVS ) { - /* EVS CMR */ - ++payload; - --payloadSizeBytes; - if ( *payload & E_BYTE ) // 1xxx xxxx - { - continue; - } - else - { - break; - } + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported codec id provided" ); } } - } - - /* parse all ToC entries */ - *frame = (unsigned char *) payload; /* no need to copy frame bytes */ - for ( iFrame = 0; someFrameFollowing; ++iFrame ) - { - if ( (int16_t) payloadSizeBytes <= 0 ) + break; + case IVAS_REQUEST_BITRATE: { - fprintf( stderr, "Error: payload too small\n" ); - return false; + uint32_t bitrate = reqValue.bitrate; + if ( bitrate < 5900 || bitrate > 512000 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate provided" ); + } } - if ( *payload & E_BYTE ) // 1xxx xxxx + break; + case IVAS_REQUEST_BANDWIDTH: { - fprintf( stderr, "Error: expected ToC, found CMR/E-byte\n" ); - return false; + uint32_t bandwidth = reqValue.bandwidth; + if ( bandwidth > IVAS_BANDWIDTH_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bandwidth provided" ); + } } - ivasPayload_parseToc( *payload, &someEvsIvasModeBit, &someFrameFollowing, &someBitrateIndex, &someIvasIndicatorBit, &someGoodFrameIndication, &bitrate ); - if ( bitrate < 0 ) + break; + case IVAS_REQUEST_FORMAT: { - fprintf( stderr, "Error: unexpected frameTypeIndex in ToC\n" ); - return false; + uint32_t format = reqValue.formatType; + if ( format > IVAS_FMT_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported format provided" ); + } } - ++payload; - ++*frame; - someFrameSizeInBits = (uint16_t) ( bitrate / 50 ); - /* just keep/copy zero padding bits - * in case of AMRWB_IO_SID the STI bit and CMI bits following the SID_1k75 frame are also kept (A.2.2.1.3 of TS 26.445) */ - payloadSizeBytes -= 1 + ( someFrameSizeInBits + 7 ) / 8; - if ( iFrame < frameIndex ) + break; + case IVAS_REQUEST_CA_MODE: { - *frame += ( someFrameSizeInBits + 7 ) / 8; - if ( !someFrameFollowing ) + uint32_t caMode = reqValue.caMode; + if ( caMode > IVAS_RTP_CA_NO_REQ ) { - fprintf( stderr, "Error: expected ToC with F bit set\n" ); - return false; + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported channel aware mode provided" ); } } - else if ( iFrame == frameIndex ) + break; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + case IVAS_REQUEST_SUBFORMAT: { - *evsIvasModeBit = someEvsIvasModeBit; - *frameFollowing = someFrameFollowing; - *bitrateIndex = someBitrateIndex; - *ivasIndicatorBit = someIvasIndicatorBit; - *isGoodFrame = someGoodFrameIndication; - *frameSizeInBits = someFrameSizeInBits; + uint32_t subFormat = reqValue.subFormatType; + if ( subFormat > IVAS_SUBFMT_NO_REQ ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported subformat provided" ); + } } - if ( (int16_t) payloadSizeBytes < 0 ) + break; + case IVAS_REQUEST_SR_CONFIG: { - fprintf( stderr, "Error: payload too small for frame %u data\n", frameIndex ); - return false; + 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" ); } - /* parse PI data */ - if ( PIdataCurrentFrame.PIdataPresent ) - { - PIdataPayloadSizeBytes = payloadSizeBytes; - PIdataPayload += ( fullPayloadSizeBytes - PIdataPayloadSizeBytes ); - if ( !ivasPayload_parsePIdata( PIdataPayload, PIdataPayloadSizeBytes, frameIndex, &PIdataCurrentFrame, PIdataDepackerState ) ) - { - fprintf( stderr, "Error while parsing PI data\n" ); - return false; - } - } + hPack->requests[reqType] = reqValue; - return true; + return IVAS_ERR_OK; } -IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( - IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ - FILE *file /* i : Input file containing the rtpdump */ -) +static bool isAmrWBIOMode( uint32_t bitrate, uint32_t *idx ) { - RTPDUMP_ERROR rtpdumpError; - self->frameFollowing = false; - rtpdumpError = RTPDUMP_OpenWithFileToRead( &self->rtpdump, file ); - if ( rtpdumpError != RTPDUMP_NO_ERROR ) + size_t n; + *idx = 0; + for ( n = 0; n < sizeof( amrWBIOFrameSizeInBits ) / sizeof( amrWBIOFrameSizeInBits[0] ); n++ ) { - return IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR; + if ( bitrate == ( amrWBIOFrameSizeInBits[n] * IVAS_NUM_FRAMES_PER_SEC ) ) + { + *idx = n; + return true; + } } - self->PIdataDepackerState.sceneOrientationSaved = false; - self->PIdataDepackerState.deviceOrientationSaved = false; - return IVAS_RTPDUMP_DEPACKER_NO_ERROR; + return false; } -IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( - IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ - uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ - uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ - uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeBits /* o : Data frame size in bits */ -) +static uint32_t getBitrateIdx( const uint32_t *table, uint32_t tableLen, uint32_t bitrate ) { - /* read next RTP packet from rtpdump */ - if ( !self->frameFollowing ) + size_t n, idx = 0; + + for ( n = 0; n < tableLen; n++ ) { - RTPDUMP_ERROR rtpdumpError = RTPDUMP_ReadPacket( self->rtpdump, &self->rtpPacket, &self->timeoffset_ms ); - if ( rtpdumpError == RTPDUMP_READ_ENDOFFILE ) + if ( bitrate > ( table[n] * IVAS_NUM_FRAMES_PER_SEC ) ) { - return IVAS_RTPDUMP_DEPACKER_EOF; + idx = n; } - else if ( rtpdumpError != RTPDUMP_NO_ERROR ) + else { - return IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR; + return idx; } - self->frameIndex = 0; - } - /* unpack next frame from RTP packet */ - if ( !ivasPayload_unpackFrame( self->rtpPacket.data + self->rtpPacket.headerSize, - self->rtpPacket.payloadSize, self->frameIndex, - evsIvasModeBit, &self->frameFollowing, bitrateIndex, ivasIndicatorBit, - isGoodFrame, frame, frameSizeBits, &self->PIdataDepackerState ) ) - { - return IVAS_RTPDUMP_DEPACKER_PAYLOAD_ERROR; - } - - /* return frame */ - *rtpSequenceNumber = self->rtpPacket.sequenceNumber; - *rtpTimeStamp = self->rtpPacket.timeStamp + self->frameIndex * 16000 / 50; - *rcvTime_ms = self->timeoffset_ms + self->frameIndex * 20; - ++self->frameIndex; - return IVAS_RTPDUMP_DEPACKER_NO_ERROR; -} - -void IVAS_RTPDUMP_DEPACKER_close( - IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ -) -{ - if ( !self ) - { - return; } - RTPDUMP_Close( &self->rtpdump, 0 ); + return idx; } -IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( - IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ - FILE *file /* i : Output file for the rtpdump stream */ +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 */ ) { - IVAS_RTPDUMP_PACKER *self; - RTPDUMP_ERROR rtpdumpError; - IVAS_QUATERNION identity; - identity.w = 1.0f; - identity.x = 0.0f; - identity.y = 0.0f; - identity.z = 0.0f; - self = calloc( sizeof( IVAS_RTPDUMP_PACKER ), 1 ); - rtpdumpError = RTPDUMP_OpenWithFileToWrite( &self->rtpdump, file ); - if ( rtpdumpError != RTPDUMP_NO_ERROR ) + /* 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 ) { - return IVAS_RTPDUMP_PACKER_RTPDUMP_ERROR; - } - RTPDUMP_SetDefaultRtpPacketHeader( &self->rtpPacket ); - memset( self->rtpPacket.data, 0, sizeof( self->rtpPacket.data ) ); - self->piDataPacker.sceneOrientationQuat = identity; - self->piDataPacker.deviceOrientationQuat = identity; - self->piDataPacker.sceneOrientationPresent = false; - self->piDataPacker.deviceOrientationPresent = false; - self->piDataPresent = false; - *rtpdumpPacker = self; - return IVAS_RTPDUMP_PACKER_NO_ERROR; -} + /* If requesting EVS/AMRWB IO from farend, only Initial E-byte present */ + IVAS_RTP_CA_MODE caMode = hPack->requests[IVAS_REQUEST_CA_MODE].caMode; -void IVAS_RTPDUMP_PACKER_writeEbytes( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). - * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ -) -{ - UWord8 initialEbyte, subsequentEbyte; - bool initialEbyteWritten; - - /* determine E-bytes */ - initialEbyte = 0; - subsequentEbyte = 0; - initialEbyteWritten = false; - if ( requestImmersiveFormatBitrate ) - { - switch ( requestedBitrate ) + if ( caMode != IVAS_RTP_CA_NO_REQ ) { - case IVAS_13k2: - initialEbyte = IVAS_CMR_13k2; - break; - case IVAS_16k4: - initialEbyte = IVAS_CMR_16k4; - break; - case IVAS_24k4: - initialEbyte = IVAS_CMR_24k4; - break; - case IVAS_32k: - initialEbyte = IVAS_CMR_32k; - break; - case IVAS_48k: - initialEbyte = IVAS_CMR_48k; - break; - case IVAS_64k: - initialEbyte = IVAS_CMR_64k; - break; - case IVAS_80k: - initialEbyte = IVAS_CMR_80k; - break; - case IVAS_96k: - initialEbyte = IVAS_CMR_96k; - break; - case IVAS_128k: - initialEbyte = IVAS_CMR_128k; - break; - case IVAS_160k: - initialEbyte = IVAS_CMR_160k; - break; - case IVAS_192k: - initialEbyte = IVAS_CMR_192k; - break; - case IVAS_256k: - initialEbyte = IVAS_CMR_256k; - break; - case IVAS_384k: - initialEbyte = IVAS_CMR_384k; - break; - case IVAS_512k: - initialEbyte = IVAS_CMR_512k; - break; - default: - initialEbyte = IVAS_CMR_NO_REQ; - break; + 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; + } } - writeByteToRtp( self, (char) initialEbyte ); - initialEbyteWritten = true; } else { - // TODO(pajunen): add EVS CMRs here - /* EVS CMR */ - initialEbyteWritten = false; - } + /* 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 - if ( ivasBandwidthRequest != NO_BANDWIDTH_REQUEST ) - { - if ( !initialEbyteWritten ) + /* Initial E-Byte only sent if either bitrate requested or subsequent E-byte is requested */ + if ( !( ( bitrate > 0 ) || isBandwidthProvided || isFormatProvided || + isSubFormatProvided || isSRConfigProvided || piDataPresent ) ) { - initialEbyte = IVAS_CMR_NO_REQ; - writeByteToRtp( self, (char) initialEbyte ); - initialEbyteWritten = true; + return; } - switch ( ivasBandwidthRequest ) + if ( bitrate > 0 ) { - case WB_REQUEST: - subsequentEbyte = IVAS_BW_REQ_WB; - break; - case SWB_REQUEST: - subsequentEbyte = IVAS_BW_REQ_SWB; - break; - case FB_REQUEST: - subsequentEbyte = IVAS_BW_REQ_FB; - break; - default: - subsequentEbyte = IVAS_BW_NO_REQ; - break; + /* 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; + } } - writeByteToRtp( self, (char) subsequentEbyte ); - } - if ( ivasFormatRequest != NO_FORMAT_REQUEST ) - { - if ( !initialEbyteWritten ) + /* Subsequent E-bytes - Bandwidth Request */ + if ( isBandwidthProvided && nByte < maxNumEBytes ) { - initialEbyte = IVAS_CMR_NO_REQ; - writeByteToRtp( self, (char) initialEbyte ); - initialEbyteWritten = true; + uint8_t bw = ( bandwidth - IVAS_BANDWIDTH_WB ) & MASK_2BIT; + eByte[nByte++] = ( EBYTE_BANDWIDTH_REQUEST | bw ); } - switch ( ivasFormatRequest ) + /* Subsequent E-bytes - Coded Format Request */ + if ( ( isFormatProvided || isSubFormatProvided ) && nByte < maxNumEBytes ) { - case STEREO_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_STEREO; - break; - case SBA_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_SBA; - break; - case MASA_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_MASA; - break; - case ISM_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_ISM; - break; - case MC_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_MC; - break; - case OMASA_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_OMASA; - break; - case OSBA_REQUEST: - subsequentEbyte = IVAS_FMT_REQ_OSBA; - break; - default: - subsequentEbyte = IVAS_FMT_NO_REQ; - break; + 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 ); } - writeByteToRtp( self, (char) subsequentEbyte ); +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ } - if ( self->piDataPresent ) + /* Final E-byte is the PI Indicator E-Byte */ + if ( piDataPresent && ( nByte < maxNumEBytes ) ) { - if ( !initialEbyteWritten ) - { - initialEbyte = IVAS_CMR_NO_REQ; - writeByteToRtp( self, (char) initialEbyte ); - initialEbyteWritten = true; - } - subsequentEbyte = IVAS_PI_INDICATION; - writeByteToRtp( self, (char) subsequentEbyte ); + eByte[nByte++] = EBYTE_PI_INDICATOR; /* PI Indication */ } + + *nBytesWritten = nByte; } -void IVAS_RTPDUMP_PACKER_writeToc( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t frameBitrate, /* i : Bitrate of the written frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). - * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ - bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ + +#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 */ ) { - UWord8 H_bit, F_bit, EVS_IVAS_mode_bit, Q_bit, toc; - int16_t is_amr_wb; - - is_amr_wb = 0; - H_bit = 0; - F_bit = someFrameFollowing ? 1 : 0; - /* FRAME_NO_DATA frames are written as in TS26.445 */ - if ( isImmersiveFormat && frameBitrate != FRAME_NO_DATA ) + uint8_t bitIdx, codecId, digetic; + if ( bitrateKbps < 256000 || bitrateKbps > 512000 ) { - toc = (UWord8) ( rate2IVASmode( frameBitrate ) ); - EVS_IVAS_mode_bit = 0; - Q_bit = 1; + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate for SR" ); } - else - { - toc = (UWord8) ( rate2EVSmode( frameBitrate, &is_amr_wb ) ); - EVS_IVAS_mode_bit = (UWord8) is_amr_wb; - Q_bit = 0; - } - toc = ( H_bit << 7 ) | ( F_bit << 6 ) | ( EVS_IVAS_mode_bit << 5 ) | ( Q_bit << 4 ) | toc; - writeByteToRtp( self, (char) toc ); -} -IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ - int32_t numBits, /* i : Number of bits contained in the data frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ + 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 ivas_error addNewFrameNode( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + FRAME_NODE **newNode ) +{ + FRAME_NODE *node = NULL; + ivas_error error = BPOOL_GetBuffer( hPack->nodePool, (void **) &node ); + ERR_CHECK_RETURN( error ); + + node->auNumBits = 0; + node->tocNumBytes = 0; + node->next = NULL; + + initPiDataFrame( &node->piDataFrame ); + + /* Add to frames FiFo */ + QUEUE_Push( hPack->frameQ, (NODE *) node ); + + *newNode = node; + return IVAS_ERR_OK; +} + +/* Push a single IVAS/EVS frame to rtp packer + * + * If multiple frames per RTP Payload are desired, multiple frames must be explicitly + * pushed before a call to IVAS_RTP_PACK_GetPacket to generate a rtp packet. + * + * It is possible to have variable frames per packet until maxFramesPerPacket frames + * if IVAS_RTP_PACK_GetPacket is invoked asyncronously w.r.t this api. + * + */ +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; + FRAME_NODE *node = (FRAME_NODE *) QUEUE_Back( hPack->frameQ ); + + /* Check if a node was added due to Generic PI Data push */ + if ( ( node == NULL ) || ( node->tocNumBytes != 0 ) ) + { + error = addNewFrameNode( hPack, &node ); + ERR_CHECK_RETURN( error ); + } + + if ( frameBuffer == NULL || frameBuffer->length == 0 ) + { + /* Indicates a NO_DATA_FRAME in case of DTX mode */ + node->toc[0] = TOC_INDICATE_NO_DATA; + node->tocNumBytes = 1; + node->auNumBits = 0; + } + else + { + error = getBitrateFromCodecAndFrameSize( codecId, frameBuffer->length, &bitrate, &frameLengthInBits, &tocByte ); + ERR_CHECK_RETURN( error ); + + node->toc[0] = tocByte; + node->tocNumBytes = 1; + node->auNumBits = frameLengthInBits; + memcpy( node->au, frameBuffer->buffer, frameBuffer->length ); + +#ifdef RTP_S4_251135_CR26253_0016_REV1 + if ( srInfo != NULL && srInfo->valid ) + { + node->toc[0] = TOC_INDICATE_SR; + error = getSRToCByte( srInfo, bitrate, &node->toc[1] ); + ERR_CHECK_RETURN( error ); + node->tocNumBytes = 2; + } +#endif + } + + return IVAS_ERR_OK; +} + +uint32_t IVAS_RTP_PACK_GetNumFrames( + IVAS_RTP_PACK_HANDLE hPack /* i/o : IVAS rtp packer handle */ +) +{ + return QUEUE_Size( hPack->frameQ ); +} + +/* 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_PI_TYPE piDataType; + ivas_error error = IVAS_ERR_OK; + FRAME_NODE *node = (FRAME_NODE *) QUEUE_Back( hPack->frameQ ); + PIDATA_FRAME *piDataFrm = NULL; + uint8_t PM = 0; + + 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" ); + } + + /* No frame in Queue to associate PI Data, create one */ + if ( node == NULL ) + { + /* PI data received before any frame in queue is generic */ + PM = PI_HEADER_PM_GENERIC; + + /* Add a new node in frame queue, toc is still zero indicating frame is expected */ + error = addNewFrameNode( hPack, &node ); + ERR_CHECK_RETURN( error ); + } + + piDataFrm = &node->piDataFrame; + piDataType = data->piDataType; + + error = PI_PackData( data, &piDataFrm->piData[piDataType], PM ); + ERR_CHECK_RETURN( error ); + + /* 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--; + } + + return IVAS_ERR_OK; +} + +/* 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 + * + */ +ivas_error IVAS_RTP_PACK_GetPayload( + IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ + IVAS_DATA_BUFFER *packet, /* o : encapsulated rtp packet */ + 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 *head = (FRAME_NODE *) QUEUE_Front( hPack->frameQ ); + FRAME_NODE *node = NULL; + size_t nBytes = packet->length, numEBytes = 0; + + if ( packet == NULL ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Output data buffer is NULL" ); + } + + /* Calculate number of frames and PI data present */ + node = head; + for ( n = 0; n < hPack->initConfig.maxFramesPerPacket && ( NULL != node ); n++, node = node->next ) + { + numFrame++; + numPiDataPresent += node->piDataFrame.numPiDataAvailable; + } + *numFramesInPayload = numFrame; /* numFrames in Packet */ + + /* IVAS Payload starts with E-Bytes */ + packEBytes( hPack, ( numPiDataPresent > 0 ), packet->capacity, &packet->buffer[packet->length], &numEBytes ); + nBytes += numEBytes; - RTPDUMP_ERROR rtpdumpError; - int32_t i, k, frameBitrate; - char tempData; + /* ToC bytes (atleast 1 byte per frame, 2 if SR )*/ + node = head; + for ( n = 0; n < numFrame && ( NULL != node ); n++, node = node->next ) + { + uint8_t fBit = ( n != ( numFrame - 1 ) ) ? TOC_HEADER_FOLLOWS : 0; /* Next ToC present */ + if ( nBytes < packet->capacity ) + { + packet->buffer[nBytes++] = ( node->toc[0] | fBit ); + } + else + { + return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + } + + if ( node->tocNumBytes == 2 ) + { + if ( nBytes < packet->capacity ) + { + packet->buffer[nBytes++] = node->toc[1]; + } + else + { + return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + } + } + } + + /* Frame Data */ + node = head; + for ( n = 0; n < numFrame && ( NULL != node ); n++, node = node->next ) + { + size_t len = ( node->auNumBits + 7 ) >> 3; /* zero padded length in bytes */ + if ( nBytes + len < packet->capacity ) + { + memcpy( &packet->buffer[nBytes], node->au, len ); + } + else + { + return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + } + nBytes += len; + } - self->writingIndex = self->rtpPacket.headerSize; - self->rtpPacket.payloadSize = 0; - memset( self->rtpPacket.data, 0, sizeof( self->rtpPacket.data ) ); + packet->length = nBytes; /* update packet length before PI packing */ - determineBitrate( numBits, &frameBitrate ); + /* PI Data */ + if ( numPiDataPresent > 0 ) + { + bool skipPiData = false; + uint32_t numPiDataWritten = 0; - /* payload header */ - IVAS_RTPDUMP_PACKER_writeEbytes( self, requestedBitrate, requestImmersiveFormatBitrate, ivasBandwidthRequest, ivasFormatRequest ); - IVAS_RTPDUMP_PACKER_writeToc( self, frameBitrate, isImmersiveFormat, false ); + node = head; + for ( n = 0; n < numFrame && ( NULL != node ); n++, node = node->next ) + { + uint32_t piDataType = 0; + 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 < packet->capacity ) + { + memcpy( &packet->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 ) + { + packet->length = nBytes; /* update packet length after PI packing */ + } + } - /* frame data */ - for ( i = 0; i < numBits; i += 8 ) + /* Pop frames from Queue */ + for ( n = 0; n < numFrame; n++ ) { - tempData = 0; - for ( k = 0; k < 8; ++k ) + node = (FRAME_NODE *) QUEUE_Pop( hPack->frameQ ); + if ( node == NULL ) { - tempData = (char) ( ( tempData << 1 ) | (char) bitStream[i + k] ); + assert( 0 ); /* catastrophic error, implementation issue */ + break; } - writeByteToRtp( self, tempData ); + + error = BPOOL_FreeBuffer( hPack->nodePool, node ); + assert( error == IVAS_ERR_OK ); /* catastrophic error if this fails */ } - /* PI data */ - IVAS_RTPDUMP_PACKER_writePIdata( self ); + return IVAS_ERR_OK; +} + +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 ); - /* write packet */ - rtpdumpError = RTPDUMP_WritePacket( self->rtpdump, &self->rtpPacket, self->timeoffset_ms ); - if ( rtpdumpError != RTPDUMP_NO_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_RTPDUMP_PACKER_RTPDUMP_ERROR; + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - /* adjust packetizer values */ - self->rtpPacket.sequenceNumber += 1; - self->rtpPacket.timeStamp += 320; - self->timeoffset_ms += 20; + *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" ); + } + + error = BPOOL_Create( &hUnpack->nodePool, sizeof( UNPACK_NODE ), IVAS_MAX_FRAMES_IN_QUEUE ); + ERR_CHECK_RETURN( error ); + + error = BPOOL_Create( &hUnpack->piDataPool, sizeof( PIDATA_NODE ), IVAS_MAX_FRAMES_IN_QUEUE * IVAS_PI_MAX_ID ); + ERR_CHECK_RETURN( error ); + + error = QUEUE_Create( &hUnpack->frameQ ); + ERR_CHECK_RETURN( error ); - return IVAS_RTPDUMP_PACKER_NO_ERROR; + error = QUEUE_Create( &hUnpack->piDataQ ); + ERR_CHECK_RETURN( error ); + + hUnpack->initConfig = *config; + mtx_init( &hUnpack->lock, 0 ); + + initRequests( hUnpack->requests ); + + *phUnpack = hUnpack; + return IVAS_ERR_OK; } -void IVAS_RTPDUMP_PACKER_writePIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +/* 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 */ ) { - if ( !self->piDataPresent ) + IVAS_RTP_UNPACK_HANDLE hUnpack; + + /* Free all memory */ + if ( phUnpack == NULL || *phUnpack == NULL ) { return; } - UWord8 PIheaderByte; - IVAS_QUATERNION_Q15 sceneOrientationQ15, deviceOrientationQ15; - bool somePIfollowing = false; + hUnpack = *phUnpack; + mtx_destroy( &hUnpack->lock ); + QUEUE_Destroy( &hUnpack->frameQ ); + QUEUE_Destroy( &hUnpack->piDataQ ); + BPOOL_Destroy( &hUnpack->piDataPool ); + BPOOL_Destroy( &hUnpack->nodePool ); + 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 ) +{ + 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 */ + + *numFrames += 1; + memset( toc, 0, sizeof( *toc ) ); + if ( *numFrames == MAX_SUPPORTED_IVAS_FRAMES_PER_PACKET ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL, "No of frames in packet exceed max defined" ); + } + + if ( FT == TOC_INDICATE_ARMWB_Q || FT == TOC_INDICATE_AMRWB ) + { + toc->codecId = IVAS_RTP_EVS; + 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_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; +} - /* PI header section */ +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; - /* scene orientation */ - if ( self->piDataPacker.sceneOrientationPresent ) + while ( PF ) { - if ( self->piDataPacker.deviceOrientationPresent ) + uint8_t piHeader0, PM, piDataType, byte = 0; + uint32_t piSize = 0; + + if ( nBytes + 1 >= payload->length ) + { + return IVAS_ERROR( IVAS_ERR_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_UNDERFLOW, "Underflow during reading piSize" ); + } + } while ( byte == 255 ); + + if ( nBytes + piSize <= payload->length ) { - somePIfollowing = true; + 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 ); } - if ( somePIfollowing ) + else { - PIheaderByte = ( PF1 << 7 ) | ( PM_NOT_LAST << 5 ) | PI_SCENE_ORIENTATION; + return IVAS_ERROR( IVAS_ERR_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[MAX_SUPPORTED_IVAS_FRAMES_PER_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; + } + + 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 ); + 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->nodePool, (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 { - PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_SCENE_ORIENTATION; + return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow during expected frame bits" ); } - writeByteToRtp( self, (char) PIheaderByte ); - writeByteToRtp( self, PI_SCENE_ORIENTATION_SIZE_BYTES ); + + /* Add to frames FiFo */ + QUEUE_Push( hUnpack->frameQ, (NODE *) node ); } - /* device orientation */ - if ( self->piDataPacker.deviceOrientationPresent ) + if ( piDataIndicated ) { - PIheaderByte = ( PF0 << 7 ) | ( PM_LAST << 5 ) | PI_DEVICE_ORIENTATION_UNCOMPENSATED; - writeByteToRtp( self, (char) PIheaderByte ); - writeByteToRtp( self, PI_DEVICE_ORIENTATION_UNCOMPENSATED_SIZE_BYTES ); + 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; + } } - /* PI frame data section */ + if ( numFramesInPacket != NULL ) + { + *numFramesInPacket = numFrames; + } - if ( self->piDataPacker.sceneOrientationPresent ) + if ( numPiDataInPacket ) { - ivasPayload_convertOrientationToQ15( self->piDataPacker.sceneOrientationQuat, &sceneOrientationQ15 ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.w >> 8 ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.w & 0x00FF ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.x >> 8 ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.x & 0x00FF ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.y >> 8 ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.y & 0x00FF ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.z >> 8 ) ); - writeByteToRtp( self, (char) ( sceneOrientationQ15.z & 0x00FF ) ); + *numPiDataInPacket = numPiData; } - if ( self->piDataPacker.deviceOrientationPresent ) + if ( remoteRequestBitmap ) { - ivasPayload_convertOrientationToQ15( self->piDataPacker.deviceOrientationQuat, &deviceOrientationQ15 ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.w >> 8 ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.w & 0x00FF ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.x >> 8 ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.x & 0x00FF ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.y >> 8 ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.y & 0x00FF ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.z >> 8 ) ); - writeByteToRtp( self, (char) ( deviceOrientationQ15.z & 0x00FF ) ); + 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; } -void IVAS_RTPDUMP_PACKER_determinePIpresence( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +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 */ ) { - self->piDataPresent = false; - if ( self->piDataPacker.sceneOrientationPresent || - self->piDataPacker.deviceOrientationPresent ) + 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 ) { - self->piDataPresent = true; + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid request key provided" ); } + *value = hUnpack->requests[type]; + return IVAS_ERR_OK; } -void IVAS_RTPDUMP_PACKER_resetPIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ +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 */ + 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 */ ) { - IVAS_QUATERNION identity; - identity.w = 1.0f; - identity.x = 0.0f; - identity.y = 0.0f; - identity.z = 0.0f; - - self->piDataPresent = false; - self->piDataPacker.sceneOrientationQuat = identity; - self->piDataPacker.deviceOrientationQuat = identity; - self->piDataPacker.sceneOrientationPresent = false; - self->piDataPacker.deviceOrientationPresent = false; + 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_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 ( 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; + } + + return BPOOL_FreeBuffer( hUnpack->nodePool, node ); } -void IVAS_RTPDUMP_PACKER_close( - IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ +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 */ ) { - if ( !self || !( *self ) ) + 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; + return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "No more pi data in unpack fifo" ); } - RTPDUMP_Close( &( *self )->rtpdump, 0 ); - free( *self ); - *self = NULL; + + pi = (IVAS_PIDATA_GENERIC *) &node->data; + + if ( data != NULL && ( pi->size <= capacity ) ) + { + *data = *pi; + } + + if ( timestamp != NULL ) + { + *timestamp = node->timestamp; + } + + return BPOOL_FreeBuffer( hUnpack->piDataPool, node ); } -#endif + +#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 0000000000..ba33abe59e --- /dev/null +++ b/lib_util/ivas_rtp_pi_data.c @@ -0,0 +1,601 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include "ivas_rtp_pi_data.h" +#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 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 uint16_t readInt16( const uint8_t *buffer ) +{ + return ( (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.0 ); + value = value > +32767.0 ? +32767.0 : value; + value = value < -32768.0 ? -32768.0 : 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_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_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 ) && ( piData->piDataType != IVAS_PI_AUDIO_FOCUS_DIRECTION ) +#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_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_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + } + + piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); + orientation->orientation.w = ((int16_t) readInt16( &buffer[0] )) / 32768.0f; + orientation->orientation.x = ((int16_t) readInt16( &buffer[2] )) / 32768.0f; + orientation->orientation.y = ((int16_t) readInt16( &buffer[4] )) / 32768.0f; + orientation->orientation.z = ((int16_t) readInt16( &buffer[6] )) / 32768.0f; + + 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; + uint32_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 < 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_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 ); + + 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; + + /* Audio Description data is max 5 bytes, 2 bytes header */ + if ( maxDataBytes < packedSize + 2 ) + { + return IVAS_ERROR( IVAS_ERR_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 > 5 ) + { + return IVAS_ERROR( IVAS_ERR_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_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_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; +} + +#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 */ + packUnsupportedData, /* DIEGETIC_TYPE */ + packUnsupportedData, /* RESERVED13 */ + packUnsupportedData, /* RESERVED14 */ + packUnsupportedData, /* RESERVED15 */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + packOrientation, /* HEAD_ORIENTATION */ +#else + packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ + packUnsupportedData, /* HEAD_ORIENTATION */ +#endif + packUnsupportedData, /* LISTENER_POSITION */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ + packAudioDescription, /* AUDIO_FOCUS_DIRECTION */ +#else + 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 */ + unpackUnsupportedData, /* DIEGETIC_TYPE */ + unpackUnsupportedData, /* RESERVED13 */ + unpackUnsupportedData, /* RESERVED14 */ + unpackUnsupportedData, /* RESERVED15 */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + unpackOrientation, /* HEAD_ORIENTATION */ +#else + unpackUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ + unpackUnsupportedData, /* HEAD_ORIENTATION */ +#endif + unpackUnsupportedData, /* LISTENER_POSITION */ +#ifdef RTP_S4_251135_CR26253_0016_REV1 + unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ + unpackOrientation, /* AUDIO_FOCUS_DIRECTION */ +#else + 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 */ + 0, /* IVAS_PI_RESERVED14 */ + 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 */ + 8, /* IVAS_PI_AUDIO_FOCUS_DIRECTION */ + 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_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; +} + +#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 0000000000..5780f32d8f --- /dev/null +++ b/lib_util/ivas_rtp_pi_data.h @@ -0,0 +1,441 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef IVAS_RTP_PI_DATA_H +#define IVAS_RTP_PI_DATA_H + +#include "common_api_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef IVAS_RTPDUMP + +#define IVAS_PI_MAX_DATA_SIZE ( 32 + 2 ) /* max packed PI data bytes + pi header bytes */ +#define IVAS_PI_MAX_OBJECTS ( 4 ) /* max ISM objects in PI data */ + + /* 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_RESERVED14, /* reserved */ + 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_DIRECTION, /* direction of interest for the listener in Quaternions */ + 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_AUDIO_FOCUS_DIRECTION + * - 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_PI_MAX_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_PI_MAX_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_PI_MAX_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_PI_MAX_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_PI_MAX_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_PI_MAX_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_PI_MAX_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_PI_MAX_OBJECTS]; /* diegetic indication as per audio format */ + } IVAS_PIDATA_DIEGETIC; + + /* Listener position */ + typedef struct + { + size_t size; /* sizeof(IVAS_PIDATA_LISTENER_POSITION) */ + uint32_t piDataType; /* IVAS_PI_LISTENER_POSITION */ + IVAS_COORDINATE position[IVAS_PI_MAX_OBJECTS]; /* 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_ORIENTATION playbackOrientation; + IVAS_PIDATA_ORIENTATION headOrientation; + IVAS_PIDATA_LISTENER_POSITION listnerPosition; + IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppression; + IVAS_PIDATA_ORIENTATION focusDirection; + 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; + +#endif /* IVAS_RTPDUMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* IVAS_RTP_PI_DATA_H */ diff --git a/lib_util/ivas_rtp_rom.c b/lib_util/ivas_rtp_rom.c new file mode 100644 index 0000000000..4b8539fb30 --- /dev/null +++ b/lib_util/ivas_rtp_rom.c @@ -0,0 +1,64 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include "ivas_rtp_internal.h" + +#ifdef IVAS_RTPDUMP + +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/mutex.h b/lib_util/mutex.h new file mode 100644 index 0000000000..f3fe493dc6 --- /dev/null +++ b/lib_util/mutex.h @@ -0,0 +1,104 @@ +/****************************************************************************************************** + + (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/*==================================================================================== + 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 */ -- GitLab From a145854081c295b007196b42add0503b06cbf3ce Mon Sep 17 00:00:00 2001 From: "Singh, Ripinder" Date: Wed, 30 Jul 2025 13:25:21 +1000 Subject: [PATCH 28/33] BugFixes, Race Condition fixes, decoder restart for codec switch Signed-off-by: Singh, Ripinder --- Workspace_msvc/lib_util.vcxproj | 4 + Workspace_msvc/lib_util.vcxproj.filters | 12 + apps/decoder.c | 217 +++++++++++-- apps/encoder.c | 47 ++- lib_dec/lib_dec.c | 3 +- lib_util/ivas_bpool.c | 8 +- lib_util/ivas_bpool.h | 8 +- lib_util/ivas_queue.c | 26 +- lib_util/ivas_rtp_api.h | 46 +-- lib_util/ivas_rtp_internal.h | 1 + lib_util/ivas_rtp_payload.c | 385 +++++++++++++----------- lib_util/ivas_rtp_pi_data.c | 18 +- lib_util/mutex.h | 2 +- 13 files changed, 522 insertions(+), 255 deletions(-) diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 94561b175a..84ff59beae 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -111,6 +111,10 @@ + + + + diff --git a/Workspace_msvc/lib_util.vcxproj.filters b/Workspace_msvc/lib_util.vcxproj.filters index afaedfb5da..776a38e3d3 100644 --- a/Workspace_msvc/lib_util.vcxproj.filters +++ b/Workspace_msvc/lib_util.vcxproj.filters @@ -85,6 +85,18 @@ util_c + + util_c + + + util_c + + + util_c + + + util_c + diff --git a/apps/decoder.c b/apps/decoder.c index 39c4f19824..c9eb700df3 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -168,6 +168,12 @@ typedef struct } IVAS_DEC_HRTF_BINARY_WRAPPER; #ifdef IVAS_RTPDUMP +#define JITTER_DURATION_MS ( 60 ) +#ifdef DEBUGGING +#define DEBUG_PRINT fprintf +#else +#define DEBUG_PRINT( ... ) +#endif typedef struct { @@ -177,8 +183,8 @@ typedef struct typedef struct { - uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * MAX_FRAMES_PER_RTP_PACKET]; - PIDATA_TS piData[IVAS_PI_MAX_ID * MAX_FRAMES_PER_RTP_PACKET]; + uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * IVAS_MAX_FRAMES_PER_RTP_PACKET]; + PIDATA_TS piData[IVAS_PI_MAX_ID * IVAS_MAX_FRAMES_PER_RTP_PACKET]; FILE *f_rtpstream; IVAS_RTP_CODEC codecId; @@ -187,11 +193,18 @@ typedef struct 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_UNPACK_HANDLE hUnpack; IVAS_RTP_UNPACK_CONFIG unpackCfg; PI_DATA_DEPACKER_STATE piDataDepackerState; +#ifdef RTP_S4_251135_CR26253_0016_REV1 + IVAS_RTP_SR_INFO srInfo; +#endif } IVAS_RTP; static void IVAS_RTP_Term( IVAS_RTP *rtp ) @@ -210,6 +223,8 @@ static ivas_error IVAS_RTP_Init( IVAS_RTP *rtp, FILE *f_rtpstream ) memset( rtp, 0, sizeof( IVAS_RTP ) ); + rtp->unpackCfg.jitterMarginMs = JITTER_DURATION_MS; + error = IVAS_RTP_UNPACK_Open( &rtp->hUnpack, &rtp->unpackCfg ); rtp->f_rtpstream = f_rtpstream; @@ -223,11 +238,9 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ { ivas_error error = IVAS_ERR_OK; IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; - uint32_t packetLen = 0u; - bool speechLostIndicated = false; -#ifdef RTP_S4_251135_CR26253_0016_REV1 - IVAS_RTP_SR_INFO srInfo; -#endif + size_t packetLen = 0u; + IVAS_RTP_CODEC codecId = IVAS_RTP_IVAS; + bool isAMRWB_IOmode = false; packedFrame.buffer = au; packedFrame.capacity = ( IVAS_MAX_BITS_PER_FRAME / 8 ); @@ -245,7 +258,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ } nread = fread( rtp->packet, sizeof( uint8_t ), packetLen, rtp->f_rtpstream ); /* Read Packet */ - if ( nread == 0 ) + if ( nread < packetLen ) { return IVAS_ERR_END_OF_FILE; } @@ -257,7 +270,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ &rtp->numFramesInPacket, &rtp->numPiDataInPacket, &rtp->remoteRequestBitmap ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "failed to unpack RTP packet\n" ); + fprintf( stderr, "failed to unpack RTP packet error = %s\n", ivas_error_to_string( error ) ); return error; } @@ -279,9 +292,9 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ } #ifdef RTP_S4_251135_CR26253_0016_REV1 - error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &rtp->codecId, &srInfo, &packedFrame, rtpTimeStamp, rtpSequenceNumber, &speechLostIndicated ); + 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, &rtp->codecId, &packedFrame, rtpTimeStamp, rtpSequenceNumber, &speechLostIndicated ); + error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &codecId, &packedFrame, auSizeBits, rtpTimeStamp, rtpSequenceNumber, &rtp->speechLostIndicated, &isAMRWB_IOmode ); #endif if ( error != IVAS_ERR_OK ) { @@ -289,9 +302,31 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ return error; } - *auSizeBits = (int16_t) ( packedFrame.length * 8 ); - *qBit = !speechLostIndicated; + 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; while ( rtp->nProcPiData < rtp->nReadPiData && @@ -305,13 +340,17 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ { case IVAS_PI_SCENE_ORIENTATION: { - error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, &piData->data.scene.orientation ); + IVAS_QUATERNION *quat = &piData->data.scene.orientation; + DEBUG_PRINT( stdout, "PI_SCENE_ORIENTATION : %f, %f, %f, %f\n", quat->w, quat->x, quat->y, quat->z ); + error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } break; case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED: { - error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, &piData->data.deviceCompensated.orientation ); + IVAS_QUATERNION *quat = &piData->data.deviceCompensated.orientation; + DEBUG_PRINT( stdout, "PI_DEVICE_ORIENTATION : %f, %f, %f, %f\n", quat->w, quat->x, quat->y, quat->z ); + error = IVAS_DEC_feedSinglePIorientation( hIvasDec, true, quat ); } break; @@ -339,7 +378,6 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ static bool parseCmdlIVAS_dec( int16_t argc, char **argv, DecArguments *arg ); static void usage_dec( void ); static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, ISAR_SPLIT_REND_BITS_DATA *splitRendBits, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); -static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); static ivas_error load_hrtf_from_file( IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtfBinary, IVAS_DEC_HANDLE hIvasDec, const IVAS_AUDIO_CONFIG OutputConfig, const int32_t output_Fs ); #ifdef DEBUGGING static ivas_error printBitstreamInfoVoip( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HANDLE hIvasDec ); @@ -348,6 +386,117 @@ static IVAS_DEC_FORCED_REND_MODE parseForcedRendModeDec( char *forcedRendModeCha #endif static void do_object_editing( IVAS_EDITABLE_PARAMETERS *editableParameters, ObjectEditFileReader *objectEditFileReader ); +#ifdef IVAS_RTPDUMP +static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, IVAS_DEC_HANDLE *phIvasDec, int16_t *pcmBuf ); + +static int restartDecoder( + IVAS_DEC_HANDLE *phIvasDec, + IVAS_DEC_MODE codec, + DecArguments *arg, + IVAS_RENDER_CONFIG_DATA *renderConfig, + IVAS_CUSTOM_LS_DATA *hLsCustomData ) +{ + ivas_error error = IVAS_ERR_OK; + IVAS_DEC_HANDLE hIvasDec; + + if ( phIvasDec == NULL ) + { + return -1; + } + + if ( NULL != *phIvasDec ) + { + IVAS_DEC_Close( phIvasDec ); + } + + if ( ( error = IVAS_DEC_Open( phIvasDec, codec ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Open failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + arg->decMode = codec; + + hIvasDec = *phIvasDec; + + uint16_t aeID = arg->aeSequence.count > 0 ? arg->aeSequence.pID[0] : 65535; + + IVAS_AUDIO_CONFIG outputConfig = ( codec == IVAS_DEC_MODE_IVAS ) ? arg->outputConfig : IVAS_AUDIO_CONFIG_MONO; + if ( ( error = IVAS_DEC_Configure( hIvasDec, arg->output_Fs, 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, arg->dpidEnabled, aeID, arg->objEditEnabled, arg->delayCompensationEnabled ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nConfigure failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( error = IVAS_DEC_GetRenderFramesize( hIvasDec, &arg->renderFramesize ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nConfigure failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( arg->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || arg->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + if ( ( error = IVAS_DEC_EnableSplitRendering( hIvasDec ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nSplit rendering configure failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( error = IVAS_DEC_GetRenderFramesize( hIvasDec, &arg->renderFramesize ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nConfigure failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + arg->enableHeadRotation = true; + } + + if ( arg->voipMode ) + { + if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, JITTER_DURATION_MS, arg->inputFormat ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nCould not enable VOIP: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_DEC_PrintConfig( hIvasDec, 1, arg->voipMode ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_PrintConfig failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( arg->renderConfigEnabled && renderConfig != NULL ) + { + if ( ( error = IVAS_DEC_FeedRenderConfig( hIvasDec, *renderConfig ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedRenderConfig failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + if ( arg->customLsOutputEnabled && hLsCustomData != NULL ) + { + if ( ( error = IVAS_DEC_FeedCustomLsData( hIvasDec, *hLsCustomData ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedCustomLsData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + return 0; + +cleanup: + IVAS_DEC_Close( phIvasDec ); + + return -1; +} +#else +static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); +#endif + /*------------------------------------------------------------------------------------------* * main() * @@ -648,7 +797,11 @@ int main( if ( arg.voipMode ) { +#ifdef IVAS_RTPDUMP + if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, JITTER_DURATION_MS, arg.inputFormat ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, 60, arg.inputFormat ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nCould not enable VOIP: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; @@ -920,7 +1073,11 @@ int main( if ( arg.voipMode ) { +#ifdef IVAS_RTPDUMP + error = decodeVoIP( arg, hBsReader, &hHrtfBinary, headRotReader, externalOrientationFileReader, refRotReader, referenceVectorReader, objectEditFileReader, &hIvasDec, pcmBuf ); +#else error = decodeVoIP( arg, hBsReader, &hHrtfBinary, headRotReader, externalOrientationFileReader, refRotReader, referenceVectorReader, objectEditFileReader, hIvasDec, pcmBuf ); +#endif } else { @@ -3178,7 +3335,11 @@ static ivas_error decodeVoIP( RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, +#ifdef IVAS_RTPDUMP + IVAS_DEC_HANDLE *phIvasDec, +#else IVAS_DEC_HANDLE hIvasDec, +#endif int16_t *pcmBuf ) { bool decodingFailed = true; /* Assume failure until cleanup is reached without errors */ @@ -3212,7 +3373,8 @@ static ivas_error decodeVoIP( int16_t i; FILE *f_rtpstream = NULL; #ifdef IVAS_RTPDUMP - IVAS_RTP ivasRtp; + IVAS_RTP ivasRtp = {0}; + IVAS_DEC_HANDLE hIvasDec = *phIvasDec; #else EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; @@ -3375,6 +3537,27 @@ static ivas_error decodeVoIP( { nSamplesRendered = 0; +#ifdef IVAS_RTPDUMP + if ( ivasRtp.restartNeeded ) + { + IVAS_DEC_MODE newCodecInPacket = ( ivasRtp.codecId == IVAS_RTP_EVS ) ? IVAS_DEC_MODE_EVS : IVAS_DEC_MODE_IVAS; + int err = restartDecoder( + &hIvasDec, + newCodecInPacket, + &arg, + NULL, /* ToDo : Provide rendererConfig */ + NULL /* ToDo : Provide LS Custom Data */ + ); + if ( err < 0 ) + { + fprintf( stderr, "\nFailed to restart decoder from %d to %d\n", arg.decMode, newCodecInPacket ); + goto cleanup; + } + *phIvasDec = hIvasDec; /* Update for main()' s free */ + ivasRtp.restartNeeded = false; + } +#endif + /* reference vector */ if ( arg.enableReferenceVectorTracking && vec_pos_update == 0 ) { diff --git a/apps/encoder.c b/apps/encoder.c index 861250a5a0..14db97bc1a 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -223,6 +223,17 @@ int main( #ifdef IVAS_RTPDUMP FILE *f_rtpstream = NULL; IVAS_RTP_PACK_HANDLE hPack = NULL; + + uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; + uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * IVAS_MAX_FRAMES_PER_RTP_PACKET]; + IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; + IVAS_DATA_BUFFER rtpPacket = { 0, 0, NULL }; + uint32_t numFramesInPayload = 0, packetLength = 0; + + packedFrame.capacity = sizeof( au ); + packedFrame.buffer = au; + rtpPacket.capacity = sizeof( packet ); + rtpPacket.buffer = packet; #endif /*------------------------------------------------------------------------------------------* @@ -729,11 +740,7 @@ int main( goto cleanup; } -#ifdef IVAS_RTPDUMP - if ( ( numSamplesRead == 0 ) && ( IVAS_RTP_PACK_GetNumFrames( hPack ) == 0 ) ) -#else if ( numSamplesRead == 0 ) -#endif { /* end of input data */ break; @@ -863,19 +870,12 @@ int main( #ifdef IVAS_RTPDUMP if ( hPack ) { - uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; - uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * MAX_FRAMES_PER_RTP_PACKET]; - uint32_t n = numBits / 8, x = 0, numFramesInPayload = 0, packetLength = 0; + uint32_t n = numBits / 8, x = 0; uint16_t *bitstrm = bitStream; - IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; - IVAS_DATA_BUFFER rtpPacket = { 0, 0, NULL }; - - packedFrame.capacity = sizeof( au ); - packedFrame.buffer = au; - rtpPacket.capacity = sizeof( packet ); - rtpPacket.buffer = packet; /* Pack Encoded Stream */ + packedFrame.length = 0; + rtpPacket.length = 0; while ( n ) { x = ( ( bitstrm[0] << 7 ) | ( bitstrm[1] << 6 ) | ( bitstrm[2] << 5 ) | ( bitstrm[3] << 4 ) | @@ -1059,6 +1059,21 @@ cleanup: #ifdef IVAS_RTPDUMP if ( hPack ) { + /* Complete the last packet */ + if ( IVAS_RTP_PACK_GetNumFrames( hPack ) != 0 ) + { + if ( ( error = IVAS_RTP_PACK_GetPacket( hPack, &rtpPacket, &numFramesInPayload ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while packing RTP Packet\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } + + /* File Format = Packet Length (uint32_t) + Packet bytes */ + packetLength = (uint32_t) rtpPacket.length; + fwrite( &packetLength, sizeof( packetLength ), 1, f_rtpstream ); + fwrite( rtpPacket.buffer, sizeof( uint8_t ), packetLength, f_rtpstream ); + } + IVAS_RTP_PACK_Close( &hPack ); } @@ -1965,9 +1980,9 @@ static bool parseCmdlIVAS_enc( else { arg->numFramesPerPacket = atoi( argv[i++] ); - if ( arg->numFramesPerPacket > MAX_FRAMES_PER_RTP_PACKET ) + if ( arg->numFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET ) { - fprintf( stderr, "numFramesPerPacket(%d) exceeds max frames per packet (%d) \n", arg->numFramesPerPacket, 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; } } diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index f9c9646c9f..11e208218a 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -339,10 +339,9 @@ void IVAS_DEC_Close( } /* destroy Split binaural renderer (ISAR) handle */ - ivas_destroy_handle_isar( &( *phIvasDec )->st_ivas->hSplitBinRend ); - if ( ( *phIvasDec )->st_ivas ) { + ivas_destroy_handle_isar( &( *phIvasDec )->st_ivas->hSplitBinRend ); ivas_destroy_dec( ( *phIvasDec )->st_ivas ); ( *phIvasDec )->st_ivas = NULL; } diff --git a/lib_util/ivas_bpool.c b/lib_util/ivas_bpool.c index cea33509ff..23754a0c11 100644 --- a/lib_util/ivas_bpool.c +++ b/lib_util/ivas_bpool.c @@ -89,7 +89,7 @@ ivas_error BPOOL_Create( BPOOL_HANDLE *pHandle, size_t bufferSize, uint32_t numB void BPOOL_Destroy( BPOOL_HANDLE *pHandle ) { - if ( pHandle != NULL ) + if ( ( pHandle != NULL ) && ( *pHandle != NULL ) ) { mtx_destroy( &( *pHandle )->lock ); free( *pHandle ); @@ -146,9 +146,9 @@ 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 ) { - uint32_t idx; + uint32_t numFreeBuffers; mtx_lock( &handle->lock ); - idx = handle->numFreeBuffers; + numFreeBuffers = handle->numFreeBuffers; mtx_unlock( &handle->lock ); - return idx; + return numFreeBuffers; } diff --git a/lib_util/ivas_bpool.h b/lib_util/ivas_bpool.h index c4cd45a736..d929ae7415 100644 --- a/lib_util/ivas_bpool.h +++ b/lib_util/ivas_bpool.h @@ -41,18 +41,18 @@ 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); +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 ); +ivas_error BPOOL_GetBuffer( BPOOL_HANDLE handle, void **dataPtr ); /* return the buffer back to pool */ -ivas_error BPOOL_FreeBuffer(BPOOL_HANDLE handle, void *dataPtr); +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); +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 index db038938a5..b72fcee9e4 100644 --- a/lib_util/ivas_queue.c +++ b/lib_util/ivas_queue.c @@ -64,10 +64,10 @@ ivas_error QUEUE_Create( QUEUE_HANDLE *pHandle ) return IVAS_ERR_OK; } -/* Destroy the queue and all free-up all allocated memory */ +/* Destroy the queue and free-up all allocated memory */ void QUEUE_Destroy( QUEUE_HANDLE *pHandle ) { - if ( pHandle != NULL ) + if ( ( pHandle != NULL ) && ( *pHandle != NULL ) ) { mtx_destroy( &( *pHandle )->lock ); free( *pHandle ); @@ -92,9 +92,9 @@ void QUEUE_Push( QUEUE_HANDLE handle, NODE *node ) } /* return the buffer back to pool */ -NODE * QUEUE_Pop( QUEUE_HANDLE handle ) +NODE *QUEUE_Pop( QUEUE_HANDLE handle ) { - NODE * node; + NODE *node; mtx_lock( &handle->lock ); node = handle->front; handle->front = handle->front->next; @@ -110,17 +110,29 @@ NODE * QUEUE_Pop( QUEUE_HANDLE handle ) /* returns the first element in the queue */ NODE *QUEUE_Front( QUEUE_HANDLE handle ) { - return handle->front; + 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 ) { - return handle->back; + 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 ) { - return handle->size; + uint32_t numNodes; + mtx_lock( &handle->lock ); + numNodes = handle->size; + mtx_unlock( &handle->lock ); + return numNodes; } diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 6b8ebb470a..597258f9f1 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -75,7 +75,7 @@ extern "C" * */ -#define MAX_FRAMES_PER_RTP_PACKET ( 8 ) /* Max supported frames per RTP packet */ +#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 @@ -301,17 +301,6 @@ extern "C" uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */ } IVAS_RTP_PACK_CONFIG; - /* 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 */ - ); - /* 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 */ @@ -325,6 +314,17 @@ extern "C" 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 * @@ -408,7 +408,7 @@ extern "C" /* Initial configuration for rtp unpacker */ typedef struct { - uint32_t maxNumberOfPayloadsInFifo; /* input payload fifo 's max length */ + uint32_t jitterMarginMs; /* expected max jitter duration in milliseconds */ } IVAS_RTP_UNPACK_CONFIG; /* Open an instance of the RTP unpacker and return a handle to rtp unpacker on success @@ -483,8 +483,7 @@ extern "C" ); /* Push a received rtp Ivas Packet to unpacker to extract number of frames, pi data and - * any remote request present in the Packet. Caller must extract RTP header and header - * extension and feed Ivas Packet alongwith RTP Timestamp and sequence number. + * 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 @@ -492,8 +491,7 @@ extern "C" * * Example usage : - * ================== - * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, packet, rtpTs, seqNum, - * &nFrames, &nPiData, &reqBitmap); + * 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 @@ -560,12 +558,14 @@ extern "C" 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 */ - 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 */ + 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 diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h index b74bdbe8d5..0acfcd2161 100644 --- a/lib_util/ivas_rtp_internal.h +++ b/lib_util/ivas_rtp_internal.h @@ -75,6 +75,7 @@ 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 */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 7bbc86171d..367aea06c8 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -112,14 +112,24 @@ typedef struct FRAME_NODE 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 lock; /* Lock to handle concurrent API invocation */ - RTP_HEADER header; - BPOOL_HANDLE nodePool; - IVAS_RTP_PACK_CONFIG initConfig; - IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX]; - QUEUE_HANDLE frameQ; /* frames queue */ + 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 @@ -127,9 +137,10 @@ 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 */ + IVAS_RTP_SR_INFO srInfo; /* Split Rendering Info */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ } TOC_INFO; typedef struct PIDATA_NODE @@ -150,9 +161,11 @@ typedef struct UNPACK_NODE struct IVAS_RTP_UNPACK { - mtx_t lock; /* Lock to handle concurrent API invocation */ + mtx_t apilock; /* Lock to handle concurrent API invocation */ + size_t maxNumberOfFrames; + size_t maxNumberOfPiData; RTP_HEADER header; - BPOOL_HANDLE nodePool; + BPOOL_HANDLE unpackNodePool; BPOOL_HANDLE piDataPool; IVAS_RTP_UNPACK_CONFIG initConfig; IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX]; @@ -170,7 +183,7 @@ static const uint32_t evsFrameSizeInBits[] = { }; static const uint32_t amrWBIOFrameSizeInBits[] = { - 132, 177, 253, 285, 317, 365, 397, 461, 477, 40 + 132, 177, 253, 285, 317, 365, 397, 461, 477, 35 }; @@ -400,7 +413,7 @@ static ivas_error UnpackRtpPacket( return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Extension Header indicated but insufficient input buffer" ); } - header->extData = realloc( header->extData, header->numExtUnits * 4 ); + header->extData = realloc( header->extData, header->numExtUnits * 4 ); if ( header->extData == NULL ) { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" ); @@ -418,7 +431,8 @@ static ivas_error getBitrateFromCodecAndFrameSize( uint32_t frameLengthBytes, uint32_t *bitrateKbps, uint32_t *frameLenInBits, - uint8_t *tocByte ) + uint8_t *tocByte, + bool *isAmrwbIOMode ) { size_t n; *bitrateKbps = 0; @@ -457,6 +471,7 @@ static ivas_error getBitrateFromCodecAndFrameSize( 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 */ @@ -486,16 +501,17 @@ ivas_error IVAS_RTP_PACK_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtppack handle" ); } - error = BPOOL_Create( &hPack->nodePool, sizeof( FRAME_NODE ), IVAS_MAX_FRAMES_IN_QUEUE ); + error = BPOOL_Create( &hPack->packNodePool, sizeof( FRAME_NODE ), IVAS_MAX_FRAMES_IN_QUEUE ); ERR_CHECK_RETURN( error ); error = QUEUE_Create( &hPack->frameQ ); ERR_CHECK_RETURN( error ); - mtx_init( &hPack->lock, 0 ); + mtx_init( &hPack->apilock, 0 ); hPack->initConfig = *config; initRequests( hPack->requests ); InitRtpHeader( &hPack->header ); + initPiDataFrame( &hPack->piDataCache ); *phPack = hPack; return IVAS_ERR_OK; } @@ -515,9 +531,9 @@ void IVAS_RTP_PACK_Close( hPack = *phPack; QUEUE_Destroy( &hPack->frameQ ); - mtx_destroy( &hPack->lock ); - BPOOL_Destroy( &hPack->nodePool ); - free ( hPack->header.extData ); + mtx_destroy( &hPack->apilock ); + BPOOL_Destroy( &hPack->packNodePool ); + free( hPack->header.extData ); free( hPack ); *phPack = NULL; } @@ -839,36 +855,28 @@ static ivas_error getSRToCByte( } #endif /* RTP_S4_251135_CR26253_0016_REV1 */ -static ivas_error addNewFrameNode( - IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */ - FRAME_NODE **newNode ) +static void addPackedPiDataToFrame( PIDATA_FRAME *piDataFrm, const PIDATA_PACKED *packedPiData, uint32_t piDataType ) { - FRAME_NODE *node = NULL; - ivas_error error = BPOOL_GetBuffer( hPack->nodePool, (void **) &node ); - ERR_CHECK_RETURN( error ); - - node->auNumBits = 0; - node->tocNumBytes = 0; - node->next = NULL; - - initPiDataFrame( &node->piDataFrame ); + piDataFrm->piData[piDataType].size = packedPiData->size; + memcpy( piDataFrm->piData[piDataType].data, packedPiData->data, packedPiData->size ); - /* Add to frames FiFo */ - QUEUE_Push( hPack->frameQ, (NODE *) node ); + /* 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++; + } - *newNode = node; - return IVAS_ERR_OK; + /* 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--; + } } -/* Push a single IVAS/EVS frame to rtp packer - * - * If multiple frames per RTP Payload are desired, multiple frames must be explicitly - * pushed before a call to IVAS_RTP_PACK_GetPacket to generate a rtp packet. - * - * It is possible to have variable frames per packet until maxFramesPerPacket frames - * if IVAS_RTP_PACK_GetPacket is invoked asyncronously w.r.t this api. - * - */ 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) */ @@ -882,42 +890,73 @@ ivas_error IVAS_RTP_PACK_PushFrame( uint32_t bitrate = 0; uint32_t frameLengthInBits = 0; uint8_t tocByte = 0; - FRAME_NODE *node = (FRAME_NODE *) QUEUE_Back( hPack->frameQ ); - - /* Check if a node was added due to Generic PI Data push */ - if ( ( node == NULL ) || ( node->tocNumBytes != 0 ) ) - { - error = addNewFrameNode( hPack, &node ); - ERR_CHECK_RETURN( error ); - } +#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 */ - node->toc[0] = TOC_INDICATE_NO_DATA; - node->tocNumBytes = 1; - node->auNumBits = 0; + 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 ); + error = getBitrateFromCodecAndFrameSize( codecId, frameBuffer->length, &bitrate, &frameLengthInBits, &tocByte, &hPack->amrwbIOMode ); ERR_CHECK_RETURN( error ); + } - node->toc[0] = tocByte; - node->tocNumBytes = 1; - node->auNumBits = frameLengthInBits; - memcpy( node->au, frameBuffer->buffer, frameBuffer->length ); + /* 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 ) + 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++ ) { - node->toc[0] = TOC_INDICATE_SR; - error = getSRToCByte( srInfo, bitrate, &node->toc[1] ); - ERR_CHECK_RETURN( error ); - node->tocNumBytes = 2; + 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 ); + } } -#endif + initPiDataFrame( piDataFrame ); /* Reset Cache */ } + mtx_unlock( &hPack->apilock ); + + /* Add to frames FiFo */ + QUEUE_Push( hPack->frameQ, (NODE *) node ); return IVAS_ERR_OK; } @@ -926,7 +965,12 @@ uint32_t IVAS_RTP_PACK_GetNumFrames( IVAS_RTP_PACK_HANDLE hPack /* i/o : IVAS rtp packer handle */ ) { - return QUEUE_Size( hPack->frameQ ); + uint32_t nFrames = 0; + if ( hPack ) + { + nFrames = QUEUE_Size( hPack->frameQ ); + } + return nFrames; } /* Push single PI data to rtp packer @@ -941,11 +985,8 @@ ivas_error IVAS_RTP_PACK_PushPiData( const IVAS_PIDATA_GENERIC *data /* i : pointer to the PIData stucture */ ) { - IVAS_PI_TYPE piDataType; ivas_error error = IVAS_ERR_OK; - FRAME_NODE *node = (FRAME_NODE *) QUEUE_Back( hPack->frameQ ); - PIDATA_FRAME *piDataFrm = NULL; - uint8_t PM = 0; + 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 */ @@ -954,137 +995,120 @@ ivas_error IVAS_RTP_PACK_PushPiData( return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong PI Data provided" ); } - /* No frame in Queue to associate PI Data, create one */ - if ( node == NULL ) - { - /* PI data received before any frame in queue is generic */ - PM = PI_HEADER_PM_GENERIC; - - /* Add a new node in frame queue, toc is still zero indicating frame is expected */ - error = addNewFrameNode( hPack, &node ); - ERR_CHECK_RETURN( error ); - } - - piDataFrm = &node->piDataFrame; - piDataType = data->piDataType; - - error = PI_PackData( data, &piDataFrm->piData[piDataType], PM ); + error = PI_PackData( data, &packedPiData, 0 ); ERR_CHECK_RETURN( error ); - /* 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 ) ) + mtx_lock( &hPack->apilock ); /* Lock to prevent access to shared cache */ { - piDataFrm->piDataBitmap &= ~( 1u << IVAS_PI_NO_DATA ); - piDataFrm->numPiDataAvailable--; + 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; } -/* 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 - * - */ +#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_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 *packet, /* o : encapsulated rtp packet */ + 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 *head = (FRAME_NODE *) QUEUE_Front( hPack->frameQ ); - FRAME_NODE *node = NULL; - size_t nBytes = packet->length, numEBytes = 0; + FRAME_NODE *availableFrameNodes[IVAS_MAX_FRAMES_PER_RTP_PACKET]; + size_t numEBytes = 0; - if ( packet == NULL ) + if ( payload == NULL ) { return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Output data buffer is NULL" ); } - /* Calculate number of frames and PI data present */ - node = head; - for ( n = 0; n < hPack->initConfig.maxFramesPerPacket && ( NULL != node ); n++, node = node->next ) + /* 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++ ) { - numFrame++; + 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; } - *numFramesInPayload = numFrame; /* numFrames in Packet */ /* IVAS Payload starts with E-Bytes */ - packEBytes( hPack, ( numPiDataPresent > 0 ), packet->capacity, &packet->buffer[packet->length], &numEBytes ); - nBytes += numEBytes; + packEBytes( hPack, ( numPiDataPresent > 0 ), payload->capacity, &payload->buffer[payload->length], &numEBytes ); + payload->length += numEBytes; /* ToC bytes (atleast 1 byte per frame, 2 if SR )*/ - node = head; - for ( n = 0; n < numFrame && ( NULL != node ); n++, node = node->next ) + for ( n = 0; n < numFrame; n++ ) { + FRAME_NODE *node = availableFrameNodes[n]; uint8_t fBit = ( n != ( numFrame - 1 ) ) ? TOC_HEADER_FOLLOWS : 0; /* Next ToC present */ - if ( nBytes < packet->capacity ) - { - packet->buffer[nBytes++] = ( node->toc[0] | fBit ); - } - else - { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); - } + WRITE_BYTE_PAYLOAD_OR_EXIT( payload, ( node->toc[0] | fBit ) ); +#ifdef RTP_S4_251135_CR26253_0016_REV1 if ( node->tocNumBytes == 2 ) { - if ( nBytes < packet->capacity ) - { - packet->buffer[nBytes++] = node->toc[1]; - } - else - { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); - } + WRITE_BYTE_PAYLOAD_OR_EXIT( payload, node->toc[1] ); } +#endif } /* Frame Data */ - node = head; - for ( n = 0; n < numFrame && ( NULL != node ); n++, node = node->next ) + for ( n = 0; n < numFrame; n++ ) { - size_t len = ( node->auNumBits + 7 ) >> 3; /* zero padded length in bytes */ - if ( nBytes + len < packet->capacity ) + FRAME_NODE *node = availableFrameNodes[n]; + size_t frameLength = ( node->auNumBits + 7 ) >> 3; /* zero padded length in bytes */ + if ( payload->length + frameLength <= payload->capacity ) { - memcpy( &packet->buffer[nBytes], node->au, len ); + memcpy( &payload->buffer[payload->length], node->au, frameLength ); } else { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + error = IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + goto err_exit; } - nBytes += len; + payload->length += frameLength; } - packet->length = nBytes; /* update packet length before PI packing */ - /* PI Data */ if ( numPiDataPresent > 0 ) { bool skipPiData = false; + size_t nBytes = payload->length; uint32_t numPiDataWritten = 0; - node = head; - for ( n = 0; n < numFrame && ( NULL != node ); n++, node = node->next ) + 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 ); @@ -1098,9 +1122,9 @@ ivas_error IVAS_RTP_PACK_GetPayload( 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 < packet->capacity ) + if ( nBytes + piDataFrame->piData[piDataType].size < payload->capacity ) { - memcpy( &packet->buffer[nBytes], piDataFrame->piData[piDataType].data, piDataFrame->piData[piDataType].size ); + memcpy( &payload->buffer[nBytes], piDataFrame->piData[piDataType].data, piDataFrame->piData[piDataType].size ); nBytes += piDataFrame->piData[piDataType].size; } else @@ -1113,25 +1137,23 @@ ivas_error IVAS_RTP_PACK_GetPayload( } if ( !skipPiData ) { - packet->length = nBytes; /* update packet length after PI packing */ + payload->length = nBytes; /* update payload length after PI packing */ } } +err_exit: /* Pop frames from Queue */ for ( n = 0; n < numFrame; n++ ) { - node = (FRAME_NODE *) QUEUE_Pop( hPack->frameQ ); - if ( node == NULL ) + if ( BPOOL_FreeBuffer( hPack->packNodePool, availableFrameNodes[n] ) != IVAS_ERR_OK ) { - assert( 0 ); /* catastrophic error, implementation issue */ - break; + assert( 0 ); /* catastrophic error if this fails */ + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "frame node could not be freed" ); } - - error = BPOOL_FreeBuffer( hPack->nodePool, node ); - assert( error == IVAS_ERR_OK ); /* catastrophic error if this fails */ + availableFrameNodes[n] = NULL; } - return IVAS_ERR_OK; + return error; } ivas_error IVAS_RTP_PACK_GetPacket( @@ -1158,6 +1180,7 @@ ivas_error IVAS_RTP_UNPACK_Open( { ivas_error error = IVAS_ERR_OK; IVAS_RTP_UNPACK_HANDLE hUnpack; + if ( phUnpack == NULL || config == NULL ) { return IVAS_ERR_UNEXPECTED_NULL_POINTER; @@ -1169,10 +1192,15 @@ ivas_error IVAS_RTP_UNPACK_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtp unpack handle" ); } - error = BPOOL_Create( &hUnpack->nodePool, sizeof( UNPACK_NODE ), IVAS_MAX_FRAMES_IN_QUEUE ); + /* maxNumberOfFrames = Ping Pong RTP Packet with max frames per packet + any jitter adjustment frames */ + hUnpack->maxNumberOfFrames += IVAS_MAX_FRAMES_PER_RTP_PACKET * 2; + hUnpack->maxNumberOfFrames += ( ( config->jitterMarginMs * IVAS_NUM_FRAMES_PER_SEC + 1000 - 1 ) / 1000 ); /* Jitter in Packets + Ping/Pong */ + 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 ), IVAS_MAX_FRAMES_IN_QUEUE * IVAS_PI_MAX_ID ); + error = BPOOL_Create( &hUnpack->piDataPool, sizeof( PIDATA_NODE ), hUnpack->maxNumberOfPiData ); ERR_CHECK_RETURN( error ); error = QUEUE_Create( &hUnpack->frameQ ); @@ -1182,7 +1210,7 @@ ivas_error IVAS_RTP_UNPACK_Open( ERR_CHECK_RETURN( error ); hUnpack->initConfig = *config; - mtx_init( &hUnpack->lock, 0 ); + mtx_init( &hUnpack->apilock, 0 ); initRequests( hUnpack->requests ); @@ -1204,12 +1232,12 @@ void IVAS_RTP_UNPACK_Close( } hUnpack = *phUnpack; - mtx_destroy( &hUnpack->lock ); + mtx_destroy( &hUnpack->apilock ); QUEUE_Destroy( &hUnpack->frameQ ); QUEUE_Destroy( &hUnpack->piDataQ ); BPOOL_Destroy( &hUnpack->piDataPool ); - BPOOL_Destroy( &hUnpack->nodePool ); - free ( hUnpack->header.extData ); + BPOOL_Destroy( &hUnpack->unpackNodePool ); + free( hUnpack->header.extData ); free( hUnpack ); *phUnpack = NULL; } @@ -1394,6 +1422,7 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy 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 ) { @@ -1604,7 +1633,7 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( UNPACK_NODE *node = NULL; /* Get a new node */ - error = BPOOL_GetBuffer( hUnpack->nodePool, (void **) &node ); + error = BPOOL_GetBuffer( hUnpack->unpackNodePool, (void **) &node ); ERR_CHECK_RETURN( error ); node->next = NULL; @@ -1613,7 +1642,7 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( node->toc = toc[n]; frameSizeBytes = ( node->toc.auNumBits + 7 ) / 8; - if ( nBytes + frameSizeBytes < payload->length ) + if ( nBytes + frameSizeBytes <= payload->length ) { memcpy( node->au, &payload->buffer[nBytes], frameSizeBytes ); nBytes += frameSizeBytes; @@ -1707,12 +1736,14 @@ 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 */ - 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 */ + 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; @@ -1731,6 +1762,11 @@ ivas_error IVAS_RTP_UNPACK_PullFrame( frameBuffer->length = length; } + if ( frameSizeInBits != NULL ) + { + *frameSizeInBits = (int16_t) node->toc.auNumBits; + } + if ( receivedCodecId != NULL ) { *receivedCodecId = node->toc.codecId; @@ -1758,7 +1794,12 @@ ivas_error IVAS_RTP_UNPACK_PullFrame( *speechLostIndicated = node->toc.speechLostIndicated; } - return BPOOL_FreeBuffer( hUnpack->nodePool, node ); + if ( isAMRWB_IOmode != NULL ) + { + *isAMRWB_IOmode = node->toc.isAMRWB_IOmode; + } + + return BPOOL_FreeBuffer( hUnpack->unpackNodePool, node ); } ivas_error IVAS_RTP_UNPACK_PullNextPiData( @@ -1781,7 +1822,7 @@ ivas_error IVAS_RTP_UNPACK_PullNextPiData( if ( data != NULL && ( pi->size <= capacity ) ) { - *data = *pi; + memcpy( data, pi, pi->size ); } if ( timestamp != NULL ) diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index ba33abe59e..8e918d76a2 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -59,9 +59,9 @@ static uint16_t readInt16( const uint8_t *buffer ) *-----------------------------------------------------------------------*/ static int16_t ivasPayload_convertToQ15( float value ) { - value = ( value * 32768.0 ); - value = value > +32767.0 ? +32767.0 : value; - value = value < -32768.0 ? -32768.0 : value; + value = ( value * 32768.0f ); + value = value > +32767.0f ? +32767.0f : value; + value = value < -32768.0f ? -32768.0f : value; return (int16_t) ( value ); } @@ -166,10 +166,10 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); - orientation->orientation.w = ((int16_t) readInt16( &buffer[0] )) / 32768.0f; - orientation->orientation.x = ((int16_t) readInt16( &buffer[2] )) / 32768.0f; - orientation->orientation.y = ((int16_t) readInt16( &buffer[4] )) / 32768.0f; - orientation->orientation.z = ((int16_t) readInt16( &buffer[6] )) / 32768.0f; + orientation->orientation.w = ( (int16_t) readInt16( &buffer[0] ) ) / 32768.0f; + orientation->orientation.x = ( (int16_t) readInt16( &buffer[2] ) ) / 32768.0f; + orientation->orientation.y = ( (int16_t) readInt16( &buffer[4] ) ) / 32768.0f; + orientation->orientation.z = ( (int16_t) readInt16( &buffer[6] ) ) / 32768.0f; return IVAS_ERR_OK; } @@ -197,7 +197,7 @@ static uint32_t getIndexTable( const float *table, uint32_t tableLength, float v static ivas_error packAcousticEnvironment( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { uint32_t nBytes = 0; - uint32_t packedSize = 1; + uint8_t packedSize = 1; const IVAS_PIDATA_ACOUSTIC_ENV *aeEnv = (const IVAS_PIDATA_ACOUSTIC_ENV *) piData; *nBytesWritten = 0; @@ -217,7 +217,7 @@ static ivas_error packAcousticEnvironment( const IVAS_PIDATA_GENERIC *piData, ui } /* Acoustic Env data is packedSize bytes, header is 2 bytes */ - if ( maxDataBytes < packedSize + 2 ) + if ( maxDataBytes < (uint32_t) packedSize + 2 ) { return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Insufficient space to pack Orientation PI data" ); } diff --git a/lib_util/mutex.h b/lib_util/mutex.h index f3fe493dc6..caf0145e2e 100644 --- a/lib_util/mutex.h +++ b/lib_util/mutex.h @@ -37,7 +37,7 @@ #ifndef _MUTEX_H #define _MUTEX_H -#if defined( __unix__ ) || defined( __linux__ ) || ( defined( __MACH__ ) && defined( __APPLE__ )) +#if defined( __unix__ ) || defined( __linux__ ) || ( defined( __MACH__ ) && defined( __APPLE__ ) ) #include typedef pthread_mutex_t mtx_t; #define _USE_POSIX ( 1 ) -- GitLab From 6dca357c0be08ef737338361cf0cec4b14a51ee5 Mon Sep 17 00:00:00 2001 From: "Singh, Ripinder" Date: Wed, 6 Aug 2025 15:51:05 +1000 Subject: [PATCH 29/33] Add pytest for PACK API - Add python version of Unpack - Check RTP Header for Timestamp, Sequenc Number, Header, SSRC - Check Payload for Codec, Bitrate and AU bytes - Check PI data for Type, Size and Pi data bytes Signed-off-by: Singh, Ripinder --- tests/rtp/ivasrtp.py | 446 ++++++++++++++++++++++++++++++++++++++++++ tests/rtp/test_rtp.py | 355 +++++++++++++++++++++++++++++++++ 2 files changed, 801 insertions(+) create mode 100644 tests/rtp/ivasrtp.py create mode 100644 tests/rtp/test_rtp.py diff --git a/tests/rtp/ivasrtp.py b/tests/rtp/ivasrtp.py new file mode 100644 index 0000000000..ecb3924866 --- /dev/null +++ b/tests/rtp/ivasrtp.py @@ -0,0 +1,446 @@ +#!/usr/bin/env python3 + +__copyright__ = """ +(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. +""" + +__doc__ = """ +To configure test modules. +""" + +import struct +from enum import Enum +from dataclasses import dataclass, field, asdict +from bitstring import ConstBitStream, ReadError +import json +import base64 +import argparse + +class CODECS(str, Enum): + AMRWB = "amrwb_io" + EVS = "evs" + IVAS = "ivas" + +class SRCODEC(str, Enum): + LCLD = "lcld" + LC3PLUS = "lc3+" + NA = "NONE" + +class BANDWIDTH(str, Enum): + NB = "narrowband" + WB = "wideband" + SWB = "super wideband" + FB = "fullband" + NREQ = "NO_REQ" + +class REQUESTS(str, Enum): + CODEC = "codec", + BR = "bitrate" + BW = "bandwidth" + CA = "ca-mode" + FMT = "format" + SUBFMT = "sub-format" + SRCFG = "sr-config" + +@dataclass +class RTPHDR: + version: int = 2 + padding: bool = False + extension: bool = False + csrcCount: int = 0 + marker: bool = False + payloadType: int = 0 + sequenceNum: int = 0 + timestamp: int = 0 + ssrc: int = 0 + extensionType: int = 0 + extensionLength: int = 0 + csrcList: list = field(default_factory=list) + extensionBytes: list = field(default_factory=list) + + def __init__(self, bitstrm: ConstBitStream): + self.version = bitstrm.read(2).uint + self.padding = bitstrm.read(1).bool + self.extension = bitstrm.read(1).bool + self.csrcCount = bitstrm.read(4).int + self.marker = bitstrm.read(1).bool + self.payloadType = bitstrm.read(7).int + self.sequenceNum = bitstrm.read(16).uintbe + self.timestamp = bitstrm.read(32).uintbe + self.ssrc = bitstrm.read(32).uintbe + self.csrcList = [ bitstrm.read(32).uintbe for _ in range(self.csrcCount) ] + if self.extension: + self.extensionType = bitstrm.read(16).uintbe + self.extensionLength = bitstrm.read(16).uintbe + self.extensionBytes = [ bitstrm.read(32).uintbe for _ in range(self.extensionLength) ] + else: + self.extensionType = 0 + self.extensionLength = 0 + self.extensionBytes = list() + +@dataclass +class SRCONFIG: + enabled: bool = False + diegetic: bool = False + yaw: bool = False + pitch: bool = False + roll: bool = False + +@dataclass +class CMR: + bandwidth: BANDWIDTH + codec: CODECS = CODECS.IVAS + startIdx: int = 0 + endIdx: int = 0 + bitrates: list = field(default_factory=list) + +@dataclass +class SRINFO: + bitrate: int = 0 + diegetic: bool = False + transportCodec: SRCODEC = SRCODEC.NA + +@dataclass +class FRAME: + codec: CODECS = CODECS.IVAS + frmSizeBits: int = 0 + bitrate: int = 0 + speechLost: bool = False + srInfo: SRINFO = None + timestamp: int = 0 + au: bytes = field(default_factory=bytes) + +@dataclass +class ORIENTATION: + w: float = 0.0 + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + +@dataclass +class PIDATA: + timestamp: int = 0 + type: str = "NO_PI_DATA" + data: any = None + +ivasBitrates = [13200, 16400, 24400, 32000, 48000, 64000, 80000, 96000, 128000, 160000, 192000, 256000, 384000, 512000, -1, 5200] +evsBitrates = [5900, 7200, 8000, 9600, 13200, 16400, 24400, 32000, 48000, 64000, 96000, 128000, 2400, -1, -1, -1] +amrwbBitrates = [6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850, 1750, -1, -1, -1, -1, -1, -1] +cmrLookup = [ + CMR(bandwidth=BANDWIDTH.NB, codec=CODECS.EVS, startIdx=0, endIdx=7, bitrates = evsBitrates), #000 = NB-EVS + CMR(bandwidth=BANDWIDTH.WB, codec=CODECS.AMRWB, startIdx=0, endIdx=9, bitrates = amrwbBitrates), #001 = AMRWB IO + CMR(bandwidth=BANDWIDTH.WB, codec=CODECS.EVS, startIdx=0, endIdx=12, bitrates = evsBitrates), #010 = WB-EVS + CMR(bandwidth=BANDWIDTH.SWB, codec=CODECS.EVS, startIdx=3, endIdx=12, bitrates = evsBitrates), #011 = SWB-EVS + CMR(bandwidth=BANDWIDTH.FB, codec=CODECS.EVS, startIdx=5, endIdx=12, bitrates = evsBitrates), #100 = FB-EVS + CMR(bandwidth=BANDWIDTH.WB, codec=CODECS.EVS, startIdx=0, endIdx=0, bitrates = []), #101 = WB-CA + CMR(bandwidth=BANDWIDTH.SWB, codec=CODECS.EVS, startIdx=0, endIdx=0, bitrates = []), #110 = SWB-CA + CMR(bandwidth=BANDWIDTH.NREQ, codec=CODECS.IVAS, startIdx=0, endIdx=14, bitrates = ivasBitrates), #111 = IVAS +] + +codedFormats = ["Stereo", "SBA", "MASA", "ISM", "MC", "OMASA", "OSBA", "NO_REQ"] +codedSubFormats = [ + "FOA planar", "HOA2 planar", "HOA3 planar", "FOA", "HOA2", "HOA3", "MASA1", "MASA2", "ISM1", + "ISM2", "ISM3", "ISM4", "ISM1 extended metadata", "ISM2 extended metadata", + "ISM3 extended metadata", "ISM4 extended metadata", "MC 5.1", "MC 7.1", "MC 5.1.2", "MC 5.1.4", + "MC 7.1.4", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", "OMASA ISM1 1TC", "OMASA ISM2 1TC", + "OMASA ISM3 1TC", "OMASA ISM4 1TC", "OMASA ISM1 2TC", "OMASA ISM2 2TC", "OMASA ISM3 2TC", + "OMASA ISM4 2TC", "OSBA ISM1 FOA planar", "OSBA ISM2 FOA planar", "OSBA ISM3 FOA planar", + "OSBA ISM4 FOA planar", "OSBA ISM1 FOA", "OSBA ISM2 FOA", "OSBA ISM3 FOA", "OSBA ISM4 FOA", + "OSBA ISM1 HOA2 planar", "OSBA ISM2 HOA2 planar", "OSBA ISM3 HOA2 planar", "OSBA ISM4 HOA2 planar", + "OSBA ISM1 HOA2", "OSBA ISM2 HOA2", "OSBA ISM3 HOA2", "OSBA ISM4 HOA2", "OSBA ISM1 HOA3 planar", + "OSBA ISM2 HOA3 planar", "OSBA ISM3 HOA3 planar", "OSBA ISM4 HOA3 planar", "OSBA ISM1 HOA3", + "OSBA ISM2 HOA3", "OSBA ISM3 HOA3", "OSBA ISM4 HOA3"] +PiTypeNames = [ + "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", "RESERVED14", + "RESERVED15","PLAYBACK_DEVICE_ORIENTATION", "HEAD_ORIENTATION", "LISTENER_POSITION", "DYNAMIC_AUDIO_SUPPRESSION", + "AUDIO_FOCUS_DIRECTION", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN", "R_ISM_ORIENTATION", "R_ISM_POSITION", "R_ISM_DIRECTION", + "RESERVED27", "RESERVED28", "RESERVED29", "RESERVED30", "NO_PI_DATA" +] + +def unpackUnsupported(bitstrm: ConstBitStream, piSize: int) -> any: + #assert False, "Unsupported PI Data" + return base64.b64encode(bitstrm.read(piSize * 8).tobytes()).decode('utf-8') + +def unpackNoPiData(bitstrm: ConstBitStream, piSize: int) -> None: + assert piSize == 0, "NO_PI_DATA should be 0 size" + +def unpackOrientation(bitstrm: ConstBitStream, piSize: int) -> ORIENTATION: + assert piSize == 8, "Incorrect PI Data Size for Orientation" + w = bitstrm.read(16).int / 32768.0 + x = bitstrm.read(16).int / 32768.0 + y = bitstrm.read(16).int / 32768.0 + z = bitstrm.read(16).int / 32768.0 + return ORIENTATION(w, x, y, z) + +PIDataUnpacker = [ + unpackOrientation, # SCENE_ORIENTATION, + unpackOrientation, # DEVICE_ORIENTATION_COMPENSATED, + unpackOrientation, # DEVICE_ORIENTATION_UNCOMPENSATED + unpackUnsupported, # ACOUSTIC_ENVIRONMENT + unpackUnsupported, # AUDIO_DESCRIPTION + unpackUnsupported, # ISM_NUM + unpackUnsupported, # ISM_ID + unpackUnsupported, # ISM_GAIN + unpackUnsupported, # ISM_ORIENTATION + unpackUnsupported, # ISM_POSITION + unpackUnsupported, # ISM_DISTANCE_ATTENUATION + unpackUnsupported, # ISM_DIRECTIVITY + unpackUnsupported, # DIEGETIC_TYPE + unpackUnsupported, # RESERVED13 + unpackUnsupported, # RESERVED14 + unpackUnsupported, # RESERVED15 + unpackUnsupported, # PLAYBACK_DEVICE_ORIENTATION + unpackUnsupported, # HEAD_ORIENTATION + unpackUnsupported, # LISTENER_POSITION + unpackUnsupported, # DYNAMIC_AUDIO_SUPPRESSION + unpackUnsupported, # AUDIO_FOCUS_DIRECTION + unpackUnsupported, # PI_LATENCY + unpackUnsupported, # R_ISM_ID + unpackUnsupported, # R_ISM_GAIN + unpackUnsupported, # R_ISM_ORIENTATION + unpackUnsupported, # R_ISM_POSITION + unpackUnsupported, # R_ISM_DIRECTION + unpackUnsupported, # RESERVED27 + unpackUnsupported, # RESERVED28 + unpackUnsupported, # RESERVED29 + unpackUnsupported, # RESERVED30 + unpackNoPiData # NO_DATA +] + +@dataclass +class IvasPayload: + lastCodec: CODECS = CODECS.IVAS # Track last frame's codec + frameList: list[FRAME] = field(default_factory=list) + piDataList: list[PIDATA] = field(default_factory=list) + requests: dict [str, any] = field(default_factory=dict) + + def __init__(self, bitstrm: ConstBitStream, rtpTimestamp, lastCodec: CODECS): + self.lastCodec = lastCodec + self.frameList = list[FRAME]() + self.piDataList = list[PIDATA]() + self.requests = dict() + + try: + piIndicated = False + if bitstrm.read(1).bool: + T = bitstrm.read(3).uint + BR = bitstrm.read(4).uint + + if T in [5, 6]:#CA MODES + if BR < 8: + self.requests[REQUESTS.CODEC] = cmrLookup[T].codec + self.requests[REQUESTS.BR] = 13200 + self.requests[REQUESTS.CA] = BR + self.requests[REQUESTS.BW] = cmrLookup[T].bandwidth + else: + raise Exception("Unsupported BR bits in CA Mode") + elif T == 7: #IVAS + if BR < 14 : + self.requests[REQUESTS.CODEC] = cmrLookup[T].codec + self.requests[REQUESTS.BR] = cmrLookup[T].bitrates[BR] + self.requests[REQUESTS.CA] = -1 + elif BR == 14 : + raise Exception("Reserved BR idx in IVAS EByte") + else: + if BR >= cmrLookup[T].startIdx and BR < cmrLookup[T].endIdx: + self.requests[REQUESTS.CODEC] = cmrLookup[T].codec + self.requests[REQUESTS.BR] = cmrLookup[T].bitrates[BR] + self.requests[REQUESTS.CA] = -1 + self.requests[REQUESTS.BW] = cmrLookup[T].bandwidth + else: + raise Exception("Reserved BR idx in {} EByte".format(cmrLookup[T].codec)) + + #Try to get all subsequent E-bytes + while bitstrm.read(1).bool: + ET = bitstrm.read(3).uint + if ET == 0 : + supportedBW = [BANDWIDTH.WB, BANDWIDTH.SWB, BANDWIDTH.FB, BANDWIDTH.NREQ] + reserved = bitstrm.read(2) + BW = bitstrm.read(2).uint + self.requests[REQUESTS.BW] = supportedBW[BW] + elif ET == 1 : + S = bitstrm.read(1).bool + FMT = bitstrm.read(3).uint + if not S: + self.requests[REQUESTS.FMT] = codedFormats[FMT] + self.requests[REQUESTS.SUBFMT] = "NO_REQ" + else: + reserved = bitstrm.read(2) + subFMT = bitstrm.read(6).uint + self.requests[REQUESTS.FMT] = "NO_REQ" + self.requests[REQUESTS.SUBFMT] = codedSubFormats[subFMT] + elif ET == 2: + reserved = bitstrm.read(4) + piIndicated = True + elif ET == 3: + D = bitstrm.read(1).bool + Y = bitstrm.read(1).bool + P = bitstrm.read(1).bool + R = bitstrm.read(1).bool + self.requests[REQUESTS.SRCFG] = SRCONFIG(enabled=True, diegetic=D, yaw=Y, pitch=P, roll=R) + else: + reserved = bitstrm.read(4) + raise Exception("Unsupported subsequent EByte with ET={}".format(ET)) + + # ToC Byte parsing starts with 'F' bit as H bit is already read above + frameTimeStamps = rtpTimestamp + F = True + frmList = list() + while F: + F = bitstrm.read(1).bool + FT = bitstrm.read(2).uint + BR = bitstrm.read(4).uint + + frm = FRAME(timestamp=frameTimeStamps) + if FT == 1 : + frm.codec = CODECS.IVAS + if BR == 14 : + supportedBitrates = [-1, 256000, 384000, 512000] + reserved = bitstrm.read(1) + D = bitstrm.read(1).bool + C = bitstrm.read(1).bool + SR_BR = bitstrm.read(2).uint + reserved = bitstrm.read(3) + if SR_BR == 0: + raise Exception("Reserved bitrate in SR Config ToC Indicated") + frm.srInfo = SRINFO(bitrate=supportedBitrates[SR_BR], diegetic=D, + transportCodec= SRCODEC.LC3PLUS if C else SRCODEC.LCLD) + else: + frm.bitrate = ivasBitrates[BR] + elif FT == 0: + # Codec switch only if not NO_DATA_FRAME, as IVAS/EVS signal using this + frm.codec = CODECS.EVS if BR != 15 else self.lastCodec + if BR == 13: + raise Exception("Reserved bitrate in EVS ToC Indicated") + frm.speechLost = (BR == 14) + frm.bitrate = evsBitrates[BR] if BR < 13 else 0 + else: + frm.codec = CODECS.AMRWB + if BR >= 10 and BR <= 13: + raise Exception("Reserved bitrate in AMRWB-IO ToC Indicated") + frm.speechLost = (BR == 14) or (FT == 2) + frm.bitrate = amrwbBitrates[BR] if BR < 10 else 0 + frm.frmSizeBits = frm.bitrate // 50 + frameTimeStamps += 320 + frmList.append(frm) + + if F: + #skip all frame specific E-bytes before next header + while (bitstrm.read(1).bool): + print("Skipping unsupported frame specific subsequent Ebytes") + reserved = bitstrm.read(7) + + #Frame AUs here + for (idx, frm) in enumerate(frmList): + auSize = (frm.frmSizeBits + 7) // 8 # Zero padded bytes in amrwb_io mode + frm.au = bitstrm.read(auSize * 8).tobytes() + self.frameList.append(frm) + + # PI Data if Indicated + piTimeStamps = rtpTimestamp + PF = piIndicated + while PF : + PF = bitstrm.read(1).bool + PM = bitstrm.read(2).uint + PiType = bitstrm.read(5).uint + PiSize = 0 + byte = 255 + while byte == 255: + byte = bitstrm.read(8).uint + PiSize += byte + + PiFrameData = PIDataUnpacker[PiType](bitstrm, PiSize) + + self.piDataList.append( + PIDATA(timestamp=piTimeStamps if PM != 3 else rtpTimestamp, # Generic Pi has base timestamp + type=PiTypeNames[PiType], + data=PiFrameData)) + piTimeStamps += 320 if PM == 2 else 0 + except ReadError as error: + print ("Underflow before completion of unpacking, error = {}".format(error)) + +@dataclass +class IvasPacket: + hdr: RTPHDR = field(default_factory=RTPHDR) + payload: IvasPayload = field(default_factory=IvasPayload) + +class IvasRtp: + def __init__(self): + self.packets = list[IvasPacket]() + self.lastCodec: CODECS = CODECS.IVAS # Track last frame's codec + + def dumpToJSON(self, jsonFileName): + with open(jsonFileName, "w") as fd: + packets = list() + for packet in self.packets: + packets.append(asdict(packet)) + json_output = json.dumps(packets, indent=4) + fd.write(json_output) + + def getPackets(self): + return self.packets + + def unpackFile(self, rtpDumpFile): + with open (rtpDumpFile, mode="rb") as fd: + while True: + size = fd.read(4) + if not size: + break + size = struct.unpack( 'i', size)[0] + packet = fd.read(size) + if not packet: + break + self.packets.append(self.unpackPacket(packet)) + + def unpackPacket(self, packet) -> IvasPacket : + bitStrm = ConstBitStream(packet) + hdr = RTPHDR(bitStrm) + payload = IvasPayload(bitStrm, rtpTimestamp=hdr.timestamp, lastCodec=self.lastCodec) + self.lastCodec = payload.frameList[-1].codec #Last Frame's codec for next frame for NO_DATA case + return IvasPacket(hdr=hdr, payload=payload) + +class ArgsParser: + def __init__(self): + self.parser = argparse.ArgumentParser() + self.parser.add_argument("-r", "--rtpdump", type=str, required=True, help="RTP Dump to unpack") + self.parser.add_argument("-j", "--json", type=str, default="unpack.json", help="Output unpacked RTP frames to JSON file") + + def parse(self): + args = self.parser.parse_args() + return args + +if __name__ == "__main__": + args = ArgsParser().parse() + rtp = IvasRtp() + if args.rtpdump: + rtp.unpackFile(args.rtpdump) + rtp.dumpToJSON(args.json) diff --git a/tests/rtp/test_rtp.py b/tests/rtp/test_rtp.py new file mode 100644 index 0000000000..00b4da5c1b --- /dev/null +++ b/tests/rtp/test_rtp.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 + +__copyright__ = """ +(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. +""" + +__doc__ = """ +To configure test modules. +""" + +import pytest +import csv +import os +import sys + +from tempfile import TemporaryDirectory +from pathlib import Path +from ivasrtp import * +from bitstring import ConstBitStream, BitStream + +THIS_PATH = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.join(os.path.dirname(THIS_PATH), "../../scripts")) + +from tests.conftest import EncoderFrontend, DecoderFrontend + +@pytest.mark.parametrize("dtx", [False, True]) +@pytest.mark.parametrize("bitrate", [6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850]) +@pytest.mark.parametrize("framesPerPacket", [1, 3, 8]) +def test_rtp_bitstream_amrwb ( + test_info, + bitrate: int, + dtx: bool, + framesPerPacket: int, + dut_encoder_frontend: EncoderFrontend +): + run_rtp_bitstream_tests ( + CODECS.AMRWB, + bitrate, + "WB", + "OFF", + "MONO", + dtx, + framesPerPacket, + dut_encoder_frontend + ) + +@pytest.mark.parametrize("dtx", [False, True]) +@pytest.mark.parametrize("bitrate", [7200, 8000, 9600, 13200, 16400, 24400, 32000, 48000, 64000, 96000, 128000]) +@pytest.mark.parametrize("bandwidth", ["NB", "WB", "SWB", "FB"]) +@pytest.mark.parametrize("caMode", ["OFF", "LO", "HI"]) +@pytest.mark.parametrize("framesPerPacket", [1, 3, 8]) +def test_rtp_bitstream_evs ( + test_info, + bitrate: int, + bandwidth: str, + caMode: str, + dtx: bool, + framesPerPacket: int, + dut_encoder_frontend: EncoderFrontend +): + run_rtp_bitstream_tests ( + CODECS.EVS, + bitrate, + bandwidth, + caMode, + "MONO", + dtx, + framesPerPacket, + dut_encoder_frontend + ) + + +@pytest.mark.parametrize("bitrate", [13200, 24400, 80000, 512000]) +@pytest.mark.parametrize("bandwidth", ["WB", "SWB", "FB"]) +@pytest.mark.parametrize("format", ["STEREO", "SBA", "MC", "MASA"]) +#@pytest.mark.parametrize("bandwidth, format, bitrate", [("WB", "MASA", 13200)]) +@pytest.mark.parametrize("framesPerPacket", [8]) +def test_rtp_bitstream_ivas_nodtx ( + test_info, + bitrate: int, + bandwidth: str, + format: str, + framesPerPacket: int, + dut_encoder_frontend: EncoderFrontend +): + run_rtp_bitstream_tests ( + CODECS.IVAS, + bitrate, + bandwidth, + "OFF", + format, + False, + framesPerPacket, + dut_encoder_frontend + ) + +@pytest.mark.parametrize("bitrate", [13200, 24400, 80000]) +@pytest.mark.parametrize("bandwidth", ["WB", "SWB", "FB"]) +@pytest.mark.parametrize("format", ["STEREO", "SBA"]) +@pytest.mark.parametrize("framesPerPacket", [1, 3, 8]) +def test_rtp_bitstream_ivas_dtx ( + test_info, + bitrate: int, + bandwidth: str, + format: str, + framesPerPacket: int, + dut_encoder_frontend: EncoderFrontend +): + run_rtp_bitstream_tests ( + CODECS.IVAS, + bitrate, + bandwidth, + "OFF", + format, + True, + framesPerPacket, + dut_encoder_frontend + ) + + +def isEqualFrame(refFrame: bytes, dutFrame: bytes): + assert len(refFrame) == len(dutFrame), "Encoded frame size is different" + for refByte, dutByte in zip(refFrame, dutFrame): + assert refByte == dutByte, "Encoded frames should be bitexact between ref and rtpdump" + +def isEqualOrientation(ref: ORIENTATION, dut: ORIENTATION): + assert abs(ref.w - dut.w) < 0.0001, "Scene Orientation PI Data mismatch in w" + assert abs(ref.x - dut.x) < 0.0001, "Scene Orientation PI Data mismatch in x" + assert abs(ref.y - dut.y) < 0.0001, "Scene Orientation PI Data mismatch in y" + assert abs(ref.z - dut.z) < 0.0001, "Scene Orientation PI Data mismatch in z" + + +class CSVREADER: + def __init__(self, csvFile: Path): + self.rIdx = 0 + self.rows = [] + with open(csvFile, 'r') as fd: + self.rows = [ row for row in csv.reader(fd) ] + self.count = len(self.rows) + + def next(self) -> list[float]: + row = self.rows[self.rIdx] + self.rIdx += 1 + if self.rIdx == self.count: + self.rIdx = 0 + return [ float(x) for x in row ] + +class RTPVALIDATE: + + DTX_BITRATES = { CODECS.IVAS: 5200, CODECS.EVS: 2400, CODECS.AMRWB: 1750 } + + + def __init__(self, codec = CODECS.IVAS, bitrate = 24400, framesPerPacket = 1, dtx = False): + self.framesPerPacket = framesPerPacket + self.dtx = dtx + self.codec = codec + self.bitrate = bitrate + self.timestamp = 0 + self.seqnum = -1 + self.ssrc = -1 + self.numFrames = 0 + self.validatePiData = False + self.g192File = None + self.frameIdx = 0 + #PI DATA + self.readers: dict[str : CSVREADER] = dict() + + def setPiDataFiles(self, piFiles: tuple[Path]): + self.validatePiData = True + self.readers[PiTypeNames[0]] = CSVREADER(piFiles[0]) + self.readers[PiTypeNames[1]] = CSVREADER(piFiles[1]) + + def setRefG192Bitstream(self, g192File: Path): + self.refPackets = list[bytes]() + self.refBitStrm = None + with open(g192File, "rb") as fd: + self.refBitStrm = ConstBitStream(fd.read()) + while self.refBitStrm.pos < self.refBitStrm.len: + sync = hex(self.refBitStrm.read(16).intle) + nBits = self.refBitStrm.read(16).intle + assert sync == "0x6b21", "G192 syncword not found at start of packet" + writer = BitStream() + for _ in range(nBits): + bit = "0b1" if self.refBitStrm.read(16).uintle == 129 else "0b0" + writer.append(bit) + self.refPackets.append(writer.tobytes()) + + def packet(self, packet: IvasPacket): + self.header(packet.hdr) + self.payload(packet.payload) + self.seqnum = (self.seqnum + 1) % 65536 + self.timestamp += 320 * self.numFrames + + def header(self, hdr: RTPHDR): + if self.timestamp == 0: + self.seqnum = hdr.sequenceNum + self.ssrc = hdr.ssrc + assert hdr.version == 2, "RTP Header Version must be 2" + assert self.ssrc == hdr.ssrc, "SSRC changed mid-stream in RTP Header" + assert self.timestamp == hdr.timestamp, "Timestamp mismatch in RTP Header" + assert self.seqnum == hdr.sequenceNum, "Sequence number mismatch in RTP Header" + + def payload(self, payload: IvasPayload): + self.numFrames = len(payload.frameList) + assert self.numFrames >= 1 and self.numFrames <= self.framesPerPacket, f"Packet must have atleast 1 frame and atmost {self.framesPerPacket} frames" + + for frame in payload.frameList: + assert self.codec == frame.codec, "Codec mismatch in RTP Payload" + if self.dtx: + assert frame.bitrate in (self.bitrate, RTPVALIDATE.DTX_BITRATES[self.codec], 0), "Bitrate mismatch in RTP Payload in DTX mode" + else: + assert frame.bitrate == self.bitrate, "Bitrate mismatch in RTP Payload" + + assert self.frameIdx < len(self.refPackets), "No. of frames mismatch" + isEqualFrame(frame.au, self.refPackets[self.frameIdx]) + self.frameIdx += 1 + + # Vallidate the PI Data + if self.validatePiData: + self.piData(payload.piDataList) + + def piData(self, piDataList: list[PIDATA]): + for piData in piDataList: + assert piData.timestamp >= self.timestamp and piData.timestamp < self.timestamp + (self.numFrames * 320), "PI Data Time stamp is OOB" + assert piData.type == PiTypeNames[0] or piData.type == PiTypeNames[1], "PI Data is neither Scene nor Device Orientation" + assert type(piData.data) == ORIENTATION, "Orientation type data expected" + #validate the PI Data provided is the PI data in the packet + refData = self.readers[piData.type].next() + isEqualOrientation(ORIENTATION(w=refData[0], x=refData[1], y=refData[2], z=refData[3]), piData.data) +@dataclass +class TVARGS: + TVROOT = Path(THIS_PATH).joinpath("../../scripts/testv") + def __init__(self): + self.tvDict = dict() + self.sceneFile = Path(THIS_PATH).joinpath("../../scripts/trajectories/azi_plus_2-ele_plus_2-every-25-rows.csv").absolute() + self.deviceFile = Path(THIS_PATH).joinpath("../../scripts/trajectories/headrot-1.5s.csv").absolute() + + def add(self, fmt:str, inputFile:str, args:list[str] = []): + inputFile = str(TVARGS.TVROOT.joinpath(inputFile).absolute()) + if fmt == "MASA": + args[2] = str(TVARGS.TVROOT.joinpath(args[2]).absolute()) + self.tvDict[fmt] = (inputFile, args) + + def input(self, fmt): + return self.tvDict[fmt][0] + + def args(self, fmt, addPI=False) -> list[str]: + args = [ x for x in self.tvDict[fmt][1] ] + if addPI and fmt != "MONO": + args += [ "-scene_orientation", str(self.sceneFile), "-device_orientation", str(self.deviceFile) ] + return args + + def piFiles(self) -> tuple[Path]: + return (self.sceneFile, self.deviceFile) + +def run_rtp_bitstream_tests ( + codec: CODECS, + bitrate: int, + bandwidth: str, + caMode: str, + format: str, + dtx: bool, + framesPerPacket: int, + dut_encoder_frontend: EncoderFrontend +): + tvArgs = TVARGS() + tvArgs.add("MONO", "stv48n.wav") + + if dtx: #use bigger file for dtx stereo + tvArgs.add("STEREO", "stvST48n.wav", ["-stereo"]) + else: + tvArgs.add("STEREO", "stv2MASA2TC48c.wav", ["-stereo"]) + + tvArgs.add("MC", "stv51MC48c.wav", ["-mc", "5_1"]) + tvArgs.add("MASA", "stv2MASA2TC48c.wav", ["-masa", "2", "stv2MASA2TC48c.met"]) + tvArgs.add("SBA", "stvFOA48c.wav", ["-sba", "+1"]) + + if (bitrate > 24400 and bandwidth == "NB") or (format == "STEREO" and bitrate > 256000): + pytest.skip() + + print("Test: dut_encoder_frontend={}, dtx={}, codec:={}, bitrate={}, bandwidth={}, caMode={}, format={},".format(dut_encoder_frontend._path, dtx, codec, bitrate, bandwidth, caMode, format)) + + validate = RTPVALIDATE( + codec=codec, + bitrate=bitrate, + framesPerPacket=framesPerPacket, + dtx=dtx + ) + + with TemporaryDirectory() as tmp_dir: + g192Out = Path(tmp_dir).joinpath(f"output-{codec}-{bitrate}-{caMode}-{format}-{dtx}.g192").absolute() + rtpdumpOut = Path(tmp_dir).joinpath(f"output-{codec}-{bitrate}-{caMode}-{format}-{dtx}.rtpdump").absolute() + + # Run WITHOUT rtpdump first to generate reference bitstream + dut_encoder_frontend.run( + bitrate=bitrate, + input_sampling_rate=48, + input_path=tvArgs.input(format), + output_bitstream_path=g192Out, + sba_order=None, + dtx_mode=dtx, + max_band=bandwidth, + add_option_list=tvArgs.args(format) + ) + validate.setRefG192Bitstream(g192File=g192Out) + + # Generate RTPDUMP + addPI = False if format == "MONO" else True + if addPI: + # Add PI Data to Pack in RTP + validate.setPiDataFiles(tvArgs.piFiles()) + + extra_args = tvArgs.args(format, addPI) + extra_args += ["-rtpdump", str(framesPerPacket)] + dut_encoder_frontend.run( + bitrate=bitrate, + input_sampling_rate=48, + input_path=tvArgs.input(format), + output_bitstream_path=rtpdumpOut, + sba_order=None, + dtx_mode=dtx, + max_band=bandwidth, + add_option_list=extra_args + ) + + ivasRtp = IvasRtp() + ivasRtp.unpackFile(rtpdumpOut) + for packet in ivasRtp.getPackets(): + validate.packet(packet) -- GitLab From de43d43ad6c169a7b8acbcf4ab2ccc0f6fc678a2 Mon Sep 17 00:00:00 2001 From: Ripinder Singh Date: Tue, 12 Aug 2025 19:15:52 +1000 Subject: [PATCH 30/33] Add dumping of PI Data in decoder, more PI support and bugfixes * API updates for Pack and Unpack APIs * Do not report NO_PI_DATA in unpack * Add support for pack/unpack Listner Position, Diegetic * Fix PI Data structure for LISTERENR POSITION * Fix shift in acoustic env pi data unpack * Add a python implementation of PACK API * Add tests to validate decoded audio and dumped PI data Signed-off-by: Ripinder Singh --- apps/decoder.c | 254 +++++++- apps/encoder.c | 2 +- lib_util/ivas_rtp_api.h | 18 +- lib_util/ivas_rtp_payload.c | 25 +- lib_util/ivas_rtp_pi_data.c | 161 ++++- lib_util/ivas_rtp_pi_data.h | 6 +- tests/requirements.txt | 2 + tests/rtp/ivasrtp.py | 1145 ++++++++++++++++++++++++++++------- tests/rtp/test_rtp.py | 197 ++++-- 9 files changed, 1508 insertions(+), 302 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index c9eb700df3..4f2307b3dc 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -130,6 +130,10 @@ typedef struct IVAS_DEC_COMPLEXITY_LEVEL complexityLevel; bool tsmEnabled; IVAS_RENDER_FRAMESIZE renderFramesize; +#ifdef IVAS_RTPDUMP + bool applyPiData; + char *piOutputFilename; +#endif #ifdef DEBUGGING IVAS_DEC_FORCED_REND_MODE forcedRendMode; #ifdef DEBUG_FOA_AGC @@ -183,10 +187,11 @@ typedef struct typedef struct { - uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * IVAS_MAX_FRAMES_PER_RTP_PACKET]; + 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]; FILE *f_rtpstream; + FILE *f_piDataOut; IVAS_RTP_CODEC codecId; uint32_t nReadPiData; uint32_t nProcPiData; @@ -207,6 +212,166 @@ typedef struct #endif } IVAS_RTP; +static const char *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", + "RESERVED14", "RESERVED15", "PLAYBACK_DEVICE_ORIENTATION", "HEAD_ORIENTATION", "LISTENER_POSITION", + "DYNAMIC_AUDIO_SUPPRESSION", "AUDIO_FOCUS_DIRECTION", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN", + "R_ISM_ORIENTATION", "R_ISM_POSITION", "R_ISM_DIRECTION", "RESERVED27", "RESERVED28", "RESERVED29", + "RESERVED30", "NO_DATA" +}; + + +static void LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t nPiDataPresent ) +{ + 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 ) + { + 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_AUDIO_FOCUS_DIRECTION: + 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; + 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: + { + 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_DYNAMIC_AUDIO_SUPPRESSION: + { + 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_RESERVED14: + 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}" ); +} + static void IVAS_RTP_Term( IVAS_RTP *rtp ) { if ( rtp->f_rtpstream ) @@ -214,27 +379,34 @@ static void IVAS_RTP_Term( IVAS_RTP *rtp ) fclose( rtp->f_rtpstream ); rtp->f_rtpstream = NULL; } + if ( rtp->f_piDataOut ) + { + fprintf( rtp->f_piDataOut, "\n}\n" ); + fclose( rtp->f_piDataOut ); + rtp->f_piDataOut = NULL; + } IVAS_RTP_UNPACK_Close( &rtp->hUnpack ); } -static ivas_error IVAS_RTP_Init( IVAS_RTP *rtp, FILE *f_rtpstream ) +static ivas_error IVAS_RTP_Init( IVAS_RTP *rtp, FILE *f_rtpstream, FILE *f_piDataOut ) { ivas_error error = IVAS_ERR_OK; memset( rtp, 0, sizeof( IVAS_RTP ) ); - rtp->unpackCfg.jitterMarginMs = JITTER_DURATION_MS; + rtp->unpackCfg.maxFramesPerPacket = IVAS_MAX_FRAMES_PER_RTP_PACKET; error = IVAS_RTP_UNPACK_Open( &rtp->hUnpack, &rtp->unpackCfg ); rtp->f_rtpstream = f_rtpstream; + rtp->f_piDataOut = f_piDataOut; rtp->rtpPacket.buffer = rtp->packet; rtp->rtpPacket.capacity = sizeof( rtp->packet ); return error; } -static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit ) +static ivas_error readNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit ) { ivas_error error = IVAS_ERR_OK; IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; @@ -289,6 +461,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ rtp->nReadPiData++; rtp->numPiDataInPacket--; } + LogPiData( rtp->f_piDataOut, rtp->piData, rtp->nReadPiData ); } #ifdef RTP_S4_251135_CR26253_0016_REV1 @@ -329,8 +502,14 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ rtp->numFramesProduced++; *nextPacketRcvTime_ms += 20; + return IVAS_ERR_OK; +} + +static ivas_error applyPiData( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint32_t rtpTimeStamp ) +{ + ivas_error error = IVAS_ERR_OK; while ( rtp->nProcPiData < rtp->nReadPiData && - rtp->piData[rtp->nProcPiData].timestamp <= *rtpTimeStamp ) + rtp->piData[rtp->nProcPiData].timestamp <= rtpTimeStamp ) { PIDATA_TS *piData = &rtp->piData[rtp->nProcPiData++]; if ( hIvasDec ) @@ -356,7 +535,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ default: { - fprintf( stderr, "Unhandled PI data of type : %d\n", piDataType ); + fprintf( stderr, "Unhandled PI data of type : %s\n", PiDataNames[piDataType] ); } break; } @@ -366,8 +545,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint8_ } } } - - return IVAS_ERR_OK; + return error; } #endif /* IVAS_RTPDUMP */ @@ -1304,6 +1482,10 @@ static bool parseCmdlIVAS_dec( arg->referenceVectorTrajFileName = NULL; arg->enableExternalOrientation = false; arg->externalOrientationTrajFileName = NULL; +#ifdef IVAS_RTPDUMP + arg->applyPiData = false; + arg->piOutputFilename = NULL; +#endif #ifdef SUPPORT_JBM_TRACEFILE arg->jbmTraceFilename = NULL; @@ -1390,6 +1572,25 @@ 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++]; + } + else if ( strcmp( argv_to_upper, "-APPLYPIDATA" ) == 0 ) + { + arg->applyPiData = true; + i++; + } +#endif #ifdef SUPPORT_JBM_TRACEFILE else if ( strcmp( argv_to_upper, "-TRACEFILE" ) == 0 ) { @@ -1979,6 +2180,8 @@ static void usage_dec( void ) 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" ); + fprintf( stdout, "-ApplyPiData Apply the PI data found in the rtp packet.\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" ); @@ -3270,7 +3473,7 @@ static ivas_error printBitstreamInfoVoip( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - error = readNextFrame( &ivasRtp, NULL, auPtr, &auSizeBits, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + error = readNextFrame( &ivasRtp, auPtr, &auSizeBits, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); #else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSizeBits ); #endif @@ -3373,8 +3576,10 @@ static ivas_error decodeVoIP( int16_t i; FILE *f_rtpstream = NULL; #ifdef IVAS_RTPDUMP - IVAS_RTP ivasRtp = {0}; + IVAS_RTP ivasRtp = { 0 }; IVAS_DEC_HANDLE hIvasDec = *phIvasDec; + FILE *f_piDataOut = NULL; + int32_t initialTsOffsetSystemAndRTP = 0; #else EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; @@ -3441,7 +3646,17 @@ static ivas_error decodeVoIP( } #ifdef IVAS_RTPDUMP - if ( ( error = IVAS_RTP_Init( &ivasRtp, f_rtpstream ) ) != IVAS_ERR_OK ) + if ( arg.piOutputFilename != NULL ) + { + f_piDataOut = fopen( arg.piOutputFilename, "w" ); + if ( f_piDataOut == NULL ) + { + fprintf( stderr, "could not open: %s\n", arg.piOutputFilename ); + goto cleanup; + } + fprintf( f_piDataOut, "{\n" ); + } + if ( ( error = IVAS_RTP_Init( &ivasRtp, f_rtpstream, f_piDataOut ) ) != IVAS_ERR_OK ) { fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); goto cleanup; @@ -3496,7 +3711,8 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - error = readNextFrame( &ivasRtp, hIvasDec, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + error = readNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + 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 @@ -3700,7 +3916,7 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - error = readNextFrame( &ivasRtp, hIvasDec, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + error = readNextFrame( &ivasRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */ rtpTimeStamp = rtpTimeStamp / 16; @@ -3745,6 +3961,18 @@ 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; + if ( ( error = applyPiData( &ivasRtp, hIvasDec, piTs ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } +#endif #ifdef SUPPORT_JBM_TRACEFILE if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, writeJbmTraceFileFrameWrapper, jbmTraceWriter, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) #else diff --git a/apps/encoder.c b/apps/encoder.c index 14db97bc1a..00c7cb519a 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -225,7 +225,7 @@ int main( IVAS_RTP_PACK_HANDLE hPack = NULL; uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; - uint8_t packet[IVAS_NOMINAL_RTP_BYTES_PER_FRAME * IVAS_MAX_FRAMES_PER_RTP_PACKET]; + uint8_t packet[NOMINAL_BUFFER_SIZE(IVAS_MAX_FRAMES_PER_RTP_PACKET)]; IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; IVAS_DATA_BUFFER rtpPacket = { 0, 0, NULL }; uint32_t numFramesInPayload = 0, packetLength = 0; diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 597258f9f1..5e269eaa43 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -82,7 +82,9 @@ extern "C" * 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 IVAS_NOMINAL_RTP_BYTES_PER_FRAME ( ( IVAS_MAX_BITS_PER_FRAME + ( IVAS_MAX_BITS_PER_FRAME / 5 ) ) / 8 ) +#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 */ @@ -375,8 +377,8 @@ extern "C" /* Generate a rtp payload using available pushed frames * - * Available remote requests, pi data and frames will be packed into a rtp payload. If no - * frame is pushed before call to this api, NO_DATA_FRAME will be generated + * 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( @@ -408,7 +410,7 @@ extern "C" /* Initial configuration for rtp unpacker */ typedef struct { - uint32_t jitterMarginMs; /* expected max jitter duration in milliseconds */ + 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 @@ -432,6 +434,10 @@ extern "C" * 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 else a race condition + * can arise if new packet is pushed while frames/pidata are still being pulled out. + * * Example usage : - * ================== * err = IVAS_RTP_UNPACK_PushPayload(hIvasUnpack, payload, rtpTs, seqNum, @@ -489,6 +495,10 @@ extern "C" * 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 else a race condition + * can arise if new packet is pushed while frames/pidata are still being pulled out. + * * Example usage : - * ================== * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, packet, &nFrames, &nPiData, &reqBitmap); diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 367aea06c8..779c627274 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -489,6 +489,7 @@ ivas_error IVAS_RTP_PACK_Open( { ivas_error error; IVAS_RTP_PACK_HANDLE hPack; + uint32_t numFramesPerPacket = ( config->maxFramesPerPacket == 0 ) ? 1 : config->maxFramesPerPacket; if ( phPack == NULL ) { @@ -501,7 +502,7 @@ ivas_error IVAS_RTP_PACK_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtppack handle" ); } - error = BPOOL_Create( &hPack->packNodePool, sizeof( FRAME_NODE ), IVAS_MAX_FRAMES_IN_QUEUE ); + error = BPOOL_Create( &hPack->packNodePool, sizeof( FRAME_NODE ), numFramesPerPacket * 4 ); ERR_CHECK_RETURN( error ); error = QUEUE_Create( &hPack->frameQ ); @@ -1192,9 +1193,7 @@ ivas_error IVAS_RTP_UNPACK_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtp unpack handle" ); } - /* maxNumberOfFrames = Ping Pong RTP Packet with max frames per packet + any jitter adjustment frames */ - hUnpack->maxNumberOfFrames += IVAS_MAX_FRAMES_PER_RTP_PACKET * 2; - hUnpack->maxNumberOfFrames += ( ( config->jitterMarginMs * IVAS_NUM_FRAMES_PER_SEC + 1000 - 1 ) / 1000 ); /* Jitter in Packets + Ping/Pong */ + hUnpack->maxNumberOfFrames = ( config->maxFramesPerPacket < IVAS_MAX_FRAMES_PER_RTP_PACKET ) ? 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 ); @@ -1544,7 +1543,16 @@ static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimes } } while ( byte == 255 ); - if ( nBytes + piSize <= payload->length ) + if ( piDataType == IVAS_PI_NO_DATA ) + { + if ( piSize > 0 ) + { + return IVAS_ERROR( IVAS_ERR_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 ); @@ -1614,6 +1622,13 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( *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 */ diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index 8e918d76a2..b88bb0e661 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -40,14 +40,14 @@ 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 uint32_t writeInt16( uint8_t *buffer, uint32_t idx, int16_t val ) +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 uint16_t readInt16( const uint8_t *buffer ) +static __inline uint16_t readInt16( const uint8_t *buffer ) { return ( (uint16_t) buffer[0] << 8 ) | ( (uint16_t) buffer[1] ); } @@ -295,7 +295,7 @@ static ivas_error unpackAcousticEnvironment( const uint8_t *buffer, uint32_t num dWord <<= 8; dWord |= buffer[n]; } - dWord <<= ( 8 - numDataBytes ); + dWord <<= ( 8 - numDataBytes ) * 8; aeEnv->aeid = (uint8_t) ( ( dWord >> 57 ) & MASK_AEID ); aeEnv->rt60[IVAS_PI_AE_LOW] = mapRT60[( dWord >> 52 ) & MASK_RT60]; @@ -424,6 +424,119 @@ static ivas_error unpackDynamicSuppression( const uint8_t *buffer, uint32_t numD 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_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 / 327.68f ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.y / 327.68f ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.z / 327.68f ) ); + *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_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 = ( (int16_t) readInt16( &buffer[0] ) ) / 100.0f; + listener->position.y = ( (int16_t) readInt16( &buffer[2] ) ) / 100.0f; + listener->position.z = ( (int16_t) readInt16( &buffer[4] ) ) / 100.0f; + 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_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Diegetic Type PI data" ); + } + + for ( n = 0; n < 5; 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_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]; + for ( n = 0; n < 5; n++ ) + { + diegetic->isDiegetic[n] = ( ( byte >> ( 7 - n ) ) & 1 ) != 0; + } + + return IVAS_ERR_OK; +} + + #endif /* RTP_S4_251135_CR26253_0016_REV1 */ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { @@ -434,7 +547,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 */ packUnsupportedData, /* ISM_NUM */ packUnsupportedData, /* ISM_ID */ @@ -443,24 +556,26 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { 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 */ packUnsupportedData, /* RESERVED14 */ packUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ - packOrientation, /* HEAD_ORIENTATION */ -#else - packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ - packUnsupportedData, /* HEAD_ORIENTATION */ -#endif - packUnsupportedData, /* LISTENER_POSITION */ -#ifdef RTP_S4_251135_CR26253_0016_REV1 + packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + packOrientation, /* HEAD_ORIENTATION */ + packListenerPosition, /* LISTENER_POSITION */ packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ packAudioDescription, /* AUDIO_FOCUS_DIRECTION */ #else - 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 */ @@ -468,7 +583,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 */ @@ -496,22 +611,24 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { 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 */ unpackUnsupportedData, /* RESERVED14 */ unpackUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ - unpackOrientation, /* HEAD_ORIENTATION */ + unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */ + unpackOrientation, /* HEAD_ORIENTATION */ + unpackListenerPosition, /* LISTENER_POSITION */ + unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ + unpackOrientation, /* AUDIO_FOCUS_DIRECTION */ #else unpackUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ unpackUnsupportedData, /* HEAD_ORIENTATION */ -#endif unpackUnsupportedData, /* LISTENER_POSITION */ -#ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ - unpackOrientation, /* AUDIO_FOCUS_DIRECTION */ -#else unpackUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */ unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */ #endif diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index 5780f32d8f..ba82914df1 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -296,9 +296,9 @@ extern "C" /* Listener position */ typedef struct { - size_t size; /* sizeof(IVAS_PIDATA_LISTENER_POSITION) */ - uint32_t piDataType; /* IVAS_PI_LISTENER_POSITION */ - IVAS_COORDINATE position[IVAS_PI_MAX_OBJECTS]; /* Position of audio objects in ISM(s) */ + 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; diff --git a/tests/requirements.txt b/tests/requirements.txt index 2eb090f4fb..a8d8f7b064 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,3 +2,5 @@ pytest>=5.3.5 pytest-xdist>=1.31.0 scipy>=1.5.2 numpy>=1.19.2 +bitstring>=4.3.1 +soundfile>=0.13 diff --git a/tests/rtp/ivasrtp.py b/tests/rtp/ivasrtp.py index ecb3924866..f6923c0077 100644 --- a/tests/rtp/ivasrtp.py +++ b/tests/rtp/ivasrtp.py @@ -37,10 +37,24 @@ To configure test modules. import struct from enum import Enum from dataclasses import dataclass, field, asdict -from bitstring import ConstBitStream, ReadError +from bitstring import ConstBitStream, BitStream, ReadError import json import base64 import argparse +from pathlib import Path +from typing import cast + +NO_REQ="NO_REQ" + +class CAMODE(str, Enum): + CA_LO_02 = "CA-LO-O2" + CA_LO_03 = "CA-LO-O3" + CA_LO_05 = "CA-LO-O5" + CA_LO_07 = "CA-LO-O7" + CA_HI_02 = "CA-HI-O2" + CA_HI_03 = "CA-HI-O3" + CA_HI_05 = "CA-HI-O5" + CA_HI_07 = "CA-HI-O7" class CODECS(str, Enum): AMRWB = "amrwb_io" @@ -50,14 +64,12 @@ class CODECS(str, Enum): class SRCODEC(str, Enum): LCLD = "lcld" LC3PLUS = "lc3+" - NA = "NONE" class BANDWIDTH(str, Enum): NB = "narrowband" WB = "wideband" SWB = "super wideband" FB = "fullband" - NREQ = "NO_REQ" class REQUESTS(str, Enum): CODEC = "codec", @@ -68,6 +80,134 @@ class REQUESTS(str, Enum): SUBFMT = "sub-format" SRCFG = "sr-config" +class FORMATS(str, Enum): + STEREO="Stereo" + SBA="SBA" + MASA="MASA" + ISM="ISM" + MC="MC" + OMASA="OMASA" + OSBA="OSBA" + +class SUBFORMATS(str, Enum): + FOA_PLANAR = "FOA planar" + HOA2_PLANAR = "HOA2 planar" + HOA3_PLANAR = "HOA3 planar" + FOA = "FOA" + HOA2 = "HOA2" + HOA3 = "HOA3" + MASA1 = "MASA1" + MASA2 = "MASA2" + ISM1 = "ISM1" + ISM2 = "ISM2" + ISM3 = "ISM3" + ISM4 = "ISM4" + ISM1_EXTENDED_METADATA = "ISM1 extended metadata" + ISM2_EXTENDED_METADATA = "ISM2 extended metadata" + ISM3_EXTENDED_METADATA = "ISM3 extended metadata" + ISM4_EXTENDED_METADATA = "ISM4 extended metadata" + MC_5_1 = "MC 5.1" + MC_7_1 = "MC 7.1" + MC_5_1_2 = "MC 5.1.2" + MC_5_1_4 = "MC 5.1.4" + MC_7_1_4 = "MC 7.1.4" + Reserved22 = "Reserved22" + Reserved23 = "Reserved23" + Reserved24 = "Reserved24" + Reserved25 = "Reserved25" + Reserved26 = "Reserved26" + Reserved27 = "Reserved27" + Reserved28 = "Reserved28" + Reserved29 = "Reserved29" + Reserved30 = "Reserved30" + Reserved31 = "Reserved31" + Reserved32 = "Reserved32" + OMASA_ISM1_1TC = "OMASA ISM1 1TC" + OMASA_ISM2_1TC = "OMASA ISM2 1TC" + OMASA_ISM3_1TC = "OMASA ISM3 1TC" + OMASA_ISM4_1TC = "OMASA ISM4 1TC" + OMASA_ISM1_2TC = "OMASA ISM1 2TC" + OMASA_ISM2_2TC = "OMASA ISM2 2TC" + OMASA_ISM3_2TC = "OMASA ISM3 2TC" + OMASA_ISM4_2TC = "OMASA ISM4 2TC" + OSBA_ISM1_FOA_PLANAR = "OSBA ISM1 FOA planar" + OSBA_ISM2_FOA_PLANAR = "OSBA ISM2 FOA planar" + OSBA_ISM3_FOA_PLANAR = "OSBA ISM3 FOA planar" + OSBA_ISM4_FOA_PLANAR = "OSBA ISM4 FOA planar" + OSBA_ISM1_FOA = "OSBA ISM1 FOA" + OSBA_ISM2_FOA = "OSBA ISM2 FOA" + OSBA_ISM3_FOA = "OSBA ISM3 FOA" + OSBA_ISM4_FOA = "OSBA ISM4 FOA" + OSBA_ISM1_HOA2_PLANAR = "OSBA ISM1 HOA2 planar" + OSBA_ISM2_HOA2_PLANAR = "OSBA ISM2 HOA2 planar" + OSBA_ISM3_HOA2_PLANAR = "OSBA ISM3 HOA2 planar" + OSBA_ISM4_HOA2_PLANAR = "OSBA ISM4 HOA2 planar" + OSBA_ISM1_HOA2 = "OSBA ISM1 HOA2" + OSBA_ISM2_HOA2 = "OSBA ISM2 HOA2" + OSBA_ISM3_HOA2 = "OSBA ISM3 HOA2" + OSBA_ISM4_HOA2 = "OSBA ISM4 HOA2" + OSBA_ISM1_HOA3_PLANAR = "OSBA ISM1 HOA3 planar" + OSBA_ISM2_HOA3_PLANAR = "OSBA ISM2 HOA3 planar" + OSBA_ISM3_HOA3_PLANAR = "OSBA ISM3 HOA3 planar" + OSBA_ISM4_HOA3_PLANAR = "OSBA ISM4 HOA3 planar" + OSBA_ISM1_HOA3 = "OSBA ISM1 HOA3" + OSBA_ISM2_HOA3 = "OSBA ISM2 HOA3" + OSBA_ISM3_HOA3 = "OSBA ISM3 HOA3" + OSBA_ISM4_HOA3 = "OSBA ISM4 HOA3" + +class PIDATAS(str, Enum): + SCENE_ORIENTATION = "SCENE_ORIENTATION" + DEVICE_ORIENTATION_COMPENSATED = "DEVICE_ORIENTATION_COMPENSATED" + DEVICE_ORIENTATION_UNCOMPENSATED = "DEVICE_ORIENTATION_UNCOMPENSATED" + ACOUSTIC_ENVIRONMENT = "ACOUSTIC_ENVIRONMENT" + AUDIO_DESCRIPTION = "AUDIO_DESCRIPTION" + ISM_NUM = "ISM_NUM" + ISM_ID = "ISM_ID" + ISM_GAIN = "ISM_GAIN" + ISM_ORIENTATION = "ISM_ORIENTATION" + ISM_POSITION = "ISM_POSITION" + ISM_DISTANCE_ATTENUATION = "ISM_DISTANCE_ATTENUATION" + ISM_DIRECTIVITY = "ISM_DIRECTIVITY" + DIEGETIC_TYPE = "DIEGETIC_TYPE" + RESERVED13 = "RESERVED13" + RESERVED14 = "RESERVED14" + RESERVED15 = "RESERVED15" + PLAYBACK_DEVICE_ORIENTATION = "PLAYBACK_DEVICE_ORIENTATION" + HEAD_ORIENTATION = "HEAD_ORIENTATION" + LISTENER_POSITION = "LISTENER_POSITION" + DYNAMIC_AUDIO_SUPPRESSION = "DYNAMIC_AUDIO_SUPPRESSION" + AUDIO_FOCUS_DIRECTION = "AUDIO_FOCUS_DIRECTION" + PI_LATENCY = "PI_LATENCY" + R_ISM_ID = "R_ISM_ID" + R_ISM_GAIN = "R_ISM_GAIN" + R_ISM_ORIENTATION = "R_ISM_ORIENTATION" + R_ISM_POSITION = "R_ISM_POSITION" + R_ISM_DIRECTION = "R_ISM_DIRECTION" + RESERVED27 = "RESERVED27" + RESERVED28 = "RESERVED28" + RESERVED29 = "RESERVED29" + RESERVED30 = "RESERVED30" + NO_PI_DATA = "NO_PI_DATA" + +class SUPPRESSION_LEVEL(int, Enum): + SUPPRESSION_LEVEL_NONE = 0 + SUPPRESSION_LEVEL_1 = 1 + SUPPRESSION_LEVEL_2 = 2 + SUPPRESSION_LEVEL_3 = 3 + SUPPRESSION_LEVEL_4 = 4 + SUPPRESSION_LEVEL_5 = 5 + SUPPRESSION_LEVEL_6 = 6 + SUPPRESSION_LEVEL_7 = 7 + SUPPRESSION_LEVEL_8 = 8 + SUPPRESSION_LEVEL_9 = 9 + SUPPRESSION_LEVEL_10 = 10 + SUPPRESSION_LEVEL_11 = 11 + SUPPRESSION_LEVEL_12 = 12 + SUPPRESSION_LEVEL_13 = 13 + SUPPRESSION_LEVEL_14 = 14 + SUPPRESSION_LEVEL_MAX = 15 + + @dataclass class RTPHDR: version: int = 2 @@ -82,31 +222,54 @@ class RTPHDR: extensionType: int = 0 extensionLength: int = 0 csrcList: list = field(default_factory=list) - extensionBytes: list = field(default_factory=list) - - def __init__(self, bitstrm: ConstBitStream): - self.version = bitstrm.read(2).uint - self.padding = bitstrm.read(1).bool - self.extension = bitstrm.read(1).bool - self.csrcCount = bitstrm.read(4).int - self.marker = bitstrm.read(1).bool - self.payloadType = bitstrm.read(7).int - self.sequenceNum = bitstrm.read(16).uintbe - self.timestamp = bitstrm.read(32).uintbe - self.ssrc = bitstrm.read(32).uintbe - self.csrcList = [ bitstrm.read(32).uintbe for _ in range(self.csrcCount) ] + extensionWords: list = field(default_factory=list) + + def updateHeader(self, numFrames: int): + self.sequenceNum = (self.sequenceNum + 1) % 65536 + self.timestamp += 320 * numFrames + + def pack(self, bitstrm: BitStream): + bitstrm.append(f'uint:2={self.version}') + bitstrm.append(f'bool={self.padding}') + bitstrm.append(f'bool={self.extension}') + bitstrm.append(f'uint:4={self.csrcCount}') + bitstrm.append(f'bool={self.marker}') + bitstrm.append(f'uint:7={self.payloadType}') + bitstrm.append(f'uintbe:16={self.sequenceNum}') + bitstrm.append(f'uintbe:32={self.timestamp}') + bitstrm.append(f'uintbe:32={self.ssrc}') + assert len(self.csrcList) == self.csrcCount, "csrcList must be of length csrcCount" + for csrc in self.csrcList: + bitstrm.append(f'uintbe:32={csrc}') if self.extension: - self.extensionType = bitstrm.read(16).uintbe - self.extensionLength = bitstrm.read(16).uintbe - self.extensionBytes = [ bitstrm.read(32).uintbe for _ in range(self.extensionLength) ] - else: - self.extensionType = 0 - self.extensionLength = 0 - self.extensionBytes = list() + bitstrm.append(f'uintbe:16={self.extensionType}') + bitstrm.append(f'uintbe:16={self.extensionLength}') + assert len(self.extensionWords) == self.extensionLength, "extensionWords must be of extensionLength csrcCount" + for ext in self.extensionWords: + bitstrm.append(f'uintbe:32={ext}') + + @classmethod + def unpack(cls, bitstrm: ConstBitStream): + hdr = cls() + hdr.version = bitstrm.read(2).uint + hdr.padding = bitstrm.read(1).bool + hdr.extension = bitstrm.read(1).bool + hdr.csrcCount = bitstrm.read(4).int + hdr.marker = bitstrm.read(1).bool + hdr.payloadType = bitstrm.read(7).int + hdr.sequenceNum = bitstrm.read(16).uintbe + hdr.timestamp = bitstrm.read(32).uintbe + hdr.ssrc = bitstrm.read(32).uintbe + if hdr.csrcCount: + hdr.csrcList = [ bitstrm.read(32).uintbe for _ in range(hdr.csrcCount) ] + if hdr.extension: + hdr.extensionType = bitstrm.read(16).uintbe + hdr.extensionLength = bitstrm.read(16).uintbe + hdr.extensionWords = [ bitstrm.read(32).uintbe for _ in range(hdr.extensionLength) ] + return hdr @dataclass class SRCONFIG: - enabled: bool = False diegetic: bool = False yaw: bool = False pitch: bool = False @@ -124,7 +287,7 @@ class CMR: class SRINFO: bitrate: int = 0 diegetic: bool = False - transportCodec: SRCODEC = SRCODEC.NA + transportCodec: SRCODEC = SRCODEC.LCLD @dataclass class FRAME: @@ -136,6 +299,7 @@ class FRAME: timestamp: int = 0 au: bytes = field(default_factory=bytes) +#PI DATA STRUCTURES @dataclass class ORIENTATION: w: float = 0.0 @@ -143,15 +307,73 @@ class ORIENTATION: y: float = 0.0 z: float = 0.0 +@dataclass +class POSITION: + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + +class ISM_POSITIONS: + positions: list[POSITION] + +@dataclass +class AUDIO_DESCRIPTION: + isSpeech: bool = False + isMusic: bool = False + isAmbiance: bool = False + isEditable: bool = False + isBinaural: bool = False + +@dataclass +class DYNAMIC_AUDIO_SUPPRESSION: + preferSpeech: bool = False + preferMusic: bool = False + preferAmbiance: bool = False + level: SUPPRESSION_LEVEL = SUPPRESSION_LEVEL.SUPPRESSION_LEVEL_MAX + +@dataclass +class DIEGETIC_TYPE: + isDigetic: list[bool] + +@dataclass +class ACOUSTIC_ENVIRONMENT: + aeid: int = 0 + rt60: tuple[float, float, float] = () + dsr: tuple[float, float, float] = () + dim: tuple[float, float, float] = () + abscoeff: tuple[float, float, float, float, float, float] = () + @dataclass class PIDATA: timestamp: int = 0 type: str = "NO_PI_DATA" data: any = None +MAX_PACKED_PI_SIZE = 32 ivasBitrates = [13200, 16400, 24400, 32000, 48000, 64000, 80000, 96000, 128000, 160000, 192000, 256000, 384000, 512000, -1, 5200] evsBitrates = [5900, 7200, 8000, 9600, 13200, 16400, 24400, 32000, 48000, 64000, 96000, 128000, 2400, -1, -1, -1] amrwbBitrates = [6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850, 1750, -1, -1, -1, -1, -1, -1] +requestBitratesForCodec = {CODECS.AMRWB: amrwbBitrates[0:9], CODECS.EVS: evsBitrates[0:12], CODECS.IVAS: ivasBitrates[0:14]} +rt60Value = [0.01, 0.0126, 0.0159, 0.02, 0.0252, 0.0317, 0.04, 0.0504, 0.0635, 0.08, 0.1008, 0.1270, 0.16, 0.2016, 0.2540, 0.32, 0.4032, + 0.5080, 0.64, 0.8063, 1.0159, 1.28, 1.6127, 2.0319, 2.56, 3.2254, 4.0637, 5.12, 6.4508, 8.1275, 10.24, 12.9016 ] +dsrValue = [ -20.0, -21.0, -22.0, -23.0, -24.0, -25.0, -26.0, -27.0, -28.0, -29.0, -30.0, -31.0, -32.0, -33.0, -34.0, -35.0, -36.0, -37.0, + -38.0, -39.0, -40.0, -41.0, -42.0, -43.0, -44.0, -45.0, -46.0, -47.0, -48.0, -49.0, -50.0, -51.0, -52.0, -53.0, -54.0, -55.0, + -56.0, -57.0, -58.0, -59.0, -60.0, -61.0, -62.0, -63.0, -64.0, -65.0, -66.0, -67.0, -68.0, -69.0, -70.0, -71.0, -72.0, -73.0, + -74.0, -75.0, -76.0, -77.0, -78.0, -79.0, -80.0, -81.0, -82.0, -83.0 ] +roomDimensionValue = [0.5, 0.707, 1.0, 1.4141, 2.0, 2.8282, 4.0, 5.6568, 8.0, 11.314, 16.0, 22.627, 32.0, 45.255, 64.0, 90.51] +absorptionCoeffValues = [0.0800, 0.1656, 0.3430, 0.7101] +codedFormats = list(FORMATS) +codedSubFormats = list(SUBFORMATS) +PiTypeNames = list(PIDATAS) + +def mapNearestIndex(table: list, val: float) -> int: + for idx, entry in enumerate(table): + if abs(entry) >= abs(val): + return idx + return len(table) - 1 + +getListIndex = lambda mylist, val: mylist.index(val) if val in mylist else -1 + cmrLookup = [ CMR(bandwidth=BANDWIDTH.NB, codec=CODECS.EVS, startIdx=0, endIdx=7, bitrates = evsBitrates), #000 = NB-EVS CMR(bandwidth=BANDWIDTH.WB, codec=CODECS.AMRWB, startIdx=0, endIdx=9, bitrates = amrwbBitrates), #001 = AMRWB IO @@ -160,74 +382,225 @@ cmrLookup = [ CMR(bandwidth=BANDWIDTH.FB, codec=CODECS.EVS, startIdx=5, endIdx=12, bitrates = evsBitrates), #100 = FB-EVS CMR(bandwidth=BANDWIDTH.WB, codec=CODECS.EVS, startIdx=0, endIdx=0, bitrates = []), #101 = WB-CA CMR(bandwidth=BANDWIDTH.SWB, codec=CODECS.EVS, startIdx=0, endIdx=0, bitrates = []), #110 = SWB-CA - CMR(bandwidth=BANDWIDTH.NREQ, codec=CODECS.IVAS, startIdx=0, endIdx=14, bitrates = ivasBitrates), #111 = IVAS + CMR(bandwidth=NO_REQ, codec=CODECS.IVAS, startIdx=0, endIdx=14, bitrates = ivasBitrates), #111 = IVAS ] -codedFormats = ["Stereo", "SBA", "MASA", "ISM", "MC", "OMASA", "OSBA", "NO_REQ"] -codedSubFormats = [ - "FOA planar", "HOA2 planar", "HOA3 planar", "FOA", "HOA2", "HOA3", "MASA1", "MASA2", "ISM1", - "ISM2", "ISM3", "ISM4", "ISM1 extended metadata", "ISM2 extended metadata", - "ISM3 extended metadata", "ISM4 extended metadata", "MC 5.1", "MC 7.1", "MC 5.1.2", "MC 5.1.4", - "MC 7.1.4", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", - "Reserved", "Reserved", "Reserved", "Reserved", "OMASA ISM1 1TC", "OMASA ISM2 1TC", - "OMASA ISM3 1TC", "OMASA ISM4 1TC", "OMASA ISM1 2TC", "OMASA ISM2 2TC", "OMASA ISM3 2TC", - "OMASA ISM4 2TC", "OSBA ISM1 FOA planar", "OSBA ISM2 FOA planar", "OSBA ISM3 FOA planar", - "OSBA ISM4 FOA planar", "OSBA ISM1 FOA", "OSBA ISM2 FOA", "OSBA ISM3 FOA", "OSBA ISM4 FOA", - "OSBA ISM1 HOA2 planar", "OSBA ISM2 HOA2 planar", "OSBA ISM3 HOA2 planar", "OSBA ISM4 HOA2 planar", - "OSBA ISM1 HOA2", "OSBA ISM2 HOA2", "OSBA ISM3 HOA2", "OSBA ISM4 HOA2", "OSBA ISM1 HOA3 planar", - "OSBA ISM2 HOA3 planar", "OSBA ISM3 HOA3 planar", "OSBA ISM4 HOA3 planar", "OSBA ISM1 HOA3", - "OSBA ISM2 HOA3", "OSBA ISM3 HOA3", "OSBA ISM4 HOA3"] -PiTypeNames = [ - "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", "RESERVED14", - "RESERVED15","PLAYBACK_DEVICE_ORIENTATION", "HEAD_ORIENTATION", "LISTENER_POSITION", "DYNAMIC_AUDIO_SUPPRESSION", - "AUDIO_FOCUS_DIRECTION", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN", "R_ISM_ORIENTATION", "R_ISM_POSITION", "R_ISM_DIRECTION", - "RESERVED27", "RESERVED28", "RESERVED29", "RESERVED30", "NO_PI_DATA" -] +q15 = lambda x : int(min(32767.0, max(-32768.0, x * 32768.0))) def unpackUnsupported(bitstrm: ConstBitStream, piSize: int) -> any: #assert False, "Unsupported PI Data" return base64.b64encode(bitstrm.read(piSize * 8).tobytes()).decode('utf-8') +def packUnsupported(bitstrm: ConstBitStream, data: any) -> any: + assert False, f"unsupported PI Data of type : {type(data)}" + def unpackNoPiData(bitstrm: ConstBitStream, piSize: int) -> None: assert piSize == 0, "NO_PI_DATA should be 0 size" +def packNoPiData(bitstrm: BitStream, data: any = None): + pass + +def unpackOrientations(bitstrm: ConstBitStream, piSize: int) -> list[ORIENTATION]: + assert (piSize % 8) == 0 and piSize <= 32, "Incorrect PI Data Size for list[ORIENTATION]" + orientations = list() + while piSize > 0: + w = bitstrm.read(16).int / 32768.0 + x = bitstrm.read(16).int / 32768.0 + y = bitstrm.read(16).int / 32768.0 + z = bitstrm.read(16).int / 32768.0 + orientations.append(ORIENTATION(w, x, y, z)) + piSize -= 8 + return orientations + +def packOrientations(bitstrm: BitStream, data: any): + assert type(data) == list, "Orientation PI Data expects a data of type list" + for orientation in cast(list, data): + assert type(orientation) == ORIENTATION, "Orientation PI Data expects a data of type list[ORIENTATION]" + bitstrm.append(f'intbe:16={q15(orientation.w)}') + bitstrm.append(f'intbe:16={q15(orientation.x)}') + bitstrm.append(f'intbe:16={q15(orientation.y)}') + bitstrm.append(f'intbe:16={q15(orientation.z)}') + +def unpackPositions(bitstrm: ConstBitStream, piSize: int) -> list[POSITION]: + assert piSize <= 24 and (piSize % 6) == 0, "Incorrect PI Data Size for Positions" + positions = list() + while piSize > 0: + x = bitstrm.read(16).int / 100.0 + y = bitstrm.read(16).int / 100.0 + z = bitstrm.read(16).int / 100.0 + positions.append(POSITION(x, y, z)) + piSize -= 6 + return positions + +def packPositions(bitstrm: BitStream, data: any): + assert type(data) == list, "Position PI Data expects a data of type list" + positions = cast(list, data) + assert len(positions) <= 4, "Max one position per ISM object" + for position in positions: + assert type(position) == POSITION, "Position PI Data expects a data of type list[POSITIONS]" + bitstrm.append(f'intbe:16={q15(position.x / 327.68)}') + bitstrm.append(f'intbe:16={q15(position.y / 327.68)}') + bitstrm.append(f'intbe:16={q15(position.z / 327.68)}') + def unpackOrientation(bitstrm: ConstBitStream, piSize: int) -> ORIENTATION: - assert piSize == 8, "Incorrect PI Data Size for Orientation" - w = bitstrm.read(16).int / 32768.0 - x = bitstrm.read(16).int / 32768.0 - y = bitstrm.read(16).int / 32768.0 - z = bitstrm.read(16).int / 32768.0 - return ORIENTATION(w, x, y, z) + assert piSize == 8, "Incorrect PI Data Size for ORIENTATION" + orientations = unpackOrientations(bitstrm, piSize) + assert len(orientations) == 1 + return orientations[0] + +def packOrientation(bitstrm: BitStream, data: any): + assert type(data) == ORIENTATION, "Orientation PI Data expects a data of type ORIENTATION" + orientation = cast(ORIENTATION, data) + packOrientations(bitstrm, [orientation]) + +def unpackPosition(bitstrm: ConstBitStream, piSize: int) -> POSITION: + assert piSize == 6, "Incorrect PI Data Size for POSITION" + positions = unpackPositions(bitstrm, piSize) + assert len(positions) == 1 + return positions[0] + +def packPosition(bitstrm: BitStream, data: any): + assert type(data) == POSITION, "Position PI Data expects a data of type POSITION" + position = cast(POSITION, data) + packPositions(bitstrm, [position]) + +def unpackAudioDescription(bitstrm: ConstBitStream, piSize: int) -> list[AUDIO_DESCRIPTION]: + assert piSize <= 5, "Incorrect PI Data Size for AUDIO_DESCRIPTION" + ad = list() + for byte in range(piSize): + V = bitstrm.read(1).bool + M = bitstrm.read(1).bool + A = bitstrm.read(1).bool + E = bitstrm.read(1).bool + B = bitstrm.read(1).bool + _ = bitstrm.read(3) + ad.append(AUDIO_DESCRIPTION(isSpeech=V, isMusic=M, isAmbiance=A, isEditable=E, isBinaural=B)) + return ad + +def packAudioDescription(bitstrm: BitStream, data: any): + assert type(data) == list, "Audio Description PI Data expects a data of type list[AUDIO_DESCRIPTION]" + for desc in cast(list, data): + assert type(desc) == AUDIO_DESCRIPTION, "Audio Description PI Data expects a data of type list[AUDIO_DESCRIPTION]" + ad = cast(AUDIO_DESCRIPTION, desc) + bitstrm.append(f'bool={ad.isSpeech}') + bitstrm.append(f'bool={ad.isMusic}') + bitstrm.append(f'bool={ad.isAmbiance}') + bitstrm.append(f'bool={ad.isEditable}') + bitstrm.append(f'bool={ad.isBinaural}') + bitstrm.append(f'uint:3=0') + +def unpackDAS(bitstrm: ConstBitStream, piSize: int) -> list[AUDIO_DESCRIPTION]: + assert piSize == 2, "Incorrect PI Data Size for DYNAMIC_AUDIO_SUPPRESSION" + V = bitstrm.read(1).bool + M = bitstrm.read(1).bool + A = bitstrm.read(1).bool + _ = bitstrm.read(5) + SLI = bitstrm.read(4).uint + _ = bitstrm.read(4) + return DYNAMIC_AUDIO_SUPPRESSION(preferSpeech=V, preferMusic=M, preferAmbiance=A, level=SLI) + +def packDAS(bitstrm: BitStream, data: any): + assert type(data) == DYNAMIC_AUDIO_SUPPRESSION, "Dynamic Audio Suppression PI Data expects a data of type DYNAMIC_AUDIO_SUPPRESSION" + das = cast(DYNAMIC_AUDIO_SUPPRESSION, data) + bitstrm.append(f'bool={das.preferSpeech}') + bitstrm.append(f'bool={das.preferMusic}') + bitstrm.append(f'bool={das.preferAmbiance}') + bitstrm.append(f'uint:5=0') + bitstrm.append(f'uint:4={das.level}') + bitstrm.append(f'uint:4=0') + +def unpackDiegetic(bitstrm: ConstBitStream, piSize: int) -> DIEGETIC_TYPE: + assert piSize == 1, "Incorrect PI Data Size for DIEGETIC_TYPE" + digType = list() + for _ in range(5): # no way to know how many bits are valid bits, so all 5 read + digType.append(bitstrm.read(1).bool) + bitstrm.bytealign() + return DIEGETIC_TYPE(isDigetic=digType) + +def packDiegetic(bitstrm: BitStream, data: any): + assert type(data) == DIEGETIC_TYPE, "Diegetic type PI Data expects a data of type DIEGETIC_TYPE" + diegetic = cast(DIEGETIC_TYPE, data) + assert len(diegetic.isDigetic) <= 5, "Maximum 1 bit per object + 1 bit for SBA/MASA is required (max 5)" + for isDigetic in diegetic.isDigetic: + bitstrm.append(f'bool={isDigetic}') + nPad = 8 - (bitstrm.pos % 8) + if nPad > 0: + bitstrm.append(f'uint:{nPad}=0') + +def unpackAcousticEnv(bitstrm: ConstBitStream, piSize: int) -> DIEGETIC_TYPE: + assert piSize == 1 or piSize == 5 or piSize == 8, "Incorrect PI Data Size for ACOUSTIC_ENVIRONMENT" + rt60 = list() + dsr = list() + dim = list() + absCoeff = list() + + if piSize == 1: + bitstrm.read(1) + + aeid = bitstrm.read(7).uint + + if piSize >= 5: + for _ in range(3): + rt60.append(rt60Value[bitstrm.read(5).uint]) + dsr.append(dsrValue[bitstrm.read(6).uint]) + if piSize == 8: + for _ in range(3): + dim.append(roomDimensionValue[bitstrm.read(4).uint]) + for _ in range(6): + absCoeff.append(absorptionCoeffValues[bitstrm.read(2).uint]) + + return ACOUSTIC_ENVIRONMENT(aeid=aeid, rt60=tuple(rt60), dsr=tuple(dsr), dim=tuple(dim), abscoeff=tuple(absCoeff)) + +def packAcousticEnv(bitstrm: BitStream, data: any): + assert type(data) == ACOUSTIC_ENVIRONMENT, "Diegetic type PI Data expects a data of type ACOUSTIC_ENVIRONMENT" + aenv = cast(ACOUSTIC_ENVIRONMENT, data) + if not aenv.rt60 and not aenv.dsr: + bitstrm.append(f'uint:8={aenv.aeid % 128}') + else: + assert len(aenv.rt60) == 3 and len(aenv.dsr) == 3, "Lo, Mi, Hi only required for RT60 and DSR values" + bitstrm.append(f'uint:7={aenv.aeid % 128}') + for n in range(3): + rt60 = mapNearestIndex(rt60Value, aenv.rt60[n]) + dsr = mapNearestIndex(dsrValue, aenv.dsr[n]) + bitstrm.append(f'uint:5={rt60}') + bitstrm.append(f'uint:6={dsr}') + if aenv.abscoeff and aenv.dim: + assert len(aenv.abscoeff) == 6 and len(aenv.dim) == 3 + for n in range(3): + dim = mapNearestIndex(roomDimensionValue, aenv.dim[n]) + bitstrm.append(f'uint:4={dim}') + for n in range(6): + absCoeff = mapNearestIndex(absorptionCoeffValues, aenv.abscoeff[n]) + bitstrm.append(f'uint:2={absCoeff}') + PIDataUnpacker = [ unpackOrientation, # SCENE_ORIENTATION, unpackOrientation, # DEVICE_ORIENTATION_COMPENSATED, unpackOrientation, # DEVICE_ORIENTATION_UNCOMPENSATED - unpackUnsupported, # ACOUSTIC_ENVIRONMENT - unpackUnsupported, # AUDIO_DESCRIPTION + unpackAcousticEnv, # ACOUSTIC_ENVIRONMENT + unpackAudioDescription, # AUDIO_DESCRIPTION unpackUnsupported, # ISM_NUM unpackUnsupported, # ISM_ID unpackUnsupported, # ISM_GAIN - unpackUnsupported, # ISM_ORIENTATION - unpackUnsupported, # ISM_POSITION + unpackOrientations,# ISM_ORIENTATION + unpackPositions, # ISM_POSITION unpackUnsupported, # ISM_DISTANCE_ATTENUATION unpackUnsupported, # ISM_DIRECTIVITY - unpackUnsupported, # DIEGETIC_TYPE + unpackDiegetic, # DIEGETIC_TYPE unpackUnsupported, # RESERVED13 unpackUnsupported, # RESERVED14 unpackUnsupported, # RESERVED15 - unpackUnsupported, # PLAYBACK_DEVICE_ORIENTATION - unpackUnsupported, # HEAD_ORIENTATION - unpackUnsupported, # LISTENER_POSITION - unpackUnsupported, # DYNAMIC_AUDIO_SUPPRESSION - unpackUnsupported, # AUDIO_FOCUS_DIRECTION + unpackOrientation, # PLAYBACK_DEVICE_ORIENTATION + unpackOrientation, # HEAD_ORIENTATION + unpackPosition, # LISTENER_POSITION + unpackDAS, # DYNAMIC_AUDIO_SUPPRESSION + unpackOrientation, # AUDIO_FOCUS_DIRECTION unpackUnsupported, # PI_LATENCY unpackUnsupported, # R_ISM_ID unpackUnsupported, # R_ISM_GAIN - unpackUnsupported, # R_ISM_ORIENTATION - unpackUnsupported, # R_ISM_POSITION + unpackOrientation, # R_ISM_ORIENTATION + unpackPosition, # R_ISM_POSITION unpackUnsupported, # R_ISM_DIRECTION unpackUnsupported, # RESERVED27 unpackUnsupported, # RESERVED28 @@ -236,176 +609,498 @@ PIDataUnpacker = [ unpackNoPiData # NO_DATA ] +PIDataPacker = [ + packOrientation, # SCENE_ORIENTATION, + packOrientation, # DEVICE_ORIENTATION_COMPENSATED, + packOrientation, # DEVICE_ORIENTATION_UNCOMPENSATED + packAcousticEnv, # ACOUSTIC_ENVIRONMENT + packAudioDescription, # AUDIO_DESCRIPTION + packUnsupported, # ISM_NUM + packUnsupported, # ISM_ID + packUnsupported, # ISM_GAIN + packOrientations,# ISM_ORIENTATION + packPositions, # ISM_POSITION + packUnsupported, # ISM_DISTANCE_ATTENUATION + packUnsupported, # ISM_DIRECTIVITY + packDiegetic, # DIEGETIC_TYPE + packUnsupported, # RESERVED13 + packUnsupported, # RESERVED14 + packUnsupported, # RESERVED15 + packOrientation, # PLAYBACK_DEVICE_ORIENTATION + packOrientation, # HEAD_ORIENTATION + packPosition, # LISTENER_POSITION + packDAS, # DYNAMIC_AUDIO_SUPPRESSION + packOrientation, # AUDIO_FOCUS_DIRECTION + packUnsupported, # PI_LATENCY + packUnsupported, # R_ISM_ID + packUnsupported, # R_ISM_GAIN + packOrientation, # R_ISM_ORIENTATION + packPosition, # R_ISM_POSITION + packUnsupported, # R_ISM_DIRECTION + packUnsupported, # RESERVED27 + packUnsupported, # RESERVED28 + packUnsupported, # RESERVED29 + packUnsupported, # RESERVED30 + packNoPiData # NO_DATA +] + +def ReadG192Bitstream(g192File: Path) -> list[bytes]: + refPackets = list[bytes]() + with open(g192File, "rb") as fd: + refBitStrm = ConstBitStream(fd.read()) + while refBitStrm.pos < refBitStrm.len: + sync = hex(refBitStrm.read(16).intle) + nBits = refBitStrm.read(16).intle + assert sync == "0x6b21", "G192 syncword not found at start of packet" + writer = BitStream() + for _ in range(nBits): + bit = "0b1" if refBitStrm.read(16).uintle == 129 else "0b0" + writer.append(bit) + refPackets.append(writer.tobytes()) + return refPackets + +def unpackEBytes(bitstrm: ConstBitStream) -> tuple[bool, dict]: + piIndicated = False + requests = dict() + try: + if bitstrm.read(1).bool: + T = bitstrm.read(3).uint + BR = bitstrm.read(4).uint + if T in [5, 6]:#CA MODES + if BR < 8: + requests[REQUESTS.CODEC] = cmrLookup[T].codec + requests[REQUESTS.BR] = 13200 + requests[REQUESTS.CA] = BR + requests[REQUESTS.BW] = cmrLookup[T].bandwidth + else: + raise Exception("Unsupported BR bits in CA Mode") + elif T == 7: #IVAS + if BR < 14 : + requests[REQUESTS.CODEC] = cmrLookup[T].codec + requests[REQUESTS.BR] = cmrLookup[T].bitrates[BR] + requests[REQUESTS.CA] = -1 + elif BR == 14 : + raise Exception("Reserved BR idx in IVAS EByte") + else: + if BR >= cmrLookup[T].startIdx and BR < cmrLookup[T].endIdx: + requests[REQUESTS.CODEC] = cmrLookup[T].codec + requests[REQUESTS.BR] = cmrLookup[T].bitrates[BR] + requests[REQUESTS.CA] = -1 + requests[REQUESTS.BW] = cmrLookup[T].bandwidth + else: + raise Exception("Reserved BR idx in {} EByte".format(cmrLookup[T].codec)) + #Try to get all subsequent E-bytes + while bitstrm.read(1).bool: + ET = bitstrm.read(3).uint + if ET == 0 : + supportedBW = [BANDWIDTH.WB, BANDWIDTH.SWB, BANDWIDTH.FB, BANDWIDTH.NREQ] + reserved = bitstrm.read(2) + BW = bitstrm.read(2).uint + requests[REQUESTS.BW] = supportedBW[BW] + elif ET == 1 : + S = bitstrm.read(1).bool + FMT = bitstrm.read(3).uint + if not S: + requests[REQUESTS.FMT] = codedFormats[FMT] + requests[REQUESTS.SUBFMT] = NO_REQ + else: + reserved = bitstrm.read(2) + subFMT = bitstrm.read(6).uint + requests[REQUESTS.FMT] = NO_REQ + requests[REQUESTS.SUBFMT] = codedSubFormats[subFMT] + elif ET == 2: + reserved = bitstrm.read(4) + piIndicated = True + elif ET == 3: + D = bitstrm.read(1).bool + Y = bitstrm.read(1).bool + P = bitstrm.read(1).bool + R = bitstrm.read(1).bool + requests[REQUESTS.SRCFG] = SRCONFIG(diegetic=D, yaw=Y, pitch=P, roll=R) + else: + reserved = bitstrm.read(4) + raise Exception("Unsupported subsequent EByte with ET={}".format(ET)) + except ReadError as error: + print ("Underflow in E-Bytes parsing during unpacking, error = {}".format(error)) + return piIndicated, requests + +def packEBytes(bitstrm: BitStream, requests: dict[str: any], piIndication: bool = False): + codec = requests[REQUESTS.CODEC] if REQUESTS.CODEC in requests.keys() else NO_REQ + bitrate = requests[REQUESTS.BR] if REQUESTS.BR in requests.keys() else 0 + bandwidth = requests[REQUESTS.BW] if REQUESTS.BW in requests.keys() else NO_REQ + camode = requests[REQUESTS.CA] if REQUESTS.CA in requests.keys() else NO_REQ + format = requests[REQUESTS.FMT] if REQUESTS.FMT in requests.keys() else NO_REQ + subFormat = requests[REQUESTS.SUBFMT] if REQUESTS.SUBFMT in requests.keys() else NO_REQ + srcfg = SRCONFIG(requests[REQUESTS.SRCFG]) if REQUESTS.SRCFG in requests.keys() else None + + # Check if any request needs to be sent + isInitialEByteNeeded = piIndication or bitrate != 0 or bandwidth != NO_REQ or camode != NO_REQ or \ + format != NO_REQ or subFormat != NO_REQ or srcfg != None + + if not isInitialEByteNeeded: + return + + if camode != NO_REQ: + T = 6 if bandwidth == BANDWIDTH.SWB else 5 + BR = getListIndex(list(CAMODE), camode) + assert BR > 0, "Channel Aware Mode not supported" + elif bitrate == 0: + T = 7 + BR = 15 + else: + mapBandwidthToTBit = {BANDWIDTH.NB: 0, BANDWIDTH.WB: 2, BANDWIDTH.SWB: 3, BANDWIDTH.FB: 4, NO_REQ: 2}[bandwidth] + T = {CODECS.AMRWB: 1, CODECS.IVAS: 7, CODECS.EVS: mapBandwidthToTBit} [codec] + BR = getListIndex(requestBitratesForCodec[codec], bitrate) + assert BR >= cmrLookup [T].startIdx and BR < cmrLookup [T].endIdx, "EVS Bitrate Index and Bandwidth Combination cannot be requested" + + # Write the Initial E-Byte + bitstrm.append(f'bool={True}') #E-Byte H=1 + bitstrm.append(f'uint:3={T}') + bitstrm.append(f'uint:4={BR}') + + # Subsequent E-bytes follow + if piIndication: + bitstrm.append('hex:8=A0') + + if codec != CODECS.IVAS: + return + + # Bandwidth E-Byte + if bandwidth != NO_REQ: + bw = {BANDWIDTH.WB: 0, BANDWIDTH.SWB: 1, BANDWIDTH.FB: 2}[bandwidth] + bitstrm.append('hex:4=8') + bitstrm.append(f'uint:4={bw}') + + # Coded Format/SubFormat Request E-Byte + if subFormat in SUBFORMATS: + subFmt = getListIndex(codedSubFormats, subFormat) + bitstrm.append('hex:8=9F') #S=0, FMT=111 + bitstrm.append(f'uint:8={subFmt}') + elif format in FORMATS: + fmt = getListIndex(codedFormats, format) + bitstrm.append('hex:4=9') + bitstrm.append(f'bool={False}') # S=0 + bitstrm.append(f'uint:3={fmt}') + + # SR Config E-Byte + with srcfg: + bitstrm.append('hex:4=B') + bitstrm.append(f'bool={srcfg.diegetic}') + bitstrm.append(f'bool={srcfg.yaw}') + bitstrm.append(f'bool={srcfg.pitch}') + bitstrm.append(f'bool={srcfg.roll}') + +def unpackAUFrames(bitstrm: ConstBitStream, frameList: list[FRAME]): + try: + #Unpack Frame AUs here + for (idx, frm) in enumerate(frameList): + auSize = (frm.frmSizeBits + 7) // 8 # Zero padded bytes in amrwb_io mode + frm.au = bitstrm.read(auSize * 8).tobytes() + except ReadError as error: + print ("Underflow in AU Frames parsing during unpacking, error = {}".format(error)) + +def packAUFrames(bitstrm: BitStream, frameList: list[FRAME]): + for frm in frameList: + bitstrm.append(frm.au) + bitstrm.bytealign() + +def unpackToCBytes(bitstrm: ConstBitStream, rtpTimestamp: int, Codec: CODECS) -> list[FRAME]: + F = True + frmList = list() + + try: + while F: + F = bitstrm.read(1).bool + FT = bitstrm.read(2).uint + BR = bitstrm.read(4).uint + frm = FRAME(timestamp=rtpTimestamp) + if FT == 1 : + frm.codec = CODECS.IVAS + if BR == 14 : + supportedBitrates = [-1, 256000, 384000, 512000] + reserved = bitstrm.read(1) + D = bitstrm.read(1).bool + C = bitstrm.read(1).bool + SR_BR = bitstrm.read(2).uint + reserved = bitstrm.read(3) + if SR_BR == 0: + raise Exception("Reserved bitrate in SR Config ToC Indicated") + frm.srInfo = SRINFO(bitrate=supportedBitrates[SR_BR], diegetic=D, + transportCodec= SRCODEC.LC3PLUS if C else SRCODEC.LCLD) + else: + frm.bitrate = ivasBitrates[BR] + elif FT == 0: + # Codec switch only if not NO_DATA_FRAME, as IVAS/EVS signal using this + frm.codec = CODECS.EVS if BR != 15 else Codec + if BR == 13: + raise Exception("Reserved bitrate in EVS ToC Indicated") + frm.speechLost = (BR == 14) + frm.bitrate = evsBitrates[BR] if BR < 13 else 0 + else: + frm.codec = CODECS.AMRWB + if BR >= 10 and BR <= 13: + raise Exception("Reserved bitrate in AMRWB-IO ToC Indicated") + frm.speechLost = (BR == 14) or (FT == 2) + frm.bitrate = amrwbBitrates[BR] if BR < 10 else 0 + frm.frmSizeBits = frm.bitrate // 50 + rtpTimestamp += 320 + frmList.append(frm) + if F: + #skip all frame specific E-bytes before next header + while (bitstrm.read(1).bool): + print("Skipping unsupported frame specific subsequent Ebytes") + reserved = bitstrm.read(7) + except ReadError as error: + print ("Underflow in ToC parsing during unpacking, error = {}".format(error)) + + return frmList + +def packToCBytes(bitstrm: BitStream, frameList: list[FRAME]): + numFrames = len(frameList) + + for idx, frame in enumerate(frameList): + F = (idx != (numFrames - 1)) + FT = 0 + BR = 0 + if frame.frmSizeBits == 0: + FT = 3 if frame.codec == CODECS.AMRWB else 0 # Only AMRWB or EVS support 0 frame case + BR = 14 if frame.speechLost else 15 #SPEECH_LOST or NO_DATA + elif frame.codec == CODECS.AMRWB: + FT = 3 + BR = getListIndex(amrwbBitrates[0:10], frame.bitrate) + elif frame.codec == CODECS.IVAS: + FT = 1 + BR = 14 if frame.srInfo else getListIndex(ivasBitrates, frame.bitrate) + else: + FT = 0 + BR = getListIndex(evsBitrates[0:13], frame.bitrate) + + assert BR >= 0, "Index for table not found" + + bitstrm.append(f'bool={False}') #ToC 0 bit + bitstrm.append(f'bool={F}') #Frame follows bit + bitstrm.append(f'uint:2={FT}') #Frame Type + bitstrm.append(f'uint:4={BR}') #Frame Type + if frame.srInfo and frame.codec == CODECS.IVAS: + SRBR = (frame.srInfo.bitrate//128000) - 1 + bitstrm.append(f'bool={False}') #ToC 0 bit + bitstrm.append(f'bool={frame.srInfo.diegetic}') + bitstrm.append(f'bool={frame.srInfo.transportCodec == SRCODEC.LC3PLUS}') + bitstrm.append(f'uint:2={SRBR}') + bitstrm.append('uint:3=0') + +def unpackPiData(bitstrm: ConstBitStream, rtpTimestamp: int) -> list[PIDATA]: + piDataList = list[PIDATA]() + try: + # PI Data if Indicated + PF = True + piTimeStamps = rtpTimestamp + while PF : + PF = bitstrm.read(1).bool + PM = bitstrm.read(2).uint + PiType = bitstrm.read(5).uint + PiSize = 0 + byte = 255 + while byte == 255: + byte = bitstrm.read(8).uint + PiSize += byte + + PiFrameData = PIDataUnpacker[PiType](bitstrm, PiSize) + + if PiTypeNames[PiType] != PIDATAS.NO_PI_DATA: + piDataList.append( + PIDATA(timestamp=piTimeStamps if PM != 3 else rtpTimestamp, # Generic Pi has base timestamp + type=PiTypeNames[PiType], + data=PiFrameData)) + piTimeStamps += 320 if PM == 2 else 0 + except ReadError as error: + print ("Underflow before completion of unpacking, error = {}".format(error)) + return piDataList + +def packPiData(bitstrm: BitStream, rtpTimestampBounds: tuple[int, int], piDataList: list[PIDATA]): + # sort the piDataList by timestamp and eliminate data where timestamp is OOB for this packet + piDataList = [data for data in piDataList if (data.timestamp >= rtpTimestampBounds[0] and data.timestamp < rtpTimestampBounds[1])] + sorted(piDataList, key=lambda data: data.timestamp) + numPiData = len(piDataList) + + # Group PI data by timestamps + piDataDict = dict[int, list[PIDATA]]() + for data in piDataList: + ts = (data.timestamp // 320) * 320 + if ts not in piDataDict.keys(): + piDataDict[ts] = list() + piDataDict[ts].append(data) + + curTimestamp = rtpTimestampBounds[0] + for ts, dataList in piDataDict.items(): + while curTimestamp < ts: + # Inset NO_PI_DATA till current Timestamp is reached + bitstrm.append('hex:16=DF00') #PI Frame follows, Last PI header for this frame, NO_PI_DATA, size=0 + curTimestamp += 320 + + for idx, data in enumerate(dataList): + pack = BitStream() + PM = 2 if idx == len(dataList) - 1 else 1 + PF = 0 if numPiData == 1 else 1 + TYPE = PiTypeNames.index(data.type) + PIDataPacker[TYPE](pack, data.data) + assert (pack.pos % 8) == 0, "PI data must be byte aligned" + SIZE = pack.pos // 8 + assert SIZE < MAX_PACKED_PI_SIZE, f"Packed PI Size should be less than MAX_PACKED_PI_SIZE ({MAX_PACKED_PI_SIZE})" + + bitstrm.append(f'uint:1={PF}') + bitstrm.append(f'uint:2={PM}') + bitstrm.append(f'uint:5={TYPE}') + bitstrm.append(f'uint:8={SIZE}') + bitstrm.append(pack) + numPiData -= 1 + curTimestamp += 320 + assert numPiData == 0, "Not all PI data was packed due to internal error" + + @dataclass class IvasPayload: - lastCodec: CODECS = CODECS.IVAS # Track last frame's codec frameList: list[FRAME] = field(default_factory=list) piDataList: list[PIDATA] = field(default_factory=list) requests: dict [str, any] = field(default_factory=dict) - def __init__(self, bitstrm: ConstBitStream, rtpTimestamp, lastCodec: CODECS): - self.lastCodec = lastCodec - self.frameList = list[FRAME]() - self.piDataList = list[PIDATA]() - self.requests = dict() + def pack(self, bitstrm: BitStream) -> int: + piIndication = len(self.piDataList) > 0 + numFrames = len(self.frameList) + packEBytes(bitstrm, self.requests, piIndication) + packToCBytes(bitstrm, self.frameList) + packAUFrames(bitstrm, self.frameList) + if piIndication: + packPiData(bitstrm, (self.frameList[0].timestamp, self.frameList[-1].timestamp + 320), self.piDataList) + return numFrames - try: - piIndicated = False - if bitstrm.read(1).bool: - T = bitstrm.read(3).uint - BR = bitstrm.read(4).uint - - if T in [5, 6]:#CA MODES - if BR < 8: - self.requests[REQUESTS.CODEC] = cmrLookup[T].codec - self.requests[REQUESTS.BR] = 13200 - self.requests[REQUESTS.CA] = BR - self.requests[REQUESTS.BW] = cmrLookup[T].bandwidth - else: - raise Exception("Unsupported BR bits in CA Mode") - elif T == 7: #IVAS - if BR < 14 : - self.requests[REQUESTS.CODEC] = cmrLookup[T].codec - self.requests[REQUESTS.BR] = cmrLookup[T].bitrates[BR] - self.requests[REQUESTS.CA] = -1 - elif BR == 14 : - raise Exception("Reserved BR idx in IVAS EByte") - else: - if BR >= cmrLookup[T].startIdx and BR < cmrLookup[T].endIdx: - self.requests[REQUESTS.CODEC] = cmrLookup[T].codec - self.requests[REQUESTS.BR] = cmrLookup[T].bitrates[BR] - self.requests[REQUESTS.CA] = -1 - self.requests[REQUESTS.BW] = cmrLookup[T].bandwidth - else: - raise Exception("Reserved BR idx in {} EByte".format(cmrLookup[T].codec)) + @classmethod + def unpack(cls, bitstrm: ConstBitStream, rtpTimestamp: int, Codec: CODECS): + # Unpack the E-bytes + piIndicated, requests = unpackEBytes(bitstrm) - #Try to get all subsequent E-bytes - while bitstrm.read(1).bool: - ET = bitstrm.read(3).uint - if ET == 0 : - supportedBW = [BANDWIDTH.WB, BANDWIDTH.SWB, BANDWIDTH.FB, BANDWIDTH.NREQ] - reserved = bitstrm.read(2) - BW = bitstrm.read(2).uint - self.requests[REQUESTS.BW] = supportedBW[BW] - elif ET == 1 : - S = bitstrm.read(1).bool - FMT = bitstrm.read(3).uint - if not S: - self.requests[REQUESTS.FMT] = codedFormats[FMT] - self.requests[REQUESTS.SUBFMT] = "NO_REQ" - else: - reserved = bitstrm.read(2) - subFMT = bitstrm.read(6).uint - self.requests[REQUESTS.FMT] = "NO_REQ" - self.requests[REQUESTS.SUBFMT] = codedSubFormats[subFMT] - elif ET == 2: - reserved = bitstrm.read(4) - piIndicated = True - elif ET == 3: - D = bitstrm.read(1).bool - Y = bitstrm.read(1).bool - P = bitstrm.read(1).bool - R = bitstrm.read(1).bool - self.requests[REQUESTS.SRCFG] = SRCONFIG(enabled=True, diegetic=D, yaw=Y, pitch=P, roll=R) - else: - reserved = bitstrm.read(4) - raise Exception("Unsupported subsequent EByte with ET={}".format(ET)) - - # ToC Byte parsing starts with 'F' bit as H bit is already read above - frameTimeStamps = rtpTimestamp - F = True - frmList = list() - while F: - F = bitstrm.read(1).bool - FT = bitstrm.read(2).uint - BR = bitstrm.read(4).uint - - frm = FRAME(timestamp=frameTimeStamps) - if FT == 1 : - frm.codec = CODECS.IVAS - if BR == 14 : - supportedBitrates = [-1, 256000, 384000, 512000] - reserved = bitstrm.read(1) - D = bitstrm.read(1).bool - C = bitstrm.read(1).bool - SR_BR = bitstrm.read(2).uint - reserved = bitstrm.read(3) - if SR_BR == 0: - raise Exception("Reserved bitrate in SR Config ToC Indicated") - frm.srInfo = SRINFO(bitrate=supportedBitrates[SR_BR], diegetic=D, - transportCodec= SRCODEC.LC3PLUS if C else SRCODEC.LCLD) - else: - frm.bitrate = ivasBitrates[BR] - elif FT == 0: - # Codec switch only if not NO_DATA_FRAME, as IVAS/EVS signal using this - frm.codec = CODECS.EVS if BR != 15 else self.lastCodec - if BR == 13: - raise Exception("Reserved bitrate in EVS ToC Indicated") - frm.speechLost = (BR == 14) - frm.bitrate = evsBitrates[BR] if BR < 13 else 0 - else: - frm.codec = CODECS.AMRWB - if BR >= 10 and BR <= 13: - raise Exception("Reserved bitrate in AMRWB-IO ToC Indicated") - frm.speechLost = (BR == 14) or (FT == 2) - frm.bitrate = amrwbBitrates[BR] if BR < 10 else 0 - frm.frmSizeBits = frm.bitrate // 50 - frameTimeStamps += 320 - frmList.append(frm) - - if F: - #skip all frame specific E-bytes before next header - while (bitstrm.read(1).bool): - print("Skipping unsupported frame specific subsequent Ebytes") - reserved = bitstrm.read(7) - - #Frame AUs here - for (idx, frm) in enumerate(frmList): - auSize = (frm.frmSizeBits + 7) // 8 # Zero padded bytes in amrwb_io mode - frm.au = bitstrm.read(auSize * 8).tobytes() - self.frameList.append(frm) - - # PI Data if Indicated - piTimeStamps = rtpTimestamp - PF = piIndicated - while PF : - PF = bitstrm.read(1).bool - PM = bitstrm.read(2).uint - PiType = bitstrm.read(5).uint - PiSize = 0 - byte = 255 - while byte == 255: - byte = bitstrm.read(8).uint - PiSize += byte - - PiFrameData = PIDataUnpacker[PiType](bitstrm, PiSize) - - self.piDataList.append( - PIDATA(timestamp=piTimeStamps if PM != 3 else rtpTimestamp, # Generic Pi has base timestamp - type=PiTypeNames[PiType], - data=PiFrameData)) - piTimeStamps += 320 if PM == 2 else 0 - except ReadError as error: - print ("Underflow before completion of unpacking, error = {}".format(error)) + # ToC Byte parsing starts with 'F' bit as H bit is already read for E-byte parsing + frameList = unpackToCBytes(bitstrm, rtpTimestamp, Codec) + + # Extract packed AU + unpackAUFrames(bitstrm, frameList) + + if piIndicated: + piDataList = unpackPiData(bitstrm, rtpTimestamp) + else: + piDataList = list() + + return cls(frameList=frameList, piDataList=piDataList, requests=requests) @dataclass class IvasPacket: hdr: RTPHDR = field(default_factory=RTPHDR) payload: IvasPayload = field(default_factory=IvasPayload) + def pack(self, bitstrm: BitStream) : + self.hdr.pack(bitstrm) + numFrames = self.payload.pack(bitstrm) + self.hdr.updateHeader(numFrames) + class IvasRtp: - def __init__(self): + def __init__(self, numFramesPerPacket = 4, codec: CODECS = CODECS.IVAS): + self.numFramesPerPacket = numFramesPerPacket self.packets = list[IvasPacket]() - self.lastCodec: CODECS = CODECS.IVAS # Track last frame's codec + self.Codec: CODECS = codec# Track last frame's codec + self.requests = dict() + self.piData = dict() def dumpToJSON(self, jsonFileName): with open(jsonFileName, "w") as fd: packets = list() for packet in self.packets: - packets.append(asdict(packet)) + packetDict = asdict(packet) + for frame in packetDict['payload']['frameList']: + frame['au'] = base64.b64encode(frame['au']).decode('utf-8') + packets.append(packetDict) json_output = json.dumps(packets, indent=4) fd.write(json_output) + def requestReader(self, timestamp: int) -> dict[str, any]: + tsList = sorted(self.requests.keys()) + if len(tsList) > 0: + lastTs = int(tsList[0]) + for ts in tsList: + if timestamp >= lastTs and timestamp < int(ts): + return self.requests[str(lastTs)] + lastTs = int(ts) + return dict() + + def piDataReader(self, startTimestamp: int, endTimestamp: int) -> list[PIDATA]: + + piDataList = list() + while startTimestamp < endTimestamp: + ts = str(startTimestamp) + if ts in self.piData.keys(): + for piTypes in self.piData[ts].keys(): + dataDict = self.piData[ts][piTypes] + if type(dataDict) != dict: + data = dataDict + elif piTypes == PIDATAS.ISM_ORIENTATION: + data = list() + for orientation in dataDict: + data.append(ORIENTATION(**orientation)) + elif "ORIENTATION" in piTypes or piTypes == PIDATAS.AUDIO_FOCUS_DIRECTION: + data = ORIENTATION(**dataDict) + elif piTypes == PIDATAS.ACOUSTIC_ENVIRONMENT: + data = ACOUSTIC_ENVIRONMENT(**dataDict) + elif piTypes == PIDATAS.AUDIO_DESCRIPTION: + data = list() + for desc in dataDict: + data.append(AUDIO_DESCRIPTION(**desc)) + elif piTypes == PIDATAS.DIEGETIC_TYPE: + data = DIEGETIC_TYPE(**dataDict) + elif piTypes == PIDATAS.LISTENER_POSITION or piTypes == PIDATAS.R_ISM_POSITION: + data = POSITION(**dataDict) + elif piTypes == PIDATAS.DYNAMIC_AUDIO_SUPPRESSION: + data = DYNAMIC_AUDIO_SUPPRESSION(**dataDict) + else: + assert False, "Unhandled PI Data" + piDataList.append(PIDATA(timestamp=startTimestamp, type=piTypes, data=data)) + startTimestamp += 320 + return piDataList + + def packG192File(self, g192File: Path, rtpDumpOut: Path, piData: dict = None, requestsData: dict = None): + packet = IvasPacket() + packet.hdr.sequenceNum=int("0xFFFF", 16) + packet.hdr.timestamp = 0 + packet.hdr.ssrc = int("0xDEADBEEF", 16) + + self.piData = piData + self.requests = requestsData + + timestamp = packet.hdr.timestamp + piTimestamps = 0 + with open(g192File, "rb") as fin: + with open(rtpDumpOut, "wb") as fout: + refBitStrm = ConstBitStream(fin.read()) + frames = list[FRAME]() + while refBitStrm.pos < refBitStrm.len: + sync = hex(refBitStrm.read(16).intle) + nBits = refBitStrm.read(16).intle + assert sync == "0x6b21", "G192 syncword not found at start of packet" + writer = BitStream() + for _ in range(nBits): + bit = "0b1" if refBitStrm.read(16).uintle == 129 else "0b0" + writer.append(bit) + frames.append(FRAME(codec=self.Codec, frmSizeBits=nBits, bitrate=nBits * 50, speechLost=False, timestamp=timestamp, au=writer.tobytes())) + if (len(frames) == self.numFramesPerPacket) or (refBitStrm.pos == refBitStrm.len): + rtpBitstrm = BitStream() + numFrames = len(frames) + packet.payload = IvasPayload(frameList=frames, piDataList=self.piDataReader(piTimestamps, piTimestamps + (numFrames * 320)), requests=self.requestReader(piTimestamps)) + packet.pack(bitstrm=rtpBitstrm) + fout.write(struct.pack('i', rtpBitstrm.bytepos)) + fout.write(rtpBitstrm.tobytes()) + frames = list() + piTimestamps += numFrames * 320 + timestamp += 320 + + def getPackets(self): return self.packets @@ -423,16 +1118,21 @@ class IvasRtp: def unpackPacket(self, packet) -> IvasPacket : bitStrm = ConstBitStream(packet) - hdr = RTPHDR(bitStrm) - payload = IvasPayload(bitStrm, rtpTimestamp=hdr.timestamp, lastCodec=self.lastCodec) - self.lastCodec = payload.frameList[-1].codec #Last Frame's codec for next frame for NO_DATA case + hdr = RTPHDR.unpack(bitStrm) + payload = IvasPayload.unpack(bitStrm, rtpTimestamp=hdr.timestamp, Codec=self.Codec) + self.Codec = payload.frameList[-1].codec #Last Frame's codec for next frame for NO_DATA case return IvasPacket(hdr=hdr, payload=payload) class ArgsParser: def __init__(self): self.parser = argparse.ArgumentParser() - self.parser.add_argument("-r", "--rtpdump", type=str, required=True, help="RTP Dump to unpack") + self.parser.add_argument("-r", "--rtpdump", type=str, default=None, help="RTP Dump to unpack") self.parser.add_argument("-j", "--json", type=str, default="unpack.json", help="Output unpacked RTP frames to JSON file") + self.parser.add_argument("-g", "--g192", type=str, default=None, help="G192 bitstream input for RTP Packing") + self.parser.add_argument("-f", "--framesPerPacket", type=int, default=1, help="Number of IVAS frames per RTP Packet") + self.parser.add_argument("-o", "--outrtpdump", type=str, default="output.rtpdump", help="Output RTP Dump file") + self.parser.add_argument("-p", "--piDataJson", type=str, default=None, help="piData to be packed") + self.parser.add_argument("-x", "--requestsJson", type=str, default=None, help="Requests to be packed") def parse(self): args = self.parser.parse_args() @@ -440,7 +1140,18 @@ class ArgsParser: if __name__ == "__main__": args = ArgsParser().parse() - rtp = IvasRtp() + rtp = IvasRtp(numFramesPerPacket=args.framesPerPacket) + if args.rtpdump: rtp.unpackFile(args.rtpdump) rtp.dumpToJSON(args.json) + elif args.g192: + piData = dict() + requestsData = dict() + if args.piDataJson: + with open(args.piDataJson) as f: + piData = json.load(f) + if args.requestsJson: + with open(args.requestsJson) as f: + requestsData = json.load(f) + rtp.packG192File(g192File=args.g192, rtpDumpOut=args.outrtpdump, piData=piData, requestsData=requestsData) diff --git a/tests/rtp/test_rtp.py b/tests/rtp/test_rtp.py index 00b4da5c1b..342e29c8b6 100644 --- a/tests/rtp/test_rtp.py +++ b/tests/rtp/test_rtp.py @@ -38,26 +38,29 @@ import pytest import csv import os import sys +import random from tempfile import TemporaryDirectory from pathlib import Path from ivasrtp import * -from bitstring import ConstBitStream, BitStream +import soundfile as sf +import numpy as np -THIS_PATH = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.join(os.path.dirname(THIS_PATH), "../../scripts")) +ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) +sys.path.append(ROOT_DIR) from tests.conftest import EncoderFrontend, DecoderFrontend @pytest.mark.parametrize("dtx", [False, True]) -@pytest.mark.parametrize("bitrate", [6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850]) +@pytest.mark.parametrize("bitrate", [6600, 12650, 23850]) @pytest.mark.parametrize("framesPerPacket", [1, 3, 8]) def test_rtp_bitstream_amrwb ( test_info, bitrate: int, dtx: bool, framesPerPacket: int, - dut_encoder_frontend: EncoderFrontend + dut_encoder_frontend: EncoderFrontend, + dut_decoder_frontend: DecoderFrontend ): run_rtp_bitstream_tests ( CODECS.AMRWB, @@ -67,11 +70,12 @@ def test_rtp_bitstream_amrwb ( "MONO", dtx, framesPerPacket, - dut_encoder_frontend + dut_encoder_frontend, + dut_decoder_frontend ) @pytest.mark.parametrize("dtx", [False, True]) -@pytest.mark.parametrize("bitrate", [7200, 8000, 9600, 13200, 16400, 24400, 32000, 48000, 64000, 96000, 128000]) +@pytest.mark.parametrize("bitrate", [9600, 24400, 128000]) @pytest.mark.parametrize("bandwidth", ["NB", "WB", "SWB", "FB"]) @pytest.mark.parametrize("caMode", ["OFF", "LO", "HI"]) @pytest.mark.parametrize("framesPerPacket", [1, 3, 8]) @@ -82,7 +86,8 @@ def test_rtp_bitstream_evs ( caMode: str, dtx: bool, framesPerPacket: int, - dut_encoder_frontend: EncoderFrontend + dut_encoder_frontend: EncoderFrontend, + dut_decoder_frontend: DecoderFrontend ): run_rtp_bitstream_tests ( CODECS.EVS, @@ -92,14 +97,14 @@ def test_rtp_bitstream_evs ( "MONO", dtx, framesPerPacket, - dut_encoder_frontend + dut_encoder_frontend, + dut_decoder_frontend ) -@pytest.mark.parametrize("bitrate", [13200, 24400, 80000, 512000]) +@pytest.mark.parametrize("bitrate", [24400, 80000, 512000]) @pytest.mark.parametrize("bandwidth", ["WB", "SWB", "FB"]) @pytest.mark.parametrize("format", ["STEREO", "SBA", "MC", "MASA"]) -#@pytest.mark.parametrize("bandwidth, format, bitrate", [("WB", "MASA", 13200)]) @pytest.mark.parametrize("framesPerPacket", [8]) def test_rtp_bitstream_ivas_nodtx ( test_info, @@ -107,7 +112,8 @@ def test_rtp_bitstream_ivas_nodtx ( bandwidth: str, format: str, framesPerPacket: int, - dut_encoder_frontend: EncoderFrontend + dut_encoder_frontend: EncoderFrontend, + dut_decoder_frontend: DecoderFrontend ): run_rtp_bitstream_tests ( CODECS.IVAS, @@ -117,20 +123,22 @@ def test_rtp_bitstream_ivas_nodtx ( format, False, framesPerPacket, - dut_encoder_frontend + dut_encoder_frontend, + dut_decoder_frontend ) @pytest.mark.parametrize("bitrate", [13200, 24400, 80000]) @pytest.mark.parametrize("bandwidth", ["WB", "SWB", "FB"]) @pytest.mark.parametrize("format", ["STEREO", "SBA"]) -@pytest.mark.parametrize("framesPerPacket", [1, 3, 8]) +@pytest.mark.parametrize("framesPerPacket", [1, 3]) def test_rtp_bitstream_ivas_dtx ( test_info, bitrate: int, bandwidth: str, format: str, framesPerPacket: int, - dut_encoder_frontend: EncoderFrontend + dut_encoder_frontend: EncoderFrontend, + dut_decoder_frontend: DecoderFrontend ): run_rtp_bitstream_tests ( CODECS.IVAS, @@ -140,9 +148,39 @@ def test_rtp_bitstream_ivas_dtx ( format, True, framesPerPacket, - dut_encoder_frontend + dut_encoder_frontend, + dut_decoder_frontend ) +def generateRequests(startTs: int, endTs: int) -> dict: + requests = dict() + return requests + +def generatePiData(startTs: int, endTs: int) -> dict: + data = dict() + + someOrientation = lambda : ORIENTATION(w=2*random.random()-1.0, x=2*random.random()-1.0, y=2*random.random()-1.0, z=2*random.random()-1.0) + somePosition = lambda : POSITION( x=random.randint(-32788, 32767)/100.0, y=random.randint(-32788, 32767)/100.0, z=random.randint(-32788, 32767)/100.0) + someDesc = lambda : AUDIO_DESCRIPTION(isSpeech=bool(random.getrandbits(1)), isMusic=bool(random.getrandbits(1)), isAmbiance=bool(random.getrandbits(1)), isEditable=bool(random.getrandbits(1)), isBinaural=bool(random.getrandbits(1))) + someDAS = lambda : DYNAMIC_AUDIO_SUPPRESSION(preferSpeech=bool(random.getrandbits(1)), preferMusic=bool(random.getrandbits(1)), preferAmbiance=bool(random.getrandbits(1)), level=random.randint(0, 15)) + someDIG = lambda : DIEGETIC_TYPE(isDigetic=[ bool(random.getrandbits(1)) for _ in range(random.randint(1, 5)) ]) + + for ts in range(startTs, endTs, 320): + pidata = dict() + pidata["SCENE_ORIENTATION"] = someOrientation() + pidata["DEVICE_ORIENTATION_COMPENSATED"] = someOrientation() + pidata["DEVICE_ORIENTATION_UNCOMPENSATED"] = someOrientation() + pidata["PLAYBACK_DEVICE_ORIENTATION"] = someOrientation() + pidata["HEAD_ORIENTATION"] = someOrientation() + pidata["AUDIO_FOCUS_DIRECTION"] = someOrientation() + pidata["LISTENER_POSITION"] = somePosition() + pidata["DYNAMIC_AUDIO_SUPPRESSION"] = someDAS() + pidata["AUDIO_DESCRIPTION"] = [someDesc() for n in range(random.randint(1, 5))] + pidata["DIEGETIC_TYPE"] = someDIG() + pidata["ACOUSTIC_ENVIRONMENT"] = ACOUSTIC_ENVIRONMENT(aeid=random.randint(0, 127)) + data[str(ts)] = pidata + return data + def isEqualFrame(refFrame: bytes, dutFrame: bytes): assert len(refFrame) == len(dutFrame), "Encoded frame size is different" @@ -155,6 +193,36 @@ def isEqualOrientation(ref: ORIENTATION, dut: ORIENTATION): assert abs(ref.y - dut.y) < 0.0001, "Scene Orientation PI Data mismatch in y" assert abs(ref.z - dut.z) < 0.0001, "Scene Orientation PI Data mismatch in z" +def isEqualPosition(ref: POSITION, dut: POSITION): + assert abs(ref.x - dut.x) < 0.3, "Position PI Data mismatch in x" + assert abs(ref.y - dut.y) < 0.3, "Position PI Data mismatch in y" + assert abs(ref.z - dut.z) < 0.3, "Position PI Data mismatch in z" + +def isEqualAD(ref: AUDIO_DESCRIPTION, dut: AUDIO_DESCRIPTION): + assert ref.isSpeech == dut.isSpeech, "Audio Description PI Data mismatch in isSpeech" + assert ref.isMusic == dut.isMusic, "Audio Description PI Data mismatch in isMusic" + assert ref.isAmbiance == dut.isAmbiance, "Audio Description PI Data mismatch in isAmbiance" + assert ref.isEditable == dut.isEditable, "Audio Description PI Data mismatch in isEditable" + assert ref.isBinaural == dut.isBinaural, "Audio Description PI Data mismatch in isBinaural" + +def isEqualDAS(ref: DYNAMIC_AUDIO_SUPPRESSION, dut: DYNAMIC_AUDIO_SUPPRESSION): + assert ref.preferSpeech == dut.preferSpeech, "Dynamic Audio Suppression PI Data mismatch in preferSpeech" + assert ref.preferMusic == dut.preferMusic, "Dynamic Audio Suppression PI Data mismatch in preferMusic" + assert ref.preferAmbiance == dut.preferAmbiance, "Dynamic Audio Suppression PI Data mismatch in preferAmbiance" + assert ref.level == dut.level, "Dynamic Audio Suppression PI Data mismatch in level" + +def isEqualDiegetic(ref: DIEGETIC_TYPE, dut: DIEGETIC_TYPE): + for r, d in zip(ref.isDigetic, dut.isDigetic): + assert r == d, f"Diegetic PI Data mismatch {r} != {d}" + +def isEqualAcousticEnv(ref: ACOUSTIC_ENVIRONMENT, dut: ACOUSTIC_ENVIRONMENT): + assert ref.aeid == dut.aeid, "Acoustic Env PI Data mismatch in Acoustic Identifier" + assert len(ref.rt60) == len(dut.rt60), "Acoustic Env PI Data mismatch in len(rt60)" + assert len(ref.dsr) == len(dut.dsr), "Acoustic Env PI Data mismatch in len(dsr)" + assert len(ref.dim) == len(dut.dim), "Acoustic Env PI Data mismatch in len(dim)" + assert len(ref.abscoeff) == len(dut.abscoeff), "Acoustic Env PI Data mismatch in len(abscoeff)" + for r, d in zip(ref.rt60, dut.rt60): + assert r == d, f"Acoustic Env PI Data mismatch in rt60 {r} != {d}" class CSVREADER: def __init__(self, csvFile: Path): @@ -197,19 +265,7 @@ class RTPVALIDATE: self.readers[PiTypeNames[1]] = CSVREADER(piFiles[1]) def setRefG192Bitstream(self, g192File: Path): - self.refPackets = list[bytes]() - self.refBitStrm = None - with open(g192File, "rb") as fd: - self.refBitStrm = ConstBitStream(fd.read()) - while self.refBitStrm.pos < self.refBitStrm.len: - sync = hex(self.refBitStrm.read(16).intle) - nBits = self.refBitStrm.read(16).intle - assert sync == "0x6b21", "G192 syncword not found at start of packet" - writer = BitStream() - for _ in range(nBits): - bit = "0b1" if self.refBitStrm.read(16).uintle == 129 else "0b0" - writer.append(bit) - self.refPackets.append(writer.tobytes()) + self.refPackets = ReadG192Bitstream(g192File) def packet(self, packet: IvasPacket): self.header(packet.hdr) @@ -255,11 +311,11 @@ class RTPVALIDATE: isEqualOrientation(ORIENTATION(w=refData[0], x=refData[1], y=refData[2], z=refData[3]), piData.data) @dataclass class TVARGS: - TVROOT = Path(THIS_PATH).joinpath("../../scripts/testv") + TVROOT = Path(ROOT_DIR).joinpath("scripts/testv") def __init__(self): self.tvDict = dict() - self.sceneFile = Path(THIS_PATH).joinpath("../../scripts/trajectories/azi_plus_2-ele_plus_2-every-25-rows.csv").absolute() - self.deviceFile = Path(THIS_PATH).joinpath("../../scripts/trajectories/headrot-1.5s.csv").absolute() + self.sceneFile = Path(ROOT_DIR).joinpath("scripts/trajectories/azi_plus_2-ele_plus_2-every-25-rows.csv").absolute() + self.deviceFile = Path(ROOT_DIR).joinpath("scripts/trajectories/headrot-1.5s.csv").absolute() def add(self, fmt:str, inputFile:str, args:list[str] = []): inputFile = str(TVARGS.TVROOT.joinpath(inputFile).absolute()) @@ -275,7 +331,7 @@ class TVARGS: if addPI and fmt != "MONO": args += [ "-scene_orientation", str(self.sceneFile), "-device_orientation", str(self.deviceFile) ] return args - + def piFiles(self) -> tuple[Path]: return (self.sceneFile, self.deviceFile) @@ -287,7 +343,8 @@ def run_rtp_bitstream_tests ( format: str, dtx: bool, framesPerPacket: int, - dut_encoder_frontend: EncoderFrontend + dut_encoder_frontend: EncoderFrontend, + dut_decoder_frontend: DecoderFrontend ): tvArgs = TVARGS() tvArgs.add("MONO", "stv48n.wav") @@ -316,6 +373,10 @@ def run_rtp_bitstream_tests ( with TemporaryDirectory() as tmp_dir: g192Out = Path(tmp_dir).joinpath(f"output-{codec}-{bitrate}-{caMode}-{format}-{dtx}.g192").absolute() rtpdumpOut = Path(tmp_dir).joinpath(f"output-{codec}-{bitrate}-{caMode}-{format}-{dtx}.rtpdump").absolute() + rtpdumpIn = Path(tmp_dir).joinpath(f"input-{codec}-{bitrate}-{caMode}-{format}-{dtx}.rtpdump").absolute() + pcmOut = Path(tmp_dir).joinpath(f"output-{codec}-{bitrate}-{caMode}-{format}-{dtx}.wav").absolute() + pcmOutG192 = Path(tmp_dir).joinpath(f"output_g192-{codec}-{bitrate}-{caMode}-{format}-{dtx}.wav").absolute() + piDataOutJson = Path(tmp_dir).joinpath(f"piData-{codec}-{bitrate}-{caMode}-{format}-{dtx}.json").absolute() # Run WITHOUT rtpdump first to generate reference bitstream dut_encoder_frontend.run( @@ -330,6 +391,68 @@ def run_rtp_bitstream_tests ( ) validate.setRefG192Bitstream(g192File=g192Out) + packer = IvasRtp(numFramesPerPacket=framesPerPacket, codec=codec) + + if codec == CODECS.IVAS: + outMode = "STEREO" if format == "STEREO" else "BINAURAL" + generatedPIData = generatePiData(0, 16000) + else: + outMode = "" + generatedPIData = dict() + + packer.packG192File(g192File=g192Out, rtpDumpOut=rtpdumpIn, piData=generatedPIData, requestsData=generateRequests(0, 1600)) + + dut_decoder_frontend.run( + output_config=outMode, + output_sampling_rate=48, + input_bitstream_path=g192Out, + output_path=pcmOutG192, + add_option_list= [] + ) + + dut_decoder_frontend.run( + output_config=outMode, + output_sampling_rate=48, + input_bitstream_path=rtpdumpIn, + output_path=pcmOut, + add_option_list= ["-VOIP_HF_ONLY=1", "-PiDataFile", str(piDataOutJson)] + ) + + decAudio, fs = sf.read(pcmOut) + g192Audio, Fs = sf.read(pcmOutG192) + decAudio = decAudio[4*960:] + assert abs(decAudio.shape[0] - g192Audio.shape[0]) <= (4 * 960), "Decoded PCM Audio is not same length as input" + minSamples = min(decAudio.shape[0], g192Audio.shape[0]) + rmsdB = 10.0 * np.log10(np.finfo(float).eps + np.sum(np.abs(g192Audio[:minSamples] - decAudio[:minSamples])**2)/minSamples) + + if dtx: + assert rmsdB < -60.0, "Bitdiff in the RTP unpacked and G192 streams for DTX stream" + else: + assert rmsdB < -96.0, "Bitdiff in the RTP unpacked and G192 streams" + + with open(piDataOutJson, "r") as fd: + decodedPiData = json.load(fd) + assert decodedPiData.keys() == generatedPIData.keys(), f"Timestamp of PI data {generatedPIData.keys()} not found in Decoded PI Data {decodedPiData.keys()}" + for ts in generatedPIData.keys(): + for pitype in generatedPIData[ts]: + data = generatedPIData[ts][pitype] + decoded = decodedPiData[ts][pitype] + if type(generatedPIData[ts][pitype]) == ORIENTATION: + isEqualOrientation(ORIENTATION(**decoded), data) + elif type(generatedPIData[ts][pitype]) == POSITION: + isEqualPosition(POSITION(**decoded), data) + elif type(generatedPIData[ts][pitype]) == DYNAMIC_AUDIO_SUPPRESSION: + isEqualDAS(DYNAMIC_AUDIO_SUPPRESSION(**decoded), data) + elif type(generatedPIData[ts][pitype]) == DIEGETIC_TYPE: + isEqualDiegetic(DIEGETIC_TYPE(**decoded), data) + elif type(generatedPIData[ts][pitype]) == ACOUSTIC_ENVIRONMENT: + isEqualAcousticEnv(ACOUSTIC_ENVIRONMENT(**decoded), data) + elif type(generatedPIData[ts][pitype]) == list: + for r, d in zip(generatedPIData[ts][pitype], decodedPiData[ts][pitype]): + isEqualAD(AUDIO_DESCRIPTION(**d), r) + else: + assert False, "Unsupported PI data found" + # Generate RTPDUMP addPI = False if format == "MONO" else True if addPI: @@ -349,7 +472,7 @@ def run_rtp_bitstream_tests ( add_option_list=extra_args ) - ivasRtp = IvasRtp() - ivasRtp.unpackFile(rtpdumpOut) - for packet in ivasRtp.getPackets(): + unpacker = IvasRtp() + unpacker.unpackFile(rtpdumpOut) + for packet in unpacker.getPackets(): validate.packet(packet) -- GitLab From e3fa8dc55d2ad50fc287aaac0d59287bfc851f85 Mon Sep 17 00:00:00 2001 From: Ripinder Singh Date: Thu, 21 Aug 2025 10:15:00 +1000 Subject: [PATCH 31/33] Code review comments #2 * Split rtp file writing * Update copyrights * Added additional comments * Added preprocessor defined for constants * Fix bug in pidata pack * Remove un-needed defines Signed-off-by: Ripinder Singh --- Workspace_msvc/lib_util.vcxproj | 1 + Workspace_msvc/lib_util.vcxproj.filters | 3 + apps/decoder.c | 145 +++++++++++------------- apps/encoder.c | 73 +++++------- lib_util/ivas_bpool.c | 2 +- lib_util/ivas_bpool.h | 2 +- lib_util/ivas_queue.c | 2 +- lib_util/ivas_queue.h | 2 +- lib_util/ivas_rtp_api.h | 22 ++-- lib_util/ivas_rtp_file.c | 138 ++++++++++++++++++++++ lib_util/ivas_rtp_file.h | 65 +++++++++++ lib_util/ivas_rtp_internal.h | 19 ++-- lib_util/ivas_rtp_payload.c | 35 +++--- lib_util/ivas_rtp_payload.h | 2 +- lib_util/ivas_rtp_pi_data.c | 41 ++++--- lib_util/ivas_rtp_pi_data.h | 2 +- lib_util/ivas_rtp_rom.c | 2 +- 17 files changed, 377 insertions(+), 179 deletions(-) create mode 100644 lib_util/ivas_rtp_file.c create mode 100644 lib_util/ivas_rtp_file.h diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 84ff59beae..94f22c71ca 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -115,6 +115,7 @@ + diff --git a/Workspace_msvc/lib_util.vcxproj.filters b/Workspace_msvc/lib_util.vcxproj.filters index 776a38e3d3..f81b34b6da 100644 --- a/Workspace_msvc/lib_util.vcxproj.filters +++ b/Workspace_msvc/lib_util.vcxproj.filters @@ -97,6 +97,9 @@ util_c + + util_c + diff --git a/apps/decoder.c b/apps/decoder.c index 4f2307b3dc..8cd444ec9a 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -41,6 +41,7 @@ #ifdef IVAS_RTPDUMP #include "ivas_rtp_api.h" #include "ivas_rtp_pi_data.h" +#include "ivas_rtp_file.h" #endif #include "jbm_file_writer.h" #include "hrtf_file_reader.h" @@ -172,7 +173,6 @@ typedef struct } IVAS_DEC_HRTF_BINARY_WRAPPER; #ifdef IVAS_RTPDUMP -#define JITTER_DURATION_MS ( 60 ) #ifdef DEBUGGING #define DEBUG_PRINT fprintf #else @@ -190,7 +190,7 @@ 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]; - FILE *f_rtpstream; + IVAS_RTP_FILE_HANDLE hReader; FILE *f_piDataOut; IVAS_RTP_CODEC codecId; uint32_t nReadPiData; @@ -223,7 +223,7 @@ static const char *PiDataNames[IVAS_PI_MAX_ID] = { }; -static void LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t nPiDataPresent ) +static void IVAS_RTP_LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t nPiDataPresent ) { uint32_t timestamp = ~0u; if ( f_piDataOut == NULL || piData == NULL || nPiDataPresent == 0 ) @@ -374,70 +374,71 @@ static void LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t nPiDataPre static void IVAS_RTP_Term( IVAS_RTP *rtp ) { - if ( rtp->f_rtpstream ) + if ( NULL != rtp ) { - fclose( rtp->f_rtpstream ); - rtp->f_rtpstream = NULL; - } - if ( rtp->f_piDataOut ) - { - fprintf( rtp->f_piDataOut, "\n}\n" ); - fclose( rtp->f_piDataOut ); - rtp->f_piDataOut = NULL; + IvasRtpFile_Close( &rtp->hReader ); + if ( rtp->f_piDataOut != NULL ) + { + fprintf( rtp->f_piDataOut, "\n}\n" ); + fclose( rtp->f_piDataOut ); + rtp->f_piDataOut = NULL; + } + IVAS_RTP_UNPACK_Close( &rtp->hUnpack ); } - IVAS_RTP_UNPACK_Close( &rtp->hUnpack ); } -static ivas_error IVAS_RTP_Init( IVAS_RTP *rtp, FILE *f_rtpstream, FILE *f_piDataOut ) +static ivas_error IVAS_RTP_Init( IVAS_RTP *rtp, const char *inputBitstreamFilename, const char *piOutputFilename ) { 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->hReader ); + if ( error != IVAS_ERR_OK ) + { + return error; + } - rtp->f_rtpstream = f_rtpstream; - rtp->f_piDataOut = f_piDataOut; - rtp->rtpPacket.buffer = rtp->packet; - rtp->rtpPacket.capacity = sizeof( rtp->packet ); + 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; } -static ivas_error readNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit ) +static 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 ) { ivas_error error = IVAS_ERR_OK; - IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; - size_t packetLen = 0u; + 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 ) { - size_t nread = fread( &packetLen, sizeof( uint32_t ), 1, rtp->f_rtpstream ); /* Read Packet Length */ - if ( nread == 0 ) + rtp->rtpPacket.length = 0; + if ( ( error = IvasRtpFile_Read( rtp->hReader, rtp->rtpPacket.buffer, &rtp->rtpPacket.length, rtp->rtpPacket.capacity ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_END_OF_FILE; - } - if ( packetLen > sizeof( rtp->packet ) ) - { - fprintf( stderr, "RTP packet > buffer capacity %lu bytes\n", sizeof( rtp->packet ) ); - return IVAS_ERR_INVALID_OUTPUT_BUFFER_SIZE; - } - - nread = fread( rtp->packet, sizeof( uint8_t ), packetLen, rtp->f_rtpstream ); /* Read Packet */ - if ( nread < packetLen ) - { - return IVAS_ERR_END_OF_FILE; + return error; } - rtp->rtpPacket.buffer = rtp->packet; - rtp->rtpPacket.length = packetLen; - if ( ( error = IVAS_RTP_UNPACK_PushPacket( rtp->hUnpack, &rtp->rtpPacket, &rtp->numFramesInPacket, &rtp->numPiDataInPacket, &rtp->remoteRequestBitmap ) ) != IVAS_ERR_OK ) @@ -461,7 +462,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits rtp->nReadPiData++; rtp->numPiDataInPacket--; } - LogPiData( rtp->f_piDataOut, rtp->piData, rtp->nReadPiData ); + IVAS_RTP_LogPiData( rtp->f_piDataOut, rtp->piData, rtp->nReadPiData ); } #ifdef RTP_S4_251135_CR26253_0016_REV1 @@ -505,7 +506,7 @@ static ivas_error readNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits return IVAS_ERR_OK; } -static ivas_error applyPiData( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint32_t rtpTimeStamp ) +static ivas_error IVAS_RTP_ApplyPiData( IVAS_RTP *rtp, IVAS_DEC_HANDLE hIvasDec, uint32_t rtpTimeStamp ) { ivas_error error = IVAS_ERR_OK; while ( rtp->nProcPiData < rtp->nReadPiData && @@ -633,7 +634,7 @@ static int restartDecoder( if ( arg->voipMode ) { - if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, JITTER_DURATION_MS, arg->inputFormat ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, 60, arg->inputFormat ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nCould not enable VOIP: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; @@ -975,11 +976,7 @@ int main( if ( arg.voipMode ) { -#ifdef IVAS_RTPDUMP - if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, JITTER_DURATION_MS, arg.inputFormat ) ) != IVAS_ERR_OK ) -#else if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, 60, arg.inputFormat ) ) != IVAS_ERR_OK ) -#endif { fprintf( stderr, "\nCould not enable VOIP: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; @@ -3406,18 +3403,18 @@ static ivas_error printBitstreamInfoVoip( { bool previewFailed = true; ivas_error error = IVAS_ERR_OK; - FILE *f_rtpstream = NULL; #ifdef IVAS_RTPDUMP IVAS_RTP ivasRtp; #else + FILE *f_rtpstream = NULL; EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; + bool isAMRWB_IOmode; + uint16_t frameTypeIndex; #endif uint8_t au[( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3]; int16_t auSizeBits; uint8_t *auPtr = NULL; - bool isAMRWB_IOmode; - uint16_t frameTypeIndex; bool qBit; uint32_t nextPacketRcvTime_ms = 0; uint16_t rtpSequenceNumber; @@ -3430,6 +3427,13 @@ static ivas_error printBitstreamInfoVoip( { case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: +#ifdef IVAS_RTPDUMP + if ( ( error = IVAS_RTP_Init( &ivasRtp, arg.inputBitstreamFilename, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); + goto cleanup; + } +#else f_rtpstream = fopen( arg.inputBitstreamFilename, "r" ); if ( f_rtpstream == NULL ) @@ -3438,13 +3442,6 @@ static ivas_error printBitstreamInfoVoip( goto cleanup; } -#ifdef IVAS_RTPDUMP - if ( ( error = IVAS_RTP_Init( &ivasRtp, f_rtpstream ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); - goto cleanup; - } -#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream, arg.inputFormat == IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF ); if ( rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) { @@ -3481,7 +3478,11 @@ static ivas_error printBitstreamInfoVoip( /* 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; @@ -3574,13 +3575,12 @@ static ivas_error decodeVoIP( int16_t delayNumSamples = -1; int32_t delayTimeScale = -1; int16_t i; - FILE *f_rtpstream = NULL; #ifdef IVAS_RTPDUMP IVAS_RTP ivasRtp = { 0 }; IVAS_DEC_HANDLE hIvasDec = *phIvasDec; - FILE *f_piDataOut = NULL; int32_t initialTsOffsetSystemAndRTP = 0; #else + FILE *f_rtpstream = NULL; EVS_RTPDUMP_DEPACKER rtpdumpDepacker; EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR; #endif @@ -3634,34 +3634,19 @@ static ivas_error decodeVoIP( case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: #ifdef IVAS_RTPDUMP - f_rtpstream = fopen( arg.inputBitstreamFilename, "rb" ); + if ( ( error = IVAS_RTP_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); + goto cleanup; + } #else f_rtpstream = fopen( arg.inputBitstreamFilename, "r" ); -#endif - if ( f_rtpstream == NULL ) { fprintf( stderr, "could not open: %s\n", arg.inputBitstreamFilename ); goto cleanup; } -#ifdef IVAS_RTPDUMP - if ( arg.piOutputFilename != NULL ) - { - f_piDataOut = fopen( arg.piOutputFilename, "w" ); - if ( f_piDataOut == NULL ) - { - fprintf( stderr, "could not open: %s\n", arg.piOutputFilename ); - goto cleanup; - } - fprintf( f_piDataOut, "{\n" ); - } - if ( ( error = IVAS_RTP_Init( &ivasRtp, f_rtpstream, f_piDataOut ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "error in IVAS_RTP_Init(): %d\n", error ); - goto cleanup; - } -#else rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_open( &rtpdumpDepacker, f_rtpstream, arg.inputFormat == IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF ); if ( rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR ) { @@ -3711,7 +3696,7 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - error = readNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + error = IVAS_RTP_ReadNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); 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 ); @@ -3916,7 +3901,7 @@ static ivas_error decodeVoIP( { auPtr = au; /* might have been set to RTP packet in prev call */ #ifdef IVAS_RTPDUMP - error = readNextFrame( &ivasRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit ); + 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; @@ -3966,7 +3951,7 @@ static ivas_error decodeVoIP( { /* Rudimentry Time Mapping to map system time to rtp timestamp */ uint32_t piTs = systemTime_ms * 16 + initialTsOffsetSystemAndRTP; - if ( ( error = applyPiData( &ivasRtp, hIvasDec, piTs ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_RTP_ApplyPiData( &ivasRtp, hIvasDec, piTs ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; diff --git a/apps/encoder.c b/apps/encoder.c index 00c7cb519a..9fb3b60013 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -42,6 +42,7 @@ #include "ivas_rtp_api.h" #include "ivas_rtp_pi_data.h" #include "rotation_file_reader.h" +#include "ivas_rtp_file.h" #endif #ifdef DEBUGGING #include "debug.h" @@ -221,14 +222,14 @@ int main( #endif #ifdef IVAS_RTPDUMP - FILE *f_rtpstream = NULL; + IVAS_RTP_FILE_HANDLE hWriter = NULL; IVAS_RTP_PACK_HANDLE hPack = NULL; uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8]; - uint8_t packet[NOMINAL_BUFFER_SIZE(IVAS_MAX_FRAMES_PER_RTP_PACKET)]; + uint8_t packet[NOMINAL_BUFFER_SIZE( IVAS_MAX_FRAMES_PER_RTP_PACKET )]; IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL }; IVAS_DATA_BUFFER rtpPacket = { 0, 0, NULL }; - uint32_t numFramesInPayload = 0, packetLength = 0; + uint32_t numFramesInPayload = 0; packedFrame.capacity = sizeof( au ); packedFrame.buffer = au; @@ -639,8 +640,8 @@ int main( packCfg.maxFramesPerPacket = arg.numFramesPerPacket; /* Open the output file for RTPDump writing */ - f_rtpstream = fopen( arg.outputBitstreamFilename, "wb" ); - if ( f_rtpstream == NULL ) + error = IvasRtpFile_Open ( arg.outputBitstreamFilename, true, &hWriter ); + if ( error != IVAS_ERR_OK ) { fprintf( stderr, "could not open: %s\n", arg.outputBitstreamFilename ); goto cleanup; @@ -861,40 +862,17 @@ int main( } /* *** Encode one frame *** */ - 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; - } - #ifdef IVAS_RTPDUMP if ( hPack ) { - uint32_t n = numBits / 8, x = 0; - uint16_t *bitstrm = bitStream; - - /* Pack Encoded Stream */ - packedFrame.length = 0; - rtpPacket.length = 0; - while ( n ) + if ( ( error = IVAS_ENC_EncodeFrameToCompact( hIvasEnc, pcmBuf, pcmBufSize, packedFrame.buffer, &numBits ) ) != IVAS_ERR_OK ) { - x = ( ( bitstrm[0] << 7 ) | ( bitstrm[1] << 6 ) | ( bitstrm[2] << 5 ) | ( bitstrm[3] << 4 ) | - ( bitstrm[4] << 3 ) | ( bitstrm[5] << 2 ) | ( bitstrm[6] << 1 ) | ( bitstrm[7] << 0 ) ); - packedFrame.buffer[packedFrame.length++] = (uint8_t) x; - bitstrm += 8; - n--; + fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; } - /* AMWWB-IO has non octet sized bitstream */ - if ( numBits & 0x7 ) - { - x = 0; - for ( n = 0; n < (uint32_t) ( numBits & 0x7 ); n++ ) - { - x |= (uint8_t) ( bitstrm[n] << ( 7 - n ) ); - } - packedFrame.buffer[packedFrame.length++] = (uint8_t) x; - } + packedFrame.length = ( numBits + 7 ) / 8; + rtpPacket.length = 0; /* Push Encoded Stream to */ if ( ( error = IVAS_RTP_PACK_PushFrame( hPack, @@ -961,15 +939,22 @@ int main( goto cleanup; } - /* File Format = Packet Length (uint32_t) + Packet bytes */ - packetLength = (uint32_t) rtpPacket.length; - fwrite( &packetLength, sizeof( packetLength ), 1, f_rtpstream ); - fwrite( rtpPacket.buffer, sizeof( uint8_t ), packetLength, f_rtpstream ); + if ( ( error = IvasRtpFile_Write ( hWriter, rtpPacket.buffer, rtpPacket.length ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while writing RTP packet\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 ) { @@ -1068,10 +1053,11 @@ cleanup: goto cleanup; } - /* File Format = Packet Length (uint32_t) + Packet bytes */ - packetLength = (uint32_t) rtpPacket.length; - fwrite( &packetLength, sizeof( packetLength ), 1, f_rtpstream ); - fwrite( rtpPacket.buffer, sizeof( uint8_t ), packetLength, f_rtpstream ); + if ( ( error = IvasRtpFile_Write ( hWriter, rtpPacket.buffer, rtpPacket.length ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while writing RTP packet\n", IVAS_ENC_GetErrorMessage( error ) ); + goto cleanup; + } } IVAS_RTP_PACK_Close( &hPack ); @@ -1087,10 +1073,7 @@ cleanup: RotationFileReader_close( &deviceOrientationFileReader ); } - if ( f_rtpstream ) - { - fclose( f_rtpstream ); - } + IvasRtpFile_Close( &hWriter ); #endif IVAS_ENC_Close( &hIvasEnc ); diff --git a/lib_util/ivas_bpool.c b/lib_util/ivas_bpool.c index 23754a0c11..2bf707cea6 100644 --- a/lib_util/ivas_bpool.c +++ b/lib_util/ivas_bpool.c @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 diff --git a/lib_util/ivas_bpool.h b/lib_util/ivas_bpool.h index d929ae7415..ae8f114127 100644 --- a/lib_util/ivas_bpool.h +++ b/lib_util/ivas_bpool.h @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 diff --git a/lib_util/ivas_queue.c b/lib_util/ivas_queue.c index b72fcee9e4..c5806e0307 100644 --- a/lib_util/ivas_queue.c +++ b/lib_util/ivas_queue.c @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 diff --git a/lib_util/ivas_queue.h b/lib_util/ivas_queue.h index 8a5d4d1017..9f2a9a856c 100644 --- a/lib_util/ivas_queue.h +++ b/lib_util/ivas_queue.h @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 5e269eaa43..29ed397beb 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 @@ -296,7 +296,7 @@ extern "C" /* Initial configuration for rtp packer * - maxFramesPerPacket is used to define if more than one frame should be packed - * in the same rtp packet. + * in the same rtp packet. If zero, will use IVAS_MAX_FRAMES_PER_RTP_PACKET. */ typedef struct { @@ -407,7 +407,11 @@ extern "C" /* 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 */ + /* 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 */ @@ -435,8 +439,10 @@ extern "C" * 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 else a race condition - * can arise if new packet is pushed while frames/pidata are still being pulled out. + * 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 : - * ================== @@ -496,8 +502,10 @@ extern "C" * 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 else a race condition - * can arise if new packet is pushed while frames/pidata are still being pulled out. + * 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 : - * ================== diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c new file mode 100644 index 0000000000..0112fdfb54 --- /dev/null +++ b/lib_util/ivas_rtp_file.c @@ -0,0 +1,138 @@ +/****************************************************************************************************** + + (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 "ivas_rtp_file.h" +#include "ivas_error_utils.h" + +struct IVAS_RTP_FILE +{ + bool isFileWriter; + FILE *f_rtpstream; +}; + +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; +} + +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; +} + +ivas_error IvasRtpFile_Write( + IVAS_RTP_FILE_HANDLE hReader, /* i : pointer to an IVAS file writer handle */ + const uint8_t *packet, + size_t numBytes ) +{ + ivas_error error = IVAS_ERR_OK; + if ( hReader->isFileWriter ) + { + uint32_t length = (uint32_t) numBytes; /* Max packet length is < 32 bits*/ + fwrite( &length, sizeof( uint32_t ), 1, hReader->f_rtpstream ); + fwrite( packet, sizeof( uint8_t ), numBytes, hReader->f_rtpstream ); + } + else + { + error = IVAS_ERR_WRONG_PARAMS; + } + return error; +} + +ivas_error IvasRtpFile_Read( + IVAS_RTP_FILE_HANDLE hReader, /* i : pointer to an IVAS file writer handle */ + uint8_t *packet, + size_t *numBytes, + size_t capacity ) +{ + size_t nread = 0; + uint32_t length = 0; + if ( hReader->isFileWriter ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "File open for writing cannot be read" ); + } + + nread = fread( &length, sizeof( uint32_t ), 1, hReader->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 ), hReader->f_rtpstream ); /* Read Packet */ + if ( nread < ( *numBytes ) ) + { + return IVAS_ERR_END_OF_FILE; + } + + 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 0000000000..47d545208a --- /dev/null +++ b/lib_util/ivas_rtp_file.h @@ -0,0 +1,65 @@ +/****************************************************************************************************** + + (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 +#include +#include "ivas_error.h" + +typedef struct IVAS_RTP_FILE *IVAS_RTP_FILE_HANDLE; + +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 */ +); + +ivas_error IvasRtpFile_Close ( + IVAS_RTP_FILE_HANDLE *phReader /* i : pointer to an IVAS file reader handle */ +); + +ivas_error IvasRtpFile_Write ( + IVAS_RTP_FILE_HANDLE hReader, /* i : pointer to an IVAS file writer handle */ + const uint8_t *packet, /* i : pointer to packed rtp packet */ + size_t numBytes /* i : length of the packet in bytes */ +); + +ivas_error IvasRtpFile_Read ( + IVAS_RTP_FILE_HANDLE hReader, /* i : pointer to an IVAS file writer handle */ + uint8_t *packet, /* o : buffer where packet is to be written */ + size_t *numBytes, /* o : length of the packet in bytes */ + size_t capacity /* i : buffer capacity of the packet buffer */ +); + +#endif /* IVAS_RTP_FILE_H */ diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h index 0acfcd2161..f3569ca031 100644 --- a/lib_util/ivas_rtp_internal.h +++ b/lib_util/ivas_rtp_internal.h @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 @@ -64,6 +64,9 @@ enum MASK_BITS #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]; @@ -74,14 +77,14 @@ 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_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 */ + 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 */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 779c627274..f716f31eee 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 @@ -45,15 +45,9 @@ #include "ivas_error_utils.h" #include "mutex.h" -#define IVAS_MAX_FRAMES_IN_QUEUE ( 32 ) #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 */ -/* Heuristically defined max values for no of frames per packet and no of pi data per packet */ -#define MAX_SUPPORTED_PI_DATA_SIZE ( 32 ) /* Currently no PI data exceeds 32 bytes */ -#define MAX_SUPPORTED_IVAS_FRAMES_PER_PACKET ( 25u ) -#define MAX_SUPPORTED_PI_FRAMES_PER_PACKET ( 150u ) - /* Generic RTP Header + Header Extension data structure */ typedef struct { @@ -489,13 +483,18 @@ ivas_error IVAS_RTP_PACK_Open( { ivas_error error; IVAS_RTP_PACK_HANDLE hPack; - uint32_t numFramesPerPacket = ( config->maxFramesPerPacket == 0 ) ? 1 : config->maxFramesPerPacket; + 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 ) { @@ -1193,7 +1192,12 @@ ivas_error IVAS_RTP_UNPACK_Open( return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtp unpack handle" ); } - hUnpack->maxNumberOfFrames = ( config->maxFramesPerPacket < IVAS_MAX_FRAMES_PER_RTP_PACKET ) ? IVAS_MAX_FRAMES_PER_RTP_PACKET : config->maxFramesPerPacket; + 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 ); @@ -1390,7 +1394,7 @@ static uint32_t parseSubsequentEByte( const IVAS_DATA_BUFFER *payload, uint32_t return nBytes; } -static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc ) +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; @@ -1411,13 +1415,14 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy nBytes++; /* Consume this e-byte */ - *numFrames += 1; - memset( toc, 0, sizeof( *toc ) ); - if ( *numFrames == MAX_SUPPORTED_IVAS_FRAMES_PER_PACKET ) + 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; @@ -1598,7 +1603,7 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( ivas_error error = IVAS_ERR_OK; uint32_t nBytes = 0, numFrames = 0, numPiData = 0, n; bool piDataIndicated = false; - TOC_INFO toc[MAX_SUPPORTED_IVAS_FRAMES_PER_PACKET]; + TOC_INFO toc[IVAS_MAX_FRAMES_PER_RTP_PACKET]; IVAS_RTP_REQUEST_VALUE oldRequests[IVAS_REQUEST_MAX]; @@ -1638,7 +1643,7 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( nBytes = parseSubsequentEByte( payload, nBytes, hUnpack->requests, &piDataIndicated ); /* Unpack the ToC Bytes => Extract number of frames in packet */ - error = parseToCByte( payload, &nBytes, &numFrames, toc ); + error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ) ); ERR_CHECK_RETURN( error ); /* Read frame bits */ diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h index 8529de51b7..92cb0e8e71 100644 --- a/lib_util/ivas_rtp_payload.h +++ b/lib_util/ivas_rtp_payload.h @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index b88bb0e661..d3e8774281 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 @@ -47,9 +47,9 @@ static __inline uint32_t writeInt16( uint8_t *buffer, uint32_t idx, int16_t val return idx; } -static __inline uint16_t readInt16( const uint8_t *buffer ) +static __inline int16_t readInt16( const uint8_t *buffer ) { - return ( (uint16_t) buffer[0] << 8 ) | ( (uint16_t) buffer[1] ); + return (int16_t) ( (uint16_t) buffer[0] << 8 ) | ( (uint16_t) buffer[1] ); } /*-----------------------------------------------------------------------* @@ -166,10 +166,10 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); - orientation->orientation.w = ( (int16_t) readInt16( &buffer[0] ) ) / 32768.0f; - orientation->orientation.x = ( (int16_t) readInt16( &buffer[2] ) ) / 32768.0f; - orientation->orientation.y = ( (int16_t) readInt16( &buffer[4] ) ) / 32768.0f; - orientation->orientation.z = ( (int16_t) readInt16( &buffer[6] ) ) / 32768.0f; + 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; } @@ -330,6 +330,11 @@ static ivas_error packAudioDescription( const IVAS_PIDATA_GENERIC *piData, uint8 *nBytesWritten = 0; + if ( audioDesc->nValidEntries > ( IVAS_PI_MAX_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 ) { @@ -358,7 +363,7 @@ static ivas_error unpackAudioDescription( const uint8_t *buffer, uint32_t numDat IVAS_PIDATA_AUDIO_DESC *audioDesc = (IVAS_PIDATA_AUDIO_DESC *) piData; /* Audio Description data is max 5 bytes */ - if ( numDataBytes > 5 ) + if ( numDataBytes > ( IVAS_PI_MAX_OBJECTS + 1 ) ) { return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } @@ -449,9 +454,9 @@ static ivas_error packListenerPosition( const IVAS_PIDATA_GENERIC *piData, uint8 buffer[nBytes++] = ( listener->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ buffer[nBytes++] = 6; - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.x / 327.68f ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.y / 327.68f ) ); - nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.z / 327.68f ) ); + 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; } @@ -468,9 +473,9 @@ static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDat listener->size = sizeof( IVAS_PIDATA_LISTENER_POSITION ); listener->piDataType = IVAS_PI_LISTENER_POSITION; - listener->position.x = ( (int16_t) readInt16( &buffer[0] ) ) / 100.0f; - listener->position.y = ( (int16_t) readInt16( &buffer[2] ) ) / 100.0f; - listener->position.z = ( (int16_t) readInt16( &buffer[4] ) ) / 100.0f; + 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; } @@ -498,7 +503,8 @@ static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buff return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Diegetic Type PI data" ); } - for ( n = 0; n < 5; n++ ) + /* Valid bits must be based on active bits defined for the input format */ + for ( n = 0; n < ( IVAS_PI_MAX_OBJECTS + 1 ); n++ ) { byte <<= 1; byte |= ( diegetic->isDiegetic[n] ); @@ -528,7 +534,8 @@ static ivas_error unpackDiegetic( const uint8_t *buffer, uint32_t numDataBytes, diegetic->piDataType = IVAS_PI_DIEGETIC_TYPE; byte = buffer[0]; - for ( n = 0; n < 5; n++ ) + /* Valid bits must be based on active bits defined for the input format */ + for ( n = 0; n < ( IVAS_PI_MAX_OBJECTS + 1 ); n++ ) { diegetic->isDiegetic[n] = ( ( byte >> ( 7 - n ) ) & 1 ) != 0; } @@ -569,7 +576,7 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packOrientation, /* HEAD_ORIENTATION */ packListenerPosition, /* LISTENER_POSITION */ packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ - packAudioDescription, /* AUDIO_FOCUS_DIRECTION */ + packOrientation, /* AUDIO_FOCUS_DIRECTION */ #else packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */ packUnsupportedData, /* HEAD_ORIENTATION */ diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index ba82914df1..3be265bb87 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 diff --git a/lib_util/ivas_rtp_rom.c b/lib_util/ivas_rtp_rom.c index 4b8539fb30..016e6ce34e 100644 --- a/lib_util/ivas_rtp_rom.c +++ b/lib_util/ivas_rtp_rom.c @@ -1,6 +1,6 @@ /****************************************************************************************************** - (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + (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 -- GitLab From bfbc2e2739ca8fa8044a21c7f1ef5f08fb8b9ac4 Mon Sep 17 00:00:00 2001 From: Ripinder Singh Date: Thu, 4 Sep 2025 18:31:37 +1000 Subject: [PATCH 32/33] Code comments Signed-off-by: Ripinder Singh --- Workspace_msvc/lib_util.vcxproj | 2 - Workspace_msvc/lib_util.vcxproj.filters | 6 - apps/decoder.c | 13 +- apps/encoder.c | 8 +- lib_com/bitstream.c | 52 --- lib_com/common_api_types.h | 9 +- lib_com/ivas_cnst.h | 23 -- lib_com/ivas_error.h | 7 +- lib_com/ivas_prot.h | 4 - lib_enc/lib_enc.c | 19 -- lib_enc/lib_enc.h | 6 - lib_util/ivas_bpool.c | 2 +- lib_util/ivas_rtp_payload.c | 46 +-- lib_util/ivas_rtp_payload.h | 403 ------------------------ lib_util/ivas_rtp_pi_data.c | 58 +++- lib_util/ivas_rtp_rom.c | 64 ---- 16 files changed, 84 insertions(+), 638 deletions(-) delete mode 100644 lib_util/ivas_rtp_payload.h delete mode 100644 lib_util/ivas_rtp_rom.c diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 94f22c71ca..7c10648b72 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -112,7 +112,6 @@ - @@ -145,7 +144,6 @@ - diff --git a/Workspace_msvc/lib_util.vcxproj.filters b/Workspace_msvc/lib_util.vcxproj.filters index f81b34b6da..ed062708ad 100644 --- a/Workspace_msvc/lib_util.vcxproj.filters +++ b/Workspace_msvc/lib_util.vcxproj.filters @@ -88,9 +88,6 @@ util_c - - util_c - util_c @@ -189,9 +186,6 @@ util_h - - util_h - diff --git a/apps/decoder.c b/apps/decoder.c index 8cd444ec9a..a9f5818606 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -568,7 +568,7 @@ static void do_object_editing( IVAS_EDITABLE_PARAMETERS *editableParameters, Obj #ifdef IVAS_RTPDUMP static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, IVAS_DEC_HANDLE *phIvasDec, int16_t *pcmBuf ); -static int restartDecoder( +static ivas_error restartDecoder( IVAS_DEC_HANDLE *phIvasDec, IVAS_DEC_MODE codec, DecArguments *arg, @@ -580,7 +580,7 @@ static int restartDecoder( if ( phIvasDec == NULL ) { - return -1; + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } if ( NULL != *phIvasDec ) @@ -665,12 +665,11 @@ static int restartDecoder( } } - return 0; + return IVAS_ERR_OK; cleanup: IVAS_DEC_Close( phIvasDec ); - - return -1; + return error; } #else static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); @@ -3742,14 +3741,14 @@ static ivas_error decodeVoIP( if ( ivasRtp.restartNeeded ) { IVAS_DEC_MODE newCodecInPacket = ( ivasRtp.codecId == IVAS_RTP_EVS ) ? IVAS_DEC_MODE_EVS : IVAS_DEC_MODE_IVAS; - int err = restartDecoder( + error = restartDecoder( &hIvasDec, newCodecInPacket, &arg, NULL, /* ToDo : Provide rendererConfig */ NULL /* ToDo : Provide LS Custom Data */ ); - if ( err < 0 ) + if ( error != IVAS_ERR_OK ) { fprintf( stderr, "\nFailed to restart decoder from %d to %d\n", arg.decMode, newCodecInPacket ); goto cleanup; diff --git a/apps/encoder.c b/apps/encoder.c index 9fb3b60013..4235e3d788 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -640,7 +640,7 @@ int main( packCfg.maxFramesPerPacket = arg.numFramesPerPacket; /* Open the output file for RTPDump writing */ - error = IvasRtpFile_Open ( arg.outputBitstreamFilename, true, &hWriter ); + error = IvasRtpFile_Open( arg.outputBitstreamFilename, true, &hWriter ); if ( error != IVAS_ERR_OK ) { fprintf( stderr, "could not open: %s\n", arg.outputBitstreamFilename ); @@ -876,7 +876,7 @@ int main( /* Push Encoded Stream to */ if ( ( error = IVAS_RTP_PACK_PushFrame( hPack, - IVAS_isImmersiveFormat( hIvasEnc ) ? IVAS_RTP_IVAS : IVAS_RTP_EVS, + arg.inputFormat != IVAS_ENC_INPUT_MONO ? IVAS_RTP_IVAS : IVAS_RTP_EVS, #ifdef RTP_S4_251135_CR26253_0016_REV1 NULL, #endif /* RTP_S4_251135_CR26253_0016_REV1 */ @@ -939,7 +939,7 @@ int main( goto cleanup; } - if ( ( error = IvasRtpFile_Write ( hWriter, rtpPacket.buffer, rtpPacket.length ) ) != IVAS_ERR_OK ) + if ( ( error = IvasRtpFile_Write( hWriter, rtpPacket.buffer, rtpPacket.length ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError %s while writing RTP packet\n", IVAS_ENC_GetErrorMessage( error ) ); goto cleanup; @@ -1053,7 +1053,7 @@ cleanup: goto cleanup; } - if ( ( error = IvasRtpFile_Write ( hWriter, rtpPacket.buffer, rtpPacket.length ) ) != IVAS_ERR_OK ) + if ( ( error = IvasRtpFile_Write( hWriter, rtpPacket.buffer, rtpPacket.length ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError %s while writing RTP packet\n", IVAS_ENC_GetErrorMessage( error ) ); goto cleanup; diff --git a/lib_com/bitstream.c b/lib_com/bitstream.c index 22fbcde10e..18bfba0d18 100644 --- a/lib_com/bitstream.c +++ b/lib_com/bitstream.c @@ -163,58 +163,6 @@ Word16 rate2EVSmode( return rate2AMRWB_IOmode( brate ); } -#ifdef IVAS_RTPDUMP -/*-------------------------------------------------------------------* - * rate2IVASmode() - * - * Lookup IVAS mode. Note: FRAME_NO_DATA frames should be looked up with rate2EVSmode(). - *-------------------------------------------------------------------*/ -Word16 rate2IVASmode( - const Word32 brate /* i : bitrate */ -) -{ - switch ( brate ) - { - /* IVAS modes */ - case IVAS_SID_5k2: - return IVAS_TOC_SID; - case IVAS_13k2: - return IVAS_TOC_13200; - case IVAS_16k4: - return IVAS_TOC_16400; - case IVAS_24k4: - return IVAS_TOC_24400; - case IVAS_32k: - return IVAS_TOC_32000; - case IVAS_48k: - return IVAS_TOC_48000; - case IVAS_64k: - return IVAS_TOC_64000; - case IVAS_80k: - return IVAS_TOC_80000; - case IVAS_96k: - return IVAS_TOC_96000; - case IVAS_128k: - return IVAS_TOC_128000; - case IVAS_160k: - return IVAS_TOC_160000; - case IVAS_192k: - return IVAS_TOC_192000; - case IVAS_256k: - return IVAS_TOC_256000; - case IVAS_384k: - return IVAS_TOC_384000; - case IVAS_512k: - return IVAS_TOC_512000; - default: - break; - } - - return -1; -} - -#endif - /*-------------------------------------------------------------------* * ind_list_realloc() * diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index d711365703..03209f3e26 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -36,9 +36,6 @@ /* options.h needed for debugging/development features * It should be stripped for delivery along with debugging switches */ #include "options.h" -#ifdef IVAS_RTPDUMP -#include -#endif #include #include #include "ivas_error.h" @@ -219,7 +216,7 @@ typedef struct _IVAS_JBM_TRACE_DATA #ifdef IVAS_RTPDUMP typedef struct { - bool PIdataPresent; + int16_t PIdataPresent; char *sceneOrientation; char *deviceOrientationCompensated; char *deviceOrientationUncompensated; @@ -230,9 +227,9 @@ typedef struct typedef struct { - bool sceneOrientationSaved; + int16_t sceneOrientationSaved; IVAS_QUATERNION sceneOrientationQuat; - bool deviceOrientationSaved; + int16_t deviceOrientationSaved; IVAS_QUATERNION deviceOrientationQuat; } PI_DATA_DEPACKER_STATE; #endif diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index f8a2ca10fd..155fa08eb2 100755 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -1758,29 +1758,6 @@ typedef enum } STEREO_DMX_EVS_PRC; -#ifdef IVAS_RTPDUMP -/* "IVAS bit rate" column in table A.3.3.3.2-1 of TS26.253 Annex A */ -typedef enum -{ - IVAS_TOC_13200 = 0x0, // 0000 - IVAS_TOC_16400 = 0x1, // 0001 - IVAS_TOC_24400 = 0x2, // 0010 - IVAS_TOC_32000 = 0x3, // 0011 - IVAS_TOC_48000 = 0x4, // 0100 - IVAS_TOC_64000 = 0x5, // 0101 - IVAS_TOC_80000 = 0x6, // 0110 - IVAS_TOC_96000 = 0x7, // 0111 - IVAS_TOC_128000 = 0x8, // 1000 - IVAS_TOC_160000 = 0x9, // 1001 - IVAS_TOC_192000 = 0xA, // 1010 - IVAS_TOC_256000 = 0xB, // 1011 - IVAS_TOC_384000 = 0xC, // 1100 - IVAS_TOC_512000 = 0xD, // 1101 - IVAS_TOC_RESERVED = 0xE, // 1110 - IVAS_TOC_SID = 0xF // 1111 -} IVAS_TOC_BITRATE_INDEX; - -#endif #endif /* clang-format on */ /* IVAS_CNST_H */ diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index 24b576d696..5a3d3fa787 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -153,10 +153,9 @@ typedef enum /*----------------------------------------* * rtp errors * *----------------------------------------*/ - IVAS_ERR_UNDERFLOW = 0x7000, - IVAS_ERR_PI_DATA_WITH_NO_INPUT_FRAME, - IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, - IVAS_ERR_UNPACK_PI_DATA, + IVAS_ERR_RTP_UNDERFLOW = 0x7000, + IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, + IVAS_ERR_RTP_UNPACK_PI_DATA, IVAS_ERR_RTP_UNSUPPORTED_FRAME, /*----------------------------------------* diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 80232e5800..262d30ca99 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -806,10 +806,6 @@ void ivas_apply_non_diegetic_panning( ); #ifdef IVAS_RTPDUMP -Word16 rate2IVASmode( - const Word32 brate /* i : bitrate */ -); - void QuaternionProduct( const IVAS_QUATERNION q1, const IVAS_QUATERNION q2, diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index b2ea192118..705f3364e4 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -2417,25 +2417,6 @@ static void init_encoder_config( return; } -#ifdef IVAS_RTPDUMP - - -/*---------------------------------------------------------------------* - * IVAS_isImmersiveFormat() - * - * Check if the used format is immersive or mono - *---------------------------------------------------------------------*/ - -bool IVAS_isImmersiveFormat( - const IVAS_ENC_HANDLE hIvasEnc ) -{ - if ( hIvasEnc->st_ivas->hEncoderConfig->ivas_format == MONO_FORMAT ) - { - return false; - } - return true; -} -#endif #ifdef DEBUGGING diff --git a/lib_enc/lib_enc.h b/lib_enc/lib_enc.h index 478133db9f..af9f68e07b 100644 --- a/lib_enc/lib_enc.h +++ b/lib_enc/lib_enc.h @@ -383,12 +383,6 @@ void IVAS_ENC_PrintDisclaimer( void ); -#ifdef IVAS_RTPDUMP -/*! r: true if ivas format is not mono */ -bool IVAS_isImmersiveFormat( - const IVAS_ENC_HANDLE hIvasEnc /* i : IVAS encoder handle */ -); -#endif #ifdef DEBUGGING int32_t IVAS_ENC_GetNoCLipping( IVAS_ENC_HANDLE hIvasEnc, /* i : IVAS encoder handle */ diff --git a/lib_util/ivas_bpool.c b/lib_util/ivas_bpool.c index 2bf707cea6..827422fac3 100644 --- a/lib_util/ivas_bpool.c +++ b/lib_util/ivas_bpool.c @@ -117,7 +117,7 @@ ivas_error BPOOL_GetBuffer( BPOOL_HANDLE handle, void **dataPtr ) if ( !isFree ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow, no free buffers in pool" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow, no free buffers in pool" ); } *dataPtr = handle->freeBuffers[idx]; diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index f716f31eee..468dce0d17 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -249,7 +249,7 @@ static ivas_error PackRtpHeader( buf->length = 0; if ( packedLength > buf->capacity ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient output buffer for RTP header packing" ); + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient output buffer for RTP header packing" ); } /* @@ -335,7 +335,7 @@ static ivas_error UnpackRtpPacket( if ( packet->length < expectedSize ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Insufficient input buffer for RTP header unpacking" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Insufficient input buffer for RTP header unpacking" ); } /* @@ -381,7 +381,7 @@ static ivas_error UnpackRtpPacket( expectedSize += ( header->CC ) * 4 + ( header->extension ? 4 : 0 ); if ( packet->length < expectedSize ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "CC indicated but insufficient input buffer" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "CC indicated but insufficient input buffer" ); } /* CSRC Identifiers */ @@ -404,7 +404,7 @@ static ivas_error UnpackRtpPacket( expectedSize += header->numExtUnits * 4; if ( packet->length < expectedSize ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Extension Header indicated but insufficient input buffer" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Extension Header indicated but insufficient input buffer" ); } header->extData = realloc( header->extData, header->numExtUnits * 4 ); @@ -1010,16 +1010,16 @@ ivas_error IVAS_RTP_PACK_PushPiData( 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_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); \ - goto err_exit; \ +#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( @@ -1088,7 +1088,7 @@ ivas_error IVAS_RTP_PACK_GetPayload( } else { - error = IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); + error = IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); goto err_exit; } payload->length += frameLength; @@ -1465,7 +1465,7 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy } else { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow during ToC SR byte" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during ToC SR byte" ); } #else /* Reserved bit not expected */ @@ -1529,7 +1529,7 @@ static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimes if ( nBytes + 1 >= payload->length ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow during expected PI Header read" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during expected PI Header read" ); } piHeader0 = payload->buffer[nBytes++]; @@ -1544,7 +1544,7 @@ static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimes piSize += byte; if ( nBytes >= payload->length ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow during reading piSize" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during reading piSize" ); } } while ( byte == 255 ); @@ -1552,7 +1552,7 @@ static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimes { if ( piSize > 0 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "NO_PI_DATA should be 0 sized" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "NO_PI_DATA should be 0 sized" ); } /* Do not add a node for NO_DATA */ @@ -1577,7 +1577,7 @@ static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimes } else { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow during reading pi data" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during reading pi data" ); } if ( PM == PI_HEADER_PM_LAST ) @@ -1669,7 +1669,7 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( } else { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "Underflow during expected frame bits" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during expected frame bits" ); } /* Add to frames FiFo */ @@ -1772,7 +1772,7 @@ ivas_error IVAS_RTP_UNPACK_PullFrame( /* Check if a node is available in FiFo */ if ( node == NULL ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "No more frames in unpack fifo" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "No more frames in unpack fifo" ); } length = ( node->toc.auNumBits + 7 ) / 8; @@ -1835,7 +1835,7 @@ ivas_error IVAS_RTP_UNPACK_PullNextPiData( /* Check if a node is available in FiFo */ if ( node == NULL ) { - return IVAS_ERROR( IVAS_ERR_UNDERFLOW, "No more pi data in unpack fifo" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "No more pi data in unpack fifo" ); } pi = (IVAS_PIDATA_GENERIC *) &node->data; diff --git a/lib_util/ivas_rtp_payload.h b/lib_util/ivas_rtp_payload.h deleted file mode 100644 index 92cb0e8e71..0000000000 --- a/lib_util/ivas_rtp_payload.h +++ /dev/null @@ -1,403 +0,0 @@ -/****************************************************************************************************** - - (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_PAYLOAD_H -#define IVAS_RTP_PAYLOAD_H - -#pragma once -#include -#include -#include -#include "common_api_types.h" -#include "ivas_cnst.h" -#include "rtpdump.h" - -#ifdef IVAS_RTPDUMP - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* clang-format off */ - -static const int32_t IVASmode2rate[16] = { - 13200, - 16400, - 24400, - 32000, - 48000, - 64000, - 80000, - 96000, - 128000, - 160000, - 192000, - 256000, - 384000, - 512000, - -1, /* Reserved */ - 5200 /* SID */ -}; - -typedef enum -{ - PF0 = 0, - PF1 = 1 -} PI_PF; - -typedef enum -{ - PM_RESERVED = 0, - PM_NOT_LAST = 1, - PM_LAST = 2, - PM_GENERAL = 3 -} PI_PM; - -typedef enum -{ - PI_SCENE_ORIENTATION = 0, - PI_DEVICE_ORIENTATION_COMPENSATED = 1, - PI_DEVICE_ORIENTATION_UNCOMPENSATED = 2, - PI_ACOUSTIC_ENVIRONMENT = 3, - PI_NO_DATA = 31 -} PI_TYPE; - -typedef enum -{ - PI_SCENE_ORIENTATION_SIZE_BYTES = 8, - PI_DEVICE_ORIENTATION_COMPENSATED_SIZE_BYTES = 8, - PI_DEVICE_ORIENTATION_UNCOMPENSATED_SIZE_BYTES = 8, - PI_ACOUSTIC_ENVIRONMENT_ID_SIZE_BYTES = 1, - PI_ACOUSTIC_ENVIRONMENT_ONLY_LATE_REVERB_SIZE_BYTES = 5, - PI_ACOUSTIC_ENVIRONMENT_LATE_REVERB_AND_EARLY_REFLECTIONS_SIZE_BYTES = 8, - PI_NO_DATA_SIZE_BYTES = 0 -} PI_SIZE_BYTES; - -typedef struct -{ - IVAS_QUATERNION sceneOrientationQuat; - IVAS_QUATERNION deviceOrientationQuat; - bool sceneOrientationPresent; - bool deviceOrientationPresent; -} PI_DATA_PACKER; - -typedef struct -{ - uint16_t w, x, y, z; -} IVAS_QUATERNION_Q15; - -typedef enum -{ - IVAS_CMR_13k2 = 0xF0, // 1111 0000 - IVAS_CMR_16k4 = 0xF1, // 1111 0001 - IVAS_CMR_24k4 = 0xF2, // 1111 0010 - IVAS_CMR_32k = 0xF3, // 1111 0011 - IVAS_CMR_48k = 0xF4, // 1111 0100 - IVAS_CMR_64k = 0xF5, // 1111 0101 - IVAS_CMR_80k = 0xF6, // 1111 0110 - IVAS_CMR_96k = 0xF7, // 1111 0111 - IVAS_CMR_128k = 0xF8, // 1111 1000 - IVAS_CMR_160k = 0xF9, // 1111 1001 - IVAS_CMR_192k = 0xFA, // 1111 1010 - IVAS_CMR_256k = 0xFB, // 1111 1011 - IVAS_CMR_384k = 0xFC, // 1111 1100 - IVAS_CMR_512k = 0xFD, // 1111 1101 - IVAS_CMR_RESERVED = 0xFE, // 1111 1110 - IVAS_CMR_NO_REQ = 0xFF // 1111 1111 -} IVAS_INITIAL_E_BYTE; - -typedef enum -{ - IVAS_BW_REQ_WB = 0x80, // 1000 0000 - IVAS_BW_REQ_SWB = 0x81, // 1000 0001 - IVAS_BW_REQ_FB = 0x82, // 1000 0010 - IVAS_BW_NO_REQ = 0x83, // 1000 0011 - IVAS_FMT_REQ_STEREO = 0xA0, // 1010 0000 - IVAS_FMT_REQ_SBA = 0xA1, // 1010 0001 - IVAS_FMT_REQ_MASA = 0xA2, // 1010 0010 - IVAS_FMT_REQ_ISM = 0xA3, // 1010 0011 - IVAS_FMT_REQ_MC = 0xA4, // 1010 0100 - IVAS_FMT_REQ_OMASA = 0xA5, // 1010 0101 - IVAS_FMT_REQ_OSBA = 0xA6, // 1010 0110 - IVAS_FMT_NO_REQ = 0xA7, // 1010 0111 - IVAS_PI_INDICATION = 0xC0 // 1100 0000 -} IVAS_SUBSEQUENT_E_BYTE; - -typedef enum -{ - WB_REQUEST, - SWB_REQUEST, - FB_REQUEST, - NO_BANDWIDTH_REQUEST -} IVAS_BANDWIDTH_REQUEST; - -typedef enum -{ - STEREO_REQUEST, - SBA_REQUEST, - MASA_REQUEST, - ISM_REQUEST, - MC_REQUEST, - OMASA_REQUEST, - OSBA_REQUEST, - NO_FORMAT_REQUEST -} IVAS_FORMAT_REQUEST; - -typedef enum -{ - E_BYTE = 0x80, // 1xxx xxxx - IVAS_E_CMR = 0xF0, // 1111 xxxx - IVAS_E_BW_REQUEST = 0x80, // 100x xxxx - IVAS_E_FMT_REQUEST = 0xA0, // 101x xxxx - IVAS_E_PI_INDICATION = 0xC0, // 110x xxxx - IVAS_E_RESERVED = 0xE0 // 111x xxxx -} IVAS_E_BYTE_INDICATIONS; - -typedef struct -{ - RTPDUMP_HANDLE rtpdump; - RTPDUMP_RTPPACKET rtpPacket; - uint32_t timeoffset_ms; - uint16_t frameIndex; - bool frameFollowing; - PI_DATA_DEPACKER_STATE PIdataDepackerState; -} IVAS_RTPDUMP_DEPACKER; - -typedef struct -{ - RTPDUMP_HANDLE rtpdump; - RTPDUMP_RTPPACKET rtpPacket; - uint32_t timeoffset_ms; - PI_DATA_PACKER piDataPacker; - bool piDataPresent; - int32_t writingIndex; -} IVAS_RTPDUMP_PACKER; - -typedef enum -{ - IVAS_RTPDUMP_DEPACKER_NO_ERROR = 0, - IVAS_RTPDUMP_DEPACKER_EOF = -1, - IVAS_RTPDUMP_DEPACKER_RTPDUMP_ERROR = 1, - IVAS_RTPDUMP_DEPACKER_PAYLOAD_ERROR -} IVAS_RTPDUMP_DEPACKER_ERROR; - -typedef enum -{ - IVAS_RTPDUMP_PACKER_NO_ERROR = 0, - IVAS_RTPDUMP_PACKER_RTPDUMP_ERROR = 1 -} IVAS_RTPDUMP_PACKER_ERROR; - - -/*-----------------------------------------------------------------------* - * ivasPayload_unpackFrame() - * - * Parse a single IVAS frame from the payload. Also read the IVAS payload header - * and parse the PI data associated with the IVAS frame. - *-----------------------------------------------------------------------*/ - -bool ivasPayload_unpackFrame( - char *payload, /* i : RTP payload data */ - uint16_t payloadSizeBytes, /* i : RTP payload size in bytes */ - uint16_t frameIndex, /* i : Index for the data frame in the payload */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - bool *frameFollowing, /* o : (F) bit in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeInBits, /* o : Data frame size in bits */ - PI_DATA_DEPACKER_STATE *PIdataDepackerState /* i/o: data handle for the PI depacker state */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_DEPACKER_open() - * - * Open IVAS rtpdump depacker. - *-----------------------------------------------------------------------*/ - -IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_open( - IVAS_RTPDUMP_DEPACKER *self, /* o : IVAS rtpdump depacker handle */ - FILE *file /* i : Input file containing the rtpdump */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_DEPACKER_readNextFrame() - * - * Unpack next frame from the RTP packet. If the packet is depleted, read the next RTP packet from the rtpdump. - *-----------------------------------------------------------------------*/ - -IVAS_RTPDUMP_DEPACKER_ERROR IVAS_RTPDUMP_DEPACKER_readNextFrame( - IVAS_RTPDUMP_DEPACKER *self, /* i/o: IVAS rtpdump depacker handle */ - uint16_t *rtpSequenceNumber, /* o : RTP sequence number of the read packet */ - uint32_t *rtpTimeStamp, /* o : RTP timestamp for the unpacked frame */ - uint32_t *rcvTime_ms, /* o : Time offset in milliseconds for the unpacked frame */ - bool *evsIvasModeBit, /* o : "EVS/IVAS mode bit" in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the "EVS mode bit" separating EVS Primary and AMR-WB IO modes (see A.2.2.1.2 in TS26.445) */ - uint16_t *bitrateIndex, /* o : Bitrate index (BR) in the ToC byte (see A.3.3.3.2 in TS26.253 for IVAS or A.2.2.1.2 in TS26.445 for EVS) */ - bool *ivasIndicatorBit, /* o : "IVAS indicator" bit in the ToC byte (see A.3.3.3.2 in TS26.253). - * In EVS mode, this is the Q-bit (see A.2.2.1.2 in TS26.445) */ - bool *isGoodFrame, /* o : Good frame indicator (set by the Q-bit in AMR-WB IO mode, otherwise always set to true) */ - unsigned char **frame, /* o : Data frame indicated by frameIndex */ - uint16_t *frameSizeBits /* o : Data frame size in bits */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_DEPACKER_close() - * - * Close IVAS rtpdump depacker. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_DEPACKER_close( - IVAS_RTPDUMP_DEPACKER *self /* i : IVAS rtpdump depacker handle */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_open() - * - * Open IVAS rtpdump packer. - *-----------------------------------------------------------------------*/ - -IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_open( - IVAS_RTPDUMP_PACKER **rtpdumpPacker, /* o : IVAS rtpdump packer handle */ - FILE *file /* i : Output file for the rtpdump stream */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writeEbytes() - * - * Write E-bytes (CMR and subsequent E-bytes) to the RTP packet. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_writeEbytes( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet for bidirectional signalling */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS). - * Immersive bitrate CMRs follow A.3.3.3.3.2 in TS26.253. Mono bitrate CMRs follow A.2.2.1.1 in TS26.445. */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet for bidirectional signalling */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet for bidirectional signalling */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writeToc() - * - * Write a single ToC byte to the RTP packet. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_writeToc( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - int32_t frameBitrate, /* i : Bitrate of the written frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS). - * Immersive format ToCs follow A.3.3.2 in TS26.253. Mono format ToCs follow A.2.2.1.2 in TS26.445.*/ - bool someFrameFollowing /* i : Flag to indicate if another frame follows this frame in the same RTP packet. */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writeNextFrame() - * - * Write IVAS payload header, a single frame data and optional PI data to an RTP packet. - *-----------------------------------------------------------------------*/ - -IVAS_RTPDUMP_PACKER_ERROR IVAS_RTPDUMP_PACKER_writeNextFrame( - IVAS_RTPDUMP_PACKER *self, /* i/o: IVAS rtpdump packer handle */ - const uint16_t *bitStream, /* i : Bitstream containing the data frame to be written */ - int32_t numBits, /* i : Number of bits contained in the data frame */ - bool isImmersiveFormat, /* i : Flag to indicate if the frame is in immersive format (IVAS) or in mono format (EVS) */ - int32_t requestedBitrate, /* i : Requested bitrate to be written as CMR in the packet */ - bool requestImmersiveFormatBitrate, /* i : Flag to indicate if the requested bitrate is for immersive modes (IVAS) or mono mode (EVS) */ - IVAS_BANDWIDTH_REQUEST ivasBandwidthRequest, /* i : Requested bandwidth to be written as subsequent E-byte in the packet */ - IVAS_FORMAT_REQUEST ivasFormatRequest /* i : Requested format to be written as subsequent E-byte in the packet */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_writePIdata() - * - * Write PI data section (PI headers and PI frame data) to the RTP packet. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_writePIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_determinePIpresence() - * - * Check if there is PI data present for the current frame. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_determinePIpresence( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_resetPIdata() - * - * Reset PI data packer handle. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_resetPIdata( - IVAS_RTPDUMP_PACKER *self /* i/o: IVAS rtpdump packer handle */ -); - - -/*-----------------------------------------------------------------------* - * IVAS_RTPDUMP_PACKER_close() - * - * Close IVAS rtpdump packer. - *-----------------------------------------------------------------------*/ - -void IVAS_RTPDUMP_PACKER_close( - IVAS_RTPDUMP_PACKER **self /* i : IVAS rtpdump packer handle */ -); - - - /* clang-format on */ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif /* IVAS_RTP_PAYLOAD_H */ diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index d3e8774281..f006b82a88 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -30,6 +30,7 @@ *******************************************************************************************************/ +#include #include "ivas_rtp_pi_data.h" #include "ivas_error_utils.h" #include "ivas_rtp_internal.h" @@ -94,7 +95,7 @@ static ivas_error packNoPiData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buff /* NO_PI_DATA is just PI header with no data */ if ( maxDataBytes < 2 ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in PI data buffer for NO_PI_DATA" ); + 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 */ @@ -110,7 +111,7 @@ static ivas_error unpackNoPiData( const uint8_t *buffer, uint32_t numDataBytes, if ( numDataBytes != 0 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "NO_PI_DATA must be 0 byte" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "NO_PI_DATA must be 0 byte" ); } piData->size = sizeof( IVAS_PIDATA_NO_DATA ); @@ -141,7 +142,7 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b /* Orientation data is 8 bytes, header is 2 bytes */ if ( maxDataBytes < 8 + 2 ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Orientation PI data" ); + 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 */ @@ -162,7 +163,7 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte /* Orientation data is 8 bytes */ if ( numDataBytes != 8 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); @@ -275,7 +276,7 @@ static ivas_error unpackAcousticEnvironment( const uint8_t *buffer, uint32_t num /* Acooustic Env data is either 1, 5 or 8 bytes */ if ( numDataBytes != 1 && numDataBytes != 5 && numDataBytes != 8 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack PI data of type Acoustic Environment" ); + 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 ); @@ -338,7 +339,7 @@ static ivas_error packAudioDescription( const IVAS_PIDATA_GENERIC *piData, uint8 /* Audio Description data is max 5 bytes, 2 bytes header */ if ( maxDataBytes < packedSize + 2 ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in Audio Description PI data buffer" ); + 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 */ @@ -365,7 +366,7 @@ static ivas_error unpackAudioDescription( const uint8_t *buffer, uint32_t numDat /* Audio Description data is max 5 bytes */ if ( numDataBytes > ( IVAS_PI_MAX_OBJECTS + 1 ) ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } audioDesc->size = sizeof( IVAS_PIDATA_AUDIO_DESC ); @@ -394,7 +395,7 @@ static ivas_error packDynamicSuppression( const IVAS_PIDATA_GENERIC *piData, uin /* Dynamic Audio Suppression data is 2 bytes, 2 bytes header */ if ( maxDataBytes < 2 + 2 ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in DAS PI data buffer" ); + 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 */ @@ -416,7 +417,7 @@ static ivas_error unpackDynamicSuppression( const uint8_t *buffer, uint32_t numD /* Dynamic Suppression data is 2 bytes */ if ( numDataBytes != 2 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack DAS PI data" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack DAS PI data" ); } das->size = sizeof( IVAS_PIDATA_AUDIO_DESC ); @@ -449,7 +450,7 @@ static ivas_error packListenerPosition( const IVAS_PIDATA_GENERIC *piData, uint8 /* Position data is 6 bytes, header is 2 bytes */ if ( maxDataBytes < 6 + 2 ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack LISTENER POSITION PI data" ); + 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 */ @@ -468,7 +469,7 @@ static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDat /* Position data is 6 bytes */ if ( numDataBytes != 6 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack LISTENER POSITION PI data" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack LISTENER POSITION PI data" ); } listener->size = sizeof( IVAS_PIDATA_LISTENER_POSITION ); @@ -500,7 +501,7 @@ static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buff /* Diegetic data is 1 bytes, header is 2 bytes */ if ( maxDataBytes < 1 + 2 ) { - return IVAS_ERROR( IVAS_ERR_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Diegetic Type PI data" ); + 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 */ @@ -527,7 +528,7 @@ static ivas_error unpackDiegetic( const uint8_t *buffer, uint32_t numDataBytes, /* Diegetic data is 1 bytes */ if ( numDataBytes != 1 ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Incorrect size to unpack Diegetic PI data" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Diegetic PI data" ); } diegetic->size = sizeof( IVAS_PIDATA_DIEGETIC ); @@ -710,7 +711,7 @@ ivas_error PI_UnPackData( uint8_t piDataType, uint32_t piSize, const uint8_t *pi /* Sanitize maximum sizes for each PI Type */ if ( piSize > maxPiDataSize[piDataType] ) { - return IVAS_ERROR( IVAS_ERR_UNPACK_PI_DATA, "Max size for PI Data type exceeded" ); + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Max size for PI Data type exceeded" ); } error = unpackPiDataFuntions[piDataType]( piDataBuffer, piSize, piData ); @@ -722,4 +723,33 @@ ivas_error PI_UnPackData( uint8_t piDataType, uint32_t piSize, const uint8_t *pi 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_rom.c b/lib_util/ivas_rtp_rom.c deleted file mode 100644 index 016e6ce34e..0000000000 --- a/lib_util/ivas_rtp_rom.c +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************************************** - - (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_rtp_internal.h" - -#ifdef IVAS_RTPDUMP - -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 */ -- GitLab From 75b97ed518dc9cf96b36afee5dfe89c50bb1e303 Mon Sep 17 00:00:00 2001 From: Ripinder Singh Date: Wed, 10 Sep 2025 21:28:13 +1000 Subject: [PATCH 33/33] code review Format, fixcmdline for self_test.prn is not followed by number Signed-off-by: Ripinder Singh --- lib_com/ivas_error.h | 16 + lib_util/ivas_bpool.h | 3 +- lib_util/ivas_queue.h | 2 +- lib_util/ivas_rtp_api.h | 1064 +++++++++++++++++----------------- lib_util/ivas_rtp_file.c | 2 +- lib_util/ivas_rtp_file.h | 14 +- lib_util/ivas_rtp_pi_data.c | 16 +- scripts/config/self_test.prm | 18 +- 8 files changed, 569 insertions(+), 566 deletions(-) diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index 66fa262d37..4a5249934c 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -296,6 +296,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_util/ivas_bpool.h b/lib_util/ivas_bpool.h index ae8f114127..30cf4962b5 100644 --- a/lib_util/ivas_bpool.h +++ b/lib_util/ivas_bpool.h @@ -33,9 +33,8 @@ #ifndef IVAS_BPOOL_H #define IVAS_BPOOL_H -#include #include -#include "ivas_error.h" +#include "common_api_types.h" /* Forward declaraiton of opaque buffer pool handle */ typedef struct BPOOL *BPOOL_HANDLE; diff --git a/lib_util/ivas_queue.h b/lib_util/ivas_queue.h index 9f2a9a856c..1c6b77504e 100644 --- a/lib_util/ivas_queue.h +++ b/lib_util/ivas_queue.h @@ -34,7 +34,7 @@ #define IVAS_QUEUE_H #include -#include "ivas_error.h" +#include "common_api_types.h" typedef struct NODE { diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 29ed397beb..06c56cd70f 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -33,47 +33,39 @@ #ifndef IVAS_RTP_API_H #define IVAS_RTP_API_H -#pragma once #include #include -#include -#include "options.h" -#include "ivas_error.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* - * +-----------------------+---------------------+--------------------+----------+ - * | 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 - * - */ +#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 */ @@ -88,516 +80,512 @@ extern "C" #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; +/* 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; +/* 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 */ +/* 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 */ + 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; + 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; +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) */ +/**********************************************/ +/* 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) */ + 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 */ - ); - -#ifdef __cplusplus -} -#endif + 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 index 0112fdfb54..0851a998f6 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -77,7 +77,7 @@ ivas_error IvasRtpFile_Close( ( *phReader )->f_rtpstream = NULL; } free( *phReader ); - *phReader = NULL; + *phReader = NULL; } return IVAS_ERR_OK; diff --git a/lib_util/ivas_rtp_file.h b/lib_util/ivas_rtp_file.h index 47d545208a..3156c34cb2 100644 --- a/lib_util/ivas_rtp_file.h +++ b/lib_util/ivas_rtp_file.h @@ -33,29 +33,29 @@ #ifndef IVAS_RTP_FILE_H #define IVAS_RTP_FILE_H -#include #include -#include "ivas_error.h" +#include +#include "common_api_types.h" typedef struct IVAS_RTP_FILE *IVAS_RTP_FILE_HANDLE; -ivas_error IvasRtpFile_Open ( +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 */ ); -ivas_error IvasRtpFile_Close ( - IVAS_RTP_FILE_HANDLE *phReader /* i : pointer to an IVAS file reader handle */ +ivas_error IvasRtpFile_Close( + IVAS_RTP_FILE_HANDLE *phReader /* i : pointer to an IVAS file reader handle */ ); -ivas_error IvasRtpFile_Write ( +ivas_error IvasRtpFile_Write( IVAS_RTP_FILE_HANDLE hReader, /* i : pointer to an IVAS file writer handle */ const uint8_t *packet, /* i : pointer to packed rtp packet */ size_t numBytes /* i : length of the packet in bytes */ ); -ivas_error IvasRtpFile_Read ( +ivas_error IvasRtpFile_Read( IVAS_RTP_FILE_HANDLE hReader, /* i : pointer to an IVAS file writer handle */ uint8_t *packet, /* o : buffer where packet is to be written */ size_t *numBytes, /* o : length of the packet in bytes */ diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index f006b82a88..e7dcde8998 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -555,7 +555,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 */ packUnsupportedData, /* ISM_NUM */ packUnsupportedData, /* ISM_ID */ @@ -567,7 +567,7 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #ifdef RTP_S4_251135_CR26253_0016_REV1 packDiegetic, /* DIEGETIC_TYPE */ #else - packUnsupportedData, /* DIEGETIC_TYPE */ + packUnsupportedData, /* DIEGETIC_TYPE */ #endif packUnsupportedData, /* RESERVED13 */ packUnsupportedData, /* RESERVED14 */ @@ -579,11 +579,11 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */ packOrientation, /* AUDIO_FOCUS_DIRECTION */ #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 */ @@ -591,7 +591,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 */ diff --git a/scripts/config/self_test.prm b/scripts/config/self_test.prm index 7f857487b9..7bfe33e4de 100644 --- a/scripts/config/self_test.prm +++ b/scripts/config/self_test.prm @@ -307,7 +307,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec EXT 48 bit testv/stvST48c.wav_stereo_sw_48-48_DTX_EXT.tst // stereo bitrate switching from 13.2 kbps to 128 kbps, 48kHz in, 48kHz out, DTX on, EXT out, rtpdump -../IVAS_cod -rtpdump -dtx -stereo ../scripts/switchPaths/sw_13k2_to_128k_10fr.bin 48 testv/stvST48c.wav bit +../IVAS_cod -rtpdump 3 -dtx -stereo ../scripts/switchPaths/sw_13k2_to_128k_10fr.bin 48 testv/stvST48c.wav bit ../IVAS_dec -VOIP_hf_only=1 EXT 48 bit testv/stvST48c.wav_stereo_sw_48-48_DTX_EXT_rtpdump.tst @@ -584,7 +584,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec BINAURAL_ROOM_REVERB 48 bit testv/stv4ISM48n.wav_BINAURAL_ROOM_REVERB_128000_48-48.tst // 4 ISM with metadata bitrate switching from 24.4 kbps to 512 kbps, 48 kHz in, 48 kHz out, DTX on, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case00_3000_q.csv -dtx -ism 4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv ../scripts/switchPaths/sw_24k4_512k.bin 48 testv/stv4ISM48s.wav bit +../IVAS_cod -rtpdump 3 -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case00_3000_q.csv -dtx -ism 4 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv ../scripts/switchPaths/sw_24k4_512k.bin 48 testv/stv4ISM48s.wav bit ../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv4ISM48s.wav_brate_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst @@ -965,7 +965,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec -render_config testv/rend_config_recreation.cfg BINAURAL_ROOM_REVERB 48 bit testv/stv3OA48c.wav_BINAURAL_ROOM_REVERB_96000_48-48_custom_configuration.tst // SBA FOA bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, DTX on, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot_case01_3000_q.csv -device_orientation testv/headrot_case02_3000_q.csv -dtx -sba 1 -max_band fb ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvFOA48c.wav bit +../IVAS_cod -rtpdump 3 -scene_orientation testv/headrot_case01_3000_q.csv -device_orientation testv/headrot_case02_3000_q.csv -dtx -sba 1 -max_band fb ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvFOA48c.wav bit ../IVAS_dec -VOIP_hf_only=1 FOA 48 bit testv/stvFOA48c.wav_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst @@ -1248,7 +1248,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec -render_config testv/rend_config_combined.cfg -t testv/headrot.csv BINAURAL_ROOM_REVERB 48 bit testv/stv1MASA1TC48c.wav_BINAURAL_ROOM_REVERB_256000_48-48_Headrot_custom_config.tst // MASA 2dir 2TC bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, DTX on, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot_case03_3000_q.csv -device_orientation testv/headrot.csv -dtx -masa 2 testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stv2MASA2TC48c.wav bit +../IVAS_cod -rtpdump 3 -scene_orientation testv/headrot_case03_3000_q.csv -device_orientation testv/headrot.csv -dtx -masa 2 testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stv2MASA2TC48c.wav bit ../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv2MASA2TC48c.wav_sw_48-48_DTX_BINAURAL_rtpdump_PIdata.tst @@ -1574,7 +1574,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec EXT 48 bit testv/stv714MC48c.wav_sw_48-48_EXT.tst // Multi-channel 5_1 bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case02_3000_q.csv -mc 5_1 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv51MC48c.wav bit +../IVAS_cod -rtpdump 3 -scene_orientation testv/headrot.csv -device_orientation testv/headrot_case02_3000_q.csv -mc 5_1 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv51MC48c.wav bit ../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stv51MC48c.wav_sw_48-48_BINAURAL_rtpdump_PIdata.tst @@ -1587,7 +1587,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec 48 bit testv/stvST48c.wav_StereoDmxEVS_24400_48-48.tst // Stereo downmix to bit-exact EVS at 24400 kbps, 48kHz in, 48kHz out, rtpdump -../IVAS_cod -rtpdump -stereo_dmx_evs 24400 48 testv/stvST48c.wav bit +../IVAS_cod -rtpdump 3 -stereo_dmx_evs 24400 48 testv/stvST48c.wav bit ../IVAS_dec -VOIP_hf_only=1 48 bit testv/stvST48c.wav_StereoDmxEVS_24400_48-48_rtpdump.tst @@ -1600,7 +1600,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec -non_diegetic_pan 80 STEREO 48 bit testv/stv1ISM48s.pcm_ISM_32000_48-48_STEREO_NON-DIEGETIC-PAN_80.tst // EVS at 13.2 kbps, 48kHz in, 48kHz out, STEREO out, rtpdump -../IVAS_cod -rtpdump 13200 48 testv/stv48c.wav bit +../IVAS_cod -rtpdump 3 13200 48 testv/stv48c.wav bit ../IVAS_dec -VOIP_hf_only=1 48 bit testv/stv48c.pcm_EVS_13200_48-48_STEREO_rtpdump.tst @@ -1880,7 +1880,7 @@ eid-xor -fer -vbr -bs g192 -ep g192 bit ../scripts/dly_error_profiles/ep_5pct.g1 ../IVAS_dec EXT 48 bit testv/stvOMASA_4ISM_2MASA2TC48c.wav_EXT_sw_48-48.tst // OMASA 2Dir2TC 3ISM at br sw techs 13.2 to 512 kbps start 160 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot_case01_3000_q.csv -device_orientation testv/headrot_case00_3000_q.csv -ism_masa 3 2 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k_2fr_start_160k_omasatechs_3ism.bin 48 testv/stvOMASA_3ISM_2MASA2TC48c.wav bit +../IVAS_cod -rtpdump 3 -scene_orientation testv/headrot_case01_3000_q.csv -device_orientation testv/headrot_case00_3000_q.csv -ism_masa 3 2 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k_2fr_start_160k_omasatechs_3ism.bin 48 testv/stvOMASA_3ISM_2MASA2TC48c.wav bit ../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stvOMASA_3ISM_2MASA2TC48c.wav_BINAURAL_sw_48-48_rtpdump_PIdata.tst @@ -2024,7 +2024,7 @@ networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit ../IVAS_dec -no_delay_cmp -Tracefile tracefile_dec -VOIP BINAURAL_ROOM_REVERB 48 netsimoutput testv/stvOSBA_2ISM_2OA32c.wav_BINAURAL_brsw_32-48_JBM5.tst // OSBA 2ISM 2OA at bitrate switching 13.2 to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data -../IVAS_cod -rtpdump -scene_orientation testv/headrot_case00_3000_q.csv -device_orientation testv/headrot_case03_3000_q.csv -ism_sba 2 2 testv/stvISM1.csv testv/stvISM2.csv ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvOSBA_2ISM_2OA48c.wav bit +../IVAS_cod -rtpdump 3 -scene_orientation testv/headrot_case00_3000_q.csv -device_orientation testv/headrot_case03_3000_q.csv -ism_sba 2 2 testv/stvISM1.csv testv/stvISM2.csv ../scripts/switchPaths/sw_13k2_512k.bin 48 testv/stvOSBA_2ISM_2OA48c.wav bit ../IVAS_dec -VOIP_hf_only=1 BINAURAL 48 bit testv/stvOSBA_2ISM_2OA48c.wav_BINAURAL_sw_48-48_rtpdump_PIdata.tst -- GitLab