Radiant Media Player

DASH and HLS DRM



Documentation sections:


Supported DRM

Radiant Media Player supports the following DRM with DASH and/or HLS streaming. Our implementation relies on DRM features provided by Shaka Player.

Our DRM implementation relies on Encrypted Media Extensions (EME) support in the browser/WebView. Complementary to EME support a browser/WebView must have a compatible Content Decryption Module (CDM) to decrypt the DRM content.

To reach all devices we support you are going to need to use a combination of multiple DRMs. The player will automatically pick the correct DRM for the targeted environment. A popular approach is to use DASH with a combo of Widevine and PlayReady to reach desktop, smart TVs and Android, while also using Apple FairPlay HLS to reach Apple devices.

The below article explains how to use DASH & HLS with Widevine/PlayReady/Clear Key DRM. Documentation for Apple FairPlay Streaming can be found here.


Supported browsers/WebView for DRM

  • Browsers
    • Widevine: Chrome for Android 5+; Chrome and Firefox for Windows 7+, macOS 10.10+ and Linux; MS Edge 79+ for Windows 7+; Chrome for ChromeOS
    • PlayReady: MS Edge Legacy and MS Edge 79+ for Windows 7+
    • FairPlay: Safari on iOS 11.2+ and iPadOS 13+; Safari for macOS 10.11+
  • Android & iOS mobile apps (WebView-based)
    • Widevine: Chrome-based or Android-system WebView for Android 7+
    • FairPlay: WKWebView for iOS 13+ and iPadOS 13+
  • OTT apps
    • Widevine: Samsung Smart TV apps; Desktop apps with Electron 6+; Cast receiver application (Google Cast)

In order to provide decent device coverage you are likely to have to use a multi-DRM approach. Combining Widevine, PlayReady and Apple FairPlay DRM is a common standard in the industry.

As an alternative to FairPlay Streaming one may use HLSe (AES-128/SAMPLE-AES encrypted HLS) as a fallback for iOS/macOS Safari, however it should be noted that HLSe provides a lesser level of security than FairPlay Streaming and may not meet studio requirements. See here for an example using DASH DRM and HLSe as a fallback.


Player configuration


General consideration

You may go through our MPEG-DASH streaming docs for a better understanding of MPEG-DASH streaming options with Radiant Media Player in this configuration.

To play DRM-protected content with MPEG-DASH, the player only needs to know 2 things: the URL of the DRM license server and what options are required to fetch and validate the license. Below you will also find various configuration options to support custom & advanced DRM use-cases.


Choosing a Key System

Radiant Media Player is key-system-agnostic, meaning it does not prefer any key systems over any others. We use EME to ask the browser what it supports, and make no assumptions. If the browser supports multiple key systems, the first supported key system in the MPEG-DASH manifest is used. The interoperable encryption standard that DRM vendors are implementing is called Common Encryption (CENC). Some MPEG-DASH manifests don't specify any particular key system at all, but instead state that any CENC system will do:

<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>

If this is the only <ContentProtection> element in the manifest, Radiant Media Player will try all key systems it knows. If the browser supports it and you configured a license server URL for it, we'll use it.


Player settings

shakaDrm: Object

This is where we feed the player the license server URL and other DRM-related options. The shakaDrm object supports 3 properties:

shakaDrm.servers: Object

This is where license server URLs are passed to the player. Example for a combination of Widevine, PlayReady & Clear Key license servers:

shakaDrm: {
  servers: {
    'com.widevine.alpha': 'https://foo.bar/drm/widevine',
    'com.microsoft.playready': 'https://foo.bar/drm/playready',
    'org.w3.clearkey': 'http://foo.bar/drm/clearkey'
  }
}
shakaDrm.clearKeys: Object

The EME specification requires browsers to support a common key system called "Clear Key". Clear Key uses unencrypted keys to decrypt CENC content, and can be useful for diagnosing problems and testing integrations. To configure Clear Key, use the configuration field shakaDrm.clearKeys and provide a map of key IDs to content keys (both in HEX format). Example:

shakaDrm: {
  clearKeys: {
    'deadbeefdeadbeefdeadbeefdeadbeef': '18675309186753091867530918675309',
    '02030507011013017019023029031037': '03050701302303204201080425098033'
  }
}
shakaDrm.advanced: Object

We have several advanced options available to give you access to the full EME configuration. The configuration field shakaDrm.advanced is an object mapping key system IDs to their advanced settings. For example, to require hardware security in Widevine:

shakaDrm: {
  servers: {
    'com.widevine.alpha': 'https://foo.bar/drm/widevine'
  },
  advanced: {
    'com.widevine.alpha': {
      'videoRobustness': 'HW_SECURE_ALL',
      'audioRobustness': 'HW_SECURE_ALL'
    }
  }
}

Refer to this Google documentation page for a list of supported properties in the shakaDrm.advanced object.

About robustness levels

The robustness level key-system-specific string specifies a required security level for video/audio. By default it is set to '', which means that no specific robustness required, and this is the less secure approach. Content owners generally require a specific robustness level in order to allow a 3rd-party to distribute their content. For Widevine those robustness levels are (a lower level means better security):

  • SW_SECURE_CRYPTO: Widevine Device Security Level 3
  • SW_SECURE_DECODE : Widevine Device Security Level 3
  • HW_SECURE_CRYPTO: Widevine Device Security Level 2
  • HW_SECURE_DECODE : Widevine Device Security Level 1
  • HW_SECURE_ALL: Widevine Device Security Level 1

Player code example

Follows a player code example with DASH Widevine DRM (works on latest Chrome, Firefox).

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var src = {
  dash: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine/dash.mpd'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  width: 640,
  height: 360,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  },
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': 'https://cwip-shaka-proxy.appspot.com/no_auth'
    }
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>

Now an example with fMP4 HLS Widevine DRM (works on latest Chrome, Firefox).

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var src = {
  hls: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine-hls/hls.m3u8'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  width: 640,
  height: 360,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  },
  hlsEngine: 'shakaplayer',
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': 'https://cwip-shaka-proxy.appspot.com/no_auth'
    }
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>

License server authentication

Your license server may require some form of authentication so that it only delivers licenses to paying users. In this section we're going to use various license server endpoints that require various forms of authentication. If you need live example to test your set up you can refer to this Google documentation page.

We provide support for 3 authentication modes: header authentication, parameter authentication & cookie authentication

Authentication is provided through the shakaRequestConfiguration player setting. You can refer to our MPEG-DASH docs for more information as this setting may also be used outside DRM context.

Header authentication

In this case your license server requires a specific header value to deliver a license. If you try to use it without setting the authentication header, you will see Error code 6007 in the player logs, which means LICENSE_REQUEST_FAILED. The JavaScript console will show you a failed HTTP request with HTTP status code 401 (Unauthorized), and playback will hang when you get to the encrypted part of the stream.

To provide header authentication we will use the player shakaRequestConfiguration setting as follows:

shakaRequestConfiguration: {
  license: {
    headers: {
      'CWIP-Auth-Header': 'VGhpc0lzQVRlc3QK'
    }
  }
}

Full player example - this example is provided for Widevine DRM - see this example here

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var src = {
  dash: 'https://storage.googleapis.com/shaka-demo-assets/sintel-widevine/dash.mpd'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  width: 640,
  height: 360,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  },
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': 'https://cwip-shaka-proxy.appspot.com/header_auth'
    }
  },
  shakaRequestConfiguration: {
    license: {
      headers: {
        'CWIP-Auth-Header': 'VGhpc0lzQVRlc3QK'
      }
    }
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>
Parameter authentication

Now, we'll try authentication using URL parameters. In this case the license server endpoint requires a specific URL parameter to deliver a license. If you try to use it without setting the parameter, you will see Error code 6007 (LICENSE_REQUEST_FAILED) in player logs just as before with header authentication.

Again to provide parameter authentication we will use the player shakaRequestConfiguration setting as follows:

shakaRequestConfiguration: {
  license: {
    parameters: '?CWIP-Auth-Param=VGhpc0lzQVRlc3QK'
  } 
}

Full player example - this example is provided for Widevine DRM - test in Chrome:

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var src = {
  dash: 'https://storage.googleapis.com/shaka-demo-assets/sintel-widevine/dash.mpd'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  width: 640,
  height: 360,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  },
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': 'https://cwip-shaka-proxy.appspot.com/param_auth'
    }
  },
  shakaRequestConfiguration: {
    license: {
      parameters: '?CWIP-Auth-Param=VGhpc0lzQVRlc3QK'
    }
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>

Now, let's try using cookies for authentication. In this case the license server endpoint requires a specific cookie to deliver a license. If you try to use it without setting the parameter, you will see Error code 6007 (LICENSE_REQUEST_FAILED) in player logs. Cookies are set by a server to be returned to that server, and are not sent by the JavaScript application. So to set the required cookie value for this test example, point your browser to the server's set_cookie page. Cookies are considered "credentials" by the browser's XmlHttpRequest API, and credentials may not be sent cross-origin unless explicitly requested by the application AND explicitly allowed by the destination server. Our cookie_auth license server endpoint sends back headers that allow credentialed requests, so we also need to tell the player to send credentials cross-site.

Again to provide cookie authentication we will use the player shakaRequestConfiguration setting as follows:

shakaRequestConfiguration: {
  license: {
    credentials: true
  } 
}

Full player example - this example is provided for Widevine DRM - test in Chrome:

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var src = {
  dash: 'https://storage.googleapis.com/shaka-demo-assets/sintel-widevine/dash.mpd'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  width: 640,
  height: 360,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  },
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': 'https://cwip-shaka-proxy.appspot.com/cookie_auth'
    }
  },
  shakaRequestConfiguration: {
    license: {
      credentials: true
    } 
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>
Asynchronous credentials

In some scenarios, you may not know the credentials right away. You would like to make an additional request to get those credentials before you attach them to the request Radiant Media Player wants to make. Since version 4.6.16 we have simplified handling of such use cases through the shakaCustomRequestFilter player setting. Refer to this Shaka player docs for more information. Following is a player code example for using asynchronous credentials and Radiant Media Player:

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var licenseServer = 'https://cwip-shaka-proxy.appspot.com/header_auth';
var authTokenServer = 'https://cwip-shaka-proxy.appspot.com/get_auth_token';
var authToken = null;
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
var shakaCustomRequestFilter = function (type, request) {
  console.log('shakaCustomRequestFilter callback');
  // Only add headers to license requests:
  if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) return;

  // If we already know the token, attach it right away:
  if (authToken) {
    console.log('Have auth token, attaching to license request.');
    request.headers['CWIP-Auth-Header'] = authToken;
    return;
  }

  console.log('Need auth token.');
  // Start an asynchronous request, and return a Promise chain based on that.
  var authRequest = {
    uris: [authTokenServer],
    method: 'POST',
  };
  var requestType = shaka.net.NetworkingEngine.RequestType.APP;
  return rmp.shakaPlayer.getNetworkingEngine().request(requestType, authRequest).then(
    function (response) {
      // This endpoint responds with the value we should use in the header.
      authToken = shaka.util.StringUtils.fromUTF8(response.data);
      console.log('Received auth token', authToken);
      request.headers['CWIP-Auth-Header'] = authToken;
      console.log('License request can now continue.'); 
    });
};
var src = {
  dash: 'https://storage.googleapis.com/shaka-demo-assets/sintel-widevine/dash.mpd'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': licenseServer
    }
  },
  shakaCustomRequestFilter: shakaCustomRequestFilter,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  }
};
rmp.init(settings);
</script>

DASH DRM with AES-128/SAMPLE-AES HLS fallback

When using a combined Widevine/PlayReady DRM approach with DASH streaming modern browser support should be fairly good. However on iOS or macOS Safari where DRM Widevine/PlayReady are not supported you can use HLSe (AES-128/SAMPLE-AES encrypted HLS) as a fallback. On macOS and iOS Safari you may also consider using Apple FairPlay DRM.

Player code example:

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var src = {
  dash: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest.mpd',
  // here is our AES-128 HLS fallback
  hls: 'https://www.radiantmediaplayer.com/media/rmp-segment/bbb-abr-aes/playlist.m3u8'
};
var settings = {
  licenseKey: 'your-license-key',
  src: src,
  width: 640,
  height: 360,
  contentMetadata: {
    poster: [
      'https://your-poster-url.jpg'
    ]
  },
  dashFirst: true,
  hlsEngine: 'hlsjs',
  // passing DRM settings
  shakaDrm: {
    servers: {
      'com.widevine.alpha': 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
      'com.microsoft.playready': 'https://drm-playready-licensing.axtest.net/AcquireLicense'
    }
  },
  shakaRequestConfiguration: {
    license: {
      headers: {
        'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.4lWwW46k-oWcah8oN18LPj5OLS5ZU-_AQv7fe0JhNjA' 
      }
    }
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>

Offline DRM and persistent license support

shakaAutoDetectPersistentLicenseSupport: Boolean

Enables or not auto detection of persistent license support. Default: true.

shakaUsePersistentLicense: Boolean

Forces uses of persistent license or not. Default: false.

Persistent licenses are supported in Chrome 64+ for Android 6+, macOS, Windows and ChromeOS. By default the player automatically detects support for persistent licenses ( shakaAutoDetectPersistentLicenseSupport setting). For other platforms, where storage of persistent licenses is not available you will get offline storage of protected content on all DRM-enabled browsers, at the cost of needing a network connection at playback time to retrieve licenses.


Changing player source with DRM

If you are using the setSrc API method to change player source with DRM content you could likely want to update the player with new DRM information. This can be done by using the following API methods:

getShakaCustomRequestFilter

Returns Function the current custom request filter for Shaka player used by Radiant Media Player.

setShakaCustomRequestFilter(shakaCustomRequestFilter)

Takes shakaCustomRequestFilter Function as an input to update the current custom request filter for Shaka player used by Radiant Media Player. This should be used just before using setSrc API method.

getShakaRequestConfiguration

Returns Object the current request configuration for Shaka player used by Radiant Media Player.

setShakaRequestConfiguration(shakaRequestConfiguration)

Takes shakaRequestConfiguration Object as an input to update the current request configuration for Shaka player used by Radiant Media Player. This should be used just before using setSrc API method.

getShakaDrm

Returns Object the current DRM configuration for Shaka player used by Radiant Media Player.

setShakaDrm(shakaDrm)

Takes shakaDrm Object as an input to update the current DRM configuration for Shaka player used by Radiant Media Player. This should be used just before using setSrc API method.

Usage example:

<!-- Include Radiant Media Player - here we use the optimised build for Shaka player -->
<script src="https://cdn.radiantmediatechs.com/rmp/5.10.2/js/rmp-shaka.min.js"></script>
<!-- Player container element -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
  var src = {
    dash: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine/dash.mpd'
  };
  var settings = {
    licenseKey: 'your-license-key',
    src: src,
    width: 640,
    height: 360,
    autoplay: true,
    // passing DRM settings
    shakaDrm: {
      servers: {
        'com.widevine.alpha': 'https://cwip-shaka-proxy.appspot.com/no_auth'
      }
    }
  };
  var elementID = 'rmpPlayer';
  var rmp = new RadiantMP(elementID);
  rmp.init(settings);
          
  // this setTimeout function just emulate a case where setSrc is called with new DRM information 
  setTimeout(function () {
    window.console.log(rmp.getShakaDrm());
    rmp.setShakaRequestConfiguration({
      license: {
        headers: {
          'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.4lWwW46k-oWcah8oN18LPj5OLS5ZU-_AQv7fe0JhNjA'
        }
      }
    });
    rmp.setShakaDrm({
      servers: {
        'com.widevine.alpha': 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
                  }
      }
    );
    rmp.setSrc({
      dash: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest.mpd'
    });
  }, 15000);
</script>

Supported DRM service providers

Radiant Media Player should work with any standard compliant DRM service providers that can encrypt media content with Widevine and/or PlayReady and/or FairPlay DRM. Below are names of DRM services that our customers have successfully used with Radiant Media Player:

Based on the solution your DRM service provider offer you may also need a solution to package your content for DASH or HLS. Wowza Streaming Engine supports on-the-fly DASH CENC encryption for on demand and live content via the PlayReady and Widevine DRM systems.

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License.