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); }
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; }