web-dev-qa-db-ja.com

CMSampleBufferからオーディオを再生する

IOSでグループ用のビデオチャットアプリを作成しました。さまざまな参加者のオーディオボリュームを個別に制御する方法をいくつか探しています。 isPlaybackEnabledRemoteAudioTrackを使用してミュートおよびミュート解除する方法を見つけましたが、音量を制御する方法はありませんでした。

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)でクラッシュしました。


編集:
これはエラーです: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)}
}
_
8
Alok Subedi

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レイテンシが必要な場合を除き、このクラスをオーディオ再生に使用します。

だから私はそれがあなたのために働くとは思いません。 AVAudioEngine または Audio Queue Services を使用することをお勧めします。

2
Pavel Kozlov

あなたの方法しないが機能する理由はわかりませんが、CMSampleBufferを使用して他のDatasを編集しました。これを試して:

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を作成し、他の人がロックしないかロックしないようにロックとロック解除を確実にします。テストするオーディオバッファーがないので、これは暗闇の中でのショットです。お知らせ下さい!

0
impression7vx