AVAudioPlayer working on Simulator but not on Real Device

While I play recorded Audio I get this error:

fatal error: unexpectedly found nil while unwrapping an Optional value

  • Why does audio work in the simulator but not on my iPad?
  • Record and play audio simultaneously in iOS
  • iOS 7 : simple audio controls with AVAudioPlayer?
  • AVAudioPlayer getting wrong file duration iOS 10
  • How to get audio to play at time from NSDatePicker?
  • Fetch All Audio & Video files in ios
  • on this line of code:

    SoundPlayer = try AVAudioPlayer(contentsOfURL: getFileURL())
    

    But it is working perfectly on Simulator except real device.

    ViewController.Swift:

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate {
    
        @IBOutlet var PlayBTN: UIButton!
        @IBOutlet var RecordBTN: UIButton!
    
    
        var soundRecorder : AVAudioRecorder!
        var SoundPlayer : AVAudioPlayer!
    
        var fileName = "audioFile.m4a"
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
            setupRecorder()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        func setupRecorder(){
    
            let recordSettings = [AVSampleRateKey : NSNumber(float: Float(44100.0)),
                AVFormatIDKey : NSNumber(int: Int32(kAudioFormatMPEG4AAC)),
                AVNumberOfChannelsKey : NSNumber(int: 1),
                AVEncoderAudioQualityKey : NSNumber(int: Int32(AVAudioQuality.Max.rawValue))]
    
            do{
                try soundRecorder = AVAudioRecorder(URL: getFileURL(), settings: recordSettings)
                    soundRecorder.delegate = self
                    soundRecorder.prepareToRecord()
            }
            catch let error as NSError {
                error.description
            }
    
        }
    
        func getCacheDirectory() -> String {
    
            let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true) 
    
            return paths[0]
    
        }
    
        func getFileURL() -> NSURL{
            let path  = (getCacheDirectory() as NSString).stringByAppendingPathComponent(fileName)
    
            let filePath = NSURL(fileURLWithPath: path)
    
    
            return filePath
        }
    
    
        @IBAction func Record(sender: UIButton) {
    
            if sender.titleLabel?.text == "Record"{
    
                soundRecorder.record()
                sender.setTitle("Stop", forState: .Normal)
                PlayBTN.enabled = false
    
            }
            else{
    
                soundRecorder.stop()
                sender.setTitle("Record", forState: .Normal)
                PlayBTN.enabled = false
            }
    
        }
    
        @IBAction func PlaySound(sender: UIButton) {
    
            if sender.titleLabel?.text == "Play" {
    
                RecordBTN.enabled = false
                sender.setTitle("Stop", forState: .Normal)
    
                preparePlayer()
                SoundPlayer.play()
    
            }
            else{
    
                SoundPlayer.stop()
                sender.setTitle("Play", forState: .Normal)
    
            }
    
        }
    
        func preparePlayer(){
            do{
                SoundPlayer = try AVAudioPlayer(contentsOfURL: getFileURL())
                SoundPlayer.delegate = self
                SoundPlayer.volume = 1.0
                SoundPlayer.prepareToPlay()
            }
            catch let error as NSError {
                error.description
            }
        }
    
        func audioRecorderDidFinishRecording(recorder: AVAudioRecorder, successfully flag: Bool) {
            PlayBTN.enabled = true
        }
    
        func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
            RecordBTN.enabled = true
            PlayBTN.setTitle("Play", forState: .Normal)
        }
    
        @IBAction func actDone(sender: AnyObject) {
            //viewRecorder.hidden = true
    
            let fm = NSFileManager.defaultManager()
            let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
    
            do {
                let items = try fm.contentsOfDirectoryAtPath(documentsDirectory)
    
                for item in items {
                    print(item)
                }
            }
            catch let error as NSError {
                error.description
            }
        }
    }
    

    Storyboard file for ViewController.Swift:

    enter image description here

    Additional info:

    • Xcode version : 7.2.1
    • Device : iPhone 5s
    • iOS version : 9.2.1

    Note: I have looked for similar SO solutions but none of them helped me. Some of them due to older Swift version and deprecated method. Some solutions were regarding playing audio file from application bundle and some of were using web URLs. So, this case is different(Real Device vs Simulator)

    Here is the link of source code on Google Drive.

    Solutions Collect From Internet About “AVAudioPlayer working on Simulator but not on Real Device”

    On a real device, it needs to setCategory() for AVAudioSession.sharedInstance()

    And a fixed project can be downloaded here too.

    func setupRecorder(){
    
            let audioSession = AVAudioSession.sharedInstance()
            do {
                try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
            } catch let error as NSError {
                print(error.description)
            }
    
            let recordSettings = [AVSampleRateKey : NSNumber(float: Float(44100.0)),
                AVFormatIDKey : NSNumber(int: Int32(kAudioFormatMPEG4AAC)),
                AVNumberOfChannelsKey : NSNumber(int: 1),
                AVEncoderAudioQualityKey : NSNumber(int: Int32(AVAudioQuality.Max.rawValue))]
    
            do{
                try soundRecorder = AVAudioRecorder(URL: getFileURL(), settings: recordSettings)
                    soundRecorder.delegate = self
                    soundRecorder.prepareToRecord()
            }
            catch let error as NSError {
                error.description
            }
    
        }
    

    NOTE: An audio session is the intermediary between your app and iOS used to configure your app’s audio behaviour. If we set category for AVAudioSessionCategoryPlayAndRecord, we define iOS audio behaviour to allow audio input (recording) and output (playback).
    Referred from: Audio Session Programming Guide