--- /dev/null
+//
+// TPCircularBuffer.c
+// Circular/Ring buffer implementation
+//
+// Created by Michael Tyson on 10/12/2011.
+// Copyright 2011-2012 A Tasty Pixel. All rights reserved.
+
+
+#include "TPCircularBuffer.h"
+#include <mach/mach.h>
+#include <stdio.h>
+
+#define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
+static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
+ if ( result != ERR_SUCCESS ) {
+ printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
+ return false;
+ }
+ return true;
+}
+
+bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
+
+ // Keep trying until we get our buffer, needed to handle race conditions
+ int retries = 3;
+ while ( true ) {
+
+ buffer->length = round_page(length); // We need whole page sizes
+
+ // Temporarily allocate twice the length, so we have the contiguous address space to
+ // support a second instance of the buffer directly after
+ vm_address_t bufferAddress;
+ kern_return_t result = vm_allocate(mach_task_self(),
+ &bufferAddress,
+ buffer->length * 2,
+ VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit
+ if ( result != ERR_SUCCESS ) {
+ if ( retries-- == 0 ) {
+ reportResult(result, "Buffer allocation");
+ return false;
+ }
+ // Try again if we fail
+ continue;
+ }
+
+ // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
+ result = vm_deallocate(mach_task_self(),
+ bufferAddress + buffer->length,
+ buffer->length);
+ if ( result != ERR_SUCCESS ) {
+ if ( retries-- == 0 ) {
+ reportResult(result, "Buffer deallocation");
+ return false;
+ }
+ // If this fails somehow, deallocate the whole region and try again
+ vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
+ continue;
+ }
+
+ // Re-map the buffer to the address space immediately after the buffer
+ vm_address_t virtualAddress = bufferAddress + buffer->length;
+ vm_prot_t cur_prot, max_prot;
+ result = vm_remap(mach_task_self(),
+ &virtualAddress, // mirror target
+ buffer->length, // size of mirror
+ 0, // auto alignment
+ 0, // force remapping to virtualAddress
+ mach_task_self(), // same task
+ bufferAddress, // mirror source
+ 0, // MAP READ-WRITE, NOT COPY
+ &cur_prot, // unused protection struct
+ &max_prot, // unused protection struct
+ VM_INHERIT_DEFAULT);
+ if ( result != ERR_SUCCESS ) {
+ if ( retries-- == 0 ) {
+ reportResult(result, "Remap buffer memory");
+ return false;
+ }
+ // If this remap failed, we hit a race condition, so deallocate and try again
+ vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
+ continue;
+ }
+
+ if ( virtualAddress != bufferAddress+buffer->length ) {
+ // If the memory is not contiguous, clean up both allocated buffers and try again
+ if ( retries-- == 0 ) {
+ printf("Couldn't map buffer memory to end of buffer\n");
+ return false;
+ }
+
+ vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
+ vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
+ continue;
+ }
+
+ buffer->buffer = (void*)bufferAddress;
+ buffer->fillCount = 0;
+ buffer->head = buffer->tail = 0;
+
+ return true;
+ }
+ return false;
+}
+
+void TPCircularBufferCleanup(TPCircularBuffer *buffer) {
+ vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2);
+ memset(buffer, 0, sizeof(TPCircularBuffer));
+}
+
+void TPCircularBufferClear(TPCircularBuffer *buffer) {
+ int32_t fillCount;
+ if ( TPCircularBufferTail(buffer, &fillCount) ) {
+ TPCircularBufferConsume(buffer, fillCount);
+ }
+}
--- /dev/null
+//
+// TPCircularBuffer.h
+// Circular/Ring buffer implementation
+//
+// https://github.com/michaeltyson/TPCircularBuffer
+//
+// Created by Michael Tyson on 10/12/2011.
+// Copyright 2011-2012 A Tasty Pixel. All rights reserved.
+//
+//
+// This implementation makes use of a virtual memory mapping technique that inserts a virtual copy
+// of the buffer memory directly after the buffer's end, negating the need for any buffer wrap-around
+// logic. Clients can simply use the returned memory address as if it were contiguous space.
+//
+// The implementation is thread-safe in the case of a single producer and single consumer.
+//
+// Virtual memory technique originally proposed by Philip Howard (http://vrb.slashusr.org/), and
+// adapted to Darwin by Kurt Revis (http://www.snoize.com,
+// http://www.snoize.com/Code/PlayBufferedSoundFile.tar.gz)
+//
+
+#ifndef TPCircularBuffer_h
+#define TPCircularBuffer_h
+
+#include <libkern/OSAtomic.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ void *buffer;
+ int32_t length;
+ int32_t tail;
+ int32_t head;
+ volatile int32_t fillCount;
+} TPCircularBuffer;
+
+/*!
+ * Initialise buffer
+ *
+ * Note that the length is advisory only: Because of the way the
+ * memory mirroring technique works, the true buffer length will
+ * be multiples of the device page size (e.g. 4096 bytes)
+ *
+ * @param buffer Circular buffer
+ * @param length Length of buffer
+ */
+bool TPCircularBufferInit(TPCircularBuffer *buffer, int32_t length);
+
+/*!
+ * Cleanup buffer
+ *
+ * Releases buffer resources.
+ */
+void TPCircularBufferCleanup(TPCircularBuffer *buffer);
+
+/*!
+ * Clear buffer
+ *
+ * Resets buffer to original, empty state.
+ *
+ * This is safe for use by consumer while producer is accessing
+ * buffer.
+ */
+void TPCircularBufferClear(TPCircularBuffer *buffer);
+
+// Reading (consuming)
+
+/*!
+ * Access end of buffer
+ *
+ * This gives you a pointer to the end of the buffer, ready
+ * for reading, and the number of available bytes to read.
+ *
+ * @param buffer Circular buffer
+ * @param availableBytes On output, the number of bytes ready for reading
+ * @return Pointer to the first bytes ready for reading, or NULL if buffer is empty
+ */
+static __inline__ __attribute__((always_inline)) void* TPCircularBufferTail(TPCircularBuffer *buffer, int32_t* availableBytes) {
+ *availableBytes = buffer->fillCount;
+ if ( *availableBytes == 0 ) return NULL;
+ return (void*)((char*)buffer->buffer + buffer->tail);
+}
+
+/*!
+ * Consume bytes in buffer
+ *
+ * This frees up the just-read bytes, ready for writing again.
+ *
+ * @param buffer Circular buffer
+ * @param amount Number of bytes to consume
+ */
+static __inline__ __attribute__((always_inline)) void TPCircularBufferConsume(TPCircularBuffer *buffer, int32_t amount) {
+ buffer->tail = (buffer->tail + amount) % buffer->length;
+ OSAtomicAdd32Barrier(-amount, &buffer->fillCount);
+}
+
+/*!
+ * Version of TPCircularBufferConsume without the memory barrier, for more optimal use in single-threaded contexts
+ */
+ static __inline__ __attribute__((always_inline)) void TPCircularBufferConsumeNoBarrier(TPCircularBuffer *buffer, int32_t amount) {
+ buffer->tail = (buffer->tail + amount) % buffer->length;
+ buffer->fillCount -= amount;
+}
+
+/*!
+ * Access front of buffer
+ *
+ * This gives you a pointer to the front of the buffer, ready
+ * for writing, and the number of available bytes to write.
+ *
+ * @param buffer Circular buffer
+ * @param availableBytes On output, the number of bytes ready for writing
+ * @return Pointer to the first bytes ready for writing, or NULL if buffer is full
+ */
+static __inline__ __attribute__((always_inline)) void* TPCircularBufferHead(TPCircularBuffer *buffer, int32_t* availableBytes) {
+ *availableBytes = (buffer->length - buffer->fillCount);
+ if ( *availableBytes == 0 ) return NULL;
+ return (void*)((char*)buffer->buffer + buffer->head);
+}
+
+// Writing (producing)
+
+/*!
+ * Produce bytes in buffer
+ *
+ * This marks the given section of the buffer ready for reading.
+ *
+ * @param buffer Circular buffer
+ * @param amount Number of bytes to produce
+ */
+static __inline__ __attribute__((always_inline)) void TPCircularBufferProduce(TPCircularBuffer *buffer, int amount) {
+ buffer->head = (buffer->head + amount) % buffer->length;
+ OSAtomicAdd32Barrier(amount, &buffer->fillCount);
+}
+
+/*!
+ * Version of TPCircularBufferProduce without the memory barrier, for more optimal use in single-threaded contexts
+ */
+static __inline__ __attribute__((always_inline)) void TPCircularBufferProduceNoBarrier(TPCircularBuffer *buffer, int amount) {
+ buffer->head = (buffer->head + amount) % buffer->length;
+ buffer->fillCount += amount;
+}
+
+/*!
+ * Helper routine to copy bytes to buffer
+ *
+ * This copies the given bytes to the buffer, and marks them ready for writing.
+ *
+ * @param buffer Circular buffer
+ * @param src Source buffer
+ * @param len Number of bytes in source buffer
+ * @return true if bytes copied, false if there was insufficient space
+ */
+static __inline__ __attribute__((always_inline)) bool TPCircularBufferProduceBytes(TPCircularBuffer *buffer, const void* src, int32_t len) {
+ int32_t space;
+ void *ptr = TPCircularBufferHead(buffer, &space);
+ if ( space < len ) return false;
+ memcpy(ptr, src, len);
+ TPCircularBufferProduce(buffer, len);
+ return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
#import <AudioToolbox/AudioFormat.h> // AudioFormatGetProperty
#import <CoreServices/CoreServices.h>
+#import "TPCircularBuffer.h"
+
#ifndef verify_noerr
# define verify_noerr(a) assert((a) == noErr)
#endif
#define BUFSIZE (FRAMESIZE * 8) * 8
#define AOUT_VAR_SPDIF_FLAG 0xf00000
+#define kBufferLength BUFSIZE
+
#define AOUT_VOLUME_DEFAULT 256
#define AOUT_VOLUME_MAX 512
struct aout_sys_t
{
aout_packet_t packet;
- AudioDeviceID i_default_dev; /* DeviceID of defaultOutputDevice */
- AudioDeviceID i_selected_dev; /* DeviceID of the selected device */
- AudioDeviceIOProcID i_procID; /* DeviceID of current device */
- UInt32 i_devices; /* Number of CoreAudio Devices */
- bool b_digital; /* Are we running in digital mode? */
- mtime_t clock_diff; /* Difference between VLC clock and Device clock */
-
- uint8_t chans_to_reorder; /* do we need channel reordering */
+ AudioDeviceID i_default_dev; /* DeviceID of defaultOutputDevice */
+ AudioDeviceID i_selected_dev; /* DeviceID of the selected device */
+ AudioDeviceIOProcID i_procID; /* DeviceID of current device */
+ UInt32 i_devices; /* Number of CoreAudio Devices */
+ bool b_digital; /* Are we running in digital mode? */
+ mtime_t clock_diff; /* Difference between VLC clock and Device clock */
+
+ uint8_t chans_to_reorder; /* do we need channel reordering */
uint8_t chan_table[AOUT_CHAN_MAX];
+ UInt32 i_numberOfChannels;
+ TPCircularBuffer circular_buffer; /* circular buffer to swap the audio data */
+
/* AUHAL specific */
- Component au_component; /* The Audiocomponent we use */
- AudioUnit au_unit; /* The AudioUnit we use */
- uint8_t p_remainder_buffer[BUFSIZE];
- uint32_t i_read_bytes;
- uint32_t i_total_bytes;
+ Component au_component; /* The Audiocomponent we use */
+ AudioUnit au_unit; /* The AudioUnit we use */
/* CoreAudio SPDIF mode specific */
- pid_t i_hog_pid; /* The keep the pid of our hog status */
- AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */
- int i_stream_index; /* The index of i_stream_id in an AudioBufferList */
- AudioStreamBasicDescription stream_format; /* The format we changed the stream to */
- AudioStreamBasicDescription sfmt_revert; /* The original format of the stream */
- bool b_revert; /* Wether we need to revert the stream format */
- bool b_changed_mixing; /* Wether we need to set the mixing mode back */
+ pid_t i_hog_pid; /* The keep the pid of our hog status */
+ AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */
+ int i_stream_index; /* The index of i_stream_id in an AudioBufferList */
+ AudioStreamBasicDescription stream_format; /* The format we changed the stream to */
+ AudioStreamBasicDescription sfmt_revert; /* The original format of the stream */
+ bool b_revert; /* Wether we need to revert the stream format */
+ bool b_changed_mixing; /* Wether we need to set the mixing mode back */
};
/*****************************************************************************
static int OpenSPDIF (audio_output_t *, audio_sample_format_t *);
static void Close (vlc_object_t *);
+static void PlayAnalog (audio_output_t *, block_t *);
+static void FlushAnalog (audio_output_t *aout, bool wait);
+static int TimeGet (audio_output_t *aout, mtime_t *);
+
static void Probe (audio_output_t *);
static int AudioDeviceHasOutput (AudioDeviceID);
static int AudioStreamSupportsDigital(audio_output_t *, AudioStreamID);
static int AudioStreamChangeFormat (audio_output_t *, AudioStreamID, AudioStreamBasicDescription);
-static OSStatus RenderCallbackAnalog (vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
- unsigned int, unsigned int, AudioBufferList *);
+static OSStatus RenderCallbackAnalog (vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *, unsigned int, unsigned int, AudioBufferList *);
+
static OSStatus RenderCallbackSPDIF (AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
AudioBufferList *, const AudioTimeStamp *, void *);
static OSStatus HardwareListener (AudioObjectID, UInt32, const AudioObjectPropertyAddress *, void *);
set_subcategory(SUBCAT_AUDIO_AOUT)
set_callbacks(Open, Close)
add_integer("macosx-audio-device", 0, ADEV_TEXT, ADEV_LONGTEXT, false)
- add_integer( "auhal-volume", AOUT_VOLUME_DEFAULT,
- VOLUME_TEXT, VOLUME_LONGTEXT, true )
- change_integer_range( 0, AOUT_VOLUME_MAX )
+ add_integer("auhal-volume", AOUT_VOLUME_DEFAULT,
+ VOLUME_TEXT, VOLUME_LONGTEXT, true)
+ change_integer_range(0, AOUT_VOLUME_MAX)
vlc_module_end ()
/*****************************************************************************
p_sys->au_component = NULL;
p_sys->au_unit = NULL;
p_sys->clock_diff = (mtime_t) 0;
- p_sys->i_read_bytes = 0;
- p_sys->i_total_bytes = 0;
p_sys->i_hog_pid = -1;
p_sys->i_stream_id = 0;
p_sys->i_stream_index = -1;
p_sys->b_revert = false;
p_sys->b_changed_mixing = false;
- memset(p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE);
-
- p_aout->time_get = aout_PacketTimeGet;
- p_aout->play = aout_PacketPlay;
- p_aout->pause = NULL;
- p_aout->flush = aout_PacketFlush;
aout_FormatPrint(p_aout, "VLC is looking for:", fmt);
/* If we change the device we want to use, we should renegotiate the audio chain */
var_AddCallback(p_aout, "audio-device", AudioDeviceCallback, NULL);
+ /* setup circular buffer */
+ TPCircularBufferInit(&p_sys->circular_buffer, kBufferLength);
+
/* Check for Digital mode or Analog output mode */
if (AOUT_FMT_SPDIF (fmt) && b_supports_digital) {
if (OpenSPDIF (p_aout, fmt)) {
msg_Dbg(p_aout, "selected %d physical channels for device output", aout_FormatNbChannels(fmt));
msg_Dbg(p_aout, "VLC will output: %s", aout_FormatPrintChannels(fmt));
+ p_sys->i_numberOfChannels = aout_FormatNbChannels(fmt);
memset (&new_layout, 0, sizeof(new_layout));
uint32_t chans_out[AOUT_CHAN_MAX];
chans_out[5] = AOUT_CHAN_REARRIGHT;
chans_out[6] = AOUT_CHAN_REARCENTER;
- p_aout->sys->chans_to_reorder = aout_CheckChannelReorder( NULL, chans_out, fmt->i_physical_channels, p_aout->sys->chan_table );
+ p_aout->sys->chans_to_reorder = aout_CheckChannelReorder(NULL, chans_out, fmt->i_physical_channels, p_aout->sys->chan_table);
if (p_aout->sys->chans_to_reorder)
- msg_Dbg( p_aout, "channel reordering needed" );
+ msg_Dbg(p_aout, "channel reordering needed");
break;
case 8:
chans_out[6] = AOUT_CHAN_REARLEFT;
chans_out[7] = AOUT_CHAN_REARRIGHT;
- p_aout->sys->chans_to_reorder = aout_CheckChannelReorder( NULL, chans_out, fmt->i_physical_channels, p_aout->sys->chan_table );
+ p_aout->sys->chans_to_reorder = aout_CheckChannelReorder(NULL, chans_out, fmt->i_physical_channels, p_aout->sys->chan_table);
if (p_aout->sys->chans_to_reorder)
- msg_Dbg( p_aout, "channel reordering needed" );
+ msg_Dbg(p_aout, "channel reordering needed");
break;
}
DeviceFormat.mSampleRate = fmt->i_rate;
DeviceFormat.mFormatID = kAudioFormatLinearPCM;
- /* We use float 32. It's the best supported format by both VLC and Coreaudio */
+ /* We use float 32 since this is VLC's endorsed format */
fmt->i_format = VLC_CODEC_FL32;
DeviceFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
DeviceFormat.mBitsPerChannel = 32;
/* Calculate framesizes and stuff */
DeviceFormat.mFramesPerPacket = 1;
DeviceFormat.mBytesPerFrame = DeviceFormat.mBitsPerChannel * DeviceFormat.mChannelsPerFrame / 8;
+ msg_Dbg(p_aout, "bytes per frame %i", DeviceFormat.mBytesPerFrame);
DeviceFormat.mBytesPerPacket = DeviceFormat.mBytesPerFrame * DeviceFormat.mFramesPerPacket;
/* Set the desired format */
/* Do the last VLC aout setups */
aout_FormatPrepare(fmt);
- aout_PacketInit(p_aout, &p_sys->packet, FRAMESIZE, fmt);
/* set the IOproc callback */
input.inputProc = (AURenderCallback) RenderCallbackAnalog;
volume * volume * volume,
0));
+ p_aout->time_get = TimeGet;
+ p_aout->play = PlayAnalog;
+ p_aout->pause = NULL;
+ p_aout->flush = FlushAnalog;
+
return true;
}
var_DelCallback(p_aout, "audio-device", AudioDeviceCallback, NULL);
- aout_PacketDestroy(p_aout);
+ /* clean-up circular buffer */
+ TPCircularBufferCleanup(&p_sys->circular_buffer);
+
+ if (p_sys->b_digital)
+ aout_PacketDestroy(p_aout);
}
/*****************************************************************************
return true;
}
+static void PlayAnalog (audio_output_t * p_aout, block_t * p_block)
+{
+ struct aout_sys_t *p_sys = p_aout->sys;
+
+ if (p_block->i_nb_samples > 0) {
+ /* 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,
+ 32);
+ }
+
+ /* Render audio into buffer */
+ AudioBufferList bufferList;
+ bufferList.mNumberBuffers = 1;
+ bufferList.mBuffers[0].mNumberChannels = p_sys->i_numberOfChannels;
+ bufferList.mBuffers[0].mData = malloc(p_block->i_nb_samples * sizeof(Float32) * p_sys->i_numberOfChannels);
+ bufferList.mBuffers[0].mDataByteSize = p_block->i_nb_samples * sizeof(Float32) * p_sys->i_numberOfChannels;
+
+ memcpy(bufferList.mBuffers[0].mData, p_block->p_buffer, p_block->i_buffer);
+
+ /* move data to buffer */
+ TPCircularBufferProduceBytes(&p_sys->circular_buffer, bufferList.mBuffers[0].mData, bufferList.mBuffers[0].mDataByteSize);
+ }
+
+ block_Release(p_block);
+}
+
+static void FlushAnalog(audio_output_t *p_aout, bool wait)
+{
+ if (!wait)
+ AudioUnitReset(p_aout->sys->au_unit, kAudioUnitScope_Global, 0);
+}
+
+static int TimeGet(audio_output_t *p_aout, mtime_t *delay)
+{
+ VLC_UNUSED(p_aout);
+ VLC_UNUSED(delay);
+
+ return -1;
+}
+
/*****************************************************************************
* RenderCallbackAnalog: This function is called everytime the AudioUnit wants
* us to provide some more audio data.
* Don't print anything during normal playback, calling blocking function from
* this callback is not allowed.
*****************************************************************************/
-static OSStatus RenderCallbackAnalog(vlc_object_t *_p_aout,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- unsigned int inBusNumber,
- unsigned int inNumberFrames,
- AudioBufferList *ioData)
-{
- AudioTimeStamp host_time;
- mtime_t current_date = 0;
- uint32_t i_mData_bytes = 0;
-
- audio_output_t * p_aout = (audio_output_t *)_p_aout;
- struct aout_sys_t * p_sys = p_aout->sys;
-
+static OSStatus RenderCallbackAnalog(vlc_object_t *p_obj,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData) {
VLC_UNUSED(ioActionFlags);
+ VLC_UNUSED(inTimeStamp);
VLC_UNUSED(inBusNumber);
VLC_UNUSED(inNumberFrames);
- host_time.mFlags = kAudioTimeStampHostTimeValid;
- AudioDeviceTranslateTime(p_sys->i_selected_dev, inTimeStamp, &host_time);
-
- /* Check for the difference between the Device clock and mdate */
- p_sys->clock_diff = - (mtime_t)
- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()) / 1000;
- p_sys->clock_diff += mdate();
-
- current_date = p_sys->clock_diff +
- AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000;
- //- ((mtime_t) 1000000 / p_aout->format.i_rate * 31); // 31 = Latency in Frames. retrieve somewhere
-
- if (ioData == NULL || ioData->mNumberBuffers < 1) {
- msg_Err(p_aout, "no iodata or buffers");
- return 0;
- }
- if (ioData->mNumberBuffers > 1)
- msg_Err(p_aout, "well this is weird. seems like there is more than one buffer...");
-
- if (p_sys->i_total_bytes > 0) {
- i_mData_bytes = __MIN(p_sys->i_total_bytes - p_sys->i_read_bytes, ioData->mBuffers[0].mDataByteSize);
- memcpy(ioData->mBuffers[0].mData,
- &p_sys->p_remainder_buffer[p_sys->i_read_bytes],
- i_mData_bytes);
- p_sys->i_read_bytes += i_mData_bytes;
- current_date += (mtime_t) ((mtime_t) 1000000 / p_sys->packet.format.i_rate) *
- (i_mData_bytes / 4 / aout_FormatNbChannels(&p_sys->packet.format)); // 4 is fl32 specific
-
- if (p_sys->i_read_bytes >= p_sys->i_total_bytes)
- p_sys->i_read_bytes = p_sys->i_total_bytes = 0;
- }
-
- while(i_mData_bytes < ioData->mBuffers[0].mDataByteSize) {
- /* We don't have enough data yet */
- block_t * p_buffer;
- p_buffer = aout_PacketNext(p_aout, current_date);
-
- if (p_buffer != NULL)
- {
- /* Do the channel reordering */
- if (p_buffer && p_sys->chans_to_reorder)
- {
- aout_ChannelReorder(p_buffer->p_buffer,
- p_buffer->i_buffer,
- p_sys->chans_to_reorder,
- p_sys->chan_table,
- 32);
- }
+ audio_output_t * p_aout = (audio_output_t *)p_obj;
+ struct aout_sys_t * p_sys = p_aout->sys;
- uint32_t i_second_mData_bytes = __MIN(p_buffer->i_buffer, ioData->mBuffers[0].mDataByteSize - i_mData_bytes);
+ int bytesToCopy = ioData->mBuffers[0].mDataByteSize;
+ Float32 *targetBuffer = (Float32*)ioData->mBuffers[0].mData;
- memcpy((uint8_t *)ioData->mBuffers[0].mData + i_mData_bytes,
- p_buffer->p_buffer, i_second_mData_bytes);
- i_mData_bytes += i_second_mData_bytes;
+ /* Pull audio from buffer */
+ int32_t availableBytes;
+ Float32 *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+ memcpy(targetBuffer, buffer, __MIN(bytesToCopy, availableBytes));
+ TPCircularBufferConsume(&p_sys->circular_buffer, __MIN(bytesToCopy, availableBytes));
- if (i_mData_bytes >= ioData->mBuffers[0].mDataByteSize)
- {
- p_sys->i_total_bytes = p_buffer->i_buffer - i_second_mData_bytes;
- memcpy(p_sys->p_remainder_buffer,
- &p_buffer->p_buffer[i_second_mData_bytes],
- p_sys->i_total_bytes);
- block_Release(p_buffer);
- break;
- } else
- /* update current_date */
- current_date += (mtime_t) ((mtime_t) 1000000 / p_sys->packet.format.i_rate) *
- (i_second_mData_bytes / 4 / aout_FormatNbChannels(&p_sys->packet.format)); // 4 is fl32 specific
- block_Release(p_buffer);
- } else {
- memset((uint8_t *)ioData->mBuffers[0].mData +i_mData_bytes,
- 0,ioData->mBuffers[0].mDataByteSize - i_mData_bytes);
- i_mData_bytes += ioData->mBuffers[0].mDataByteSize - i_mData_bytes;
- }
- }
return noErr;
}