Enabling Widevine L1 on Android Chrome using Encrypted Media Extensions

The Media Source Extensions (MSE) and Encrypted Media Extensions (EME) are the two APIs that enable playback of DRM protected adaptive streaming content in the browser. Both are supported in all four major browsers, namely Chrome, Firefox, Edge and Safari. Quite recently Google announced that Android devices support a Widevine DRM with security level 1 directly in the Chrome browser:

Chrome on Android is a Widevine L1 implementation as it leverages the built-in CDM on Android OS.

Let us take a closer look what that means and how we can enable this new feature.

Typically Hollywood studios have pretty strict demands when it comes to protecting their assets against piracy. In order to be allowed to play UHD movies on a platform, providers need to guarantee a maximum level of  protection. In terms of DRM this means they need to support a hardware based system. For Googles Widevine DRM, three different security levels are defined: 

  • Security Level 1 (L1): The complete processing is performed in a Trusted Execution Environment (TEE). This level refers to a hardware DRM
  • Security Level 2 (L2): The cryptography is performed within the TEE. The video processing is done through separate video hardware or software. This level still refers to a hardware DRM.
  • Security Level 3 (L3): No TEE is present on the device. Decryption is typically performed directly in the browser. This level refers to a software DRM.

To come back to our example of playing UHD content, only devices with L1 are allowed to playback such high quality content. So how can we check if an Android device supports a L1 Widevine DRM in the browser? 

When talking about playback in the browser, the EME provides us the necessary functions to communicate with the DRM system on the device. The requestMediaKeySystemAccess function of the EME is used to detect which DRM systems are available and what the supported configurations are. The EME defines five different security levels which can be directly mapped to a respective Widevine security level.

EME LevelRobustness LevelWidevine Security  Level
1SW_SECURE_CRYPTO3
2SW_SECURE_DECODE3
3HW_SECURE_CRYPTO2
4HW_SECURE_DECODE1
5HW_SECURE_ALL1

Unfortunately, the mapping of EME level to Widevine security level is a bit confusing. For instance, EME level 1 maps to a Widevine security level of 3. So in order to avoid misunderstandings it is highly recommended to always specify the type of the level (either EME or Widevine).

The EME level is not directly specified in the requestMediaKeySystemAccess call. Instead the robustness level parameter is used. The complete invocation of the initial EME call includes a config array combining all the required parameters and looks like the following:

 navigator.requestMediaKeySystemAccess(data.systemString, config)
.then(function (mediaKeySystemAccess) {
        // Do something afterwards
        })
.catch(function (e) {
        // Ups this configuration is not supported
        });

Typically, not only the video track is encrypted, but also the audio track. Widevine recommends to use different encryption keys for both tracks. Moreover, video tracks are much more valuable and therefor most platforms only support Widevine L3 or L2 for audio tracks. Following that, a sample configuration for the requestMediaKeySystemAccess() call can have the following values:

const config = [
  {
    "initDataTypes": [
      "cenc"
    ],
    "persistentState": "optional",
    "distinctiveIdentifier": "optional",
    "sessionTypes": [
      "temporary"
    ],
    "audioCapabilities": [
      {
        "robustness": "SW_SECURE_CRYPTO",
        "contentType": "audio/mp4;codecs=\"mp4a.40.2\""
      }
    ],
    "videoCapabilities": [
      {
        "robustness": "HW_SECURE_ALL",
        "contentType": "video/mp4;codecs=\"avc1.42E01E\""
      }
    ]
  }
]

In this example the video track requires at least a Widevine level 1 DRM, while audio only needs level 3. 

As mentioned in the beginning of this post, Google has announced support for Widevine level 1 in Android Chrome browser. The crucial point when trying to verify this, is to keep in mind that the EME seems to return the biggest common denominator of a requestMediaKeySystemAccess() call. This means if we use the configuration from our example above, we will never get a valid configuration for an EME level greater than 2. Instead we have to make a separat call for our video track, nulling the audioCapabilities:

const config = [
  {
    "initDataTypes": [
      "cenc"
    ],
    "persistentState": "optional",
    "distinctiveIdentifier": "optional",
    "sessionTypes": [
      "temporary"
    ],
    "audioCapabilities": [],
    "videoCapabilities": [
      {
        "robustness": "HW_SECURE_ALL",
        "contentType": "video/mp4;codecs=\"avc1.42E01E\""
      }
    ]
  }
]

Doing that, we are able to see support for Widevine level 1 on most of the available Android devices using an up-to-date version of Chrome. 

In my next blog post I will introduce a very simple test application which iterates through most of the available configuration settings. Using the application we can identify the best available configuration for a device.