Swift 4 AVFoundation - 同时录制多个音频源

Posted

技术标签:

【中文标题】Swift 4 AVFoundation - 同时录制多个音频源【英文标题】:Swift 4 AVFoundation - Recording multiple audio sources simultaneously 【发布时间】:2017-10-15 16:14:15 【问题描述】:

我目前正在尝试同时监控 iPhone 的每个内置麦克风的音频输入。

在下面提到的代码中,我选择了我想用这行代码监控/测量的麦克风(底部、前置或后置麦克风):

try recordingSession.setInputDataSource(recordingSession.inputDataSources?[2])

不幸的是,我似乎只能为我的音频会话设置一个输入数据源。

也许有办法为每个记录通道设置一个输入数据源?

我也曾尝试探索其他解决方案,例如 AVAudioEngine,但由于有关此主题的 Swift 资源并不多,因此我很难分析走哪条路。

import UIKit
import AVFoundation

        class ViewController: UIViewController, AVAudioRecorderDelegate, AVAudioPlayerDelegate 

            @IBOutlet var recordButton: UIButton!
            var recordingSession: AVAudiosession!
            var audioPlayer: AVAudioPlayer!
            var audioRecorder: AVAudioRecorder!

            var timer: Timer!

            override func viewDidLoad() 
                recordingSession = AVAudioSession.sharedInstance()

                do 
                    try recordingSession.setCategory(AVAudioSessionCategoryMultiRoute)
                    //try recordingSession.setMode(AVAudioSessionModeMeasurement)
                    try recordingSession.setActive(true)


                    try recordingSession.setInputDataSource(recordingSession.inputDataSources?[2])
                    try recordingSession.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
                    recordingSession.requestRecordPermission()  [unowned self] allowed in
                        DispatchQueue.main.async 
                            if allowed 

                             else 
                                // failed to record!
                            
                        
                    
                 catch 
                    print("NOT ALLOWED")
                    // failed to record!
                

            

            @objc func updateMeters()
                audioRecorder.updateMeters()


                print("CHANNEL 0 PEAK : \(audioRecorder.peakPower(forChannel: 0))")
                print("CHANNEL 1 PEAK : \(audioRecorder.peakPower(forChannel: 1))")
                print(audioRecorder.averagePower(forChannel: 0))
                print(audioRecorder.currentTime)
            


            func startRecording() 
                let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.m4a")

                let settings = [
                    AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                    AVSampleRateKey: 12000,
                    AVNumberOfChannelsKey: 2,
                    AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
                ]

                do 

                    audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
                    audioRecorder.delegate = self
                    audioRecorder.isMeteringEnabled = true
                    audioRecorder.record()

                    recordButton.setTitle("Tap to Stop", for: .normal)

                    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateMeters), userInfo: nil, repeats: true)
                 catch 
                    finishRecording(success: false)
                
            

            func getDocumentsDirectory() -> URL 
                let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
                let documentsDirectory = paths[0]
                return documentsDirectory
            

            func finishRecording(success: Bool) 
                timer.invalidate()
                audioRecorder.stop()
                audioRecorder = nil

                if success 
                    recordButton.setTitle("Tap to Re-record", for: .normal)
                 else 
                    recordButton.setTitle("Tap to Record", for: .normal)
                    // recording failed :(
                
            

            @IBAction func recordTapped() 
                if audioRecorder == nil 
                    startRecording()
                 else 
                    finishRecording(success: true)
                
            

            func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) 
                if !flag 
                    finishRecording(success: false)
                
            

            @IBAction func play(_ sender: UIButton) 
                let fileURL = getDocumentsDirectory().appendingPathComponent("recording.m4a")
                    self.audioPlayer = try! AVAudioPlayer(contentsOf: fileURL)
                    self.audioPlayer.prepareToPlay()
                    self.audioPlayer.delegate = self
                    self.audioPlayer.play()
            
        

【问题讨论】:

【参考方案1】:

正如 smakusdod 在 reddit thread 中提到的:

iphone 有 3 个麦克风...根据哪个摄像头像阵列一样使用 处于活动状态,或者如果您处于免提模式等,如果苹果愿意, 他们可以将这些麦克风用于立体声录音。例如,使用 右声道底部麦克风,左声道顶部麦克风。目前 他们不允许这样做,而是只公开一个单声道。

因为苹果只提供了一个单声道通道,这意味着 iOS 开发者不可能同时为我们访问这些内置麦克风。

如果您认为应该可以,Apple 会为您提供机会让他们知道: https://www.apple.com/feedback/iphone.html

【讨论】:

可能硬件不支持。

以上是关于Swift 4 AVFoundation - 同时录制多个音频源的主要内容,如果未能解决你的问题,请参考以下文章

swift 在Swift中使用AVFoundation修剪视频

如何将代码 AVFoundation 目标 c 转换为 Swift?

swift使用AVFoundation实现自定义相机

使用 AVFoundation 和 Swift 访问多个音频硬件输出/通道

Swift AVFoundation 二维码扫描和生成

swift使用AVFoundation实现自定义相机