2015-04-20 12 views
1

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

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

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

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

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

ответ

2

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

описания состояний:

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

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

Update:

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

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

+0

Да, как я уже упоминал в конце, чтобы избежать блокировки мьютекса, похоже, что мне понадобится бесплатный кольцевой буфер и что-то другое, кроме std :: condition_variable, чтобы заставить рабочий поток проснуться, когда есть данные (семафор GCD выглядит наиболее перспективным для этого).Эта реализация циклического буфера полезна, и хорошо, что на самом деле у нее есть * документированная * технология потоковой передачи, в отличие от CARingBuffer, поэтому благодарим за это. Тем не менее, по-прежнему стоит вопрос о том, действительно ли необходимо избегать мьютекса во входном обратном вызове. – Tom

+0

Обновленный ответ. – rocky