DRM Content Playback

Note

This guide introduces the DRM service and provides an example code of how to use the service. To implement the streaming player with Media Source Extensions (MSE), use Encrypted Media Extensions (EME) referred to Supported Media Formats.

webOS TV provides the DRM Service to support DRM content playback. The DRM service manages the DRM Client, which holds a particular type of information required to get a license key. When playing DRM content, Media Pipeline (Player) needs the license key for decryption. Media Pipeline acquires the license key either directly from a DRM Client (PlayReady).

webOS TV supports the following DRM types:

PlayReady

On PlayReady DRM, the DRM Client requests a key from the DRM License Server with the initiator information directly. Media Pipeline gets the license key from the DRM Client. The following diagram shows the operation flow of PlayReady DRM content playback.

PlayReady DRM data flow diagram

The following introduces each component of the above diagram:

  • DRM Service: The DRM Service manages the DRM Client instance and provides APIs to manage the DRM Client.

  • Web App: The web app requests Media Pipeline to play DRM content and sends the DRM message (initiator information) to the DRM client.

  • DRM Client: The DRM Client holds initiator information and gets a license key from the License Server. Licensing error might occur during content playback via the DRM Client.

  • Media Pipeline: Media Pipeline gets the license key from the DRM Client. Media Pipeline decrypts DRM content with the license key and plays it.

  • Content Server: The Content Server stores and publishes DRM content.

  • License Server: The License Server manages rights and returns the key for decryption.

The following sequence diagram shows the PlayReady DRM playback process among the components.

PlayReady sequence diagram

PlayReady DRM playback sequence is described as below:

  1. The web app requests the DRM Service to create a DRM Client with the load() method. The load() method requires the DRM type and App ID.

  2. The DRM Service creates the DRM Client instance and returns its ID to the web app with a callback function.

  3. The web app uses the sendDrmMessage() method to give the DRM message to the DRM client. The DRM message holds initiator information in DRM message format.

  4. The DRM client verifies the DRM message and returns the result with msgId. The msgId is used to identify the subscription message of the getRightsError() method.

  5. As licensing error might occur during content playback via the DRM Client, the web app needs to subscribe licensing error message with the getRightsError() method.

  6. The DRM client gets a license key from the License Server.

  7. The web app gives a content target, DRM Client ID, and playback options to Media Pipeline with the video element and mediaOption Parameter.

  8. Media Pipeline gets the license key from the DRM Client.

  9. Media Pipeline decrypts the DRM content stream with the license key and plays the decrypted content stream.

  10. The callback function, registered by the getRightsError() method for the licensing error message, verifies the message and handles errors during content playback.

  11. The DRM Client must be removed with the unload() method before unloading the web app.

A licensing error message is broadcasted to every subscribed app. The web app needs to check the valid message with msgId, which is given by the sendDrmMessage() method.

Note

You must unload the DRM Client before:

  • Terminating your app
  • Preparing to play other types of DRM content (for re-initialization).

To play PlayReady DRM content, you need to use LS API of the DRM Service and mediaOption parameter. You can play PlayReady DRM content as follows:

  1. Add the webOS library in your app to call DRM Service API.

    <!-- HTML Code -->
    <script type="text/javascript" src="lib/webOS.js"></script>
    ...
  2. Call the load() method when your app is loaded.

    var appId = 'com.yourdomain.yourapp';
    
    // Define DRM Type
    var drmType = 'playready';
    var clientId;
    var isDrmClientLoaded;
    
    function loadDrmClient() {
      var request = webOS.service.request('luna://com.webos.service.drm', {
        method: 'load',
        parameters: {
          drmType: drmType,
          appId: appId,
        },
        onSuccess: function (result) {
          clientId = result.clientId;
          isDrmClientLoaded = true;
          console.log('DRM Client is loaded successfully.');
        },
        onFailure: function (result) {
          console.log('[' + result.errorCode + '] ' + result.errorText);
          // Do something for error handling
        },
      });
    }
  3. Send the DRM message (initiator information) with the sendDrmMessage() method.

    // Message example for playready
    var msg = '<?xml version="1.0" encoding="utf-8"?>
    <PlayReadyInitiator xmlns= "http://schemas.microsoft.com/DRM/2007/03/protocols/">
      <LicenseAcquisition>
        <Header>
          <WRMHEADER xmlns= "http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.0.0.0">
            <DATA>
              <PROTECTINFO>
                <KEYLEN>16</KEYLEN>
                <ALGID>AESCTR</ALGID>
              </PROTECTINFO>
              <LA_URL>http://playready.directtaps.net/pr/svc/rightsmanager.asmx</LA_URL>
              <KID>lFmb2gxg0Cr5bfEnJXgJeA==</KID>
              <CHECKSUM>P7ORpD2IpA==</CHECKSUM>
            </DATA>
          </WRMHEADER>
        </Header>
        <CustomData>AuthZToken XYZ</CustomData>
      </LicenseAcquisition>
    </PlayReadyInitiator>'
    
    var msgId;
    
    // Message type for PlayReady
    var msgType = "application/vnd.ms-playready.initiator+xml";
    
    // Unique ID of DRM system
    var drmSystemId = "urn:dvb:casystemid:19219";
    
    function sendRightInformation() {
        request = webOS.service.request("luna://com.webos.service.drm", {
            method:"sendDrmMessage",
            parameters: {
                "clientId": clientId,
                "msgType": msgType,
                "msg": msg,
                "drmSystemId": drmSystemId
            },
            onSuccess: function (result) {
                msgId = result.msgId;
                var resultCode = result.resultCode;
                var resultMsg = result.resultMsg;
                console.log("Message ID: " + msgId);
                console.log("[" + resultCode + "] " + resultMsg);
    
                if (resultCode != 0){
                    // Do Handling DRM message error
                }
            },
            onFailure: function (result) {
                console.log("[" + result.errorCode + "] " + result.errorText);
            }
        });
    }
    Note

    For more information about DRM messages, see DRM Message.

  4. Subscribe the licensing error message with the getRightsError() method.

    // JavaScript code
    var subscriptionHandler;
    ...
    function subscribeLicensingError() {
        var request = webOS.service.request("luna://com.webos.service.drm", {
            method:"getRightsError",
            parameters: {
                "clientId": clientId,
                "subscribe": true
            },
            onSuccess: function (result) { // Subscription Callback
                contentId = result.contentId;
                if (contentId == msgId) {
                    if ( 0 == result.errorState) {
                        console.log("No license");
                        // Do something for error handling
                    }
                    else if ( 1 == result.errorState) {
                        console.log("Invalid license");
                        // Do something for error handling
                    }
                    console.log("DRM System ID: " + result.drmSystemId);
                    console.log("License Server URL: " + result.rightIssueUrl);
                }
            },
            onFailure: function (result) {
                console.log("[" + result.errorCode + "] " + result.errorText);
            }
        });
        //Register subscription handler
        subscriptionHandler = request;
    }
    ...
  5. Create an object for mediaOption of the video element and set the playback options.

    <!-- HTML code -->
    <video id="myVideo" ...> </video>
    // JavaScript code
    var options = {};
    options.option = {};
    options.option.drm = {};
    options.option.drm.type = drmType;
    options.option.drm.clientId = clientId;
  6. Convert the created object to JSON string and encode it.

    var mediaOption = encodeURIComponent(JSON.stringify(options));
  7. Create the source element.

    var source = document.createElement('source');
  8. Add attributes to the created source element for media content. Add the encoded string to type attribute as below:

    var dataURL = 'http://example.com/test.mp4';
    source.setAttribute('src', dataURL);
    source.setAttribute('type', 'video/mp4;mediaOption=' + mediaOption);
    Note

    For more information about media types, see the Platform Specification.

  9. Add the created source element to the video element or audio element.

    video = document.getElementById('myVideo');
    video.appendChild(source);
  10. Call the unload() method and cancel the subscription before terminating your app or preparing to play other types of DRM content (for re-initialization).

    <!-- HTML Code -->
    ...
    <body onunload="unloadDrmClient()">
    ...
    // JavaScript Code
    ...
    function unloadDrmClient() {
        if (isDrmClientLoaded) {
            var request = webOS.service.request("luna://com.webos.service.drm", {
                method:"unload",
                parameters: { "clientId": clientId },
                onSuccess: function (result) {
                    isDrmClientLoaded = false;
                    console.log("DRM Client is unloaded successfully.");
                },
                onFailure: function (result) {
                    console.log("[" + result.errorCode + "] " + result.errorText);
                    // Do something for error handling
                }
            });
    
            // Cancel the subscription
            subscriptionHandler.cancel();
        }
    }
No Headings