Offline Widevine streaming for Android with Media Services v3

Media Services logo v3


AMS website | Media Services v2 documentation | Code Samples | Troubleshooting guide

In addition to protecting content for online streaming, media content subscription and rental services offer downloadable content that works when you are not connected to the internet. You might need to download content onto your phone or tablet for playback in airplane mode when flying disconnected from the network. Additional scenarios, in which you might want to download content:

  • Some content providers may disallow DRM license delivery beyond a country/region's border. If a user wants to watch content while traveling abroad, offline download is needed.
  • In some countries/regions, Internet availability and/or bandwidth is limited. Users may choose to download content to be able to watch it in high enough resolution for satisfactory viewing experience.

Note

Widevine is not available in the GovCloud region.

This article discusses how to implement offline mode playback for DASH content protected by Widevine on Android devices. Offline DRM allows you to provide subscription, rental, and purchase models for your content, enabling customers of your services to easily take content with them when disconnected from the internet.

For building the Android player apps, we outline three options:

  • Build a player using the Java API of ExoPlayer SDK
  • Build a player using Xamarin binding of ExoPlayer SDK
  • Build a player using Encrypted Media Extension (EME) and Media Source Extension (MSE) in Chrome mobile browser v62 or later

The article also answers some common questions related to offline streaming of Widevine protected content.

Note

Offline DRM is only billed for making a single request for a license when you download the content. Any errors are not billed.

Prerequisites

Before implementing offline DRM for Widevine on Android devices, you should first:

Configure content protection in Azure Media Services

In the GetOrCreateContentKeyPolicyAsync method, the following necessary steps are present:

  1. Specify how content key delivery is authorized in the license delivery service:

    ContentKeyPolicySymmetricTokenKey primaryKey = new ContentKeyPolicySymmetricTokenKey(tokenSigningKey);
    List<ContentKeyPolicyTokenClaim> requiredClaims = new List<ContentKeyPolicyTokenClaim>()
    {
        ContentKeyPolicyTokenClaim.ContentKeyIdentifierClaim
    };
    List<ContentKeyPolicyRestrictionTokenKey> alternateKeys = null;
    ContentKeyPolicyTokenRestriction restriction
        = new ContentKeyPolicyTokenRestriction(Issuer, Audience, primaryKey, ContentKeyPolicyRestrictionTokenType.Jwt, alternateKeys, requiredClaims);
    
  2. Configure Widevine license template:

    ContentKeyPolicyWidevineConfiguration widevineConfig = ConfigureWidevineLicenseTempate();
    
  3. Create ContentKeyPolicyOptions:

    options.Add(
        new ContentKeyPolicyOption()
        {
            Configuration = widevineConfig,
            Restriction = restriction
        });
    

Enable offline mode

To enable offline mode for Widevine licenses, you need to configure Widevine license template. In the policy_overrides object, set the can_persist property to true (default is false), as shown in ConfigureWidevineLicenseTemplate.

Configuring the Android player for offline playback

The easiest way to develop a native player app for Android devices is to use the Google ExoPlayer SDK, an open-source video player SDK. ExoPlayer supports features not currently supported by Android's native MediaPlayer API, including MPEG-DASH and Microsoft Smooth Streaming delivery protocols.

ExoPlayer version 2.6 and higher includes many classes that support offline Widevine DRM playback. In particular, the OfflineLicenseHelper class provides utility functions to facilitate the use of the DefaultDrmSessionManager for downloading, renewing, and releasing offline licenses. The classes provided in the SDK folder "library/core/src/main/java/com/google/android/exoplayer2/offline/" support offline video content downloading.

The following list of classes facilitates offline mode in the ExoPlayer SDK for Android:

  • library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java
  • library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java
  • library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java
  • library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java
  • library/core/src/main/java/com/google/android/exoplayer2/drm/ErrorStateDrmSession.java
  • library/core/src/main/java/com/google/android/exoplayer2/drm/ExoMediaDrm.java
  • library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java
  • library/core/src/main/java/com/google/android/exoplayer2/offline/DownloaderConstructorHelper.java
  • library/core/src/main/java/com/google/android/exoplayer2/offline/Downloader.java
  • library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java

Developers should reference the ExoPlayer Developer Guide and the corresponding Developer Blog during development of an application. Google has not released a fully documented reference implementation or sample code for the ExoPlayer app supporting Widevine offline at this time, so the information is limited to the developers' guide and blog.

Working with older Android devices

For some older Android devices, you must set values for the following policy_overrides properties (defined in Widevine license template: rental_duration_seconds, playback_duration_seconds, and license_duration_seconds. Alternatively, you can set them to zero, which means infinite/unlimited duration.

The values must be set to avoid an integer overflow bug. For more explanation about the issue, see https://github.com/google/ExoPlayer/issues/3150 and https://github.com/google/ExoPlayer/issues/3112.
If you do not set the values explicitly, very large values for PlaybackDurationRemaining and LicenseDurationRemaining will be assigned, (for example, 9223372036854775807, which is the maximum positive value for a 64-bit integer). As a result, the Widevine license appears expired and hence the decryption will not happen.

This issue does not occur on Android 5.0 Lollipop or later since Android 5.0 is the first Android version, which has been designed to fully support ARMv8 (Advanced RISC Machine) and 64-bit platforms, while Android 4.4 KitKat was originally designed to support ARMv7 and 32-bit platforms as with other older Android versions.

Using Xamarin to build an Android playback app

You can find Xamarin bindings for ExoPlayer using the following links:

Also, see the following thread: Xamarin binding.

Chrome player apps for Android

Starting with the release of Chrome for Android v. 62, persistent license in EME is supported. Widevine L1 is now also supported in Chrome for Android. This allows you to create offline playback applications in Chrome if your end users have this (or higher) version of Chrome.

In addition, Google has produced a Progressive Web App (PWA) sample and open-sourced it:

If you upgrade your mobile Chrome browser to v62 (or higher) on an Android phone and test the above hosted sample app, you will see that both online streaming and offline playback work.

The above open-source PWA app is authored in Node.js. If you want to host your own version on an Ubuntu server, keep in mind the following common encountered issues that can prevent playback:

  1. CORS issue: The sample video in the sample app is hosted in https://storage.googleapis.com/biograf-video-files/videos/. Google has set up CORS for all their test samples hosted in Google Cloud Storage bucket. They are served with CORS headers, specifying explicitly the CORS entry: https://biograf-155113.appspot.com (the domain in which google hosts their sample) preventing access by any other sites. If you try, you will see the following HTTP error: Failed to load https://storage.googleapis.com/biograf-video-files/videos/poly-sizzle-2015/mp4/dash.mpd: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https:\//13.85.80.81:8080' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
  2. Certificate issue: Starting from Chrome v 58, EME for Widevine requires HTTPS. Therefore, you need to host the sample app over HTTPS with an X509 certificate. A usual test certificate does not work due to the following requirements: You need to obtain a certificate meeting the following minimum requirements:
    • Chrome and Firefox require SAN-Subject Alternative Name setting to exist in the certificate
    • The certificate must have trusted CA and a self-signed development certificate does not work
    • The certificate must have a CN matching the DNS name of the web server or gateway

More information

For more information, see Content Protection in the FAQ.

Widevine is a service provided by Google Inc. and subject to the terms of service and Privacy Policy of Google, Inc.