Search code examples
swiftavaudioplayernsurl

AVAudioPlayer didn't run from url file in Swift Programming


I am very new to Swift programming and has started learning a few weeks now. I am testing a AVAudioPlayer from YouTube tutorials and it works perfectly. Here is the code.

let filelocation  = NSString( string: NSBundle.mainBundle().pathForResource(self.navigationItem.title, ofType: "mp3")!)
player = AVAudioPlayer(contentsOfURL: NSURL( fileURLWithPath: filelocation as String)!, error: &error)

Those mp3 files are placed in the project so it is playing locally. I changed the code to the following to get mp3 file from URL and played it here. But it didn't work.

let url : NSString = "https://ia601409.us.archive.org/20/items/UsaNationalAnthemFromSilo/silosinging-us-anthem_64kb.mp3"
let urlStr : NSString = url.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
player = AVAudioPlayer(contentsOfURL: NSURL( fileURLWithPath: urlStr as String)!, error: &error)

I got an error at player.prepareToPlay() with "fatal error: unexpectedly found nil while unwrapping an Optional value" and value is "error NSError? domain: "NSOSStatusErrorDomain" - code: 2003334207 0x00007fc3e3e4b820"

I am thinking NSURL(fileURLWithPath: urlStr as String)! is not correct, so it is giving just nil. Any thoughts on how to correct it! Thanks.


Solution

  • You can not use NSURL(fileURLWithPath:) method to create a url from a web link. When creating url from links you need to use NSURL(string:) but you should download your data asynchronously using dataTaskWithUrl as follow:

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController {
        var player:AVAudioPlayer!
        override func viewDidLoad() {
            super.viewDidLoad()
            let link = "https://ia601409.us.archive.org/20/items/UsaNationalAnthemFromSilo/silosinging-us-anthem_64kb.mp3"
            if let linkUrl = NSURL(string: link) {
                println(linkUrl)
                NSURLSession.sharedSession().dataTaskWithURL(linkUrl, completionHandler: { (data, response, error) -> Void in
                    dispatch_async(dispatch_get_main_queue()) {
                        println("Finished downloading")
                        // you can use the data! here
                        if let data = data {
                            var error:NSError?
                            self.player = AVAudioPlayer(data: data, error: &error)
                            if let error = error {
                                println(error.description)
                            } else {
                                self.player.prepareToPlay()
                                self.player.play()
                            }
                            // there is data. do this
                        } else if let error = error {
                            println(error.description)
                        }
                    }
                }).resume()
            }
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }