如何使用本机 WebOS 播放器播放 DRM 内容
How to play DRM content using native WebOS player
我们正在尝试使用本机 WebOS 播放器和 com.webos.service.drm 服务播放视频内容。目标是至少播放一些 DRM 内容(dash+widevine 或 hls+widevine)。清除内容工作正常,但 DRM 内容完全卡住,并且没有出现诊断消息。
同样的结果发生在 WebOS 3.4、4.4 和 6.0 上。是否有任何 DRM 内容播放的工作示例?
我们的代码如下。
var appId = "com.zodiac.app";
// Define DRM Type
var drmType = "widevine";
function webos_request(service, params)
{
var caller = arguments.callee.caller.name;
console.log("REQ: %s: %s %s", caller, service, JSON.stringify(params))
return new Promise( function(resolve, reject) {
webOS.service.request(service, Object.assign({}, params, {
onSuccess: function (result) { console.log("REQ SUCCESS: %s: %s %s: %s", caller, service, params.method, JSON.stringify(result)); resolve(result) },
// onFailure: function (result) {
// console.log("[" + result.errorCode + "] " + result.errorText);
// reject()
// }
onFailure: function (result) { console.error("REQ ERROR: %s: %s %s: %s", caller, service, params.method, JSON.stringify(result)); reject(result) }
}))
});
}
function webos_subscribe(service, params, method)
{
var caller = arguments.callee.caller.name;
var completed = false
return new Promise( function(resolve, reject) {
params.parameters = params.parameters || {}
params.parameters.subscribe = true;
console.log("SUB: %s: %s %s", caller, service, JSON.stringify(params))
webOS.service.request("luna://com.webos.service.drm", Object.assign({}, params, {
onSuccess: function (result) { // Subscription Callback
if (!completed) {
completed = true;
if (result.subscribed) {
console.log("SUB: %s: %s: SUCCESS", caller, service)
resolve(result)
}
else {
console.error("SUB: %s: %s: FAILED", caller, service)
reject();
}
}
else
method(result)
},
onFailure: function (result) {
console.error("SUB: %s: %s: onFailure", caller, service, result)
// console.log('Player.subscribeLicensingError onFailure: ' + '[' + result.errorCode + '] ' + result.errorText);
completed = true;
reject()
}
}));
});
}
function unloadDrmClient(clientId)
{
webos_request("luna://com.webos.service.drm",
{
method:"unload",
parameters: {
"clientId": result.clientId
}
});
}
function loadDrmClient()
{
return webos_request( "luna://com.webos.service.drm", {
method:"load",
parameters: {
"drmType": drmType,
"appId": appId
}})
.then(function (result) {
console.log("DRM Client is loaded successfully. %s", JSON.stringify(result));
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
unloadDrmClient(result.clientId)
}
})
return result.clientId
})
}
function sendRightInformation(clientId, url, la_url) {
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>' + url + '</ContentURL>',
'<DeviceID></DeviceID>',
'<StreamID></StreamID>',
'<ClientIP></ClientIP>',
'<DRMServerURL>' + la_url + '</DRMServerURL>',
'<DRMAckServerURL></DRMAckServerURL>',
'<DRMHeartBeatURL></DRMHeartBeatURL>',
'<DRMHeartBeatPeriod>0</DRMHeartBeatPeriod>',
'<UserData></UserData>',
'<Portal></Portal>',
'<StoreFront></StoreFront>',
'<BandwidthCheckURL></BandwidthCheckURL>',
'<BandwidthCheckInterval></BandwidthCheckInterval>',
'</WidevineCredentialsInfo>',
].join("")
// Message type for widevine
var msgType = "application/widevine+xml";
// Unique ID of DRM system
var drmSystemId = "urn:dvb:casystemid:19156";
return webos_request( "luna://com.webos.service.drm", {
method:"sendDrmMessage",
parameters: {
"clientId": clientId,
"msgType": msgType,
"msg": msg,
"drmSystemId": drmSystemId
}})
.then( function (result) {
// DRM API does not return the msgId, resultCode, resultMsg for Widevine type.
console.log("sendDrmMessage succeeded. %s", JSON.stringify(result));
return
});
}
function subscribeLicensingError(clientId, msgId)
{
return webos_subscribe("luna://com.webos.service.drm", {
method:"getRightsError",
parameters: {
"clientId": clientId
}},
function (result) { // Subscription Callback
var 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
}
else {
console.log("Unknown errorState: %s", JSON.stringify(result));
}
}
else {
console.log("skip notification %s", JSON.stringify(result));
}
});
}
var video = document.getElementById('myVideo');
function playback()
{
var config = {
'dash+wv': {
type: "application/dash+xml",
mediaTransportType: "WIDEVINE",
url: 'https://bitmovin-a.akamaihd.net/content/art-of-motion_drm/mpds/11331.mpd',
la_url: 'https://widevine-proxy.appspot.com/proxy'
},
'hls+wv': {
type: "application/x-mpegURL",
mediaTransportType: "HLS",
url: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine-hls/hls.m3u8',
la_url: 'https://cwip-shaka-proxy.appspot.com/no_auth'
},
'mp4': {
type: "video/mp4",
url: "https://jsoncompare.org/LearningContainer/SampleFiles/Video/MP4/Sample-MP4-Video-File-Download.mp4"
},
'hls': {
type: "application/vnd.apple.mpegurl",
url: "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8",
},
'dash': {
type: "application/dash+xml",
url: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd'
}
}
var stream = config['hls+wv']
var prepare
if (stream.la_url) {
prepare = loadDrmClient()
.then( function(id) {
subscribeLicensingError(id, undefined);
document.body.addEventListener("unload", function() {
webOS.service.request("luna://com.webos.service.drm", {
method:"unload",
parameters: { "clientId": id },
onSuccess: function (result) {
console.log("DRM Client is unloaded successfully.");
},
onFailure: function (result) {
console.log("[" + result.errorCode + "] " + result.errorText);
// Do something for error handling
}
});
})
return sendRightInformation(id, stream.url, stream.la_url).then( function () { return id; })
})
}
else {
prepare = Promise.resolve()
}
return prepare.then( function (id) {
var type = stream.type
if (stream.la_url) {
var options = {
mediaTransportType: stream.mediaTransportType,
option: {
drm: {
type: drmType,
clientId: id,
}
}
};
console.log("Options: %s", JSON.stringify(options));
var mediaOption = encodeURIComponent(JSON.stringify(options));
type += ';mediaOption=' + mediaOption;
}
console.log("open url: %s", stream.url)
console.log("type : %s", type)
var source = document.createElement("source");
source.setAttribute('src', stream.url);
source.setAttribute('type', type);
video.addEventListener('loadedmetadata', function(event) {
console.log("loadedmetadata %O", event)
});
video.addEventListener('error', function(e) {
console.error('error', e);
});
video.addEventListener('stalled', function(e) {
console.log('stalled', e);
});
video.addEventListener('loadeddata', function() {
console.log('[Device_Webos_Player] loadeddata');
});
video.addEventListener('loadedmetadata', function() {
console.log('[Device_Webos_Player] loadedmetadata');
});
video.addEventListener('canplay', function () {
console.log('[Device_Webos_Player] canplay');
});
video.addEventListener('durationchange', function() {
console.log('[Device_Webos_Player] durationchange: ' + video.duration);
});
video.addEventListener('timeupdate', function() {
console.log('[Device_Webos_Player] timeupdate: ' + video.currentTime);
}, { once: true});
video.appendChild(source);
// video.load()
video.play()
})
}
playback()
我们正在尝试使用本机 WebOS 播放器和 com.webos.service.drm 服务播放视频内容。目标是至少播放一些 DRM 内容(dash+widevine 或 hls+widevine)。清除内容工作正常,但 DRM 内容完全卡住,并且没有出现诊断消息。
同样的结果发生在 WebOS 3.4、4.4 和 6.0 上。是否有任何 DRM 内容播放的工作示例?
我们的代码如下。
var appId = "com.zodiac.app";
// Define DRM Type
var drmType = "widevine";
function webos_request(service, params)
{
var caller = arguments.callee.caller.name;
console.log("REQ: %s: %s %s", caller, service, JSON.stringify(params))
return new Promise( function(resolve, reject) {
webOS.service.request(service, Object.assign({}, params, {
onSuccess: function (result) { console.log("REQ SUCCESS: %s: %s %s: %s", caller, service, params.method, JSON.stringify(result)); resolve(result) },
// onFailure: function (result) {
// console.log("[" + result.errorCode + "] " + result.errorText);
// reject()
// }
onFailure: function (result) { console.error("REQ ERROR: %s: %s %s: %s", caller, service, params.method, JSON.stringify(result)); reject(result) }
}))
});
}
function webos_subscribe(service, params, method)
{
var caller = arguments.callee.caller.name;
var completed = false
return new Promise( function(resolve, reject) {
params.parameters = params.parameters || {}
params.parameters.subscribe = true;
console.log("SUB: %s: %s %s", caller, service, JSON.stringify(params))
webOS.service.request("luna://com.webos.service.drm", Object.assign({}, params, {
onSuccess: function (result) { // Subscription Callback
if (!completed) {
completed = true;
if (result.subscribed) {
console.log("SUB: %s: %s: SUCCESS", caller, service)
resolve(result)
}
else {
console.error("SUB: %s: %s: FAILED", caller, service)
reject();
}
}
else
method(result)
},
onFailure: function (result) {
console.error("SUB: %s: %s: onFailure", caller, service, result)
// console.log('Player.subscribeLicensingError onFailure: ' + '[' + result.errorCode + '] ' + result.errorText);
completed = true;
reject()
}
}));
});
}
function unloadDrmClient(clientId)
{
webos_request("luna://com.webos.service.drm",
{
method:"unload",
parameters: {
"clientId": result.clientId
}
});
}
function loadDrmClient()
{
return webos_request( "luna://com.webos.service.drm", {
method:"load",
parameters: {
"drmType": drmType,
"appId": appId
}})
.then(function (result) {
console.log("DRM Client is loaded successfully. %s", JSON.stringify(result));
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
unloadDrmClient(result.clientId)
}
})
return result.clientId
})
}
function sendRightInformation(clientId, url, la_url) {
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>' + url + '</ContentURL>',
'<DeviceID></DeviceID>',
'<StreamID></StreamID>',
'<ClientIP></ClientIP>',
'<DRMServerURL>' + la_url + '</DRMServerURL>',
'<DRMAckServerURL></DRMAckServerURL>',
'<DRMHeartBeatURL></DRMHeartBeatURL>',
'<DRMHeartBeatPeriod>0</DRMHeartBeatPeriod>',
'<UserData></UserData>',
'<Portal></Portal>',
'<StoreFront></StoreFront>',
'<BandwidthCheckURL></BandwidthCheckURL>',
'<BandwidthCheckInterval></BandwidthCheckInterval>',
'</WidevineCredentialsInfo>',
].join("")
// Message type for widevine
var msgType = "application/widevine+xml";
// Unique ID of DRM system
var drmSystemId = "urn:dvb:casystemid:19156";
return webos_request( "luna://com.webos.service.drm", {
method:"sendDrmMessage",
parameters: {
"clientId": clientId,
"msgType": msgType,
"msg": msg,
"drmSystemId": drmSystemId
}})
.then( function (result) {
// DRM API does not return the msgId, resultCode, resultMsg for Widevine type.
console.log("sendDrmMessage succeeded. %s", JSON.stringify(result));
return
});
}
function subscribeLicensingError(clientId, msgId)
{
return webos_subscribe("luna://com.webos.service.drm", {
method:"getRightsError",
parameters: {
"clientId": clientId
}},
function (result) { // Subscription Callback
var 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
}
else {
console.log("Unknown errorState: %s", JSON.stringify(result));
}
}
else {
console.log("skip notification %s", JSON.stringify(result));
}
});
}
var video = document.getElementById('myVideo');
function playback()
{
var config = {
'dash+wv': {
type: "application/dash+xml",
mediaTransportType: "WIDEVINE",
url: 'https://bitmovin-a.akamaihd.net/content/art-of-motion_drm/mpds/11331.mpd',
la_url: 'https://widevine-proxy.appspot.com/proxy'
},
'hls+wv': {
type: "application/x-mpegURL",
mediaTransportType: "HLS",
url: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine-hls/hls.m3u8',
la_url: 'https://cwip-shaka-proxy.appspot.com/no_auth'
},
'mp4': {
type: "video/mp4",
url: "https://jsoncompare.org/LearningContainer/SampleFiles/Video/MP4/Sample-MP4-Video-File-Download.mp4"
},
'hls': {
type: "application/vnd.apple.mpegurl",
url: "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8",
},
'dash': {
type: "application/dash+xml",
url: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd'
}
}
var stream = config['hls+wv']
var prepare
if (stream.la_url) {
prepare = loadDrmClient()
.then( function(id) {
subscribeLicensingError(id, undefined);
document.body.addEventListener("unload", function() {
webOS.service.request("luna://com.webos.service.drm", {
method:"unload",
parameters: { "clientId": id },
onSuccess: function (result) {
console.log("DRM Client is unloaded successfully.");
},
onFailure: function (result) {
console.log("[" + result.errorCode + "] " + result.errorText);
// Do something for error handling
}
});
})
return sendRightInformation(id, stream.url, stream.la_url).then( function () { return id; })
})
}
else {
prepare = Promise.resolve()
}
return prepare.then( function (id) {
var type = stream.type
if (stream.la_url) {
var options = {
mediaTransportType: stream.mediaTransportType,
option: {
drm: {
type: drmType,
clientId: id,
}
}
};
console.log("Options: %s", JSON.stringify(options));
var mediaOption = encodeURIComponent(JSON.stringify(options));
type += ';mediaOption=' + mediaOption;
}
console.log("open url: %s", stream.url)
console.log("type : %s", type)
var source = document.createElement("source");
source.setAttribute('src', stream.url);
source.setAttribute('type', type);
video.addEventListener('loadedmetadata', function(event) {
console.log("loadedmetadata %O", event)
});
video.addEventListener('error', function(e) {
console.error('error', e);
});
video.addEventListener('stalled', function(e) {
console.log('stalled', e);
});
video.addEventListener('loadeddata', function() {
console.log('[Device_Webos_Player] loadeddata');
});
video.addEventListener('loadedmetadata', function() {
console.log('[Device_Webos_Player] loadedmetadata');
});
video.addEventListener('canplay', function () {
console.log('[Device_Webos_Player] canplay');
});
video.addEventListener('durationchange', function() {
console.log('[Device_Webos_Player] durationchange: ' + video.duration);
});
video.addEventListener('timeupdate', function() {
console.log('[Device_Webos_Player] timeupdate: ' + video.currentTime);
}, { once: true});
video.appendChild(source);
// video.load()
video.play()
})
}
playback()