From 6abbfbf39bd4f55361109b08b8a9ad0c55246f82 Mon Sep 17 00:00:00 2001 From: Ripinder Singh Date: Mon, 10 Nov 2025 10:23:02 +1100 Subject: [PATCH 1/2] SR codec framesize support in RTP ToC SR byte To estmate the correct frame size of a SR frame in RTP payload, it is important to know the codec's framesize employed in addition to the bitrate. This can be propagated from SDP, this work extends to resolve this info from the ToC byte which makes it easier to parse an rtp dump even if the sdp negotiated codec framesize is not available. Signed-off-by: Ripinder Singh --- apps/decoder.c | 5 +++++ lib_com/options.h | 2 ++ lib_util/ivas_rtp_api.h | 9 ++++++--- lib_util/ivas_rtp_payload.c | 24 ++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 889fde4798..87c431c341 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3442,7 +3442,11 @@ static ivas_error decodeVoIP( #ifdef IVAS_RTPDUMP IVAS_RTP ivasRtp = { 0 }; IVAS_RTP srRtp = { 0 }; +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + IVAS_RTP_SR_INFO srInfo = { true, false, 0, 20, IVAS_SR_TRANSPORT_LCLD }; +#else IVAS_RTP_SR_INFO srInfo = { true, false, 0, IVAS_SR_TRANSPORT_LCLD }; +#endif int32_t initialTsOffsetSystemAndRTP = 0; #else FILE *f_rtpstream = NULL; @@ -4125,6 +4129,7 @@ static ivas_error decodeVoIP( { srInfo.bitrateKbps = splitRendBits->bits_written * 1000 / splitRendBits->codec_frame_size_ms; srInfo.codec = ( splitRendBits->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS ) ? IVAS_SR_TRANSPORT_LC3PLUS : IVAS_SR_TRANSPORT_LCLD; + srInfo.codecFrameSizeMs = (uint32_t) splitRendBits->codec_frame_size_ms; if ( ( error = IVAS_RTP_WriteNextFrame( &srRtp, splitRendBits->bits_buf, &srInfo, (int16_t) splitRendBits->bits_written, false, false ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError %s while pushing SR audio bitstream to RTP pack\n", ivas_error_to_string( error ) ); diff --git a/lib_com/options.h b/lib_com/options.h index 1038a3c7ff..ad5111c39a 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -167,6 +167,8 @@ #define ISM_PI_DATA /* Add reading and packing/unpacking of ISM PI data */ #define REVERSE_ISM_PI_DATA /* Add reading and packing/unpacking of reverse ISM PI data */ #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*/ + /* ################### Start BE switches ################################# */ /* only BE switches wrt selection floating point code */ diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index 8e551c5ffc..a296e8ab39 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -272,9 +272,12 @@ typedef enum typedef struct { - bool valid; /* Valid Split Rendering Info for/in the ToC */ - bool diegetic; /* SR content digetic */ - uint32_t bitrateKbps; /* SR bitrate in kbps */ + bool valid; /* Valid Split Rendering Info for/in the ToC */ + bool diegetic; /* SR content digetic */ + uint32_t bitrateKbps; /* SR bitrate in kbps */ +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + uint32_t codecFrameSizeMs; /* SR transport codec framesize in ms (5/10/20) */ +#endif IVAS_RTP_SR_TRANSPORT codec; /* SR Transport Codec used*/ } IVAS_RTP_SR_INFO; #endif /* RTP_S4_251135_CR26253_0016_REV1 */ diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 98846adf84..83d163b544 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -852,7 +852,16 @@ static ivas_error getSRToCByte( uint8_t *tocByte /* o : toc byte 2 */ ) { +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + uint8_t bitIdx, codecId, digetic, codecFrameSize; + + if ( srInfo->codecFrameSizeMs != 5 && srInfo->codecFrameSizeMs != 10 && srInfo->codecFrameSizeMs != 20 ) + { + return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported codec framesize for SR provided" ); + } +#else uint8_t bitIdx, codecId, digetic; +#endif if ( srInfo->bitrateKbps < 256000 || srInfo->bitrateKbps > 512000 ) { return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Unsupported bitrate for SR" ); @@ -862,7 +871,12 @@ static ivas_error getSRToCByte( codecId = (uint8_t) srInfo->codec; digetic = srInfo->diegetic ? 1 : 0; +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + codecFrameSize = ( srInfo->codecFrameSizeMs == 20 ) ? 3 : (uint8_t) ( srInfo->codecFrameSizeMs / 5 ); + *tocByte = ( digetic << 6 ) | ( codecId << 5 ) | ( bitIdx << 3 ) | ( codecFrameSize << 1 ); +#else *tocByte = ( digetic << 6 ) | ( codecId << 5 ) | ( bitIdx << 3 ); +#endif return IVAS_ERR_OK; } @@ -1474,6 +1488,9 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy if ( nBytes < payload->length ) { uint8_t SR_BR; +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + static const uint8_t codecFrameSizeMap[4] = { 0, 5, 10, 20 }; +#endif byte = payload->buffer[nBytes++]; SR_BR = ( byte >> 3 ) & MASK_2BIT; if ( SR_BR == 0 ) @@ -1484,7 +1501,14 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy toc->srInfo.diegetic = ( byte >> 6 ) & MASK_1BIT; toc->srInfo.codec = IVAS_SR_TRANSPORT_LCLD + ( ( byte >> 5 ) & MASK_1BIT ); toc->srInfo.bitrateKbps = ( SR_BR + 1 ) * 128000u; +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + toc->srInfo.codecFrameSizeMs = codecFrameSizeMap[( byte >> 1 ) & MASK_2BIT]; + /* SDP negotiated codecFrameSizeMs must match ToC codecFrameSizeMs */ + assert( toc->srInfo.codecFrameSizeMs == srCodecFrameSizeMs ); + toc->auNumBits = toc->srInfo.bitrateKbps * toc->srInfo.codecFrameSizeMs / 1000; +#else toc->auNumBits = toc->srInfo.bitrateKbps * srCodecFrameSizeMs / 1000; +#endif } else { -- GitLab From 3cd7d7a26f1e026c8296e7c120cca5838d14ab8e Mon Sep 17 00:00:00 2001 From: Ripinder Singh Date: Mon, 10 Nov 2025 19:06:00 +1100 Subject: [PATCH 2/2] Use SR framesize signalling in RTP ToC for post-renderer initialization * Add a preview of the RTP stream to extract the codec, and framesize fields as reported in the RTP SR ToC byte * Override the user provided renderer framesize to codec framesize in rtp cases to prevent bitstream read errors due to unparsed padding in the end of ISAR bitstream. * Code formatting changes * Eof early exit without throwing error in rtp for post renderer * Remove the external SR CodecFrameSize from RTP API SR CodecFrameSize read from RTP stream, hence no need to be set externally. Signed-off-by: Ripinder Singh --- apps/decoder.c | 8 ++++ apps/isar_post_rend.c | 77 +++++++++++++++++++++++++++++++++++++ lib_util/ivas_rtp_api.h | 2 + lib_util/ivas_rtp_file.c | 4 ++ lib_util/ivas_rtp_file.h | 2 + lib_util/ivas_rtp_payload.c | 6 ++- 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 87c431c341..4e5972ae96 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -2074,12 +2074,16 @@ static ivas_error initOnFirstGoodFrame( fParamsSR = fopen( srParamsFile, "w" ); if ( NULL != fParamsSR ) { +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + fprintf( fParamsSR, "DOF = %d;\nLC3PLUS_HIGHRES = %d;\n", poseCorrection, lc3plusHighRes ); +#else fprintf( fParamsSR, "CODEC = %s;\nDOF = %d;\nFRAMESIZE = %d;\nRENDERSIZE = %d;\nLC3PLUS_HIGHRES = %d;\n", splitRendCodec == ISAR_SPLIT_REND_CODEC_LC3PLUS ? "LC3PLUS" : "LCLD", poseCorrection, splitRendCodecFrameSizeMs, splitRendIsarFrameSizeMs, lc3plusHighRes ); +#endif fclose( fParamsSR ); fParamsSR = NULL; } @@ -3278,8 +3282,10 @@ static ivas_error printBitstreamInfoVoip( case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: #ifdef IVAS_RTPDUMP +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, 0, arg.inputBitstreamFilename, arg.piOutputFilename, arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL, arg.outputWavFilename ) ) != IVAS_ERR_OK ) +#endif #else if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename, arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL, arg.outputWavFilename ) ) != IVAS_ERR_OK ) #endif @@ -3526,8 +3532,10 @@ static ivas_error decodeVoIP( case IVAS_DEC_INPUT_FORMAT_RTPDUMP: case IVAS_DEC_INPUT_FORMAT_RTPDUMP_HF: #ifdef IVAS_RTPDUMP +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, 0, arg.inputBitstreamFilename, arg.piOutputFilename, arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL, arg.outputWavFilename ) ) != IVAS_ERR_OK ) +#endif #else if ( ( error = IVAS_RTP_READER_Init( &ivasRtp, arg.inputBitstreamFilename, arg.piOutputFilename, arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL, arg.outputWavFilename ) ) != IVAS_ERR_OK ) #endif diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index 7d8fd0939f..96dc9b827f 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -749,6 +749,9 @@ static void trim( char *str ) static ivas_error parseSRParamsFile( const char *srParamsFilePath, +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + const char *rtpFilePath, +#endif ISAR_SPLIT_REND_CODEC *codec, ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, int16_t *codec_frame_size_ms, @@ -775,6 +778,24 @@ static ivas_error parseSRParamsFile( trim( key ); trim( value ); +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + if ( 0 == strncmp( key, "DOF", 3 ) ) + { + int val = atoi( value ); + if ( val == 0 || val == 1 ) + { + *poseCorrection = ( val == 0 ) ? ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE : ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB; + } + } + else if ( 0 == strncmp( key, "LC3PLUS_HIGHRES", 15 ) ) + { + int val = atoi( value ); + if ( val == 0 || val == 1 ) + { + *lc3plusHighRes = (int16_t) val; + } + } +#else if ( 0 == strncmp( key, "CODEC", 5 ) ) { *codec = ( 0 == strncmp( value, "LCLD", 4 ) ) ? ISAR_SPLIT_REND_CODEC_LCLD : *codec; @@ -812,10 +833,52 @@ static ivas_error parseSRParamsFile( *lc3plusHighRes = (int16_t) val; } } +#endif } } fclose( fParamSR ); + +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + { + /* Peek the RTP stream to ascertain the codec and codec_frame_size */ + ivas_error error = IVAS_ERR_OK; + IVAS_RTP srRtp = { 0 }; + if ( ( error = IVAS_RTP_READER_Init( &srRtp, rtpFilePath, NULL, false, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "error in IVAS_RTP_READER_Init() for sr RTP peek: %d\n", error ); + return error; + } + + /* read a frame */ + while ( 1 ) + { + bool qBit = false; + IVAS_RTP_SR_INFO srInfo = { 0 }; + uint8_t au[( IVAS_MAX_BITS_PER_FRAME + 7 ) >> 3]; + int16_t auSize = 0; + uint16_t rtpSequenceNumber = 0; + uint32_t rtpTimeStamp = 0, nextPacketRcvTime_ms = 0; + + error = IVAS_RTP_ReadNextFrame( &srRtp, au, &auSize, &rtpTimeStamp, &rtpSequenceNumber, &nextPacketRcvTime_ms, &srInfo, &qBit ); + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_RTP_ReadNextFrame, error code: %d\n", error ); + return error; + } + + if ( srInfo.valid ) + { + *codec = ( srInfo.codec == IVAS_SR_TRANSPORT_LCLD ) ? ISAR_SPLIT_REND_CODEC_LCLD : ISAR_SPLIT_REND_CODEC_LC3PLUS; + *codec_frame_size_ms = (int16_t) srInfo.codecFrameSizeMs; + *isar_frame_size_ms = *codec_frame_size_ms; /* for rtp force codec framesize as isar renderer frame size */ + break; + } + } + IVAS_RTP_Term( &srRtp ); + } +#endif + return IVAS_ERR_OK; } #endif @@ -949,6 +1012,9 @@ int main( if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].srRtp ) ) { error = parseSRParamsFile( args.srParamsFilePath, +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + args.inputFilePath, +#endif &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, @@ -960,12 +1026,20 @@ int main( goto cleanup; } +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE if ( ( error = IVAS_RTP_READER_Init( &srRTP, (uint32_t) bitsBuffer.config.codec_frame_size_ms, args.inputFilePath, NULL, false, NULL ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_RTP_READER_Init( &srRTP, args.inputFilePath, NULL, false, NULL ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "error in IVAS_RTP_READER_Init(): %d\n", error ); goto cleanup; } audioReader = NULL; +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + /* Force owerwrite of command line provided rendersize to align with codec frame size */ + args.render_framesize = bitsBuffer.config.isar_frame_size_ms / 5; +#endif } /*if split renderer is running in post renderer mode*/ else if ( ( args.inConfig.numBinBuses > 0 ) && ( args.inConfig.binBuses[0].audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ) @@ -1195,6 +1269,9 @@ int main( if ( error == IVAS_ERR_END_OF_FILE ) { numSamplesRead = 0; +#ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE + break; +#endif } else { diff --git a/lib_util/ivas_rtp_api.h b/lib_util/ivas_rtp_api.h index a296e8ab39..78fb6144b7 100644 --- a/lib_util/ivas_rtp_api.h +++ b/lib_util/ivas_rtp_api.h @@ -423,9 +423,11 @@ typedef struct IVAS_RTP_UNPACK *IVAS_RTP_UNPACK_HANDLE; /* rtp unpacker handle t typedef struct { uint32_t maxFramesPerPacket; /* maximum no of frame per packet expected during the session */ +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 uint32_t srCodecFrameSizeMs; /* split rendering transport codec frame size in ms (5/10/20) set by sdp negotiation */ #endif +#endif } IVAS_RTP_UNPACK_CONFIG; /* Open an instance of the RTP unpacker and return a handle to rtp unpacker on success diff --git a/lib_util/ivas_rtp_file.c b/lib_util/ivas_rtp_file.c index c766e9162c..65f9fec15d 100644 --- a/lib_util/ivas_rtp_file.c +++ b/lib_util/ivas_rtp_file.c @@ -871,8 +871,10 @@ ivas_error IVAS_RTP_WRITER_Init( ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, /* i/o : IVAS RTP File reader handle */ +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 uint32_t srCodecFrameSizeMs, /* i : SR Codec Framesize in ms */ +#endif #endif const char *inputBitstreamFilename, /* i : Input rtpdump filename */ const char *piOutputFilename, /* i : Output PI data json filename */ @@ -885,7 +887,9 @@ ivas_error IVAS_RTP_READER_Init( memset( rtp, 0, sizeof( IVAS_RTP ) ); rtp->unpackCfg.maxFramesPerPacket = IVAS_MAX_FRAMES_PER_RTP_PACKET; +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE rtp->unpackCfg.srCodecFrameSizeMs = srCodecFrameSizeMs; +#endif rtp->rtpPacket.buffer = rtp->packet; rtp->rtpPacket.capacity = sizeof( rtp->packet ); diff --git a/lib_util/ivas_rtp_file.h b/lib_util/ivas_rtp_file.h index 70f8c99f0e..684903e175 100644 --- a/lib_util/ivas_rtp_file.h +++ b/lib_util/ivas_rtp_file.h @@ -75,8 +75,10 @@ ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilen #else ivas_error IVAS_RTP_WRITER_Init( IVAS_RTP *rtp, const char *outputBitstreamFilename, uint32_t numFramesPerPacket ); #endif +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, uint32_t srCodecFrameSizeMs, const char *inputBitstreamFilename, const char *piOutputFilename, bool isExtOutput, const char *outputWavFilename ); +#endif #else ivas_error IVAS_RTP_READER_Init( IVAS_RTP *rtp, const char *inputBitstreamFilename, const char *piOutputFilename, bool isExtOutput, const char *outputWavFilename ); #endif diff --git a/lib_util/ivas_rtp_payload.c b/lib_util/ivas_rtp_payload.c index 83d163b544..0398d9ce40 100644 --- a/lib_util/ivas_rtp_payload.c +++ b/lib_util/ivas_rtp_payload.c @@ -1426,8 +1426,10 @@ static uint32_t parseSubsequentEByte( const IVAS_DATA_BUFFER *payload, uint32_t return nBytes; } +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc, uint32_t maxNumberOfToCBytes, uint32_t srCodecFrameSizeMs ) +#endif #else static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBytes, uint32_t *numFrames, TOC_INFO *toc, uint32_t maxNumberOfToCBytes ) #endif @@ -1503,8 +1505,6 @@ static ivas_error parseToCByte( const IVAS_DATA_BUFFER *payload, uint32_t *numBy toc->srInfo.bitrateKbps = ( SR_BR + 1 ) * 128000u; #ifdef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE toc->srInfo.codecFrameSizeMs = codecFrameSizeMap[( byte >> 1 ) & MASK_2BIT]; - /* SDP negotiated codecFrameSizeMs must match ToC codecFrameSizeMs */ - assert( toc->srInfo.codecFrameSizeMs == srCodecFrameSizeMs ); toc->auNumBits = toc->srInfo.bitrateKbps * toc->srInfo.codecFrameSizeMs / 1000; #else toc->auNumBits = toc->srInfo.bitrateKbps * srCodecFrameSizeMs / 1000; @@ -1691,8 +1691,10 @@ ivas_error IVAS_RTP_UNPACK_PushPayload( /* Unpack the ToC Bytes => Extract number of frames in packet */ +#ifndef RTP_SR_CODEC_FRAME_SIZE_IN_TOC_BYTE #ifdef RTP_S4_251135_CR26253_0016_REV1 error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ), hUnpack->initConfig.srCodecFrameSizeMs ); +#endif #else error = parseToCByte( payload, &nBytes, &numFrames, toc, sizeof( toc ) / sizeof( toc[0] ) ); #endif -- GitLab