3

I am following Apple's documentation on caching HLS (.m3u8) video.

https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/HTTPLiveStreaming/HTTPLiveStreaming.html

Under Playing Offline Assets in the documentation, it is instructed to use AVAssetDownloadTask's asset to simultaneously start 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 issue is that the same asset is downloaded twice.

Right after AVPlayer is initialized it starts to buffer the asset. Initially, I assumed that the data from the buffer must be used to create cache but AVAssetDownloadTask doesn't start to download the data for caching until AVPlayer finishes playing the asset. The buffered data is basically discarded.

I used KVO on currentItem.loadedTimeRanges to check state of buffer.

playerTimeRangesObserver = currentPlayer.observe(\.currentItem?.loadedTimeRanges, options: [.new, .old]) { (player, change) in

    let time = self.currentPlayer.currentItem?.loadedTimeRanges.firs.                                                
    if let t = time {
         print(t.timeRangeValue.duration.seconds)
    }
}

Below method to check the downloading status of AVAssetDownloadTask.

/// Method to adopt to subscribe to progress updates of an AVAssetDownloadTask.
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) {

    // This delegate callback should be used to provide download progress for your AVAssetDownloadTask.
    guard let asset = activeDownloadsMap[assetDownloadTask] else { return }

    var percentComplete = 0.0
    for value in loadedTimeRanges {
        let loadedTimeRange: CMTimeRange = value.timeRangeValue
        percentComplete +=
            loadedTimeRange.duration.seconds / timeRangeExpectedToLoad.duration.seconds
    }
    
    print("PercentComplete for \(asset.stream.name) = \(percentComplete)")
}

Is this the right behaviour or am I doing something wrong? I want to be able to use the video data that is being cached (AVAssetDownloadTask downloading is in progress) to play in AVPlayer.

Aryan Sharma
  • 105
  • 7
  • 1
    Did you figure it out? – om-ha Jan 19 '21 at 01:16
  • Did you try re-initializing AVPlayerItem as suggested [here](https://stackoverflow.com/questions/58206226/cache-hls-video-while-playing-with-avassetdownloadtask#comment102931175_58232317)? – om-ha Jan 19 '21 at 01:29

1 Answers1

0

Your AVAssetDownloadTask must be configured to download differing HLS variants than your AVPlayerItem is requesting.

If you already have some data downloaded by AVAssetDownloadTask, your AVPlayerItem will subsequently use it. But if you already have some data downloaded by AVPlayerItem, your AVAssetDownloadTask may ignore it, as it needs to satisfy the requirements of your download configuration.

M. LeRouge
  • 61
  • 2