0
votes

I am downloading the audio message first then play it using Avaudioplayer

downloadTask = NSURLSession.sharedSession().downloadTaskWithURL(urlStr, completionHandler: { (URL, response, error) -> Void in

           self.play(URL!)


})
downloadTask

This works fine, but if I call play(URL) method after saving the response URL that I have stored in NSUserDefaults. The URL is same in both cases. I have checked it. its something like:

file:///Users/mymac/Library/Developer/CoreSimulator/Devices/X-CD91-XXXXXXX-XXX-XXXXXX/data/Containers/Data/Application/XXXXXXX-XXXX-XXXXXXXXXX/tmp/CFNetworkDownload_InUTA3.tmp

Passing this file url to:

func play(url : NSURL) {

        do {
            player = try AVAudioPlayer(contentsOfURL: url)
            player.prepareToPlay()
            player.play()

        } catch let error as NSError {
            //self.player = nil
            print(error.localizedDescription)

        } catch {

            print("AVAudioPlayer init failed")
        }

    }

Url path is same, but the audioPlayer is unable to play the sound, it shows the following error:

The operation couldn’t be completed. (OSStatus error 2003334207.)

Can anyone guide me in this regard?

Thanks.

2
So...just to understand you correct. If you call play with a URL that you have stored in your UserDefaults...it works? And if you call it straight here in the completion handler of downloadTaskWithURL it does not work...correct? Or is it the other way around?pbodsk
You need to store it with proper file extension. .tmp can never be played, If you know whats the type of the file, rename it to that proper name. And then play it.Sachin Vas
@pbodsk nop the URL with UserDefaults doesnt work correct it works correct when i call Play() in the completion block it works right after the download.Adeel Noor
Ah, OK, Thanks :) Before you exit the completionHandler you must move the file somewhere else. As it says here about the location: developer.apple.com/reference/foundation/nsurlsession/… "The location of a temporary file where the server’s response is stored. You must move this file or open it for reading before your completion handler returns. Otherwise, the file is deleted, and the data is lost.", so if you don't do that already, then that could be why it works in the completionHandler and not later.pbodsk
This also explains why you crash, you just pass it a force unwrapped URL and since there is no longer an item at that location which you've saved in your UserDefaults, it crashespbodsk

2 Answers

0
votes

As can be seen from the comments above the problem was that the downloaded file was not moved before completing the completionHandler of the downloadTask method.

As it says in the description of the location parameter

The location of a temporary file where the server’s response is stored. You must move this file or open it for reading before your completion handler returns. Otherwise, the file is deleted, and the data is lost.

Therefore, in your completionHandler you must move the file to another location that you control before ending the completionHandler.

This probably also explains the crash. If the "temp" URL is saved to UserDefaults in the completionHandler then that URL is no longer valid when the completionHandler has completed. So when you then later call

play(URL!)

with a force unwrapped URL that is now invalid, you get a crash.

Therefore, as an extra safety measure, try unwrapping the URL before trying to use it:

if let url = urlFromUserDefaults {
    play(url)
}

Hope that helps you.

0
votes

You can simply write this...

 do
        {
            self.player = try AVAudioPlayer(contentsOf:Url)
            self.player?.numberOfLoops = 0
            self.player?.prepareToPlay()
            self.player?.volume = 1.0
            self.player?.play()
            self.player?.delegate=self
        }
        catch let error as NSError
        {
            print(error)
        }