Offline Playback: Download to Own (DTO) and Rentals (DTR) for iOS

Apple released new APIs capable of downloading HLS assets to iOS devices. We're using these APIs to enable downloading of assets in our Ooyala SDK. Use the Ooyala SDK if you wish to download Ooyala assets stored in one of our CMSs (e.g. Backlot). Assets otherwise cannot be downloaded by default.

Overview

With the Ooyala SDK you will be able to:

  • Download an asset.
    • If the HLS master playlist contains multiple bitrates, you can select which one to download by specifying a minimum bitrate.
  • Cancel a download in progress.
  • Listen to updates on the download process.
  • Delete a downloaded asset.
  • Play a downloaded asset.
  • Prevent a downloaded asset from being played after a specific date.

We do not currently support:

  • Closed captions for the downloaded asset.
  • A promo or static image representing the downloaded asset.
  • Multi-audio (e.g. Spanish, English, etc). The SDK will download only the default language for the asset.
  • Pausing a download in progress.
  • Resume a download. If a download is explicitly canceled by the user, what has been downloaded to this point will be deleted.
  • Estimating the size of the video to download.
  • Checking the license expiration date. The license is readable by iOS only.
  • Auto delete assets that have an expired license.
Note: Note: When uninstalling the app used to download assets, the contents of the downloaded assets will be deleted also. This is expected behavior because downloaded files within iOS apps are downloaded to an inner container specific to the app and that container will live as the app is installed. When you delete the app this container will be removed too, meaning all downloaded assets will be deleted.

Requirements

DTO and DTR using the Ooyala SDK requires:

  • iOS 10 and above.
  • iOS Ooyala SDK v4.21.0 and above.
  • DTR additionally requires FairPlay HLS assets.

iOS supports downloading the following video formats:

Offline Playback Use-Cases: Buy and Rent

There are several use cases for offline videos. We expose the same client APIs for Download to Own (DTO) and Download to Rent (DTR), but the difference is that we consider assets to be DTO if they are clear HLS or FairPlay HLS with an infinite license, meaning the license will never expire, and if you download an asset with these characteristics you will be able to play as long as it remains on your device. On the other hand, Rentals (DTR) requires FairPlay HLS assets with a finite license. The access windows are defined by the entitlement settings, setting the expiration date for when a downloaded asset will no longer be playable by the user.

To add rental access period rules for your assets, you must set entitlements for them. For more information, see Rights Locker API Reference.

Caveats

  • If the FairPlay license expires when the user is playing the offline video, they will be able to continue the video content until the player is destroyed. We can't force the video session to end because the license is being enforced by iOS and the license is only retrieved when the player is initialized with a new asset.

Using the Ooyala SDK for iOS DTO and DTR capabilities

First, you must setup your app with the Ooyala SDK. If you are not familiar on linking a framework like the Ooyala SDK.framework into an iOS app, follow the tutorial we created on the following page: Getting Started: Setting Up Your Environment in Xcode.

We provide the following classes for DTO:

You must use an OOAssetDownloadManager object to start a download process. He also needs to implement OOAssetDownloadManagerDelegate and set the instance to be the delegate of OOAssetDownloadManager. This way the developer will be able to get updates about a download process.

Sample App

We provide a sample app that you can use as a guide to build your own. It uses the classes we introduced for DTO and shows you how to manage multiple downloable assets in your app. Here is the link to the sample app: https://github.com/ooyala/ios-sample-apps/tree/stable/PlaybackLab/DownloadToOwnSampleApp. See the README for more information about the application setup.

Starting a download

To start a download, you must use an instance of OOAssetDownloadManager and call the startDownload method. OOAssetDownloadManager needs an OOAssetDownloadOptions object to know which asset to download. The developer supplies options like the pcode, embed code, domain, and embed token generator. The embedTokenGenerator is required for FairPlay assets, as OPT is needed for all DRM assets. Look at the BasicEmbedTokenGenerator in the sample app for an example of an OOEmbedTokenGenerator implementation.

- (void)startDownload {
    // Initialize an options with the configuration of the asset that is going to be downloaded
    OOAssetDownloadOptions *options = [[OOAssetDownloadOptions alloc] init];
    options.pcode = self.pcode;
    options.embedCode = self.embedCode;
    options.domain = [OOPlayeDomain domainWithString:self.domain];
    options.embedTokenGenerator = self.embedTokenGenerator;
    OOAssetDownloadManager *manager = [[OOAssetDownloadManager alloc] initWithOptions:options];
 	
    // set the OOAssetDownloadManager delegate to receive download callbacks
    manager.delegate = self;
  
    [downloadManager startDownload];
}

It is important to set a delegate for the manager. The delegate is an instance of OOAssetDownloadManagerDelegate and its methods will be called during a download process, even if there's an error. After calling the startDownload method in the example above, the downloadManager:downloadTaskStartedWithError: method of the delegate will be called.

- (void)downloadManager:(OOAssetDownloadManager *)manager downloadTaskStartedWithError:(OOOoyalaError *)error {
    if (error) {
        // Download failed to start
    } else { 
        // Download started successfully
    }
}

OOAssetDownloadManager has an embedCode property which you can use to identify which is the asset being downloaded.

Selecting bitrate to download

When building the OOAssetDownloadOptions instance supplied to OOAssetDownloadManager, you can select the minimum bitrate to download.

OOAssetDownloadOptions *options = [[OOAssetDownloadOptions alloc] init];
// set other options
options.minimumBitrate = 1500000;
OOAssetDownloadManager *manager = [[OOAssetDownloadManager alloc] initWithOptions:options];

If you supply a minimum bitrate to download, when the download process begins it will search for the first bitrate greater or equal to the minimum bitrate supplied in your options object.

The following example HLS master playlist shows 4 different variants:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2855600,CODECS="avc1.4d001f,mp4a.40.2",RESOLUTION=960x540
medium.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=5605600,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720
high.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1755600,CODECS="avc1.42001f,mp4a.40.2",RESOLUTION=640x360
low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=545600,CODECS="avc1.42001e,mp4a.40.2",RESOLUTION=416x234
cellular.m3u8

Let's assume that we are going to download that example HLS asset. If we use the bitrate provided in the code snippet above (minimumBitrate = 1500000), then it will select the variant with BANDWIDTH of 1755600. That is the variant that will be downloaded because that is the first variant with a value greater or equal to 1500000.

Checking download progress

OOAssetDownloadManagerDelegate lets you know about the progress of a download through its downloadManager:downloadPercentage: method.

- (void)downloadManager:(OOAssetDownloadManager *)manager downloadPercentage:(Float64)percentage {
    // percentage is a number from 0.0 to 1.0
}

Storing the downloaded asset

OOAssetDownloadManagerDelegate has the downloadManager:downloadCompletedAtLocation:withError: method, which lets you know about the location where the asset was stored. You persist this location yourself because you need it to playback the content.

- (void)downloadManager:(OOAssetDownloadManager *)manager downloadCompletedAtLocation:(NSURL *)location withError:(OOOoyalaError *)error {
    if (error) {
        //download failed
    } else {
        // Example showing how to store the location in NSUserDefaults
        [[NSUserDefaults standardUserDefaults] setURL:location forKey:manager.embedCode];
    }
}

You do not have to store the video yourself; it is already stored and you are only given its location through the location parameter of this method.

Storing the FairPlay license (optional)

This step is only necessary if the asset is DRM protected with FairPlay. During the download process, you get authorized for that particular asset. Part of this authorization asks our FairPlay server if the asset can be downloaded. If yes, OOAssetDownloadManagerDelegate has a downloadManager:persistedContentKeyAtLocation: method that will be called when the license was persisted successfully.

- (void)downloadManager:(OOAssetDownloadManager *)manager persistedContentKeyAtLocation:(NSURL *)location {
    // Example showing how to store the location of the license in NSUserDefaults
    // As an example, if we had an embed code of "myEmbedCode" it will save the location using the NSString key "DTO_myEmbedCode.key"
    [[NSUserDefaults standardUserDefaults] setURL:location forKey:[NSString stringWithFormat:@"DTO_%@.key", manager.embedCode]];
}

For FairPlay assets, you also need the license when playing an offline video. That's why we need to save the location for later use.

Playing an offline video

Now that you have an offline video, you can play it back using the OOOoyalaPlayer. The following code assumes you have a UIViewController with a UIView that will become the OOOoyalaPlayer's view.

- (void)initializePlayer {
    OOOptions *options = [[OOOptions alloc] init];
    options.secureURLGenerator = ... // instance of a OOSecureURLGenerator required for FairPlay assets
  
    OOOoyalaPlayer *player = [[OOOoyalaPlayer alloc] initWithPcode:self.pcode 
                                domain:[OOPlayerDoamin domainWithString:self.domain] 
                                embedTokenGenerator:self.embedTokenGenerator 
                                options:options];
 	
    /*
     * This comment block assumes there's code to set the OOOoyalaPlayer into an OOOoyalaPlayerViewController
     */
 
    // Initialize an OOOfflineVideo with the location of the downloaded video and FairPlay license
    NSURL *videoLocation = [[NSUserDefaults standardUserDefaults] URLForKey:self.embedCode];
    NSURL *keyLocation = [[NSUserDefaults standardUserDefaults] URLForKey:[NSString stringWithFormat:@"DTO_%@.key", self.embedCode]];
    OOOfflineVideo *video = [OOOfflineVideo videoWithVideoLocation:videoLocation fairplayKeyLocation:keyLocation];
    [player setUnbundledVideo:video];
}

After calling setUnbundledVideo: you should be able to playback the offline asset successfully using the OOOoyalaPlayer.

Deleting a downloaded asset

Here's a code snippet showing how to delete both the contents and license of an asset. If you followed the examples above, you might want to clear the keys in the NSUserDefaults object.

- (void)deleteAsset:(NSString *)embedCode {
    // Delete the video content
    [OOAssetDownloadManager deleteFileAtLocation:[[NSUserDefaults standardUserDefaults] URLForKey:embedCode]];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:embedCode];

    // Delete the FairPlay license content
    [OOAssetDownloadManager deleteFileAtLocation:[[NSUserDefaults standardUserDefaults] URLForKey:[NSString stringWithFormat:@"DTO_%@.key", embedCode]]];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:@"DTO_%@.key", embedCode]];
}

Reference

해당 내용이 도움 되었습니까?