AVAudioEngine播放多声道audio

简单的问题。 如何使用AVAudioEngine播放多声道audio文件(> 2声道),以便在默认的双声道输出(耳机/扬声器)上听到所有声道。 以下代码(删除错误检查提交)播放文件的第一个两个渠道,但我只能听到耳机插入时听到。

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]; 

我尝试了很多与播放器 – >混音器和混音器 – >输出连接格式的组合,但是它们的结果与上面的代码相同,或者更可能与以下两者中的一个崩溃:

 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];上发生崩溃[player play];

必须有某种方式像我想要的那样播放,因为使用AUGraph可以毫无问题地进行播放,但是,由于AVAudioEngine提供了一个必须包含的function,所以我坚持使用它。

我用来检查我的代码的多声道audio文件可以在这里find

更新好的,所以只听耳机的audio可能是由于我忘记设置audio会话,以激活我的testing应用程序。 但我仍然只听到前两个频道

我在Swift有类似的问题。 错误是'com.apple.coreaudio.avfaudio',原因是:'所需条件为false:!nodeimpl-> SslEngineImpl()'。

任务是一个接一个地播放两个audio文件。 如果我在播放完第一个audio文件后停止播放,然后播放第二个audio文件,则系统崩溃。

我发现在我创build的函数中,我有audioEngine.attachNode(audioPlayerNode) ,这意味着audioPlayerNode被连接到audioEngine一次,然后退出。 所以我把这个附件移到了viewDidLoad()函数中,以便它每次都被传递。

所以这是我到目前为止所做的。 这远非完美,但有点作用。

要获得所有通道,您需要使用AVAudioPCMBuffer,并在每个文件中存储两个通道。 另外,对于每个声道对,您需要单独的AVAudioPlayerNode,然后将每个播放器连接到AVAudioMixerNode,我们就完成了。 一些简单的6声道audio代码:

 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]; 

现在这个解决scheme还不够完美,因为在不同的时间为每个玩家打电话,所以在频道对之间会有延迟。 我也不能从我的testing文件中播放8声道audio(请参阅OP中的链接)。 AVAudioFile处理格式的通道数为0,即使我用正确的通道数量和布局创build了我自己的格式,在读取缓冲区时也会出错。 请注意,我可以使用AUGraph完美​​地播放此文件。

所以我会在接受这个答案之前等,如果你有更好的解决scheme请分享。

编辑

所以看来,我无法同步节点的问题,不能播放这个特定的8声道audio是错误(由苹果开发者支持确认)。

对于在iOS上干扰audio的人们提供的build议很less。 虽然AVAudioEngine对于简单的东西来说是不错的,但是你应该select带有更复杂的东西的AUGraph,甚至是与AVAudioEngine一起工作的东西。 如果你不知道如何从AUGraph的AVAudioEngine中复制某些东西(比如我自己),好吧,好运气。