Commit b9991916 authored by Vladimir Malenovsky's avatar Vladimir Malenovsky
Browse files

wrap both split-coded audio and ISAR metadata in the flushing API

parent 39102f53
Loading
Loading
Loading
Loading
Loading
+71 −10
Original line number Diff line number Diff line
@@ -2916,17 +2916,42 @@ static ivas_error decodeG192(
            }
        }

#ifdef FIX_1342_PROPER_FLUSH_IN_SR
        if ( isSplitRend )
        {
            if ( ( error = IVAS_DEC_FlushSplitBinaural( hIvasDec, (void *) pcmBuf, splitRendBits, &nSamplesFlushed ) ) != IVAS_ERR_OK )
            {
                fprintf( stderr, "\nError in IVAS_DEC_FlushSplitBinaural: %s\n", IVAS_DEC_GetErrorMessage( error ) );
                goto cleanup;
            }

            if ( nSamplesFlushed > 0 )
            {
                if ( split_rend_write_bitstream_to_file( splitRendWriter, splitRendBits->bits_buf, &splitRendBits->bits_read, &splitRendBits->bits_written ) != IVAS_ERR_OK )
                {
                    fprintf( stderr, "\nUnable to write to bitstream file!\n" );
                    goto cleanup;
                }
            }
        }
        else
        {
#endif
            /* flush remaining audio */
            if ( ( error = IVAS_DEC_Flush( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, &nSamplesFlushed ) ) != IVAS_ERR_OK )
            {
                fprintf( stderr, "\nError in IVAS_DEC_VoIP_Flush: %s\n", IVAS_DEC_GetErrorMessage( error ) );
                goto cleanup;
            }
#ifdef FIX_1342_PROPER_FLUSH_IN_SR
        }
#endif

#ifdef FIX_1342_PROPER_FLUSH_IN_SR
        if ( !isSplitCoded )
        if ( nSamplesFlushed > 0 && !isSplitCoded )
        {
#endif

            /* Write current frame */
            if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, nSamplesFlushed * nOutChannels ) ) != IVAS_ERR_OK )
            {
@@ -2936,7 +2961,6 @@ static ivas_error decodeG192(
#ifdef FIX_1342_PROPER_FLUSH_IN_SR
        }
#endif

        /* Write ISM metadata to external file(s) */
        if ( decodedGoodFrame && arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL )
        {
@@ -3852,12 +3876,49 @@ static ivas_error decodeVoIP(

    int16_t nSamplesFlushed = 0;

    if ( isSplitRend )
    {
        if ( ( error = IVAS_DEC_FlushSplitBinaural( hIvasDec, (void *) pcmBuf, splitRendBits, &nSamplesFlushed ) ) != IVAS_ERR_OK )
        {
            fprintf( stderr, "\nError in IVAS_DEC_FlushSplitBinaural: %s\n", IVAS_DEC_GetErrorMessage( error ) );
            goto cleanup;
        }

        if ( nSamplesFlushed > 0 )
        {
            if ( !srRtp.hPack )
            {
                if ( split_rend_write_bitstream_to_file( splitRendWriter, splitRendBits->bits_buf, &splitRendBits->bits_read, &splitRendBits->bits_written ) != IVAS_ERR_OK )
                {
                    fprintf( stderr, "\nUnable to write to bitstream file!\n" );
                    goto cleanup;
                }
            }
            else
            {
                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 ) );
                    goto cleanup;
                }
                splitRendBits->bits_written = 0;
                splitRendBits->bits_read = 0;
            }
        }
    }
    else
    {
        /* flush remaining audio */
        if ( ( error = IVAS_DEC_Flush( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, &nSamplesFlushed ) ) != IVAS_ERR_OK )
        {
            fprintf( stderr, "\nError in IVAS_DEC_VoIP_Flush: %s\n", IVAS_DEC_GetErrorMessage( error ) );
            goto cleanup;
        }
    }

    if ( nSamplesFlushed && !isSplitCoded )
    {
+124 −54
Original line number Diff line number Diff line
@@ -2267,6 +2267,129 @@ ivas_error IVAS_DEC_GetSplitBinauralBitstream(
    return IVAS_ERR_OK;
}

#ifdef FIX_1342_PROPER_FLUSH_IN_SR
static ivas_error ivas_dec_flush_split_binaural_internal(
    IVAS_DEC_HANDLE hIvasDec,                 /* i/o: IVAS decoder handle                                       */
    void *pcmBuf_out,                         /* o  : output synthesis signal for BINAURAL_SPLIT_PCM            */
    ISAR_SPLIT_REND_BITS_DATA *splitRendBits, /* o  : output split rendering bits, may be NULL to discard       */
    int16_t *nOutSamples                      /* o  : number of samples per channel flushed                     */
)
{
    Decoder_Struct *st_ivas;
    ivas_error error;
    float head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES][L_FRAME48k];
    float *p_head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES];
    ISAR_SPLIT_REND_BITS_DATA localSplitRendBits;
    uint8_t localSplitRendBitsBuf[ISAR_MAX_SPLIT_REND_BITS_BUFFER_SIZE_IN_BYTES];
    bool needNewFrame;
    int16_t i;

    if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL || nOutSamples == NULL )
    {
        return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    }

    st_ivas = hIvasDec->st_ivas;

    if ( is_split_rendering_enabled( st_ivas->hDecoderConfig, st_ivas->hRenderConfig ) == 0 )
    {
        return IVAS_ERR_WRONG_PARAMS;
    }

    if ( splitRendBits == NULL )
    {
        localSplitRendBits.bits_buf = localSplitRendBitsBuf;
        localSplitRendBits.bits_read = 0;
        localSplitRendBits.bits_written = 0;
        localSplitRendBits.buf_len = ISAR_MAX_SPLIT_REND_BITS_BUFFER_SIZE_IN_BYTES;
        localSplitRendBits.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
        localSplitRendBits.pose_correction = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
        localSplitRendBits.codec_frame_size_ms = 0;
        localSplitRendBits.isar_frame_size_ms = 0;
        localSplitRendBits.lc3plus_highres = 0;
        splitRendBits = &localSplitRendBits;
    }
    else
    {
        splitRendBits->bits_read = 0;
        splitRendBits->bits_written = 0;
    }

    if ( st_ivas->ivas_format == MONO_FORMAT || hIvasDec->nSamplesAvailableNext == 0 )
    {
        *nOutSamples = 0;
        return IVAS_ERR_OK;
    }

    for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i )
    {
        /* Zero-initialise so that ivas_limiter_dec() doesnt read uninitialised memory
           when the ring buffer provides fewer samples than the nominal frame size */
        set_zero( head_pose_buf[i], L_FRAME48k );
        p_head_pose_buf[i] = head_pose_buf[i];
    }

    if ( ( error = isar_render_poses( hIvasDec, isar_get_frame_size( st_ivas ), nOutSamples, &needNewFrame ) ) != IVAS_ERR_OK )
    {
        return error;
    }

    if ( !hIvasDec->hasBeenFedFirstGoodFrame || *nOutSamples <= 0 )
    {
        return IVAS_ERR_OK;
    }

    /* Split-coded flush path currently assumes a full frame of ISAR metadata generation.
       In case of a shorter trailing frame (ee.g. in VoIP flush), this can break the
       LCLD encoder assumptions and lead to a crash. Therefore, we skip
       such cases. */
    if ( st_ivas->hDecoderConfig->output_config != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
         *nOutSamples < isar_get_frame_size( st_ivas ) )
    {
        *nOutSamples = 0;
        splitRendBits->bits_read = 0;
        splitRendBits->bits_written = 0;
        return IVAS_ERR_OK;
    }

    if ( ( error = isar_generate_metadata_and_bitstream( st_ivas, p_head_pose_buf, *nOutSamples, splitRendBits ) ) != IVAS_ERR_OK )
    {
        return error;
    }

    if ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM && pcmBuf_out != NULL )
    {
#ifndef DISABLE_LIMITER
        ivas_limiter_dec( st_ivas->hLimiter, p_head_pose_buf, st_ivas->hDecoderConfig->nchan_out, *nOutSamples, st_ivas->BER_detect );
#endif
        ivas_syn_output( p_head_pose_buf, *nOutSamples, st_ivas->hDecoderConfig->nchan_out, (int16_t *) pcmBuf_out );
    }

    return IVAS_ERR_OK;
}


/*---------------------------------------------------------------------*
 * IVAS_DEC_FlushSplitBinaural( )
 *
 * Flush split-rendering audio and metadata/bitstream.
 *---------------------------------------------------------------------*/

ivas_error IVAS_DEC_FlushSplitBinaural(
    IVAS_DEC_HANDLE hIvasDec,                 /* i/o: IVAS decoder handle                                       */
    void *pcmBuf,                             /* o  : output synthesis signal for BINAURAL_SPLIT_PCM            */
    ISAR_SPLIT_REND_BITS_DATA *splitRendBits, /* o  : output split rendering bits                               */
    int16_t *nSamplesFlushed                  /* o  : number of samples per channel written to output buffer    */
)
{
    if ( splitRendBits == NULL )
    {
        return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    }

    return ivas_dec_flush_split_binaural_internal( hIvasDec, pcmBuf, splitRendBits, nSamplesFlushed );
}
#endif

/*---------------------------------------------------------------------*
 * ivas_dec_setup_all()
@@ -4346,60 +4469,7 @@ ivas_error IVAS_DEC_Flush(
#ifdef FIX_1342_PROPER_FLUSH_IN_SR
        if ( is_split_rendering_enabled( hIvasDec->st_ivas->hDecoderConfig, hIvasDec->st_ivas->hRenderConfig ) )
        {
            int16_t i, nOutSamples = 0;
            bool needNewFrame;
            const int16_t splitFrameSize = isar_get_frame_size( hIvasDec->st_ivas );
            float head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES][L_FRAME48k];
            float *p_head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES];

            /* Zero-initialise so that ivas_limiter_dec never reads uninitialised memory
               (e.g. when the ring buffer provides fewer samples than the nominal frame size) */
            for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i )
            {
                set_zero( head_pose_buf[i], L_FRAME48k );
                p_head_pose_buf[i] = head_pose_buf[i];
            }

            /* Render remaining buffered audio into the SR ring buffers using the
               correctly-sized internal float buffer to avoid writing beyond the end of the pcmBuf */
            if ( ( error = isar_render_poses( hIvasDec, splitFrameSize, &nOutSamples, &needNewFrame ) ) != IVAS_ERR_OK )
            {
                return error;
            }

            *nSamplesFlushed = nOutSamples;

            /* Flush the remaining audio output in SR mode.
               For BINAURAL_SPLIT_PCM, generate metadata and binaural PCM from the ring buffer.
               The ISAR metadata output is discarded (flush frames are not written to the metadata file). */
            if ( hIvasDec->st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
                 hIvasDec->hasBeenFedFirstGoodFrame && nOutSamples > 0 )
            {
                Decoder_Struct *st_ivas_flush = hIvasDec->st_ivas;
                ISAR_SPLIT_REND_BITS_DATA flushSplitRendBits;
                uint8_t flushBitsBuf[ISAR_MAX_SPLIT_REND_BITS_BUFFER_SIZE_IN_BYTES];

                flushSplitRendBits.bits_buf = flushBitsBuf;
                flushSplitRendBits.bits_read = 0;
                flushSplitRendBits.bits_written = 0;
                flushSplitRendBits.buf_len = ISAR_MAX_SPLIT_REND_BITS_BUFFER_SIZE_IN_BYTES;
                flushSplitRendBits.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
                flushSplitRendBits.pose_correction = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
                flushSplitRendBits.codec_frame_size_ms = 0;
                flushSplitRendBits.isar_frame_size_ms = 0;
                flushSplitRendBits.lc3plus_highres = 0;

                /* Pop from ring buffer and generate binaural PCM into p_head_pose_buf */
                if ( ( error = isar_generate_metadata_and_bitstream( st_ivas_flush, p_head_pose_buf, nOutSamples, &flushSplitRendBits ) ) != IVAS_ERR_OK )
                {
                    return error;
                }

#ifndef DISABLE_LIMITER
                ivas_limiter_dec( st_ivas_flush->hLimiter, p_head_pose_buf, st_ivas_flush->hDecoderConfig->nchan_out, nOutSamples, st_ivas_flush->BER_detect );
#endif
                ivas_syn_output( p_head_pose_buf, nOutSamples, st_ivas_flush->hDecoderConfig->nchan_out, (int16_t *) pcmBuf );
            }
            error = ivas_dec_flush_split_binaural_internal( hIvasDec, pcmBuf, NULL, nSamplesFlushed );
        }
        else
        {
+9 −0
Original line number Diff line number Diff line
@@ -330,6 +330,15 @@ ivas_error IVAS_DEC_VoIP_GetSplitBinauralBitstream(
    const uint32_t systemTimestamp_ms           /* i  : current system timestamp                                                */
);

#ifdef FIX_1342_PROPER_FLUSH_IN_SR
ivas_error IVAS_DEC_FlushSplitBinaural(
    IVAS_DEC_HANDLE hIvasDec,                   /* i/o: IVAS decoder handle                                                     */
    void *pcmBuf,                               /* o  : output synthesis signal for BINAURAL_SPLIT_PCM                          */
    ISAR_SPLIT_REND_BITS_DATA *splitRendBits,   /* o  : output split rendering bits for flushed audio                           */
    int16_t *nSamplesFlushed                    /* o  : number of samples per channel written to output buffer                  */
);
#endif

ivas_error IVAS_DEC_Flush(
    IVAS_DEC_HANDLE hIvasDec,                   /* i/o: IVAS decoder handle                                                     */
    const int16_t nSamplesPerChannel,           /* i  : number of samples per channel requested to be written to output buffer  */
+2 −2

File changed.

Contains only whitespace changes.