首页 > 解决方案 > 播放使用 AVCaptureAudioDataOutput 录制的音频

问题描述

我正在尝试录制视频和音频并通过网络发送它们,以便它们可以在其他客户端上实时播放。我已成功录制和播放视频,但仍然无法播放音频(请参阅下面代码底部的 AVAudioPlayer)。我做错了什么或缺少什么?(还有几个其他 StackOverflow 问题似乎解决了同样的问题,但即使那里的评论表明有些人能够使它工作,但没有一个显示出明确的工作答案。)提前谢谢你任何输入。

let captureSession = AVCaptureSession()

private func startVideoFeed() {
    let sessionPreset = AVCaptureSession.Preset.low
    if captureSession.canSetSessionPreset(sessionPreset) {
        captureSession.sessionPreset = sessionPreset
    }
    switch AVCaptureDevice.authorizationStatus(for: .video) {
    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .video) { success in
            self.startVideoFeed()
        }
    case .authorized:
        captureSession.beginConfiguration()
        let captureVideoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)!
        let captureVideoInput = try! AVCaptureDeviceInput(device: captureVideoDevice)
        if captureSession.canAddInput(captureVideoInput) {
            captureSession.addInput(captureVideoInput)
        }
        let captureVideoOutput = AVCaptureVideoDataOutput()
        captureVideoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
        if captureSession.canAddOutput(captureVideoOutput) {
            captureSession.addOutput(captureVideoOutput)
        }
        captureSession.commitConfiguration()
        captureSession.startRunning()
    default:
        break
    }
}

private func startAudioFeed() {
    switch AVCaptureDevice.authorizationStatus(for: .audio) {
    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .audio) { success in
            self.startAudioFeed()
        }
    case .authorized:
        captureSession.beginConfiguration()
        let captureAudioDevice = AVCaptureDevice.default(for: .audio)!
        let captureAudioInput = try! AVCaptureDeviceInput(device: captureAudioDevice)
        if captureSession.canAddInput(captureAudioInput) {
            captureSession.addInput(captureAudioInput)
        }
        let captureAudioOutput = AVCaptureAudioDataOutput()
        captureAudioOutput.audioSettings = [AVFormatIDKey: kAudioFormatLinearPCM, AVNumberOfChannelsKey: NSNumber(value: 1), AVSampleRateKey: NSNumber(value: 44100)]
        captureAudioOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
        if captureSession.canAddOutput(captureAudioOutput) {
            captureSession.addOutput(captureAudioOutput)
        }
        captureSession.commitConfiguration()
    default:
        break
    }
}

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    if let imageBuffer = sampleBuffer.imageBuffer {
        let ciImage = CIImage(cvPixelBuffer: imageBuffer)
        let cgImage = CIContext().createCGImage(ciImage, from: ciImage.extent)!
        let data = CFDataCreateMutable(nil, 0)!
        let imageDestination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil)!
        CGImageDestinationAddImage(imageDestination, cgImage, [kCGImageDestinationLossyCompressionQuality: NSNumber(value: 0)] as CFDictionary)
        CGImageDestinationFinalize(imageDestination)
        play(data: data as Data)
    } else if let dataBuffer = sampleBuffer.dataBuffer {
        let data = try! dataBuffer.dataBytes()
        play(data: data)
    }
}

private func play(data: Data) {
    if let image = CGImage(jpegDataProviderSource: CGDataProvider(data: data as CFData)!, decode: nil, shouldInterpolate: false, intent: .defaultIntent) {
        // image is a valid image
    } else if let audioPlayer = try? AVAudioPlayer(data: data) {
        audioPlayer.play()
        // audioPlayer is always nil with error: Error Domain=NSOSStatusErrorDomain Code=1954115647 "(null)"
    }
}

标签: iosswiftmacosavfoundationavkit

解决方案


https://developer.apple.com/documentation/coremedia/1489629-cmsamplebuffergetdatabuffer

调用者不拥有返回的 dataBuffer,如果调用者需要维护对它的引用,则必须显式保留它。

您将需要对数据执行CFRetain和 CFRelease。

由于您正在初始化它的数据,播放器为零。将 sampleBuffer 转换为 Data

NSOSStatusErrorDomain 代码=1954115647


推荐阅读