From 9f18ceba632a1df956faaa54472ffdecf3e1dfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20Toftg=C3=A5rd?= Date: Thu, 30 Oct 2025 10:59:19 +0100 Subject: [PATCH 1/2] Add reading and packing/unpacking of ISM PI data, under define ISM_PI_DATA. --- apps/decoder.c | 28 ++ lib_com/options.h | 1 + lib_util/ivas_rtp_internal.h | 9 + lib_util/ivas_rtp_pi_data.c | 616 ++++++++++++++++++++++++++++++++++- lib_util/ivas_rtp_pi_data.h | 1 - tests/rtp/ivasrtp.py | 184 ++++++++++- tests/rtp/test_rtp.py | 15 + 7 files changed, 826 insertions(+), 28 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index da0fdd2fbd..4bd2c802f5 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -226,6 +226,9 @@ static const char *PiDataNames[IVAS_PI_MAX_ID] = { static void IVAS_RTP_LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t nPiDataPresent ) { uint32_t timestamp = ~0u; +#ifdef ISM_PI_DATA + uint16_t n; +#endif if ( f_piDataOut == NULL || piData == NULL || nPiDataPresent == 0 ) { return; @@ -387,6 +390,30 @@ static void IVAS_RTP_LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t n fprintf( f_piDataOut, "{}" ); } break; +#ifdef ISM_PI_DATA + case IVAS_PI_ISM_ORIENTATION: + { + fprintf( f_piDataOut, "[\n" ); + for ( n = 0; n < cur->data.ismOrientation.size / 8; n++ ) + { + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"w\": %f,\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t},\n", + cur->data.ismOrientation.orientation[n].w, cur->data.ismOrientation.orientation[n].x, cur->data.ismOrientation.orientation[n].y, cur->data.ismOrientation.orientation[n].z ); + } + fprintf( f_piDataOut, "\t\t]" ); + } + break; + case IVAS_PI_ISM_NUM: + case IVAS_PI_ISM_ID: + case IVAS_PI_ISM_GAIN: + + 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: +#else case IVAS_PI_ISM_NUM: case IVAS_PI_ISM_ID: case IVAS_PI_ISM_GAIN: @@ -398,6 +425,7 @@ static void IVAS_RTP_LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t n case IVAS_PI_R_ISM_ID: case IVAS_PI_R_ISM_GAIN: case IVAS_PI_R_ISM_DIRECTION: +#endif #endif /* RTP_S4_251135_CR26253_0016_REV1 */ case IVAS_PI_NO_DATA: { diff --git a/lib_com/options.h b/lib_com/options.h index b1f5965027..988fe14dcf 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -160,6 +160,7 @@ #define RTP_S4_251135_CR26253_0016_REV1 /* RTP Pack/Unpack API corresponding to CR 26253 */ #define IVAS_RTPDUMP /* RTPDUMP writing and reading for IVAS payloads */ +#define ISM_PI_DATA /* Add reading and packing/unpacking of ISM PI data */ /* ################### Start BE switches ################################# */ /* only BE switches wrt selection floating point code */ diff --git a/lib_util/ivas_rtp_internal.h b/lib_util/ivas_rtp_internal.h index f3569ca031..59ba5b04b1 100644 --- a/lib_util/ivas_rtp_internal.h +++ b/lib_util/ivas_rtp_internal.h @@ -72,6 +72,15 @@ extern const float mapRT60[1u << NBITS_RT60]; extern const float mapRoomDims[1u << NBITS_DIM]; extern const float mapAbsorbtion[1u << NBITS_ABS]; +#ifdef ISM_PI_DATA +extern const int16_t ismGains[98]; +extern const float refDistances[64]; +extern const float maxDistances[65]; +extern const float rollOffFactors[41]; +extern const int16_t innerOuterAngles[25]; +extern const float outerAttenuations[32]; +#endif + enum IVAS_RTP_HEADER_BITS { diff --git a/lib_util/ivas_rtp_pi_data.c b/lib_util/ivas_rtp_pi_data.c index c939c4539c..3f2fa18463 100644 --- a/lib_util/ivas_rtp_pi_data.c +++ b/lib_util/ivas_rtp_pi_data.c @@ -156,6 +156,43 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error packISMOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ISM_ORIENTATION *orientation = (const IVAS_PIDATA_ISM_ORIENTATION *) piData; + uint16_t n; + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ISM_ORIENTATION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in Orientation PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_ORIENTATION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in Orientation PI data" ); + } + /* Orientation data is 8 bytes, header is 2 bytes */ + if ( maxDataBytes < 8 * IVAS_PI_MAX_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack Orientation PI data" ); + } + + buffer[nBytes++] = ( orientation->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) piData->size; + for ( n = 0; n < piData->size / 8; n++ ) + { + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].w ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].x ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].y ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( orientation->orientation[n].z ) ); + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} +#endif + static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) { IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData; @@ -175,6 +212,31 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error unpackISMOrientation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ISM_ORIENTATION *orientation = (IVAS_PIDATA_ISM_ORIENTATION *) piData; + + /* Orientation data is 8 bytes */ + uint16_t n; + if ( numDataBytes % 8 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); + } + + piData->size = numDataBytes; + for ( n = 0; n < numDataBytes / 8; n++ ) + { + orientation->orientation[n].w = FLOAT_FROM_Q15( readInt16( &buffer[8 * n] ) ); + orientation->orientation[n].x = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 2] ) ); + orientation->orientation[n].y = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 4] ) ); + orientation->orientation[n].z = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 6] ) ); + } + + return IVAS_ERR_OK; +} +#endif + static uint32_t getIndexTable( const float *table, uint32_t tableLength, float value ) { uint32_t idx = 0; @@ -195,6 +257,25 @@ static uint32_t getIndexTable( const float *table, uint32_t tableLength, float v #define GET_IDX( table, nBits, value ) getIndexTable( table, ( 1u << ( nBits ) ), ( value ) ) +static uint32_t getIndexTable_s( const int16_t *table, uint32_t tableLength, int16_t 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; +} + + static ivas_error packAcousticEnvironment( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { uint32_t nBytes = 0; @@ -480,6 +561,65 @@ static ivas_error unpackListenerPosition( const uint8_t *buffer, uint32_t numDat return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error packISMPosition( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_POSITION *listener = (const IVAS_PIDATA_ISM_POSITION *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ISM_POSITION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM POSITION PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_POSITION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM POSITION PI data" ); + } + + /* Position data is 6 bytes, header is 2 bytes */ + if ( maxDataBytes < 6 * IVAS_PI_MAX_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM POSITION PI data" ); + } + + buffer[nBytes++] = ( listener->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) piData->size; + for ( n = 0; n < piData->size / 6; n++ ) + { + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position[n].x / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position[n].y / MAX_PI_POSITION_METERS ) ); + nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( listener->position[n].z / MAX_PI_POSITION_METERS ) ); + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMPosition( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint16_t n; + IVAS_PIDATA_ISM_POSITION *listener = (IVAS_PIDATA_ISM_POSITION *) piData; + + /* Position data is 6 bytes */ + if ( numDataBytes % 6 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack LISTENER POSITION PI data" ); + } + + listener->size = sizeof( IVAS_PIDATA_ISM_POSITION ); + listener->piDataType = IVAS_PI_ISM_POSITION; + for ( n = 0; n < numDataBytes / 6; n++ ) + { + listener->position[n].x = FLOAT_FROM_Q15( readInt16( &buffer[6 * n] ) ) * MAX_PI_POSITION_METERS; + listener->position[n].y = FLOAT_FROM_Q15( readInt16( &buffer[6 * n + 2] ) ) * MAX_PI_POSITION_METERS; + listener->position[n].z = FLOAT_FROM_Q15( readInt16( &buffer[6 * n + 4] ) ) * MAX_PI_POSITION_METERS; + } + return IVAS_ERR_OK; +} +#endif + static ivas_error packDiegetic( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { uint32_t nBytes = 0, n; @@ -590,7 +730,7 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.y ) ); nBytes = writeInt16( buffer, nBytes, ivasPayload_convertToQ15( audioFocus->direction.z ) ); } - if ( packedSize == 9 || packedSize == 1) + if ( packedSize == 9 || packedSize == 1 ) { buffer[nBytes++] = ( (uint8_t) audioFocus->flvl & MASK_4BIT ) << 4; } @@ -632,6 +772,328 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat return IVAS_ERR_OK; } +#ifdef ISM_PI_DATA +static ivas_error packISMNum( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0; + const IVAS_PIDATA_ISM_NUM *ism_num = (const IVAS_PIDATA_ISM_NUM *) piData; + + *nBytesWritten = 0; + + if ( piData->size != sizeof( IVAS_PIDATA_ISM_NUM ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_NUM PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_NUM ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_NUM PI data" ); + } + + /* ISM_NUM data is 1 bytes, header is 2 bytes */ + if ( maxDataBytes < 1 + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_NUM PI data" ); + } + + buffer[nBytes++] = ( ism_num->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = 1; + buffer[nBytes++] = ( ism_num->numObjects - 1 ) & MASK_2BIT << 6; + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMNum( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + IVAS_PIDATA_ISM_NUM *ism_num = (IVAS_PIDATA_ISM_NUM *) piData; + uint8_t byte; + + /* ISM_NUM data is 1 bytes */ + if ( numDataBytes != 1 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_NUM PI data" ); + } + + ism_num->size = sizeof( IVAS_PIDATA_ISM_NUM ); + ism_num->piDataType = IVAS_PI_ISM_NUM; + + byte = buffer[0]; + ism_num->numObjects = ( ( byte >> 6 ) & MASK_2BIT ) + 1; + + return IVAS_ERR_OK; +} +static ivas_error packISMID( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_ID *ism_id = (const IVAS_PIDATA_ISM_ID *) piData; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_ID ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_ID PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_ID ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_ID PI data" ); + } + + /* ISM_ID data is 1 byte per object, header is 2 bytes */ + if ( maxDataBytes < 1 * IVAS_PI_MAX_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_NUM PI data" ); + } + + buffer[nBytes++] = ( ism_id->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) piData->size; + /* Pack ID for each object */ + for ( n = 0; n < piData->size; n++ ) + { + buffer[nBytes++] = ( ism_id->id[n] & MASK_8BIT ); + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMID( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n; + IVAS_PIDATA_ISM_ID *ism_id = (IVAS_PIDATA_ISM_ID *) piData; + + /* ISM_ID data is 1 byte per object */ + if ( numDataBytes > IVAS_PI_MAX_OBJECTS ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_ID PI data" ); + } + + ism_id->size = sizeof( IVAS_PIDATA_ISM_ID ); + ism_id->piDataType = IVAS_PI_ISM_ID; + + /* Unpack ID for each object (1 byte each) */ + for ( n = 0; n < numDataBytes; n++ ) + { + ism_id->id[n] = buffer[n]; + } + + return IVAS_ERR_OK; +} + +static ivas_error packISMGain( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n, idx; + int16_t gain; + const IVAS_PIDATA_ISM_GAIN *ism_gain = (const IVAS_PIDATA_ISM_GAIN *) piData; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_GAIN ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_GAIN PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_GAIN ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_GAIN PI data" ); + } + + /* ISM_GAIN data is 1 byte per object, header is 2 bytes */ + if ( maxDataBytes < 1 * IVAS_PI_MAX_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_GAIN PI data" ); + } + + buffer[nBytes++] = ( ism_gain->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) piData->size; + /* Pack ID for each object */ + for ( n = 0; n < piData->size; n++ ) + { + gain = (int16_t) ism_gain->dB[n]; + if ( gain >= 0 ) + { + idx = getIndexTable_s( ismGains, 4, gain ); + if ( idx > 0 ) + { + idx += 97; + } + } + else + { + idx = getIndexTable_s( ismGains, 98, -gain ); + } + buffer[nBytes++] = ( idx & MASK_7BIT ) << 1; + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMGain( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n, idx; + IVAS_PIDATA_ISM_GAIN *ism_gain = (IVAS_PIDATA_ISM_GAIN *) piData; + + /* ISM_GAIN data is 1 byte per object */ + if ( numDataBytes > IVAS_PI_MAX_OBJECTS ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_GAIN PI data" ); + } + + ism_gain->size = sizeof( IVAS_PIDATA_ISM_GAIN ); + ism_gain->piDataType = IVAS_PI_ISM_GAIN; + + /* Unpack ID for each object (1 byte each) */ + for ( n = 0; n < numDataBytes; n++ ) + { + idx = ( buffer[n] ) >> 1; + if ( idx < 98 ) + { + ism_gain->dB[n] = (int8_t) -ismGains[idx]; + } + else + { + ism_gain->dB[n] = (int8_t) ismGains[idx]; + } + } + return IVAS_ERR_OK; +} + +static ivas_error packISMDistanceAttenuation( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_ATTENUATION *ism_att = (const IVAS_PIDATA_ISM_ATTENUATION *) piData; + uint32_t lWord; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_ATTENUATION ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_DISTANCE_ATTENUATION PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_DISTANCE_ATTENUATION ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_DISTANCE_ATTENUATION PI data" ); + } + + /* ISM_DISTANCE_ATTENUATION data is 3 bytes per object, header is 2 bytes */ + if ( maxDataBytes > 3 * IVAS_PI_MAX_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_DISTANCE_ATTENUATION PI data" ); + } + + buffer[nBytes++] = ( ism_att->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) piData->size; + /* Pack ID for each object */ + for ( n = 0; n < piData->size; n++ ) + { + lWord = (uint32_t) ( getIndexTable( refDistances, 64, ism_att->distAtten[n].ref_dist ) << 18 ); + lWord |= (uint32_t) ( getIndexTable( maxDistances, 65, ism_att->distAtten[n].max_dist ) << 12 ); + lWord |= (uint32_t) ( getIndexTable( rollOffFactors, 41, ism_att->distAtten[n].roll ) << 6 ); + + buffer[nBytes++] = ( lWord >> 16 ) & MASK_8BIT; + buffer[nBytes++] = ( lWord >> 8 ) & MASK_8BIT; + buffer[nBytes++] = lWord & MASK_8BIT; + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMDistanceAttenuation( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n, lWord; + IVAS_PIDATA_ISM_ATTENUATION *ism_att = (IVAS_PIDATA_ISM_ATTENUATION *) piData; + + /* ISM_DISTANCE_ATTENUATION data is 3 bytes per object */ + if ( numDataBytes % 3 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_DISTANCE_ATTENUATION PI data" ); + } + + ism_att->size = sizeof( IVAS_PIDATA_ISM_ATTENUATION ); + ism_att->piDataType = IVAS_PI_ISM_DISTANCE_ATTENUATION; + + /* Unpack attenuation for each object (3 bytes each) */ + for ( n = 0; n < numDataBytes / 3; n++ ) + { + lWord = ( buffer[3 * n] ) << 16; + lWord = ( buffer[3 * n + 1] ) << 8; + lWord = buffer[3 * n + 2]; + + ism_att->distAtten[n].ref_dist = refDistances[( lWord >> 18 ) & MASK_6BIT]; + ism_att->distAtten[n].max_dist = maxDistances[( lWord >> 12 ) & MASK_6BIT]; + ism_att->distAtten[n].roll = rollOffFactors[( lWord >> 6 ) & MASK_6BIT]; + } + return IVAS_ERR_OK; +} +static ivas_error packISMDirectivity( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) +{ + uint32_t nBytes = 0, n; + const IVAS_PIDATA_ISM_DIRECTIVITY *ism_directivity = (const IVAS_PIDATA_ISM_DIRECTIVITY *) piData; + uint16_t word; + + *nBytesWritten = 0; + + if ( piData->size > sizeof( IVAS_PIDATA_ISM_DIRECTIVITY ) ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect size in ISM_DIRECTIVITY PI data" ); + } + + if ( piData->piDataType != IVAS_PI_ISM_DIRECTIVITY ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Incorrect PI ID in ISM_DIRECTIVITY PI data" ); + } + + /* ISM_DIRECTIVITY data is 2 bytes per object, header is 2 bytes */ + if ( maxDataBytes > 2 * IVAS_PI_MAX_OBJECTS + 2 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_INSUFFICIENT_OUTPUT_SIZE, "Insufficient space to pack ISM_DIRECTIVITY PI data" ); + } + + buffer[nBytes++] = ( ism_directivity->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ + buffer[nBytes++] = (uint8_t) piData->size; + /* Pack ID for each object */ + for ( n = 0; n < piData->size; n++ ) + { + word = (uint16_t) ( getIndexTable_s( innerOuterAngles, 25, ism_directivity->directivity[n].innerConeAngle ) << 11 ); + word |= (uint16_t) ( getIndexTable_s( innerOuterAngles, 25, ism_directivity->directivity[n].outerConeAngle ) << 6 ); + word |= (uint16_t) ( getIndexTable( outerAttenuations, 32, ism_directivity->directivity[n].outerAttenuationdB ) << 1 ); + + buffer[nBytes++] = ( word >> 8 ) & MASK_8BIT; + buffer[nBytes++] = word & MASK_8BIT; + } + *nBytesWritten = nBytes; + return IVAS_ERR_OK; +} + +static ivas_error unpackISMDirectivity( const uint8_t *buffer, uint32_t numDataBytes, IVAS_PIDATA_GENERIC *piData ) +{ + uint32_t n; + uint16_t word; + IVAS_PIDATA_ISM_DIRECTIVITY *ism_directivity = (IVAS_PIDATA_ISM_DIRECTIVITY *) piData; + + /* ISM_DIRECTIVITY data is 2 bytes per object */ + if ( numDataBytes % 2 != 0 ) + { + return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack ISM_DIRECTIVITY PI data" ); + } + + ism_directivity->size = sizeof( IVAS_PIDATA_ISM_DIRECTIVITY ); + ism_directivity->piDataType = IVAS_PI_ISM_DIRECTIVITY; + + /* Unpack attenuation for each object (3 bytes each) */ + for ( n = 0; n < numDataBytes / 2; n++ ) + { + word = ( buffer[3 * n] ) << 16; + word = ( buffer[3 * n + 1] ) << 8; + word = buffer[3 * n + 2]; + + ism_directivity->directivity[n].innerConeAngle = innerOuterAngles[( word >> 11 ) & MASK_5BIT]; + ism_directivity->directivity[n].outerConeAngle = innerOuterAngles[( word >> 6 ) & MASK_5BIT]; + ism_directivity->directivity[n].outerAttenuationdB = outerAttenuations[( word >> 1 ) & MASK_5BIT]; + } + return IVAS_ERR_OK; +} +#endif #endif /* RTP_S4_251135_CR26253_0016_REV1 */ @@ -645,14 +1107,24 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { 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 */ +#endif /* RTP_S4_251135_CR26253_0016_REV1 */ +#ifdef ISM_PI_DATA + packISMNum, /* ISM_NUM */ + packISMID, /* ISM_ID */ + packISMGain, /* ISM_GAIN */ + packISMOrientation, /* ISM_ORIENTATION */ + packISMPosition, /* ISM_POSITION */ + packISMDistanceAttenuation, /* ISM_DISTANCE_ATTENUATION */ + packISMDirectivity, /* ISM_DIRECTIVITY */ +#else + packUnsupportedData, /* ISM_NUM */ + packUnsupportedData, /* ISM_ID */ + packUnsupportedData, /* ISM_GAIN */ + packUnsupportedData, /* ISM_ORIENTATION */ + packUnsupportedData, /* ISM_POSITION */ + packUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ + packUnsupportedData, /* ISM_DIRECTIVITY */ +#endif #ifdef RTP_S4_251135_CR26253_0016_REV1 packDiegetic, /* DIEGETIC_TYPE */ #else @@ -660,9 +1132,9 @@ static const PACK_PI_FN packPiDataFuntions[IVAS_PI_MAX_ID] = { #endif packUnsupportedData, /* RESERVED13 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - packAudioFocusCommon,/* AUDIO_FOCUS_INDICATION */ + packAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ #else - packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ + packUnsupportedData, /* AUDIO_FOCUS_INDICATION */ #endif packUnsupportedData, /* RESERVED15 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 @@ -705,6 +1177,15 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #else unpackUnsupportedData, /* AUDIO_DESCRIPTION */ #endif +#ifdef ISM_PI_DATA + unpackISMNum, /* ISM_NUM */ + unpackISMID, /* ISM_ID */ + unpackISMGain, /* ISM_GAIN */ + unpackISMOrientation, /* ISM_ORIENTATION */ + unpackISMPosition, /* ISM_POSITION */ + unpackISMDistanceAttenuation, /* ISM_DISTANCE_ATTENUATION */ + unpackISMDirectivity, /* ISM_DIRECTIVITY */ +#else unpackUnsupportedData, /* ISM_NUM */ unpackUnsupportedData, /* ISM_ID */ unpackUnsupportedData, /* ISM_GAIN */ @@ -712,6 +1193,7 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { unpackUnsupportedData, /* ISM_POSITION */ unpackUnsupportedData, /* ISM_DISTANCE_ATTENUATION */ unpackUnsupportedData, /* ISM_DIRECTIVITY */ +#endif #ifdef RTP_S4_251135_CR26253_0016_REV1 unpackDiegetic, /* DIEGETIC_TYPE */ #else @@ -719,7 +1201,7 @@ static const UNPACK_PI_FN unpackPiDataFuntions[IVAS_PI_MAX_ID] = { #endif unpackUnsupportedData, /* RESERVED13 */ #ifdef RTP_S4_251135_CR26253_0016_REV1 - unpackAudioFocusCommon,/* AUDIO_FOCUS_INDICATION */ + unpackAudioFocusCommon, /* AUDIO_FOCUS_INDICATION */ #else unpackUnsupportedData, /* AUDIO_FOCUS_INDICATION */ #endif @@ -848,5 +1330,115 @@ const float mapAbsorbtion[1u << NBITS_ABS] = { 0.0800f, 0.1656f, 0.3430f, 0.7101f }; +#ifdef ISM_PI_DATA +/* gains with negative values flipped to positive for the search */ +const int16_t ismGains[98] = { + 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 32767 +}; +// const float ismGains[98] = { +// 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, +// 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, +// 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, +// 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, +// 28.0f, 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f, +// 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, +// 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, +// 49.0f, 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, +// 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, +// 63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, +// 70.0f, 71.0f, 72.0f, 73.0f, 74.0f, 75.0f, 76.0f, +// 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f, 83.0f, +// 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f, +// 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, 96.0f, 32768.0f +// }; + +const float refDistances[64] = { + 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, + 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, + 1.7f, 1.8f, 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, + 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, + 3.3f, 3.4f, 3.5f, 3.6f, 3.7f, 3.8f, 3.9f, 4.0f, + 4.1f, 4.2f, 4.3f, 4.4f, 4.5f, 4.6f, 4.7f, 4.8f, + 4.9f, 5.0f, 5.1f, 5.2f, 5.3f, 5.4f, 5.5f, 5.6f, + 5.7f, 5.8f, 5.9f, 6.0f, 6.1f, 6.2f, 6.3f, 6.4f +}; + +// const int16_t maxDistances[65] = { +// 0, 1, 2, 3, 4, 5, +// 6, 7, 8, 9, 10, 11, +// 12, 13, 14, 15, 16, 17, +// 18, 19, 20, 21, 22, 23, +// 24, 25, 26, 27, 28, 29, +// 30, 31, 32, 33, 34, 35, +// 36, 37, 38, 39, 40, 41, +// 42, 43, 44, 45, 46, 47, +// 48, 49, 50, 51, 52, 53, +// 54, 55, 56, 57, 58, 59, +// 60, 61, 62, 63, 64 +// }; +const float maxDistances[65] = { + 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, + 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, + 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, + 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, + 30.0f, 31.0f, 32.0f, 33.0f, 34.0f, 35.0f, + 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, + 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, + 48.0f, 49.0f, 50.0f, 51.0f, 52.0f, 53.0f, + 54.0f, 55.0f, 56.0f, 57.0f, 58.0f, 59.0f, + 60.0f, 61.0f, 62.0f, 63.0f, 64.0f +}; + +const float rollOffFactors[41] = { + 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, + 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, + 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, + 1.8f, 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, + 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, + 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.5f, + 3.6f, 3.7f, 3.8f, 3.9f, 4.0f +}; +const int16_t innerOuterAngles[25] = { + 0, 15, 30, 45, 60, + 75, 90, 105, 120, 135, + 150, 165, 180, 195, 210, + 225, 240, 255, 270, 285, + 300, 315, 330, 345, 360 +}; +// const float innerOuterAngles[25] = { +// 0.0f, 15.0f, 30.0f, 45.0f, 60.0f, +// 75.0f, 90.0f, 105.0f, 120.0f, 135.0f, +// 150.0f, 165.0f, 180.0f, 195.0f, 210.0f, +// 225.0f, 240.0f, 255.0f, 270.0f, 285.0f, +// 300.0f, 315.0f, 330.0f, 345.0f, 360.0f +// }; +// const int16_t outerAttenuations[32] = { +// -32768, -90, -87, -84, -81, -78, -75, -72, +// -69, -66, -63, -60, -57, -54, -51, -48, +// -45, -42, -39, -36, -33, -30, -27, -24, +// -21, -18, -15, -12, -9, -6, -3, 0 +//}; + +const float outerAttenuations[32] = { + -32768.0f, -90.0f, -87.0f, -84.0f, -81.0f, -78.0f, -75.0f, -72.0f, + -69.0f, -66.0f, -63.0f, -60.0f, -57.0f, -54.0f, -51.0f, -48.0f, + -45.0f, -42.0f, -39.0f, -36.0f, -33.0f, -30.0f, -27.0f, -24.0f, + -21.0f, -18.0f, -15.0f, -12.0f, -9.0f, -6.0f, -3.0f, 0.0f +}; +#endif #endif /* IVAS_RTPDUMP */ diff --git a/lib_util/ivas_rtp_pi_data.h b/lib_util/ivas_rtp_pi_data.h index aad50dd6b6..1ea89aaf39 100644 --- a/lib_util/ivas_rtp_pi_data.h +++ b/lib_util/ivas_rtp_pi_data.h @@ -334,7 +334,6 @@ extern "C" 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 diff --git a/tests/rtp/ivasrtp.py b/tests/rtp/ivasrtp.py index 1eec45fdce..a7599a59be 100644 --- a/tests/rtp/ivasrtp.py +++ b/tests/rtp/ivasrtp.py @@ -43,6 +43,7 @@ import base64 import argparse from pathlib import Path from typing import cast, Optional +import numpy as np NO_REQ="NO_REQ" @@ -330,9 +331,6 @@ class POSITION: y: float = 0.0 z: float = 0.0 -class ISM_POSITIONS: - positions: list[POSITION] - @dataclass class AUDIO_DESCRIPTION: isSpeech: bool = False @@ -360,6 +358,46 @@ class ACOUSTIC_ENVIRONMENT: dim: tuple[float, float, float] = () abscoeff: tuple[float, float, float, float, float, float] = () +@dataclass +class ISM_NUM: + num: int = 1 + +@dataclass +class ISM_ID: + ids: list[int] + +@dataclass +class ISM_GAIN: + gains: list[int] + +@dataclass +class ISM_ORIENTATION: + orientations: list[ORIENTATION] + +@dataclass +class ISM_POSITION: + positions: list[POSITION] + +@dataclass +class DISTANCE_ATTENUATION: + ref_dist: float = 1.0 + max_dist: int = 10 + roll_off: float = 1.0 + +@dataclass +class ISM_DISTANCE_ATTENUATION: + distance_attenuations: list[DISTANCE_ATTENUATION] + +@dataclass +class DIRECTIVITY: + inner_ang: int = 360 + outer_ang: int = 0 + outer_att: int = 0 + +@dataclass +class ISM_DIRECTIVITY: + directivities: list[DIRECTIVITY] + @dataclass class AUDIO_FOCUS: direction: Optional[ORIENTATION] = None @@ -371,7 +409,7 @@ class PIDATA: type: str = "NO_PI_DATA" data: any = None -MAX_PACKED_PI_SIZE = 32 +MAX_PACKED_PI_SIZE = 64 ivasBitrates = [13200, 16400, 24400, 32000, 48000, 64000, 80000, 96000, 128000, 160000, 192000, 256000, 384000, 512000, -1, 5200] evsBitrates = [5900, 7200, 8000, 9600, 13200, 16400, 24400, 32000, 48000, 64000, 96000, 128000, 2400, -1, -1, -1] amrwbBitrates = [6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850, 1750, -1, -1, -1, -1, -1, -1] @@ -384,6 +422,12 @@ dsrValue = [ -20.0, -21.0, -22.0, -23.0, -24.0, -25.0, -26.0, -27.0, -28.0, -29. -74.0, -75.0, -76.0, -77.0, -78.0, -79.0, -80.0, -81.0, -82.0, -83.0 ] roomDimensionValue = [0.5, 0.707, 1.0, 1.4141, 2.0, 2.8282, 4.0, 5.6568, 8.0, 11.314, 16.0, 22.627, 32.0, 45.255, 64.0, 90.51] absorptionCoeffValues = [0.0800, 0.1656, 0.3430, 0.7101] +ismGains = list(range(0, -97, -1)) + [-float("inf")] + list(range(1, 4)) +refDistances = [round(x * 0.1, 1) for x in range(1, 65)] +maxDistances = list(range(1,65)) +rolloffFactors = [round(x * 0.1, 1) for x in range(0, 41)] +innerOuterAngles = list(range(0,361,15)) +outerAttenuations = [-float("inf")] + list(range(-90,1,3)) codedFormats = list(FORMATS) codedSubFormats = list(SUBFORMATS) PiTypeNames = list(PIDATAS) @@ -616,9 +660,119 @@ def packAudioFocus(bitstrm: BitStream, data: any): if auFocus.direction is not None: packOrientations(bitstrm, [auFocus.direction]) if auFocus.level is not None: - bitstrm.append(f'uint:4={auFocus.level}') + level = int(auFocus.level) + bitstrm.append(f'uint:4={level}') bitstrm.append(f'uint:4=0') +def unpackISMNum(bitstrm: ConstBitStream, piSize: int) -> ISM_NUM: + assert piSize == 1, "Incorrect PI Data Size for ISM_NUM" + numISM = bitstrm.read(2).uint + 1 + bitstrm.bytealign() + return ISM_NUM(num=numISM) + +def packISMNum(bitstrm: BitStream, data: any): + assert type(data) == ISM_NUM, "Data of type ISM_NUM is expected" + ism_num = cast(ISM_NUM, data) + assert ism_num.num <= 4, "Maximum 4 objects" + bitstrm.append(f'uint:2={ism_num.num-1}') + bitstrm.append(f'uint:6=0') + +def unpackISMID(bitstrm: ConstBitStream, piSize: int) -> ISM_ID: + assert piSize == 1 or piSize == 2 or piSize == 3 or piSize == 4, "Incorrect PI Data Size for ISM_ID" + IsmID = list() + for _ in range(piSize): + IsmID.append(bitstrm.read(8).uint+1) + return ISM_ID(ids=IsmID) + +def packISMID(bitstrm: BitStream, data: any): + assert type(data) == ISM_ID, "Data of type ISM_ID is expected" + ism_id = cast(ISM_ID, data) + assert len(ism_id.ids) <= 4, "Maximum 4 objects" + for id in ism_id.ids: + bitstrm.append(f'uint:8={id}') + +def unpackISMGain(bitstrm: ConstBitStream, piSize: int) -> ISM_GAIN: + assert piSize == 1 or piSize == 2 or piSize == 3 or piSize == 4, "Incorrect PI Data Size for ISM_GAIN" + IsmGain = list() + for _ in range(piSize): + IsmGain.append(bitstrm.read(7).uint) + bitstrm.bytealign() + return ISM_GAIN(gains=IsmGain) + +def packISMGain(bitstrm: BitStream, data: any): + assert type(data) == ISM_GAIN, "Data of type ISM_GAIN is expected" + ism_gain = cast(ISM_GAIN, data) + assert len(ism_gain.gains) <= 4, "Maximum 4 objects" + for gain in ism_gain.gains: + gain_idx = getListIndex(ismGains, gain) + bitstrm.append(f'uint:7={gain_idx}') + bitstrm.append(f'uint:1=0') + +def unpackISMDistanceAttenuation(bitstrm: ConstBitStream, piSize: int) -> ISM_DISTANCE_ATTENUATION: + ref_dist = None + max_dist = None + roll_off = None + assert piSize == 1*3 or piSize == 2*3 or piSize == 3*3 or piSize == 4*3, "Incorrect PI Data Size for ISM_DISTANCE_ATTENUATION" + ism_distance_attenutation = list() + for _ in range(piSize): + ref_dist = bitstrm.read(6).uint + max_dist = bitstrm.read(6).uint + roll_off = bitstrm.read(6).uint + ism_distance_attenutation.append(DISTANCE_ATTENUATION(ref_dist=ref_dist, max_dist=max_dist, roll_off=roll_off)) + bitstrm.bytealign() + return ISM_DISTANCE_ATTENUATION(distance_attenuations=ism_distance_attenutation) + +def packISMDistanceAttenuation(bitstrm: BitStream, data: any): + assert type(data) == list, "Data of type list is expected" + + for att in cast(list, data): + assert type(att) == DISTANCE_ATTENUATION, "Data of type list[DISTANCE_ATTENUATION] is expected" + ref_dist_idx = getListIndex(refDistances, att.ref_dist) + max_dist_idx = getListIndex(maxDistances, att.max_dist) + roll_off_idx = getListIndex(rolloffFactors, att.roll_off) + bitstrm.append(f'uint:6={ref_dist_idx}') + bitstrm.append(f'uint:6={max_dist_idx}') + bitstrm.append(f'uint:6={roll_off_idx}') + bitstrm.append(f'uint:6=0') + + +def unpackPositions(bitstrm: ConstBitStream, piSize: int) -> list[POSITION]: + assert piSize <= 24 and (piSize % 6) == 0, "Incorrect PI Data Size for Positions" + positions = list() + while piSize > 0: + x = bitstrm.read(16).int / 100.0 + y = bitstrm.read(16).int / 100.0 + z = bitstrm.read(16).int / 100.0 + positions.append(POSITION(x, y, z)) + piSize -= 6 + return positions + +def unpackISMDirectivity(bitstrm: ConstBitStream, piSize: int) -> list[DISTANCE_ATTENUATION]: + inner_ang = None + outer_ang = None + outer_att = None + assert piSize == 1*2 or piSize == 2*2 or piSize == 3*2 or piSize == 4*2, "Incorrect PI Data Size for ISM_DISTANCE_ATTENUATION" + directivities = list() + for _ in range(piSize): + inner_ang = bitstrm.read(5).uint + outer_ang = bitstrm.read(5).uint + outer_att = bitstrm.read(5).uint + directivities.append(DIRECTIVITY(inner_ang=inner_ang, outer_ang=outer_ang, outer_att=outer_att)) + bitstrm.bytealign() + return directivities + +def packISMDirectivity(bitstrm: BitStream, data: any): + assert type(data) == list, "Data of type ISM_DIRECTIVITY is expected" + + for dir in cast(list, data): + assert type(dir) == DIRECTIVITY, "Orientation PI Data expects a data of type list[DIRECTIVITY]" + inner_ang_idx = getListIndex(innerOuterAngles, dir.inner_ang) + outer_ang_idx = getListIndex(innerOuterAngles, dir.outer_ang) + outer_att_idx = getListIndex(outerAttenuations, dir.outer_att) + bitstrm.append(f'uint:5={inner_ang_idx}') + bitstrm.append(f'uint:5={outer_ang_idx}') + bitstrm.append(f'uint:5={outer_att_idx}') + bitstrm.append(f'uint:1=0') PIDataUnpacker = [ unpackOrientation, # SCENE_ORIENTATION, @@ -626,13 +780,13 @@ PIDataUnpacker = [ unpackOrientation, # DEVICE_ORIENTATION_UNCOMPENSATED unpackAcousticEnv, # ACOUSTIC_ENVIRONMENT unpackAudioDescription, # AUDIO_DESCRIPTION - unpackUnsupported, # ISM_NUM - unpackUnsupported, # ISM_ID - unpackUnsupported, # ISM_GAIN + unpackISMNum, # ISM_NUM + unpackISMID, # ISM_ID + unpackISMGain, # ISM_GAIN unpackOrientations,# ISM_ORIENTATION unpackPositions, # ISM_POSITION - unpackUnsupported, # ISM_DISTANCE_ATTENUATION - unpackUnsupported, # ISM_DIRECTIVITY + unpackISMDistanceAttenuation, # ISM_DISTANCE_ATTENUATION + unpackISMDirectivity, # ISM_DIRECTIVITY unpackDiegetic, # DIEGETIC_TYPE unpackUnsupported, # RESERVED13 unpackAudioFocus, # AUDIO_FOCUS_INDICATION @@ -661,13 +815,13 @@ PIDataPacker = [ packOrientation, # DEVICE_ORIENTATION_UNCOMPENSATED packAcousticEnv, # ACOUSTIC_ENVIRONMENT packAudioDescription, # AUDIO_DESCRIPTION - packUnsupported, # ISM_NUM - packUnsupported, # ISM_ID - packUnsupported, # ISM_GAIN + packISMNum, # ISM_NUM + packISMID, # ISM_ID + packISMGain, # ISM_GAIN packOrientations,# ISM_ORIENTATION packPositions, # ISM_POSITION - packUnsupported, # ISM_DISTANCE_ATTENUATION - packUnsupported, # ISM_DIRECTIVITY + packISMDistanceAttenuation, # ISM_DISTANCE_ATTENUATION + packISMDirectivity, # ISM_DIRECTIVITY packDiegetic, # DIEGETIC_TYPE packUnsupported, # RESERVED13 packAudioFocus, # AUDIO_FOCUS_INDICATION diff --git a/tests/rtp/test_rtp.py b/tests/rtp/test_rtp.py index 4e394ee478..b770fd0fd6 100644 --- a/tests/rtp/test_rtp.py +++ b/tests/rtp/test_rtp.py @@ -169,6 +169,14 @@ def generatePiData(startTs: int, endTs: int) -> dict: someAuFocusLvl = lambda : AUDIO_FOCUS(level=AUDIO_FOCUS_LEVEL(random.randint(0, 15))) someAuFocusList = [someAuFocusDirLvl, someAuFocusDir, someAuFocusLvl] + someNumISM = lambda : ISM_NUM(num=random.randint(1, 4)) + someISMIds = lambda num_ism : ISM_ID(ids=[int(random.getrandbits(8)) for _ in range(num_ism)]) + someISMGains = lambda num_ism : ISM_GAIN(gains=[int(random.randint(-96,3)) for _ in range(num_ism)]) + someISMOrientations = lambda num_ism : [ORIENTATION(w=2*random.random()-1.0, x=2*random.random()-1.0, y=2*random.random()-1.0, z=2*random.random()-1.0) for _ in range(num_ism)] + someISMPositions = lambda num_ism : [POSITION( x=random.randint(-32788, 32767)/100.0, y=random.randint(-32788, 32767)/100.0, z=random.randint(-32788, 32767)/100.0) for _ in range(num_ism)] + someISMDistanceAttenuations = lambda num_ism : [DISTANCE_ATTENUATION(ref_dist=random.randint(1,64)/10.0, max_dist=random.randint(1,64), roll_off=random.randint(0,40)/10.0) for _ in range(num_ism)] + someISMDirectivities = lambda num_ism : [DIRECTIVITY(inner_ang=random.randint(0,24)*15, outer_ang=random.randint(0,24)*15, outer_att=random.randint(-30,0)*3) for _ in range(num_ism)] + for ts in range(startTs, endTs, 320): pidata = dict() pidata["SCENE_ORIENTATION"] = someOrientation() @@ -182,6 +190,13 @@ def generatePiData(startTs: int, endTs: int) -> dict: pidata["AUDIO_DESCRIPTION"] = [someDesc() for n in range(random.randint(1, 5))] pidata["DIEGETIC_TYPE"] = someDIG() pidata["ACOUSTIC_ENVIRONMENT"] = ACOUSTIC_ENVIRONMENT(aeid=random.randint(0, 127)) + pidata["ISM_NUM"] = someNumISM() + pidata["ISM_ID"] = someISMIds(pidata["ISM_NUM"].num) + pidata["ISM_GAIN"] = someISMGains(pidata["ISM_NUM"].num) + pidata["ISM_ORIENTATION"] = someISMOrientations(pidata["ISM_NUM"].num) + pidata["ISM_POSITION"] = someISMPositions(pidata["ISM_NUM"].num) + pidata["ISM_DISTANCE_ATTENUATION"] = someISMDistanceAttenuations(pidata["ISM_NUM"].num) + pidata["ISM_DIRECTIVITY"] = someISMDirectivities(pidata["ISM_NUM"].num) data[str(ts)] = pidata return data -- GitLab From bf093618cc135544b3da7a06a54ab3fb6572079a Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 30 Oct 2025 15:18:48 +0200 Subject: [PATCH 2/2] Fix ISM orientation PI json writing --- apps/decoder.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 4bd2c802f5..40c4ef78ec 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -396,10 +396,14 @@ static void IVAS_RTP_LogPiData( FILE *f_piDataOut, PIDATA_TS *piData, uint32_t n fprintf( f_piDataOut, "[\n" ); for ( n = 0; n < cur->data.ismOrientation.size / 8; n++ ) { - fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"w\": %f,\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t},\n", + if ( n != 0 ) + { + fprintf( f_piDataOut, ",\n" ); + } + fprintf( f_piDataOut, "\t\t\t{\n\t\t\t\t\"w\": %f,\n\t\t\t\t\"x\": %f,\n\t\t\t\t\"y\": %f,\n\t\t\t\t\"z\": %f \n\t\t\t}", cur->data.ismOrientation.orientation[n].w, cur->data.ismOrientation.orientation[n].x, cur->data.ismOrientation.orientation[n].y, cur->data.ismOrientation.orientation[n].z ); } - fprintf( f_piDataOut, "\t\t]" ); + fprintf( f_piDataOut, "\n\t\t]" ); } break; case IVAS_PI_ISM_NUM: -- GitLab