Какие действия разрешены во входном обратном вызове модуля вывода звука

Я использую блок аудиовыхода для захвата данных микрофона. Я получаю уведомление о том, что есть данные для чтения с помощью обратного вызова, который я установил с помощью свойства kAudioOutputUnit_SetInputCallback, и в обратном вызове я читаю данные, вызывая AudioUnitRender().

В конечном счете, я буду обновлять пользовательский интерфейс своего приложения на основе некоторой информации, извлеченной путем анализа этих данных. Поэтому на каком-то этапе мне нужно будет выполнить dispatch_async в основной очереди. Анализ занимает умеренное время и выполняется фрагментами, которые намного больше, чем те, которые я получаю от AudioUnitRender(), поэтому нагрузка носит скачкообразный характер.

Мой вопрос: какие операции считаются приемлемыми при реализации самого входного обратного вызова? Я нашел множество источников со строгими ограничениями на обратные вызовы render (без выделения памяти, ввода-вывода, синхронизации с другими потоками и т. д.), но никакой информации о input< /em> обратные вызовы.

Если я буду следовать тем же правилам, что и для обратных вызовов рендеринга, у меня возникнет небольшая проблема. Сам по себе dispatch_async() нежелателен, так как он выделяет память, а загрузка в любом случае носит скачкообразный характер (может быть длиннее одного цикла рендеринга на одних ходах и практически равна нулю на других). Поэтому представляется необходимым отправить мои данные в рабочий поток для обработки и выполнения вызовов dispatch_async(). Однако мне все еще нужно управлять передачей данных в этот рабочий поток. Самый простой способ (в C++) — использовать циклический буфер, а также мьютекс и условную переменную для сигнализации о доступности данных. Однако для этого потребовался бы обратный вызов ввода для блокировки мьютекса, что явно не рекомендуется в рекомендациях по обратным вызовам рендеринга.

Избегание этой блокировки мьютекса приведет меня к циклическим буферам без блокировки, семафорам (POSIX или GCD), спин-блокировкам и тому подобному, и мне интересно, не слишком ли это для простого прослушивания микрофона. Ужасно мало документации по этому делу, и я понятия не имею, что на самом деле происходит за кулисами. Мне действительно нужно беспокоиться об ожидании мьютекса (только ненадолго и редко блокируемого другим потоком) в моей реализации обратного вызова ввода?


person Tom    schedule 20.04.2015    source источник


Ответы (1)


Я использую циклический буфер из: https://github.com/michaeltyson/TPCircularBuffer.

В описании указано:

Пока вы ограничиваете многопоточный доступ только одним производителем и только одним потребителем, эта утилита должна быть потокобезопасной.

Таким образом, вы можете безопасно выполнять рендеринг (производство) и обработку (потребление) из кольцевого буфера, не беспокоясь о блокировках.

Обновление:

Действительно ли мне нужно беспокоиться об ожидании мьютекса (только ненадолго и редко блокируемого другим потоком) в моей реализации обратного вызова ввода?

На это я говорю да. «Редко блокируется» — это все, что вам нужно для сбоя обратного вызова ввода. А "кратко" - это уже слишком долго. У меня были входные обратные вызовы, которые терпели неудачу просто из-за чего-то NSLogging.

person rocky    schedule 20.04.2015
comment
Да, как я упомянул в конце, чтобы избежать блокировки мьютекса, похоже, мне понадобится циклический буфер без блокировки и что-то другое, кроме std::condition_variable, чтобы заставить рабочий поток просыпаться, когда есть данные ( Семафор GCD выглядит наиболее перспективным для этого). Эта реализация циклического буфера полезна, и приятно, что она действительно имеет документированную гарантию многопоточности, в отличие от CARingBuffer, так что спасибо за это. Однако остается открытым вопрос, действительно ли необходимо избегать мьютекса при обратном вызове ввода. - person Tom; 21.04.2015