如何通过 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 块(即使你读得少),缓冲区创建可能总是成功。现在可能不会了。
您可以在 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 块(即使你读得少),缓冲区创建可能总是成功。现在可能不会了。