swift - 从 AVCaptureSession 录制的音频在流式传输到另一台设备时生成 "Bad Address"错误

标签 swift audio stream avfoundation avaudiosession

提前致谢,我知道这个问题可能很难理解。如果您需要任何说明或希望我更好地解释方法,那么我很乐意为您提供帮助。

我正在设置 AVCaptureSession 并使用此方法创建 OutputStream。 OutputStream 由 MultipeerConnectivity 中的方法创建。更具体地说,方法:startStream(withName: _, fromPeer: _)。如果您不熟悉此方法,它会返回 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
    }
}
}

一旦用户真正相互连接,委托(delegate)方法就会被调用。在委托(delegate)方法中我们得到 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 方法(我相信这是一个委托(delegate)方法)。在此方法内部,我尝试将 CMSampleBuffer 转换为 UnsafePointer,以便我可以将其写入 outputStream 并在另一端接收。问题是我收到错误消息“操作无法完成。地址错误”。我认为这与我录制音频的方式有关,但我不完全确定。

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)")
        }
    }
}

在最后一个 print 语句中,我得到了我之前提到的错误“操作无法完成。错误的地址”。

有没有人在录制音频然后将该音频转换为 UnsafePointer 对象方面具有一定的专业知识?

谢谢!

最佳答案

buffer.mData?.load(as: UnsafePointer<UInt8>.self)

读取 buffer.mData 的字节指向 UnsafePointer<UInt8> 变量,换句话说,指针被取消引用,并且结果 作为缓冲区地址传递给 write()方法。 然而,buffer.mData指向音频数据而不是(有效) 指针,这就是为什么 write()因“地址错误”而失败。

您真正想要的是“转换”或“重新诠释”buffer.mData 作为UnsafePointer<UInt8> , 这是用

let u8ptr = buffer.mData!.assumingMemoryBound(to: UInt8.self)
let output = outputStream!.write(u8ptr, maxLength: Int(buffer.mDataByteSize))

(我留给你用可选绑定(bind)替换强制解包 或可选的链接。)

关于swift - 从 AVCaptureSession 录制的音频在流式传输到另一台设备时生成 "Bad Address"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41968817/

相关文章:

ios - 为什么每次快速播放声音时我的游戏都会出现延迟?

ios - UIButton 文本仅在触摸时出现

macos - 不调用委托(delegate)函数 - NSURLConnection

stream - 读取字节忽略 SBCL 灰色流中的 eof-error-p

android - 下载大文件时 Dart/Flutter HTTP 响应不完整

c++ - 将文件流重定向到内存流

Swift函数,一个参数有两个名字

java - 如何修复声音?

iphone - 如何在 OpenAL 或 Core Audio 中调整 Head-related transfer function (HRTF)?

java - 如何让一个声音在Processing中播放一次?