AVAudioPlayer didn't run from url file in Swift Programming

2.2k Views Asked by At

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.

2

There are 2 best solutions below

8
On BEST ANSWER

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()
    }
}
1
On

You have to pre load the mp3 first, you can try this:

var p: AVAudioPlayer?

override func viewDidLoad() {
        super.viewDidLoad()
        var errorPointer: NSErrorPointer = NSErrorPointer()
        var url = NSURL(string: "https://ia601409.us.archive.org/20/items/UsaNationalAnthemFromSilo/silosinging-us-anthem_64kb.mp3")
        var request:NSMutableURLRequest = NSMutableURLRequest(URL:url!)
        let conf: NSURLSessionConfiguration = NSURLSession.sharedSession().configuration
        let session = NSURLSession(configuration: conf)
        session.dataTaskWithRequest(request) {
            data, response, error in
            if error != nil {
                println("\(error)")
            }else {
                self.p = AVAudioPlayer(data: data, error: errorPointer)
            }
            }.resume()

    }

and then in an action do this:

@IBAction func pushButton(sender: AnyObject) {
        p!.prepareToPlay()
        p!.volume = 100
        p!.play()
    }