iosobjective-caudioextaudiofileread

Looping AAC file with ExtAudioFileRead - bug?


Reading audio files on iOS with ExtAudioFileRead, it seems that reaching eof completely freezes the reader… Example, assumes _abl AudioBufferList and _eaf ExtendedAudioFileRef are allocated and correctly configured:

- ( void )testRead
{
    UInt32 requestedFrames = 1024;
    UInt32 numFrames = requestedFrames;
    OSStatus error = 0;

    error = ExtAudioFileRead( _eaf, &numFrames, _abl );

    if( numFrames < requestedFrames ) //eof, want to read enough frames from the beginning of the file to reach requestedFrames and loop gaplessly
    {
         requestedFrames = requestedFrames - numFrames;
         numFrames = requestedFrames;
         // move some pointers in _abl's buffers to write at the correct offset
         error = ExtAudioFileSeek( _eaf, 0 );
         error = ExtAudioFileRead( _eaf, &numFrames, _abl );
         if( numFrames != requestedFrames ) //Now this call always sets numFrames to the same value as the previous read call...
         {
             NSLog( @"Oh no!" );
         }
    }
}

No errors, always the same behavior, exactly as if the reader was stuck at the end of the file. ExtAudioFileTell confirms the requested seek, btw. Also tried keeping track of the position in the file to request only the number of frames available at eof, same result: as soon as the last packet is read, seek seems to have no effect.

Happily seeking in other circumstances.

Bug? Feature? Imminent face palm? I'd very much appreciate any help in solving this!

I'm testing this on an iPad 3 ( iOS7.1 ).

Cheers,

Gregzo


Solution

  • Woozah!

    Gotcha, evil AudioBufferList tinkerer.

    So, in addition to informing the client as to the number of frames actually read, ExtAudioFileRead also sets the AudioBufferList's AudioBuffers mDataByteSize to the number of bytes read. As it clamps reading to that value, not resetting it at eof results in perpetually getting less frames than asking.

    So, once eof is reached, simply reset the abl's buffers size.

    -( void )resetABLBuffersSize: ( AudioBufferList * )alb size: ( UInt32 )size
    {
         AudioBuffer * buffer;
         UInt32 i;
    
         for( i = 0; i < abl->mNumberBuffers; i++ )
         {
             buffer = &( abl->mBuffers[ i ] );
             buffer->mDataByteSize = size;
         }
    }
    

    Shouldn't this be documented? The official docs only describe the AudioBufferList parameter as such: One or more buffers into which the audio data is read.

    Cheers,

    Gregzo