簡體   English   中英

AVAudioEngine播放多聲道音頻

[英]AVAudioEngine playing multi channel audio

簡單的問題。 如何使用AVAudioEngine播放多聲道音頻文件(> 2聲道),以便我可以在默認的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];

必須有一些像我想要的那樣播放它,因為我能夠毫無問題地使用AUGraph,但是,因為AVAudioEngine提供了我必須包含的一個功能,所以我堅持使用它。

我可以在這里找到用於檢查我的代碼的多聲道音頻文件

更新好的,所以只聽到耳機中的音頻可能是因為我忘了在我的測試應用程序中將音頻會話設置為活動狀態。 但我仍然只聽到前兩個頻道......

我在Swift中遇到過類似的問題。 錯誤是'com.apple.coreaudio.avfaudio',原因是:'required condition is false:!nodeimpl-> SslEngineImpl()'。

任務是一個接一個地播放兩個音頻文件。 如果我在播放第一個音頻文件然后播放第二個音頻文件后點擊停止,則系統崩潰。

我發現在我創建的函數中我有audioEngine.attachNode(audioPlayerNode) ,這意味着audioPlayerNode被連接到audioEngine一次然后退出。 所以我將此附件移動到viewDidLoad()函數,以便每次都傳遞它。

所以這就是我到目前為止所管理的內容。 它遠非完美,但它有點奏效。

要獲得所有通道,您需要使用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完美​​地播放此文件。

所以我會在接受這個答案之前等待,如果你有更好的解決方案請分享。

編輯

因此,似乎無法同步節點問題而無法播放此特定8聲道音頻都是錯誤(Apple開發人員支持確認)。

對於在iOS上干擾音頻的人來說,這么少的建議。 雖然AVAudioEngine對於簡單的東西來說很好,但你應該選擇AUGraph來處理更復雜的東西,甚至可以選擇與AVAudioEngine一起使用的東西。 如果你不知道如何從AUGraph中的AVAudioEngine復制某些東西(比如我自己),那么,運氣不好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM