void TPCircularBufferProduceAudioBufferList(TPCircularBuffer *buffer, const AudioTimeStamp *inTimestamp) {
    int32_t availableBytes;
    TPCircularBufferABLBlockHeader *block = (TPCircularBufferABLBlockHeader*)TPCircularBufferHead(buffer, &availableBytes);
    
    assert(block);
    
    assert(!((unsigned long)block & 0xF) /* Beware unaligned accesses */);
    
    assert(block->bufferList.mBuffers[0].mDataByteSize > 0);
    
    if ( inTimestamp ) {
        memcpy(&block->timestamp, inTimestamp, sizeof(AudioTimeStamp));
    }
    
    UInt32 calculatedLength = (UInt32)(((char*)block->bufferList.mBuffers[block->bufferList.mNumberBuffers-1].mData + block->bufferList.mBuffers[block->bufferList.mNumberBuffers-1].mDataByteSize) - (char*)block);

    // Make sure whole buffer (including timestamp and length value) is 16-byte aligned in length
    calculatedLength = (UInt32)align16byte(calculatedLength);
    
    assert(calculatedLength <= block->totalLength && calculatedLength <= availableBytes);
    
    block->totalLength = calculatedLength;
    
    TPCircularBufferProduce(buffer, block->totalLength);
}
Example #2
0
void
ca_Play(audio_output_t * p_aout, block_t * p_block)
{
    struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;

    /* Do the channel reordering */
    if (p_sys->chans_to_reorder)
       aout_ChannelReorder(p_block->p_buffer, p_block->i_buffer,
                           p_sys->chans_to_reorder, p_sys->chan_table,
                           VLC_CODEC_FL32);

    /* move data to buffer */
    while (!TPCircularBufferProduceBytes(&p_sys->circular_buffer,
                                         p_block->p_buffer, p_block->i_buffer))
    {
        if (atomic_load_explicit(&p_sys->b_paused, memory_order_relaxed))
        {
            msg_Warn(p_aout, "dropping block because the circular buffer is "
                     "full and paused");
            break;
        }

        /* Try to play what we can */
        int32_t i_avalaible_bytes;
        TPCircularBufferHead(&p_sys->circular_buffer, &i_avalaible_bytes);
        assert(i_avalaible_bytes >= 0);
        if (unlikely((size_t) i_avalaible_bytes >= p_block->i_buffer))
            continue;

        bool ret =
            TPCircularBufferProduceBytes(&p_sys->circular_buffer,
                                         p_block->p_buffer, i_avalaible_bytes);
        assert(ret == true);
        p_block->p_buffer += i_avalaible_bytes;
        p_block->i_buffer -= i_avalaible_bytes;

        /* Wait for the render buffer to play the remaining data */
        const mtime_t i_frame_us =
            FramesToUs(p_sys, BytesToFrames(p_sys, p_block->i_buffer));
        msleep(i_frame_us / 2);
    }

    unsigned i_underrun_size = atomic_exchange(&p_sys->i_underrun_size, 0);
    if (i_underrun_size > 0)
        msg_Warn(p_aout, "underrun of %u bytes", i_underrun_size);

    block_Release(p_block);
}
void TPCircularBufferProduceAudioBufferList(TPCircularBuffer *buffer) {
    int32_t availableBytes;
    AudioTimeStamp *timestamp = (AudioTimeStamp*)TPCircularBufferHead(buffer, &availableBytes);
    UInt32 *totalLengthInBytes = (UInt32*)(timestamp+1);

    AudioBufferList *list = (AudioBufferList*)(totalLengthInBytes+1);
    UInt32 calculatedLength = ((char*)list->mBuffers[list->mNumberBuffers-1].mData + list->mBuffers[list->mNumberBuffers-1].mDataByteSize) - (char*)list;
    assert(calculatedLength < *totalLengthInBytes && sizeof(AudioTimeStamp)+sizeof(UInt32)+calculatedLength <= availableBytes);
    
    *totalLengthInBytes = calculatedLength;
    
    TPCircularBufferProduce(buffer, 
                            sizeof(AudioTimeStamp) +
                            sizeof(UInt32) +
                            *totalLengthInBytes);
}
UInt32 TPCircularBufferGetAvailableSpace(TPCircularBuffer *buffer, const AudioStreamBasicDescription *audioFormat) {
    // Look at buffer head; make sure there's space for the block metadata
    int32_t availableBytes;
    TPCircularBufferABLBlockHeader *block = (TPCircularBufferABLBlockHeader*)TPCircularBufferHead(buffer, &availableBytes);
    if ( !block ) return 0;
    assert(!((unsigned long)block & 0xF) /* Beware unaligned accesses */);
    
    // Now find out how much 16-byte aligned audio we can store in the space available
    int numberOfBuffers = audioFormat->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? audioFormat->mChannelsPerFrame : 1;
    char * endOfBuffer = (char*)block + availableBytes;
    char * dataPtr = (char*)align16byte((long)(&block->bufferList + sizeof(AudioBufferList)+((numberOfBuffers-1)*sizeof(AudioBuffer))));
    if ( dataPtr >= endOfBuffer ) return 0;
    int32_t availableAudioBytes = (int)(endOfBuffer - dataPtr);
    
    int32_t availableAudioBytesPerBuffer = availableAudioBytes / numberOfBuffers;
    availableAudioBytesPerBuffer -= (availableAudioBytesPerBuffer % (16-1));
    
    return availableAudioBytesPerBuffer > 0 ? availableAudioBytesPerBuffer / audioFormat->mBytesPerFrame : 0;
}
bool TPCircularBufferCopyAudioBufferList(TPCircularBuffer *buffer, const AudioBufferList *bufferList, const AudioTimeStamp *inTimestamp) {
    int bufferListSize = sizeof(AudioBufferList) + ((bufferList->mNumberBuffers-1) * sizeof(AudioBuffer));
    
    int32_t availableBytes;
    AudioTimeStamp *timestamp = (AudioTimeStamp*)TPCircularBufferHead(buffer, &availableBytes);
    if ( availableBytes < sizeof(AudioTimeStamp) + bufferListSize ) return false;
    
    // Store timestamp, followed by buffer list
    if ( inTimestamp ) {
        *timestamp = *inTimestamp;
    } else {
        memset(timestamp, 0, sizeof(AudioTimeStamp));
    }
    
    UInt32 *totalLengthInBytes = (UInt32*)(timestamp+1);
    
    AudioBufferList *list = (AudioBufferList*)(totalLengthInBytes+1);
    
    memcpy(list, bufferList, bufferListSize);
    
    char *dataPtr = (char*)list + bufferListSize;
    for ( int i=0; i<bufferList->mNumberBuffers; i++ ) {
        // Find the next 16-byte aligned memory area
        dataPtr = (char*)align16bit((long)dataPtr);
        
        if ( (dataPtr + bufferList->mBuffers[i].mDataByteSize) - (char*)timestamp > availableBytes ) {
            return false;
        }
        
        assert(bufferList->mBuffers[i].mData != NULL);
        
        list->mBuffers[i].mData = dataPtr;
        memcpy(dataPtr, bufferList->mBuffers[i].mData, bufferList->mBuffers[i].mDataByteSize);
        dataPtr += bufferList->mBuffers[i].mDataByteSize;
    }
    
    *totalLengthInBytes = (dataPtr-(char*)list);
    
    TPCircularBufferProduce(buffer, dataPtr-(char*)timestamp);
    
    return true;
}
AudioBufferList *TPCircularBufferPrepareEmptyAudioBufferList(TPCircularBuffer *buffer, int numberOfBuffers, int bytesPerBuffer, const AudioTimeStamp *inTimestamp) {
    int bufferListSize = sizeof(AudioBufferList) + ((numberOfBuffers-1) * sizeof(AudioBuffer));
    
    int32_t availableBytes;
    AudioTimeStamp *timestamp = (AudioTimeStamp*)TPCircularBufferHead(buffer, &availableBytes);
    if ( availableBytes < sizeof(AudioTimeStamp) + sizeof(UInt32) + bufferListSize ) return NULL;
    
    // Store timestamp, followed by a UInt32 defining the number of bytes from the start of the buffer list to the end of the segment, then the buffer list
    if ( inTimestamp ) {
        *timestamp = *inTimestamp;
    } else {
        memset(timestamp, 0, sizeof(AudioTimeStamp));
    }
    
    UInt32 *totalLengthInBytes = (UInt32*)(timestamp+1);
    
    AudioBufferList *list = (AudioBufferList*)(totalLengthInBytes+1);
    
    memset(list, 0, bufferListSize);
    
    list->mNumberBuffers = numberOfBuffers;
    
    char *dataPtr = (char*)list + bufferListSize;
    for ( int i=0; i<numberOfBuffers; i++ ) {
        // Find the next 16-byte aligned memory area
        dataPtr = (char*)align16bit((long)dataPtr);
        
        if ( (dataPtr + bytesPerBuffer) - (char*)timestamp > availableBytes ) {
            return NULL;
        }
        
        list->mBuffers[i].mData = dataPtr;
        list->mBuffers[i].mDataByteSize = bytesPerBuffer;
        list->mBuffers[i].mNumberChannels = 1;
        
        dataPtr += bytesPerBuffer;
    }
    
    *totalLengthInBytes = (dataPtr - (char*)list);
    
    return list;
}
AudioBufferList *TPCircularBufferPrepareEmptyAudioBufferList(TPCircularBuffer *buffer, int numberOfBuffers, int bytesPerBuffer, const AudioTimeStamp *inTimestamp) {
    int32_t availableBytes;
    TPCircularBufferABLBlockHeader *block = (TPCircularBufferABLBlockHeader*)TPCircularBufferHead(buffer, &availableBytes);
    if ( !block || availableBytes < sizeof(TPCircularBufferABLBlockHeader)+((numberOfBuffers-1)*sizeof(AudioBuffer))+(numberOfBuffers*bytesPerBuffer) ) return NULL;
    
    assert(!((unsigned long)block & 0xF) /* Beware unaligned accesses */);
    
    if ( inTimestamp ) {
        memcpy(&block->timestamp, inTimestamp, sizeof(AudioTimeStamp));
    } else {
        memset(&block->timestamp, 0, sizeof(AudioTimeStamp));
    }
    
    memset(&block->bufferList, 0, sizeof(AudioBufferList)+((numberOfBuffers-1)*sizeof(AudioBuffer)));
    block->bufferList.mNumberBuffers = numberOfBuffers;
    
    char *dataPtr = (char*)&block->bufferList + sizeof(AudioBufferList)+((numberOfBuffers-1)*sizeof(AudioBuffer));
    for ( int i=0; i<numberOfBuffers; i++ ) {
        // Find the next 16-byte aligned memory area
        dataPtr = (char*)align16byte((long)dataPtr);
        
        if ( (dataPtr + bytesPerBuffer) - (char*)block > availableBytes ) {
            return NULL;
        }
        
        block->bufferList.mBuffers[i].mData = dataPtr;
        block->bufferList.mBuffers[i].mDataByteSize = bytesPerBuffer;
        block->bufferList.mBuffers[i].mNumberChannels = 1;
        
        dataPtr += bytesPerBuffer;
    }
    
    // Make sure whole buffer (including timestamp and length value) is 16-byte aligned in length
    block->totalLength = (UInt32)align16byte(dataPtr - (char*)block);
    if ( block->totalLength > availableBytes ) {
        return NULL;
    }
    
    return &block->bufferList;
}