macos - OS X 上音频编程的任何延迟(比 Mach 信号量)更低的同步方式?

标签 macos audio core-audio semaphore mach

我目前正在使用 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;
 }

最佳答案

Apple DTS 似乎建议不要在短的实时音频单元渲染回调中执行任何可能锁定或分配内存的操作,甚至可能包括信号量和 mach 信号。

相反,应用程序可以在另一个线程(而不是渲染回调线程)中重复轮询无锁循环 fifo。鉴于采样率和 fifo 的大小都是已知的,轮询率明显快于 fifo 空到阈值率应该有效,相当有效,并且不需要锁定。可以通过改变阈值级别和相应的轮询率来控制延迟。重复的 NSTimer 或 CADisplayLink(或 Open GL 帧渲染)计时器可能适合轮询。

请注意,循环缓冲区需要大于填充阈值,以便填充例程有足够的时间与音频回调异步工作。当然,最坏情况下的填充率必须比最佳情况下的 fifo 清空率更快。

关于macos - OS X 上音频编程的任何延迟(比 Mach 信号量)更低的同步方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23693656/

相关文章:

objective-c - 自定义日志记录宏不接受多个参数

java - Android 获取音频输出

flutter - 如何一个一个播放多个音频?

iphone - iPhone游戏中的音效

python - 在 Python (Mac) 中使用 OpenCV 裁剪视频

macos - 保存整个桌面状态?

git - .gitignore_global 在 OS X 上保存在哪里?

python - 为什么来自 librosa 库的频谱图与实际音轨的持续时间不同?

ios - MPMusicPlayerController 是否更新播放计数?

objective-c - 输入队列回调已调用但没有数据