如何通过 OutputStream 发送 NSData

How to send NSData over an OutputStream

您可以在 github 上查看此项目:https://github.com/Lkember/MotoIntercom/

重要的class是PhoneViewController.swift

我有一个 AVAudioPCMBuffer。然后使用此函数将缓冲区转换为 NSData:

func audioBufferToNSData(PCMBuffer: AVAudioPCMBuffer) -> NSData {
    let channelCount = 1
    let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: channelCount)
    let data = NSData(bytes: channels[0], length:Int(PCMBuffer.frameCapacity * PCMBuffer.format.streamDescription.pointee.mBytesPerFrame))

    return data
}

根据 OutputStream.write 上的文档,此数据需要转换为 UnsafePointer< UInt8 >。

https://developer.apple.com/reference/foundation/outputstream/1410720-write

这是我目前所拥有的:

let data = self.audioBufferToNSData(PCMBuffer: buffer)
let output = self.outputStream!.write(UnsafePointer<UInt8>(data.bytes.assumingMemoryBound(to: UInt8.self)), maxLength: data.length)

收到此数据后,使用此方法将其转换回 AVAudioPCMBuffer:

func dataToPCMBuffer(data: NSData) -> AVAudioPCMBuffer {

    let audioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)  // given NSData audio format
    let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.length) / audioFormat.streamDescription.pointee.mBytesPerFrame)
    audioBuffer.frameLength = audioBuffer.frameCapacity
    let channels = UnsafeBufferPointer(start: audioBuffer.floatChannelData, count: Int(audioBuffer.format.channelCount))
    data.getBytes(UnsafeMutableRawPointer(channels[0]) , length: data.length)
    return audioBuffer
}

不幸的是,当我播放这个 audioBuffer 时,我只听到静电。我不认为这是我从 AVAudioPCMBuffer 到 NSData 的转换或从 NSData 转换回 AVAudioPCMBuffer 的问题。我想这就是我将 NSData 写入流的方式。

我不相信这是我的转换的原因是因为我创建了一个位于 here 的示例项目(您可以下载并尝试)将音频录制到 AVAudioPCMBuffer,然后将其转换为 NSData ,将 NSData 转换回 AVAudioPCMBuffer 并播放音频。在这种情况下播放音频没有问题。


编辑:

我也从未展示过我实际上是如何从流中获取数据的。这是如何完成的:

func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    switch (eventCode) {

    case Stream.Event.hasBytesAvailable:
        DispatchQueue.global().async {

            var buffer = [UInt8](repeating: 0, count: 8192)
            let length = self.inputStream!.read(&buffer, maxLength: buffer.count)

            let data = NSData.init(bytes: buffer, length: buffer.count)

            print("\(#file) > \(#function) > \(length) bytes read on queue \(self.currentQueueName()!) buffer.count \(data.length)")

            if (length > 0) {
                let audioBuffer = self.dataToPCMBuffer(data: data)

                self.audioPlayerQueue.async {
                    self.peerAudioPlayer.scheduleBuffer(audioBuffer)

                    if (!self.peerAudioPlayer.isPlaying && self.localAudioEngine.isRunning) {
                        self.peerAudioPlayer.play()
                    }
                }
            }
            else if (length == 0) {
                print("\(#file) > \(#function) > Reached end of stream")
            }
        }

获得此数据后,我使用 dataToPCMBuffer 方法将其转换为 AVAudioPCMBuffer。


编辑 1:

这是我使用的 AVAudioFormat:

self.localInputFormat = AVAudioFormat.init(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)

最初,我使用的是:

self.localInputFormat = self.localInput?.inputFormat(forBus: 0)

但是,如果频道数不等于预期的频道数,我就会崩溃。所以我把它切换到上面。

我实际使用的 AVAudioPCMBuffer 在 installTap 方法中(其中 localInput 是一个 AVAudioInputNode):

localInput?.installTap(onBus: 0, bufferSize: 4096, format: localInputFormat) {
        (buffer, time) -> Void in

很确定你想替换这个:

let length = self.inputStream!.read(&buffer, maxLength: buffer.count)
let data = NSData.init(bytes: buffer, length: buffer.count)

let length = self.inputStream!.read(&buffer, maxLength: buffer.count)
let data = NSData.init(bytes: buffer, length: length)

另外,我不是 100% 确定随机数据块总是可以用来制作音频缓冲区。您可能需要先将数据收集到更大的 NSData 块中。

现在,因为你总是传入 8192 块(即使你读得少),缓冲区创建可能总是成功。现在可能不会了。