从 AVCaptureSession 录制的音频流式传输到另一台设备时会生成 "Bad Address" 错误
Audio being recorded from AVCaptureSession is generating a "Bad Address" error when streaming to another device
非常感谢,我知道这个问题可能很难理解。如果您需要任何说明或希望我更好地解释方法,那么我很乐意为您提供帮助。
我正在设置 AVCaptureSession 并使用此方法创建 OutputStream。 OutputStream 由 MultipeerConnectivity 中的方法创建。更具体地说,方法:startStream(withName: _, fromPeer: _)。如果您不熟悉此方法,它 returns outputStream 并将 inputStream 发送到对等方。
func setupAVRecorder() {
do {
try recordingSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try recordingSession.setMode(AVAudioSessionModeVoiceChat)
try recordingSession.setPreferredSampleRate(44000.00)
try recordingSession.setPreferredIOBufferDuration(0.2)
try recordingSession.setActive(true)
recordingSession.requestRecordPermission() { [unowned self] (allowed: Bool) -> Void in
DispatchQueue.main.async {
if allowed {
do {
self.captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
try self.captureDeviceInput = AVCaptureDeviceInput.init(device: self.captureDevice)
self.outputDevice = AVCaptureAudioDataOutput()
self.outputDevice?.setSampleBufferDelegate(self, queue: DispatchQueue.main)
self.captureSession = AVCaptureSession()
self.captureSession.addInput(self.captureDeviceInput)
self.captureSession.addOutput(self.outputDevice)
}
catch let error {
print("\(#file) > \(#function) > ERROR: \(error.localizedDescription)")
}
}
}
}
}
catch let error {
print("\(#file) > \(#function) > ERROR: \(error.localizedDescription)")
}
//------------------------------------------------------------------
// Set output stream
if (!outputStreamIsSet) {
do {
outputStream = try self.appDelegate.connectionManager.sessions[sessionIndex!].startStream(withName: "audioStream", toPeer: peerID!)
outputStreamIsSet = true
}
catch let error as NSError {
print("\(#file) > \(#function) > Failed to create outputStream: \(error.localizedDescription)")
endCallButtonIsClicked(endCallButton) // this just ends the stream
}
}
}
一旦用户真正相互连接,就会调用委托方法。在委托方法中我们得到 InputStream,我们打开输出和输入流,最后我们使用 startRunning() 方法开始记录:
func startedStreamWithPeer(_ peerID: MCPeerID, inputStream: InputStream) {
if (peerID == self.peerID) {
self.inputStream = inputStream
self.inputStreamIsSet = true
self.inputStream?.delegate = self
self.inputStream?.open()
self.outputStream?.open()
self.captureSession.startRunning()
}
else {
print("\(#file) > \(#function) > Should not print.")
}
}
问题来了。 captureSession 将数据记录到缓冲区并调用 captureOutput 方法(我相信这是一个委托方法)。在此方法内部,我尝试将 CMSampleBuffer 转换为 UnsafePointer,以便我可以将其写入 outputStream 并在另一端接收。问题是我得到一个错误 "The operation couldn’t be completed. Bad address"。我认为这与我录制音频的方式有关,但我不完全确定。
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
var blockBuffer: CMBlockBuffer?
var audioBufferList: AudioBufferList = AudioBufferList.init()
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, nil, &audioBufferList, MemoryLayout<AudioBufferList>.size, nil, nil, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer)
let buffers = UnsafeMutableAudioBufferListPointer(&audioBufferList)
for buffer in buffers {
let output = outputStream?.write((buffer.mData?.load(as: UnsafePointer<UInt8>.self))!, maxLength: Int(buffer.mDataByteSize))
if (output == -1) {
let error = outputStream?.streamError
print("\(#file) > \(#function) > Error: \(error!.localizedDescription)")
}
}
}
在最后一个打印语句中,我收到了我之前提到的错误 "The operation couldn’t be completed. Bad address"。
有没有人在录制音频然后将该音频转换为 UnsafePointer 对象方面具有一定的专业知识?
谢谢!
buffer.mData?.load(as: UnsafePointer<UInt8>.self)
读取buffer.mData
指向的字节到UnsafePointer<UInt8>
变量,换句话说,指针被 取消引用, 和结果
作为缓冲区地址传递给 write()
方法。
但是,buffer.mData
指向音频数据而不是(有效)
指针,这就是为什么 write()
以 "Bad address".
失败的原因
你真正想要的是 "cast" 或 "reinterpret" buffer.mData
作为 UnsafePointer<UInt8>
,这是用
完成的
let u8ptr = buffer.mData!.assumingMemoryBound(to: UInt8.self)
let output = outputStream!.write(u8ptr, maxLength: Int(buffer.mDataByteSize))
(我留给你用可选绑定替换强制解包
或可选的链接。)
非常感谢,我知道这个问题可能很难理解。如果您需要任何说明或希望我更好地解释方法,那么我很乐意为您提供帮助。
我正在设置 AVCaptureSession 并使用此方法创建 OutputStream。 OutputStream 由 MultipeerConnectivity 中的方法创建。更具体地说,方法:startStream(withName: _, fromPeer: _)。如果您不熟悉此方法,它 returns outputStream 并将 inputStream 发送到对等方。
func setupAVRecorder() {
do {
try recordingSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try recordingSession.setMode(AVAudioSessionModeVoiceChat)
try recordingSession.setPreferredSampleRate(44000.00)
try recordingSession.setPreferredIOBufferDuration(0.2)
try recordingSession.setActive(true)
recordingSession.requestRecordPermission() { [unowned self] (allowed: Bool) -> Void in
DispatchQueue.main.async {
if allowed {
do {
self.captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
try self.captureDeviceInput = AVCaptureDeviceInput.init(device: self.captureDevice)
self.outputDevice = AVCaptureAudioDataOutput()
self.outputDevice?.setSampleBufferDelegate(self, queue: DispatchQueue.main)
self.captureSession = AVCaptureSession()
self.captureSession.addInput(self.captureDeviceInput)
self.captureSession.addOutput(self.outputDevice)
}
catch let error {
print("\(#file) > \(#function) > ERROR: \(error.localizedDescription)")
}
}
}
}
}
catch let error {
print("\(#file) > \(#function) > ERROR: \(error.localizedDescription)")
}
//------------------------------------------------------------------
// Set output stream
if (!outputStreamIsSet) {
do {
outputStream = try self.appDelegate.connectionManager.sessions[sessionIndex!].startStream(withName: "audioStream", toPeer: peerID!)
outputStreamIsSet = true
}
catch let error as NSError {
print("\(#file) > \(#function) > Failed to create outputStream: \(error.localizedDescription)")
endCallButtonIsClicked(endCallButton) // this just ends the stream
}
}
}
一旦用户真正相互连接,就会调用委托方法。在委托方法中我们得到 InputStream,我们打开输出和输入流,最后我们使用 startRunning() 方法开始记录:
func startedStreamWithPeer(_ peerID: MCPeerID, inputStream: InputStream) {
if (peerID == self.peerID) {
self.inputStream = inputStream
self.inputStreamIsSet = true
self.inputStream?.delegate = self
self.inputStream?.open()
self.outputStream?.open()
self.captureSession.startRunning()
}
else {
print("\(#file) > \(#function) > Should not print.")
}
}
问题来了。 captureSession 将数据记录到缓冲区并调用 captureOutput 方法(我相信这是一个委托方法)。在此方法内部,我尝试将 CMSampleBuffer 转换为 UnsafePointer,以便我可以将其写入 outputStream 并在另一端接收。问题是我得到一个错误 "The operation couldn’t be completed. Bad address"。我认为这与我录制音频的方式有关,但我不完全确定。
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
var blockBuffer: CMBlockBuffer?
var audioBufferList: AudioBufferList = AudioBufferList.init()
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, nil, &audioBufferList, MemoryLayout<AudioBufferList>.size, nil, nil, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer)
let buffers = UnsafeMutableAudioBufferListPointer(&audioBufferList)
for buffer in buffers {
let output = outputStream?.write((buffer.mData?.load(as: UnsafePointer<UInt8>.self))!, maxLength: Int(buffer.mDataByteSize))
if (output == -1) {
let error = outputStream?.streamError
print("\(#file) > \(#function) > Error: \(error!.localizedDescription)")
}
}
}
在最后一个打印语句中,我收到了我之前提到的错误 "The operation couldn’t be completed. Bad address"。
有没有人在录制音频然后将该音频转换为 UnsafePointer 对象方面具有一定的专业知识?
谢谢!
buffer.mData?.load(as: UnsafePointer<UInt8>.self)
读取buffer.mData
指向的字节到UnsafePointer<UInt8>
变量,换句话说,指针被 取消引用, 和结果
作为缓冲区地址传递给 write()
方法。
但是,buffer.mData
指向音频数据而不是(有效)
指针,这就是为什么 write()
以 "Bad address".
你真正想要的是 "cast" 或 "reinterpret" buffer.mData
作为 UnsafePointer<UInt8>
,这是用
let u8ptr = buffer.mData!.assumingMemoryBound(to: UInt8.self)
let output = outputStream!.write(u8ptr, maxLength: Int(buffer.mDataByteSize))
(我留给你用可选绑定替换强制解包 或可选的链接。)