iOS Swift: звукозапись прерывается при переключении на наушники или с наушников - PullRequest
1 голос
/ 04 апреля 2019

Я использую приведенный ниже код для записи 5-секундного образца звука в приложении iOS Swift.Код отлично работает для записи, а также правильно распознает наушники, если они подключены. Однако, если во время записи наушники будут добавлены или удалены, запись будет прервана.Интересно, почему это так, иначе все идет гладко?

import AVFoundation

class RecorderViewController: UIViewController {

var recorder:          AVAudioRecorder!
var uploadObjectSuccess = false

@IBOutlet weak var recordButton:       UIButton!
@IBOutlet weak var statusLabel:        UILabel!
@IBOutlet weak var progressView:       UIProgressView!

var meterTimer:      Timer!
var soundFileURL:    URL!

override func viewDidLoad() {
    super.viewDidLoad()

    setSessionPlayback()
    askForNotifications()
    checkHeadphones()
}

func updateAudioMeter(_ timer:Timer) {
  self.progressView.setProgress(0, animated: false)
  if recorder != nil && recorder.isRecording {
        let sec = Int(recorder.currentTime.truncatingRemainder(dividingBy: 60))
        let s = String(format: "%02d", sec)
        statusLabel.text = s
        recorder.updateMeters()
        self.progressView.setProgress(Float(sec*4), animated: true)
    if (sec==6) && recorder != nil {
        func aux()->Bool {
            recorder.stop()
            return true
        }
        if aux()==true {
            if self.soundFileURL != nil {
            self.uploadObjectSuccess          = false
            let path                 = Auth.auth().currentUser?.uid
            let FIRStoragePath       = Storage.storage().reference().child(path!).child(FileName!)
                let uploadObject = FIRStoragePath.putFile(from: self.soundFileURL!, metadata: nil)
                uploadObject.observe(.success) { snapshot in
                    // Upload completed successfully
                    self.uploadObjectSuccess = true
                }
                uploadObject.observe(.failure) { snapshot in
                    // Upload failed
                    self.uploadObjectSuccess = true
                }
            }
        }
    }
  } else if (uploadObjectSuccess==true) {
        self.statusLabel.text             = "00"
        self.recordButton.isEnabled       = true
        isPlaying = false
        self.uploadObjectSuccess          = false
  } else {
        self.statusLabel.text             = "00"
  }
}

@IBAction func record(_ sender: Any) {

    if recorder != nil {
        recorder.stop()
    }
    recordButton.isEnabled = false

    recordWithPermission(true)
}

func setupRecorder() {
    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    self.soundFileURL = documentsDirectory.appendingPathComponent(self.currentFileName) //appendingPathComponent(currentFileName)
    if FileManager.default.fileExists(atPath: soundFileURL.absoluteString) {
        do {
            try FileManager.default.removeItem(atPath: self.soundFileURL.absoluteString)
        } catch let error as NSError {
            print("Ooops! Something went wrong: \(error)")
        }
    }

    let recordSettings:[String : AnyObject] = [
        AVFormatIDKey:             NSNumber(value:(kAudioFormatMPEG4AAC)),
        AVEncoderAudioQualityKey : NSNumber(value:AVAudioQuality.min.rawValue),
        //AVEncoderBitRateKey :      NSNumber(value:16),
        AVNumberOfChannelsKey:     NSNumber(value:1),
        AVSampleRateKey :          NSNumber(value:16000.0)
    ]

    do {
        recorder = try AVAudioRecorder(url: soundFileURL, settings: recordSettings)
        recorder.delegate = self
        recorder.isMeteringEnabled = true
        recorder.prepareToRecord() // creates/overwrites the file at soundFileURL
    } catch let error as NSError {
        recorder = nil
        print(error.localizedDescription)
    }
}

func recordWithPermission(_ setup:Bool) {

    checkHeadphones()
    setSessionPlayback()
    askForNotifications()

    let session:AVAudioSession = AVAudioSession.sharedInstance()

    // ios 8 and later
    if (session.responds(to: #selector(AVAudioSession.requestRecordPermission(_:)))) {
        AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
            if granted {
                print("Permission to record granted")
                self.setSessionPlayAndRecord()
                if setup {
                    self.setupRecorder()
                }
                self.recorder.record()
                self.meterTimer = Timer.scheduledTimer(timeInterval: 0.1,
                    target:self,
                    selector:#selector(RecorderViewController.updateAudioMeter(_:)),
                    userInfo:nil,
                    repeats:true)
            } else {
                print("Permission to record not granted")

                self.statusLabel.text             = "00"
                self.recordButton.isEnabled       = true
                self.uploadObjectSuccess          = false
                self.recorder.stop()
            }
        })
    } else {
                print("requestRecordPermission unrecognized")

                self.statusLabel.text             = "00"
                self.recordButton.isEnabled       = true
                self.uploadObjectSuccess          = false
                self.recorder.stop()
    }
}

func setSessionPlayback() {
    let session:AVAudioSession = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(AVAudioSessionCategoryPlayback)
    } catch let error as NSError {
        print("could not set session category")
        print(error.localizedDescription)
    }
    do {
        try session.setActive(true)
    } catch let error as NSError {
        print("could not make session active")
        print(error.localizedDescription)
    }
}

func setSessionPlayAndRecord() {
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
    } catch let error as NSError {
        print("could not set session category")
        print(error.localizedDescription)
    }
    do {
        try session.setActive(true)
    } catch let error as NSError {
        print("could not make session active")
        print(error.localizedDescription)
    }
}

func askForNotifications() {
    NotificationCenter.default.addObserver(self,
        selector:#selector(RecorderViewController.background(_:)),
        name:NSNotification.Name.UIApplicationWillResignActive,
        object:nil)

    NotificationCenter.default.addObserver(self,
        selector:#selector(RecorderViewController.foreground(_:)),
        name:NSNotification.Name.UIApplicationWillEnterForeground,
        object:nil)

    NotificationCenter.default.addObserver(self,
        selector:#selector(RecorderViewController.routeChange(_:)),
        name:NSNotification.Name.AVAudioSessionRouteChange,
        object:nil)
}

@objc func background(_ notification:Notification) {
    print("background")

    if recorder != nil {
        recorder.stop()
    }
}

@objc func foreground(_ notification:Notification) {
    print("foreground")
}

@objc func routeChange(_ notification:Notification) {
    print("routeChange \(String(describing: (notification as NSNotification).userInfo))")

    if let userInfo = (notification as NSNotification).userInfo {
        //print("userInfo \(userInfo)")
        if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt {
            //print("reason \(reason)")
            switch AVAudioSessionRouteChangeReason(rawValue: reason)! {
            case AVAudioSessionRouteChangeReason.newDeviceAvailable:
                print("NewDeviceAvailable")
                print("did you plug in headphones?")
                checkHeadphones()
            case AVAudioSessionRouteChangeReason.oldDeviceUnavailable:
                print("OldDeviceUnavailable")
                print("did you unplug headphones?")
                checkHeadphones()
            case AVAudioSessionRouteChangeReason.categoryChange:
                print("CategoryChange")
            case AVAudioSessionRouteChangeReason.override:
                print("Override")
            case AVAudioSessionRouteChangeReason.wakeFromSleep:
                print("WakeFromSleep")
            case AVAudioSessionRouteChangeReason.unknown:
                print("Unknown")
            case AVAudioSessionRouteChangeReason.noSuitableRouteForCategory:
                print("NoSuitableRouteForCategory")
            case AVAudioSessionRouteChangeReason.routeConfigurationChange:
                print("RouteConfigurationChange")

            }
        }
    }
}

func checkHeadphones() {
    // check NewDeviceAvailable and OldDeviceUnavailable for them being plugged in/unplugged
    let currentRoute = AVAudioSession.sharedInstance().currentRoute
    if currentRoute.outputs.count > 0 {
        for description in currentRoute.outputs {
            if description.portType == AVAudioSessionPortHeadphones {
                print("headphones are plugged in")
                break
            } else {
                print("headphones are unplugged")
            }
        }
    } else {
        print("checking headphones requires a connection to a device")
    }
}
}

// MARK: AVAudioRecorderDelegate
extension RecorderViewController : AVAudioRecorderDelegate {

func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder,
    successfully flag: Bool) {
        print("finished recording \(flag)")
}

func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder,
    error: Error?) {
        if let e = error {
        print("\(e.localizedDescription)")
        }
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...