Обратный вызов и синхронизация AudioUnit: как обеспечить безопасность потоков с помощью GCD - PullRequest
0 голосов
/ 23 октября 2019

Я создаю аудио-приложение на основе функции обратного вызова AudioUnit и графика узлов обработки звука. Я знаю, что обратный вызов выполняется в отдельном (высокоприоритетном?) Потоке, и поэтому все взаимодействие с моими узлами обработки, например, изменение параметров эквалайзера во время воспроизведения, должно выполняться потокобезопасным способом. Другими словами, узлы должны быть защищены от модификации во время выполнения цепочки обратного вызова аудио.

Я понимаю это с точки зрения более низкого уровня многопоточности: мне нужна блокировка либо в каждом узлеили один для всего графа, который предотвращает запись во время обработки аудио-буферов.

Однако я хотел бы, чтобы реализация была более "быстрой" и использовала DispatchQueue / DispatchGroup, которая должна обеспечиватьупомянутая функциональность. Я просто не могу понять, как сделать это наиболее эффективным способом.

Итак, допустим, все изменения параметров звука выполняются в очереди, например так:

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

Как сделатьЯ гарантирую, что этот блок не выполняется, пока обратный вызов AudioUnit не завершится? Использование audioQueue.sync не вариант, потому что это означает, что системный аудиопоток будет зависеть от моего audioQueue, это не очень хорошо.

Если бы я использовал DispatchGroup, какой был бы лучший способ реализоватьупомянутый поток?

1 Ответ

2 голосов
/ 24 октября 2019

Обратный вызов аудиоустройства в режиме реального времени никогда не должен блокировать, ждать блокировок или управлять памятью (объекты или методы Swift или Objective C).

Я бы удвоил буферизацию набора параметров звука (или более,например, кольцевой буфер наборов параметров). Писатель должен заблокировать изменяемый набор, разблокировать его по завершении и никогда не переключать наборы со скоростью, превышающей известную скорость обратного вызова аудио (безопаснее было бы в 2 раза медленнее). Попросите периодического считывателя (обратный вызов аудиоустройства в режиме реального времени) проверить блокировки и не использовать набор параметров, который заблокирован.

Чтобы не использовать блокировки на кольцевых буферах между потоками, вы можете использоватьБарьеры атомарной памяти ОС для указателя, индекса или состояния загружаются / сохраняются: load_acquire, store_release и т. Д., Чтобы предотвратить изменение порядка данных в буфере записи процессора ARM или изменение порядка в оптимизаторе Swift.

...