在 Swift 中使用 AVAudioRecorder 在后台恢复录制的问题

问题描述

在上下文中,我正在开发一个应用程序,该应用程序在后台或应用程序中记录大量时间。我在使用 AVAudioRecorder 在我的应用中录制时遇到两个问题:

  • 例如,当我在 WhatsApp 中播放音频或在 Instagram 中播放视频时,我的录音恢复正常。但是当我在 Apple Music 中播放歌曲或播放语音笔记时,它不会再次恢复录音。

  • 如果我正在接听电话并开始录音,我的应用会崩溃并输出以下内容:

    (OSStatus 561017449 错误。)

  • 我认为还需要处理输入/输出设备发生变化时的情况,以免我的应用程序崩溃。

我为我正在录制的课程(以及我使用录音机播放声音,以便我可以尝试看看它是否有效)实现的代码是这样的:

class RecordViewController: UIViewController,AVAudioPlayerDelegate,AVAudioRecorderDelegate {


@IBOutlet weak var principalLabel: UILabel!
@IBOutlet weak var loginLabel: UILabel!
@IBOutlet weak var recordBTN: UIButton!
@IBOutlet weak var playBTN: UIButton!

var audioRecorder : AVAudioRecorder!
var audioPlayer : AVAudioPlayer!

var isAudioRecordingGranted: Bool!
var isRecording = false
var isPlaying = false

override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .white
    check_record_permission()
    checkActivateMicrophone()
    
    NotificationCenter.default.addObserver(self,selector: #selector(handleInterruption(notification:)),name: AVAudioSession.interruptionNotification,object: audioRecorder)
    
    let tapRegister: UITapGestureRecognizer = UITapGestureRecognizer(target: self,action: #selector(self.goToLogin))
    loginLabel.addGestureRecognizer(tapRegister)
    loginLabel.isUserInteractionEnabled = true
}

@objc func goToLogin() {
    self.performSegue(withIdentifier: "goToLogin",sender: self)
}

@objc func handleInterruption(notification: Notification) {
    guard let userInfo = notification.userInfo,let typeInt = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,let type = AVAudioSession.InterruptionType(rawValue: typeInt) else {
            return
    }

    switch type {
    
    case .began:
        
        if isRecording {
            print("OOOOOOO")
            audioRecorder.pause()
        }
        
        break
    case .ended:
        guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
        let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
        if options.contains(.shouldResume) {
            audioRecorder.record()
            print("AAAAAAA")
        } else {
            print("III")
            DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                self.audioRecorder.record()
            }
        }

    default: ()
    }
}

func check_record_permission()
{
    switch AVAudioSession.sharedInstance().recordPermission {
    case AVAudioSessionRecordPermission.granted:
        isAudioRecordingGranted = true
        break
    case AVAudioSessionRecordPermission.denied:
        isAudioRecordingGranted = false
        break
    case AVAudioSessionRecordPermission.undetermined:
        AVAudioSession.sharedInstance().requestRecordPermission({ (allowed) in
                if allowed {
                    self.isAudioRecordingGranted = true
                } else {
                    self.isAudioRecordingGranted = false
                }
        })
        break
    default:
        break
    }
}

func checkActivateMicrophone() {
    if !isAudioRecordingGranted {
        playBTN.isEnabled = false
        playBTN.alpha = 0.5
        recordBTN.isEnabled = false
        recordBTN.alpha = 0.5
        principalLabel.text = "Activa el micrófono desde ajustes"
    } else {
        playBTN.isEnabled = true
        playBTN.alpha = 1
        recordBTN.isEnabled = true
        recordBTN.alpha = 1
        principalLabel.text = "¡Prueba las grabaciones!"
    }
}

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

func getFileUrl() -> URL
{
    let filename = "myRecording.m4a"
    let filePath = getDocumentsDirectory().appendingPathComponent(filename)
    return filePath
}

func setup_recorder()
{
    if isAudioRecordingGranted
    {
        let session = AVAudioSession.sharedInstance()
        do
        {
            try session.setCategory(AVAudioSession.Category.playAndRecord,options: .defaultToSpeaker)
            try session.setActive(true)
            let settings = [
                AVFormatIDKey: Int(kAudioFormatMPEG4AAC),AVSampleRateKey: 44100,AVNumberOfChannelsKey: 2,AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue
            ]
            audioRecorder = try AVAudioRecorder(url: getFileUrl(),settings: settings)
            audioRecorder.delegate = self
            audioRecorder.isMeteringEnabled = true
            audioRecorder.prepareToRecord()
        }
        catch let error {
            print(error.localizedDescription)
        }
    }
    else
    {
        print("AAAAA")
    }
}


@IBAction func recordAct(_ sender: Any) {
            
    if(isRecording) {
        finishAudioRecording(success: true)
        recordBTN.setTitle("Record",for: .normal)
        playBTN.isEnabled = true
        isRecording = false
    }
    else
    {
        setup_recorder()
        audioRecorder.record()//aaaaaa
        recordBTN.setTitle("Stop",for: .normal)
        playBTN.isEnabled = false
        isRecording = true
    }
}

func finishAudioRecording(success: Bool)
{
    if success
    {
        audioRecorder.stop()
        audioRecorder = nil
        print("recorded successfully.")
    }
    else
    {
        print("Recording failed.")
    }
}


func prepare_play()
{
    do
    {
        audioPlayer = try AVAudioPlayer(contentsOf: getFileUrl())
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
    }
    catch{
        print("Error")
    }
}

@IBAction func playAct(_ sender: Any) {
    
    if(isPlaying)
        {
            audioPlayer.stop()
            recordBTN.isEnabled = true
            playBTN.setTitle("Play",for: .normal)
            isPlaying = false
        }
        else
        {
            if FileManager.default.fileExists(atPath: getFileUrl().path)
            {
                recordBTN.isEnabled = false
                playBTN.setTitle("pause",for: .normal)
                prepare_play()
                audioPlayer.play()
                isPlaying = true
            }
            else
            {
                print("Audio file is missing.")
            }
        }
}

func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder,successfully flag: Bool)
{
    if !flag
    {
        print("UUU")
        finishAudioRecording(success: false)
    }
    playBTN.isEnabled = true
}

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer,successfully flag: Bool)
{
    recordBTN.isEnabled = true
}
}

我实现了音频、AirPlay 和画中画的“背景模式”

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...