Enabling Hardware DRM on Android Chrome using the Encrypted Media Extensions

The Media Source Extensions (MSE) and Encrypted Media Extensions (EME) are two APIs that enable playback of Digital Rights Management (DRM) protected adaptive streaming content in a browser. Both APIs are supported in all four major browsers: Chrome, Firefox, Edge and Safari. Recently, Google announced that Android devices directly support Widevine Hardware DRM in Chrome browsers:

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

Let’s take a closer look on the implications and how we can enable this feature.

DRM Security Levels

Content owners and publishers have strong security requirements when it comes to content protection and potential content piracy. In order to be allowed to offer Ultra HD movies, providers need to guarantee a maximum level of  protection. In terms of DRM, this means that the protectors themselves need to support a hardware-based DRM system. For Google’s Widevine DRM system, three different security levels are defined: 

  • Security Level 1 (L1): complete processing is performed in a Trusted Execution Environment (TEE). This level refers to a hardware DRM.
  • Security Level 2 (L2): 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.

Coming back to our example of playing Ultra HD content, only devices with a security level of L1 are allowed to play such high quality content. So, how can we check whether an Android device supports a L1 Widevine DRM in Chrome or not? 

Hardware DRM and EME – The theory

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

Source: https://docs.microsoft.com/en-us/azure/media-services/previous/offline-widevine-for-android
EME LevelRobustness LevelWidevine Security Level

Unfortunately, the mapping of EME to Widevine security levels is a bit confusing. For example, EME level 1 maps to a Widevine security level of 3. In order to avoid any confusion, it is highly recommended to always specify the level type (either EME or Widevine).

The EME level is not specified directly in the requestMediaKeySystemAccess call. Instead, the robustness level parameter is used. The complete invocation of the initial EME call includes a configuration array that combines all required parameters:

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

Typically, not only is the video track encrypted, but the audio track as well. Widevine recommends using different encryption keys for both tracks. Additionally, video tracks are much more valuable and as a result, platforms only support Widevine L3 audio tracks. Following that, a sample configuration for the requestMediaKeySystemAccess call can have the following values:

const config = [
    "initDataTypes": [
    "persistentState": "optional",
    "distinctiveIdentifier": "optional",
    "sessionTypes": [
    "audioCapabilities": [
        "robustness": "SW_SECURE_CRYPTO",
        "contentType": "audio/mp4;codecs="mp4a.40.2""
    "videoCapabilities": [
        "robustness": "HW_SECURE_ALL",
        "contentType": "video/mp4;codecs="avc1.42800C""

In this example, the video track requires at least a Widevine level 1 DRM, while audio only needs level 3. One thing to keep in mind, is that changing parameters like persistentState, distinctiveIdentifier or the contentType have a significant influence on the result of the call. The underlying CDM may reject the configuration if one of these settings is not supported, regardless of Hardware DRM support or not.

Hardware DRM and EME – Practical tests

Now that we covered all theories, let’s see if this really works. In our tests, we used a Samsung Galaxy S9 with Android 9 and Chrome 75.0.3770.101, and a HTC OnePlus 5T with Android 8.1 and Chrome 75.0.3770.101.

Good news first: with the configuration described above, the promise returned by the requestMediaKeysSystemAccessCall is successfully resolved on both devices. Unfortunately, this does not necessarily mean that our device really supports Hardware DRM. On one of our test devices, we encountered an error when trying to create the MediaKeys afterwards. So, whenever we are checking if our device supports a Hardware DRM or not, we need to check for MediaKeys as well. This leaves us with the following code:

          .requestMediaKeySystemAccess(keySystem, config)
          .then((keySystemAccess) => {
            return keySystemAccess.createMediaKeys();
          .then(() => {
            // yay it works
          .catch((e) => {
            // no UHD on this device :(

That concludes our dive into the world of Hardware DRM and EME. If you want to find out more about our DRM activities, feel free to check out our website.

Leave a Reply

Your email address will not be published. Required fields are marked *