尝试通过多路连接将音频从麦克风传输到另一部手机

nul*_*ife 7 avfoundation audio-streaming swift avaudioengine swift3

我正试图通过Apples Multipeer Connectivity框架将音频从麦克风传输到另一部iPhone.要做到音频捕获和播放我使用AVAudioEngine(非常感谢艺术Fistman"的回答在这里).

我通过在输入上安装一个麦克风来接收来自麦克风的数据,从中我得到一个AVAudioPCMBuffer,然后我将其转换为一个UInt8数组,然后我将其流式传输到另一部手机.

但是当我将数组转换回AVAudioPCMBuffer时,我得到一个EXC_BAD_ACCESS异常,编译器指向我再次将字节数组转换为AVAudioPCMBuffer的方法.

以下是我正在处理,转换和流式传输输入的代码:

input.installTap(onBus: 0, bufferSize: 2048, format: input.inputFormat(forBus: 0), block: {
                (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in

                let audioBuffer = self.typetobinary(buffer)
                stream.write(audioBuffer, maxLength: audioBuffer.count)
            })
Run Code Online (Sandbox Code Playgroud)

我对将数据转换两种功能(摘自Martin.R的答案在这里):

func binarytotype <T> (_ value: [UInt8], _: T.Type) -> T {
    return value.withUnsafeBufferPointer {
        UnsafeRawPointer($0.baseAddress!).load(as: T.self)
    }

}

func typetobinary<T>(_ value: T) -> [UInt8] {
    var data = [UInt8](repeating: 0, count: MemoryLayout<T>.size)
    data.withUnsafeMutableBufferPointer {
        UnsafeMutableRawPointer($0.baseAddress!).storeBytes(of: value, as: T.self)
    }
    return data
}
Run Code Online (Sandbox Code Playgroud)

并在接收端:

func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
    if streamName == "voice" {

        stream.schedule(in: RunLoop.current, forMode: .defaultRunLoopMode)
        stream.open()

        var bytes = [UInt8](repeating: 0, count: 8)
        stream.read(&bytes, maxLength: bytes.count)

        let audioBuffer = self.binarytotype(bytes, AVAudioPCMBuffer.self) //Here is where the app crashes

        do {
            try engine.start()

            audioPlayer.scheduleBuffer(audioBuffer, completionHandler: nil)
            audioPlayer.play()
       }catch let error {
            print(error.localizedDescription)

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我可以来回转换字节数组并在流式传输之前播放声音(在同一部手机中),但不能在接收端创建AVAudioPCMBuffer.有谁知道为什么转换在接收端不起作用?这是正确的方法吗?

任何帮助,关于此的想法/意见将非常感激.

Rhy*_*man 4

您的AVAudioPCMBuffer序列化/反序列化是错误的。

Swift3 的转换发生了很大变化,并且似乎比 Swift2 需要更多的复制。

[UInt8]以下是在和s之间进行转换的方法AVAudioPCMBuffer

注意:此代码假设单浮点数据为 44.1kHz。
你可能想改变这一点。

func copyAudioBufferBytes(_ audioBuffer: AVAudioPCMBuffer) -> [UInt8] {
    let srcLeft = audioBuffer.floatChannelData![0]
    let bytesPerFrame = audioBuffer.format.streamDescription.pointee.mBytesPerFrame
    let numBytes = Int(bytesPerFrame * audioBuffer.frameLength)

    // initialize bytes to 0 (how to avoid?)
    var audioByteArray = [UInt8](repeating: 0, count: numBytes)

    // copy data from buffer
    srcLeft.withMemoryRebound(to: UInt8.self, capacity: numBytes) { srcByteData in
        audioByteArray.withUnsafeMutableBufferPointer {
            $0.baseAddress!.initialize(from: srcByteData, count: numBytes)
        }
    }

    return audioByteArray
}

func bytesToAudioBuffer(_ buf: [UInt8]) -> AVAudioPCMBuffer {
    // format assumption! make this part of your protocol?
    let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: true)
    let frameLength = UInt32(buf.count) / fmt.streamDescription.pointee.mBytesPerFrame

    let audioBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: frameLength)
    audioBuffer.frameLength = frameLength

    let dstLeft = audioBuffer.floatChannelData![0]
    // for stereo
    // let dstRight = audioBuffer.floatChannelData![1]

    buf.withUnsafeBufferPointer {
        let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: Float.self, capacity: Int(frameLength))
        dstLeft.initialize(from: src, count: Int(frameLength))
    }

    return audioBuffer
}
Run Code Online (Sandbox Code Playgroud)