Playing DRM Content

webOS TV provides DRM service to support DRM content playback. DRM service manages DRM client which holds a certain 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 License Server (Widevine) or from DRM client (PlayReady, Verimatrix).


webOS TV supports the following DRM types:

Widevine

On Widevine DRM playback, DRM Client only holds credential information. Media Pipeline gets the credential information from DRM client and requests key from DRM License Server with the credential information. Media Pipeline uses the returned key for decryption. The following diagram shows the operation flow of Widevine DRM content playback.

Widevine_Structure.png

The following introduces each component of the above diagram:

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

  • Web App
    Web App requests Media Pipeline to play DRM content and sends DRM message (credential information) to DRM client.

  • DRM Client
    DRM Client only holds credential information.

  • Media Pipeline
    Media Pipeline gets the credential information from DRM Client and requests the key from DRM License Server. After getting the license key, Media Pipeline decrypts and plays DRM Content.

  • Content Server
    Content Server stores and publishes DRM content.

  • License Server
    License Server manages rights and returns key for decryption.

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

Widevine_Sequence_Diagram.png

Widevine DRM playback sequence is described as below:

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

  2. DRM Service creates DRM Client instance and returns its ID to Web App with a callback function.

  3. Web App uses sendDrmMessage() method to give a DRM message to DRM client. DRM message holds credential information in DRM message format.

  4. DRM client verifies DRM message and returns the result to Web App with a callback function.

  5. Web App gives a content target, DRM Client ID, and playback options to Media Pipeline with video element and mediaOption Parameter.

  6. Media Pipeline gets the credential information from DRM Client.

  7. Media Pipeline gets the license key from the license server. Media Pipeline requests it with credential information.

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

  9. DRM Client must be removed with unload() method before unloading app.

You must unload DRM Client before:

  • Terminating app

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

To play Widevine DRM content, you need to use LS API of DRM Service and mediaOption parameter. You can play Widevine 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 load() method when the app is loaded.

var appId = "com.yourdomain.yourapp";

// Define DRM Type
var drmType = "widevine";
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 DRM message (credential information) with sendDrmMessage() method.

var msgId;

// Message format for widevine
var msg = '<?xml version="1.0" encoding="utf-8"?>
<WidevineCredentialsInfo xmlns="http://www.smarttv-alliance.org/DRM/widevine/2012/protocols/">
    <ContentURL>http://example.org/examplePath/example.vob</ContentURL>
    <DeviceID>ab-cd-ef-01-02-03</DeviceID>
    <StreamID>123abc-ab12-1234-abcd-abc123</StreamID>
    <ClientIP>Sample</ClientIP>
    <DRMServerURL>https://drmserver.example.org/drmserver.cgi</DRMServerURL>
    <DRMAckServerURL>https://ackserver.example.org/ack.cgi</DRMAckServerURL>
    <DRMHeartBeatURL>https://heartbeat.example.org/heartbeat.cgi</DRMHeartBeatURL>
    <DRMHeartBeatPeriod>120</DRMHeartBeatPeriod>
    <UserData>SampleUserData</UserData>
    <Portal>Sample (e.g. company name)</Portal>
    <StoreFront>Sample (e.g. company name)</StoreFront>
    <BandwidthCheckURL>none</BandwidthCheckURL>
    <BandwidthCheckInterval>none</BandwidthCheckInterval>
</WidevineCredentialsInfo >'

// Message type for widevine
var msgType = "application/widevine+xml";

// Unique ID of DRM system
var drmSystemId = "urn:dvb:casystemid:19156";

function sendRightInformation() {
    var request = webOS.service.request("luna://com.webos.service.drm", { 
        method:"sendDrmMessage", 
        parameters: {
            "clientId": clientId,
            "msgType": msgType,
            "msg": msg,
            "drmSystemId": drmSystemId
        }, 
        onSuccess: function (result) {
            // DRM API does not return the msgId, resultCode, resultMsg for Widevine type.
            console.log("sendDrmMessage succeeded");
        },
        onFailure: function (result) {
            console.log("[" + result.errorCode + "] " + result.errorText);
        }
    });
}

You should do:

  • Even if you do not use the optional elements, you must specify the elements with an empty value.
  • You should keep the order of XML elements in the Widevine message as above example.

For more detailed information, see the DRM Message.

4. Create an object for mediaOption of video element and set the playback options.

// HTML code
<video id="myVideo" ...> </video>

// JavaScript code
var options = {};
options.mediaTransportType = "WIDEVINE";
options.option = {};
options.option.drm = {};
options.option.drm.type = drmType;
options.option.drm.clientId = clientId;

5. Convert the created object to JSON string and encode it.

var mediaOption = encodeURIComponent(JSON.stringify(options));

6. Create the source element.

var source = document.createElement("source");

7. 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);

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

video = document.getElementById('myVideo');
video.appendChild(source);

9. Call unload() method before terminating 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
            }  
        });
    }
}

PlayReady

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

PlayReady_Structure.png

The following introduces each component of the above diagram:

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

  • Web App
    Web App requests Media Pipeline to play DRM content and sends DRM message (initiator information) to DRM client.

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

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

  • Content Server
    Content Server stores and publishes DRM content.

  • License Server
    License Server manages rights and returns key for decryption.

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

PlayReady_Sequence_Diagram.png

PlayReady DRM playback sequence is described as below:

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

  2. DRM Service creates DRM Client instance and returns its ID to Web App with a callback function.

  3. Web App uses sendDrmMessage() method to give a DRM message to DRM client. DRM message holds initiator information in DRM message format.

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

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

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

  7. Web App gives a content target, DRM Client ID, and playback options to Media Pipeline with video element and mediaOption Parameter.

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

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

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

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

Licensing error message is broadcasted to every subscribed app. Web app needs to check valid message with msgId which is given by sendDrmMessage() method.

You must unload DRM Client before:

  • Terminating app

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

To play PlayReady DRM content, you need to use LS API of 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 load() method when the 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 DRM message (initiator information) with 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);
        }
    });
}

For more details on DRM message, see the DRM Message.

4. Subscribe licensing error message with 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 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);

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

video = document.getElementById('myVideo');
video.appendChild(source);

10. Call unload() method and cancel the subscription before terminating 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();
    }
}

Verimatrix

On Verimatrix DRM, DRM Client requests a key from DRM license server with the VCAS configuration directly. Media Pipeline gets the license key from DRM Client. The following diagram shows the operation flow of Verimatrix DRM content playback.

Verimatrix_Structure.png

 

The following introduces each component of the above diagram:

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

  • Web App
    Web App requests Media Pipeline to play DRM content and sends DRM message (VCAS configuration) to DRM client.

  • DRM Client
    DRM Client holds VCAS configuration and gets the license key from License Server.

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

  • Content Server
    Content Server stores and publishes DRM content.

  • License Server
    License Server manages rights and returns key for decryption.

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

Verimatrix_Sequence_Diagram.png

Verimatrix DRM playback sequence is described as below:

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

  2. DRM Service creates DRM Client instance and returns its ID to Web App with a callback function.

  3. Web App uses sendDrmMessage() method to give a DRM message to DRM client. DRM message holds VCAS configuration in DRM message format.

  4. DRM client verifies DRM message and returns the result to Web App with a callback function.

  5. Web App gives a content target, DRM Client ID, and playback options to Media Pipeline with video element and mediaOption Parameter.

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

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

  8. DRM Client must be removed with unload() method before unloading app.

You must unload DRM Client before:

  • Terminating app

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

To play Verimatrix DRM content, you need to use LS API of DRM Service and mediaOption parameter. You can play Verimatrix 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 load() method when the app is loaded.

var appId = "com.yourdomain.yourapp";
 
// Define DRM Type
var drmType = "viewright_web";
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 DRM message (VCAS configuration) with sendDrmMessage() method.

var msgId;

// Message format for Verimatrix
var msg = '{"company_name":"Verimatrix", "vcas_boot_address":"public-ott.verimatrix.com"}';
 
// Message type for Verimatrix
var msgType = "json";
 
// Unique ID of DRM system
var drmSystemId = "0x5601";
 
function sendRightInformation() {
    var request = webOS.service.request("luna://com.webos.service.drm", { 
        method:"sendDrmMessage", 
        parameters: {
            "clientId": clientId,
            "msgType": msgType,
            "msg": msg,
            "drmSystemId": drmSystemId
        }, 
        onSuccess: function (result) {
            // DRM API does not return the msgId, resultCode, resultMsg for Verimatrix type.
            console.log("sendDrmMessage succeeded");
        },
        onFailure: function (result) {
            console.log("[" + result.errorCode + "] " + result.errorText);
        }
    });
}

For more details on DRM message, see the DRM Message.

4.Create an object for mediaOption of 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 = "verimatrix";
options.option.drm.clientId = clientId;

5. Convert the created object to JSON string and encode it.

var mediaOption = encodeURIComponent(JSON.stringify(options));

6. Create the source element.

var source = document.createElement("source");

7. 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.m3u8";
source.setAttribute('src', dataURL);
source.setAttribute('type', 'application/x-mpegurl;mediaOption=' + mediaOption);

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

video = document.getElementById('myVideo');
video.appendChild(source);

9. Call unload() method before terminating 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
            }    
        });
    }
}

Navigation