JSemelhago
JSemelhago

Reputation: 21

AVAudioPlayer playing recorded audio in simulator but not on phone

I'm trying to create an app that simply records and plays audio. I have tried multiple different methods of playing audio but it does not seem to work when playing on an iPhone 6 and an iPhone 8 Plus but works on the simulator.

The error:

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

This happens when SoundPlayer is trying to play. The error printed in the console is:

Error Domain=NSOSStatusErrorDomain Code=2003334207 "(null)"

@IBOutlet weak var recordBtn: UIButton!
@IBOutlet weak var playBtn: UIButton!
var soundRecorder : AVAudioRecorder!
var soundPlayer : AVAudioPlayer!
var fileName = "audioFile0.aac"

var screenCounter = 0 (global variable)

override open func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override open func viewDidLoad() {
    super.viewDidLoad()
    if (screenCounter == 0){
    // Do any additional setup after loading the view, typically from a nib.
        setupRecorder()
        screenCounter += 1
    }
}



func setupRecorder(){
    let recordSettings = [ AVFormatIDKey : kAudioFormatMPEG4AAC
        , AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue, AVEncoderBitRateKey : 320000, AVNumberOfChannelsKey : 2, AVSampleRateKey : 44100.0 ] as [String : Any]
    let _ : NSError?
    do{
        soundRecorder = try AVAudioRecorder(url : getFileURL() as URL, settings : recordSettings)
    }catch{
        print("Something went wrong")
    }
    soundRecorder.delegate = self
    soundRecorder.prepareToRecord()

}

func getCacheDirectory() -> String{
    let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
     return paths[0]
}

func getFileURL() -> NSURL{
    let pathURL = NSURL(fileURLWithPath : getCacheDirectory()).appendingPathComponent(fileName)
    let pathString = pathURL?.path
    let filePath = NSURL(fileURLWithPath : pathString!)
    return filePath
}


@IBAction func record(_ sender: UIButton) {
    if sender.titleLabel?.text == "Record"{
        soundRecorder.record()
        sender.setTitle("Stop", for : .normal)
        playBtn.isEnabled = false
    }else{
        soundRecorder.stop()
        sender.setTitle("Record", for : .normal)
        playBtn.isEnabled = false
    }
}
@IBAction func playSound(_ sender: UIButton) {
    if sender.titleLabel?.text == "Play"{
            recordBtn.isEnabled = false
            sender.setTitle("Stop", for : .normal)
            preparePlayer()
            soundPlayer.play()
    }else{
        soundPlayer.stop()
        sender.setTitle("Play", for : .normal)
    }
}

func preparePlayer(){
    let _ : NSError?
    do{
        soundPlayer = try AVAudioPlayer(contentsOf : getFileURL() as URL)
    }catch{
        print(error)
    }
    soundPlayer.delegate = self
    soundPlayer.prepareToPlay()
    soundPlayer.volume = 1.0
}


open func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
    playBtn.isEnabled = true
}
open func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    recordBtn.isEnabled = true
    playBtn.setTitle("Play", for : .normal)
}

Any help would be greatly appreciated.

UPDATE

Thanks for all your suggestions! I ended up finding the error on another forum here. It appears there needed to be an intermediary between recording and playing the audio called an audio session.

Upvotes: 2

Views: 385

Answers (2)

Razib Mollick
Razib Mollick

Reputation: 5052

It seems that audio file url is nil. Would you try with this FileManager

//func to give path(URL) to store the recording
    func getDirectory() -> URL {
        let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let docDirectory = path[0]
        return docDirectory
    }

And your file URL full path should be:

let path =   getDirectory().appendingPathComponent(fileName)

NOTE: As I could not run and test your code, I am not sure of the solution. Let me know the result. Otherwise, I will delete my post.

Upvotes: 1

Raghav Grandhi
Raghav Grandhi

Reputation: 66

Try initializing the soundPlayer outside of the playSoung method.

var soundPlayer = AVAudioPlayer()

func preparePlayer() {
    ...
}

Upvotes: 1

Related Questions