iosaudioavplayeravqueueplayeravurlasset

AVQueuePlayer unable to play local MP3 files


I'm currently writing an iOS app that allows users to stream music from soundcloud. Currently I am able to stream just fine from Soundcloud, in booth forefront and background app states. I have an issue when I download an MP3 files and attempt to play it and have continuously playback when the app in in the background, more specifically in the locked screen or the screen is off.

When I play a downloaded file and lock the screen, the audio continues to play for a while. Usually it plays for 2 -3 mins. After that playback will stop and any other downloaded mp3 files in the playlist will not playback until the user returns to the app. Items in the playlist that are not downloaded will playback perfectly if the user has an internet connection, regardless if a downloaded item failed to play previously.

There are times when I receive the following error:

AVPlayerItemStatusFailed: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not becompleted" UserInfo=0x170270500 {NSUnderlyingError=0x170059380 "The operation couldn’t be completed. Operation not permitted", NSLocalizedFailureReason=An unknown error occurred (1), NSLocalizedDescription=The operation could not be completed}

I will additionally get the following notification from the AVPlayerItem

Notification: NSConcreteNotification 0x1700538c0 {name = AVPlayerItemDidPlayToEndTimeNotification; object = AVPlayerItem: 0x178009300, asset = AVURLAsset: 0x17822aaa0, URL = file:///var/mobile/Applications/51118E74-3334-4EFC-B148-B485DE675F9E/Documents/Downloads/SC_165903784.mp3}

This notification is received when the first item that is playing stop playing. It doesn't make sense that I get this notification when it doesn't finish playing to end of its duration.

My guess is that because the app is in background mode there is a limited time set for reading files, but I somehow doubt that.

I'm using the following to create a AVPlayerItem from a Local file.

NSURL* url = [NSURL fileURLWithPath:song.downloadFilePath]; [AVPlayerItem playerItemWithURL:url];

I have tried building my own AVQueuePlayer and also using iOS Hysteria Player, but both instances have given me the same bug for offline download playback.

Any insights or solutions are greatly appreciated.

Thanks!


Solution

  • Are you playing your files from the Documents directory? (Or anywhere besides the app bundle?)

    If so, be sure to save the files to the directory using [fileToSave writeToFile:filePath options:NSDataWritingFileProtectionNone error:nil];.

    The NSDataWritingFileProtectionNone is the critical bit! What's going on, at least in my case, is this: iOS is trying to be secure, and so is by default enabling file protection on the files you add to the Documents directory (and also the other non-app-bundle directories as well, I believe). By adding NSDataWritingFileProtectionNone, you're requesting the system to no longer enable this protection on your files.

    From Apple's iOS Documentation:

    If you protect a file, your app must be prepared to lose access to that file. When complete file protection is enabled, your app loses the ability to read and write the file’s contents when the user locks the device.

    Now, as soon as I read that, I was almost positive that this was the cause for my app not being able to continue playback once the device was locked. For security's sake, iOS seems to default to automatically putting files under protection… but this keeps everything, including your app, from being able to access it while the device is locked. My bug was that it only played part of the song as soon as the device was locked, and that makes sense… since its access to the actual song file was revoked, it was only able to play the part of the song that had already been buffered into RAM!

    This was the fix for a month-long problem I've been pulling my hair out to try to solve. I sincerely hope it fixes the issue for you too.