Swift - 录制视频时如何处理音频会话中断

Swift - How to handle audio session interruptions while recording video

提问人:p_dip 提问时间:1/30/2023 更新时间:1/30/2023 访问量:316

问:

我正在尝试修复我的 iOS 应用程序的行为。应用程序中有一个相机插件,允许用户录制视频和拍照。录制视频时,如果发生来电或闹钟声等中断,相机会发热并且不会保存视频。我想处理这种情况,中断视频并保存它或在继续录制时删除音频。 但是,在中断开始并识别事件后,有关已录制视频的变量将被重新初始化,从而导致应用程序不保存任何内容。

任何帮助将不胜感激。

var captureSession: AVCaptureSession?


public func fileOutput(\_: AVCaptureFileOutput, didStartRecordingTo \_: URL, from \_: \[AVCaptureConnection\]) {
        NotificationCenter.default.addObserver(self, selector: #selector(sessionInterruptionBegin), name: .AVCaptureSessionWasInterrupted, object: captureSession)
        NotificationCenter.default.addObserver(self, selector: #selector(sessionInterruptionEnd),name: .AVCaptureSessionInterruptionEnded, object: captureSession)
        NotificationCenter.default.addObserver(self, selector: #selector(audioSessionInterrupted), name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance)
print("STO PASSANDO DA AVCaptureFileOutputRecordingDelegate")

        captureSession?.beginConfiguration()
        if flashMode != .off {
            _updateIlluminationMode(flashMode)
        }
    
        captureSession?.commitConfiguration() //at this point captureSession starts collecting data about the video
    
    }

extension CameraManager {
        @objc func sessionInterruptionBegin(notification: Notification) {
                print("Capture Session Interruption begin Notification!")
                guard let reasonNumber = notification.userInfo?\        [AVCaptureSessionInterruptionReasonKey\] as? NSNumber else {
                return
}
let reason = AVCaptureSession.InterruptionReason(rawValue: reasonNumber.intValue)

        switch reason {
            case .audioDeviceInUseByAnotherClient:
                removeAudioInput()
            default:
                break
        }
    }
    
    func addAudioInput() throws {
        if audioDeviceInput != nil {
            return
        }
        removeAudioInput()
    
        print("Adding audio input...")
        captureSession?.beginConfiguration()
        guard let audioDevice = AVCaptureDevice.default(for: .audio) else {
            throw NSError()
        }
        audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
        guard captureSession!.canAddInput(audioDeviceInput!) else {
            throw NSError()
        }
        captureSession?.addInput(audioDeviceInput!)
        captureSession?.automaticallyConfiguresApplicationAudioSession = false
        captureSession?.commitConfiguration()
    }
    
    func removeAudioInput() {
        //when the code reaches this point audioDeviceInput is reinitialized so the audio session is not removed from the recording
         //captureSession is not filled with the data about the video recorded
        guard let audioInput = audioDeviceInput else {
            return
        }
        captureSession?.beginConfiguration()
        captureSession?.removeInput(audioInput)
        audioDeviceInput = nil
        captureSession?.commitConfiguration()
    }
    
    @objc func sessionInterruptionEnd(notification: Notification) {
        print("Capture Session Interruption end Notification!")
        guard let reasonNumber = notification.userInfo?[AVCaptureSessionInterruptionReasonKey] as? NSNumber else {
            return
        }
        let reason = AVCaptureSession.InterruptionReason(rawValue: reasonNumber.intValue)
    
        switch reason {
            case .audioDeviceInUseByAnotherClient:
                // add audio again because we removed it when we received the interruption.
                configureAudioSession()
            default:
                // don't do anything, iOS will automatically resume session
                break
        }
    }
    @objc func audioSessionInterrupted(notification: Notification) {
        print("Audio Session Interruption Notification!")
        guard let userInfo = notification.userInfo,
              let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
              let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
            return
        }
    
        switch type {
            case .began:
                print("The Audio Session was interrupted!")
                removeAudioInput()
            case .ended:
                print("The Audio Session interruption has ended.")
                guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
                let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
                if options.contains(.shouldResume) {
                    print("Resuming interrupted Audio Session...")
                    // restart audio session because interruption is over
                    configureAudioSession()
                } else {
                    print("Cannot resume interrupted Audio Session!")
                }
            @unknown default: ()
        }
    }
    
    func configureAudioSession() {
        let start = DispatchTime.now()
        do {
            try self.addAudioInput()
    
            let audioSession = AVAudioSession.sharedInstance()
            if audioSession.category != .playAndRecord {
                // allow background music playback
                try audioSession.setCategory(AVAudioSession.Category.playAndRecord, options: [.mixWithOthers, .allowBluetoothA2DP, .defaultToSpeaker])
            }
    
            // activate current audio session because camera is active
            try audioSession.setActive(true)
        } catch let error as NSError {
            switch error.code {
                case 561_017_449:
                    print(error.description)
                default:
                    print(error.description)
            }
            self.removeAudioInput()
        }
    
        let end = DispatchTime.now()
        let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
        print("Configured Audio session in \(Double(nanoTime) / 1_000_000)ms!")
    }

}
iOS Swift AVCacucess AVAudioSession 通知中心

评论


答: 暂无答案