我目前正在使用 TPCircularBuffer 来同步解码来自外部库(libxmp:http://xmp.sourceforge.net/)的音频数据,并通过 OS X 上的 AudioUnits API 播放它。
Mach 信号量用于在需要重新填充缓冲区时发出信号。
但是,当信号量被触发时,音频中似乎存在“间隙”(并且音频似乎播放得比平时慢)。
在这种情况下,是否可以使用任何延迟较低的同步方法?
概念验证在这里:https ://gist.github.com/douglas-carmichael/cda1117e42e917397ed7
这是我传递给回调的结构:
struct StreamData
{
TPCircularBuffer ringBuffer;
semaphore_t semaphore;
int fillThreshold;
};
这是我创建信号量的方式:
// Initialize our semaphore
mach_port_t self = mach_task_self();
kern_return_t ret = semaphore_create(self, &ourStream.semaphore, SYNC_POLICY_FIFO, 0);
if (ret != KERN_SUCCESS)
{
NSLog(@"Semaphore creation failed. Error <%d, %s>", ret, mach_error_string(ret));
return 0;
}
这是播放循环:
// Start our playback loop
struct xmp_frame_info ourFrameInfo;
int err = true;
while (xmp_play_frame(myContext) == 0)
{
xmp_get_frame_info(myContext, &ourFrameInfo);
if (ourFrameInfo.loop_count > 0)
break;
/* Are we getting a buffer overrun? */
if (err != false)
{
err = TPCircularBufferProduceBytes(&ourStream.ringBuffer, ourFrameInfo.buffer, ourFrameInfo.buffer_size);
}
semaphore_wait(ourStream.semaphore);
}
这是渲染回调:
static OSStatus renderModuleCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inBufferFrames,
AudioBufferList *ioData)
{
struct StreamData *ourStream = inRefCon;
/* Initialize our variable for how much is available */
int bytesAvailable = 0;
/* Grab the data from the circular buffer into a temporary buffer */
SInt16 *ourBuffer = TPCircularBufferTail(&ourStream->ringBuffer, &bytesAvailable);
/* Do we have enough data? */
/* Note: fillThreshold is the maximum output buffer size for the device. */
if (bytesAvailable < ourStream->fillThreshold)
{
semaphore_signal(ourStream->semaphore);
}
/* memcpy() the data to the audio output */
memcpy(ioData->mBuffers[0].mData, ourBuffer, bytesAvailable);
/* Clear that section of the buffer */
TPCircularBufferConsume(inRefCon, bytesAvailable);
return noErr;
}