2017-01-31 28 views
2

非常感謝,我知道這個問題可能很難遵循。如果您需要澄清或希望我更好地解釋一種方法,那麼我會很樂意幫助您。從AVCaptureSession錄製的音頻在流到其他設備時產生「錯誤地址」錯誤

我正在設置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 
    } 
} 
} 

一旦用戶真正連接到對方,委託方法就會被調用。裏面的委託方法,我們得到的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,並且可以在另一端接收它。問題是,我得到一個錯誤「操作無法完成。錯誤的地址」。我認爲這與我錄製音頻的方式有關,但我不完全確定。

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

在上次的打印聲明中,我收到了前面提到的錯誤「操作無法完成。錯誤的地址」。

有沒有人有錄音的專業知識,然後將該音頻轉換爲UnsafePointer對象?

謝謝!

回答

2
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)) 

(我讓你來取代強迫做可選綁定 解開或可選的鏈接。)

+0

感謝@Martin修復了這個問題。現在唯一的問題是InputStream委託方法「func stream(Stream,eventCode)」沒有被調用......我想這是另一個問題。 – Logan