14

I am trying to play an MP3 file (works when played via VLC/iTunes) when a button is pressed. Here is my code:

     var audioPlayer: AVAudioPlayer!
     @IBAction func playEpisode(sender: AnyObject) {
    println("now playing")
    let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
    let data: CDEpisode = fetchedResultsController.objectAtIndexPath(indexPath!) as! CDEpisode
    var err: NSError?
    let url = NSURL(string: data.localPath)
    println("The url is \(url)")

    audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &err)
    if audioPlayer == nil {
        if let e = err {
            println(e.localizedDescription)
        }
    }
    audioPlayer.delegate = self
    audioPlayer.prepareToPlay()
    audioPlayer.play()
}

Here is the log:

now playing
The url is Optional(file:///var/mobile/Containers/Data/Application/4747A71E-A63F-4EFC-B2DF-8B361361080B/Documents/serial-s01-e12.mp3)
The operation couldn’t be completed. (OSStatus error 2003334207.)
fatal error: unexpectedly found nil while unwrapping an Optional value

The EXC_BREAKPOINT happens on the audioPlayer.delegate = self.

Other threads on StackoOverflow do not help. Any ideas? Thanks

Edit: I have tried passing a localURL to contentsOfURL (instead of a CDEpisode object) and it still fails.

user2747220
  • 863
  • 3
  • 12
  • 31
  • I looked up the Error code, and 2003334207 gives the localizedDescription "The Operation Couldn't be Completed". In my app I was trying to access a file that didn't exist. – Unome Jan 19 '16 at 20:20

7 Answers7

9

This is probably caused by trying to load a file that doesn't exist. If that helps someone adding the call to url.checkResourceIsReachable() will log more descriptive message.

Example code:

    do {
        let url = URL(fileURLWithPath: dbObject.path)
        let isReachable = try url.checkResourceIsReachable()
        // ... you can set breaking points after that line, and if you stopped at them it means file exist.
    } catch let e {
        print("couldnt load file \(e.localizedDescription)")
    }
Dima Gimburg
  • 1,376
  • 3
  • 17
  • 35
6

It looks like your trying to unwrap a variable that has a nil value. You should safely unwrap your variables to prevent this.

if let data: CDEpisode = fetchedResultsController.objectAtIndexPath(indexPath!) as! CDEpisode
{
    var err: NSError?
    let url = NSURL(string: data.localPath)
    println("The url is \(url)")

    //rest of code
}

You will still need to figure out why it is returning nil but this is a safer way to unwrap variables and prevent crashing as there would need to be more context to resolve that issue.

Some questions to look into:

  • Are you sure the fetchedResultsController is returning an object at all?
  • Are you sure it is of CDEpisode?
chrissukhram
  • 2,957
  • 1
  • 13
  • 13
6

try this one

var player: AVAudioPlayer = AVAudioPlayer()


@IBAction func playX(_ sender: Any) {
    let urlstring = "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3"
    let url = URL(string: urlstring)
    let data = try! Data(contentsOf: url!)
    player = try! AVAudioPlayer(data: data)
    player.prepareToPlay()
    player.volume = 1.0
    player.play()
}
Ten
  • 1,426
  • 1
  • 14
  • 18
4

You're checking if audioPlayer is nil but then you go on to use it as if it wasn't anyway. You probably want something like:

if audioPlayer == nil {
    if let e = err {
        println(e.localizedDescription)
    }
} else {
    audioPlayer.delegate = self
    audioPlayer.prepareToPlay()
    audioPlayer.play()
}

And do something to actually handle the error case rather than just printing the error.

dan
  • 9,695
  • 1
  • 42
  • 40
  • You're absolutely correct. This is just makeshift code and not final. I've added an else statement and it doesn't crash the app anymore but it still throws the same error. – user2747220 Mar 17 '15 at 11:19
0

In my case I was having the same issue and I found out that I needed to set this before start recording

try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)

Hope it helps anyone

0

I also got this problem, after checking up the audio file url, found that it is stored in Cache directory. so audio player probably couldn't find audio file according to your "url".

please ensure, the url path is under Document directory.

Chris Lee
  • 21
  • 3
0

As others have said, the audio player couldn't find the file.

This helped me: Document directory path change when rebuild application

Basically, you cannot load files with an absolute reference, as the sandbox environment regenerates the absolute file url each time. So you will need to add a small bit of code (see above) to get the correct urls to use.

Ashok Khanna
  • 325
  • 2
  • 9