Loading lib_com/options.h +1 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,7 @@ #define DECODER_FORMAT_SWITCHING /* Re-initialize the decoder when the format/subformat of the incoming stream is changed */ #define RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE /* CR for split rendering codec framesize signalling in Toc Byte*/ #define FIX_SPLIT_RENDERING_ON_DECODER_RESTART /* Re-configure split rendering on decoder restart */ #define COMPACT_ORIENTATION_PI_DATA /* ################### Start BE switches ################################# */ /* only BE switches wrt selection floating point code */ Loading lib_util/ivas_rtp_internal.h +3 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,9 @@ enum MASK_BITS #ifdef REVERSE_ISM_PI_DATA MASK_9BIT = 0x1FF, #endif #ifdef COMPACT_ORIENTATION_PI_DATA MASK_10BIT = 0x3FF, #endif }; Loading lib_util/ivas_rtp_pi_data.c +125 −19 Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ #endif #ifdef ISM_PI_DATA #include <stdlib.h> #ifdef COMPACT_ORIENTATION_PI_DATA #include "tools.c" #endif #ifndef min #define min( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) Loading Loading @@ -79,6 +82,85 @@ static int16_t ivasPayload_convertToQ15( float value ) return (int16_t) ( value ); } #ifdef COMPACT_ORIENTATION_PI_DATA static uint32_t packQuaternion( IVAS_QUATERNION orientation, uint8_t *buffer ) { uint32_t nBytes = 0; float q[4], q_max; uint16_t max_q_idx, n, k; uint32_t lWord; q[0] = orientation.w; q[1] = orientation.x; q[2] = orientation.y; q[3] = orientation.z; max_q_idx = maximumAbs( q, 4, &q_max ); if ( q[max_q_idx] < 0 ) { for ( n = 0; n < 4; n++ ) { q[n] = -q[n]; } } lWord = max_q_idx << 30; k = 1; for ( n = 0; n < 4; n++ ) { if ( n == max_q_idx ) { continue; } lWord |= ( ( (int16_t) ( ( q[n] + 1 ) * 1023 * 0.5f ) & MASK_10BIT ) << ( 30 - k * 10 ) ); k++; } buffer[nBytes++] = ( lWord >> 24 ) & MASK_8BIT; buffer[nBytes++] = ( lWord >> 16 ) & MASK_8BIT; buffer[nBytes++] = ( lWord >> 8 ) & MASK_8BIT; buffer[nBytes++] = (lWord) &MASK_8BIT; return nBytes; } static ivas_error unpackQuaternion( const uint8_t *buffer, IVAS_QUATERNION *orientation ) { uint32_t i, k, lWord; uint16_t max_q_idx, tmp; float q[4], qs; lWord = ( buffer[0] ) << 24; lWord |= ( buffer[1] ) << 16; lWord |= ( buffer[2] ) << 8; lWord |= buffer[3]; max_q_idx = ( lWord >> 30 ) & MASK_2BIT; k = 1; qs = 0.0f; for ( i = 0; i < 4; i++ ) { if ( i == max_q_idx ) { continue; } tmp = ( lWord >> ( 30 - k * 10 ) ) & MASK_10BIT; q[i] = tmp / 1023.0f * 2.0f - 1; qs += q[i] * q[i]; k++; } q[max_q_idx] = sqrtf( 1 - qs ); orientation->w = q[0]; orientation->x = q[1]; orientation->y = q[2]; orientation->z = q[3]; return IVAS_ERR_OK; } #endif static ivas_error packUnsupportedData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { (void) piData; Loading Loading @@ -152,19 +234,22 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b 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 ) /* Orientation data is 4 bytes, header is 2 bytes */ if ( maxDataBytes < 4 + 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; buffer[nBytes++] = 4; #ifdef COMPACT_ORIENTATION_PI_DATA nBytes += packQuaternion( orientation->orientation, &buffer[nBytes] ); #else 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 ) ); #endif *nBytesWritten = nBytes; return IVAS_ERR_OK; } Loading Loading @@ -196,10 +281,14 @@ static ivas_error packISMOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t buffer[nBytes++] = (uint8_t) orientation->numObjects * 8; for ( n = 0; n < orientation->numObjects; n++ ) { #ifdef COMPACT_ORIENTATION_PI_DATA nBytes += packQuaternion( orientation->orientation[n], &buffer[nBytes] ); #else 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 ) ); #endif } *nBytesWritten = nBytes; return IVAS_ERR_OK; Loading @@ -210,17 +299,21 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte { IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData; /* Orientation data is 8 bytes */ if ( numDataBytes != 8 ) /* Orientation data is 4 bytes */ if ( numDataBytes != 4 ) { return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); #ifdef COMPACT_ORIENTATION_PI_DATA unpackQuaternion( buffer, &( orientation->orientation ) ); #else 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] ) ); #endif return IVAS_ERR_OK; } Loading @@ -230,22 +323,26 @@ static ivas_error unpackISMOrientation( const uint8_t *buffer, uint32_t numDataB { IVAS_PIDATA_ISM_ORIENTATION *ism_orientation = (IVAS_PIDATA_ISM_ORIENTATION *) piData; /* Orientation data is 8 bytes */ /* Orientation data is 4 bytes */ uint16_t n; if ( numDataBytes % 8 != 0 ) if ( numDataBytes % 4 != 0 ) { return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } ism_orientation->size = sizeof( IVAS_PIDATA_ISM_ORIENTATION ); ism_orientation->numObjects = (uint16_t) numDataBytes / 8; ism_orientation->numObjects = (uint16_t) numDataBytes / 4; for ( n = 0; n < ism_orientation->numObjects; n++ ) { #ifdef COMPACT_ORIENTATION_PI_DATA unpackQuaternion( &buffer[4 * n], &( ism_orientation->orientation[n] ) ); #else ism_orientation->orientation[n].w = FLOAT_FROM_Q15( readInt16( &buffer[8 * n] ) ); ism_orientation->orientation[n].x = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 2] ) ); ism_orientation->orientation[n].y = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 4] ) ); ism_orientation->orientation[n].z = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 6] ) ); #endif } for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) { Loading Loading @@ -754,11 +851,11 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 if ( audioFocus->availDirection && audioFocus->availLevel ) { packedSize = 9; packedSize = 5; } else if ( audioFocus->availDirection ) { packedSize = 8; packedSize = 4; } else if ( audioFocus->availLevel ) { Loading @@ -778,14 +875,19 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 buffer[nBytes++] = ( audioFocus->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ buffer[nBytes++] = packedSize; if ( packedSize == 9 || packedSize == 8 ) if ( packedSize == 5 || packedSize == 4 ) { #ifdef COMPACT_ORIENTATION_PI_DATA nBytes += packQuaternion( audioFocus->direction, &buffer[nBytes] ); #else 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 ) ); #endif } if ( packedSize == 9 || packedSize == 1 ) if ( packedSize == 5 || packedSize == 1 ) { buffer[nBytes++] = ( (uint8_t) audioFocus->flvl & MASK_4BIT ) << 4; } Loading @@ -798,15 +900,15 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat { 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 ) /* Audio Focus data is either 1, 4 or 5 bytes */ if ( numDataBytes != 1 && numDataBytes != 4 && numDataBytes != 5 ) { 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 ); audioFocus->availDirection = ( numDataBytes >= 4 ); audioFocus->availLevel = ( numDataBytes == 1 || numDataBytes == 5 ); if ( numDataBytes == 1 ) { Loading @@ -814,14 +916,18 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat } else { #ifdef COMPACT_ORIENTATION_PI_DATA unpackQuaternion( buffer, &( audioFocus->direction ) ); #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] ) ); #endif if ( numDataBytes == 9 ) if ( numDataBytes == 5 ) { audioFocus->flvl = ( buffer[8] >> 4 ); audioFocus->flvl = ( buffer[4] >> 4 ); } } Loading tests/rtp/ivasrtp.py +31 −13 Original line number Diff line number Diff line Loading @@ -748,16 +748,28 @@ def packNoPiData(bitstrm: BitStream, data: any = None): def unpackOrientations(bitstrm: ConstBitStream, piSize: int) -> list[ORIENTATION]: assert ( piSize % 8 piSize % 4 ) == 0 and piSize <= 32, "Incorrect PI Data Size for list[ORIENTATION]" orientations = list() q = [(float)]*4 qs = 0 while piSize > 0: w = bitstrm.read(16).int / 32768.0 x = bitstrm.read(16).int / 32768.0 y = bitstrm.read(16).int / 32768.0 z = bitstrm.read(16).int / 32768.0 max_q_idx = bitstrm.read(2).uint for i in range(0,4): if i == max_q_idx: continue tmp = bitstrm.read(10).uint q[i] = (tmp / 1023.0) * 2.0 - 1.0 qs = qs + q[i]**2 q[max_q_idx] = (1 - qs)**0.5 w = q[0] x = q[1] y = q[2] z = q[3] orientations.append(ORIENTATION(w, x, y, z)) piSize -= 8 piSize -= 4 return orientations Loading @@ -767,10 +779,16 @@ def packOrientations(bitstrm: BitStream, data: any): assert ( type(orientation) == ORIENTATION ), "Orientation PI Data expects a data of type list[ORIENTATION]" bitstrm.append(f"intbe:16={q15(orientation.w)}") bitstrm.append(f"intbe:16={q15(orientation.x)}") bitstrm.append(f"intbe:16={q15(orientation.y)}") bitstrm.append(f"intbe:16={q15(orientation.z)}") q = [orientation.w, orientation.x, orientation.y, orientation.z] max_q = max(q, key=abs) max_q_idx = q.index(max_q) if max_q < 0: q = [-x for x in q] bitstrm.append(f"uint:2={max_q_idx}") for i in range(0,4): if i == max_q_idx: continue bitstrm.append(f"uint:10={(int)((q[i]+1)*1023*1/2)}") def unpackPositions(bitstrm: ConstBitStream, piSize: int) -> list[POSITION]: Loading Loading @@ -799,7 +817,7 @@ def packPositions(bitstrm: BitStream, data: any): def unpackOrientation(bitstrm: ConstBitStream, piSize: int) -> ORIENTATION: assert piSize == 8, "Incorrect PI Data Size for ORIENTATION" assert piSize == 4, "Incorrect PI Data Size for ORIENTATION" orientations = unpackOrientations(bitstrm, piSize) assert len(orientations) == 1 return orientations[0] Loading Loading @@ -983,8 +1001,8 @@ def unpackAudioFocus(bitstrm: ConstBitStream, piSize: int) -> AUDIO_FOCUS: level = bitstrm.read(4).uint _ = bitstrm.read(4) else: direction = unpackOrientation(bitstrm, 8) if piSize == 9: direction = unpackOrientation(bitstrm, 4) if piSize == 5: level = bitstrm.read(4).uint _ = bitstrm.read(4) Loading tests/rtp/test_rtp.py +22 −32 Original line number Diff line number Diff line Loading @@ -182,12 +182,17 @@ def generateRequests(startTs: int, endTs: int) -> dict: def generatePiData(startTs: int, endTs: int) -> dict: data = dict() someOrientation = lambda: ORIENTATION( w=2 * random.random() - 1.0, x=2 * random.random() - 1.0, y=2 * random.random() - 1.0, z=2 * random.random() - 1.0, ) def random_unit_quaternion(): w = 2*random.random() - 1.0 x = 2*random.random() - 1.0 y = 2*random.random() - 1.0 z = 2*random.random() - 1.0 n = (w*w + x*x + y*y + z*z)**0.5 if n == 0.0: return random_unit_quaternion() return ORIENTATION(w/n, x/n, y/n, z/n) someOrientation = lambda: random_unit_quaternion() somePosition = lambda: POSITION( x=random.randint(-32788, 32767) / 100.0, y=random.randint(-32788, 32767) / 100.0, Loading @@ -209,23 +214,8 @@ def generatePiData(startTs: int, endTs: int) -> dict: someDIG = lambda: DIEGETIC_TYPE( isDigetic=[bool(random.getrandbits(1)) for _ in range(random.randint(1, 5))] ) someAuFocusDirLvl = lambda: AUDIO_FOCUS( 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, ), level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)), ) someAuFocusDir = lambda: AUDIO_FOCUS( 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, ) ) someAuFocusDirLvl = lambda: AUDIO_FOCUS(random_unit_quaternion(),level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)),) someAuFocusDir = lambda: AUDIO_FOCUS(random_unit_quaternion()) someAuFocusLvl = lambda: AUDIO_FOCUS(level=AUDIO_FOCUS_LEVEL(random.randint(0, 15))) someAuFocusList = [someAuFocusDirLvl, someAuFocusDir, someAuFocusLvl] someLatency = lambda: PI_LATENCY( Loading Loading @@ -273,7 +263,7 @@ def generatePiData(startTs: int, endTs: int) -> dict: 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=[random.choice([int(random.randint(-24,12)), -128]) for _ in range(num_ism)]) # -128 corresponds to -Inf 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)] someISMOrientations = lambda num_ism : [random_unit_quaternion() 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.choice([random.randint(-30,0)*3, -128])) for _ in range(num_ism)] # -128 corresponds to -Inf Loading Loading @@ -322,10 +312,10 @@ def isEqualFrame(refFrame: bytes, dutFrame: bytes): def isEqualOrientation(ref: ORIENTATION, dut: ORIENTATION): assert abs(ref.w - dut.w) < 0.0001, "Scene Orientation PI Data mismatch in w" assert abs(ref.x - dut.x) < 0.0001, "Scene Orientation PI Data mismatch in x" assert abs(ref.y - dut.y) < 0.0001, "Scene Orientation PI Data mismatch in y" assert abs(ref.z - dut.z) < 0.0001, "Scene Orientation PI Data mismatch in z" assert abs(abs(ref.w) - abs(dut.w)) < 0.01, "Scene Orientation PI Data mismatch in w" assert abs(abs(ref.x) - abs(dut.x)) < 0.01, "Scene Orientation PI Data mismatch in x" assert abs(abs(ref.y) - abs(dut.y)) < 0.01, "Scene Orientation PI Data mismatch in y" assert abs(abs(ref.z) - abs(dut.z)) < 0.01, "Scene Orientation PI Data mismatch in z" def isEqualPosition(ref: POSITION, dut: POSITION): Loading Loading @@ -392,16 +382,16 @@ def isEqualAudioFocus(ref: AUDIO_FOCUS, dut: AUDIO_FOCUS): assert dut.direction is not None, "Audio Focus PI Data missing direction" if ref.direction is not None and dut.direction is not None: assert ( abs(ref.direction["w"] - dut.direction.w) < 0.0001 abs(abs(ref.direction["w"]) - abs(dut.direction.w)) < 0.01 ), "Audio Focus PI Data mismatch in direction w" assert ( abs(ref.direction["x"] - dut.direction.x) < 0.0001 abs(abs(ref.direction["x"]) - abs(dut.direction.x)) < 0.01 ), "Audio Focus PI Data mismatch in direction x" assert ( abs(ref.direction["y"] - dut.direction.y) < 0.0001 abs(abs(ref.direction["y"]) - abs(dut.direction.y)) < 0.01 ), "Audio Focus PI Data mismatch in direction y" assert ( abs(ref.direction["z"] - dut.direction.z) < 0.0001 abs(abs(ref.direction["z"]) - abs(dut.direction.z)) < 0.01 ), "Audio Focus PI Data mismatch in direction z" assert ref.level == dut.level, "Audio Focus PI Data mismatch in level" Loading Loading
lib_com/options.h +1 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,7 @@ #define DECODER_FORMAT_SWITCHING /* Re-initialize the decoder when the format/subformat of the incoming stream is changed */ #define RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE /* CR for split rendering codec framesize signalling in Toc Byte*/ #define FIX_SPLIT_RENDERING_ON_DECODER_RESTART /* Re-configure split rendering on decoder restart */ #define COMPACT_ORIENTATION_PI_DATA /* ################### Start BE switches ################################# */ /* only BE switches wrt selection floating point code */ Loading
lib_util/ivas_rtp_internal.h +3 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,9 @@ enum MASK_BITS #ifdef REVERSE_ISM_PI_DATA MASK_9BIT = 0x1FF, #endif #ifdef COMPACT_ORIENTATION_PI_DATA MASK_10BIT = 0x3FF, #endif }; Loading
lib_util/ivas_rtp_pi_data.c +125 −19 Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ #endif #ifdef ISM_PI_DATA #include <stdlib.h> #ifdef COMPACT_ORIENTATION_PI_DATA #include "tools.c" #endif #ifndef min #define min( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) Loading Loading @@ -79,6 +82,85 @@ static int16_t ivasPayload_convertToQ15( float value ) return (int16_t) ( value ); } #ifdef COMPACT_ORIENTATION_PI_DATA static uint32_t packQuaternion( IVAS_QUATERNION orientation, uint8_t *buffer ) { uint32_t nBytes = 0; float q[4], q_max; uint16_t max_q_idx, n, k; uint32_t lWord; q[0] = orientation.w; q[1] = orientation.x; q[2] = orientation.y; q[3] = orientation.z; max_q_idx = maximumAbs( q, 4, &q_max ); if ( q[max_q_idx] < 0 ) { for ( n = 0; n < 4; n++ ) { q[n] = -q[n]; } } lWord = max_q_idx << 30; k = 1; for ( n = 0; n < 4; n++ ) { if ( n == max_q_idx ) { continue; } lWord |= ( ( (int16_t) ( ( q[n] + 1 ) * 1023 * 0.5f ) & MASK_10BIT ) << ( 30 - k * 10 ) ); k++; } buffer[nBytes++] = ( lWord >> 24 ) & MASK_8BIT; buffer[nBytes++] = ( lWord >> 16 ) & MASK_8BIT; buffer[nBytes++] = ( lWord >> 8 ) & MASK_8BIT; buffer[nBytes++] = (lWord) &MASK_8BIT; return nBytes; } static ivas_error unpackQuaternion( const uint8_t *buffer, IVAS_QUATERNION *orientation ) { uint32_t i, k, lWord; uint16_t max_q_idx, tmp; float q[4], qs; lWord = ( buffer[0] ) << 24; lWord |= ( buffer[1] ) << 16; lWord |= ( buffer[2] ) << 8; lWord |= buffer[3]; max_q_idx = ( lWord >> 30 ) & MASK_2BIT; k = 1; qs = 0.0f; for ( i = 0; i < 4; i++ ) { if ( i == max_q_idx ) { continue; } tmp = ( lWord >> ( 30 - k * 10 ) ) & MASK_10BIT; q[i] = tmp / 1023.0f * 2.0f - 1; qs += q[i] * q[i]; k++; } q[max_q_idx] = sqrtf( 1 - qs ); orientation->w = q[0]; orientation->x = q[1]; orientation->y = q[2]; orientation->z = q[3]; return IVAS_ERR_OK; } #endif static ivas_error packUnsupportedData( const IVAS_PIDATA_GENERIC *piData, uint8_t *buffer, uint32_t maxDataBytes, uint32_t *nBytesWritten ) { (void) piData; Loading Loading @@ -152,19 +234,22 @@ static ivas_error packOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t *b 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 ) /* Orientation data is 4 bytes, header is 2 bytes */ if ( maxDataBytes < 4 + 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; buffer[nBytes++] = 4; #ifdef COMPACT_ORIENTATION_PI_DATA nBytes += packQuaternion( orientation->orientation, &buffer[nBytes] ); #else 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 ) ); #endif *nBytesWritten = nBytes; return IVAS_ERR_OK; } Loading Loading @@ -196,10 +281,14 @@ static ivas_error packISMOrientation( const IVAS_PIDATA_GENERIC *piData, uint8_t buffer[nBytes++] = (uint8_t) orientation->numObjects * 8; for ( n = 0; n < orientation->numObjects; n++ ) { #ifdef COMPACT_ORIENTATION_PI_DATA nBytes += packQuaternion( orientation->orientation[n], &buffer[nBytes] ); #else 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 ) ); #endif } *nBytesWritten = nBytes; return IVAS_ERR_OK; Loading @@ -210,17 +299,21 @@ static ivas_error unpackOrientation( const uint8_t *buffer, uint32_t numDataByte { IVAS_PIDATA_ORIENTATION *orientation = (IVAS_PIDATA_ORIENTATION *) piData; /* Orientation data is 8 bytes */ if ( numDataBytes != 8 ) /* Orientation data is 4 bytes */ if ( numDataBytes != 4 ) { return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } piData->size = sizeof( IVAS_PIDATA_ORIENTATION ); #ifdef COMPACT_ORIENTATION_PI_DATA unpackQuaternion( buffer, &( orientation->orientation ) ); #else 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] ) ); #endif return IVAS_ERR_OK; } Loading @@ -230,22 +323,26 @@ static ivas_error unpackISMOrientation( const uint8_t *buffer, uint32_t numDataB { IVAS_PIDATA_ISM_ORIENTATION *ism_orientation = (IVAS_PIDATA_ISM_ORIENTATION *) piData; /* Orientation data is 8 bytes */ /* Orientation data is 4 bytes */ uint16_t n; if ( numDataBytes % 8 != 0 ) if ( numDataBytes % 4 != 0 ) { return IVAS_ERROR( IVAS_ERR_RTP_UNPACK_PI_DATA, "Incorrect size to unpack Orientation PI data" ); } ism_orientation->size = sizeof( IVAS_PIDATA_ISM_ORIENTATION ); ism_orientation->numObjects = (uint16_t) numDataBytes / 8; ism_orientation->numObjects = (uint16_t) numDataBytes / 4; for ( n = 0; n < ism_orientation->numObjects; n++ ) { #ifdef COMPACT_ORIENTATION_PI_DATA unpackQuaternion( &buffer[4 * n], &( ism_orientation->orientation[n] ) ); #else ism_orientation->orientation[n].w = FLOAT_FROM_Q15( readInt16( &buffer[8 * n] ) ); ism_orientation->orientation[n].x = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 2] ) ); ism_orientation->orientation[n].y = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 4] ) ); ism_orientation->orientation[n].z = FLOAT_FROM_Q15( readInt16( &buffer[8 * n + 6] ) ); #endif } for ( ; n < IVAS_MAX_NUM_OBJECTS; n++ ) { Loading Loading @@ -754,11 +851,11 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 if ( audioFocus->availDirection && audioFocus->availLevel ) { packedSize = 9; packedSize = 5; } else if ( audioFocus->availDirection ) { packedSize = 8; packedSize = 4; } else if ( audioFocus->availLevel ) { Loading @@ -778,14 +875,19 @@ static ivas_error packAudioFocusCommon( const IVAS_PIDATA_GENERIC *piData, uint8 buffer[nBytes++] = ( audioFocus->piDataType & MASK_5BIT ); /* PF/PM populated during final packing */ buffer[nBytes++] = packedSize; if ( packedSize == 9 || packedSize == 8 ) if ( packedSize == 5 || packedSize == 4 ) { #ifdef COMPACT_ORIENTATION_PI_DATA nBytes += packQuaternion( audioFocus->direction, &buffer[nBytes] ); #else 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 ) ); #endif } if ( packedSize == 9 || packedSize == 1 ) if ( packedSize == 5 || packedSize == 1 ) { buffer[nBytes++] = ( (uint8_t) audioFocus->flvl & MASK_4BIT ) << 4; } Loading @@ -798,15 +900,15 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat { 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 ) /* Audio Focus data is either 1, 4 or 5 bytes */ if ( numDataBytes != 1 && numDataBytes != 4 && numDataBytes != 5 ) { 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 ); audioFocus->availDirection = ( numDataBytes >= 4 ); audioFocus->availLevel = ( numDataBytes == 1 || numDataBytes == 5 ); if ( numDataBytes == 1 ) { Loading @@ -814,14 +916,18 @@ static ivas_error unpackAudioFocusCommon( const uint8_t *buffer, uint32_t numDat } else { #ifdef COMPACT_ORIENTATION_PI_DATA unpackQuaternion( buffer, &( audioFocus->direction ) ); #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] ) ); #endif if ( numDataBytes == 9 ) if ( numDataBytes == 5 ) { audioFocus->flvl = ( buffer[8] >> 4 ); audioFocus->flvl = ( buffer[4] >> 4 ); } } Loading
tests/rtp/ivasrtp.py +31 −13 Original line number Diff line number Diff line Loading @@ -748,16 +748,28 @@ def packNoPiData(bitstrm: BitStream, data: any = None): def unpackOrientations(bitstrm: ConstBitStream, piSize: int) -> list[ORIENTATION]: assert ( piSize % 8 piSize % 4 ) == 0 and piSize <= 32, "Incorrect PI Data Size for list[ORIENTATION]" orientations = list() q = [(float)]*4 qs = 0 while piSize > 0: w = bitstrm.read(16).int / 32768.0 x = bitstrm.read(16).int / 32768.0 y = bitstrm.read(16).int / 32768.0 z = bitstrm.read(16).int / 32768.0 max_q_idx = bitstrm.read(2).uint for i in range(0,4): if i == max_q_idx: continue tmp = bitstrm.read(10).uint q[i] = (tmp / 1023.0) * 2.0 - 1.0 qs = qs + q[i]**2 q[max_q_idx] = (1 - qs)**0.5 w = q[0] x = q[1] y = q[2] z = q[3] orientations.append(ORIENTATION(w, x, y, z)) piSize -= 8 piSize -= 4 return orientations Loading @@ -767,10 +779,16 @@ def packOrientations(bitstrm: BitStream, data: any): assert ( type(orientation) == ORIENTATION ), "Orientation PI Data expects a data of type list[ORIENTATION]" bitstrm.append(f"intbe:16={q15(orientation.w)}") bitstrm.append(f"intbe:16={q15(orientation.x)}") bitstrm.append(f"intbe:16={q15(orientation.y)}") bitstrm.append(f"intbe:16={q15(orientation.z)}") q = [orientation.w, orientation.x, orientation.y, orientation.z] max_q = max(q, key=abs) max_q_idx = q.index(max_q) if max_q < 0: q = [-x for x in q] bitstrm.append(f"uint:2={max_q_idx}") for i in range(0,4): if i == max_q_idx: continue bitstrm.append(f"uint:10={(int)((q[i]+1)*1023*1/2)}") def unpackPositions(bitstrm: ConstBitStream, piSize: int) -> list[POSITION]: Loading Loading @@ -799,7 +817,7 @@ def packPositions(bitstrm: BitStream, data: any): def unpackOrientation(bitstrm: ConstBitStream, piSize: int) -> ORIENTATION: assert piSize == 8, "Incorrect PI Data Size for ORIENTATION" assert piSize == 4, "Incorrect PI Data Size for ORIENTATION" orientations = unpackOrientations(bitstrm, piSize) assert len(orientations) == 1 return orientations[0] Loading Loading @@ -983,8 +1001,8 @@ def unpackAudioFocus(bitstrm: ConstBitStream, piSize: int) -> AUDIO_FOCUS: level = bitstrm.read(4).uint _ = bitstrm.read(4) else: direction = unpackOrientation(bitstrm, 8) if piSize == 9: direction = unpackOrientation(bitstrm, 4) if piSize == 5: level = bitstrm.read(4).uint _ = bitstrm.read(4) Loading
tests/rtp/test_rtp.py +22 −32 Original line number Diff line number Diff line Loading @@ -182,12 +182,17 @@ def generateRequests(startTs: int, endTs: int) -> dict: def generatePiData(startTs: int, endTs: int) -> dict: data = dict() someOrientation = lambda: ORIENTATION( w=2 * random.random() - 1.0, x=2 * random.random() - 1.0, y=2 * random.random() - 1.0, z=2 * random.random() - 1.0, ) def random_unit_quaternion(): w = 2*random.random() - 1.0 x = 2*random.random() - 1.0 y = 2*random.random() - 1.0 z = 2*random.random() - 1.0 n = (w*w + x*x + y*y + z*z)**0.5 if n == 0.0: return random_unit_quaternion() return ORIENTATION(w/n, x/n, y/n, z/n) someOrientation = lambda: random_unit_quaternion() somePosition = lambda: POSITION( x=random.randint(-32788, 32767) / 100.0, y=random.randint(-32788, 32767) / 100.0, Loading @@ -209,23 +214,8 @@ def generatePiData(startTs: int, endTs: int) -> dict: someDIG = lambda: DIEGETIC_TYPE( isDigetic=[bool(random.getrandbits(1)) for _ in range(random.randint(1, 5))] ) someAuFocusDirLvl = lambda: AUDIO_FOCUS( 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, ), level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)), ) someAuFocusDir = lambda: AUDIO_FOCUS( 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, ) ) someAuFocusDirLvl = lambda: AUDIO_FOCUS(random_unit_quaternion(),level=AUDIO_FOCUS_LEVEL(random.randint(0, 15)),) someAuFocusDir = lambda: AUDIO_FOCUS(random_unit_quaternion()) someAuFocusLvl = lambda: AUDIO_FOCUS(level=AUDIO_FOCUS_LEVEL(random.randint(0, 15))) someAuFocusList = [someAuFocusDirLvl, someAuFocusDir, someAuFocusLvl] someLatency = lambda: PI_LATENCY( Loading Loading @@ -273,7 +263,7 @@ def generatePiData(startTs: int, endTs: int) -> dict: 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=[random.choice([int(random.randint(-24,12)), -128]) for _ in range(num_ism)]) # -128 corresponds to -Inf 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)] someISMOrientations = lambda num_ism : [random_unit_quaternion() 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.choice([random.randint(-30,0)*3, -128])) for _ in range(num_ism)] # -128 corresponds to -Inf Loading Loading @@ -322,10 +312,10 @@ def isEqualFrame(refFrame: bytes, dutFrame: bytes): def isEqualOrientation(ref: ORIENTATION, dut: ORIENTATION): assert abs(ref.w - dut.w) < 0.0001, "Scene Orientation PI Data mismatch in w" assert abs(ref.x - dut.x) < 0.0001, "Scene Orientation PI Data mismatch in x" assert abs(ref.y - dut.y) < 0.0001, "Scene Orientation PI Data mismatch in y" assert abs(ref.z - dut.z) < 0.0001, "Scene Orientation PI Data mismatch in z" assert abs(abs(ref.w) - abs(dut.w)) < 0.01, "Scene Orientation PI Data mismatch in w" assert abs(abs(ref.x) - abs(dut.x)) < 0.01, "Scene Orientation PI Data mismatch in x" assert abs(abs(ref.y) - abs(dut.y)) < 0.01, "Scene Orientation PI Data mismatch in y" assert abs(abs(ref.z) - abs(dut.z)) < 0.01, "Scene Orientation PI Data mismatch in z" def isEqualPosition(ref: POSITION, dut: POSITION): Loading Loading @@ -392,16 +382,16 @@ def isEqualAudioFocus(ref: AUDIO_FOCUS, dut: AUDIO_FOCUS): assert dut.direction is not None, "Audio Focus PI Data missing direction" if ref.direction is not None and dut.direction is not None: assert ( abs(ref.direction["w"] - dut.direction.w) < 0.0001 abs(abs(ref.direction["w"]) - abs(dut.direction.w)) < 0.01 ), "Audio Focus PI Data mismatch in direction w" assert ( abs(ref.direction["x"] - dut.direction.x) < 0.0001 abs(abs(ref.direction["x"]) - abs(dut.direction.x)) < 0.01 ), "Audio Focus PI Data mismatch in direction x" assert ( abs(ref.direction["y"] - dut.direction.y) < 0.0001 abs(abs(ref.direction["y"]) - abs(dut.direction.y)) < 0.01 ), "Audio Focus PI Data mismatch in direction y" assert ( abs(ref.direction["z"] - dut.direction.z) < 0.0001 abs(abs(ref.direction["z"]) - abs(dut.direction.z)) < 0.01 ), "Audio Focus PI Data mismatch in direction z" assert ref.level == dut.level, "Audio Focus PI Data mismatch in level" Loading