播放来自CMSampleBuffer的音频

时间:2019-07-17 12:08:15

标签: ios swift twilio avaudioplayer cmsamplebuffer

我为iOS中的群组创建了视频聊天应用。我一直在寻找一些方法来分别控制不同参与者的音量。我在isPlaybackEnabled中找到了使用RemoteAudioTrack静音取消静音的方法,但没有控制音量。

我还认为我们是否可以在AVAudioPlayer中使用它。我找到了addSink。这是我在here

中尝试过的
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)上崩溃了。

3 个答案:

答案 0 :(得分:2)

您可以从 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 :(得分:0)

虽然我不确定为什么您的方法不起作用起作用,但是我使用CMSampleBuffer编辑了其他Data。试试这个:

class Audio: NSObject {
    func renderSample(_ sampleBuffer: CMSampleBuffer!) {
        let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
        CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
        let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!)
        let height = CVPixelBufferGetHeight(imageBuffer!)
        let src_buff = CVPixelBufferGetBaseAddress(imageBuffer!)
        let data = Data(bytes: src_buff!, count: bytesPerRow * height)
        CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))

        doSomething(data: Data)
    }

    func doSomething(data:Data)
    {
        print(data.count) //Make sure isn't 0
    }
}

这只是从缓冲区创建一个Data,并确保锁定和解锁,以使其他人不锁定或不锁定。由于我没有要测试的音频缓冲区,所以这只是黑暗中的一枪。让我知道!

答案 2 :(得分:-2)

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

    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()
    }