AudioUnit callback and synchronization: how to ensure thread safety with GCD

强颜欢笑 提交于 2019-12-23 04:33:24

问题


I am building an audio app based on the AudioUnit callback facility and a graph of audio processing nodes. I know that the callback is executed in a separate (high priority?) thread and therefore all interaction with my processing nodes, such as e.g. changing EQ parameters while playing, should be done in a thread safe manner. In other words, the nodes should be protected from modification while the audio callback chain is being executed.

The way I understand it in terms of more low-level multithreading is that, I need a lock either in each node or a single one for the entire graph, that prevents writes while audio buffers are being processed.

However, I would like the implementation to be more "Swifty" and use DispatchQueue/DispatchGroup which should provide the said functionality. I just can't quite understand how to do it in the most efficient manner.

So let's say all audio parameter modifications are done on a queue, like so:

audioQueue.async {
    eqNode.setEqParameters(...)
}

How do I ensure this block is not executed until the AudioUnit callback completes? Using audioQueue.sync is not an option because it means the system audio thread will depend on my audioQueue, this is not great.

If I were to use DispatchGroup what would be the best way to implement the said flow?


回答1:


A real-time Audio Unit callback should never lock, wait on locks, or manage memory (Swift or Objective C objects or methods).

I would double buffer the set of audio parameters (or more, e.g. a ring buffer of parameter sets). Have the writer lock the set that is being changed, unlock when done, and never switch sets at or faster than the known audio callback rate (2X+ slower would be safe). Have the periodic reader (Audio Unit real-time callback) check the locks and not use the set of parameters that is locked.

In order to not use locks on inter-thread ring buffers, you might want to use OS atomic memory barriers on the pointer, index, or status load/stores: load_acquire, store_release, etc., to prevent ARM processor write buffer reordering, or Swift optimizer instruction reordering, from corrupting your data.



来源:https://stackoverflow.com/questions/58512485/audiounit-callback-and-synchronization-how-to-ensure-thread-safety-with-gcd

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!