diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj
index bead7110f33c5f14f0318980c52e315d490a5d9b..85859e257cb0d7e5ebb4efb670a53c44e7cd6361 100644
--- a/Workspace_msvc/lib_util.vcxproj
+++ b/Workspace_msvc/lib_util.vcxproj
@@ -110,6 +110,12 @@
+
+
+
+
+
+
@@ -123,7 +129,6 @@
-
@@ -139,6 +144,14 @@
+
+
+
+
+
+
+
+
@@ -152,7 +165,6 @@
-
diff --git a/Workspace_msvc/lib_util.vcxproj.filters b/Workspace_msvc/lib_util.vcxproj.filters
index 8fc8082d1a4d9a3ab8790074ae02daf283a9ba20..07c8fdfe435e4f5835dd69ec4c25598d4e67e0f4 100644
--- a/Workspace_msvc/lib_util.vcxproj.filters
+++ b/Workspace_msvc/lib_util.vcxproj.filters
@@ -67,9 +67,6 @@
util_c
-
- util_c
-
util_c
@@ -82,6 +79,24 @@
util_c
+
+ util_c
+
+
+ util_c
+
+
+ util_c
+
+
+ util_c
+
+
+ util_c
+
+
+ util_c
+
@@ -150,9 +165,6 @@
util_h
-
- util_h
-
util_h
@@ -171,6 +183,30 @@
util_h
+
+ util_h
+
+
+ util_h
+
+
+ util_h
+
+
+ util_h
+
+
+ util_h
+
+
+ util_h
+
+
+ util_h
+
+
+ util_h
+
diff --git a/apps/decoder.c b/apps/decoder.c
index 63f68854776e937077ec9ef0522af8eeca6c3d7f..ed96f7919618ff1fc2c47531da14f77b5b81b8de 100644
--- a/apps/decoder.c
+++ b/apps/decoder.c
@@ -38,6 +38,9 @@
#include "bitstream_reader.h"
#include "evs_rtp_payload.h"
#include "ism_file_writer.h"
+#ifdef IVAS_RTPDUMP
+#include "ivas_rtp_file.h"
+#endif
#include "jbm_file_writer.h"
#include "hrtf_file_reader.h"
#include "ls_custom_file_reader.h"
@@ -129,6 +132,9 @@ typedef struct
IVAS_DEC_COMPLEXITY_LEVEL complexityLevel;
bool tsmEnabled;
IVAS_RENDER_FRAMESIZE renderFramesize;
+#ifdef IVAS_RTPDUMP
+ char *piOutputFilename;
+#endif
#ifdef DEBUGGING
#ifdef DEBUG_FOA_AGC
FILE *agcBitstream; /* temporary */
@@ -738,6 +744,7 @@ int main(
if ( arg.voipMode )
{
+
#ifdef FIX_1119_SPLIT_RENDERING_VOIP
error = decodeVoIP( arg, hBsReader, &hHrtfBinary, headRotReader, externalOrientationFileReader, refRotReader, referenceVectorReader, objectEditFileReader, &splitRendBits, hIvasDec, pcmBuf );
#else
@@ -968,6 +975,9 @@ static bool parseCmdlIVAS_dec(
arg->referenceVectorTrajFileName = NULL;
arg->enableExternalOrientation = false;
arg->externalOrientationTrajFileName = NULL;
+#ifdef IVAS_RTPDUMP
+ arg->piOutputFilename = NULL;
+#endif
#ifdef SUPPORT_JBM_TRACEFILE
arg->jbmTraceFilename = NULL;
@@ -1054,6 +1064,20 @@ static bool parseCmdlIVAS_dec(
arg->inputFormat = IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF;
i++;
}
+#ifdef IVAS_RTPDUMP
+ else if ( strcmp( argv_to_upper, "-PIDATAFILE" ) == 0 )
+ {
+ i++;
+ if ( argc - i <= 3 || argv[i][0] == '-' )
+ {
+ fprintf( stderr, "Error: PI Data Output file name not specified!\n\n" );
+ usage_dec();
+ return false;
+ }
+
+ arg->piOutputFilename = argv[i++];
+ }
+#endif
#ifdef SUPPORT_JBM_TRACEFILE
else if ( strcmp( argv_to_upper, "-TRACEFILE" ) == 0 )
{
@@ -1638,10 +1662,19 @@ static void usage_dec( void )
fprintf( stdout, "--------\n" );
fprintf( stdout, "-VOIP : VoIP mode: RTP in G192\n" );
fprintf( stdout, "-VOIP_hf_only=0 : VoIP mode: EVS RTP Payload Format hf_only=0 in rtpdump\n" );
+#ifdef IVAS_RTPDUMP
+ fprintf( stdout, "-VOIP_hf_only=1 : VoIP mode: EVS or IVAS RTP Payload Format hf_only=1 in rtpdump\n" );
+ fprintf( stdout, " The decoder may read rtpdump files containing TS26.445 Annex A.2.2\n" );
+ fprintf( stdout, " EVS RTP Payload Format or rtpdump files containing TS26.253 Annex A\n" );
+ fprintf( stdout, " IVAS RTP Payload Format. The SDP parameter hf_only is required.\n" );
+ fprintf( stdout, " Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.\n" );
+ fprintf( stdout, "-PiDataFile PF Log the timestampped PI data.\n" );
+#else
fprintf( stdout, "-VOIP_hf_only=1 : VoIP mode: EVS RTP Payload Format hf_only=1 in rtpdump\n" );
fprintf( stdout, " The decoder may read rtpdump files containing TS26.445 Annex A.2.2\n" );
fprintf( stdout, " EVS RTP Payload Format. The SDP parameter hf_only is required.\n" );
fprintf( stdout, " Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.\n" );
+#endif
#ifdef SUPPORT_JBM_TRACEFILE
fprintf( stdout, "-Tracefile TF : VoIP mode: Generate trace file named TF. Requires -no_delay_cmp to\n" );
fprintf( stdout, " be enabled so that trace contents remain in sync with audio output.\n" );
@@ -2881,24 +2914,40 @@ static ivas_error printBitstreamInfoVoip(
{
bool previewFailed = true;
ivas_error error = IVAS_ERR_OK;
+#ifdef IVAS_RTPDUMP
+ IVAS_RTP ivasRtp;
+ uint8_t au[( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3];
+ int16_t auSizeBits;
+ uint8_t *auPtr = NULL;
+#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;
uint8_t au[( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3];
int16_t auSizeBits;
uint8_t *auPtr = NULL;
- bool isAMRWB_IOmode;
- uint16_t frameTypeIndex;
+#endif
bool qBit;
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:
case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF:
+#ifdef IVAS_RTPDUMP
+ if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "error in IVAS_RTP_READER_Init(): %d\n", error );
+ goto cleanup;
+ }
+#else
f_rtpstream = fopen( arg.inputBitstreamFilename, "r" );
if ( f_rtpstream == NULL )
@@ -2913,6 +2962,7 @@ static ivas_error printBitstreamInfoVoip(
fprintf( stderr, "error in EVS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError );
goto cleanup;
}
+#endif
break;
case IVAS_DEC_INPUT_FORMAT_G192:
auPtr = au;
@@ -2933,12 +2983,20 @@ static ivas_error printBitstreamInfoVoip(
else
{
auPtr = au; /* might have been set to RTP packet in prev call */
+#ifdef IVAS_RTPDUMP
+ error = IVAS_RTP_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
/* 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;
@@ -2957,7 +3015,11 @@ static ivas_error printBitstreamInfoVoip(
cleanup:
+#ifdef IVAS_RTPDUMP
+ IVAS_RTP_Term( &ivasRtp );
+#else
EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker );
+#endif
if ( previewFailed && error == IVAS_ERR_OK )
{
@@ -3026,12 +3088,18 @@ static ivas_error decodeVoIP(
int16_t delayNumSamples = -1;
int32_t delayTimeScale = -1;
int16_t i;
+#ifdef IVAS_RTPDUMP
+ IVAS_RTP ivasRtp = { 0 };
+#else
FILE *f_rtpstream = NULL;
EVS_RTPDUMP_DEPACKER rtpdumpDepacker;
EVS_RTPDUMP_DEPACKER_ERROR rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_NO_ERROR;
+#endif
uint8_t *auPtr = NULL;
+#ifndef IVAS_RTPDUMP
bool isAMRWB_IOmode;
uint16_t frameTypeIndex;
+#endif
bool qBit;
IVAS_DEC_BS_FORMAT bsFormat = IVAS_DEC_BS_UNKOWN;
@@ -3092,11 +3160,20 @@ static ivas_error decodeVoIP(
delayNumSamples_orig[0] = -1;
+#ifndef IVAS_RTPDUMP
rtpdumpDepacker.rtpdump = NULL;
+#endif
switch ( arg.inputFormat )
{
case IVAS_DEC_INPUT_FORMAT_RTPDUMP:
case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF:
+#ifdef IVAS_RTPDUMP
+ if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "error in IVAS_RTP_READER_Init(): %d\n", error );
+ goto cleanup;
+ }
+#else
f_rtpstream = fopen( arg.inputBitstreamFilename, "r" );
if ( f_rtpstream == NULL )
@@ -3111,6 +3188,7 @@ static ivas_error decodeVoIP(
fprintf( stderr, "error in EVS_RTPDUMP_DEPACKER_open(): %d\n", rtpdumpDepackerError );
goto cleanup;
}
+#endif
break;
case IVAS_DEC_INPUT_FORMAT_G192:
auPtr = au;
@@ -3152,12 +3230,20 @@ static ivas_error decodeVoIP(
else
{
auPtr = au; /* might have been set to RTP packet in prev call */
+#ifdef IVAS_RTPDUMP
+ error = IVAS_RTP_ReadNextFrame( &ivasRtp, auPtr, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit );
+#else
rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp, &nextPacketRcvTime_ms, &isAMRWB_IOmode, &frameTypeIndex, &qBit, &auPtr, (uint16_t *) &auSize );
+#endif
/* EVS RTP payload format has timescale 16000, JBM uses 1000 internally */
rtpTimeStamp = rtpTimeStamp / 16;
}
+#ifdef IVAS_RTPDUMP
+ if ( error != IVAS_ERR_OK )
+#else
if ( error != IVAS_ERR_OK || rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR )
+#endif
{
fprintf( stderr, "failed to read first RTP packet\n" );
goto cleanup;
@@ -3327,19 +3413,34 @@ static ivas_error decodeVoIP(
else
{
auPtr = au; /* might have been set to RTP packet in prev call */
+#ifdef IVAS_RTPDUMP
+ error = IVAS_RTP_ReadNextFrame( &ivasRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &qBit );
+
+ /* IVAS RTP payload format has timescale 16000, JBM uses 1000 internally */
+ rtpTimeStamp = rtpTimeStamp / 16;
+#else
rtpdumpDepackerError = EVS_RTPDUMP_DEPACKER_readNextFrame( &rtpdumpDepacker, &rtpSequenceNumber, &rtpTimeStamp,
&nextPacketRcvTime_ms,
&isAMRWB_IOmode, &frameTypeIndex, &qBit,
&auPtr, (uint16_t *) &auSize );
/* EVS RTP payload format has timescale 16000, JBM uses 1000 internally */
rtpTimeStamp = rtpTimeStamp / 16;
+#endif
}
+#ifdef IVAS_RTPDUMP
+ if ( error == IVAS_ERR_END_OF_FILE )
+#else
if ( error == IVAS_ERR_END_OF_FILE || rtpdumpDepackerError == EVS_RTPDUMP_DEPACKER_EOF )
+#endif
{
/* finished reading */
nextPacketRcvTime_ms = (uint32_t) -1;
}
+#ifdef IVAS_RTPDUMP
+ else if ( error != IVAS_ERR_OK )
+#else
else if ( error != IVAS_ERR_OK || rtpdumpDepackerError != EVS_RTPDUMP_DEPACKER_NO_ERROR )
+#endif
{
fprintf( stderr, "\nError in BS_Reader_ReadVoipFrame_compact, error code: %d\n", error );
goto cleanup;
@@ -3735,7 +3836,11 @@ static ivas_error decodeVoIP(
cleanup:
+#ifdef IVAS_RTPDUMP
+ IVAS_RTP_Term( &ivasRtp );
+#else
EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker );
+#endif
AudioFileWriter_close( &afWriter );
#ifdef FIX_1119_SPLIT_RENDERING_VOIP
split_rend_reader_writer_close( &splitRendWriter );
diff --git a/apps/encoder.c b/apps/encoder.c
index 4d9626edc3f972407ac59ce47074f613529597d1..44fda79373b257c91adccbe9d0e54191c78e7383 100644
--- a/apps/encoder.c
+++ b/apps/encoder.c
@@ -38,6 +38,10 @@
#include "ism_file_reader.h"
#include "jbm_file_reader.h"
#include "masa_file_reader.h"
+#ifdef IVAS_RTPDUMP
+#include "rotation_file_reader.h"
+#include "ivas_rtp_file.h"
+#endif
#ifdef DEBUGGING
#include "debug.h"
#endif
@@ -149,6 +153,12 @@ typedef struct
#endif
bool pca;
bool ism_extended_metadata;
+#ifdef IVAS_RTPDUMP
+ bool rtpdumpOutput;
+ uint32_t numFramesPerPacket;
+ char *sceneOrientationTrajFileName;
+ char *deviceOrientationTrajFileName;
+#endif
} EncArguments;
@@ -192,6 +202,10 @@ int main(
MasaFileReader *masaReader = NULL;
IsmFileReader *ismReaders[IVAS_MAX_NUM_OBJECTS] = { NULL, NULL, NULL, NULL };
int16_t *pcmBuf = NULL;
+#ifdef IVAS_RTPDUMP
+ RotFileReader *sceneOrientationFileReader = NULL;
+ RotFileReader *deviceOrientationFileReader = NULL;
+#endif
#ifdef DEBUGGING
FILE *f_forcedModeProfile = NULL;
#ifdef DEBUG_SBA
@@ -212,6 +226,11 @@ int main(
enable_float_exception_trap( FLE_MASK_DENORM | FLE_MASK_UNDERFLOW );
#endif
+#ifdef IVAS_RTPDUMP
+ uint8_t au[IVAS_MAX_BITS_PER_FRAME / 8];
+ IVAS_RTP ivasRtp = { 0 };
+#endif
+
/*------------------------------------------------------------------------------------------*
* Parse command-line arguments
*------------------------------------------------------------------------------------------*/
@@ -240,7 +259,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;
@@ -598,6 +621,47 @@ int main(
}
}
+#ifdef IVAS_RTPDUMP
+ /*------------------------------------------------------------------------------------------*
+ * RTPDump
+ *------------------------------------------------------------------------------------------*/
+
+ if ( arg.rtpdumpOutput )
+ {
+ if ( ( error = IVAS_RTP_WRITER_Init( &ivasRtp, arg.outputBitstreamFilename, arg.numFramesPerPacket ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError: Can't open output bitstream file for RTP output %s \n\n", arg.outputBitstreamFilename );
+ goto cleanup;
+ }
+ }
+
+ /*------------------------------------------------------------------------------------------*
+ * Open scene orientation file
+ *------------------------------------------------------------------------------------------*/
+
+ if ( arg.sceneOrientationTrajFileName != NULL )
+ {
+ if ( ( error = RotationFileReader_open( arg.sceneOrientationTrajFileName, &sceneOrientationFileReader ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError: Can't open scene orientation file %s \n\n", arg.sceneOrientationTrajFileName );
+ goto cleanup;
+ }
+ }
+
+ /*------------------------------------------------------------------------------------------*
+ * Open device orientation file
+ *------------------------------------------------------------------------------------------*/
+
+ if ( arg.deviceOrientationTrajFileName != NULL )
+ {
+ if ( ( error = RotationFileReader_open( arg.deviceOrientationTrajFileName, &deviceOrientationFileReader ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError: Can't open device orientation file %s \n\n", arg.deviceOrientationTrajFileName );
+ goto cleanup;
+ }
+ }
+#endif
+
int16_t numSamplesRead = 0;
uint16_t bitStream[IVAS_MAX_BITS_PER_FRAME];
uint16_t numBits = 0;
@@ -762,18 +826,78 @@ int main(
}
/* *** Encode one frame *** */
- if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, pcmBuf, pcmBufSize, bitStream, &numBits ) ) != IVAS_ERR_OK )
+#ifdef IVAS_RTPDUMP
+ if ( ivasRtp.hPack )
{
- fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) );
- goto cleanup;
- }
+ bool isMono = ( arg.inputFormat == IVAS_ENC_INPUT_MONO );
+ bool forcePacket = ( numSamplesRead < pcmBufSize ); /* If EoF force Packet generation */
+
+ ivasRtp.nWrittenPiData = 0;
+
+ /* scene orientation */
+ if ( sceneOrientationFileReader )
+ {
+ PIDATA_TS *piDataTs = &ivasRtp.piData[ivasRtp.nWrittenPiData++];
+ IVAS_PIDATA_ORIENTATION *scene = &piDataTs->data.scene;
+
+ memset( piDataTs, 0, sizeof( PIDATA_TS ) );
+ scene->size = sizeof( IVAS_PIDATA_ORIENTATION );
+ scene->piDataType = IVAS_PI_SCENE_ORIENTATION;
+
+ if ( ( error = HeadRotationFileReading( sceneOrientationFileReader, &scene->orientation, NULL ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while reading scene orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( sceneOrientationFileReader ) );
+ goto cleanup;
+ }
+ }
+
+ /* device orientation */
+ if ( deviceOrientationFileReader )
+ {
+ PIDATA_TS *piDataTs = &ivasRtp.piData[ivasRtp.nWrittenPiData++];
+ IVAS_PIDATA_ORIENTATION *device = &piDataTs->data.deviceUnCompensated;
+
+ memset( piDataTs, 0, sizeof( PIDATA_TS ) );
+ device->size = sizeof( IVAS_PIDATA_ORIENTATION );
+ device->piDataType = IVAS_PI_DEVICE_ORIENTATION_COMPENSATED;
+
+ if ( ( error = HeadRotationFileReading( deviceOrientationFileReader, &device->orientation, NULL ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while reading device orientation from %s\n", IVAS_ENC_GetErrorMessage( error ), RotationFileReader_getFilePath( deviceOrientationFileReader ) );
+ goto cleanup;
+ }
+ }
- /* write bitstream */
- if ( ( error = BS_Writer_WriteFrame_short( hBsWriter, bitStream, numBits, totalBitrate ) ) != IVAS_ERR_OK )
+ if ( ( error = IVAS_ENC_EncodeFrameToCompact( hIvasEnc, pcmBuf, pcmBufSize, au, &numBits ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) );
+ goto cleanup;
+ }
+
+ if ( ( error = IVAS_RTP_WriteNextFrame( &ivasRtp, au, numBits, isMono, forcePacket ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while pushing audio frame to RTP pack\n", IVAS_ENC_GetErrorMessage( error ) );
+ goto cleanup;
+ }
+ }
+ else
{
- fprintf( stderr, "\nBS_Writer_WriteFrame_short failed, error code %d\n\n", error );
- goto cleanup;
+#endif
+ if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, pcmBuf, pcmBufSize, bitStream, &numBits ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nencodeFrame failed: %s\n\n", IVAS_ENC_GetErrorMessage( error ) );
+ goto cleanup;
+ }
+
+ /* write bitstream */
+ if ( ( error = BS_Writer_WriteFrame_short( hBsWriter, bitStream, numBits, totalBitrate ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nBS_Writer_WriteFrame_short failed, error code %d\n\n", error );
+ goto cleanup;
+ }
+#ifdef IVAS_RTPDUMP
}
+#endif
frame++;
if ( !arg.quietModeEnabled )
@@ -851,6 +975,20 @@ cleanup:
fclose( f_bitrateProfile );
}
+#ifdef IVAS_RTPDUMP
+ if ( sceneOrientationFileReader )
+ {
+ RotationFileReader_close( &sceneOrientationFileReader );
+ }
+
+ if ( deviceOrientationFileReader )
+ {
+ RotationFileReader_close( &deviceOrientationFileReader );
+ }
+
+ IVAS_RTP_Term( &ivasRtp );
+#endif
+
IVAS_ENC_Close( &hIvasEnc );
#ifdef WMOPS
@@ -921,6 +1059,11 @@ static bool parseCmdlIVAS_enc(
arg->mimeOutput = false;
arg->ism_extended_metadata = false;
arg->complexityLevel = IVAS_ENC_COMPLEXITY_LEVEL_THREE;
+#ifdef IVAS_RTPDUMP
+ arg->rtpdumpOutput = false;
+ arg->sceneOrientationTrajFileName = NULL;
+ arg->deviceOrientationTrajFileName = NULL;
+#endif
#ifdef DEBUGGING
arg->forcedMode = IVAS_ENC_FORCE_UNFORCED;
@@ -1715,6 +1858,71 @@ static bool parseCmdlIVAS_enc(
i++;
}
+#ifdef IVAS_RTPDUMP
+ /*-----------------------------------------------------------------*
+ * RTPDump output
+ *-----------------------------------------------------------------*/
+
+ else if ( strcmp( argv_to_upper, "-RTPDUMP" ) == 0 )
+ {
+ i++;
+ arg->rtpdumpOutput = true;
+ if ( i < argc - 4 )
+ {
+ if ( !is_digits_only( argv[i] ) )
+ {
+ arg->numFramesPerPacket = 1; /* Default to 1 frame per packet */
+ }
+ else
+ {
+ arg->numFramesPerPacket = atoi( argv[i++] );
+ if ( arg->numFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET )
+ {
+ fprintf( stderr, "numFramesPerPacket(%d) exceeds max frames per packet (%d) \n", arg->numFramesPerPacket, IVAS_MAX_FRAMES_PER_RTP_PACKET );
+ arg->numFramesPerPacket = 1;
+ }
+ }
+ }
+ fprintf( stdout, "Output format: RTPDump using %d frames/packet \n", arg->numFramesPerPacket );
+ }
+
+ /*-----------------------------------------------------------------*
+ * Scene orientation
+ *-----------------------------------------------------------------*/
+
+ else if ( strcmp( argv_to_upper, "-SCENE_ORIENTATION" ) == 0 )
+ {
+ i++;
+ if ( argc - i <= 4 || argv[i][0] == '-' )
+ {
+ fprintf( stderr, "Error: Scene orientation file name not specified!\n\n" );
+ usage_enc();
+ return false;
+ }
+
+ arg->sceneOrientationTrajFileName = argv[i];
+ i++;
+ }
+
+ /*-----------------------------------------------------------------*
+ * Device orientation
+ *-----------------------------------------------------------------*/
+
+ else if ( strcmp( argv_to_upper, "-DEVICE_ORIENTATION" ) == 0 )
+ {
+ i++;
+ if ( argc - i <= 4 || argv[i][0] == '-' )
+ {
+ fprintf( stderr, "Error: Device orientation file name not specified!\n\n" );
+ usage_enc();
+ return false;
+ }
+
+ arg->deviceOrientationTrajFileName = argv[i];
+ i++;
+ }
+
+#endif
/*-----------------------------------------------------------------*
* Option not recognized
*-----------------------------------------------------------------*/
@@ -1726,6 +1934,21 @@ 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;
+ }
+
+#endif
/*-----------------------------------------------------------------*
* Mandatory input arguments
*-----------------------------------------------------------------*/
@@ -1932,6 +2155,14 @@ static void usage_enc( void )
#endif
fprintf( stdout, "-q : Quiet mode, no frame counters\n" );
fprintf( stdout, " default is deactivated\n" );
+#ifdef IVAS_RTPDUMP
+ fprintf( stdout, "-rtpdump : RTPDump output, hf_only=1 by default. The encoder will packetize the \n" );
+ fprintf( stdout, " bitstream frames into TS26.253 Annex A IVAS RTP Payload Format packets and \n" );
+ fprintf( stdout, " writes those to the output file. In EVS mono operating mode, TS26.445 Annex A.2.2 \n" );
+ fprintf( stdout, " EVS RTP Payload Format is used. Optional N represents number of frames per RTP packet\n" );
+ fprintf( stdout, "-scene_orientation : Scene orientation trajectory file. Only used with rtpdump output.\n" );
+ fprintf( stdout, "-device_orientation : Device orientation trajectory file. Only used with rtpdump output.\n" );
+#endif
fprintf( stdout, "\n" );
return;
diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h
index 563b10e39112c34c9c5093d1d50bde1242ca558a..4a5249934ce8cd4167a9d3a39b410dc9c9bee7b2 100644
--- a/lib_com/ivas_error.h
+++ b/lib_com/ivas_error.h
@@ -151,6 +151,14 @@ typedef enum
IVAS_ERR_LC3PLUS_INVALID_BITRATE,
IVAS_ERR_INVALID_SPLIT_REND_CONFIG,
+ /*----------------------------------------*
+ * rtp errors *
+ *----------------------------------------*/
+ IVAS_ERR_RTP_UNDERFLOW = 0x7000,
+ IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE,
+ IVAS_ERR_RTP_UNPACK_PI_DATA,
+ IVAS_ERR_RTP_UNSUPPORTED_FRAME,
+
/*----------------------------------------*
* unknown error *
*----------------------------------------*/
@@ -288,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_com/options.h b/lib_com/options.h
index 2266c70dbbdabd3494847e34fa383126c24ed4c7..682494ad64b4cd50e15f0382b960e89ceed17064 100755
--- a/lib_com/options.h
+++ b/lib_com/options.h
@@ -159,6 +159,9 @@
/* ################## 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 ################################# */
/* only BE switches wrt selection floating point code */
diff --git a/lib_util/g192.c b/lib_util/g192.c
index a96a8ee56dc1ea4997e164f35c70beedd178dad7..a5eb030a4fd4bb37dcb9fbd96d7f8b67d0e61121 100644
--- a/lib_util/g192.c
+++ b/lib_util/g192.c
@@ -482,7 +482,11 @@ G192_ERROR G192_WriteVoipFrame_short(
const uint16_t *serial,
const int16_t numBits,
uint16_t const rtpSequenceNumber,
+#ifdef IVAS_RTPDUMP
+ uint32_t const rtpTimeStamp,
+#else
uint16_t const rtpTimeStamp,
+#endif
uint32_t const rcvTime_ms )
{
int16_t G192_HEADER[2], G192_DATA[IVAS_MAX_BITS_PER_FRAME];
diff --git a/lib_util/g192.h b/lib_util/g192.h
index 751f1324fb286131ba1cd8fd23d68622e69fce3c..0c22b739b9ff372d2939c423615a13458d31e7fd 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_bpool.c b/lib_util/ivas_bpool.c
new file mode 100644
index 0000000000000000000000000000000000000000..9db909f535e17a2911ab7e809c3a27caaf277edd
--- /dev/null
+++ b/lib_util/ivas_bpool.c
@@ -0,0 +1,153 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+#include
+#include
+#include "ivas_bpool.h"
+#include "ivas_error_utils.h"
+#include "mutex.h"
+
+struct BPOOL
+{
+ mtx_t lock;
+ uint32_t bufferSize;
+ uint32_t numBuffers;
+ uint32_t numFreeBuffers;
+ void **freeBuffers;
+};
+
+ivas_error BPOOL_Create( BPOOL_HANDLE *pHandle, size_t bufferSize, uint32_t numBuffers )
+{
+ uint32_t n;
+ uint8_t *base = NULL;
+ BPOOL_HANDLE handle;
+ size_t allocSize = sizeof( struct BPOOL );
+
+ if ( pHandle == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer to Buffer Pool Handle" );
+ }
+
+ *pHandle = NULL;
+
+ allocSize += bufferSize * numBuffers; /* pool memory */
+ allocSize += sizeof( void * ) * numBuffers; /* free buffers stack */
+
+ base = calloc( allocSize, sizeof( uint8_t ) );
+ if ( base == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Couldn't allocate Buffer pool" );
+ }
+
+ handle = (BPOOL_HANDLE) base;
+ base += sizeof( struct BPOOL );
+
+ mtx_init( &handle->lock, 0 );
+ handle->bufferSize = bufferSize;
+ handle->numBuffers = numBuffers;
+ handle->numFreeBuffers = numBuffers;
+ handle->freeBuffers = (void **) base;
+ base += ( sizeof( void * ) * numBuffers );
+ for ( n = 0; n < numBuffers; n++ )
+ {
+ handle->freeBuffers[n] = base;
+ base += bufferSize;
+ }
+
+ *pHandle = handle;
+ return IVAS_ERR_OK;
+}
+
+void BPOOL_Destroy( BPOOL_HANDLE *pHandle )
+{
+ if ( ( pHandle != NULL ) && ( *pHandle != NULL ) )
+ {
+ mtx_destroy( &( *pHandle )->lock );
+ free( *pHandle );
+ *pHandle = NULL;
+ }
+}
+
+ivas_error BPOOL_GetBuffer( BPOOL_HANDLE handle, void **dataPtr )
+{
+ uint32_t idx = 0;
+ bool isFree = false;
+
+ if ( handle == NULL || dataPtr == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer args in GetBuffer" );
+ }
+
+ mtx_lock( &handle->lock );
+ isFree = ( handle->numFreeBuffers > 0 );
+ if ( isFree )
+ {
+ idx = --handle->numFreeBuffers;
+ }
+ mtx_unlock( &handle->lock );
+
+ if ( !isFree )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow, no free buffers in pool" );
+ }
+
+ *dataPtr = handle->freeBuffers[idx];
+ return IVAS_ERR_OK;
+}
+
+/* return the buffer back to pool */
+ivas_error BPOOL_FreeBuffer( BPOOL_HANDLE handle, void *dataPtr )
+{
+ uint32_t idx;
+
+ if ( handle == NULL || dataPtr == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer args in GetBuffer" );
+ }
+
+ mtx_lock( &handle->lock );
+ idx = handle->numFreeBuffers++;
+ mtx_unlock( &handle->lock );
+
+ handle->freeBuffers[idx] = dataPtr;
+
+ return IVAS_ERR_OK;
+}
+
+/* return the number of free buffers available atm in the pool */
+uint32_t BPOOL_AvailableBuffers( BPOOL_HANDLE handle )
+{
+ uint32_t numFreeBuffers;
+ mtx_lock( &handle->lock );
+ numFreeBuffers = handle->numFreeBuffers;
+ mtx_unlock( &handle->lock );
+ return numFreeBuffers;
+}
diff --git a/lib_util/ivas_bpool.h b/lib_util/ivas_bpool.h
new file mode 100644
index 0000000000000000000000000000000000000000..30cf4962b5198fd2a22a522061e8ce4cff2be915
--- /dev/null
+++ b/lib_util/ivas_bpool.h
@@ -0,0 +1,57 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef IVAS_BPOOL_H
+#define IVAS_BPOOL_H
+
+#include
+#include "common_api_types.h"
+
+/* Forward declaraiton of opaque buffer pool handle */
+typedef struct BPOOL *BPOOL_HANDLE;
+
+/* Create a buffer pool with given element size and max number of buffers */
+ivas_error BPOOL_Create( BPOOL_HANDLE *pHandle, size_t bufferSize, uint32_t numBuffers );
+
+/* Destroy the buffer pool and all free-up all allocated memory */
+void BPOOL_Destroy( BPOOL_HANDLE *pHandle );
+
+/* request a buffer from the pool */
+ivas_error BPOOL_GetBuffer( BPOOL_HANDLE handle, void **dataPtr );
+
+/* return the buffer back to pool */
+ivas_error BPOOL_FreeBuffer( BPOOL_HANDLE handle, void *dataPtr );
+
+/* return the number of free buffers available atm in the pool */
+uint32_t BPOOL_AvailableBuffers( BPOOL_HANDLE handle );
+
+#endif /* IVAS_BPOOL_H */
diff --git a/lib_util/ivas_queue.c b/lib_util/ivas_queue.c
new file mode 100644
index 0000000000000000000000000000000000000000..b17cf3e21a6e0222b439ba0826780dd031551670
--- /dev/null
+++ b/lib_util/ivas_queue.c
@@ -0,0 +1,137 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#include
+#include "ivas_queue.h"
+#include "ivas_error_utils.h"
+#include "mutex.h"
+
+struct QUEUE
+{
+ mtx_t lock;
+ NODE *front;
+ NODE *back;
+ uint32_t size;
+};
+
+ivas_error QUEUE_Create( QUEUE_HANDLE *pHandle )
+{
+ QUEUE_HANDLE handle = NULL;
+ *pHandle = NULL;
+
+ if ( pHandle == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid pointer to Buffer Pool Handle" );
+ }
+
+ handle = calloc( 1, sizeof( struct QUEUE ) );
+ if ( handle != NULL )
+ {
+ mtx_init( &handle->lock, 0 );
+ }
+
+ *pHandle = handle;
+ return IVAS_ERR_OK;
+}
+
+/* Destroy the queue and free-up all allocated memory */
+void QUEUE_Destroy( QUEUE_HANDLE *pHandle )
+{
+ if ( ( pHandle != NULL ) && ( *pHandle != NULL ) )
+ {
+ mtx_destroy( &( *pHandle )->lock );
+ free( *pHandle );
+ *pHandle = NULL;
+ }
+}
+
+void QUEUE_Push( QUEUE_HANDLE handle, NODE *node )
+{
+ mtx_lock( &handle->lock );
+ if ( handle->back == NULL )
+ {
+ handle->front = node;
+ }
+ else
+ {
+ handle->back->next = node;
+ }
+ handle->back = node;
+ handle->size++;
+ mtx_unlock( &handle->lock );
+}
+
+/* return the buffer back to pool */
+NODE *QUEUE_Pop( QUEUE_HANDLE handle )
+{
+ NODE *node;
+ mtx_lock( &handle->lock );
+ node = handle->front;
+ handle->front = handle->front->next;
+ if ( NULL == handle->front )
+ {
+ handle->back = NULL;
+ }
+ handle->size--;
+ mtx_unlock( &handle->lock );
+ return node;
+}
+
+/* returns the first element in the queue */
+NODE *QUEUE_Front( QUEUE_HANDLE handle )
+{
+ NODE *node;
+ mtx_lock( &handle->lock );
+ node = handle->front;
+ mtx_unlock( &handle->lock );
+ return node;
+}
+
+/* returns the last element in the queue */
+NODE *QUEUE_Back( QUEUE_HANDLE handle )
+{
+ NODE *node;
+ mtx_lock( &handle->lock );
+ node = handle->back;
+ mtx_unlock( &handle->lock );
+ return node;
+}
+
+/* return the number of elements in the queue */
+size_t QUEUE_Size( QUEUE_HANDLE handle )
+{
+ uint32_t numNodes;
+ mtx_lock( &handle->lock );
+ numNodes = handle->size;
+ mtx_unlock( &handle->lock );
+ return numNodes;
+}
diff --git a/lib_util/ivas_queue.h b/lib_util/ivas_queue.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c6b77504e501b6f0ec680839cd52f3f10b04ca8
--- /dev/null
+++ b/lib_util/ivas_queue.h
@@ -0,0 +1,68 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef IVAS_QUEUE_H
+#define IVAS_QUEUE_H
+
+#include
+#include "common_api_types.h"
+
+typedef struct NODE
+{
+ struct NODE *next;
+} NODE;
+
+/* Forward declaraiton of opaque queue handle */
+typedef struct QUEUE *QUEUE_HANDLE;
+
+/* Create a queue with given element size and max number of buffers */
+ivas_error QUEUE_Create( QUEUE_HANDLE *pHandle );
+
+/* Destroy the queue and all free-up all allocated memory */
+void QUEUE_Destroy( QUEUE_HANDLE *pHandle );
+
+/* push a buffer to a queue */
+void QUEUE_Push( QUEUE_HANDLE handle, NODE *data );
+
+/* pop the buffer from the front */
+NODE *QUEUE_Pop( QUEUE_HANDLE handle );
+
+/* returns the first element from the front */
+NODE *QUEUE_Front( QUEUE_HANDLE handle );
+
+/* returns the last element from the back */
+NODE *QUEUE_Back( QUEUE_HANDLE handle );
+
+/* return the number of elements in the queue */
+size_t QUEUE_Size( QUEUE_HANDLE handle );
+
+#endif /* IVAS_QUEUE_H */
diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h
new file mode 100644
index 0000000000000000000000000000000000000000..06c56cd70f15f1ec34f4d5a464f1fe572d5e1a07
--- /dev/null
+++ b/lib_util/ivas_rtp_api.h
@@ -0,0 +1,591 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef IVAS_RTP_API_H
+#define IVAS_RTP_API_H
+
+#include
+#include
+#include "common_api_types.h"
+
+/*
+ * +-----------------------+---------------------+--------------------+----------+
+ * | RTP Header (+ HDREXT) | payload header | frame data | PI data |
+ * +-----------------------+---------------------+--------------------+----------+
+ * \--------------------\ /------------------------------/
+ * IVAS payload
+ *
+ * This api provides a mechanism to generate/unpack the IVAS payload. The RTP Header
+ * and header extension fields must be handled by caller.
+ *
+ * IVAS General Payload structure
+ * ===============================
+ *
+ * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ * H H H H F H
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1| T | D |1| ET1 |x x x x|1| ET2 |x x x x|0|1|0 1| BR |1| ET3 |x x x x|…
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * \--------------/\--------------/\--------------/\--------------/\--------------/
+ * Initial E byte Subsqnt Ebyte1 Subsqnt Ebyte2 ToC1 Subsqnt Ebyte3
+ *
+ * H F
+ * +-+-+-+-+-+-+-+-+-------------------------- ---+-------------------- ---+-------+
+ * …|0|0|0 1| BR | IVAS frame 1 ... | IVAS frame 2 ... |PI data|
+ * +-+-+-+-+-+-+-+-+-------------------------- ---+-------------------- ---+-------+
+ * \--------------/
+ * ToC2
+ *
+ */
+
+#define IVAS_MAX_FRAMES_PER_RTP_PACKET ( 8 ) /* Max supported frames per RTP packet */
+
+/* It is difficult to decide the RTP Payload buffer's capacity intrinsically however computing
+ * using the maximum frame size and all currently supported PI data present gives a crude
+ * estimate or RTP packet size per frame. The additional PI data is assumed to add upto a 20%
+ * overhead in bitrate for the computation.
+ */
+#define NOMINAL_BUFFER_SIZE( numFramesPerPacket ) ( ( IVAS_MAX_BITS_PER_FRAME + ( IVAS_MAX_BITS_PER_FRAME / 5 ) ) * ( numFramesPerPacket ) / 8 )
+
+#define DEFAULT_MAX_PACKET_BYTES ( 1400 ) /* Typical MTU size of 4G/5G Cellular Interfaces */
+
+#define NO_BITRATE_REQ ( 0u ) /* If no bitrate is requested from remote */
+
+/* IVAS Codec Types */
+typedef enum
+{
+ IVAS_RTP_EVS, /* EVS */
+ IVAS_RTP_IVAS /* IVAS */
+} IVAS_RTP_CODEC;
+
+/* IVAS Bandwidth Requests */
+typedef enum
+{
+ IVAS_BANDWIDTH_NB, /* Narrowband */
+ IVAS_BANDWIDTH_WB, /* Wideband*/
+ IVAS_BANDWIDTH_SWB, /* SuperWideband*/
+ IVAS_BANDWIDTH_FB, /* Fullband */
+ IVAS_BANDWIDTH_NO_REQ, /* No Preference */
+} IVAS_RTP_BANDWIDTH;
+
+/* Channel Aware Coding */
+typedef enum
+{
+ IVAS_RTP_CA_LO_O2, /* FER=LO, OFFSET=2 */
+ IVAS_RTP_CA_LO_O3, /* FER=LO, OFFSET=3 */
+ IVAS_RTP_CA_LO_O5, /* FER=LO, OFFSET=5 */
+ IVAS_RTP_CA_LO_O7, /* FER=LO, OFFSET=7 */
+ IVAS_RTP_CA_HI_O2, /* FER=HI, OFFSET=2 */
+ IVAS_RTP_CA_HI_O3, /* FER=HI, OFFSET=3 */
+ IVAS_RTP_CA_HI_O5, /* FER=HI, OFFSET=5 */
+ IVAS_RTP_CA_HI_O7, /* FER=HI, OFFSET=7 */
+ IVAS_RTP_CA_NO_REQ /* No request */
+} IVAS_RTP_CA_MODE;
+
+/* Coded Format Requests */
+typedef enum
+{
+ IVAS_FMT_STEREO, /* Stereo */
+ IVAS_FMT_SBA, /* Scene Based Audio */
+ IVAS_FMT_MASA, /* Metadata Assisted Spatial Audio */
+ IVAS_FMT_ISM, /* Object Based Audio */
+ IVAS_FMT_MC, /* Multichannel Audio */
+ IVAS_FMT_OMASA, /* Object + MASA */
+ IVAS_FMT_OSBA, /* Object + SBA */
+ IVAS_FMT_NO_REQ, /* No preference */
+} IVAS_RTP_FORMAT;
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+/* Coded Subformat Requests */
+typedef enum
+{
+ IVAS_SUBFMT_FOA_PLANAR,
+ IVAS_SUBFMT_HOA2_PLANAR,
+ IVAS_SUBFMT_HOA3_PLANAR,
+ IVAS_SUBFMT_FOA,
+ IVAS_SUBFMT_HOA2,
+ IVAS_SUBFMT_HOA3,
+ IVAS_SUBFMT_MASA1,
+ IVAS_SUBFMT_MASA2,
+ IVAS_SUBFMT_ISM1,
+ IVAS_SUBFMT_ISM2,
+ IVAS_SUBFMT_ISM3,
+ IVAS_SUBFMT_ISM4,
+ IVAS_SUBFMT_ISM1_EXTENDED_METADATA,
+ IVAS_SUBFMT_ISM2_EXTENDED_METADATA,
+ IVAS_SUBFMT_ISM3_EXTENDED_METADATA,
+ IVAS_SUBFMT_ISM4_EXTENDED_METADATA,
+ IVAS_SUBFMT_MC_5_1,
+ IVAS_SUBFMT_MC_7_1,
+ IVAS_SUBFMT_MC_5_1_2,
+ IVAS_SUBFMT_MC_5_1_4,
+ IVAS_SUBFMT_MC_7_1_4,
+ IVAS_SUBFMT_RESERVED_21,
+ IVAS_SUBFMT_RESERVED_22,
+ IVAS_SUBFMT_RESERVED_23,
+ IVAS_SUBFMT_RESERVED_24,
+ IVAS_SUBFMT_RESERVED_25,
+ IVAS_SUBFMT_RESERVED_26,
+ IVAS_SUBFMT_RESERVED_27,
+ IVAS_SUBFMT_RESERVED_28,
+ IVAS_SUBFMT_RESERVED_29,
+ IVAS_SUBFMT_RESERVED_30,
+ IVAS_SUBFMT_RESERVED_31,
+ IVAS_SUBFMT_OMASA_ISM1_1TC,
+ IVAS_SUBFMT_OMASA_ISM2_1TC,
+ IVAS_SUBFMT_OMASA_ISM3_1TC,
+ IVAS_SUBFMT_OMASA_ISM4_1TC,
+ IVAS_SUBFMT_OMASA_ISM1_2TC,
+ IVAS_SUBFMT_OMASA_ISM2_2TC,
+ IVAS_SUBFMT_OMASA_ISM3_2TC,
+ IVAS_SUBFMT_OMASA_ISM4_2TC,
+ IVAS_SUBFMT_OSBA_ISM1_FOA_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM2_FOA_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM3_FOA_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM4_FOA_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM1_FOA,
+ IVAS_SUBFMT_OSBA_ISM2_FOA,
+ IVAS_SUBFMT_OSBA_ISM3_FOA,
+ IVAS_SUBFMT_OSBA_ISM4_FOA,
+ IVAS_SUBFMT_OSBA_ISM1_HOA2_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM2_HOA2_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM3_HOA2_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM4_HOA2_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM1_HOA2,
+ IVAS_SUBFMT_OSBA_ISM2_HOA2,
+ IVAS_SUBFMT_OSBA_ISM3_HOA2,
+ IVAS_SUBFMT_OSBA_ISM4_HOA2,
+ IVAS_SUBFMT_OSBA_ISM1_HOA3_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM2_HOA3_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM3_HOA3_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM4_HOA3_PLANAR,
+ IVAS_SUBFMT_OSBA_ISM1_HOA3,
+ IVAS_SUBFMT_OSBA_ISM2_HOA3,
+ IVAS_SUBFMT_OSBA_ISM3_HOA3,
+ IVAS_SUBFMT_OSBA_ISM4_HOA3,
+ IVAS_SUBFMT_NO_REQ
+} IVAS_RTP_SUBFORMAT;
+
+/* Split Rendering Requests */
+typedef struct
+{
+ uint32_t valid : 1; /* is split rendering request valid */
+ uint32_t diegetic : 1; /* enabling diegetic support for Split Rendering */
+ uint32_t yaw : 1; /* transmission metadata for correction around yaw axis */
+ uint32_t pitch : 1; /* transmission metadata for correction around pitch axis */
+ uint32_t roll : 1; /* transmission metadata for correction around roll axis */
+ uint32_t reserved : 27; /* reserved */
+} IVAS_RTP_SPLITRENDER;
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+
+/* Remote Requests Types (Keys) */
+typedef enum
+{
+ IVAS_REQUEST_CODEC, /* Request codec type, value of type IVAS_RTP_CODEC */
+ IVAS_REQUEST_BITRATE, /* Request bitrate, value of type uint32_t in kbps */
+ IVAS_REQUEST_BANDWIDTH, /* Request bandwidth, value of type IVAS_RTP_BANDWIDTH */
+ IVAS_REQUEST_FORMAT, /* Request format, value of type IVAS_RTP_FORMAT */
+ IVAS_REQUEST_CA_MODE, /* Request channel awareness, value of type IVAS_RTP_CA_MODE */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_REQUEST_SUBFORMAT, /* Request subFormat, value of type IVAS_RTP_SUBFORMAT */
+ IVAS_REQUEST_SR_CONFIG, /* Request spit rendering, value of type IVAS_RTP_SPLITRENDER */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ IVAS_REQUEST_MAX /* Max number of requests */
+} IVAS_RTP_REQUEST_TYPE;
+
+/* Remote Request Values */
+typedef union
+{
+ uint32_t bitrate; /* bitrate in kbps when request type is IVAS_REQUEST_BITRATE */
+ IVAS_RTP_CODEC codec; /* codec id when request type is IVAS_REQUEST_CODEC */
+ IVAS_RTP_BANDWIDTH bandwidth; /* badwidth when request type is IVAS_REQUEST_BANDWIDTH */
+ IVAS_RTP_FORMAT formatType; /* format type when request type is IVAS_REQUEST_FORMAT */
+ IVAS_RTP_CA_MODE caMode; /* channel aware mode when request type is IVAS_REQUEST_CA_MODE */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SUBFORMAT subFormatType; /* sub-format type when request type is IVAS_REQUEST_SUBFORMAT */
+ IVAS_RTP_SPLITRENDER srConfig; /* split rendering config when request type is IVAS_REQUEST_SR_CONFIG */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+} IVAS_RTP_REQUEST_VALUE;
+
+/* Template for pi data types, all defined pi data follow this template
+ * for example scene orientation pi data can be represented as :-
+ *
+ * typedef struct {
+ * size_t size; // sizeof(IVAS_PIDATA_SCENE_ORIENTATION)
+ * uint32_t piDataType; // IVAS_PI_SCENE_ORIENTATION
+ * float w, x, y, z; // pi data of scene orientation in quaternions
+ * } IVAS_PIDATA_SCENE_ORIENTATION;
+ *
+ */
+typedef struct
+{
+ size_t size; /* size of this structure */
+ uint32_t piDataType; /* IVAS PI data type */
+ uint8_t data[1]; /* Variable length array */
+} IVAS_PIDATA_GENERIC;
+
+/* Generic data buffer for sending/receiving coded frames / rtp payloads
+ * data buffer is owned and initialized by caller, rtp api will ensure
+ * buffer write does not exceed capacity.
+ */
+typedef struct
+{
+ size_t capacity; /* allocated size of the data buffer */
+ size_t length; /* length of the initialized data in the buffer */
+ uint8_t *buffer; /* pointer to the payload buffer */
+} IVAS_DATA_BUFFER;
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+typedef enum
+{
+ IVAS_SR_TRANSPORT_LCLD,
+ IVAS_SR_TRANSPORT_LC3PLUS
+} IVAS_RTP_SR_TRANSPORT;
+
+typedef struct
+{
+ bool valid; /* Valid Split Rendering Info for/in the ToC */
+ bool diegetic; /* SR content digetic */
+ IVAS_RTP_SR_TRANSPORT codec; /* SR Transport Codec used*/
+} IVAS_RTP_SR_INFO;
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+
+/**********************************************/
+/* IVAS RTP PACKER API */
+/**********************************************/
+
+/* Forward declaration of rtp pack/unpack handle types */
+typedef struct IVAS_RTP_PACK *IVAS_RTP_PACK_HANDLE; /* rtp packer handle type */
+
+/* Initial configuration for rtp packer
+ * - maxFramesPerPacket is used to define if more than one frame should be packed
+ * in the same rtp packet. If zero, will use IVAS_MAX_FRAMES_PER_RTP_PACKET.
+ */
+typedef struct
+{
+ uint32_t maxFramesPerPacket; /* maximum no of frame per packet desired during the session */
+} IVAS_RTP_PACK_CONFIG;
+
+/* Open an instance of the RTP packer and return a handle to rtp packer on success
+ * error code is retured on failure and handle is set to NULL
+ */
+ivas_error IVAS_RTP_PACK_Open(
+ IVAS_RTP_PACK_HANDLE *phIvasPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */
+ const IVAS_RTP_PACK_CONFIG *config /* i : pointer to initial config for RTP Packer */
+);
+
+/* Close and free an existing instance of rtp packer */
+void IVAS_RTP_PACK_Close(
+ IVAS_RTP_PACK_HANDLE *phIvasPack /* i/o : pointer to an IVAS rtp packer handle to be closed */
+);
+
+/* Update the RTP Header structure */
+ivas_error IVAS_RTP_PACK_UpdateHeader(
+ IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */
+ uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */
+ uint8_t numCC, /* i : numCC indicates no. of contributing sources */
+ uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */
+ uint16_t extHeaderId, /* i : extension header ID */
+ uint16_t numExtensionBytes, /* i : length of the extension data */
+ uint8_t *extData /* i : extension data pointer */
+);
+
+/* Add requests for remote sender using a key value pair api
+ * each key must be provided with a corresponding value type
+ *
+ * Cross validation of some key,value pairs will not be done
+ * in this API. E.g. Codec ID and supported bitrates/bandwidths
+ * will not be performed at this level.
+ */
+ivas_error IVAS_RTP_PACK_PushRemoteRequest(
+ IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */
+ IVAS_RTP_REQUEST_TYPE reqType, /* i : remote request type */
+ IVAS_RTP_REQUEST_VALUE reqValue /* i : value of the requested type */
+);
+
+/* Push a single IVAS/EVS frame to rtp packer
+ *
+ * If multiple frames per RTP packet are desired, multiple frames must be explicitly
+ * pushed before a call to IVAS_RTP_PACK_GetPayload to generate a rtp payload.
+ *
+ * It is possible to have variable frames per packet until maxFramesPerPacket frames
+ * if IVAS_RTP_PACK_GetPayload is invoked asyncronously w.r.t this api.
+ *
+ */
+ivas_error IVAS_RTP_PACK_PushFrame(
+ IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */
+ IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info (NULL if absent) */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */
+);
+
+/* Get the number of frames in the FiFo currently */
+uint32_t IVAS_RTP_PACK_GetNumFrames(
+ IVAS_RTP_PACK_HANDLE hIvasPack /* i/o : IVAS rtp packer handle */
+);
+
+/* Push single PI data to rtp packer
+ *
+ * Provide PI data for a current RTP packet. All PI data is locally cached in the packer
+ * and set to the rtp payload with policy defined in initial configuration during call to
+ * IVAS_RTP_PACK_GetPayload.
+ *
+ */
+ivas_error IVAS_RTP_PACK_PushPiData(
+ IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */
+ const IVAS_PIDATA_GENERIC *data /* i : pointer to the PIData stucture */
+);
+
+/* Generate a rtp payload using available pushed frames
+ *
+ * Available remote requests, pi data and frames will be packed into a rtp payload. The
+ * capacity field of payload is used to limits the maximum RTP packet size.
+ *
+ */
+ivas_error IVAS_RTP_PACK_GetPayload(
+ IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */
+ IVAS_DATA_BUFFER *payload, /* o : encapsulated rtp payload */
+ uint32_t *numFramesInPayload /* o : no. of frames in payload */
+);
+
+/* Generate a rtp packet using available pushed frames
+ *
+ * Available remote requests, pi data and frames will be packed into a rtp packet. If no
+ * frame is pushed before call to this api, NO_DATA_FRAME will be generated
+ * Takes care of updates to the RTP Header
+ *
+ */
+ivas_error IVAS_RTP_PACK_GetPacket(
+ IVAS_RTP_PACK_HANDLE hIvasPack, /* i/o : IVAS rtp packer handle */
+ IVAS_DATA_BUFFER *packet, /* o : encapsulated rtp packet */
+ uint32_t *numFramesInPacket /* o : no. of frames in packet */
+);
+
+/**********************************************/
+/* IVAS RTP UNPACKER API */
+/**********************************************/
+
+/* Forward declaration of rtp unpack handle types */
+typedef struct IVAS_RTP_UNPACK *IVAS_RTP_UNPACK_HANDLE; /* rtp unpacker handle type */
+
+/* Initial configuration for rtp unpacker
+ * - maxFramesPerPacket is used to define maximum supported frames per rtp packet
+ * to allow for internal memory allocaton, if zero, will use IVAS_MAX_FRAMES_PER_RTP_PACKET
+ */
+
+typedef struct
+{
+ uint32_t maxFramesPerPacket; /* maximum no of frame per packet expected during the session */
+} IVAS_RTP_UNPACK_CONFIG;
+
+/* Open an instance of the RTP unpacker and return a handle to rtp unpacker on success
+ * error code is retured on failure and handle is set to NULL
+ */
+ivas_error IVAS_RTP_UNPACK_Open(
+ IVAS_RTP_UNPACK_HANDLE *phIvasUnpack, /* i/o : rtp unpacker handle */
+ const IVAS_RTP_UNPACK_CONFIG *config /* i : initial configuration for rtp unpacker */
+);
+
+/* Close and free an existing instance of rtp unpacker */
+void IVAS_RTP_UNPACK_Close(
+ IVAS_RTP_UNPACK_HANDLE *phIvasUnpack /* i/o : IVAS rtp unpacker handle */
+);
+
+/* Push a received rtp Ivas Payload to unpacker to extract number of frames, pi data and
+ * any remote request present in the payload. Caller must extract RTP header and header
+ * extension and feed Ivas Payload alongwith RTP Timestamp and sequence number.
+ *
+ * In case of DTX transmission modes, the number of frames in packet will be reduced by
+ * the number of NO_DATA frame received. All PullFrame calls for non NO_DATA frames shall
+ * be reported with timestamp jump indicating missing/NO_DATA IVAS frames.
+ *
+ * It is important to ensure IVAS_RTP_UNPACK_PushPayload, IVAS_RTP_UNPACK_PullFrame and
+ * IVAS_RTP_UNPACK_PullNextPiData API are invoked in same thread context or in a thread
+ * safe manner else a race condition can arise if new packet is pushed while frames/pidata
+ * are still being pulled out. The IVAS_RTP_UNPACK_PushPayload will gererate an error if
+ * new paylod is pushed before all frames/pidata are pulled out.
+ *
+ * Example usage : -
+ * ==================
+ * err = IVAS_RTP_UNPACK_PushPayload(hIvasUnpack, payload, rtpTs, seqNum,
+ * &nFrames, &nPiData, &reqBitmap);
+ * if (err != IVAS_ERR_OK) { return err; }
+ *
+ * // Read the frames in payload and feed to decoder
+ * while (nFrames-- > 0) {
+ * err = IVAS_RTP_UNPACK_PullFrame(hIvasUnpack, &recCodecId, &srInfo, &frame, &frameTs, &seqNum, &SpeechLostIndicated);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * err = IVAS_DEC_VoIP_FeedFrame(hIvasDec, frame.buffer, frame.length, seqNum, frameTs, rcvTime, isGoodFrame);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * }
+ *
+ * // Read PI Data
+ * while (nPiData-- > 0) {
+ * err = IVAS_RTP_UNPACK_PullNextPiData(hIvasUnpack, &piData, &piTs);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * // handle pi data based on fwd/rev pi data types
+ * handlePIData(&piData, piTs)
+ * }
+ *
+ * // Read remote requests
+ * for (req = 0; req < IVAS_REQUEST_MAX; req++) {
+ * if (reqBitmap & (1u << req)) {
+ * err = IVAS_RTP_UNPACK_GetRequest(hIvasUnpack, req, &value);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * switch(req) {
+ * case IVAS_REQUEST_CODEC : handleCodec(value.codec); break;
+ * case IVAS_REQUEST_BITRATE : handleBitrate(value.bitrate); break;
+ * case IVAS_REQUEST_BANDWIDTH : handleBandwidth(value.bandwidth); break;
+ * case IVAS_REQUEST_FORMAT : handleFormat(value.formatType); break;
+ * case IVAS_REQUEST_SUBFORMAT : handleSubFormat(value.subFormatType); break;
+ * case IVAS_REQUEST_CA_MODE : handleCAModevalue.caMode); break;
+ * case IVAS_REQUEST_SR_CONFIG : handleSRConfig(value.srConfig); break;
+ * }
+ * }
+ * }
+ *
+ */
+ivas_error IVAS_RTP_UNPACK_PushPayload(
+ IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */
+ const IVAS_DATA_BUFFER *payload, /* i : received rtp payload */
+ uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */
+ uint16_t sequenceNumber, /* i : sequence number from rtp header */
+ uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */
+ uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */
+ uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */
+);
+
+/* Push a received rtp Ivas Packet to unpacker to extract number of frames, pi data and
+ * any remote request present in the Packet.
+ *
+ * In case of DTX transmission modes, the number of frames in packet will be reduced by
+ * the number of NO_DATA frame received. All PullFrame calls for non NO_DATA frames shall
+ * be reported with timestamp jump indicating missing/NO_DATA IVAS frames.
+ *
+ * It is important to ensure IVAS_RTP_UNPACK_PushPacket, IVAS_RTP_UNPACK_PullFrame and
+ * IVAS_RTP_UNPACK_PullNextPiData API are invoked in same thread context or in a thread
+ * safe manner else a race condition can arise if new packet is pushed while frames/pidata
+ * are still being pulled out. The IVAS_RTP_UNPACK_PushPacket will gererate an error if
+ * new packet is pushed before all frames/pidata are pulled out.
+ *
+ * Example usage : -
+ * ==================
+ * err = IVAS_RTP_UNPACK_PushPacket(hIvasUnpack, packet, &nFrames, &nPiData, &reqBitmap);
+ * if (err != IVAS_ERR_OK) { return err; }
+ *
+ * // Read the frames in packet and feed to decoder
+ * while (nFrames-- > 0) {
+ * err = IVAS_RTP_UNPACK_PullFrame(hIvasUnpack, &recCodecId, &srInfo, &frame, &frameTs, &seqNum, &SpeechLostIndicated);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * err = IVAS_DEC_VoIP_FeedFrame(hIvasDec, frame.buffer, frame.length, seqNum, frameTs, rcvTime, isGoodFrame);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * }
+ *
+ * // Read PI Data
+ * while (nPiData-- > 0) {
+ * err = IVAS_RTP_UNPACK_PullNextPiData(hIvasUnpack, &piData, &piTs);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * // handle pi data based on fwd/rev pi data types
+ * handlePIData(&piData, piTs)
+ * }
+ *
+ * // Read remote requests
+ * for (req = 0; req < IVAS_REQUEST_MAX; req++) {
+ * if (reqBitmap & (1u << req)) {
+ * err = IVAS_RTP_UNPACK_GetRequest(hIvasUnpack, req, &value);
+ * if (err != IVAS_ERR_OK) { return err; }
+ * switch(req) {
+ * case IVAS_REQUEST_CODEC : handleCodec(value.codec); break;
+ * case IVAS_REQUEST_BITRATE : handleBitrate(value.bitrate); break;
+ * case IVAS_REQUEST_BANDWIDTH : handleBandwidth(value.bandwidth); break;
+ * case IVAS_REQUEST_FORMAT : handleFormat(value.formatType); break;
+ * case IVAS_REQUEST_SUBFORMAT : handleSubFormat(value.subFormatType); break;
+ * case IVAS_REQUEST_CA_MODE : handleCAModevalue.caMode); break;
+ * case IVAS_REQUEST_SR_CONFIG : handleSRConfig(value.srConfig); break;
+ * }
+ * }
+ * }
+ */
+ivas_error IVAS_RTP_UNPACK_PushPacket(
+ IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */
+ const IVAS_DATA_BUFFER *packet, /* i : received rtp Packet */
+ uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */
+ uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */
+ uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */
+);
+
+/* Fetch requests from sender using a key value pair api
+ * each key must be provided with a corresponding value storage type
+ *
+ * On call to IVAS_RTP_UNPACK_PushPayload(), remoteRequestBitmap can be used
+ * an indicator of new request available this frame
+ *
+ */
+ivas_error IVAS_RTP_UNPACK_GetRequest(
+ IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp packer handle */
+ IVAS_RTP_REQUEST_TYPE type, /* i : remote request type */
+ IVAS_RTP_REQUEST_VALUE *value /* o : pointer of the requested type */
+);
+
+/* Extract a single IVAS/EVS frame from provided rtp payload alongwith rtp timestamp
+ * and sequence number
+ *
+ * If multiple frames per RTP packet are available, multiple calls to IVAS_RTP_UNPACK_PullFrame
+ * are needed.
+ */
+ivas_error IVAS_RTP_UNPACK_PullFrame(
+ IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */
+ IVAS_RTP_CODEC *receivedCodecId, /* o : Codec type (IVAS/EVS) */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SR_INFO *srInfo, /* o : Split Rendering Info */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ IVAS_DATA_BUFFER *frameBuffer, /* o : packed frame bitstream for IVAS/EVS */
+ int16_t *frameSizeInBits, /* o : exact frame size in bits (AMRWB IO) */
+ uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */
+ uint16_t *sequenceNumber, /* o : sequence number from rtp header */
+ bool *speechLostIndicated, /* o : Is current frame indicated as Lost */
+ bool *isAMRWB_IOmode /* o : Is AMRWB_IO mode EVS frame */
+);
+
+/* Pull a single PI data from rtp unpacker instance for current packet
+ * Each Pi data is accompanied with a corresponding timestamp
+ */
+ivas_error IVAS_RTP_UNPACK_PullNextPiData(
+ IVAS_RTP_UNPACK_HANDLE hIvasUnpack, /* i/o : IVAS rtp unpacker handle */
+ IVAS_PIDATA_GENERIC *data, /* o : output data buffer for the Pi data */
+ size_t capacity, /* i : capacity of pi data buffer in bytes */
+ uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */
+);
+
+#endif /* IVAS_RTP_API_H */
diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c
new file mode 100644
index 0000000000000000000000000000000000000000..8555480efd332900c9fceda25bd914b60bd9e18e
--- /dev/null
+++ b/lib_util/ivas_rtp_file.c
@@ -0,0 +1,612 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+#include
+#include
+#include "ivas_rtp_file.h"
+#include "ivas_error_utils.h"
+
+struct IVAS_RTP_FILE
+{
+ bool isFileWriter;
+ FILE *f_rtpstream;
+};
+
+static ivas_error IvasRtpFile_Open(
+ const char *filePath, /* i : path to CA config file */
+ bool isFileWriter, /* i : instance is a file writer else reader */
+ IVAS_RTP_FILE_HANDLE *phRtpFile /* o : pointer to an IVAS file reader handle */
+)
+{
+ const char *mode = isFileWriter ? "wb" : "rb";
+ FILE *f_rtpstream = fopen( filePath, mode );
+ if ( f_rtpstream == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_FILE_OPEN, "could not open: %s\n", filePath );
+ }
+
+ *phRtpFile = calloc( 1, sizeof( struct IVAS_RTP_FILE ) );
+ if ( *phRtpFile != NULL )
+ {
+ ( *phRtpFile )->isFileWriter = isFileWriter;
+ ( *phRtpFile )->f_rtpstream = f_rtpstream;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+static ivas_error IvasRtpFile_Close(
+ IVAS_RTP_FILE_HANDLE *phReader /* i : pointer to an IVAS file reader handle */
+)
+{
+ if ( phReader != NULL && *phReader != NULL )
+ {
+ if ( ( *phReader )->f_rtpstream != NULL )
+ {
+ fclose( ( *phReader )->f_rtpstream );
+ ( *phReader )->f_rtpstream = NULL;
+ }
+ free( *phReader );
+ *phReader = NULL;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+static ivas_error IvasRtpFile_Write(
+ IVAS_RTP_FILE_HANDLE hRtpFile, /* i : pointer to an IVAS file writer handle */
+ const uint8_t *packet, /* i : rtp packet to be written to rtpdump file */
+ size_t numBytes ) /* i : size in bytes of the rtp packet */
+{
+ ivas_error error = IVAS_ERR_OK;
+ if ( hRtpFile->isFileWriter )
+ {
+ uint32_t length = (uint32_t) numBytes; /* Max packet length is < 32 bits*/
+ fwrite( &length, sizeof( uint32_t ), 1, hRtpFile->f_rtpstream );
+ fwrite( packet, sizeof( uint8_t ), numBytes, hRtpFile->f_rtpstream );
+ }
+ else
+ {
+ error = IVAS_ERR_WRONG_PARAMS;
+ }
+ return error;
+}
+
+static ivas_error IvasRtpFile_Read(
+ IVAS_RTP_FILE_HANDLE hRtpFile, /* i : pointer to an IVAS file reader handle */
+ uint8_t *packet, /* o : read rtp packet */
+ size_t *numBytes, /* o : no of bytes in packet */
+ size_t capacity /* i : max capacity of the packet buffer */
+)
+{
+ size_t nread = 0;
+ uint32_t length = 0;
+ if ( hRtpFile->isFileWriter )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "File open for writing cannot be read" );
+ }
+
+ nread = fread( &length, sizeof( uint32_t ), 1, hRtpFile->f_rtpstream ); /* Read Packet Length */
+ if ( nread == 0 )
+ {
+ return IVAS_ERR_END_OF_FILE;
+ }
+
+ *numBytes = length;
+ if ( ( *numBytes ) > capacity )
+ {
+ fprintf( stderr, "RTP packet > buffer capacity %lu bytes\n", capacity );
+ return IVAS_ERR_INVALID_OUTPUT_BUFFER_SIZE;
+ }
+
+ nread = fread( packet, sizeof( uint8_t ), ( *numBytes ), hRtpFile->f_rtpstream ); /* Read Packet */
+ if ( nread < ( *numBytes ) )
+ {
+ return IVAS_ERR_END_OF_FILE;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+static const char *const PiDataNames[IVAS_PI_MAX_ID] = {
+ "SCENE_ORIENTATION", "DEVICE_ORIENTATION_COMPENSATED", "DEVICE_ORIENTATION_UNCOMPENSATED",
+ "ACOUSTIC_ENVIRONMENT", "AUDIO_DESCRIPTION", "ISM_NUM", "ISM_ID", "ISM_GAIN", "ISM_ORIENTATION",
+ "ISM_POSITION", "ISM_DISTANCE_ATTENUATION", "ISM_DIRECTIVITY", "DIEGETIC_TYPE", "RESERVED13",
+ "AUDIO_FOCUS_INDICATION", "RESERVED15", "PLAYBACK_DEVICE_ORIENTATION", "HEAD_ORIENTATION", "LISTENER_POSITION",
+ "DYNAMIC_AUDIO_SUPPRESSION", "AUDIO_FOCUS_REQUEST", "PI_LATENCY", "R_ISM_ID", "R_ISM_GAIN",
+ "R_ISM_ORIENTATION", "R_ISM_POSITION", "R_ISM_DIRECTION", "RESERVED27", "RESERVED28", "RESERVED29",
+ "RESERVED30", "NO_DATA"
+};
+
+void IVAS_RTP_LogPiData(
+ FILE *f_piDataOut, /* i/o : Output json file handle to dump PI data for debug/test */
+ const PIDATA_TS *piData, /* i : PI Data + Timestamp array containing all PI data in current packet */
+ uint32_t nPiDataPresent /* i : Number of valid elements in the piData array */
+)
+{
+ uint32_t timestamp = ~0u;
+ if ( f_piDataOut == NULL || piData == NULL || nPiDataPresent == 0 )
+ {
+ return;
+ }
+
+ if ( ftell( f_piDataOut ) > 2 )
+ {
+ fprintf( f_piDataOut, ",\n" );
+ }
+
+ while ( nPiDataPresent-- > 0 )
+ {
+ const PIDATA_TS *cur = piData++;
+
+ if ( timestamp != ( ~0u ) && timestamp != cur->timestamp )
+ {
+ fprintf( f_piDataOut, "\n\t},\n\t\"%d\": {\n", cur->timestamp );
+ }
+ else if ( timestamp != cur->timestamp )
+ {
+ fprintf( f_piDataOut, "\t\"%d\": {\n", cur->timestamp );
+ }
+ else
+ {
+ fprintf( f_piDataOut, ",\n" );
+ }
+ fprintf( f_piDataOut, "\t\t\"%s\" : ", PiDataNames[cur->data.noPiData.piDataType] );
+ switch ( cur->data.noPiData.piDataType )
+ {
+ case IVAS_PI_SCENE_ORIENTATION:
+ case IVAS_PI_DEVICE_ORIENTATION_COMPENSATED:
+ case IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED:
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ case IVAS_PI_PLAYBACK_DEVICE_ORIENTATION:
+ case IVAS_PI_HEAD_ORIENTATION:
+ case IVAS_PI_R_ISM_ORIENTATION:
+#endif
+ {
+ fprintf( f_piDataOut, "{\n\t\t\t\"w\": %f,\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}",
+ cur->data.scene.orientation.w, cur->data.scene.orientation.x, cur->data.scene.orientation.y, cur->data.scene.orientation.z );
+ }
+ break;
+
+ case IVAS_PI_ACOUSTIC_ENVIRONMENT:
+ {
+ fprintf( f_piDataOut, "{\n\t\t\t\"aeid\": %d", cur->data.acousticEnv.aeid );
+ if ( cur->data.acousticEnv.availLateReverb )
+ {
+ fprintf( f_piDataOut, ",\n\t\t\t\"rt60\": [ %f, %f, %f ],\n", cur->data.acousticEnv.rt60[0], cur->data.acousticEnv.rt60[1], cur->data.acousticEnv.rt60[2] );
+ fprintf( f_piDataOut, "\t\t\t\"dsr\": [ %f, %f, %f ]", cur->data.acousticEnv.dsr[0], cur->data.acousticEnv.dsr[1], cur->data.acousticEnv.dsr[2] );
+ }
+ if ( cur->data.acousticEnv.availEarlyReflections )
+ {
+ fprintf( f_piDataOut, ",\n\t\t\t\"dim\": [ %f, %f, %f ],\n", cur->data.acousticEnv.roomDimensions.x, cur->data.acousticEnv.roomDimensions.y, cur->data.acousticEnv.roomDimensions.z );
+ fprintf( f_piDataOut, "\t\t\t\"abscoeff\": [ %f, %f, %f, %f, %f, %f ]", cur->data.acousticEnv.absorbCoeffs[0], cur->data.acousticEnv.absorbCoeffs[1], cur->data.acousticEnv.absorbCoeffs[2], cur->data.acousticEnv.absorbCoeffs[3], cur->data.acousticEnv.absorbCoeffs[4], cur->data.acousticEnv.absorbCoeffs[5] );
+ }
+ fprintf( f_piDataOut, "\n\t\t}" );
+ }
+ break;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ case IVAS_PI_LISTENER_POSITION:
+ case IVAS_PI_R_ISM_POSITION:
+ {
+ fprintf( f_piDataOut, "{\n\t\t\t\"x\": %f,\n\t\t\t\"y\": %f,\n\t\t\t\"z\": %f \n\t\t}",
+ cur->data.listnerPosition.position.x, cur->data.listnerPosition.position.y, cur->data.listnerPosition.position.z );
+ }
+ break;
+ case IVAS_PI_AUDIO_DESCRIPTION:
+ {
+ uint32_t nEntries = cur->data.audioDesc.nValidEntries;
+ const IVAS_AUDIO_ID *audioId = cur->data.audioDesc.audioId;
+
+ fprintf( f_piDataOut, "[\n" );
+ while ( nEntries-- > 0 )
+ {
+ fprintf( f_piDataOut, "\t\t\t{\n" );
+ fprintf( f_piDataOut, "\t\t\t\t\"isSpeech\": %s,\n", audioId->speech ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t\"isMusic\": %s,\n", audioId->music ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t\"isAmbiance\": %s,\n", audioId->ambiance ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t\"isEditable\": %s,\n", audioId->editable ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t\"isBinaural\": %s\n", audioId->binaural ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t}%c\n", ( nEntries == 0 ) ? ' ' : ',' );
+ audioId++;
+ }
+ fprintf( f_piDataOut, "\t\t]" );
+ }
+ break;
+ case IVAS_PI_DIEGETIC_TYPE:
+ {
+ const bool *isDiegetic = cur->data.digeticIndicator.isDiegetic;
+ fprintf( f_piDataOut, "{\n" );
+ fprintf( f_piDataOut, "\t\t\t\"isDigetic\": [\n" );
+ fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[0] ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[1] ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[2] ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t%s,\n", isDiegetic[3] ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\t%s\n", isDiegetic[4] ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t]\n\t\t}" );
+ }
+ break;
+ case IVAS_PI_AUDIO_FOCUS_INDICATION:
+ {
+ fprintf( f_piDataOut, "{" );
+ if ( cur->data.focusIndication.availDirection )
+ {
+ fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" );
+ fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}",
+ cur->data.focusIndication.direction.w, cur->data.focusIndication.direction.x, cur->data.focusIndication.direction.y, cur->data.focusIndication.direction.z );
+ if ( cur->data.focusIndication.availLevel )
+ {
+ fprintf( f_piDataOut, "," );
+ }
+ }
+ if ( cur->data.focusIndication.availLevel )
+ {
+ fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusIndication.flvl );
+ }
+ fprintf( f_piDataOut, "\n\t\t}" );
+ }
+ break;
+ case IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION:
+ {
+ const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = &cur->data.dynSuppression;
+ fprintf( f_piDataOut, "{\n" );
+ fprintf( f_piDataOut, "\t\t\t\"preferSpeech\": %s,\n", das->speech ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\"preferMusic\": %s,\n", das->music ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\"preferAmbiance\": %s,\n", das->ambiance ? "true" : "false" );
+ fprintf( f_piDataOut, "\t\t\t\"level\": %d", das->sli );
+ fprintf( f_piDataOut, "\n\t\t}" );
+ }
+ break;
+ case IVAS_PI_RESERVED13:
+ case IVAS_PI_AUDIO_FOCUS_REQUEST:
+ {
+ fprintf( f_piDataOut, "{" );
+ if ( cur->data.focusRequest.availDirection )
+ {
+ fprintf( f_piDataOut, "\n\t\t\t\"direction\": {\n" );
+ fprintf( f_piDataOut, "\t\t\t\t\t\t\"w\": %f,\n\t\t\t\t\t\t\"x\": %f,\n\t\t\t\t\t\t\"y\": %f,\n\t\t\t\t\t\t\"z\": %f \n\t\t\t}",
+ cur->data.focusRequest.direction.w, cur->data.focusRequest.direction.x, cur->data.focusRequest.direction.y, cur->data.focusRequest.direction.z );
+ if ( cur->data.focusRequest.availLevel )
+ {
+ fprintf( f_piDataOut, "," );
+ }
+ }
+ if ( cur->data.focusRequest.availLevel )
+ {
+ fprintf( f_piDataOut, "\n\t\t\t\"level\": %d", cur->data.focusRequest.flvl );
+ }
+ fprintf( f_piDataOut, "\n\t\t}" );
+ }
+ break;
+ case IVAS_PI_RESERVED15:
+ case IVAS_PI_RESERVED27:
+ case IVAS_PI_RESERVED28:
+ case IVAS_PI_RESERVED29:
+ case IVAS_PI_RESERVED30:
+ {
+ fprintf( f_piDataOut, "{}" );
+ }
+ break;
+ case IVAS_PI_ISM_NUM:
+ case IVAS_PI_ISM_ID:
+ case IVAS_PI_ISM_GAIN:
+ case IVAS_PI_ISM_ORIENTATION:
+ case IVAS_PI_ISM_POSITION:
+ case IVAS_PI_ISM_DISTANCE_ATTENUATION:
+ case IVAS_PI_ISM_DIRECTIVITY:
+ case IVAS_PI_PI_LATENCY:
+ case IVAS_PI_R_ISM_ID:
+ case IVAS_PI_R_ISM_GAIN:
+ case IVAS_PI_R_ISM_DIRECTION:
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ case IVAS_PI_NO_DATA:
+ {
+ fprintf( f_piDataOut, "{}" );
+ }
+ break;
+ }
+ timestamp = cur->timestamp;
+ }
+ fprintf( f_piDataOut, "\n\t}" );
+}
+
+void IVAS_RTP_Term(
+ IVAS_RTP *rtp /* i/o : IVAS RTP File reader/writer handle */
+)
+{
+ if ( NULL != rtp )
+ {
+ if ( rtp->hPack != NULL )
+ {
+ /* Complete the last packet */
+ if ( IVAS_RTP_PACK_GetNumFrames( rtp->hPack ) != 0 )
+ {
+ ivas_error error = IVAS_ERR_OK;
+ uint32_t numFramesInPayload = 0;
+
+ if ( ( error = IVAS_RTP_PACK_GetPacket( rtp->hPack, &rtp->rtpPacket, &numFramesInPayload ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while packing RTP Packet\n", ivas_error_to_string( error ) );
+ }
+ else if ( numFramesInPayload > 0 )
+ {
+ if ( ( error = IvasRtpFile_Write( rtp->hRtpFile, rtp->rtpPacket.buffer, rtp->rtpPacket.length ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while writing RTP packet\n", ivas_error_to_string( error ) );
+ }
+ }
+ }
+ IVAS_RTP_PACK_Close( &rtp->hPack );
+ }
+
+ if ( rtp->hUnpack != NULL )
+ {
+ IVAS_RTP_UNPACK_Close( &rtp->hUnpack );
+ }
+
+ if ( rtp->f_piDataOut != NULL )
+ {
+ fprintf( rtp->f_piDataOut, "\n}\n" );
+ fclose( rtp->f_piDataOut );
+ rtp->f_piDataOut = NULL;
+ }
+
+ if ( rtp->hRtpFile != NULL )
+ {
+ IvasRtpFile_Close( &rtp->hRtpFile );
+ }
+ }
+}
+
+ivas_error IVAS_RTP_WRITER_Init(
+ IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */
+ const char *outputBitstreamFilename, /* i : RTP Dump filename */
+ uint32_t numFramesPerPacket /* i : No. of frames per packet desired */
+)
+{
+ uint32_t SSRC = ( rand() & 0xFFFF ) | ( (uint32_t) rand() << 16 );
+ ivas_error error = IVAS_ERR_OK;
+
+ memset( rtp, 0, sizeof( IVAS_RTP ) );
+
+ rtp->packCfg.maxFramesPerPacket = numFramesPerPacket;
+ rtp->rtpPacket.buffer = rtp->packet;
+ rtp->rtpPacket.capacity = sizeof( rtp->packet );
+
+ error = IVAS_RTP_PACK_Open( &rtp->hPack, &rtp->packCfg );
+ if ( error == IVAS_ERR_OK )
+ {
+ /* Open the output file for RTPDump writing */
+ error = IvasRtpFile_Open( outputBitstreamFilename, true, &rtp->hRtpFile );
+ if ( error != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ error = IVAS_RTP_PACK_UpdateHeader( rtp->hPack, SSRC, 0, NULL, 0, 0, NULL );
+ if ( error != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "error in IVAS_RTP_PACK_UpdateHeader(): %d\n", error );
+ }
+ }
+
+ return error;
+}
+
+ivas_error IVAS_RTP_READER_Init(
+ IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */
+ const char *inputBitstreamFilename, /* i : Input rtpdump filename */
+ const char *piOutputFilename /* i : Output PI data json filename */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+
+ memset( rtp, 0, sizeof( IVAS_RTP ) );
+
+ rtp->unpackCfg.maxFramesPerPacket = IVAS_MAX_FRAMES_PER_RTP_PACKET;
+ rtp->rtpPacket.buffer = rtp->packet;
+ rtp->rtpPacket.capacity = sizeof( rtp->packet );
+
+ error = IVAS_RTP_UNPACK_Open( &rtp->hUnpack, &rtp->unpackCfg );
+ if ( error == IVAS_ERR_OK )
+ {
+ error = IvasRtpFile_Open( inputBitstreamFilename, false, &rtp->hRtpFile );
+ if ( error != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ if ( piOutputFilename != NULL )
+ {
+ rtp->f_piDataOut = fopen( piOutputFilename, "w" );
+ if ( rtp->f_piDataOut == NULL )
+ {
+ fprintf( stderr, "could not open: %s\n", piOutputFilename );
+ return IVAS_ERR_FAILED_FILE_OPEN;
+ }
+ fprintf( rtp->f_piDataOut, "{\n" );
+ }
+ }
+
+ return error;
+}
+
+ivas_error IVAS_RTP_WriteNextFrame(
+ IVAS_RTP *rtp, /* i/o : IVAS RTP File writer handle */
+ uint8_t *au, /* i : IVAS Compressed AU (Packed frame) */
+ int16_t auSizeBits, /* i : Frame size in bits */
+ bool isMono, /* i : input was evs(true) or ivas(false) */
+ bool forcePacket /* i : force packets with whatever frames pushed so far */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint32_t nProcPiData = 0;
+ IVAS_DATA_BUFFER packedFrame = { 0, 0, NULL };
+
+ packedFrame.capacity = ( auSizeBits + 7 ) / 8;
+ packedFrame.length = ( auSizeBits + 7 ) / 8;
+ packedFrame.buffer = (uint8_t *) au;
+ rtp->rtpPacket.length = 0;
+
+ /* Push Encoded Stream to */
+ error = IVAS_RTP_PACK_PushFrame( rtp->hPack,
+ isMono ? IVAS_RTP_EVS : IVAS_RTP_IVAS,
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ NULL,
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ &packedFrame );
+ if ( error != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ while ( rtp->nWrittenPiData-- > 0 )
+ {
+ PIDATA_TS *piDataTs = &rtp->piData[nProcPiData++];
+ if ( ( error = IVAS_RTP_PACK_PushPiData( rtp->hPack, (const IVAS_PIDATA_GENERIC *) &piDataTs->data ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while pushing scene orientation\n", ivas_error_to_string( error ) );
+ return error;
+ }
+ }
+
+ if ( forcePacket || IVAS_RTP_PACK_GetNumFrames( rtp->hPack ) == rtp->packCfg.maxFramesPerPacket )
+ {
+ uint32_t numFramesInPayload = 0;
+
+ /* Generate RTP Packet */
+ if ( ( error = IVAS_RTP_PACK_GetPacket( rtp->hPack, &rtp->rtpPacket, &numFramesInPayload ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while packing RTP Header\n", ivas_error_to_string( error ) );
+ return error;
+ }
+
+ if ( ( error = IvasRtpFile_Write( rtp->hRtpFile, rtp->rtpPacket.buffer, rtp->rtpPacket.length ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "\nError %s while writing RTP packet\n", ivas_error_to_string( error ) );
+ return error;
+ }
+ }
+
+ return error;
+}
+
+ivas_error IVAS_RTP_ReadNextFrame(
+ IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */
+ uint8_t *au, /* o : Read next IVAS Compressed AU (Packed frame) */
+ int16_t *auSizeBits, /* o : Reported Frame size in bits */
+ uint32_t *rtpTimeStamp, /* o : RTP Timestamp for this frame */
+ uint16_t *rtpSequenceNumber, /* o : RTP sequence number for this packet */
+ uint32_t *nextPacketRcvTime_ms, /* i/o : Clock indicating packet receive times need in JBM */
+ bool *qBit /* o : AMRWB Q bite as indicated in the RTP packet */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ IVAS_DATA_BUFFER packedFrame;
+ IVAS_RTP_CODEC codecId = IVAS_RTP_IVAS;
+ bool isAMRWB_IOmode = false;
+
+ packedFrame.length = 0;
+ packedFrame.buffer = au;
+ packedFrame.capacity = ( IVAS_MAX_BITS_PER_FRAME / 8 );
+ if ( rtp->numFramesInPacket == 0 )
+ {
+ rtp->rtpPacket.length = 0;
+ if ( ( error = IvasRtpFile_Read( rtp->hRtpFile, rtp->rtpPacket.buffer, &rtp->rtpPacket.length, rtp->rtpPacket.capacity ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ if ( ( error = IVAS_RTP_UNPACK_PushPacket( rtp->hUnpack, &rtp->rtpPacket,
+ &rtp->numFramesInPacket, &rtp->numPiDataInPacket,
+ &rtp->remoteRequestBitmap ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "failed to unpack RTP packet error = %s\n", ivas_error_to_string( error ) );
+ return error;
+ }
+
+ rtp->nReadPiData = 0;
+ rtp->nProcPiData = 0;
+
+ /* Pre-read all PI data */
+ while ( rtp->numPiDataInPacket != 0 )
+ {
+ PIDATA_TS *piData = &rtp->piData[rtp->nReadPiData];
+ if ( ( error = IVAS_RTP_UNPACK_PullNextPiData( rtp->hUnpack, (IVAS_PIDATA_GENERIC *) &piData->data, sizeof( piData->data ), &piData->timestamp ) ) != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "failed to pull PI Data, error = %s\n", ivas_error_to_string( error ) );
+ return error;
+ }
+ rtp->nReadPiData++;
+ rtp->numPiDataInPacket--;
+ }
+ IVAS_RTP_LogPiData( rtp->f_piDataOut, rtp->piData, rtp->nReadPiData );
+ }
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &codecId, &rtp->srInfo, &packedFrame, auSizeBits, rtpTimeStamp, rtpSequenceNumber, &rtp->speechLostIndicated, &isAMRWB_IOmode );
+#else
+ error = IVAS_RTP_UNPACK_PullFrame( rtp->hUnpack, &codecId, &packedFrame, auSizeBits, rtpTimeStamp, rtpSequenceNumber, &rtp->speechLostIndicated, &isAMRWB_IOmode );
+#endif
+ if ( error != IVAS_ERR_OK )
+ {
+ fprintf( stderr, "failed to pull frame after unpack\n" );
+ return error;
+ }
+
+ rtp->restartNeeded = false;
+ if ( *auSizeBits == 0 )
+ {
+ /* NO_DATA_FRAME/SPEECH_LOST for IVAS and EVS is indicated by same bits
+ Do not restart decoder on codec/amrwb mode change in this case */
+ }
+ else
+ {
+ rtp->restartNeeded = ( rtp->codecId != codecId ) ||
+ ( codecId == IVAS_RTP_EVS && ( rtp->isAMRWB_IOmode != isAMRWB_IOmode ) );
+
+ if ( rtp->restartNeeded )
+ {
+ fprintf( stdout, "\nRTP packet codec changed %s -> %s\n",
+ ( rtp->codecId == IVAS_RTP_EVS ) ? ( rtp->isAMRWB_IOmode ? "AMRWB_IO" : "EVS" ) : "IVAS",
+ ( codecId == IVAS_RTP_EVS ) ? ( isAMRWB_IOmode ? "AMRWB_IO" : "EVS" ) : "IVAS" );
+ }
+
+ rtp->codecId = codecId;
+ rtp->isAMRWB_IOmode = isAMRWB_IOmode;
+ }
+
+ *qBit = !rtp->speechLostIndicated;
+ rtp->numFramesInPacket--;
+ rtp->numFramesProduced++;
+ *nextPacketRcvTime_ms += 20;
+
+ return IVAS_ERR_OK;
+}
diff --git a/lib_util/ivas_rtp_file.h b/lib_util/ivas_rtp_file.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a58dc1c967b01c191bc2625965c31eb4425f387
--- /dev/null
+++ b/lib_util/ivas_rtp_file.h
@@ -0,0 +1,79 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef IVAS_RTP_FILE_H
+#define IVAS_RTP_FILE_H
+
+#include "common_api_types.h"
+#include "ivas_rtp_api.h"
+#include "ivas_rtp_pi_data.h"
+
+typedef struct IVAS_RTP_FILE *IVAS_RTP_FILE_HANDLE;
+
+typedef struct
+{
+ uint8_t packet[NOMINAL_BUFFER_SIZE( IVAS_MAX_FRAMES_PER_RTP_PACKET )];
+ PIDATA_TS piData[IVAS_PI_MAX_ID * IVAS_MAX_FRAMES_PER_RTP_PACKET];
+
+ IVAS_RTP_FILE_HANDLE hRtpFile;
+ FILE *f_piDataOut;
+ IVAS_RTP_CODEC codecId;
+ uint32_t nWrittenPiData;
+ uint32_t nReadPiData;
+ uint32_t nProcPiData;
+ uint32_t numFramesInPacket;
+ uint32_t numPiDataInPacket;
+ uint32_t remoteRequestBitmap;
+ bool speechLostIndicated;
+ bool restartNeeded;
+ bool isAMRWB_IOmode;
+ size_t numFramesProduced;
+
+ IVAS_DATA_BUFFER rtpPacket;
+ IVAS_RTP_PACK_HANDLE hPack;
+ IVAS_RTP_UNPACK_HANDLE hUnpack;
+ IVAS_RTP_PACK_CONFIG packCfg;
+ IVAS_RTP_UNPACK_CONFIG unpackCfg;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SR_INFO srInfo;
+#endif
+} IVAS_RTP;
+
+ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilename, uint32_t numFramesPerPacket );
+ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, const char *inputBitstreamFilename, const char *piOutputFilename );
+void IVAS_RTP_Term( IVAS_RTP *rtp );
+ivas_error IVAS_RTP_WriteNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t auSizeBits, bool isMono, bool forcePacket );
+ivas_error IVAS_RTP_ReadNextFrame( IVAS_RTP *rtp, uint8_t *au, int16_t *auSizeBits, uint32_t *rtpTimeStamp, uint16_t *rtpSequenceNumber, uint32_t *nextPacketRcvTime_ms, bool *qBit );
+void IVAS_RTP_LogPiData( FILE *f_piDataOut, const PIDATA_TS *piData, uint32_t nPiDataPresent );
+
+
+#endif /* IVAS_RTP_FILE_H */
diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3569ca031ac7c8c60d0d31efb7f60b06644f9d7
--- /dev/null
+++ b/lib_util/ivas_rtp_internal.h
@@ -0,0 +1,140 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef IVAS_RTP_INTERNAL_H
+#define IVAS_RTP_INTERNAL_H
+
+#include "ivas_rtp_api.h"
+#include "ivas_rtp_pi_data.h"
+
+#ifdef IVAS_RTPDUMP
+
+enum MASK_BITS
+{
+ MASK_1BIT = 0x1,
+ MASK_2BIT = 0x3,
+ MASK_3BIT = 0x7,
+ MASK_4BIT = 0xF,
+ MASK_5BIT = 0x1F,
+ MASK_6BIT = 0x3F,
+ MASK_7BIT = 0x7F,
+ MASK_8BIT = 0xFF,
+
+};
+
+/* tables */
+#define NBITS_AEID ( 7 )
+#define NBITS_RT60 ( 5 )
+#define NBITS_DSR ( 6 )
+#define NBITS_DIM ( 4 )
+#define NBITS_ABS ( 2 )
+
+#define MASK_AEID ( ( 1u << NBITS_AEID ) - 1 )
+#define MASK_RT60 ( ( 1u << NBITS_RT60 ) - 1 )
+#define MASK_DSR ( ( 1u << NBITS_DSR ) - 1 )
+#define MASK_DIM ( ( 1u << NBITS_DIM ) - 1 )
+#define MASK_ABS ( ( 1u << NBITS_ABS ) - 1 )
+
+#define MAX_PI_POSITION_METERS ( 327.68f )
+#define FLOAT_FROM_Q15( q15Val ) ( (float) ( q15Val ) / 32768.0f )
+
+extern const float mapDSR[1u << NBITS_DSR];
+extern const float mapRT60[1u << NBITS_RT60];
+extern const float mapRoomDims[1u << NBITS_DIM];
+extern const float mapAbsorbtion[1u << NBITS_ABS];
+
+enum IVAS_RTP_HEADER_BITS
+{
+
+ EBYTE_TOC_HEADER_BIT = 0x80, /* Ebyte/ToC indicator H bit, 1 = EByte, 0 = ToC */
+
+ TOC_HEADER_FOLLOWS = 0x40, /* ToC header byte is followed by another header byte */
+ TOC_INDICATE_NO_DATA_AMRWB = 0x3F, /* ToC byte indicates NO_DATA in DTX mode for AMRWB */
+ TOC_INDICATE_NO_DATA = 0x0F, /* ToC header byte indicates NO_DATA in DTX mode */
+ TOC_INDICATE_IVAS = 0x10, /* ToC header byte indicates IVAS data */
+ TOC_INDICATE_EVS = 0x00, /* ToC header byte indicates EVS data */
+ TOC_INDICATE_AMRWB = 0x30, /* ToC header byte indicates AMR-WB IO data */
+ TOC_INDICATE_ARMWB_Q = 0x20, /* ToC header byte indicates AMR-WB IO lost frame */
+ TOC_INDICATE_SR = 0x1E, /* Indicate Split Rendering in ToC bytes */
+
+ EBYTE_CMR_T_EVS_NB = 0x80, /* Initial E-byte indicating EVS NarrowBand modes */
+ EBYTE_CMR_T_EVS_IO = 0x90, /* Initial E-byte indicating EVS AMRWB IO modes */
+ EBYTE_CMR_T_EVS_WB = 0xA0, /* Initial E-byte indicating EVS WideBand modes */
+ EBYTE_CMR_T_EVS_SWB = 0xB0, /* Initial E-byte indicating EVS SuperWideBand modes */
+ EBYTE_CMR_T_EVS_FB = 0xC0, /* Initial E-byte indicating EVS FullBand modes */
+ EBYTE_CMR_T_EVS_CA_WB = 0xD0, /* Initial E-byte indicating EVS CA WideBand modes */
+ EBYTE_CMR_T_EVS_CA_SWB = 0xE0, /* Initial E-byte indicating EVS CA SuperWideBand modes */
+ EBYTE_CMR_T_IVAS = 0xF0, /* Initial E-byte indicating IVAS modes */
+ EBYTE_CMR_T_NO_REQ = 0xFF, /* If no bitrate and no CA mode requested for IVAS/EVS */
+
+ EBYTE_BANDWIDTH_REQUEST = 0x80, /* Subsequent E-byte for Bandwidth Request */
+ EBYTE_FORMAT_REQUEST = 0x90, /* Subsequent E-byte for Format Request */
+ EBYTE_SUBFORMAT_REQUEST = 0x9F, /* Subsequent E-byte for SubFormat Request */
+ EBYTE_PI_INDICATOR = 0xA0, /* Subsequent E-byte for PI Indicator */
+ EBYTE_SR_REQUEST = 0xB0, /* Subsequent E-byte for Split Rendering Request */
+
+ PI_HEADER_PF_LAST = 0x00, /* Last PI header of the Payload in PI Header */
+ PI_HEADER_PF_NOT_LAST = 0x80, /* Another PI header follows after this in PI Header */
+ PI_HEADER_PM_NOT_LAST = 0x20, /* PI Frame Marker, not the last PI Header in current frame */
+ PI_HEADER_PM_LAST = 0x40, /* PI Frame Marker, the last PI Header in current frame */
+ PI_HEADER_PM_GENERIC = 0x60, /* PI Frame Marker, Generic applied to all frames */
+
+ PI_AD_SPEECH_INDICATED = 0x80, /* Audio Description indicate Speech in Audio data */
+ PI_AD_MUSIC_INDICATED = 0x40, /* Audio Description indicate Misuc in Audio data */
+ PI_AD_AMBIANCE_INDICATED = 0x20, /* Audio Description indicate Ambiance in Audio data */
+ PI_AD_EDITABLE_INDICATED = 0x10, /* Audio Description indicate metadata is editable */
+ PI_AD_BINAURAL_INDICATED = 0x8, /* Audio Description indicate Stereo stream in Binaural */
+
+};
+
+
+#define ERR_CHECK_RETURN( err ) \
+ { \
+ if ( ( err ) != IVAS_ERR_OK ) \
+ { \
+ return ( err ); \
+ } \
+ }
+
+
+typedef struct
+{
+ uint32_t size;
+ uint8_t data[IVAS_PI_MAX_DATA_SIZE];
+} PIDATA_PACKED;
+
+ivas_error PI_PackData( const IVAS_PIDATA_GENERIC *piData, PIDATA_PACKED *packed, uint8_t pmBits );
+ivas_error PI_UnPackData( uint8_t piDataType, uint32_t piSize, const uint8_t *piDataBuffer, IVAS_PIDATA_GENERIC *piData );
+
+#endif /* IVAS_RTPDUMP */
+
+#endif /* IVAS_RTP_INTERNAL_H */
diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c
new file mode 100644
index 0000000000000000000000000000000000000000..4e4b11f2aa6611548902c3e87bae50c0ae85aafb
--- /dev/null
+++ b/lib_util/ivas_rtp_payload.c
@@ -0,0 +1,1854 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+#include
+#include
+#include
+#include
+#include "common_api_types.h"
+
+#ifdef IVAS_RTPDUMP
+
+#include "ivas_rtp_internal.h"
+#include "ivas_bpool.h"
+#include "ivas_queue.h"
+#include "ivas_error_utils.h"
+#include "mutex.h"
+
+#define IVAS_MAX_BYTES_PER_FRAME ( ( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3 )
+#define MAX_TOC_PER_FRAME ( 2u ) /* Main ToC Byte + SR-ToC byte */
+
+/* Generic RTP Header + Header Extension data structure */
+typedef struct
+{
+ uint32_t ssrc; /* synchronization source id as negotiated in SDP */
+ uint8_t version; /* version of RTP protocol, currently 2 */
+ bool padding; /* false = no padding, true = zeoo padded payload (last byte = padding count) */
+ bool extension; /* true = extension header is present before payload */
+ uint8_t CC; /* if some streams mixed together, CC indicates no. of contributing sources (4 bits) */
+ bool marker; /* Marker bit field */
+ uint8_t payloadType; /* 7-bit payload type field indicating IVAS */
+ uint16_t seqNumber; /* 16-bit sequence number for RTP packets */
+ uint32_t timestamp; /* timer ticks @ 16KHz clock corrsponding to 1st frame in the Payload */
+ uint32_t CSRC[15]; /* SSRC of contributing Sources for a mixed stream */
+ uint16_t extHeaderId; /* extension header ID */
+ uint16_t numExtUnits; /* length of the extension data in 32-bit words */
+ uint8_t *extData; /* Extension data pointer */
+} RTP_HEADER;
+
+typedef struct
+{
+ PIDATA_PACKED piData[IVAS_PI_MAX_ID]; /* pi data per frame */
+ uint32_t piDataBitmap; /* bitmap showing available pi */
+ uint32_t numPiDataAvailable; /* number of pi data available */
+} PIDATA_FRAME;
+
+static void initRequests( IVAS_RTP_REQUEST_VALUE *requests )
+{
+ requests[IVAS_REQUEST_CODEC].codec = IVAS_RTP_IVAS;
+ requests[IVAS_REQUEST_BITRATE].bitrate = 0;
+ requests[IVAS_REQUEST_BANDWIDTH].bandwidth = IVAS_BANDWIDTH_NO_REQ;
+ requests[IVAS_REQUEST_FORMAT].formatType = IVAS_FMT_NO_REQ;
+ requests[IVAS_REQUEST_CA_MODE].caMode = IVAS_RTP_CA_NO_REQ;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ requests[IVAS_REQUEST_SUBFORMAT].subFormatType = IVAS_SUBFMT_NO_REQ;
+ requests[IVAS_REQUEST_SR_CONFIG].srConfig.valid = false;
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+}
+
+static void initPiDataFrame( PIDATA_FRAME *piDataFrm )
+{
+ /* Add NO_PI_DATA by default */
+ piDataFrm->numPiDataAvailable = 1;
+ piDataFrm->piDataBitmap = ( 1u << IVAS_PI_NO_DATA );
+ piDataFrm->piData[IVAS_PI_NO_DATA].size = 2;
+ piDataFrm->piData[IVAS_PI_NO_DATA].data[0] = ( IVAS_PI_NO_DATA ); /* PF/PM populated during final packing */
+ piDataFrm->piData[IVAS_PI_NO_DATA].data[1] = 0; /* NO_PI_DATA is 0 bytes */
+}
+
+typedef struct FRAME_NODE
+{
+ struct FRAME_NODE *next; /* next node */
+ PIDATA_FRAME piDataFrame; /* PI data for this frame */
+ uint8_t au[IVAS_MAX_BYTES_PER_FRAME]; /* ivas/evs packed frame (AU) */
+ uint8_t toc[MAX_TOC_PER_FRAME]; /* ToC bytes for this frame */
+ uint32_t auNumBits; /* Actual frame size in bits */
+ uint32_t tocNumBytes; /* valid ToC bytes (1 or 2) */
+} FRAME_NODE;
+
+static void initFrameNode( FRAME_NODE *node )
+{
+ node->next = NULL;
+ initPiDataFrame( &node->piDataFrame );
+ node->auNumBits = 0;
+ node->tocNumBytes = 0;
+}
+
+struct IVAS_RTP_PACK
+{
+ mtx_t apilock; /* Lock to handle concurrent API invocation */
+ bool amrwbIOMode; /* If EVS is an AMRWB-IO mode frame */
+ RTP_HEADER header; /* RTP Header Params */
+ BPOOL_HANDLE packNodePool; /* Buffer pool to allocate FRAME_NODEs */
+ PIDATA_FRAME piDataCache; /* temporary cache for PI data pushed before any frame is available in Queue */
+ IVAS_RTP_PACK_CONFIG initConfig; /* Initial Configuration for Unpacker */
+ IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX]; /* Requests Storage */
+ QUEUE_HANDLE frameQ; /* frames queue for FRAME_NODEs */
+};
+
+typedef struct
+{
+ IVAS_RTP_CODEC codecId; /* Coded frame type (IVAS/EVS) */
+ uint32_t auNumBits; /* Actual frame size in bits */
+ bool speechLostIndicated; /* Speech Lost indicated */
+ bool isAMRWB_IOmode; /* EVS frame is AMRWB_IO */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SR_INFO srInfo; /* Split Rendering Info */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+} TOC_INFO;
+
+typedef struct PIDATA_NODE
+{
+ struct PIDATA_NODE *next; /* next node is first element */
+ PIDATA data; /* unpacked pi data per frame */
+ uint32_t timestamp; /* rtp timestamp of this frame */
+} PIDATA_NODE;
+
+typedef struct UNPACK_NODE
+{
+ struct UNPACK_NODE *next; /* next node is first element */
+ uint8_t au[IVAS_MAX_BYTES_PER_FRAME]; /* ivas/evs packed frame (AU) */
+ TOC_INFO toc; /* unpacked ToC information */
+ uint32_t timestamp; /* timestamp of this frame */
+ uint16_t seqNumber; /* sequence number of the packet */
+} UNPACK_NODE;
+
+struct IVAS_RTP_UNPACK
+{
+ mtx_t apilock; /* Lock to handle concurrent API invocation */
+ size_t maxNumberOfFrames;
+ size_t maxNumberOfPiData;
+ RTP_HEADER header;
+ BPOOL_HANDLE unpackNodePool;
+ BPOOL_HANDLE piDataPool;
+ IVAS_RTP_UNPACK_CONFIG initConfig;
+ IVAS_RTP_REQUEST_VALUE requests[IVAS_REQUEST_MAX];
+ uint32_t numPiDataAvailable; /* number of pi data available */
+ QUEUE_HANDLE frameQ; /* frame queue */
+ QUEUE_HANDLE piDataQ; /* pi data queue */
+};
+
+static const uint32_t ivasFrameSizeInBits[] = {
+ 264, 328, 488, 640, 960, 1280, 1600, 1920, 2560, 3200, 3840, 5120, 7680, 10240, 0, 104
+};
+
+static const uint32_t evsFrameSizeInBits[] = {
+ 56, 144, 160, 192, 264, 328, 488, 640, 960, 1280, 1920, 2560, 48
+};
+
+static const uint32_t amrWBIOFrameSizeInBits[] = {
+ 132, 177, 253, 285, 317, 365, 397, 461, 477, 35
+};
+
+
+/* Update the RTP Header structure */
+ivas_error IVAS_RTP_PACK_UpdateHeader(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */
+ uint32_t ssrc, /* i : Unique 32-bit Source ID as negotiated during SDP */
+ uint8_t numCC, /* i : numCC indicates no. of contributing sources */
+ uint32_t *csrc, /* i : SSRCs of contributing Sources for a mixed stream */
+ uint16_t extHeaderId, /* i : extension header ID */
+ uint16_t numExtensionBytes, /* i : length of the extension data */
+ uint8_t *extData /* i : extension data pointer */
+)
+{
+ RTP_HEADER *header = &hPack->header;
+
+ if ( numCC > 15 )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "CC must be less than 16" );
+ }
+
+ header->ssrc = ssrc;
+ header->CC = numCC;
+ memcpy( header->CSRC, csrc, numCC & 0xF );
+
+ if ( ( numExtensionBytes > 0 ) && ( extData != NULL ) )
+ {
+ header->extHeaderId = extHeaderId;
+ header->extData = realloc( header->extData, numExtensionBytes );
+ if ( header->extData == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" );
+ }
+ memcpy( header->extData, extData, numExtensionBytes );
+ header->extension = true;
+ header->numExtUnits = numExtensionBytes / sizeof( uint32_t );
+ }
+ else
+ {
+ header->numExtUnits = 0;
+ header->extension = false;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+static void InitRtpHeader(
+ RTP_HEADER *header /* RTP header structure */
+)
+{
+ time_t t;
+ memset( header, 0, sizeof( *header ) );
+ srand( (uint32_t) time( &t ) );
+ header->version = 2;
+ header->seqNumber = rand() & 0xFFFF;
+}
+
+static ivas_error PackRtpHeader(
+ RTP_HEADER *header,
+ IVAS_DATA_BUFFER *buf )
+{
+ uint32_t nBytes = 0;
+ uint8_t CC = header->CC & MASK_4BIT;
+ uint32_t *CSRC = header->CSRC;
+ bool extension = header->extension && ( NULL != header->extData );
+ uint32_t extensionLength = header->extension ? ( 1 + header->numExtUnits ) : 0; /* in u32 words */
+ uint32_t packedLength = 12 + ( 4 * CC ) + ( 4 * extensionLength );
+
+ buf->length = 0;
+ if ( packedLength > buf->capacity )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient output buffer for RTP header packing" );
+ }
+
+ /*
+ +---+---+---+---+---+---+---+---+
+ | V | V | P | X | CC (4 - bits) |
+ +---+---+---+---+---+---+---+---+
+ */
+ buf->buffer[nBytes++] = ( header->version << 6 ) |
+ ( (uint8_t) header->padding << 5 ) |
+ ( (uint8_t) extension << 4 ) |
+ CC;
+ /*
+ +---+---+---+---+---+---+---+---+
+ | M | PT (7 - bits) |
+ +---+---+---+---+---+---+---+---+
+ */
+ buf->buffer[nBytes++] = ( (uint8_t) header->marker << 7 ) |
+ ( header->payloadType & MASK_7BIT );
+ /*
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ | SEQUENCE NUMBER (16 bit) |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ */
+ buf->buffer[nBytes++] = (uint8_t) ( header->seqNumber >> 8 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->seqNumber );
+
+ /* Timestamp (32-bit) */
+ buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 24 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 16 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 8 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->timestamp >> 0 );
+
+ /* SSRC (32-bit) */
+ buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 24 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 16 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 8 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->ssrc >> 0 );
+
+ /* CSRC Identifiers */
+ while ( CC )
+ {
+ /* CSRC[n] (32-bit) */
+ uint32_t id = *CSRC++;
+ buf->buffer[nBytes++] = (uint8_t) ( id >> 24 );
+ buf->buffer[nBytes++] = (uint8_t) ( id >> 16 );
+ buf->buffer[nBytes++] = (uint8_t) ( id >> 8 );
+ buf->buffer[nBytes++] = (uint8_t) ( id >> 0 );
+ CC--;
+ }
+
+ if ( extension )
+ {
+ buf->buffer[nBytes++] = (uint8_t) ( header->extHeaderId >> 8 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->extHeaderId >> 0 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->numExtUnits >> 8 );
+ buf->buffer[nBytes++] = (uint8_t) ( header->numExtUnits >> 0 );
+
+ memcpy( &buf->buffer[nBytes], header->extData, header->numExtUnits * 4 );
+ nBytes += header->numExtUnits;
+ }
+
+ buf->length = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static void UpdateRtpHeader(
+ RTP_HEADER *header, /* RTP header structure */
+ uint32_t timestampOffset /* Timestamp offset @ 16KHz clock for next frame */
+)
+{
+ header->seqNumber++;
+ header->timestamp += timestampOffset;
+}
+
+static ivas_error UnpackRtpPacket(
+ const IVAS_DATA_BUFFER *packet, /* Input buffer with RTP Packet */
+ RTP_HEADER *header, /* RTP header structure */
+ uint32_t *numHeaderBytes /* No. of rtp header bytes */
+)
+{
+ uint32_t n = 0, nByte = 0, expectedSize = 12;
+ uint8_t byte;
+
+ if ( packet->length < expectedSize )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Insufficient input buffer for RTP header unpacking" );
+ }
+
+ /*
+ +---+---+---+---+---+---+---+---+
+ | V | V | P | X | CC (4 - bits) |
+ +---+---+---+---+---+---+---+---+
+ */
+ byte = packet->buffer[nByte++];
+ header->version = ( byte >> 6 ) & MASK_2BIT;
+ header->padding = ( byte >> 5 ) & MASK_1BIT;
+ header->extension = ( byte >> 4 ) & MASK_1BIT;
+ header->CC = ( byte & MASK_4BIT );
+
+ /*
+ +---+---+---+---+---+---+---+---+
+ | M | PT (7 - bits) |
+ +---+---+---+---+---+---+---+---+
+ */
+ byte = packet->buffer[nByte++];
+ header->marker = ( byte >> 7 ) & MASK_1BIT;
+ header->payloadType = byte & MASK_7BIT;
+
+ /*
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ | SEQUENCE NUMBER (16 bit) |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ */
+ header->seqNumber = (uint16_t) packet->buffer[nByte++] << 8;
+ header->seqNumber |= (uint16_t) packet->buffer[nByte++] << 8;
+
+ /* Timestamp (32-bit) */
+ header->timestamp = ( (uint32_t) packet->buffer[nByte++] << 24 );
+ header->timestamp |= ( (uint32_t) packet->buffer[nByte++] << 16 );
+ header->timestamp |= ( (uint32_t) packet->buffer[nByte++] << 8 );
+ header->timestamp |= ( (uint32_t) packet->buffer[nByte++] );
+
+ /* SSRC (32-bit) */
+ header->ssrc = ( (uint32_t) packet->buffer[nByte++] << 24 );
+ header->ssrc |= ( (uint32_t) packet->buffer[nByte++] << 16 );
+ header->ssrc |= ( (uint32_t) packet->buffer[nByte++] << 8 );
+ header->ssrc |= ( (uint32_t) packet->buffer[nByte++] );
+
+ expectedSize += ( header->CC ) * 4 + ( header->extension ? 4 : 0 );
+ if ( packet->length < expectedSize )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "CC indicated but insufficient input buffer" );
+ }
+
+ /* CSRC Identifiers */
+ for ( n = 0; n < header->CC; n++ )
+ {
+ /* CSRC[n] (32-bit) */
+ header->CSRC[n] = ( (uint32_t) packet->buffer[nByte++] << 24 );
+ header->CSRC[n] |= ( (uint32_t) packet->buffer[nByte++] << 16 );
+ header->CSRC[n] |= ( (uint32_t) packet->buffer[nByte++] << 8 );
+ header->CSRC[n] |= ( (uint32_t) packet->buffer[nByte++] );
+ }
+
+ if ( header->extension )
+ {
+ header->extHeaderId = ( (uint32_t) packet->buffer[nByte++] << 8 );
+ header->extHeaderId |= ( (uint32_t) packet->buffer[nByte++] );
+ header->numExtUnits = ( (uint32_t) packet->buffer[nByte++] << 8 );
+ header->numExtUnits |= ( (uint32_t) packet->buffer[nByte++] );
+
+ expectedSize += header->numExtUnits * 4;
+ if ( packet->length < expectedSize )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Extension Header indicated but insufficient input buffer" );
+ }
+
+ header->extData = realloc( header->extData, header->numExtUnits * 4 );
+ if ( header->extData == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "failed to allocate extdata" );
+ }
+ memcpy( header->extData, &packet->buffer[nByte], header->numExtUnits * 4 );
+ nByte += header->numExtUnits * 4;
+ }
+
+ *numHeaderBytes = nByte;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error getBitrateFromCodecAndFrameSize(
+ IVAS_RTP_CODEC codecId,
+ uint32_t frameLengthBytes,
+ uint32_t *bitrateKbps,
+ uint32_t *frameLenInBits,
+ uint8_t *tocByte,
+ bool *isAmrwbIOMode )
+{
+ size_t n;
+ *bitrateKbps = 0;
+ *frameLenInBits = 0;
+ if ( codecId == IVAS_RTP_IVAS )
+ {
+ /* Validate the framelength is supported for ivas frame */
+ for ( n = 0; n < sizeof( ivasFrameSizeInBits ) / sizeof( ivasFrameSizeInBits[0] ); n++ )
+ {
+ if ( ivasFrameSizeInBits[n] == frameLengthBytes * 8 )
+ {
+ *bitrateKbps = ( frameLengthBytes * IVAS_NUM_FRAMES_PER_SEC * 8 ); /* bitrate in kbps */
+ *frameLenInBits = frameLengthBytes * 8; /* frame length in bits */
+ *tocByte = TOC_INDICATE_IVAS | ( n & MASK_4BIT ); /* bitrate index */
+ return IVAS_ERR_OK;
+ }
+ }
+ return IVAS_ERR_INVALID_BITRATE;
+ }
+ else
+ {
+ /* Try if frameLength is a supported EVS frame length */
+ for ( n = 0; n < sizeof( evsFrameSizeInBits ) / sizeof( evsFrameSizeInBits[0] ); n++ )
+ {
+ if ( evsFrameSizeInBits[n] == frameLengthBytes * 8 )
+ {
+ *bitrateKbps = ( frameLengthBytes * IVAS_NUM_FRAMES_PER_SEC * 8 ); /* bitrate in kbps */
+ *frameLenInBits = frameLengthBytes * 8; /* frame length in bits */
+ *tocByte = TOC_INDICATE_EVS | ( n & MASK_4BIT ); /* bitrate index */
+ return IVAS_ERR_OK;
+ }
+ }
+ /* Try if frameLength is a supported AMRWB-IO frame length */
+ for ( n = 0; n < sizeof( amrWBIOFrameSizeInBits ) / sizeof( amrWBIOFrameSizeInBits[0] ); n++ )
+ {
+ uint32_t lengthInBits = amrWBIOFrameSizeInBits[n];
+ if ( ( ( lengthInBits + 7 ) / 8 ) == frameLengthBytes )
+ {
+ *isAmrwbIOMode = true;
+ *bitrateKbps = ( lengthInBits * IVAS_NUM_FRAMES_PER_SEC ); /* bitrate in kbps */
+ *frameLenInBits = lengthInBits; /* frame length in bits */
+ *tocByte = TOC_INDICATE_AMRWB | ( n & MASK_4BIT ); /* bitrate index */
+ return IVAS_ERR_OK;
+ }
+ }
+ return IVAS_ERR_INVALID_BITRATE;
+ }
+}
+
+ivas_error IVAS_RTP_PACK_Open(
+ IVAS_RTP_PACK_HANDLE *phPack, /* i/o: pointer to an IVAS rtp packer handle to be opened */
+ const IVAS_RTP_PACK_CONFIG *config /* i : pointer to initial config for RTP Packer */
+)
+{
+ ivas_error error;
+ IVAS_RTP_PACK_HANDLE hPack;
+ uint32_t numFramesPerPacket = ( config->maxFramesPerPacket == 0 ) ? IVAS_MAX_FRAMES_PER_RTP_PACKET : config->maxFramesPerPacket;
+
+ if ( phPack == NULL )
+ {
+ return IVAS_ERR_UNEXPECTED_NULL_POINTER;
+ }
+
+ if ( numFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Max frame per packet exeeds %d", IVAS_MAX_FRAMES_PER_RTP_PACKET );
+ }
+
+ *phPack = NULL;
+ if ( ( hPack = (IVAS_RTP_PACK_HANDLE) calloc( 1, sizeof( struct IVAS_RTP_PACK ) ) ) == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtppack handle" );
+ }
+
+ error = BPOOL_Create( &hPack->packNodePool, sizeof( FRAME_NODE ), numFramesPerPacket * 4 );
+ ERR_CHECK_RETURN( error );
+
+ error = QUEUE_Create( &hPack->frameQ );
+ ERR_CHECK_RETURN( error );
+
+ mtx_init( &hPack->apilock, 0 );
+ hPack->initConfig = *config;
+ initRequests( hPack->requests );
+ InitRtpHeader( &hPack->header );
+ initPiDataFrame( &hPack->piDataCache );
+ *phPack = hPack;
+ return IVAS_ERR_OK;
+}
+
+/* Close and free an existing instance of rtp packer */
+void IVAS_RTP_PACK_Close(
+ IVAS_RTP_PACK_HANDLE *phPack /* i/o : pointer to an IVAS rtp packer handle to be closed */
+)
+{
+ IVAS_RTP_PACK_HANDLE hPack;
+
+ /* Free all memory */
+ if ( phPack == NULL || *phPack == NULL )
+ {
+ return;
+ }
+
+ hPack = *phPack;
+ QUEUE_Destroy( &hPack->frameQ );
+ mtx_destroy( &hPack->apilock );
+ BPOOL_Destroy( &hPack->packNodePool );
+ free( hPack->header.extData );
+ free( hPack );
+ *phPack = NULL;
+}
+
+ivas_error IVAS_RTP_PACK_PushRemoteRequest(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */
+ IVAS_RTP_REQUEST_TYPE reqType, /* i : remote request type */
+ IVAS_RTP_REQUEST_VALUE reqValue /* i : value of the requested type */
+)
+{
+ if ( reqType < 0 || reqType >= IVAS_REQUEST_MAX )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid request key provided" );
+ }
+
+ /* Sanity on API */
+ switch ( reqType )
+ {
+ case IVAS_REQUEST_CODEC:
+ {
+ uint32_t codec = reqValue.codec;
+ if ( codec != IVAS_RTP_IVAS && codec != IVAS_RTP_EVS )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported codec id provided" );
+ }
+ }
+ break;
+ case IVAS_REQUEST_BITRATE:
+ {
+ uint32_t bitrate = reqValue.bitrate;
+ if ( bitrate < 5900 || bitrate > 512000 )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate provided" );
+ }
+ }
+ break;
+ case IVAS_REQUEST_BANDWIDTH:
+ {
+ uint32_t bandwidth = reqValue.bandwidth;
+ if ( bandwidth > IVAS_BANDWIDTH_NO_REQ )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bandwidth provided" );
+ }
+ }
+ break;
+ case IVAS_REQUEST_FORMAT:
+ {
+ uint32_t format = reqValue.formatType;
+ if ( format > IVAS_FMT_NO_REQ )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported format provided" );
+ }
+ }
+ break;
+ case IVAS_REQUEST_CA_MODE:
+ {
+ uint32_t caMode = reqValue.caMode;
+ if ( caMode > IVAS_RTP_CA_NO_REQ )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported channel aware mode provided" );
+ }
+ }
+ break;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ case IVAS_REQUEST_SUBFORMAT:
+ {
+ uint32_t subFormat = reqValue.subFormatType;
+ if ( subFormat > IVAS_SUBFMT_NO_REQ )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported subformat provided" );
+ }
+ }
+ break;
+ case IVAS_REQUEST_SR_CONFIG:
+ {
+ IVAS_RTP_SPLITRENDER srConfig = reqValue.srConfig;
+ if ( srConfig.reserved != 0 )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported reserved bits in SR config provided" );
+ }
+ }
+ break;
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ default:
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported request type" );
+ }
+
+ hPack->requests[reqType] = reqValue;
+
+ return IVAS_ERR_OK;
+}
+
+static bool isAmrWBIOMode( uint32_t bitrate, uint32_t *idx )
+{
+ size_t n;
+ *idx = 0;
+ for ( n = 0; n < sizeof( amrWBIOFrameSizeInBits ) / sizeof( amrWBIOFrameSizeInBits[0] ); n++ )
+ {
+ if ( bitrate == ( amrWBIOFrameSizeInBits[n] * IVAS_NUM_FRAMES_PER_SEC ) )
+ {
+ *idx = n;
+ return true;
+ }
+ }
+ return false;
+}
+
+static uint32_t getBitrateIdx( const uint32_t *table, uint32_t tableLen, uint32_t bitrate )
+{
+ size_t n, idx = 0;
+
+ for ( n = 0; n < tableLen; n++ )
+ {
+ if ( bitrate > ( table[n] * IVAS_NUM_FRAMES_PER_SEC ) )
+ {
+ idx = n;
+ }
+ else
+ {
+ return idx;
+ }
+ }
+ return idx;
+}
+
+static void packEBytes(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */
+ bool piDataPresent, /* i : Signals if PI data present */
+ size_t maxNumEBytes, /* i : max capacity of eByte buffer */
+ uint8_t *eByte, /* o : output buffer for E-Bytes */
+ size_t *nBytesWritten /* o : max capacity of eByte buffer */
+)
+{
+ /* Initial E-byte structure
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |H|T|T|T| BR |
+ * +-+-+-+-+-+-+-+-+
+ */
+ uint32_t nByte = 0;
+ uint8_t T = EBYTE_CMR_T_IVAS; /* IVAS */
+ uint8_t BR = 0;
+
+ IVAS_RTP_CODEC codec = hPack->requests[IVAS_REQUEST_CODEC].codec;
+ IVAS_RTP_BANDWIDTH bandwidth = hPack->requests[IVAS_REQUEST_BANDWIDTH].bandwidth;
+ uint32_t bitrate = hPack->requests[IVAS_REQUEST_BITRATE].bitrate;
+ uint32_t bitrateIdx = 0;
+
+ *nBytesWritten = 0;
+
+ if ( codec == IVAS_RTP_EVS )
+ {
+ /* If requesting EVS/AMRWB IO from farend, only Initial E-byte present */
+ IVAS_RTP_CA_MODE caMode = hPack->requests[IVAS_REQUEST_CA_MODE].caMode;
+
+ if ( caMode != IVAS_RTP_CA_NO_REQ )
+ {
+ T = ( bandwidth == IVAS_BANDWIDTH_SWB ) ? EBYTE_CMR_T_EVS_CA_SWB : EBYTE_CMR_T_EVS_CA_WB;
+ BR = caMode & MASK_3BIT; /* only 8 valid values */
+ if ( nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = ( T | BR );
+ }
+ }
+ else if ( bitrate > 0 && isAmrWBIOMode( bitrate, &bitrateIdx ) )
+ {
+ /* AMR WB IO Mode */
+ T = EBYTE_CMR_T_EVS_IO;
+ BR = (uint8_t) bitrateIdx & MASK_4BIT;
+ if ( nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = ( T | BR );
+ }
+ }
+ else if ( bitrate > 0 )
+ {
+ /* EVS Modes */
+ bitrate = ( bitrate > 128000 ) ? 128000 : bitrate;
+ bitrate = ( bitrate < 5900 ) ? 5900 : bitrate;
+ bitrateIdx = getBitrateIdx( evsFrameSizeInBits, sizeof( evsFrameSizeInBits ) / sizeof( evsFrameSizeInBits[0] ), bitrate );
+ BR = (uint8_t) bitrateIdx & MASK_4BIT;
+
+ /* If a bandwidth choice cannot be signalled for a given bitrate
+ preference is given to bitrate choice, bandwidth req is modified */
+ switch ( bandwidth )
+ {
+ case IVAS_BANDWIDTH_NB:
+ T = ( bitrate <= 24400u ) ? EBYTE_CMR_T_EVS_NB : EBYTE_CMR_T_EVS_SWB;
+ break;
+ case IVAS_BANDWIDTH_WB:
+ T = EBYTE_CMR_T_EVS_WB;
+ break;
+ case IVAS_BANDWIDTH_SWB:
+ T = ( bitrate >= 9600u ) ? EBYTE_CMR_T_EVS_SWB : EBYTE_CMR_T_EVS_WB;
+ break;
+ case IVAS_BANDWIDTH_FB:
+ T = ( bitrate >= 16400u ) ? EBYTE_CMR_T_EVS_FB : EBYTE_CMR_T_EVS_WB;
+ break;
+ default: /*IVAS_BANDWIDTH_NO_REQ */
+ T = ( bitrate >= 9600u ) ? EBYTE_CMR_T_EVS_SWB : EBYTE_CMR_T_EVS_WB;
+ break;
+ }
+ if ( nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = ( T | BR );
+ }
+ }
+ else if ( piDataPresent )
+ {
+ /* Send an initial E-byte to allow for subsequent PI indication E-byte */
+ if ( nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = EBYTE_CMR_T_NO_REQ;
+ }
+ }
+ }
+ else
+ {
+ /* Requesting IVAS from farend, Subsequent E-byte indicate BW, CFR, SR */
+ IVAS_RTP_FORMAT format = hPack->requests[IVAS_REQUEST_FORMAT].formatType;
+ bool isBandwidthProvided = ( bandwidth != IVAS_BANDWIDTH_NO_REQ && bandwidth != IVAS_BANDWIDTH_NB );
+ bool isFormatProvided = ( format != IVAS_FMT_NO_REQ );
+ bool isSubFormatProvided = false;
+ bool isSRConfigProvided = false;
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SUBFORMAT subFormat = hPack->requests[IVAS_REQUEST_SUBFORMAT].subFormatType;
+ IVAS_RTP_SPLITRENDER srConfig = hPack->requests[IVAS_REQUEST_SR_CONFIG].srConfig;
+
+ isSubFormatProvided = ( subFormat != IVAS_SUBFMT_NO_REQ );
+ isSRConfigProvided = srConfig.valid;
+#endif
+
+ /* Initial E-Byte only sent if either bitrate requested or subsequent E-byte is requested */
+ if ( !( ( bitrate > 0 ) || isBandwidthProvided || isFormatProvided ||
+ isSubFormatProvided || isSRConfigProvided || piDataPresent ) )
+ {
+ return;
+ }
+
+ if ( bitrate > 0 )
+ {
+ /* Initial E-Byte */
+ bitrate = ( bitrate > 512000 ) ? 512000 : bitrate;
+ bitrate = ( bitrate < 13200 ) ? 13200 : bitrate;
+ bitrateIdx = getBitrateIdx( ivasFrameSizeInBits, sizeof( ivasFrameSizeInBits ) / sizeof( ivasFrameSizeInBits[0] ), bitrate );
+ BR = (uint8_t) bitrateIdx & MASK_4BIT;
+ if ( nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = ( EBYTE_CMR_T_IVAS | BR );
+ }
+ }
+ else
+ {
+ if ( nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = EBYTE_CMR_T_NO_REQ;
+ }
+ }
+
+ /* Subsequent E-bytes - Bandwidth Request */
+ if ( isBandwidthProvided && nByte < maxNumEBytes )
+ {
+ uint8_t bw = ( bandwidth - IVAS_BANDWIDTH_WB ) & MASK_2BIT;
+ eByte[nByte++] = ( EBYTE_BANDWIDTH_REQUEST | bw );
+ }
+
+ /* Subsequent E-bytes - Coded Format Request */
+ if ( ( isFormatProvided || isSubFormatProvided ) && nByte < maxNumEBytes )
+ {
+ uint8_t fmtEByte = ( EBYTE_FORMAT_REQUEST | ( (uint8_t) format & MASK_3BIT ) );
+ eByte[nByte++] = isSubFormatProvided ? EBYTE_SUBFORMAT_REQUEST : fmtEByte;
+ }
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ if ( isSubFormatProvided && nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = ( (uint8_t) subFormat & MASK_6BIT ); /* Requested Coded subFormat */
+ }
+ /* Subsequent E-bytes - Split Renderer Configuration Request */
+ if ( isSRConfigProvided && nByte < maxNumEBytes )
+ {
+ eByte[nByte++] = EBYTE_SR_REQUEST |
+ ( (uint8_t) srConfig.diegetic << 3 ) | ( (uint8_t) srConfig.yaw << 2 ) |
+ ( (uint8_t) srConfig.pitch << 1 ) | ( (uint8_t) srConfig.roll << 0 );
+ }
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ }
+
+ /* Final E-byte is the PI Indicator E-Byte */
+ if ( piDataPresent && ( nByte < maxNumEBytes ) )
+ {
+ eByte[nByte++] = EBYTE_PI_INDICATOR; /* PI Indication */
+ }
+
+ *nBytesWritten = nByte;
+}
+
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+static ivas_error getSRToCByte(
+ IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */
+ uint32_t bitrateKbps, /* i : Bitrate in kbps */
+ uint8_t *tocByte /* o : toc byte 2 */
+)
+{
+ uint8_t bitIdx, codecId, digetic;
+ if ( bitrateKbps < 256000 || bitrateKbps > 512000 )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate for SR" );
+ }
+
+ bitIdx = ( ( bitrateKbps / 128000u ) - 1 ) & MASK_2BIT;
+ codecId = (uint8_t) srInfo->codec;
+ digetic = srInfo->diegetic ? 1 : 0;
+
+ *tocByte = ( digetic << 6 ) | ( codecId << 5 ) | ( bitIdx << 3 );
+
+ return IVAS_ERR_OK;
+}
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+
+static void addPackedPiDataToFrame( PIDATA_FRAME *piDataFrm, const PIDATA_PACKED *packedPiData, uint32_t piDataType )
+{
+ piDataFrm->piData[piDataType].size = packedPiData->size;
+ memcpy( piDataFrm->piData[piDataType].data, packedPiData->data, packedPiData->size );
+
+ /* Indicate th PI data type presense in bitmap, If the same pi data type is
+ already pushed for this frame, it is overwritten with the newer data */
+ if ( !( piDataFrm->piDataBitmap & ( 1u << piDataType ) ) )
+ {
+ piDataFrm->piDataBitmap |= ( 1u << piDataType );
+ piDataFrm->numPiDataAvailable++;
+ }
+
+ /* Atleast one valid PI data is now pushed for this frame, clear No PI data
+ for this frame */
+ if ( piDataFrm->piDataBitmap & ( 1u << IVAS_PI_NO_DATA ) )
+ {
+ piDataFrm->piDataBitmap &= ~( 1u << IVAS_PI_NO_DATA );
+ piDataFrm->numPiDataAvailable--;
+ }
+}
+
+ivas_error IVAS_RTP_PACK_PushFrame(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */
+ IVAS_RTP_CODEC codecId, /* i : Codec type (IVAS/EVS) */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SR_INFO *srInfo, /* i : Split Rendering Info */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ const IVAS_DATA_BUFFER *frameBuffer /* i : packed frame bitstream for IVAS/EVS */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint32_t bitrate = 0;
+ uint32_t frameLengthInBits = 0;
+ uint8_t tocByte = 0;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ uint8_t tocByte1 = 0;
+#endif
+ FRAME_NODE *node = NULL;
+ PIDATA_FRAME *piDataFrame = &hPack->piDataCache;
+ uint32_t piDataType = 0;
+
+ if ( frameBuffer == NULL || frameBuffer->length == 0 )
+ {
+ /* Indicates a NO_DATA_FRAME in case of DTX mode */
+ tocByte = ( hPack->amrwbIOMode ) ? TOC_INDICATE_NO_DATA_AMRWB : TOC_INDICATE_NO_DATA;
+ }
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ else if ( srInfo != NULL && srInfo->valid )
+ {
+ tocByte = TOC_INDICATE_SR;
+ error = getSRToCByte( srInfo, bitrate, &tocByte1 );
+ ERR_CHECK_RETURN( error );
+ }
+#endif
+ else
+ {
+ error = getBitrateFromCodecAndFrameSize( codecId, frameBuffer->length, &bitrate, &frameLengthInBits, &tocByte, &hPack->amrwbIOMode );
+ ERR_CHECK_RETURN( error );
+ }
+
+ /* Allocate a new frame node for this frame */
+ error = BPOOL_GetBuffer( hPack->packNodePool, (void **) &node );
+ ERR_CHECK_RETURN( error );
+
+ initFrameNode( node );
+
+ /* Set ToC byte & frame */
+ node->toc[node->tocNumBytes++] = tocByte;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ if ( srInfo != NULL && srInfo->valid )
+ {
+ node->toc[node->tocNumBytes++] = tocByte1;
+ }
+#endif
+
+ node->auNumBits = frameLengthInBits;
+ if ( frameBuffer != NULL )
+ {
+ memcpy( node->au, frameBuffer->buffer, frameBuffer->length );
+ }
+
+ /* If some Pi data is is Cache add to Frame Node's associated Pi Data */
+ mtx_lock( &hPack->apilock ); /* Lock to prevent access to shared cache */
+ if ( piDataFrame->numPiDataAvailable )
+ {
+ uint32_t bitmap = piDataFrame->piDataBitmap;
+ for ( piDataType = 0; piDataType < 32 && ( bitmap != 0 ); piDataType++ )
+ {
+ uint32_t mask = ( 1u << piDataType );
+ if ( bitmap & mask )
+ {
+ bitmap &= ~mask; /* Mask out this pi type to indicate processed */
+ addPackedPiDataToFrame( &node->piDataFrame, &piDataFrame->piData[piDataType], piDataType );
+ }
+ }
+ initPiDataFrame( piDataFrame ); /* Reset Cache */
+ }
+ mtx_unlock( &hPack->apilock );
+
+ /* Add to frames FiFo */
+ QUEUE_Push( hPack->frameQ, (NODE *) node );
+
+ return IVAS_ERR_OK;
+}
+
+uint32_t IVAS_RTP_PACK_GetNumFrames(
+ IVAS_RTP_PACK_HANDLE hPack /* i/o : IVAS rtp packer handle */
+)
+{
+ uint32_t nFrames = 0;
+ if ( hPack )
+ {
+ nFrames = QUEUE_Size( hPack->frameQ );
+ }
+ return nFrames;
+}
+
+/* Push single PI data to rtp packer
+ *
+ * Provide PI data for a current RTP Payload. All PI data is locally cached in the packer
+ * and set to the rtp packet with policy defined in initial configuration during call to
+ * IVAS_RTP_PACK_GetPacket.
+ *
+ */
+ivas_error IVAS_RTP_PACK_PushPiData(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */
+ const IVAS_PIDATA_GENERIC *data /* i : pointer to the PIData stucture */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ PIDATA_PACKED packedPiData;
+
+ if ( data == NULL ||
+ data->piDataType >= IVAS_PI_NO_DATA || /* NO_PI_DATA cannot be provided by user, it is generated in packing */
+ data->size > sizeof( PIDATA ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong PI Data provided" );
+ }
+
+ error = PI_PackData( data, &packedPiData, 0 );
+ ERR_CHECK_RETURN( error );
+
+ mtx_lock( &hPack->apilock ); /* Lock to prevent access to shared cache */
+ {
+ FRAME_NODE *node = (FRAME_NODE *) QUEUE_Back( hPack->frameQ );
+ /* use cache if no frame in Queue to associate PI data */
+ PIDATA_FRAME *piDataFrm = ( node != NULL ) ? &node->piDataFrame : &hPack->piDataCache;
+ addPackedPiDataToFrame( piDataFrm, &packedPiData, data->piDataType );
+ }
+ mtx_unlock( &hPack->apilock );
+
+ return IVAS_ERR_OK;
+}
+
+#define WRITE_BYTE_PAYLOAD_OR_EXIT( payload, byte ) \
+ if ( payload->length < payload->capacity ) \
+ { \
+ uint8_t _byte = ( byte ); \
+ payload->buffer[payload->length++] = _byte; \
+ } \
+ else \
+ { \
+ error = IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" ); \
+ goto err_exit; \
+ }
+
+ivas_error IVAS_RTP_PACK_GetPayload(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */
+ IVAS_DATA_BUFFER *payload, /* o : encapsulated rtp payload */
+ uint32_t *numFramesInPayload /* o : no. of frames in payload */
+)
+{
+ uint32_t n = 0, numFrame = 0;
+ ivas_error error = IVAS_ERR_OK;
+ uint32_t numPiDataPresent = 0;
+ FRAME_NODE *availableFrameNodes[IVAS_MAX_FRAMES_PER_RTP_PACKET];
+ size_t numEBytes = 0;
+
+ if ( payload == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Output data buffer is NULL" );
+ }
+
+ /* Calculate number of frames to pack in this payload */
+ numFrame = QUEUE_Size( hPack->frameQ );
+ numFrame = ( numFrame > hPack->initConfig.maxFramesPerPacket ) ? hPack->initConfig.maxFramesPerPacket : numFrame;
+ *numFramesInPayload = numFrame; /* numFrames in Packet */
+
+ /* Collect all the frame nodes from FiFo */
+ for ( n = 0; n < numFrame; n++ )
+ {
+ FRAME_NODE *node = (FRAME_NODE *) QUEUE_Pop( hPack->frameQ );
+ if ( node == NULL )
+ {
+ assert( 0 ); /* catastrophic error, implementation issue somewhere */
+ return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "NULL found in frame nodes" );
+ }
+ /* Calculate number of PI data present in total */
+ numPiDataPresent += node->piDataFrame.numPiDataAvailable;
+ availableFrameNodes[n] = node;
+ }
+
+ /* IVAS Payload starts with E-Bytes */
+ packEBytes( hPack, ( numPiDataPresent > 0 ), payload->capacity, &payload->buffer[payload->length], &numEBytes );
+ payload->length += numEBytes;
+
+ /* ToC bytes (atleast 1 byte per frame, 2 if SR )*/
+ for ( n = 0; n < numFrame; n++ )
+ {
+ FRAME_NODE *node = availableFrameNodes[n];
+ uint8_t fBit = ( n != ( numFrame - 1 ) ) ? TOC_HEADER_FOLLOWS : 0; /* Next ToC present */
+
+ WRITE_BYTE_PAYLOAD_OR_EXIT( payload, ( node->toc[0] | fBit ) );
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ if ( node->tocNumBytes == 2 )
+ {
+ WRITE_BYTE_PAYLOAD_OR_EXIT( payload, node->toc[1] );
+ }
+#endif
+ }
+
+ /* Frame Data */
+ for ( n = 0; n < numFrame; n++ )
+ {
+ FRAME_NODE *node = availableFrameNodes[n];
+ size_t frameLength = ( node->auNumBits + 7 ) >> 3; /* zero padded length in bytes */
+ if ( payload->length + frameLength <= payload->capacity )
+ {
+ memcpy( &payload->buffer[payload->length], node->au, frameLength );
+ }
+ else
+ {
+ error = IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient memory to write RTP Payload" );
+ goto err_exit;
+ }
+ payload->length += frameLength;
+ }
+
+ /* PI Data */
+ if ( numPiDataPresent > 0 )
+ {
+ bool skipPiData = false;
+ size_t nBytes = payload->length;
+ uint32_t numPiDataWritten = 0;
+
+ for ( n = 0; n < numFrame; n++ )
+ {
+ uint32_t piDataType = 0;
+ FRAME_NODE *node = availableFrameNodes[n];
+ PIDATA_FRAME *piDataFrame = &node->piDataFrame;
+ uint32_t bitmap = piDataFrame->piDataBitmap;
+ uint8_t PM = 0, PF = 0;
+
+ for ( piDataType = 0; piDataType < 32 && ( bitmap != 0 ); piDataType++ )
+ {
+ uint32_t mask = ( 1u << piDataType );
+ if ( bitmap & mask )
+ {
+ bitmap &= ~mask; /* Mask out this pi type to indicate processing */
+ /* Check if last PI data this frame */
+ PM = piDataFrame->piData[piDataType].data[0] & 0x60;
+ PM = (uint8_t) ( ( bitmap == 0 && PM != PI_HEADER_PM_GENERIC ) ? PI_HEADER_PM_LAST : PM );
+ /* Check if last PI data all frames */
+ PF = (uint8_t) ( ( bitmap == 0 && ( numPiDataWritten + 1 == numPiDataPresent ) ) ? PI_HEADER_PF_LAST : PI_HEADER_PF_NOT_LAST ); /* Last PI in Payload */
+ /* Update the first byte of PI Header with PF/PM */
+ piDataFrame->piData[piDataType].data[0] |= ( PF | PM );
+ if ( nBytes + piDataFrame->piData[piDataType].size < payload->capacity )
+ {
+ memcpy( &payload->buffer[nBytes], piDataFrame->piData[piDataType].data, piDataFrame->piData[piDataType].size );
+ nBytes += piDataFrame->piData[piDataType].size;
+ }
+ else
+ {
+ skipPiData = true; /* Not enough bytes in output for PI data */
+ }
+ numPiDataWritten++;
+ }
+ }
+ }
+ if ( !skipPiData )
+ {
+ payload->length = nBytes; /* update payload length after PI packing */
+ }
+ }
+
+err_exit:
+ /* Pop frames from Queue */
+ for ( n = 0; n < numFrame; n++ )
+ {
+ if ( BPOOL_FreeBuffer( hPack->packNodePool, availableFrameNodes[n] ) != IVAS_ERR_OK )
+ {
+ assert( 0 ); /* catastrophic error if this fails */
+ return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "frame node could not be freed" );
+ }
+ availableFrameNodes[n] = NULL;
+ }
+
+ return error;
+}
+
+ivas_error IVAS_RTP_PACK_GetPacket(
+ IVAS_RTP_PACK_HANDLE hPack, /* i/o : IVAS rtp packer handle */
+ IVAS_DATA_BUFFER *packet, /* o : encapsulated rtp packet */
+ uint32_t *numFramesInPacket /* o : no. of frames in packet */
+)
+{
+ ivas_error error = PackRtpHeader( &hPack->header, packet );
+ ERR_CHECK_RETURN( error );
+
+ error = IVAS_RTP_PACK_GetPayload( hPack, packet, numFramesInPacket );
+ ERR_CHECK_RETURN( error );
+
+ UpdateRtpHeader( &hPack->header, ( *numFramesInPacket ) * 320 );
+
+ return IVAS_ERR_OK;
+}
+
+ivas_error IVAS_RTP_UNPACK_Open(
+ IVAS_RTP_UNPACK_HANDLE *phUnpack, /* i/o : rtp unpacker handle */
+ const IVAS_RTP_UNPACK_CONFIG *config /* i : initial configuration for rtp unpacker */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ IVAS_RTP_UNPACK_HANDLE hUnpack;
+
+ if ( phUnpack == NULL || config == NULL )
+ {
+ return IVAS_ERR_UNEXPECTED_NULL_POINTER;
+ }
+
+ *phUnpack = NULL;
+ if ( ( hUnpack = (IVAS_RTP_UNPACK_HANDLE) calloc( 1, sizeof( struct IVAS_RTP_UNPACK ) ) ) == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS rtp unpack handle" );
+ }
+
+ if ( config->maxFramesPerPacket > IVAS_MAX_FRAMES_PER_RTP_PACKET )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Max frame per packet exeeds %d", IVAS_MAX_FRAMES_PER_RTP_PACKET );
+ }
+
+ hUnpack->maxNumberOfFrames = ( config->maxFramesPerPacket == 0 ) ? IVAS_MAX_FRAMES_PER_RTP_PACKET : config->maxFramesPerPacket;
+ hUnpack->maxNumberOfPiData = hUnpack->maxNumberOfFrames * IVAS_PI_MAX_ID;
+
+ error = BPOOL_Create( &hUnpack->unpackNodePool, sizeof( UNPACK_NODE ), hUnpack->maxNumberOfFrames );
+ ERR_CHECK_RETURN( error );
+
+ error = BPOOL_Create( &hUnpack->piDataPool, sizeof( PIDATA_NODE ), hUnpack->maxNumberOfPiData );
+ ERR_CHECK_RETURN( error );
+
+ error = QUEUE_Create( &hUnpack->frameQ );
+ ERR_CHECK_RETURN( error );
+
+ error = QUEUE_Create( &hUnpack->piDataQ );
+ ERR_CHECK_RETURN( error );
+
+ hUnpack->initConfig = *config;
+ mtx_init( &hUnpack->apilock, 0 );
+
+ initRequests( hUnpack->requests );
+
+ *phUnpack = hUnpack;
+ return IVAS_ERR_OK;
+}
+
+/* Close and free an existing instance of rtp unpacker */
+void IVAS_RTP_UNPACK_Close(
+ IVAS_RTP_UNPACK_HANDLE *phUnpack /* i/o : IVAS rtp unpacker handle */
+)
+{
+ IVAS_RTP_UNPACK_HANDLE hUnpack;
+
+ /* Free all memory */
+ if ( phUnpack == NULL || *phUnpack == NULL )
+ {
+ return;
+ }
+
+ hUnpack = *phUnpack;
+ mtx_destroy( &hUnpack->apilock );
+ QUEUE_Destroy( &hUnpack->frameQ );
+ QUEUE_Destroy( &hUnpack->piDataQ );
+ BPOOL_Destroy( &hUnpack->piDataPool );
+ BPOOL_Destroy( &hUnpack->unpackNodePool );
+ free( hUnpack->header.extData );
+ free( hUnpack );
+ *phUnpack = NULL;
+}
+
+static void setEVSRequests( IVAS_RTP_BANDWIDTH bandwidth, uint32_t bitrate, IVAS_RTP_CA_MODE caMode, IVAS_RTP_REQUEST_VALUE *requests )
+{
+ requests[IVAS_REQUEST_CODEC].codec = IVAS_RTP_EVS;
+ requests[IVAS_REQUEST_CA_MODE].caMode = caMode;
+ requests[IVAS_REQUEST_BITRATE].bitrate = bitrate;
+ requests[IVAS_REQUEST_BANDWIDTH].bandwidth = bandwidth;
+}
+
+static uint32_t parseInitialEByte( const IVAS_DATA_BUFFER *payload, uint32_t nBytes, IVAS_RTP_REQUEST_VALUE *requests )
+{
+ if ( nBytes < payload->length )
+ {
+ uint8_t byte = payload->buffer[nBytes];
+ uint8_t EvsIvasIndicator = ( byte & ( ~MASK_4BIT ) );
+ uint8_t BR = ( byte & MASK_4BIT );
+
+ if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 )
+ {
+ return nBytes;
+ }
+
+ nBytes++; /* Consume this e-byte */
+
+ switch ( EvsIvasIndicator )
+ {
+ case EBYTE_CMR_T_EVS_NB:
+ if ( BR < 7 )
+ {
+ uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC;
+ setEVSRequests( IVAS_BANDWIDTH_NB, bitrate, IVAS_RTP_CA_NO_REQ, requests );
+ }
+ break;
+ case EBYTE_CMR_T_EVS_IO: /* AMRWB-IO */
+ if ( BR < 9 )
+ {
+ uint32_t bitrate = amrWBIOFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC;
+ setEVSRequests( IVAS_BANDWIDTH_NO_REQ, bitrate, IVAS_RTP_CA_NO_REQ, requests );
+ }
+ break;
+ case EBYTE_CMR_T_EVS_CA_WB:
+ if ( BR < 8 )
+ {
+ uint32_t bitrate = 13200; /* Fixed in CA Mode */
+ setEVSRequests( IVAS_BANDWIDTH_WB, bitrate, BR, requests );
+ }
+ break;
+ case EBYTE_CMR_T_EVS_CA_SWB:
+ if ( BR < 8 )
+ {
+ uint32_t bitrate = 13200; /* Fixed in CA Mode */
+ setEVSRequests( IVAS_BANDWIDTH_SWB, bitrate, BR, requests );
+ }
+ break;
+ case EBYTE_CMR_T_EVS_WB:
+ if ( BR < 12 )
+ {
+ uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC;
+ setEVSRequests( IVAS_BANDWIDTH_WB, bitrate, IVAS_RTP_CA_NO_REQ, requests );
+ }
+ break;
+ case EBYTE_CMR_T_EVS_SWB: /* Intentional fall through */
+ if ( BR < 12 && BR > 2 )
+ {
+ uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC;
+ setEVSRequests( IVAS_BANDWIDTH_SWB, bitrate, IVAS_RTP_CA_NO_REQ, requests );
+ }
+ break;
+ case EBYTE_CMR_T_EVS_FB:
+ if ( BR < 12 && BR > 4 )
+ {
+ uint32_t bitrate = evsFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC;
+ setEVSRequests( IVAS_BANDWIDTH_FB, bitrate, IVAS_RTP_CA_NO_REQ, requests );
+ }
+ break;
+ case EBYTE_CMR_T_IVAS: /* IVAS */
+ if ( BR != 14 )
+ {
+ requests[IVAS_REQUEST_CODEC].codec = IVAS_RTP_IVAS;
+ requests[IVAS_REQUEST_BITRATE].bitrate = ( BR == 0xF ) ? 0 : ivasFrameSizeInBits[BR] * IVAS_NUM_FRAMES_PER_SEC;
+ requests[IVAS_REQUEST_CA_MODE].caMode = IVAS_RTP_CA_NO_REQ;
+ }
+ break;
+ }
+ }
+
+ return nBytes;
+}
+
+static uint32_t parseSubsequentEByte( const IVAS_DATA_BUFFER *payload, uint32_t nBytes, IVAS_RTP_REQUEST_VALUE *requests, bool *piDataIndicated )
+{
+ while ( nBytes < payload->length )
+ {
+ uint8_t byte = payload->buffer[nBytes];
+ uint8_t ET = ( byte & ( ~MASK_4BIT ) );
+
+ if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 )
+ {
+ return nBytes;
+ }
+
+ nBytes++; /* Consume this e-byte */
+
+ switch ( ET )
+ {
+ case EBYTE_BANDWIDTH_REQUEST: /* Bandwidth Request */
+ {
+ requests[IVAS_REQUEST_BANDWIDTH].bandwidth = IVAS_BANDWIDTH_WB + ( byte & MASK_2BIT );
+ }
+ break;
+ case EBYTE_FORMAT_REQUEST: /* Format Request */
+ {
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ bool S = ( byte >> 3 ) & MASK_1BIT;
+ if ( S )
+ {
+ /* Use the next byte to extract SubFormat */
+ if ( nBytes < payload->length )
+ {
+ byte = payload->buffer[nBytes++];
+ requests[IVAS_REQUEST_SUBFORMAT].subFormatType = byte & MASK_6BIT;
+ }
+ }
+#endif
+ requests[IVAS_REQUEST_FORMAT].formatType = byte & MASK_3BIT;
+ }
+ break;
+ case EBYTE_PI_INDICATOR: /* PI Indication */
+ *piDataIndicated = true;
+ break;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ case EBYTE_SR_REQUEST: /* Split Rendering Request */
+ {
+ IVAS_RTP_SPLITRENDER *srConfig = &requests[IVAS_REQUEST_SR_CONFIG].srConfig;
+ srConfig->diegetic = ( byte >> 3 ) & MASK_1BIT;
+ srConfig->yaw = ( byte >> 2 ) & MASK_1BIT;
+ srConfig->pitch = ( byte >> 1 ) & MASK_1BIT;
+ srConfig->roll = byte & MASK_1BIT;
+ srConfig->valid = true;
+ }
+ break;
+#endif
+ default: /* Reserved for future use - unhandled atm */
+ assert( 0 );
+ }
+ }
+
+ return nBytes;
+}
+
+static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc, uint32_t maxNumberOfToCBytes )
+{
+ bool headerFollows = true;
+ uint32_t nBytes = *numBytes;
+
+ *numFrames = 0;
+ while ( nBytes < payload->length && headerFollows )
+ {
+ uint8_t byte = payload->buffer[nBytes];
+ uint8_t BR = byte & MASK_4BIT;
+ uint8_t FT = byte & ( ( ~MASK_4BIT ) & MASK_6BIT );
+
+ headerFollows = ( byte & ( ~MASK_6BIT ) ) == TOC_HEADER_FOLLOWS;
+
+ if ( ( byte & EBYTE_TOC_HEADER_BIT ) != 0 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Expected ToC byte missing" );
+ }
+
+ nBytes++; /* Consume this e-byte */
+
+ if ( *numFrames == maxNumberOfToCBytes )
+ {
+ return IVAS_ERROR( IVAS_ERR_INTERNAL, "No of frames in packet exceed max defined" );
+ }
+
+ *numFrames += 1;
+ memset( toc, 0, sizeof( *toc ) );
+
+ if ( FT == TOC_INDICATE_ARMWB_Q || FT == TOC_INDICATE_AMRWB )
+ {
+ toc->codecId = IVAS_RTP_EVS;
+ toc->isAMRWB_IOmode = true;
+ toc->speechLostIndicated = ( FT == TOC_INDICATE_ARMWB_Q ) ? true : false; /* Q bit = 0 for AMRWB, BR is valid */
+ if ( BR <= 9 )
+ {
+ toc->auNumBits = amrWBIOFrameSizeInBits[BR];
+ }
+ else if ( BR < 14 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved bitrate provided in AMRWB ToC" );
+ }
+ else
+ {
+ toc->speechLostIndicated = ( BR == 14 ); /* SPEECH_LOST */
+ toc->auNumBits = 0;
+ }
+ }
+ else if ( FT == TOC_INDICATE_IVAS )
+ {
+ toc->codecId = IVAS_RTP_IVAS;
+ if ( BR == 14 )
+ {
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ /* Read Unconditional SR-ToC byte */
+ if ( nBytes < payload->length )
+ {
+ uint8_t SR_BR;
+ byte = payload->buffer[nBytes++];
+ SR_BR = ( byte >> 3 ) & MASK_2BIT;
+ if ( SR_BR == 0 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved bitrate provided in SR ToC" );
+ }
+ toc->srInfo.valid = true;
+ toc->srInfo.diegetic = ( byte >> 6 ) & MASK_1BIT;
+ toc->srInfo.codec = IVAS_SR_TRANSPORT_LCLD + ( ( byte >> 5 ) & MASK_1BIT );
+ toc->auNumBits = ( SR_BR + 1 ) * 128000u / IVAS_NUM_FRAMES_PER_SEC;
+ }
+ else
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during ToC SR byte" );
+ }
+#else
+ /* Reserved bit not expected */
+ return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved BR idx reported in ToC" );
+#endif
+ }
+ else
+ {
+ toc->auNumBits = ivasFrameSizeInBits[BR];
+ }
+ }
+ else /* EVS */
+ {
+ toc->codecId = IVAS_RTP_EVS;
+ toc->speechLostIndicated = ( FT == TOC_INDICATE_ARMWB_Q ) ? true : false; /* Q bit = 0 for AMRWB, BR is valid */
+ if ( BR < 13 )
+ {
+ toc->auNumBits = evsFrameSizeInBits[BR];
+ }
+ else if ( BR == 13 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Reserved bitrate provided in EVS ToC" );
+ }
+ else
+ {
+ toc->speechLostIndicated = ( BR == 14 ); /* SPEECH_LOST */
+ toc->auNumBits = 0;
+ }
+ }
+
+ toc++;
+
+ /* Handle any frame specific E-Bytes here currently there are none, so we skip any E-Bytes here after */
+ if ( headerFollows )
+ {
+ while ( nBytes < payload->length )
+ {
+ byte = payload->buffer[nBytes];
+ if ( ( byte & EBYTE_TOC_HEADER_BIT ) == 0 )
+ {
+ break;
+ }
+ nBytes++;
+ }
+ }
+ }
+
+ *numBytes = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error parsePIData( IVAS_RTP_UNPACK_HANDLE hUnpack, uint32_t rtpTimestamp, const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numPiDataInPacket )
+{
+ bool PF = true;
+ uint32_t nBytes = *numBytes;
+
+ while ( PF )
+ {
+ uint8_t piHeader0, PM, piDataType, byte = 0;
+ uint32_t piSize = 0;
+
+ if ( nBytes + 1 >= payload->length )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during expected PI Header read" );
+ }
+
+ piHeader0 = payload->buffer[nBytes++];
+
+ PF = ( piHeader0 >> 7 ) & MASK_1BIT; /* New PI header follows this PI Data Frame */
+ PM = ( piHeader0 & ( ~MASK_5BIT ) ) & MASK_7BIT; /* PI Marker Bits */
+ piDataType = ( piHeader0 & MASK_5BIT );
+
+ do
+ {
+ byte = payload->buffer[nBytes++];
+ piSize += byte;
+ if ( nBytes >= payload->length )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during reading piSize" );
+ }
+ } while ( byte == 255 );
+
+ if ( piDataType == IVAS_PI_NO_DATA )
+ {
+ if ( piSize > 0 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "NO_PI_DATA should be 0 sized" );
+ }
+
+ /* Do not add a node for NO_DATA */
+ }
+ else if ( nBytes + piSize <= payload->length )
+ {
+ PIDATA_NODE *node = NULL;
+ ivas_error error = BPOOL_GetBuffer( hUnpack->piDataPool, (void **) &node );
+ ERR_CHECK_RETURN( error );
+
+ node->next = NULL;
+
+ error = PI_UnPackData( piDataType, piSize, &payload->buffer[nBytes], (IVAS_PIDATA_GENERIC *) &node->data );
+ ERR_CHECK_RETURN( error );
+
+ node->timestamp = rtpTimestamp;
+
+ nBytes += piSize;
+ *numPiDataInPacket += 1;
+
+ QUEUE_Push( hUnpack->piDataQ, (NODE *) node );
+ }
+ else
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during reading pi data" );
+ }
+
+ if ( PM == PI_HEADER_PM_LAST )
+ {
+ rtpTimestamp += 16000 / IVAS_NUM_FRAMES_PER_SEC;
+ }
+ }
+
+ *numBytes = nBytes;
+ return IVAS_ERR_OK;
+}
+
+ivas_error IVAS_RTP_UNPACK_PushPayload(
+ IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */
+ const IVAS_DATA_BUFFER *payload, /* i : received rtp payload */
+ uint32_t timestamp, /* i : timestamp in RTP Clock @ 16KHz from rtp header */
+ uint16_t sequenceNumber, /* i : sequence number from rtp header */
+ uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */
+ uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */
+ uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint32_t nBytes = 0, numFrames = 0, numPiData = 0, n;
+ bool piDataIndicated = false;
+ TOC_INFO toc[IVAS_MAX_FRAMES_PER_RTP_PACKET];
+
+ IVAS_RTP_REQUEST_VALUE oldRequests[IVAS_REQUEST_MAX];
+
+ if ( hUnpack == NULL || payload == NULL )
+ {
+ return IVAS_ERR_UNEXPECTED_NULL_POINTER;
+ }
+
+ if ( remoteRequestBitmap != NULL )
+ {
+ *remoteRequestBitmap = 0;
+ }
+
+ if ( numFramesInPacket != NULL )
+ {
+ *numFramesInPacket = 0;
+ }
+
+ if ( numPiDataInPacket != NULL )
+ {
+ *numPiDataInPacket = 0;
+ }
+
+ /* Sanity check if any frame or PI data from last packet is still not pulled */
+ if ( QUEUE_Size( hUnpack->frameQ ) > 0 || QUEUE_Size( hUnpack->piDataQ ) > 0 )
+ {
+ assert( 0 );
+ return IVAS_ERROR( IVAS_ERR_INTERNAL, "Previous packet data should be consumed before next packet is pushed" );
+ }
+
+ memcpy( oldRequests, hUnpack->requests, sizeof( oldRequests ) );
+
+ /* Unpack IVAS Payload, starting with the E-Bytes */
+ nBytes = parseInitialEByte( payload, nBytes, hUnpack->requests );
+
+ /* Unpack any subsequent E-bytes */
+ nBytes = parseSubsequentEByte( payload, nBytes, hUnpack->requests, &piDataIndicated );
+
+ /* Unpack the ToC Bytes => Extract number of frames in packet */
+ error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ) );
+ ERR_CHECK_RETURN( error );
+
+ /* Read frame bits */
+ for ( n = 0; n < numFrames; n++ )
+ {
+ uint32_t frameSizeBytes;
+ UNPACK_NODE *node = NULL;
+
+ /* Get a new node */
+ error = BPOOL_GetBuffer( hUnpack->unpackNodePool, (void **) &node );
+ ERR_CHECK_RETURN( error );
+
+ node->next = NULL;
+ node->timestamp = timestamp + ( n * 320 );
+ node->seqNumber = sequenceNumber;
+ node->toc = toc[n];
+
+ frameSizeBytes = ( node->toc.auNumBits + 7 ) / 8;
+ if ( nBytes + frameSizeBytes <= payload->length )
+ {
+ memcpy( node->au, &payload->buffer[nBytes], frameSizeBytes );
+ nBytes += frameSizeBytes;
+ }
+ else
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "Underflow during expected frame bits" );
+ }
+
+ /* Add to frames FiFo */
+ QUEUE_Push( hUnpack->frameQ, (NODE *) node );
+ }
+
+ if ( piDataIndicated )
+ {
+ error = parsePIData( hUnpack, timestamp, payload, &nBytes, &numPiData );
+ if ( error != IVAS_ERR_OK )
+ {
+ /* PI Parsing errors are not fatal => indicate no PI data in packet as workaround */
+ numPiData = 0;
+ }
+ }
+
+ if ( numFramesInPacket != NULL )
+ {
+ *numFramesInPacket = numFrames;
+ }
+
+ if ( numPiDataInPacket )
+ {
+ *numPiDataInPacket = numPiData;
+ }
+
+ if ( remoteRequestBitmap )
+ {
+ for ( n = 0; n < IVAS_REQUEST_MAX; n++ )
+ {
+ bool changed = ( memcmp( &hUnpack->requests[n], &oldRequests[n], sizeof( IVAS_RTP_REQUEST_VALUE ) ) != 0 );
+ *remoteRequestBitmap |= changed ? ( 1u << n ) : 0;
+ }
+ }
+
+ return IVAS_ERR_OK;
+}
+
+ivas_error IVAS_RTP_UNPACK_PushPacket(
+ IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */
+ const IVAS_DATA_BUFFER *packet, /* i : received rtp Packet */
+ uint32_t *numFramesInPacket, /* o : number of IVAS/EVS frames in rtp packet */
+ uint32_t *numPiDataInPacket, /* o : number of PI data received in rtp packet */
+ uint32_t *remoteRequestBitmap /* o : bitmap of available request in this packet */
+)
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint32_t numHeaderBytes = 0;
+ IVAS_DATA_BUFFER payload;
+
+ error = UnpackRtpPacket( packet, &hUnpack->header, &numHeaderBytes );
+ ERR_CHECK_RETURN( error );
+
+ /* Offset to RTP Payload */
+ payload.capacity = packet->capacity;
+ payload.buffer = packet->buffer + numHeaderBytes;
+ payload.length = packet->length - numHeaderBytes;
+
+ return IVAS_RTP_UNPACK_PushPayload(
+ hUnpack,
+ &payload,
+ hUnpack->header.timestamp,
+ hUnpack->header.seqNumber,
+ numFramesInPacket,
+ numPiDataInPacket,
+ remoteRequestBitmap );
+}
+
+ivas_error IVAS_RTP_UNPACK_GetRequest(
+ IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp packer handle */
+ IVAS_RTP_REQUEST_TYPE type, /* i : remote request type */
+ IVAS_RTP_REQUEST_VALUE *value /* o : pointer of the requested type */
+)
+{
+ if ( type < 0 || type >= IVAS_REQUEST_MAX )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid request key provided" );
+ }
+ *value = hUnpack->requests[type];
+ return IVAS_ERR_OK;
+}
+
+ivas_error IVAS_RTP_UNPACK_PullFrame(
+ IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */
+ IVAS_RTP_CODEC *receivedCodecId, /* o : Codec type (IVAS/EVS) */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_RTP_SR_INFO *srInfo, /* o : Split Rendering Info */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ IVAS_DATA_BUFFER *frameBuffer, /* o : packed frame bitstream for IVAS/EVS */
+ int16_t *frameSizeInBits, /* o : exact frame size in bits (AMRWB IO) */
+ uint32_t *timestamp, /* o : timestamp in RTP Clock @ 16KHz */
+ uint16_t *sequenceNumber, /* o : sequence number from rtp header */
+ bool *speechLostIndicated, /* o : Is current frame indicated as Lost */
+ bool *isAMRWB_IOmode /* o : Is AMRWB_IO mode EVS frame */
+)
+{
+ size_t length = 0;
+ UNPACK_NODE *node = (UNPACK_NODE *) QUEUE_Pop( hUnpack->frameQ );
+
+ /* Check if a node is available in FiFo */
+ if ( node == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "No more frames in unpack fifo" );
+ }
+
+ length = ( node->toc.auNumBits + 7 ) / 8;
+ if ( frameBuffer != NULL && ( length <= frameBuffer->capacity ) )
+ {
+ memcpy( frameBuffer->buffer, node->au, length );
+ frameBuffer->length = length;
+ }
+
+ if ( frameSizeInBits != NULL )
+ {
+ *frameSizeInBits = (int16_t) node->toc.auNumBits;
+ }
+
+ if ( receivedCodecId != NULL )
+ {
+ *receivedCodecId = node->toc.codecId;
+ }
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ if ( srInfo != NULL )
+ {
+ *srInfo = node->toc.srInfo;
+ }
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+
+ if ( timestamp != NULL )
+ {
+ *timestamp = node->timestamp;
+ }
+
+ if ( sequenceNumber != NULL )
+ {
+ *sequenceNumber = node->seqNumber;
+ }
+
+ if ( speechLostIndicated != NULL )
+ {
+ *speechLostIndicated = node->toc.speechLostIndicated;
+ }
+
+ if ( isAMRWB_IOmode != NULL )
+ {
+ *isAMRWB_IOmode = node->toc.isAMRWB_IOmode;
+ }
+
+ return BPOOL_FreeBuffer( hUnpack->unpackNodePool, node );
+}
+
+ivas_error IVAS_RTP_UNPACK_PullNextPiData(
+ IVAS_RTP_UNPACK_HANDLE hUnpack, /* i/o : IVAS rtp unpacker handle */
+ IVAS_PIDATA_GENERIC *data, /* o : output data buffer for the Pi data */
+ size_t capacity, /* i : capacity of pi data buffer in bytes */
+ uint32_t *timestamp /* o : timestamp in RTP Clock @ 16KHz */
+)
+{
+ IVAS_PIDATA_GENERIC *pi = NULL;
+ PIDATA_NODE *node = (PIDATA_NODE *) QUEUE_Pop( hUnpack->piDataQ );
+
+ /* Check if a node is available in FiFo */
+ if ( node == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNDERFLOW, "No more pi data in unpack fifo" );
+ }
+
+ pi = (IVAS_PIDATA_GENERIC *) &node->data;
+
+ if ( data != NULL && ( pi->size <= capacity ) )
+ {
+ memcpy( data, pi, pi->size );
+ }
+
+ if ( timestamp != NULL )
+ {
+ *timestamp = node->timestamp;
+ }
+
+ return BPOOL_FreeBuffer( hUnpack->piDataPool, node );
+}
+
+#endif /* IVAS_RTPDUMP */
diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c
new file mode 100644
index 0000000000000000000000000000000000000000..7150cfe4a80bd911f5adfd3bedc946e4db90fc0b
--- /dev/null
+++ b/lib_util/ivas_rtp_pi_data.c
@@ -0,0 +1,850 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#include "ivas_error_utils.h"
+#include "ivas_rtp_internal.h"
+
+#ifdef IVAS_RTPDUMP
+
+/* Generic PI data packing/unpacking functions */
+typedef ivas_error ( *PACK_PI_FN )( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten );
+typedef ivas_error ( *UNPACK_PI_FN )( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData );
+
+static __inline uint32_t writeInt16( uint8_t *buffer, uint32_t idx, int16_t val )
+{
+ buffer[idx++] = (uint8_t) ( val >> 8 );
+ buffer[idx++] = (uint8_t) ( val & 0x00FF );
+ return idx;
+}
+
+static __inline int16_t readInt16( const uint8_t *buffer )
+{
+ return (int16_t) ( (uint16_t) buffer[0] << 8 ) | ( (uint16_t) buffer[1] );
+}
+
+/*-----------------------------------------------------------------------*
+ * ivasPayload_convertToQ15()
+ *
+ * Convert a float value into a Q15 encoded value.
+ *-----------------------------------------------------------------------*/
+static int16_t ivasPayload_convertToQ15( float value )
+{
+ value = ( value * 32768.0f );
+ value = value > +32767.0f ? +32767.0f : value;
+ value = value < -32768.0f ? -32768.0f : value;
+ return (int16_t) ( value );
+}
+
+static ivas_error packUnsupportedData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ (void) piData;
+ (void) buffer;
+ (void) maxDataBytes;
+ /* Skip packing */
+ *nBytesWritten = 0;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackUnsupportedData( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ (void) piData;
+ (void) buffer;
+ (void) numDataBytes;
+ /* Skip unpacking */
+ return IVAS_ERR_OK;
+}
+
+static ivas_error packNoPiData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0;
+ (void) piData;
+
+ *nBytesWritten = 0;
+
+ /* NO_PI_DATA is just PI header with no data */
+ if ( maxDataBytes < 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in PI data buffer for NO_PI_DATA" );
+ }
+
+ buffer[nBytes++] = ( IVAS_PI_NO_DATA ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = 0; /* NO_PI_DATA is 0 bytes */
+
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackNoPiData( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ (void) buffer;
+
+ if ( numDataBytes != 0 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "NO_PI_DATA must be 0 byte" );
+ }
+
+ piData->size = sizeof( IVAS_PIDATA_NO_DATA );
+ return IVAS_ERR_OK;
+}
+
+static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0;
+ const IVAS_PIDATA_ORIENTATION *orientation = (const IVAS_PIDATA_ORIENTATION *) piData;
+
+ *nBytesWritten = 0;
+
+ if ( piData->size != sizeof( IVAS_PIDATA_ORIENTATION ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in Orientation PI data" );
+ }
+
+ if ( ( piData->piDataType != IVAS_PI_SCENE_ORIENTATION ) && ( piData->piDataType != IVAS_PI_DEVICE_ORIENTATION_COMPENSATED ) && ( piData->piDataType != IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED )
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ && ( piData->piDataType != IVAS_PI_PLAYBACK_DEVICE_ORIENTATION ) && ( piData->piDataType != IVAS_PI_HEAD_ORIENTATION )
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Orientation PI data" );
+ }
+
+ /* Orientation data is 8 bytes, header is 2 bytes */
+ if ( maxDataBytes < 8 + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Orientation PI data" );
+ }
+
+ buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = 8;
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.w ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.x ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.y ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation.z ) );
+
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData;
+
+ /* Orientation data is 8 bytes */
+ if ( numDataBytes != 8 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" );
+ }
+
+ piData->size = sizeof( IVAS_PIDATA_ORIENTATION );
+ orientation->orientation.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) );
+ orientation->orientation.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) );
+ orientation->orientation.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) );
+ orientation->orientation.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) );
+
+ return IVAS_ERR_OK;
+}
+
+static uint32_t getIndexTable( const float *table, uint32_t tableLength, float value )
+{
+ uint32_t idx = 0;
+ if ( value <= table[0] )
+ {
+ return 0;
+ }
+
+ for ( idx = 1; idx < tableLength; idx++ )
+ {
+ if ( value < table[idx] )
+ {
+ break;
+ }
+ }
+ return idx - 1;
+}
+
+#define GET_IDX( table, nBits, value ) getIndexTable( table, ( 1u << ( nBits ) ), ( value ) )
+
+static ivas_error packAcousticEnvironment( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0;
+ uint8_t packedSize = 1;
+ const IVAS_PIDATA_ACOUSTIC_ENV *aeEnv = (const IVAS_PIDATA_ACOUSTIC_ENV *) piData;
+
+ *nBytesWritten = 0;
+
+ if ( piData->size != sizeof( IVAS_PIDATA_ACOUSTIC_ENV ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in PI data of type Acoustic Environment" );
+ }
+
+ if ( aeEnv->availEarlyReflections )
+ {
+ packedSize = 8;
+ }
+ else if ( aeEnv->availLateReverb )
+ {
+ packedSize = 5;
+ }
+
+ /* Acoustic Env data is packedSize bytes, header is 2 bytes */
+ if ( maxDataBytes < (uint32_t) packedSize + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Insufficient space to pack Orientation PI data" );
+ }
+
+ buffer[nBytes++] = ( IVAS_PI_ACOUSTIC_ENVIRONMENT ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = packedSize;
+
+ if ( packedSize == 1 )
+ {
+ buffer[nBytes++] = aeEnv->aeid & 0x7F;
+ }
+ else
+ {
+ uint64_t dWord = (uint64_t) aeEnv->aeid << 57;
+
+ dWord |= (uint64_t) GET_IDX( mapRT60, NBITS_RT60, aeEnv->rt60[IVAS_PI_AE_LOW] ) << 52;
+ dWord |= (uint64_t) GET_IDX( mapDSR, NBITS_DSR, aeEnv->dsr[IVAS_PI_AE_LOW] ) << 46;
+ dWord |= (uint64_t) GET_IDX( mapRT60, NBITS_RT60, aeEnv->rt60[IVAS_PI_AE_MID] ) << 41;
+ dWord |= (uint64_t) GET_IDX( mapDSR, NBITS_DSR, aeEnv->dsr[IVAS_PI_AE_MID] ) << 35;
+ dWord |= (uint64_t) GET_IDX( mapRT60, NBITS_RT60, aeEnv->rt60[IVAS_PI_AE_HIGH] ) << 30;
+ dWord |= (uint64_t) GET_IDX( mapDSR, NBITS_DSR, aeEnv->dsr[IVAS_PI_AE_HIGH] ) << 24;
+
+ buffer[nBytes++] = (uint8_t) ( dWord >> 56 );
+ buffer[nBytes++] = (uint8_t) ( dWord >> 48 );
+ buffer[nBytes++] = (uint8_t) ( dWord >> 40 );
+ buffer[nBytes++] = (uint8_t) ( dWord >> 32 );
+ buffer[nBytes++] = (uint8_t) ( dWord >> 24 );
+
+ if ( packedSize > 5 )
+ {
+ dWord |= (uint64_t) GET_IDX( mapRoomDims, NBITS_DIM, aeEnv->roomDimensions.x ) << 20;
+ dWord |= (uint64_t) GET_IDX( mapRoomDims, NBITS_DIM, aeEnv->roomDimensions.y ) << 16;
+ dWord |= (uint64_t) GET_IDX( mapRoomDims, NBITS_DIM, aeEnv->roomDimensions.z ) << 12;
+ dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_FRONT] ) << 10;
+ dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_BACK] ) << 8;
+ dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_LEFT] ) << 6;
+ dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_RIGHT] ) << 4;
+ dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_CEILING] ) << 2;
+ dWord |= (uint64_t) GET_IDX( mapAbsorbtion, NBITS_ABS, aeEnv->absorbCoeffs[IVAS_PI_AE_FLOOR] );
+
+ buffer[nBytes++] = (uint8_t) ( dWord >> 16 );
+ buffer[nBytes++] = (uint8_t) ( dWord >> 8 );
+ buffer[nBytes++] = (uint8_t) ( dWord );
+ }
+ }
+
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackAcousticEnvironment( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ IVAS_PIDATA_ACOUSTIC_ENV *aeEnv = (IVAS_PIDATA_ACOUSTIC_ENV *) piData;
+
+ /* Acooustic Env data is either 1, 5 or 8 bytes */
+ if ( numDataBytes != 1 && numDataBytes != 5 && numDataBytes != 8 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack PI data of type Acoustic Environment" );
+ }
+
+ piData->size = sizeof( IVAS_PIDATA_ACOUSTIC_ENV );
+ aeEnv->availLateReverb = ( numDataBytes >= 5 );
+ aeEnv->availEarlyReflections = ( numDataBytes == 8 );
+
+ if ( numDataBytes == 1 )
+ {
+ aeEnv->aeid = buffer[0];
+ }
+ else
+ {
+ uint64_t dWord = 0ull;
+ uint32_t n;
+ for ( n = 0; n < numDataBytes; n++ )
+ {
+ dWord <<= 8;
+ dWord |= buffer[n];
+ }
+ dWord <<= ( 8 - numDataBytes ) * 8;
+
+ aeEnv->aeid = (uint8_t) ( ( dWord >> 57 ) & MASK_AEID );
+ aeEnv->rt60[IVAS_PI_AE_LOW] = mapRT60[( dWord >> 52 ) & MASK_RT60];
+ aeEnv->dsr[IVAS_PI_AE_LOW] = mapDSR[( dWord >> 46 ) & MASK_DSR];
+ aeEnv->rt60[IVAS_PI_AE_MID] = mapRT60[( dWord >> 41 ) & MASK_RT60];
+ aeEnv->dsr[IVAS_PI_AE_MID] = mapDSR[( dWord >> 35 ) & MASK_DSR];
+ aeEnv->rt60[IVAS_PI_AE_HIGH] = mapRT60[( dWord >> 30 ) & MASK_RT60];
+ aeEnv->dsr[IVAS_PI_AE_HIGH] = mapDSR[( dWord >> 24 ) & MASK_DSR];
+
+ aeEnv->roomDimensions.x = mapRoomDims[( dWord >> 20 ) & MASK_DIM];
+ aeEnv->roomDimensions.y = mapRoomDims[( dWord >> 16 ) & MASK_DIM];
+ aeEnv->roomDimensions.z = mapRoomDims[( dWord >> 12 ) & MASK_DIM];
+
+ aeEnv->absorbCoeffs[IVAS_PI_AE_FRONT] = mapAbsorbtion[( dWord >> 10 ) & MASK_ABS];
+ aeEnv->absorbCoeffs[IVAS_PI_AE_BACK] = mapAbsorbtion[( dWord >> 8 ) & MASK_ABS];
+ aeEnv->absorbCoeffs[IVAS_PI_AE_LEFT] = mapAbsorbtion[( dWord >> 6 ) & MASK_ABS];
+ aeEnv->absorbCoeffs[IVAS_PI_AE_RIGHT] = mapAbsorbtion[( dWord >> 4 ) & MASK_ABS];
+ aeEnv->absorbCoeffs[IVAS_PI_AE_CEILING] = mapAbsorbtion[( dWord >> 2 ) & MASK_ABS];
+ aeEnv->absorbCoeffs[IVAS_PI_AE_FLOOR] = mapAbsorbtion[( dWord >> 0 ) & MASK_ABS];
+ }
+
+ return IVAS_ERR_OK;
+}
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+static ivas_error packAudioDescription( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t n;
+ uint32_t nBytes = 0;
+ const IVAS_PIDATA_AUDIO_DESC *audioDesc = (const IVAS_PIDATA_AUDIO_DESC *) piData;
+ uint32_t packedSize = audioDesc->nValidEntries; /* Each Entry is 1 byte */
+
+ *nBytesWritten = 0;
+
+ if ( audioDesc->nValidEntries > ( IVAS_MAX_NUM_OBJECTS + 1 ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNSUPPORTED_FRAME, "Audio Description cannot have more than 5 entries" );
+ }
+
+ /* Audio Description data is max 5 bytes, 2 bytes header */
+ if ( maxDataBytes < packedSize + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in Audio Description PI data buffer" );
+ }
+
+ buffer[nBytes++] = ( IVAS_PI_AUDIO_DESCRIPTION ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = (uint8_t) packedSize;
+
+ for ( n = 0; n < audioDesc->nValidEntries; n++ )
+ {
+ buffer[nBytes++] = ( audioDesc->audioId[n].speech ? PI_AD_SPEECH_INDICATED : 0 ) |
+ ( audioDesc->audioId[n].music ? PI_AD_MUSIC_INDICATED : 0 ) |
+ ( audioDesc->audioId[n].ambiance ? PI_AD_AMBIANCE_INDICATED : 0 ) |
+ ( audioDesc->audioId[n].editable ? PI_AD_EDITABLE_INDICATED : 0 ) |
+ ( audioDesc->audioId[n].binaural ? PI_AD_BINAURAL_INDICATED : 0 );
+ }
+
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackAudioDescription( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ uint32_t n;
+ IVAS_PIDATA_AUDIO_DESC *audioDesc = (IVAS_PIDATA_AUDIO_DESC *) piData;
+
+ /* Audio Description data is max 5 bytes */
+ if ( numDataBytes > ( IVAS_MAX_NUM_OBJECTS + 1 ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" );
+ }
+
+ audioDesc->size = sizeof( IVAS_PIDATA_AUDIO_DESC );
+ audioDesc->nValidEntries = numDataBytes;
+ audioDesc->piDataType = IVAS_PI_AUDIO_DESCRIPTION;
+
+ for ( n = 0; n < audioDesc->nValidEntries; n++ )
+ {
+ audioDesc->audioId[n].speech = ( buffer[n] & PI_AD_SPEECH_INDICATED ) != 0;
+ audioDesc->audioId[n].music = ( buffer[n] & PI_AD_MUSIC_INDICATED ) != 0;
+ audioDesc->audioId[n].ambiance = ( buffer[n] & PI_AD_AMBIANCE_INDICATED ) != 0;
+ audioDesc->audioId[n].editable = ( buffer[n] & PI_AD_EDITABLE_INDICATED ) != 0;
+ audioDesc->audioId[n].binaural = ( buffer[n] & PI_AD_BINAURAL_INDICATED ) != 0;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+static ivas_error packDynamicSuppression( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0;
+ const IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = (const IVAS_PIDATA_DYNAMIC_SUPPRESSION *) piData;
+
+ *nBytesWritten = 0;
+
+ /* Dynamic Audio Suppression data is 2 bytes, 2 bytes header */
+ if ( maxDataBytes < 2 + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space in DAS PI data buffer" );
+ }
+
+ buffer[nBytes++] = ( IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = 2u;
+
+ buffer[nBytes++] = ( das->speech ? PI_AD_SPEECH_INDICATED : 0 ) |
+ ( das->music ? PI_AD_MUSIC_INDICATED : 0 ) |
+ ( das->ambiance ? PI_AD_AMBIANCE_INDICATED : 0 );
+ buffer[nBytes++] = ( (uint8_t) das->sli & MASK_4BIT ) << 4;
+
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackDynamicSuppression( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ IVAS_PIDATA_DYNAMIC_SUPPRESSION *das = (IVAS_PIDATA_DYNAMIC_SUPPRESSION *) piData;
+
+ /* Dynamic Suppression data is 2 bytes */
+ if ( numDataBytes != 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack DAS PI data" );
+ }
+
+ das->size = sizeof( IVAS_PIDATA_AUDIO_DESC );
+ das->piDataType = IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION;
+ das->speech = ( buffer[0] & PI_AD_SPEECH_INDICATED ) != 0;
+ das->music = ( buffer[0] & PI_AD_MUSIC_INDICATED ) != 0;
+ das->ambiance = ( buffer[0] & PI_AD_AMBIANCE_INDICATED ) != 0;
+ das->sli = ( buffer[1] >> 4 );
+
+ return IVAS_ERR_OK;
+}
+
+static ivas_error packListenerPosition( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0;
+ const IVAS_PIDATA_LISTENER_POSITION *listener = (const IVAS_PIDATA_LISTENER_POSITION *) piData;
+
+ *nBytesWritten = 0;
+
+ if ( piData->size != sizeof( IVAS_PIDATA_LISTENER_POSITION ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in LISTENER POSITION PI data" );
+ }
+
+ if ( piData->piDataType != IVAS_PI_LISTENER_POSITION )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in LISTENER POSITION PI data" );
+ }
+
+ /* Position data is 6 bytes, header is 2 bytes */
+ if ( maxDataBytes < 6 + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack LISTENER POSITION PI data" );
+ }
+
+ buffer[nBytes++] = ( listener->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = 6;
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.x / MAX_PI_POSITION_METERS ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.y / MAX_PI_POSITION_METERS ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position.z / MAX_PI_POSITION_METERS ) );
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ IVAS_PIDATA_LISTENER_POSITION *listener = (IVAS_PIDATA_LISTENER_POSITION *) piData;
+
+ /* Position data is 6 bytes */
+ if ( numDataBytes != 6 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack LISTENER POSITION PI data" );
+ }
+
+ listener->size = sizeof( IVAS_PIDATA_LISTENER_POSITION );
+ listener->piDataType = IVAS_PI_LISTENER_POSITION;
+ listener->position.x = FLOAT_FROM_Q15( readInt16( &buffer[0] ) ) * MAX_PI_POSITION_METERS;
+ listener->position.y = FLOAT_FROM_Q15( readInt16( &buffer[2] ) ) * MAX_PI_POSITION_METERS;
+ listener->position.z = FLOAT_FROM_Q15( readInt16( &buffer[4] ) ) * MAX_PI_POSITION_METERS;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0, n;
+ uint8_t byte = 0;
+ const IVAS_PIDATA_DIEGETIC *diegetic = (const IVAS_PIDATA_DIEGETIC *) piData;
+
+ *nBytesWritten = 0;
+
+ if ( piData->size != sizeof( IVAS_PIDATA_DIEGETIC ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in Diegetic Type PI data" );
+ }
+
+ if ( piData->piDataType != IVAS_PI_DIEGETIC_TYPE )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Diegetic Type PI data" );
+ }
+
+ /* Diegetic data is 1 bytes, header is 2 bytes */
+ if ( maxDataBytes < 1 + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Diegetic Type PI data" );
+ }
+
+ /* Valid bits must be based on active bits defined for the input format */
+ for ( n = 0; n < ( IVAS_MAX_NUM_OBJECTS + 1 ); n++ )
+ {
+ byte <<= 1;
+ byte |= ( diegetic->isDiegetic[n] );
+ }
+ byte <<= 3;
+
+ buffer[nBytes++] = ( diegetic->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = 1;
+ buffer[nBytes++] = byte;
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackDiegetic( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ uint32_t n;
+ IVAS_PIDATA_DIEGETIC *diegetic = (IVAS_PIDATA_DIEGETIC *) piData;
+ uint8_t byte;
+
+ /* Diegetic data is 1 bytes */
+ if ( numDataBytes != 1 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Diegetic PI data" );
+ }
+
+ diegetic->size = sizeof( IVAS_PIDATA_DIEGETIC );
+ diegetic->piDataType = IVAS_PI_DIEGETIC_TYPE;
+
+ byte = buffer[0];
+ /* Valid bits must be based on active bits defined for the input format */
+ for ( n = 0; n < ( IVAS_MAX_NUM_OBJECTS + 1 ); n++ )
+ {
+ diegetic->isDiegetic[n] = ( ( byte >> ( 7 - n ) ) & 1 ) != 0;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten )
+{
+ uint32_t nBytes = 0;
+ uint8_t packedSize = 1;
+ const IVAS_PIDATA_AUDIO_FOCUS *audioFocus = (const IVAS_PIDATA_AUDIO_FOCUS *) piData;
+
+ *nBytesWritten = 0;
+
+ if ( piData->size != sizeof( IVAS_PIDATA_AUDIO_FOCUS ) )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in PI data of type Audio Focus" );
+ }
+
+ if ( audioFocus->availDirection && audioFocus->availLevel )
+ {
+ packedSize = 9;
+ }
+ else if ( audioFocus->availDirection )
+ {
+ packedSize = 8;
+ }
+ else if ( audioFocus->availLevel )
+ {
+ packedSize = 1;
+ }
+ else
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Neither direction or level is available for packing Audio Focus" );
+ }
+
+ /* Audio Focus data is packedSize bytes, header is 2 bytes */
+ if ( maxDataBytes < (uint32_t) packedSize + 2 )
+ {
+ return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Insufficient space to pack Audio Focus PI data" );
+ }
+
+ buffer[nBytes++] = ( audioFocus->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */
+ buffer[nBytes++] = packedSize;
+
+ if ( packedSize == 9 || packedSize == 8 )
+ {
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.w ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.x ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.y ) );
+ nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.z ) );
+ }
+ if ( packedSize == 9 || packedSize == 1 )
+ {
+ buffer[nBytes++] = ( (uint8_t) audioFocus->flvl & MASK_4BIT ) << 4;
+ }
+
+ *nBytesWritten = nBytes;
+ return IVAS_ERR_OK;
+}
+
+static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData )
+{
+ IVAS_PIDATA_AUDIO_FOCUS *audioFocus = (IVAS_PIDATA_AUDIO_FOCUS *) piData;
+
+ /* Audio Focus data is either 1, 8 or 9 bytes */
+ if ( numDataBytes != 1 && numDataBytes != 8 && numDataBytes != 9 )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack PI data of type Audio Focus" );
+ }
+
+ piData->size = sizeof( IVAS_PIDATA_AUDIO_FOCUS );
+ audioFocus->availDirection = ( numDataBytes >= 8 );
+ audioFocus->availLevel = ( numDataBytes == 1 || numDataBytes == 9 );
+
+ if ( numDataBytes == 1 )
+ {
+ audioFocus->flvl = ( buffer[0] >> 4 );
+ }
+ else
+ {
+ audioFocus->direction.w = FLOAT_FROM_Q15( readInt16( &buffer[0] ) );
+ audioFocus->direction.x = FLOAT_FROM_Q15( readInt16( &buffer[2] ) );
+ audioFocus->direction.y = FLOAT_FROM_Q15( readInt16( &buffer[4] ) );
+ audioFocus->direction.z = FLOAT_FROM_Q15( readInt16( &buffer[6] ) );
+
+ if ( numDataBytes == 9 )
+ {
+ audioFocus->flvl = ( buffer[8] >> 4 );
+ }
+ }
+
+ return IVAS_ERR_OK;
+}
+
+
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+
+static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = {
+ packOrientation, /* SCENE_ORIENTATION */
+ packOrientation, /* DEVICE_ORIENTATION_COMPENSATED */
+ packOrientation, /* DEVICE_ORIENTATION_UNCOMPENSATED */
+ packAcousticEnvironment, /* ACOUSTIC_ENVIRONMENT */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ packAudioDescription, /* AUDIO_DESCRIPTION */
+#else
+ packUnsupportedData, /* AUDIO_DESCRIPTION */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ packUnsupportedData, /* ISM_NUM */
+ packUnsupportedData, /* ISM_ID */
+ packUnsupportedData, /* ISM_GAIN */
+ packUnsupportedData, /* ISM_ORIENTATION */
+ packUnsupportedData, /* ISM_POSITION */
+ packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */
+ packUnsupportedData, /* ISM_DIRECTIVITY */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ packDiegetic, /* DIEGETIC_TYPE */
+#else
+ packUnsupportedData, /* DIEGETIC_TYPE */
+#endif
+ packUnsupportedData, /* RESERVED13 */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ packAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */
+#else
+ packUnsupportedData, /* AUDIO_FOCUS_INDICATION */
+#endif
+ packUnsupportedData, /* RESERVED15 */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ packOrientation, /* PLAYBACK_DEVICE_ORIENTATION */
+ packOrientation, /* HEAD_ORIENTATION */
+ packListenerPosition, /* LISTENER_POSITION */
+ packDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */
+ packAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */
+#else
+ packUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */
+ packUnsupportedData, /* HEAD_ORIENTATION */
+ packUnsupportedData, /* LISTENER_POSITION */
+ packUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */
+ packUnsupportedData, /* AUDIO_FOCUS_DIRECTION */
+#endif
+ packUnsupportedData, /* PI_LATENCY */
+ packUnsupportedData, /* R_ISM_ID */
+ packUnsupportedData, /* R_ISM_GAIN */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ packOrientation, /* R_ISM_ORIENTATION */
+#else
+ packUnsupportedData, /* R_ISM_ORIENTATION */
+#endif
+ packUnsupportedData, /* R_ISM_POSITION */
+ packUnsupportedData, /* R_ISM_DIRECTION */
+ packUnsupportedData, /* RESERVED27 */
+ packUnsupportedData, /* RESERVED28 */
+ packUnsupportedData, /* RESERVED29 */
+ packUnsupportedData, /* RESERVED30 */
+ packNoPiData /* NO_DATA */
+};
+
+static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = {
+ unpackOrientation, /* SCENE_ORIENTATION */
+ unpackOrientation, /* DEVICE_ORIENTATION_COMPENSATED */
+ unpackOrientation, /* DEVICE_ORIENTATION_UNCOMPENSATED */
+ unpackAcousticEnvironment, /* ACOUSTIC_ENVIRONMENT */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ unpackAudioDescription, /* AUDIO_DESCRIPTION */
+#else
+ unpackUnsupportedData, /* AUDIO_DESCRIPTION */
+#endif
+ unpackUnsupportedData, /* ISM_NUM */
+ unpackUnsupportedData, /* ISM_ID */
+ unpackUnsupportedData, /* ISM_GAIN */
+ unpackUnsupportedData, /* ISM_ORIENTATION */
+ unpackUnsupportedData, /* ISM_POSITION */
+ unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */
+ unpackUnsupportedData, /* ISM_DIRECTIVITY */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ unpackDiegetic, /* DIEGETIC_TYPE */
+#else
+ unpackUnsupportedData, /* DIEGETIC_TYPE */
+#endif
+ unpackUnsupportedData, /* RESERVED13 */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */
+#else
+ unpackUnsupportedData, /* AUDIO_FOCUS_INDICATION */
+#endif
+ unpackUnsupportedData, /* RESERVED15 */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ unpackOrientation, /* PLAYBACK_DEVICE_ORIENTATION */
+ unpackOrientation, /* HEAD_ORIENTATION */
+ unpackListenerPosition, /* LISTENER_POSITION */
+ unpackDynamicSuppression, /* DYNAMIC_AUDIO_SUPPRESSION */
+ unpackAudioFocusCommon, /* AUDIO_FOCUS_REQUEST */
+#else
+ unpackUnsupportedData, /* PLAYBACK_DEVICE_ORIENTATION */
+ unpackUnsupportedData, /* HEAD_ORIENTATION */
+ unpackUnsupportedData, /* LISTENER_POSITION */
+ unpackUnsupportedData, /* DYNAMIC_AUDIO_SUPPRESSION */
+ unpackUnsupportedData, /* AUDIO_FOCUS_DIRECTION */
+#endif
+ unpackUnsupportedData, /* PI_LATENCY */
+ unpackUnsupportedData, /* R_ISM_ID */
+ unpackUnsupportedData, /* R_ISM_GAIN */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ unpackOrientation, /* R_ISM_ORIENTATION */
+#else
+ unpackUnsupportedData, /* R_ISM_ORIENTATION */
+#endif
+ unpackUnsupportedData, /* R_ISM_POSITION */
+ unpackUnsupportedData, /* R_ISM_DIRECTION */
+ unpackUnsupportedData, /* RESERVED27 */
+ unpackUnsupportedData, /* RESERVED28 */
+ unpackUnsupportedData, /* RESERVED29 */
+ unpackUnsupportedData, /* RESERVED30 */
+ unpackNoPiData /* NO_DATA */
+};
+
+static const uint32_t maxPiDataSize[IVAS_PI_MAX_ID] = {
+ 8, /* IVAS_PI_SCENE_ORIENTATION */
+ 8, /* IVAS_PI_DEVICE_ORIENTATION_COMPENSATED */
+ 8, /* IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED */
+ 8, /* IVAS_PI_ACOUSTIC_ENVIRONMENT */
+ 5, /* IVAS_PI_AUDIO_DESCRIPTION */
+ 1, /* IVAS_PI_ISM_NUM */
+ 4, /* IVAS_PI_ISM_ID */
+ 4, /* IVAS_PI_ISM_GAIN */
+ 32, /* IVAS_PI_ISM_ORIENTATION */
+ 24, /* IVAS_PI_ISM_POSITION */
+ 12, /* IVAS_PI_ISM_DISTANCE_ATTENUATION */
+ 8, /* IVAS_PI_ISM_DIRECTIVITY */
+ 1, /* IVAS_PI_DIEGETIC_TYPE */
+ 0, /* IVAS_PI_RESERVED13 */
+ 9, /* IVAS_PI_AUDIO_FOCUS_INDICATION */
+ 0, /* IVAS_PI_RESERVED15 */
+ 8, /* IVAS_PI_PLAYBACK_DEVICE_ORIENTATION */
+ 8, /* IVAS_PI_HEAD_ORIENTATION */
+ 6, /* IVAS_PI_LISTENER_POSITION */
+ 2, /* IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION */
+ 9, /* IVAS_PI_AUDIO_FOCUS_REQUEST */
+ 4, /* IVAS_PI_PI_LATENCY */
+ 1, /* IVAS_PI_R_ISM_ID */
+ 1, /* IVAS_PI_R_ISM_GAIN */
+ 8, /* IVAS_PI_R_ISM_ORIENTATION */
+ 6, /* IVAS_PI_R_ISM_POSITION */
+ 2, /* IVAS_PI_R_ISM_DIRECTION */
+ 0, /* IVAS_PI_RESERVED27 */
+ 0, /* IVAS_PI_RESERVED28 */
+ 0, /* IVAS_PI_RESERVED29 */
+ 0, /* IVAS_PI_RESERVED30 */
+ 0, /* IVAS_PI_NO_DATA = 31 */
+};
+
+ivas_error PI_PackData( const IVAS_PIDATA_GENERIC *piData, PIDATA_PACKED *packed, uint8_t pmBits )
+{
+ uint32_t type = (IVAS_PI_TYPE) ( piData->piDataType & MASK_5BIT );
+ ivas_error error = packPiDataFuntions[type]( piData, packed->data, sizeof( packed->data ), &packed->size );
+ if ( error == IVAS_ERR_OK )
+ {
+ packed->data[0] |= pmBits; /* Update the PM bits */
+ }
+ assert( packed->size != 0 );
+ return error;
+}
+
+ivas_error PI_UnPackData( uint8_t piDataType, uint32_t piSize, const uint8_t *piDataBuffer, IVAS_PIDATA_GENERIC *piData )
+{
+ ivas_error error;
+
+ /* Sanitize maximum sizes for each PI Type */
+ if ( piSize > maxPiDataSize[piDataType] )
+ {
+ return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Max size for PI Data type exceeded" );
+ }
+
+ error = unpackPiDataFuntions[piDataType]( piDataBuffer, piSize, piData );
+ ERR_CHECK_RETURN( error );
+
+ /* since some pi data share piData structure, pi id are re-filled after unpacking */
+ piData->piDataType = piDataType;
+
+ return IVAS_ERR_OK;
+}
+
+/* PIDATA Tables */
+const float mapRT60[1u << NBITS_RT60] = {
+ 0.01f, 0.0126f, 0.0159f, 0.02f, 0.0252f, 0.0317f, 0.04f, 0.0504f,
+ 0.0635f, 0.08f, 0.1008f, 0.1270f, 0.16f, 0.2016f, 0.2540f, 0.32f,
+ 0.4032f, 0.5080f, 0.64f, 0.8063f, 1.0159f, 1.28f, 1.6127f, 2.0319f,
+ 2.56f, 3.2254f, 4.0637f, 5.12f, 6.4508f, 8.1275f, 10.24f, 12.9016f
+};
+
+const float mapDSR[1u << NBITS_DSR] = {
+ -20.f, -21.f, -22.f, -23.f, -24.f, -25.f, -26.f, -27.f,
+ -28.f, -29.f, -30.f, -31.f, -32.f, -33.f, -34.f, -35.f,
+ -36.f, -37.f, -38.f, -39.f, -40.f, -41.f, -42.f, -43.f,
+ -44.f, -45.f, -46.f, -47.f, -48.f, -49.f, -50.f, -51.f,
+ -52.f, -53.f, -54.f, -55.f, -56.f, -57.f, -58.f, -59.f,
+ -60.f, -61.f, -62.f, -63.f, -64.f, -65.f, -66.f, -67.f,
+ -68.f, -69.f, -70.f, -71.f, -72.f, -73.f, -74.f, -75.f,
+ -76.f, -77.f, -78.f, -79.f, -80.f, -81.f, -82.f, -83.f
+};
+
+const float mapRoomDims[1u << NBITS_DIM] = {
+ 0.5f, 0.707f, 1.f, 1.4141f, 2, 2.8282f, 4.f, 5.6568f,
+ 8.f, 11.314f, 16.f, 22.627f, 32.f, 45.255f, 64.f, 90.51f
+};
+
+const float mapAbsorbtion[1u << NBITS_ABS] = {
+ 0.0800f, 0.1656f, 0.3430f, 0.7101f
+};
+
+
+#endif /* IVAS_RTPDUMP */
diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fc95f8d8db2fc7211c2685c78e9a9b61a2797f6
--- /dev/null
+++ b/lib_util/ivas_rtp_pi_data.h
@@ -0,0 +1,471 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef IVAS_RTP_PI_DATA_H
+#define IVAS_RTP_PI_DATA_H
+
+#include "common_api_types.h"
+
+#ifdef IVAS_RTPDUMP
+
+#define IVAS_PI_MAX_DATA_SIZE ( 32 + 2 ) /* max packed PI data bytes + pi header bytes */
+
+/* IVAS PI Data Types */
+typedef enum
+{
+ /* Forward direction PI types */
+ IVAS_PI_SCENE_ORIENTATION, /* orientation of audio scene in unit quaternions */
+ IVAS_PI_DEVICE_ORIENTATION_COMPENSATED, /* orientation of device in unit quaternions (compensated) */
+ IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED, /* orientation of device in unit quaternions (un-compensated) */
+ IVAS_PI_ACOUSTIC_ENVIRONMENT, /* describe the acoustic environment */
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_PI_AUDIO_DESCRIPTION, /* audio content description (voice/music/ambiance) */
+ IVAS_PI_ISM_NUM, /* Number of objects */
+ IVAS_PI_ISM_ID, /* id of each object */
+ IVAS_PI_ISM_GAIN, /* gain of each object */
+ IVAS_PI_ISM_ORIENTATION, /* orientation of each object */
+ IVAS_PI_ISM_POSITION, /* position of each object */
+ IVAS_PI_ISM_DISTANCE_ATTENUATION, /* distance attenuation for each object */
+ IVAS_PI_ISM_DIRECTIVITY, /* directivity of each object */
+ IVAS_PI_DIEGETIC_TYPE, /* digetic audio indication */
+ IVAS_PI_RESERVED13, /* reserved */
+ IVAS_PI_AUDIO_FOCUS_INDICATION, /* audio focus indication (direction in Quaternions and/or level) */
+ IVAS_PI_RESERVED15, /* reserved */
+
+ /* Reverse direction PI types */
+ IVAS_PI_PLAYBACK_DEVICE_ORIENTATION, /* orientation of the playback device in quaternions */
+ IVAS_PI_HEAD_ORIENTATION, /* head orientation of the listener in Quaternions */
+ IVAS_PI_LISTENER_POSITION, /* position of the listener in 3D space */
+ IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION, /* receiver’s preference with respect to audio suppression */
+ IVAS_PI_AUDIO_FOCUS_REQUEST, /* direction of interest for the listener in Quaternions and/or audio focus level */
+ IVAS_PI_PI_LATENCY, /* round-trip latency for PI frames */
+ IVAS_PI_R_ISM_ID, /* id of an object for editing */
+ IVAS_PI_R_ISM_GAIN, /* editing request for gain factor for received object */
+ IVAS_PI_R_ISM_ORIENTATION, /* editing request for orientation for received object */
+ IVAS_PI_R_ISM_POSITION, /* editing request for position for received object */
+ IVAS_PI_R_ISM_DIRECTION, /* editing request for direction for received object */
+ IVAS_PI_RESERVED27, /* reserved */
+ IVAS_PI_RESERVED28, /* reserved */
+ IVAS_PI_RESERVED29, /* reserved */
+ IVAS_PI_RESERVED30, /* reserved */
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ IVAS_PI_NO_DATA = 31, /* Indicates an empty PI data frame */
+ IVAS_PI_MAX_ID /* Max number of PI data IDs supprted */
+} IVAS_PI_TYPE;
+
+/* cartesian coordinates (X,Y,Z) in 3D space */
+typedef struct
+{
+ float x, y, z;
+} IVAS_COORDINATE;
+
+/* orientation data corresponding to any of the following pi data types :-
+ * - IVAS_PI_SCENE_ORIENTATION
+ * - IVAS_PI_DEVICE_ORIENTATION_COMPENSATED
+ * - IVAS_PI_DEVICE_ORIENTATION_UNCOMPENSATED
+ * - IVAS_PI_PLAYBACK_DEVICE_ORIENTATION
+ * - IVAS_PI_HEAD_ORIENTATION
+ * - IVAS_PI_R_ISM_ORIENTATION
+ *
+ * piDataType is used to identify the correct pi data type contained here
+ */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_SCENE_ORIENTATION) */
+ uint32_t piDataType; /* one of supported orientation data types */
+ IVAS_QUATERNION orientation; /* orientation data expressed as quartenions */
+} IVAS_PIDATA_ORIENTATION;
+
+/* Acoustic environment corresponding to IVAS_PI_ACOUSTIC_ENVIRONMENT
+ *
+ * acoustic environment ID
+ * late reverb parameters
+ * - RT60 – indicating the time that it takes for the reflections to reduce 60 dB in energy level, per frequency band
+ * - DSR – diffuse to source signal energy ratio, per frequency band
+ * - Pre-delay – delay at which the computation of DSR values was performed
+ * early reflections
+ * - 3D rectangular virtual room dimensions
+ * - Broadband energy absorption coefficient per wall surface
+ */
+typedef enum
+{
+ IVAS_PI_AE_LOW, /* center frequency 25 Hz */
+ IVAS_PI_AE_MID, /* center frequency 250 Hz */
+ IVAS_PI_AE_HIGH, /* center frequency 2.5 kHz */
+ IVAS_PI_AE_NUM_BANDS /* number of ae bands */
+} IVAS_PI_AE_BANDS;
+
+typedef enum
+{
+ IVAS_PI_AE_FRONT,
+ IVAS_PI_AE_BACK,
+ IVAS_PI_AE_LEFT,
+ IVAS_PI_AE_RIGHT,
+ IVAS_PI_AE_CEILING,
+ IVAS_PI_AE_FLOOR,
+ IVAS_PI_AE_NUM_SURFACE
+} IVAS_PI_AE_SURFACE;
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ACOUSTIC_ENV) */
+ uint32_t piDataType; /* IVAS_PI_ACOUSTIC_ENVIRONMENT */
+ bool availLateReverb; /* AE contains only late reverb parameters */
+ bool availEarlyReflections; /* AE containing late reverb and simplified early reflections */
+ uint8_t aeid; /* seven-bit acoustic environment identifier */
+
+ /* only valid if availLateReverb==true or availEarlyReflections==true */
+ float rt60[IVAS_PI_AE_NUM_BANDS]; /* time for the reflections to reduce 60 dB per band in seconds */
+ float dsr[IVAS_PI_AE_NUM_BANDS]; /* diffuse to source signal energy ratio per band in dB */
+
+ /* only valid if availEarlyReflections==true */
+ IVAS_COORDINATE roomDimensions; /* room dimensions in meters length (x), width (y), height (z) */
+ float absorbCoeffs[IVAS_PI_AE_NUM_SURFACE]; /* absorption coefficients for all surfaces */
+} IVAS_PIDATA_ACOUSTIC_ENV;
+
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+/* Audio Description corresponding to IVAS_PI_AUDIO_DESCRIPTION
+ * Describe the following audio decriptors per object/type :-
+ * - audio content type is speech/music/ambiance
+ * - if audio rendering is editable
+ * - if stereo audio is binaural
+ *
+ * number of valid entries decide on basis of audio format:-
+ * - Stereo/SBA/MASA = 1 entry
+ * - MultiChannel = 2 entries (1 for center channel + 1 for all other channels)
+ * - ISM = Number of Object entries ( 1 per object )
+ * - OMASA/OSBA = 1 + Num Discrete Coded Objects
+ *
+ */
+typedef struct
+{
+ bool speech; /* audio has voice/speech */
+ bool music; /* audio has music */
+ bool ambiance; /* audio has background ambiance */
+ bool editable; /* rendering audio metadata is editable */
+ bool binaural; /* stereo stream is binaural */
+} IVAS_AUDIO_ID;
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_AUDIO_DESC) */
+ uint32_t piDataType; /* IVAS_PI_AUDIO_DESCRIPTION */
+ uint32_t nValidEntries; /* Number of valid audio IDs */
+ IVAS_AUDIO_ID audioId[1 + IVAS_MAX_NUM_OBJECTS]; /* audio id as per format */
+} IVAS_PIDATA_AUDIO_DESC;
+
+/* ISM specific PI data related to PI types : -
+ *
+ * - IVAS_PI_ISM_NUM
+ * - IVAS_PI_ISM_ID
+ * - IVAS_PI_ISM_GAIN
+ * - IVAS_PI_ISM_ORIENTATION
+ * - IVAS_PI_ISM_POSITION
+ * - IVAS_PI_ISM_DISTANCE_ATTENUATION
+ * - IVAS_PI_ISM_DIRECTIVITY
+ */
+
+/* Number of ISMs */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_NUM) */
+ uint32_t piDataType; /* IVAS_PI_ISM_NUM */
+ uint32_t numObjects; /* Number of ISM */
+} IVAS_PIDATA_ISM_NUM;
+
+/* ISM ID */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_ID) */
+ uint32_t piDataType; /* IVAS_PI_ISM_ID */
+ uint8_t id[IVAS_MAX_NUM_OBJECTS]; /* 8-bit ISM id of object */
+} IVAS_PIDATA_ISM_ID;
+
+/* ISM gain */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_GAIN) */
+ uint32_t piDataType; /* IVAS_PI_ISM_GAIN */
+ int8_t dB[IVAS_MAX_NUM_OBJECTS]; /* ISM gain in dB per object [-96, +3] */
+} IVAS_PIDATA_ISM_GAIN;
+
+/* ISM orientation */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_ORIENTATION) */
+ uint32_t piDataType; /* IVAS_PI_ISM_ORIENTATION */
+ IVAS_QUATERNION orientation[IVAS_MAX_NUM_OBJECTS]; /* Orientation of audio objects in ISM(s) */
+} IVAS_PIDATA_ISM_ORIENTATION;
+
+/* ISM position */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_POSITION) */
+ uint32_t piDataType; /* IVAS_PI_ISM_POSITION */
+ IVAS_COORDINATE position[IVAS_MAX_NUM_OBJECTS]; /* Position of audio objects in ISM(s) */
+} IVAS_PIDATA_ISM_POSITION;
+
+/* ISM distance attenuation comprising of following gains per ISM
+ * - reference distance
+ * - maximum distance
+ * - roll-off factor
+ */
+typedef struct
+{
+ float ref_dist; /* reference distance in meters */
+ float max_dist; /* maximum distance in meters */
+ float roll; /* roll-off factor values */
+} IVAS_DIST_ATTEN;
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_ATTENUATION) */
+ uint32_t piDataType; /* IVAS_PI_ISM_DISTANCE_ATTENUATION */
+ IVAS_DIST_ATTEN distAtten[IVAS_MAX_NUM_OBJECTS]; /* Distance attenuation of audio objects */
+} IVAS_PIDATA_ISM_ATTENUATION;
+
+/* ISM Directivity comprising of following per ISM :-
+ * - inner cone angle determines the size of the main cone directed to the front of the object
+ * - outer cone angle determines the size of the outer (back) cone
+ * - outer attenuation gain determines the attenuation outside the outer cone
+ */
+typedef struct
+{
+ uint16_t innerConeAngle; /* inner cone angle in degrees (0 - 360) */
+ uint16_t outerConeAngle; /* outer cone angle in degrees (0 - 360) */
+ float outerAttenuationdB; /* attenuation outside the outer cone in dB */
+} IVAS_ISM_DIRECTIVITY;
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_DIRECTIVITY) */
+ uint32_t piDataType; /* IVAS_PI_ISM_DIRECTIVITY */
+ IVAS_ISM_DIRECTIVITY directivity[IVAS_MAX_NUM_OBJECTS]; /* Directivity of audio objects */
+} IVAS_PIDATA_ISM_DIRECTIVITY;
+
+/* Diegetic and non-diegetic indication flag as per audio format
+ *
+ * number of valid entries decided on basis of audio format:-
+ * - Stereo/SBA/MASA/MultiChannel = 1 entry
+ * - ISM = Number of Object entries ( 1 per object )
+ * - OMASA/OSBA = 1 (last) + Num Discrete Coded Objects
+ */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_DIEGETIC) */
+ uint32_t piDataType; /* IVAS_PI_DIEGETIC_TYPE */
+ bool isDiegetic[1 + IVAS_MAX_NUM_OBJECTS]; /* diegetic indication as per audio format */
+} IVAS_PIDATA_DIEGETIC;
+
+/* Audio focus direction indicates a direction of interest.
+ * The audio focus level indicates the amount of suppression applied to the
+ * directions other than the audio focus direction.
+ */
+typedef enum
+{
+ IVAS_FLVL_NO_AUDIO_FOCUS = 0, /* Apply no audio focus */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_1, /* Audio focus level 1 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_2, /* Audio focus level 2 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_3, /* Audio focus level 3 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_4, /* Audio focus level 4 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_5, /* Audio focus level 5 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_6, /* Audio focus level 6 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_7, /* Audio focus level 7 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_8, /* Audio focus level 8 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_9, /* Audio focus level 9 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_10, /* Audio focus level 10 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_11, /* Audio focus level 11 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_12, /* Audio focus level 12 */
+ IVAS_FLVL_FOCUS_LEVEL_LEVEL_13, /* Audio focus level 13 */
+ IVAS_FLVL_DEFAULT_AUDIO_FOCUS, /* Default audio focus */
+ IVAS_FLVL_MAX_AUDIO_FOCUS, /* Apply max audio focus */
+} IVAS_FLVL;
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_AUDIO_FOCUS) */
+ uint32_t piDataType; /* IVAS_PI_AUDIO_FOCUS_INDCATION or IVAS_PI_AUDIO_FOCUS_REQUEST */
+ bool availDirection; /* audio focus contains direction */
+ bool availLevel; /* audio focus contains level */
+ IVAS_QUATERNION direction; /* direction data expressed as quarternions */
+ IVAS_FLVL flvl; /* audio focus level */
+} IVAS_PIDATA_AUDIO_FOCUS;
+
+/* Listener position */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_LISTENER_POSITION) */
+ uint32_t piDataType; /* IVAS_PI_LISTENER_POSITION */
+ IVAS_COORDINATE position; /* Position of audio objects in ISM(s) */
+} IVAS_PIDATA_LISTENER_POSITION;
+
+
+/* Dynamic Audio Suppression describes receiver’s preference with respect to the
+ * type of audio content that should be enhanced and the amount of suppression to
+ * be applied to the background noise
+ */
+typedef enum
+{
+ IVAS_SLI_NO_SUPPRESSION = 0, /* Apply no suppression */
+ IVAS_SLI_SUPPRESSION_LEVEL_1, /* Suppression level 1 */
+ IVAS_SLI_SUPPRESSION_LEVEL_2, /* Suppression level 2 */
+ IVAS_SLI_SUPPRESSION_LEVEL_3, /* Suppression level 3 */
+ IVAS_SLI_SUPPRESSION_LEVEL_4, /* Suppression level 4 */
+ IVAS_SLI_SUPPRESSION_LEVEL_5, /* Suppression level 5 */
+ IVAS_SLI_SUPPRESSION_LEVEL_6, /* Suppression level 6 */
+ IVAS_SLI_SUPPRESSION_LEVEL_7, /* Suppression level 7 */
+ IVAS_SLI_SUPPRESSION_LEVEL_8, /* Suppression level 8 */
+ IVAS_SLI_SUPPRESSION_LEVEL_9, /* Suppression level 9 */
+ IVAS_SLI_SUPPRESSION_LEVEL_10, /* Suppression level 10 */
+ IVAS_SLI_SUPPRESSION_LEVEL_11, /* Suppression level 11 */
+ IVAS_SLI_SUPPRESSION_LEVEL_12, /* Suppression level 12 */
+ IVAS_SLI_SUPPRESSION_LEVEL_13, /* Suppression level 13 */
+ IVAS_SLI_SUPPRESSION_LEVEL_14, /* Suppression level 14 */
+ IVAS_SLI_MAX_SUPPRESSION, /* Apply max suppression */
+} IVAS_SLI;
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_DYNAMIC_SUPPRESSION) */
+ uint32_t piDataType; /* IVAS_PI_DYNAMIC_AUDIO_SUPPRESSION */
+ bool speech; /* receiver's preference is voice/speech */
+ bool music; /* receiver's preference is music */
+ bool ambiance; /* receiver's preference is background ambiance */
+ IVAS_SLI sli; /* suppression level indicator [0, 15] */
+} IVAS_PIDATA_DYNAMIC_SUPPRESSION;
+
+/* Reverse PI latency calculated as the elapsed time between the sent reverse PI data
+ * and received forward PI data. It is based on the receiving device experiencing the
+ * result of its sent data by receiving the corresponding data in forward direction as
+ * forward PI data
+ */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_REVERSE_PI_LATENCY) */
+ uint32_t piDataType; /* IVAS_PI_PI_LATENCY */
+ IVAS_PI_TYPE type; /* Reverse PI used for computation of Latency */
+ int32_t latency; /* Latency as 27-bit int on RTP Clock @ 16KHz */
+} IVAS_PIDATA_REVERSE_PI_LATENCY;
+
+/* ISM specific PI data editing requests */
+
+/* ISM ID in editing requests */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_ID) */
+ uint32_t piDataType; /* IVAS_PI_R_ISM_ID */
+ uint8_t id; /* 8-bit ISM id of object to edit */
+} IVAS_PIDATA_ISM_EDIT_ID;
+
+/* Editing request for ISM gain */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_GAIN) */
+ uint32_t piDataType; /* IVAS_PI_R_ISM_GAIN */
+ int8_t dB; /* Preferred ISM gain in dB [-96, +3] */
+} IVAS_PIDATA_ISM_EDIT_GAIN;
+
+/* Editing request for ISM orientation */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_ORIENTATION) */
+ uint32_t piDataType; /* IVAS_PI_R_ISM_ORIENTATION */
+ IVAS_QUATERNION orientation; /* orientation editing request for received ISM */
+} IVAS_PIDATA_ISM_EDIT_ORIENTATION;
+
+/* Editing request for ISM position */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_POSITION) */
+ uint32_t piDataType; /* IVAS_PI_R_ISM_POSITION */
+ IVAS_COORDINATE position; /* Positional editing request for received ISM */
+} IVAS_PIDATA_ISM_EDIT_POSITION;
+
+/* Editing request for ISM direction */
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_ISM_EDIT_DIRECTION) */
+ uint32_t piDataType; /* IVAS_PI_R_ISM_DIRECTION */
+ float azimuth; /* azimuth angle in degrees [-180, 180] */
+ float elevation; /* elevation angle in degrees [-90°, 90°] */
+} IVAS_PIDATA_ISM_EDIT_DIRECTION;
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+
+typedef struct
+{
+ size_t size; /* sizeof(IVAS_PIDATA_NO_DATA) */
+ uint32_t piDataType; /* IVAS_PI_NO_DATA */
+} IVAS_PIDATA_NO_DATA;
+
+
+typedef union
+{
+ IVAS_PIDATA_ORIENTATION scene;
+ IVAS_PIDATA_ORIENTATION deviceCompensated;
+ IVAS_PIDATA_ORIENTATION deviceUnCompensated;
+ IVAS_PIDATA_ACOUSTIC_ENV acousticEnv;
+#ifdef RTP_S4_251135_CR26253_0016_REV1
+ IVAS_PIDATA_AUDIO_DESC audioDesc;
+ IVAS_PIDATA_ISM_NUM ismNum;
+ IVAS_PIDATA_ISM_ID ismId;
+ IVAS_PIDATA_ISM_GAIN ismGain;
+ IVAS_PIDATA_ISM_ORIENTATION ismOrientation;
+ IVAS_PIDATA_ISM_POSITION ismPosition;
+ IVAS_PIDATA_ISM_ATTENUATION ismAttenuation;
+ IVAS_PIDATA_ISM_DIRECTIVITY ismDirectivity;
+ IVAS_PIDATA_DIEGETIC digeticIndicator;
+ IVAS_PIDATA_AUDIO_FOCUS focusIndication;
+
+ IVAS_PIDATA_ORIENTATION playbackOrientation;
+ IVAS_PIDATA_ORIENTATION headOrientation;
+ IVAS_PIDATA_LISTENER_POSITION listnerPosition;
+ IVAS_PIDATA_DYNAMIC_SUPPRESSION dynSuppression;
+ IVAS_PIDATA_AUDIO_FOCUS focusRequest;
+ IVAS_PIDATA_REVERSE_PI_LATENCY piLatency;
+ IVAS_PIDATA_ISM_EDIT_ID ismEditId;
+ IVAS_PIDATA_ISM_EDIT_GAIN ismEditGain;
+ IVAS_PIDATA_ISM_EDIT_ORIENTATION ismEditOrientation;
+ IVAS_PIDATA_ISM_EDIT_POSITION ismEditPosition;
+ IVAS_PIDATA_ISM_EDIT_DIRECTION ismEditDirection;
+#endif /* RTP_S4_251135_CR26253_0016_REV1 */
+ IVAS_PIDATA_NO_DATA noPiData;
+} PIDATA;
+
+typedef struct
+{
+ PIDATA data;
+ uint32_t timestamp;
+} PIDATA_TS;
+
+#endif /* IVAS_RTPDUMP */
+
+#endif /* IVAS_RTP_PI_DATA_H */
diff --git a/lib_util/mutex.h b/lib_util/mutex.h
new file mode 100644
index 0000000000000000000000000000000000000000..82094b61c823e909f22282f982413abe037489f6
--- /dev/null
+++ b/lib_util/mutex.h
@@ -0,0 +1,104 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+/*====================================================================================
+ EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
+ ====================================================================================*/
+
+#ifndef _MUTEX_H
+#define _MUTEX_H
+
+#if defined( __unix__ ) || defined( __linux__ ) || ( defined( __MACH__ ) && defined( __APPLE__ ) )
+#include
+typedef pthread_mutex_t mtx_t;
+#define _USE_POSIX ( 1 )
+#elif defined( _WIN32 ) || defined( _WIN64 )
+#include
+typedef CRITICAL_SECTION mtx_t;
+#define _USE_WIN ( 1 )
+#else
+typedef int mtx_t;
+#warning Mutex implementation to be defined for this platform here.
+#endif
+
+static __inline int mtx_init( mtx_t *mutex, int type )
+{
+ int err = 0;
+ (void) type;
+#ifdef _USE_POSIX
+ err = pthread_mutex_init( mutex, NULL );
+#elif defined( _USE_WIN )
+ InitializeCriticalSection( mutex );
+#else
+ (void) mutex;
+#endif
+ return err;
+}
+
+static __inline void mtx_destroy( mtx_t *mutex )
+{
+#if _USE_POSIX
+ pthread_mutex_destroy( mutex );
+#elif defined( _USE_WIN )
+ DeleteCriticalSection( mutex );
+#else
+ (void) mutex;
+#endif
+}
+
+static __inline int mtx_lock( mtx_t *mutex )
+{
+ int err = 0;
+#if _USE_POSIX
+ err = pthread_mutex_lock( mutex );
+#elif defined( _USE_WIN )
+ EnterCriticalSection( mutex );
+#else
+ (void) mutex;
+#endif
+ return err;
+}
+
+static __inline int mtx_unlock( mtx_t *mutex )
+{
+ int err = 0;
+#if _USE_POSIX
+ err = pthread_mutex_unlock( mutex );
+#elif defined( _USE_WIN )
+ LeaveCriticalSection( mutex );
+#else
+ (void) mutex;
+#endif
+ return err;
+}
+
+#endif /* _MUTEX_H */
diff --git a/lib_util/rtpdump.c b/lib_util/rtpdump.c
index 9b25633a9385f57d14922a659a9bfe932a5dd1d4..f89b36f82a686192ec0f843251a56bf23312dec1 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;
diff --git a/readme.txt b/readme.txt
index 8e471c429bb5a677a6671b17057ac8782e673a4f..54b602c99529e6fe8e3d6f797153023d32bcae91 100644
--- a/readme.txt
+++ b/readme.txt
@@ -249,6 +249,12 @@ EVS mono is default, for IVAS choose one of the following: -stereo, -ism, -sba,
-level level : Complexity level, level = (1, 2, 3), will be defined after characterisation.
Currently, all values default to level 3 (full functionality).
-q : Quiet mode, limit printouts to terminal, default is deactivated
+-rtpdump : RTPDump output, hf_only=1 by default. The encoder will packetize the
+ bitstream frames into TS26.253 Annex A IVAS RTP Payload Format packets and
+ writes those to the output file. In EVS mono operating mode, TS26.445 Annex A.2.2
+ EVS RTP Payload Format is used. Optional N represents number of frames per RTP packet
+-scene_orientation : Scene orientation trajectory file. Only used with rtpdump output.
+-device_orientation : Device orientation trajectory file. Only used with rtpdump output.
The usage of the "IVAS_dec" program is as follows:
@@ -274,9 +280,10 @@ Options:
--------
-VOIP : VoIP mode: RTP in G192
-VOIP_hf_only=0 : VoIP mode: EVS RTP Payload Format hf_only=0 in rtpdump
--VOIP_hf_only=1 : VoIP mode: EVS RTP Payload Format hf_only=1 in rtpdump
+-VOIP_hf_only=1 : VoIP mode: EVS or IVAS RTP Payload Format hf_only=1 in rtpdump
The decoder may read rtpdump files containing TS26.445 Annex A.2.2
- EVS RTP Payload Format. The SDP parameter hf_only is required.
+ EVS RTP Payload Format or rtpdump files containing TS26.253 Annex A
+ IVAS RTP Payload Format. The SDP parameter hf_only is required.
Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.
-Tracefile TF : VoIP mode: Generate trace file named TF. Requires -no_delay_cmp to
be enabled so that trace contents remain in sync with audio output.
diff --git a/scripts/config/self_test.prm b/scripts/config/self_test.prm
index 28254ed77c2bd2dddb7b0857cf728d187f83ba3a..496a23e70f1950321eea13cfe9f588cbe240c509 100644
--- a/scripts/config/self_test.prm
+++ b/scripts/config/self_test.prm
@@ -307,7 +307,6 @@ 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
-
// 1 ISM with metadata at 13.2 kbps, 48 kHz in, 48 kHz out, EXT out
../IVAS_cod -ism 1 testv/stvISM1.csv 13200 48 testv/stv1ISM48s.wav bit
../IVAS_dec EXT 48 bit testv/stv1ISM48s.wav_13200_48-48_EXT.tst
@@ -581,7 +580,6 @@ 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
-
// SBA at 13.2 kbps, 32kHz in, 32kHz out, HOA3 out, bandwidth switching
../IVAS_cod -max_band testv/ivas_bws_20fr_start_WB.txt -sba 3 13200 32 testv/stv3OA32c.wav bit
../IVAS_dec HOA3 32 bit testv/stv3OA32c.wav_SBA_13200_32-32_HOA3.tst
@@ -959,7 +957,6 @@ 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
-
// MASA 1dir 1TC at 13.2 kbps, 48kHz in, 48kHz out, BINAURAL out, bandwidth switching
../IVAS_cod -max_band testv/ivas_bws_20fr_start_SWB.txt -masa 1 testv/stv1MASA1TC48c.met 13200 48 testv/stv1MASA1TC48c.wav bit
../IVAS_dec BINAURAL 48 bit testv/stv1MASA1TC48c.wav_13200_48-48_BINAURAL.tst
@@ -1239,7 +1236,6 @@ 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
-
// Multi-channel 5_1 at 13.2 kbps, 48kHz in, 48kHz out
../IVAS_cod -mc 5_1 13200 48 testv/stv51MC48c.wav bit
../IVAS_dec 5_1 48 bit testv/stv51MC48c.wav_MC51_13200_48-48_5_1.tst
@@ -1562,7 +1558,6 @@ 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
-
// Stereo downmix to bit-exact EVS at 13200 kbps, 32kHz in, 32kHz out
../IVAS_cod -stereo_dmx_evs 13200 32 testv/stvST32c.wav bit
../IVAS_dec 32 bit testv/stvST32c.wav_StereoDmxEVS_13200_32-32.tst
@@ -1572,7 +1567,6 @@ 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
-
// EVS non-diegetic panning at 64 kbps, 48kHz in, 48kHz out, STEREO out
../IVAS_cod 64000 48 testv/stv48c.wav bit
../IVAS_dec -non_diegetic_pan -50 48 bit testv/stv48c.pcm_EVS_64000_48-48_STEREO_NON-DIEGETIC-PAN_-50.tst
@@ -1582,7 +1576,6 @@ 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
-
// 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
networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_0.dat bit netsimoutput tracefile_sim 2 0
@@ -1859,7 +1852,6 @@ 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
-
// OSBA FOA 1ISM at 32 kbps, 48kHz in, 48kHz out, BINAURAL out
../IVAS_cod -ism_sba 1 1 testv/stvISM1.csv 32000 48 testv/stvOSBA_1ISM_FOA48c.wav bit
../IVAS_dec BINAURAL 48 bit testv/stvOSBA_1ISM_FOA48c.wav_BINAURAL_32000_48-48.tst
@@ -2058,3 +2050,40 @@ 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 -no_delay_cmp -Tracefile tracefile_dec -VOIP BINAURAL 48 netsimoutput testv/stv4ISM48s.wav_sw_48-48_BINAURAL_OE_JBM5.tst
+
+
+// stereo bitrate switching from 13.2 kbps to 128 kbps, 48kHz in, 48kHz out, DTX on, EXT out, rtpdump
+../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
+
+// 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 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
+
+// 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 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
+
+// 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 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
+
+// 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 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
+
+// Stereo downmix to bit-exact EVS at 24400 kbps, 48kHz in, 48kHz out, rtpdump
+../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
+
+// EVS at 13.2 kbps, 48kHz in, 48kHz out, STEREO out, rtpdump
+../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
+
+// 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 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
+
+// OSBA 2ISM 2OA at bitrate switching 13.2 to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, rtpdump, PI data
+../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
diff --git a/tests/codec_be_on_mr_nonselection/test_param_file.py b/tests/codec_be_on_mr_nonselection/test_param_file.py
index d2acacd39eacbb6513f0e01b5804f1ac6990c659..0e0e082c63c144775292089637995384309e4caa 100644
--- a/tests/codec_be_on_mr_nonselection/test_param_file.py
+++ b/tests/codec_be_on_mr_nonselection/test_param_file.py
@@ -228,6 +228,9 @@ def test_param_file_tests(
):
enc_opts, dec_opts, sim_opts, eid_opts = param_file_test_dict[test_tag]
+ if "rtpdump" in test_tag:
+ pytest.xfail("Skip RTP tests for now")
+
run_test(
test_info,
props_to_record,