5

I am trying cache an HLS stream while I am playing it. I was following the Apple documentation on this (the section Playing Offline Assets):

https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/HTTPLiveStreaming/HTTPLiveStreaming.html#//apple_ref/doc/uid/TP40016757-CH11-SW1

I've implemented the following method - which should make my HLS streams download while playing:

func downloadAndPlayAsset(_ asset: AVURLAsset) {
    // Create new AVAssetDownloadTask for the desired asset
    // Passing a nil options value indicates the highest available bitrate should be downloaded
    let downloadTask = downloadSession.makeAssetDownloadTask(asset: asset,
                                                             assetTitle: assetTitle,
                                                             assetArtworkData: nil,
                                                             options: nil)!
    // Start task
    downloadTask.resume()

    // Create standard playback items and begin playback
    let playerItem = AVPlayerItem(asset: downloadTask.urlAsset)
    player = AVPlayer(playerItem: playerItem)
    player.play()
}

The problem is it just doesn't download the video, only plays the stream. I've also implemented the delegates, but then none of them get called:

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange)

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL)

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)

Rather strangely, I noticed that the next time I open the app, the assetDownloadURLSession.getAllTasks returns pending tasks for my downloads from the last session. So it doesn't download the streams but it does add them to a pending queue. Do you know what would be the rationale behind that? I had a theory that the stream being downloaded and the live stream use different quality so it does need to be redownloaded in the right quality. So I created an HLS stream for testing with just one quality but the result is still the same.

If I remove the lines assigning the AVPlayerItem to AVPlayer the download starts and all the delegates gets called. So the download on its own work, but anytime I try to play it just stops.

Thanks for help!

Tomas

Tomáš Kohout
  • 755
  • 6
  • 15

2 Answers2

1

I had a theory that the stream being downloaded and the live stream use different quality so it does need to be redownloaded in the right quality.

Your theory is correct.

So the download on its own work, but anytime I try to play it just stops.

The download will be deferred until the AVPlayerItem is terminated. Try calling player.replaceCurrentItem(nil).

M. LeRouge
  • 61
  • 2
  • If `The download will be deferred until the AVPlayerItem is terminated`, how do you implement playing while downloading? – Hansen W Jul 15 '21 at 00:09
  • Simply wire up an AVPlayerItem to the same AVAsset that you used with AVAssetDownloadTask. Whatever AVAssetDownloadTask has downloaded, AVPlayerItem will be able to use. Whatever AVPlayerItem downloads, AVAssetDownloadTask might be able to use. – M. LeRouge Jul 16 '21 at 04:10
  • This is what I am currently doing, but I realized the download won't start while the AVPlayItem is using the AVAsset(playing it) like you said. I was wondering how to achieve simultaneous caching and playing. – Hansen W Jul 23 '21 at 23:45
0

Did that happened on iOS13 or newer? https://forums.developer.apple.com/thread/121097 If so, we met the same problem maybe, and Apple just hasn't given us any hits

Chan Gu
  • 41
  • 5
  • Thanks for replying. I am still testing on iOS 12. Good to know there might be a problem on iOS 13 ... we actually might ditch the whole HLS approach (in my opinion the API is one of the worst I have seen so far in Apple ecosystem) and go with directly downloading mp4s (makes sense in our use case). – Tomáš Kohout Oct 04 '19 at 12:20
  • @TomášKohout How about 1.try another m3u8 or 2. start session on a different thread, so far I believe it's working on iOS12 – Chan Gu Oct 07 '19 at 00:55
  • Hey, I am not sure if we are talking about the same thing - the download works on iOS 12 but not while I am playing the video at the same time. Btw, I have installed iOS 13 and it seems to be downloading fine for me (but still not playing at the same time, which is the main issue). I have found an annoying bug when the download stops working randomly and I have to restart my device for it to work again. – Tomáš Kohout Oct 07 '19 at 09:48
  • @TomášKohout Try not adding same Asset, just reinit a AVPlayerItem by your video url, like this : `your.playerItem = [[AVPlayerItem alloc] initWithURL:yourVideoUrl];` – Chan Gu Oct 08 '19 at 08:41