iOS: потоковое решение, необходимое для обработки аудио - PullRequest
1 голос
/ 06 декабря 2011

Я наблюдаю за микрофоном в режиме обратного вызова рендеринга.

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

Если это так, я начинаю запись в буфер, пока снова не тишина.

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

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

Я наивно предполагал, что смогу отправить NSNotification из моего обратного вызова рендеринга, и он будет получен в другом потоке. Но этого не происходит! Он выполняется в том же потоке.

Что такое аккуратный способ сделать это?

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

1 Ответ

2 голосов
/ 06 декабря 2011

Я сделал похожую вещь, «простой» ответ - я создаю очередь последовательной отправки, затем в обратном вызове рендеринга аудиоустройства я собираю данные и использую dispatch_async для передачи новых аудиоданных в последовательную очередь. Я использую вторичную очередь, поскольку аудиоустройства требуют, чтобы вы проводили как можно меньше времени в обратном вызове - также вы не должны выделять память или генерировать прерывания и тому подобное.

здесь lockData и unlockData получают предварительно выделенные объекты NSMutableData и сохраняют их в заблокированном / разблокированном массиве.

// в вашем методе init

self.captureQueue = dispatch_queue_create("AudioCaptureQueue", NULL);

в обратном вызове рендеринга:

__block NSMutableData * audiodata = [audioIO lockData];

status = AudioUnitRender(audioIO.audioUnit, 
            ioActionFlags, 
            inTimeStamp, 
            inBusNumber, 
                     inNumberFrames, 
                     &auBufferList);

dispatch_async(audioIO.captureQueue, ^{
    [audioIO.sampleCaptureDelegate audioComponent:audioIO 
                  hasSampleBuffer:audiodata];

        [audioIO unlockData:audiodata];
});

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

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:kAPPAudioQueueDidDetect 
                                                            object:nil];
    });

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

...