Skip to main content

Downloading videos for offline

Generating OTP for Offline Playback

To initialize video playback on website or app, your backend has to generate an OTP+playbackInfo using the VdoCipher API. The regular OTP does not have permission to be persisted offline. To enable offline playback you will need to send additional parameters while making the API call for the OTP.

You can specify the time period for which the offline download will be available for playback. The time period of validity is called the rental duration. Beyond the rental duration the license will expire, and the downloaded file will no longer play.

How to generate offline OTP ยป

You can find more details on the OTP-based playback mechanism at the API page.

Setting up offline

Requires Fairplay setup

Offline video playback is only available if you have set up Fairplay DRM and configured it with your VdoCipher account.

1. Notification handlers

// listen to the download events
NotificationCenter.default.addObserver(
self,
selector: #selector(handleDownloadProgress(_:)),
name: .AssetDownloadProgress, object: nil
)

NotificationCenter.default.addObserver(
self,
selector: #selector(handleDownloadStateChange(_:)),
name: .AssetDownloadStateChanged, object: nil
)

NotificationCenter.default.addObserver(
self,
selector: #selector(handleDownloadFailed(_:)),
name: .AssetDownloadFailed, object: nil
)

2. Handler functions to update the UI about progress and download completions

The notification received from the above will be of the following structures.

AssetDownloadProgress

{
"videoId": "____",
"percentDownlaod": 0.2
}

AssetDownloadStateChanged

The downloadState will be one of the enum from VdoAsset.DownloadState.

{
"videoId": "___",
"downloadState": "downloaded"
}

AssetDownloadFailed

{
"videoId": "____",
"message": "___ __ __",
"code": xxxx
}
note

Do not use string for the keys. Use the VdoAsset.Keys struct for the keys of the userInfo. Check the examples below for an example.

Sample handler code

// MARK: Notification handlers

@objc func handleDownloadStateChange(_ notification: Notification) {
print("handle download state change")
let notice = notification.userInfo!
guard videoId == notice[VdoAsset.Keys.videoId] as? String else {
return
}
guard let stateRawValue = notice[VdoAsset.Keys.downloadState] as? String,
let newState = VdoAsset.DownloadState(rawValue: (stateRawValue)) else {
return
}
print("state change: \(newState)")
DispatchQueue.main.async {
self.updateUI(downloadState: newState)
}
}

@objc func handleDownloadProgress(_ notification: Notification) {
print("handle download progress")
let notice = notification.userInfo!
guard videoId == notice[VdoAsset.Keys.videoId] as? String else {
return
}
guard let percent = notice[VdoAsset.Keys.percentDownloaded] as? Double else {
return
}
print("progress percent: \(percent)")
DispatchQueue.main.async {
self.updateUI(downloadState: .downloading, percentDownload: percent)
}
}

@objc func handleDownloadFailed(_ notification: Notification) {
print("handle download failed")
let notice = notification.userInfo!
if let message = notice[VdoAsset.Keys.message], let code = notice[VdoAsset.Keys.code]
{
print("Download Failed with message:\(message) code:\(code)")
}
}

3. Call the download APIs from the UI

@IBAction func downloadAction(_ sender: Any) {
guard let asset = asset, let button = sender as? UIButton, let buttonText = button.currentTitle else {
return print("not ready for playback or action not defined")
}
asset.startDownload(otp: otp, playbackInfo: playbackInfo)
}

@IBAction func cancelAction(_ sender: Any) {
asset.deleteDownload()
}

@IBAction func deleteAction(_ sender: Any) {
asset.deleteDownload()
}

4. Call the playOffline() method to start offline playback

@IBAction func playOffline(_ sender: Any) {
guard let asset = asset else {
return print("not ready for offline playback")
}
if asset.downloadState != .downloaded {
return print("not downloaded yet")
}
asset.playOffline()
}