While recording a video, if an interruption occurs such as an incoming call or an alarm sound, the camera frezees and the video is not saved. I would like to handle this situation interrupting the video and saving it or removing the audio while it keeps recording.
But after the interruption starts and the event is recognized, the variables regarding the video already recorded are reinitialized, causing the app not to save anything.
This is part of the CameraManager class:
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!")
}
}