2014-12-02 2 views
1

Простой вопрос. Как воспроизвести многоканальные аудиофайлы (> 2 канала) с помощью AVAudioEngine, чтобы я мог слышать все каналы по умолчанию по 2-канальному выходу (наушники/динамик). После кода (разделите проверки ошибок для представления) воспроизводит файл первых два канала, но я могу слышать его только тогда, когда подключены наушники.AVAudioEngine воспроизведение многоканальный аудио

AVAudioFile *file = [[AVAudioFile alloc] initForReading:[[NSBundle mainBundle] URLForResource:@"nums6ch" withExtension:@"wav"] error:nil]; 
AVAudioEngine *engine = [[AVAudioEngine alloc] init]; 
AVAudioPlayerNode *player = [[AVAudioPlayerNode alloc] init]; 
AVAudioMixerNode *mixer = [[AVAudioMixerNode alloc] init]; 
[engine attachNode:player]; 
[engine attachNode:mixer]; 
AVAudioFormat *processingFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 sampleRate:file.processingFormat.streamDescription->mSampleRate channels:2 interleaved:false]; 
[engine connect:player to:mixer format:processingFormat]; 
[engine connect:mixer to:engine.outputNode format:processingFormat]; 
[engine startAndReturnError:nil]; 
[player scheduleFile:file atTime:nil completionHandler:nil]; 
[player play]; 

Я пробовал много комбинаций с форматами как для player-> смесителя и mixer-> выходные соединения, но они либо результат с той же вещи, как код выше, или более вероятно, аварии либо с:

ERROR:  [0x19c392310] AVAudioNode.mm:495: AUGetFormat: required condition is false: nil != channelLayout && channelLayout.channelCount == asbd.mChannelsPerFrame 
*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: nil != channelLayout && channelLayout.channelCount == asbd.mChannelsPerFrame' 

или AUSetFormat OSStatus код -10868 (который формат не поддерживается, если я не ошибаюсь). Использование file.processingFormat для любого соединения приводит к сбою приложения с первой ошибкой выше. Кроме того, авария происходит на [player play];

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

Мульти канал аудио файлы, которые я использую, чтобы проверить мой код можно найти here

UPDATE Ok, так что слух звук в наушниках только был, вероятно, из-за меня забыть настройки аудио сеанс активен в моем тестовом приложении. Но я до сих пор слышу только первые два канала ...

ответ

1

Так вот, до сих пор я справлялся. Это далеко не идеально, но это работает.

Чтобы получить все каналы, вам необходимо использовать AVAudioPCMBuffer и сохранить два канала из файла в каждом. Кроме того, для каждой пары каналов вам потребуется отдельный AVAudioPlayerNode, а затем просто подключите каждого игрока к AVAudioMixerNode, и мы закончили. Некоторый простой код для 6-канального звука:

AVAudioFormat *outputFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 sampleRate:file.processingFormat.sampleRate channels:2 interleaved:false]; 
AVAudioFile *file = [[AVAudioFile alloc] initForReading:[[NSBundle mainBundle] URLForResource:@"nums6ch" withExtension:@"wav"] error:nil]; 
AVAudioPCMBuffer *wholeBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:file.processingFormat frameCapacity:(AVAudioFrameCount)file.length]; 
AVAudioPCMBuffer *buffer1 = [[AVAudioPCMBuffer alloc] initWithPCMFormat:outputFormat frameCapacity:(AVAudioFrameCount)file.length]; 
AVAudioPCMBuffer *buffer2 = [[AVAudioPCMBuffer alloc] initWithPCMFormat:outputFormat frameCapacity:(AVAudioFrameCount)file.length]; 
AVAudioPCMBuffer *buffer3 = [[AVAudioPCMBuffer alloc] initWithPCMFormat:outputFormat frameCapacity:(AVAudioFrameCount)file.length]; 
memcpy(buffer1.audioBufferList->mBuffers[0].mData, wholeBuffer.audioBufferList->mBuffers[0].mData, wholeBuffer.audioBufferList->mBuffers[0].mDataByteSize); 
memcpy(buffer1.audioBufferList->mBuffers[1].mData, wholeBuffer.audioBufferList->mBuffers[1].mData, wholeBuffer.audioBufferList->mBuffers[1].mDataByteSize); 
buffer1.frameLength = wholeBuffer.audioBufferList->mBuffers[0].mDataByteSize/sizeof(UInt32); 
memcpy(buffer2.audioBufferList->mBuffers[0].mData, wholeBuffer.audioBufferList->mBuffers[2].mData, wholeBuffer.audioBufferList->mBuffers[2].mDataByteSize); 
memcpy(buffer2.audioBufferList->mBuffers[1].mData, wholeBuffer.audioBufferList->mBuffers[3].mData, wholeBuffer.audioBufferList->mBuffers[3].mDataByteSize); 
buffer2.frameLength = wholeBuffer.audioBufferList->mBuffers[0].mDataByteSize/sizeof(UInt32); 
memcpy(buffer3.audioBufferList->mBuffers[0].mData, wholeBuffer.audioBufferList->mBuffers[4].mData, wholeBuffer.audioBufferList->mBuffers[4].mDataByteSize); 
memcpy(buffer3.audioBufferList->mBuffers[1].mData, wholeBuffer.audioBufferList->mBuffers[5].mData, wholeBuffer.audioBufferList->mBuffers[5].mDataByteSize); 
buffer3.frameLength = wholeBuffer.audioBufferList->mBuffers[0].mDataByteSize/sizeof(UInt32); 

AVAudioEngine *engine = [[AVAudioEngine alloc] init]; 
AVAudioPlayerNode *player1 = [[AVAudioPlayerNode alloc] init]; 
AVAudioPlayerNode *player2 = [[AVAudioPlayerNode alloc] init]; 
AVAudioPlayerNode *player3 = [[AVAudioPlayerNode alloc] init]; 
AVAudioMixerNode *mixer = [[AVAudioMixerNode alloc] init]; 
[engine attachNode:player1]; 
[engine attachNode:player2]; 
[engine attachNode:player3]; 
[engine attachNode:mixer]; 
[engine connect:player1 to:mixer format:outputFormat]; 
[engine connect:player2 to:mixer format:outputFormat]; 
[engine connect:player3 to:mixer format:outputFormat]; 
[engine connect:mixer to:engine.outputNode format:outputFormat]; 
[engine startAndReturnError:nil]; 

[player1 scheduleBuffer:buffer1 completionHandler:nil]; 
[player2 scheduleBuffer:buffer2 completionHandler:nil]; 
[player3 scheduleBuffer:buffer3 completionHandler:nil]; 
[player1 play]; 
[player2 play]; 
[player3 play]; 

Теперь это решение далеко от совершенства, так как там будет задержка между парами каналов из-за вызовом play для каждого игрока в разное время. Я также не могу воспроизводить 8-канальный звук из своих тестовых файлов (см. Ссылку в OP). Формат обработки AVAudioFile имеет 0 для количества каналов, и даже если я создаю свой собственный формат с правильным количеством каналов и макета, я получаю ошибку при чтении буфера. Обратите внимание, что я могу отлично воспроизвести этот файл с помощью AUGraph.

Так что я подожду, прежде чем принимать этот ответ, если у вас есть лучшее решение, пожалуйста, поделитесь.

EDIT

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

Так мало советов для людей, вмешивающихся в аудио на iOS. Хотя AVAudioEngine отлично подходит для простых вещей, вам обязательно нужно пойти на AUGraph с более сложными вещами, даже с материалами, которые, как предполагается, будут работать с AVAudioEngine. И если вы не знаете, как копировать определенные вещи из AVAudioEngine в AUGraph (например, я), хорошо, сложно.

+0

Просьба уточнить ошибки, которые вы упомянули. Невозможно ли использовать 'listBuffer' AVAudioPlayerNode': atTime: options: completeHandler' для указания того же 'AVAudioTIme' для всех трех узлов? – Mark

+1

На момент написания этого вопроса и ответа, даже если вы поместите тот же AVAudioTime для всех трех узлов, все еще будет небольшая задержка между звуками. Не знаю, если они исправили это или нет. – Kegluneq

2

У меня была аналогичная проблема в Свифт. Ошибка была «com.apple.coreaudio.avfaudio», причина: «обязательное условие - false:! Nodeimpl-> SslEngineImpl()».

Задача состояла в том, чтобы воспроизвести два аудиофайла один за другим. Если я ударил стоп после воспроизведения первого аудиофайла, а затем воспроизвел второй аудиофайл, система потерпела крах.

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

Смежные вопросы