【问题标题】:How to get Audio recording buffer data live?如何实时获取音频录制缓冲区数据?
【发布时间】:2019-01-11 22:51:26
【问题描述】:

我正在从 iPhone 麦克风获取音频数据并将其发送到套接字,我已经尝试使用 AVAudioEngine 来获取音频缓冲区,但有些它无法正常工作。所以你能建议我用什么更好的方法来实时记录缓冲区数据。

  override func viewDidLoad() {
        super.viewDidLoad()



        // initialize engine
        engine = AVAudioEngine()
        guard nil != engine?.inputNode else {
            // @TODO: error out
            return
        }



        SocketIOManager.sharedInstance.socket.on("listen") {data, ack in

            let BuffurData:Data = data[0] as! Data

            // let playData = self?.audioBufferToNSData(PCMBuffer: BuffurData as! AVAudioPCMBuffer)
            do {
               // let data = NSData(bytes: &BuffurData, length: BuffurData.count)

                let player = try AVAudioPlayer(data:BuffurData)
                player.play()
            } catch let error as NSError {
                print(error.description)
            }



            print("socket connected \(data)")
        }
    }

 func installTap() {

        engine = AVAudioEngine()
        guard let engine = engine, let input = engine.inputNode else {
            // @TODO: error out
            return
        }

        let format = input.inputFormat(forBus: 0)
        input.installTap(onBus: 0, bufferSize:4096, format:format, block: { [weak self] buffer, when in

            guard let this = self else {
                return
            }

            // writing to file: for testing purposes only
            do {
                try this.file!.write(from: buffer)
            } catch {

            }

            if let channel1Buffer = buffer.floatChannelData?[0] {
               let test = self?.copyAudioBufferBytes(buffer)
                let stram = self?.toNSData(PCMBuffer: buffer)
                SocketIOManager.sharedInstance.socket.emit("talk",stram!);

               // socket.on("listen", function (data)



                /*! @property floatChannelData
                 @abstract Access the buffer's float audio samples.
                 @discussion
                 floatChannelData returns pointers to the buffer's audio samples if the buffer's format is
                 32-bit float, or nil if it is another format.

                 The returned pointer is to format.channelCount pointers to float. Each of these pointers
                 is to "frameLength" valid samples, which are spaced by "stride" samples.

                 If format.interleaved is false (as with the standard deinterleaved float format), then
                 the pointers will be to separate chunks of memory. "stride" is 1.

                 If format.interleaved is true, then the pointers will refer into the same chunk of interleaved
                 samples, each offset by 1 frame. "stride" is the number of interleaved channels.
                 */

                // @TODO: send data, better to pass into separate queue for processing
            }            
        })

        engine.prepare()

        do {
            try engine.start()
        } catch {
            // @TODO: error out
        }
    }

【问题讨论】:

  • AVAudioEngine 有什么问题?
  • 查看我的更新代码,我希望我将缓冲区转换为数据并发送到套接字,当我通过套接字获取一些数据时,我无法播放它。查看 viewDidLoad 函数,我正在尝试从套接字响应中播放它。
  • 你应该使用 AVAudioPlayerNode 来播放缓冲区。首先,将数据转换为缓冲区,然后播放。
  • self.audioPlayer.scheduleBuffer(pcmBuffer, completionHandler: nil), self.audioPlayer.play()
  • 能否请您提供更多关于如何玩的信息

标签: ios swift audio-streaming


【解决方案1】:

试试这个代码:

var audioPlayerQueue = DispatchQueue(label: "audioPlayerQueue", qos: DispatchQoS.userInteractive)

var peerAudioPlayer: AVAudioPlayerNode = AVAudioPlayerNode()
var peerInputFormat: AVAudioFormat?

override func viewDidLoad() {
    super.viewDidLoad()
    // initialize engine
    engine = AVAudioEngine()
    guard nil != engine?.inputNode else {
        // @TODO: error out
        return
    }
    engine.attach(self.peerAudioPlayer)
    self.peerInputFormat = AVAudioFormat.init(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)
    self.peerAudioEngine.connect(peerAudioPlayer, to: self.peerAudioEngine.mainMixerNode, format: peerInput?.outputFormat(forBus: 0))
    do {
        peerAudioEngine.prepare()
        try peerAudioEngine.start()
    } catch let error {
        print(error.localizedDescription)
    }

    SocketIOManager.sharedInstance.socket.on("listen") { data, ack in
        let pcmBuffer = toPCMBuffer(data: data)
        self.audioPlayerQueue.async {
            self.peerAudioPlayer.scheduleBuffer(pcmBuffer, completionHandler: nil)
            if self.peerAudioEngine.isRunning {
                self.peerAudioPlayer.play()
            } else {
                do {
                    try self.peerAudioEngine.start()
                } catch {
                    print(error.localizedDescription)
                }
            }
        }
    }

    print("socket connected \(data)")
}       

func toPCMBuffer(data: NSData) -> AVAudioPCMBuffer {
    let audioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)  // given NSData audio format
    let PCMBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.length) / audioFormat.streamDescription.pointee.mBytesPerFrame)
    PCMBuffer.frameLength = PCMBuffer.frameCapacity
    let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: Int(PCMBuffer.format.channelCount))
    data.getBytes(UnsafeMutableRawPointer(channels[0]) , length: data.length)
    return PCMBuffer
}

func installTap() {    
    engine = AVAudioEngine()
    guard let engine = engine, let input = engine.inputNode else {
        // @TODO: error out
        return
    }

    let format = input.inputFormat(forBus: 0)
    input.installTap(onBus: 0, bufferSize: 4410, format: format, block: { (buffer: AVAudioPCMBuffer, AVAudioTime) in
        guard let this = self else {
            return
        }
        let stram = self?.toNSData(PCMBuffer: buffer)
        SocketIOManager.sharedInstance.socket.emit("talk",stram!)
    })

    do {    
        engine.prepare()
        try engine.start()
    } catch {
        // @TODO: error out
    }
}

// **Edit: For Enable Lound Speaker**

func speakerEnabled(_ enabled:Bool) -> Bool {
    let session = AVAudioSession.sharedInstance()
    var options = session.categoryOptions

    if (enabled) {
        options.insert(.defaultToSpeaker)
    } else {
        options.remove(.defaultToSpeaker)
    }

    try! session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: options)
    return true
}

【讨论】:

  • 其中的peerInput是什么?
  • 是的,但它在 self.peerAudioPlayer.play() 中崩溃,收到消息“所需条件为假:_engine != nil”
  • 你能建议我如何获得麦克风音频缓冲区吗?
  • @DipenChudasama 检查我为安装水龙头功能编辑的答案
  • 是的,正在工作,但请建议我如何设置 pcm16bit 的音频输入格式。
猜你喜欢
  • 2011-11-02
  • 2014-11-14
  • 2021-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多