从CMSampleBuffer播放音频

9
我已经在iOS上为群组创建了一个视频聊天应用。我一直在寻找控制不同参与者音量的方法。我发现可以使用RemoteAudioTrack中的isPlaybackEnabled来静音和取消静音,但不能控制音量。
我还尝试将其应用于AVAudioPlayer。我找到了addSink。这是我从这里尝试的内容:
class Audio: NSObject, AudioSink {
    var a = 1
    func renderSample(_ audioSample: CMSampleBuffer!) {
        print("audio found", a)
        a += 1

        var audioBufferList = AudioBufferList()
        var data = Data()
        var blockBuffer : CMBlockBuffer?

        CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(audioSample, bufferListSizeNeededOut: nil, bufferListOut: &audioBufferList, bufferListSize: MemoryLayout<AudioBufferList>.size, blockBufferAllocator: nil, blockBufferMemoryAllocator: nil, flags: 0, blockBufferOut: &blockBuffer)
        let buffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, count: Int(audioBufferList.mNumberBuffers))

        for audioBuffer in buffers {
            let frame = audioBuffer.mData?.assumingMemoryBound(to: UInt8.self)
            data.append(frame!, count: Int(audioBuffer.mDataByteSize))
        }

        let player = try! AVAudioPlayer(data: data) //crash here
        player.play()
    }
}

但是在let player = try! AVAudioPlayer(data: data)时崩溃了。


编辑:
这是错误:Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSOSStatusErrorDomain Code=-39 "(null)": file

所以我想这个data没有被转换:

 0 bytes
  - count : 0
   pointer : 0x000000016d7ae160
    - pointerValue : 6131736928
  - bytes : 0 elements

这是音频样本 (audioSample):

<CMAudioFormatDescription 0x2815a3de0 [0x1bb2ef830]> {
    mediaType:'soun' 
    mediaSubType:'lpcm' 
    mediaSpecific: {
        ASBD: {
            mSampleRate: 16000.000000 
            mFormatID: 'lpcm' 
            mFormatFlags: 0xc 
            mBytesPerPacket: 2 
            mFramesPerPacket: 1 
            mBytesPerFrame: 2 
            mChannelsPerFrame: 1 
            mBitsPerChannel: 16     } 
        cookie: {(null)} 
        ACL: {(null)}
        FormatList Array: {(null)} 
    } 
    extensions: {(null)}
}

2
首先,你的错误是什么?崩溃可能意味着10000000件事情。 - impression7vx
2
这可能会有所帮助。您可能想要使用音频队列服务。我有一种预感,为每个小数据包创建一个新的AVAudioPlayer可能会导致很多卡顿。 - Daniel
你是如何初始化和获取CMSampleBuffer的数据?你使用了哪个包?稍后我会展示如何使用音频队列服务来完成此操作。 - Rakeeb Hossain
@RakeebHossain 我在使用Twilio。因此,Twilio会发送名为“ RemoteAudioTrack”的音频,并自动播放。为了更好地控制,他们有一个协议“ AudioSink”,其中包含一个函数,该函数提供与上面的Audio类中相同的CMSampleBuffer。 - Alok Subedi
2个回答

5
你可以从 CMSampleBuffer 中获取完整的数据缓冲区,并将其转换为 Data:
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer)
let blockBufferDataLength = CMBlockBufferGetDataLength(blockBuffer!)
var blockBufferData  = [UInt8](repeating: 0, count: blockBufferDataLength)
let status = CMBlockBufferCopyDataBytes(blockBuffer!, atOffset: 0, dataLength: blockBufferDataLength, destination: &blockBufferData)
guard status == noErr else { return }
let data = Data(bytes: blockBufferData, count: blockBufferDataLength)

请参考AVAudioPlayer概述:

除非您正在播放从网络流捕获的音频或需要非常低的I/O延迟,否则请使用此类进行音频播放。

因此我认为它不适合您。您最好使用AVAudioEngineAudio Queue Services


1
已经获取到数据。我将尝试使用“音频队列服务”并进行更新。谢谢。 - Alok Subedi
嘿,Alok。你解决了这个问题吗?我也在尝试实现类似的功能。我正在使用Twilio并尝试让屏幕上的音量控制器正常工作。我已经花费了数小时来使用MPVolumeView进行工作,但是没有结果。现在正在尝试弄清楚如何将CMSampleBuffer输入AVAudioPlayer,以便MPVolumeView可以按预期工作。 - jones_corey

-4

尝试将音频文件保存到文档目录,然后播放声音。这对我有效。

    func playMusic() {
        let url = NSBundle.mainBundle().URLForResource("Audio", withExtension: "mp3")!
        let data = NSData(contentsOfURL: url)!
        AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
        AVAudioSession.sharedInstance().setActive(true, error: nil)
        audioPlayer = AVAudioPlayer(data: data, fileTypeHint: AVFileTypeMPEGLayer3, error: nil)
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    }


你能提供保存音频文件到文档的代码吗? - Alok Subedi
do{ let documentDirectory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false) let pathToSave = "\Music.mp3" let fileURL = documentDirectory.appendingPathComponent(pathToSave) try data.write(to: fileURL) }catch { print(error) } - Manav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接