【问题标题】:Can't play audio recorded from voice using AVCaptureAudioDataOutputSampleDelegate无法使用 AVCaptureAudioDataOutputSampleDelegate 播放从语音录制的音频
【发布时间】:2017-01-16 13:23:07
【问题描述】:

我已经用谷歌搜索和研究了好几天,但我似乎无法让它工作,我在互联网上找不到任何解决方案。

我正在尝试使用麦克风捕捉我的声音,然后通过扬声器播放。

这是我的代码:

class ViewController: UIViewController, AVAudioRecorderDelegate, AVCaptureAudioDataOutputSampleBufferDelegate {

var recordingSession: AVAudioSession!
var audioRecorder: AVAudioRecorder!
var captureSession: AVCaptureSession!
var microphone: AVCaptureDevice!
var inputDevice: AVCaptureDeviceInput!
var outputDevice: AVCaptureAudioDataOutput!

override func viewDidLoad() {
    super.viewDidLoad()

    recordingSession = AVAudioSession.sharedInstance()

    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.microphone = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
                        try self.inputDevice = AVCaptureDeviceInput.init(device: self.microphone)

                        self.outputDevice = AVCaptureAudioDataOutput()
                        self.outputDevice.setSampleBufferDelegate(self, queue: DispatchQueue.main)

                        self.captureSession = AVCaptureSession()
                        self.captureSession.addInput(self.inputDevice)
                        self.captureSession.addOutput(self.outputDevice)
                        self.captureSession.startRunning()
                    }
                    catch let error {
                        print(error.localizedDescription)
                    }
                }
            }
        }
    }catch let error{
        print(error.localizedDescription)
    }
}

还有回调函数:

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {

    var audioBufferList = AudioBufferList(
        mNumberBuffers: 1,
        mBuffers: AudioBuffer(mNumberChannels: 0,
        mDataByteSize: 0,
        mData: nil)
    )

    var blockBuffer: CMBlockBuffer?

    var osStatus = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(

        sampleBuffer,
        nil,
        &audioBufferList,
        MemoryLayout<AudioBufferList>.size,
        nil,
        nil,
        UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment),
        &blockBuffer
    )

    do {
        var data: NSMutableData = NSMutableData.init()
        for i in 0..<audioBufferList.mNumberBuffers {

            var audioBuffer = AudioBuffer(
                 mNumberChannels: audioBufferList.mBuffers.mNumberChannels,
                 mDataByteSize: audioBufferList.mBuffers.mDataByteSize,
                 mData: audioBufferList.mBuffers.mData
            )

            let frame = audioBuffer.mData?.load(as: Float32.self)
            data.append(audioBuffer.mData!, length: Int(audioBuffer.mDataByteSize))

        }

        var dataFromNsData = Data.init(referencing: data)
        var avAudioPlayer: AVAudioPlayer = try AVAudioPlayer.init(data: dataFromNsData)
        avAudioPlayer.prepareToPlay()
        avAudioPlayer.play()
        }
    }
    catch let error {
        print(error.localizedDescription)
        //prints out The operation couldn’t be completed. (OSStatus error 1954115647.)
}

对此的任何帮助都会令人惊叹,并且可能也会帮助很多其他人,因为那里有很多不完整的 swift 版本。

谢谢。

【问题讨论】:

标签: ios swift avfoundation swift3 avaudiosession


【解决方案1】:

你很亲密!您在 didOutputSampleBuffer 回调中捕获音频,但这是一个高频回调,因此您创建了很多 AVAudioPlayers 并将原始 LPCM 数据传递给它们,而它们只知道如何解析 CoreAudio 文件类型,然后它们将继续反正超出范围。

您可以使用AVAudioEngineAVAudioPlayerNode 轻松播放使用AVCaptureSession 捕获的缓冲区,但此时您也可以使用AVAudioEngine 从麦克风录制:

import UIKit
import AVFoundation

class ViewController: UIViewController {
    var engine = AVAudioEngine()

    override func viewDidLoad() {
        super.viewDidLoad()

        let input = engine.inputNode!
        let player = AVAudioPlayerNode()
        engine.attach(player)

        let bus = 0
        let inputFormat = input.inputFormat(forBus: bus)
        engine.connect(player, to: engine.mainMixerNode, format: inputFormat)

        input.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) -> Void in
            player.scheduleBuffer(buffer)
        }

        try! engine.start()
        player.play()
    }
}

【讨论】:

  • 这很棒,正是我想要的!非常感谢!
  • 你能解释一下关于 func captureOutput 我们必须写什么以及如何使用你的代码吗? @节奏
  • stackoverflow.com/questions/50968519/… 请你帮忙解决这个问题,我已经写了所有要点
猜你喜欢
  • 2013-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多