Radiant Media Player

Apple FairPlay Streaming



Apple FairPlay Streaming

Apple FairPlay Streaming with HLS is supported in Radiant Media Player since version 4.0.11

Information on Apple FairPlay Streaming can be found here.

Safari 9+ on macOS supports DRM through Apple FairPlay Streaming (FPS). Radiant Media Player provides flexible options for supporting Apple FairPlay Streaming with HLS. Our implementation is based on the reference sample provided by Apple with the FairPlay Streaming Server SDK v3. This sample is provided as it is provided by Apple as of March 2017 - it needs to be adapted first before usage - view page source for an understanding of the JavaScript logic. We have extended this implementation through advanced player settings to provide support for virtually any standard-compliant DRM service providers, including ExpressPlay or EZDRM. If you need additional tuning for your Apple FairPlay Streaming setup please contact technical support.

Apple FairPlay DRM is not available in iOS (either in Safari or in web-based mobile apps)


Player settings


Apple reference example

In its simple form we just comply with the Apple reference sample. For such a use case you just need to pass to the player your HLS URL, your server certificate URL and server processSPC URL.

<!-- Include Radiant Media Player JavaScript file in your <body> or <head> -->
<script src="https://cdn.radiantmediatechs.com/rmp/4.5.15/js/rmp.min.js" 
  integrity="sha384-UOGahVOpoWqVqcgcNFKFOEWH3RV2PoLAq2jmk8g1u9VR/bL8dqsHAsDGwFHPkmuE"
  crossorigin="anonymous"></script>
<!-- Set up your wrapper div with its unique id -->
<div id="rmpPlayer"></div>
<!-- Set up player configuration options -->
<script>
var bitrates = { 
  fps: 'https://your-url-to-fps-hls.m3u8' 
};
var settings = {
  licenseKey: 'your-license-key',
  bitrates: bitrates,  
  delayToFade: 3000,
  width: 640,
  height: 360,
  poster: 'https://www.radiantmediaplayer.com/images/poster-rmp-showcase.jpg',
  // pass FPS DRM info to the player
  fpsDrm: {
    certificatePath: 'https://your-url-to-server-certificate.cer',
    processSpcPath: 'https://your-url-to-server-processSPC'
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>

Configuration options

See the EZDRM example below for a full example of custom setup with the below setting.

fpsDrm: Object

This setting holds the required information to be passed to the player for proper retrieval of FPS licenses.

fpsDrm.certificatePath: String

The server path/URL to your FPS certificate. This is a required setting.

fpsDrm.processSpcPath: String

This is the path/URL to the keyserver module that processes the SPC and returns a CKC. This is a required setting.

fpsDrm.licenseResponseType: String

Specifies the responseType for the XMLHttpRequest when requesting the FPS license to the server. The default value is 'text' (as provided by the Apple reference sample). Other possible values are 'arraybuffer', 'json', and 'blob'.

fpsDrm.licenseRequestHeaders: Array

This setting specifies an Array of Object to set the request headers for the XMLHttpRequest when requesting the FPS license from the server. Each item of the array should be an object containing a name property and a value property both set as String. Default [] (as provided by the Apple reference sample).

fpsDrm.certificateRequestHeaders: Array

This setting specifies an Array of Object to set the request headers for the XMLHttpRequest when requesting the FPS certificate from the server. Each item of the array should be an object containing a name property and a value property both set as String. Default (as provided by the Apple reference sample):

[{
  name: 'Pragma',
  value: 'Cache-Control: no-cache'
}, {
  name: 'Cache-Control',
  value: 'max-age=0'
}];
fpsDrm.extractContentId: Function

This function specifies how to extract the content id which is part of the session data used to initialize the keySession. Default (as provided by the Apple reference sample):

function (initData) {
  var arrayToString = function (array) {
    var uint16array = new Uint16Array(array.buffer);
    return String.fromCharCode.apply(null, uint16array);
  };
  var contentId = arrayToString(initData);
  var link = document.createElement('a');
  link.href = contentId;
  return link.hostname;
};
fpsDrm.licenseRequestMessage: Function

This function specifies how the received license key message is treated by the player and return the message to be sent to the license server. Default (as provided by the Apple reference sample):

function (message, session) {
  return 'spc=' + base64EncodeUint8Array(message) + '&assetId=' + encodeURIComponent(session.contentId);
};

the base64EncodeUint8Array function is provided internally by the player for the default value so you do not need to provide it.

fpsDrm.licenseRequestLoaded: Function

This function specifies the callback function when the license is succesffuly loaded from the server. Default (as provided by the Apple reference sample):

function (event) {
  var request = event.target;
  var session = request.session;
  var keyText = request.responseText.trim();
  if (keyText.substr(0, 5) === '<ckc>' && keyText.substr(-6) === '</ckc>') {
    keyText = keyText.slice(5, -6);
  }
  var key = base64DecodeUint8Array(keyText);
  session.update(key);
};

EZDRM example

<script src="https://cdn.radiantmediatechs.com/rmp/4.5.15/js/rmp.min.js" 
  integrity="sha384-UOGahVOpoWqVqcgcNFKFOEWH3RV2PoLAq2jmk8g1u9VR/bL8dqsHAsDGwFHPkmuE"
  crossorigin="anonymous"></script>
<div id="rmpPlayer"></div>
<script>
var bitrates = {
  fps: 'https://fps-hls-url.m3u8'
};
// we define our functions and variables to be passed to the player
// extractContentId
var extractContentId = function (initData) {
  var arrayToString = function (array) {
    var uint16array = new Uint16Array(array.buffer);
    return String.fromCharCode.apply(null, uint16array);
  };
  var uri = arrayToString(initData);
  var uriParts = uri.split('://', 1);
  var protocol = uriParts[0].slice(-3);
  uriParts = uri.split(';', 2);
  var contentId = uriParts.length > 1 ? uriParts[1] : '';
  return protocol.toLowerCase() == 'skd' ? contentId : '';
};
// licenseRequestMessage
var licenseRequestMessage = function (message) {
  return new Blob([message], { type: 'application/octet-binary' });
};
// licenseRequestLoaded
var licenseRequestLoaded = function (event) {
  var request = event.target;
  if (request.status == 200) {
    var blob = request.response;
    var reader = new FileReader();
    reader.addEventListener('loadend', function () {
      var array = new Uint8Array(reader.result);
      request.session.update(array);
    });
    reader.readAsArrayBuffer(blob);
  }
};
// processSpcPath
var processSpcPath = 'http://fps.ezdrm.com/api/licenses/09cc0377-6dd4-40cb-b09d-b582236e70fe' + '?p1=' + Date.now();
// licenseRequestHeaders
var licenseRequestHeaders = [
  {
    name: 'Content-type',
    value: 'application/octet-stream'
  }
];
var settings = {
  licenseKey: 'your-license-key',
  bitrates: bitrates,
  delayToFade: 3000,
  width: 640,
  height: 360,
  poster: 'https://www.radiantmediaplayer.com/images/poster-rmp-showcase.jpg',
  // we pass it our FPS setting through fpsDrm object
  fpsDrm: {
    certificatePath: 'https://url-to-certificate.cer',
    processSpcPath: processSpcPath,
    licenseResponseType: 'blob',
    licenseRequestHeaders: licenseRequestHeaders,
    certificateRequestHeaders: [],
    extractContentId: extractContentId,
    licenseRequestMessage: licenseRequestMessage,
    licenseRequestLoaded: licenseRequestLoaded
  }
};
var elementID = 'rmpPlayer';
var rmp = new RadiantMP(elementID);
rmp.init(settings);
</script>
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License.