I'm downloading offline video thanks to AVAssetDownloadURLSession, AVAssetDownloadDelegate for iOS 11 using makeAssetDownloadTask(...) and aggregateAssetDownloadTask(...) method.
Everything works but I just want to let the users know the progress of each download as accurately as possible.
To do so I use:
- urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange)
- urlSession(_ session: URLSession, aggregateAssetDownloadTask: AVAggregateAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange, for mediaSelection: AVMediaSelection)
With these methods I'm able to calculate the download progress of the video and each tracks (audio/subtitle) separately. So I assume the video is 70% of the download and for the tracks it's 30% divided by the number of tracks. I store the download progress of each items in a temporary dictionary (multiplied by their ratio) and I add each progress for a download to have a global representation.
In the end it works fine but it's not as smooth as expected. For example I spend 3min to download the content but if the weight of a track is light, the progress will jump from 70% to 85% in 1sec (if I have 2 tracks to download) and slow down right after. I would like to have a global progress.
I definitely not happy with this solution but I currently did not find another solution.
Do some of you have any ideas/solutions?
Thanks guys
And it continually changes the value of progress bar to the amount of data being transferred. So you will see the progress bar gradually moves from left to right as the file gets downloaded. The speed of progress bar depends on the size of the file and your internet connection.
The algorithm to calculate the remaining time is pretty simple. We get the difference between total size of file and the file currently being downloaded, and divide that by amount of data downloaded in bytes per second. This gives the time in seconds. But we need to show it in minutes too.
AJAX also provides us a method to track progress in an event called onprogress, it will have an argument and it tells the total amount of data that needs to be transferred (the size of file) and the which is currently been transferred so far. We will set the total amount of data as the maximum value for the progress bar.
We can calculate the percentage of the file downloaded by dividing the file currently downloaded by total size of file. That will return the value in between 0 and 1, for example 0.841. Multiplying this by 100 will return in 84.1 which means that 84.1 percent file has been downloaded.
First of all, this is just my case, you should update the method for your needs.
In my scenario, as a most complicated array example I have something like this:
[English(soun),Turkish(soun),English(sbtl),Turkish(sbtl)]
We'll give 80 percent for Audio all audios, and 20 percent for all subtitles.
The total calculation formula must be something like this:
(100*(0,80/2))+(100*(0,80/2))+(100*(0,20/2))+(100(0,20/2))
We need an enum for representing AVMediaType:
// AVMediaType
enum MediaType: String {
// Sound
case soun
// Subtitle
case sbtl
// Closed Caption
// case clcp // Removed for simplifying the example.
}
Also, we'll need a Dictionary to handle Asset Download Progress:
var totalDownloadProgressForAsset = [String: Double]()
And here is the method:
public func getTotalProgress() -> Double {
var result = 0.0
let soundMultiplier = 0.80
let subtitleMultiplier = 0.20
var soundCount = 0
var subtitleCount = 0
for (key, _) in totalDownloadProgressForAsset {
let mediaTypeKey = String(key.suffix(4))
let type = MediaType(rawValue: mediaTypeKey)
switch type {
case .soun:
soundCount += 1
case .sbtl:
subtitleCount += 1
case .none:
break
}
}
for (key, value) in totalDownloadProgressForAsset {
let mediaTypeKey = String(key.suffix(4))
let type = MediaType(rawValue: mediaTypeKey)
switch type {
case .soun:
result += Double(value*(soundMultiplier/Double(soundCount)))
case .sbtl:
result += Double(value*(subtitleMultiplier/Double(subtitleCount)))
case .none:
break
}
}
return result
}
Of course, we can write this differently, this is just for example.
Feel free to ask anything about it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With