Custom DRM Player with Dash.js for Samsung Tizen TV
Posted By : Prahalad Singh Ranawat | 31-Jan-2025
Overview
Digital Rights Management (DRM) is crucial for protecting premium content in streaming applications. Samsung Tizen TV supports DRM playback using AVPlay or custom implementations with Dash.js. In this guide, we will implement a DRM-enabled player using Dash.js and integrate remote key handling for seamless navigation on a Tizen web application.
Step 1: Setting Up the Basic HTML Player Screen
First, create a player screen in player.html
to display video playback.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>YourTV</title>
<script src="../js/dash.min.js"></script>
<link rel="stylesheet" href="player.css">
</head>
<body>
<!-- Expire Session -->
<!-- <div id="sessionExpirePopup" class="popup-overlay">
<div class="popup-content">
<p>Session expired. Please log in again.</p>
<button id="okButton">OK</button>
</div>
</div> -->
<!-- No Internet -->
<div id="no-internet-popup">
<img src="../images/no-wifi.png" class="no-wifi-icon" alt="no-wifi">
<h1>No Internet Connection</h1>
<button id="retry-button" class="retry-wifi-btn">Retry</button>
</div>
<!-- END No Internet -->
<video id="videoPlayer" type="video/mp4"></video>
<img src="../images/logo 5.png" alt="logo" class="logo-watermark">
<div id="playPauseIcon" class="icon-container">
<img src="../images/Icons/play-icon.png" id="playImage" alt="Play">
<img src="../images/Icons/pause-icon.png" id="pauseImage" alt="Pause" style="display: none;">
</div>
<script src="player.js"></script>
<script src="../js/no-internet.js"></script>
</body>
</html>
Step 2: Implementing DRM Playback in player.js
Next, set up Dash.js to handle DRM-protected content and remote key.
const remoteKeys = { LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, RETURN: 10009, ENTER: 13 };
let player;
let videoElement = document.querySelector("#videoPlayer");
let playPauseIcon = document.querySelector("#playPauseIcon");
let playImage = document.querySelector("#playImage");
let pauseImage = document.querySelector("#pauseImage");
let hideIconTimeout;
// Popup elements
let noInternetPopup = document.querySelector("#noInternetPopup");
let retryButton = document.querySelector("#retryButton");
(function() {
const streamUrl = localStorage.getItem("channelUrl");
const drmData = localStorage.getItem("drmData");
const widevinelicense = localStorage.getItem("widevinelicense");
console.log("streamUrl", streamUrl);
console.log("drmData", drmData);
console.log("widevinelicense", widevinelicense);
player = dashjs.MediaPlayer().create();
if (streamUrl) {
player.initialize(videoElement, streamUrl, true);
if (drmData || widevinelicense) {
player.setProtectionData({
"com.widevine.alpha": {
serverURL: "https://widevine.keyos.com/api/v4/getLicense",
httpRequestHeaders: { customdata: drmData }
},
"com.microsoft.playready": {
serverURL: "https://playready.keyos.com/api/v4/getLicense",
httpRequestHeaders: { customdata: drmData }
}
});
}
}
})();
// Function to show play/pause icon
function showPlayPauseIcon(isPlaying) {
clearTimeout(hideIconTimeout);
playPauseIcon.style.display = "block";
// Toggle between play and pause icons
if (isPlaying) {
playImage.style.display = "none";
pauseImage.style.display = "block";
} else {
playImage.style.display = "block";
pauseImage.style.display = "none";
}
// Hide the icon after 2 seconds
hideIconTimeout = setTimeout(() => {
playPauseIcon.style.display = "none";
}, 2000);
}
// Function to show no internet popup
function showNoInternetPopup() {
noInternetPopup.style.display = "block";
retryButton.focus();
}
// Function to hide no internet popup
function hideNoInternetPopup() {
noInternetPopup.style.display = "none";
}
// Remote key event handling
document.addEventListener("keydown", (event) => {
const popup = document.querySelector("#no-internet-popup");
// Check if the No Internet popup is visible
if (popup && popup.style.display === "block") {
if (event.key === 'Enter') {
retryConnection();
// Hide the popup if internet is restored
setTimeout(() => {
if (!localStorage.getItem("no_internet")) {
toggleNoInternetPopup(false);
}
}, 500);
}
// Prevent further actions if No Internet popup is visible
return;
}
// Normal key handling if internet is available
switch (event.keyCode) {
case remoteKeys.RIGHT:
console.log("Right key pressed");
break;
case remoteKeys.LEFT:
console.log("Left key pressed");
break;
case remoteKeys.DOWN:
console.log("Down key pressed");
break;
case remoteKeys.UP:
console.log("Up key pressed");
break;
case remoteKeys.ENTER:
if (videoElement.paused) {
player.play();
console.log("Video playing via Enter key");
showPlayPauseIcon(true);
} else {
player.pause();
console.log("Video paused via Enter key");
showPlayPauseIcon(false);
}
break;
case remoteKeys.RETURN:
location.href = "../programmeguide/epg.html";
break;
}
});
Step 3: Styling the Player UI (player.css
)
A simple CSS for styling the player screen.
.logo-watermark {
position: absolute !important;top: 15px;left: 0;opacity: .4;width: 12%;
}
#videoPlayer{
width: 100%; height: auto;
position: relative;
}
#bufferingIcon {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #ffc800;
border-radius: 50%;
animation: spin 1s linear infinite;
z-index: 9999;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Overlay background */
.popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.3s ease-in-out;
}
/* Popup content */
.popup-content {
background-color: rgb(0 35 96);
color: white;
padding: 60px;
border-radius: 8px;
text-align: center;
font-size: 28px;
font-weight: 900;
width: 500px;
box-shadow: 0px 4px 6px rgb(0 0 0 / 30%);
}
.popup-content button {
background-color: #ffc800;
color: #000;
border: none;
padding: 10px 20px;
font-size: 20px;
border-radius: 5px;
cursor: pointer;
margin-top: 15px;
}
/* Show popup */
.popup-overlay.show {
visibility: visible;
opacity: 1;
}
/* Centered icon container */
.icon-container {
position: absolute;
z-index: 99999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
}
.icon-container img {
width: 80px;
height: 80px;
}
Conclusion
You now have a working DRM-enabled player using Dash.js for Samsung Tizen TV, complete with remote key navigation. For more advanced features like dynamic channel switching and UI enhancements, explore the full capabilities of Tizen's AVPlay API.
For a complete guide on building a Samsung Tizen TV EPG with remote navigation, check out this blog.
Need help with your Tizen project? Contact us to discuss your requirements!
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
Prahalad Singh Ranawat
Prahalad Singh Ranawat is a highly skilled backend developer with extensive experience in PHP, Laravel, Magento, Headless Magento, RESTful API, Node.js, and Vue.js. He also possesses knowledge in Shopify. Prahalad has a solid background in working with Postman, Swagger, Git, MySQL, MongoDB, and the LAMP stack. With his passion for learning and creativity, he is constantly exploring new technologies to enhance his skills. He has provided DevOps support and contributed his expertise to a range of projects, including Yumi Paws, OACustomer-Dashboard, Vlad Application, Information Sharing Website, Eating Disorder Intervention, TRO Platform, and SimplyNoted.