Playing Video

Seamlessly switching between web apps and streaming video

The Senza platform has two modes:

  1. It can use a web browser in the cloud to run HTML5 apps with rich content, including video.
  2. It can stream the video directly, without the need to consume the resources required for a web browser. 

If your web app plays a video fullscreen, Senza can seamlessly switch between these two modes. This gives you the power to use web technologies whenever you want to, and the efficiency of streaming directly to the client when you don't need them.

This app implements the Reference Integration for the client library.

See the Remote Player documentation for more details.

Banner

For this demo, we'll add a "Welcome to Senza" banner that displays on top of the video. 

  1. When we want to show the banner, we'll switch to foreground mode to see the browser.
  2. When we want to hide the banner, we'll switch to background mode and stream the video.

Code

We can start with some HTML in index.html :

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="main">
  <video id="video" width="1920" height="1080" muted="muted"></video>
   <div id="banner">
     Welcome to Senza
   </div>
</div>
</body>
<script  type="text/javascript" src="./dist/bundle.js"></script>
</html>

And a little bit of CSS in styles.css to make our banner look pretty:

@font-face {
  font-family: Montserrat;
  src: url(https://fonts.gstatic.com/s/montserrat/v26/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2);
}

body {
  width: 1920px;
  height: 1080px;
	margin: 0px;
	background-color: black;
  overflow: hidden;
}
  
#main {
  position: relative;
  width: 1920px;
  height: 1080px;
	background-color: white;
  text-align: center;
}

#banner {
  position: absolute;
  width: 1800px;
  height: 175px;
  top: 800px;
  left: 60px;
  color: white;
  padding-top: 45px;
  font: 80pt Montserrat;
  font-weight: 500;
  background-color: black;
  background-image: url("images/gradient.jpg");
  filter: drop-shadow(0px 10px 15px black);
  border-radius: 20px;
  z-index: 2;
  opacity: 0.9;
}

Then create a index.js file for your script.

Webpack

We're going to use webpack to transpile all your scripts, including the client library, into one bundle.
First, make sure you have installed Node.js and the Client Library.

Create a package.json file like this:

{
  "name": "banner",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.72.1",
    "webpack-cli": "^4.9.2"
  },
  "dependencies": {
    "senza-sdk": "^3.19.10",
    "shaka-player": "^3.2.9"
  }
}

And a webpack.config.js file like this:

const path = require("path");
 
module.exports = {
    entry: ["./index.js"],
    mode: "development",
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.js"
    }
};

Run the following commands once to download the required node modules. This will create a node_modules folder and a package-lock.json file.

npm install
npm ci

Now each time you make changes to the banner.js file, run the webpack command to update the bundle.js file in the dist folder:

npx webpack -w --config webpack.config.js

The -wflag tells the command to stay running, and it will continuously watch your code for changes. That way you don't have to run the command each time you modify your code.

You'll want to load the page using your local web server. See viewing your app with Senza for details, as well as instructions on how to turn on your local web server.

When you load the page you'll see the banner on top of the video.

UnitedPlayer

We're going to use a class called UnfiedPlayer to help us play video on Senza. It provides a layer of abstraction that makes the two players work together as one:

  • The local player, a video element from your web page that you pass to the UnifiedPlayer when you create it.
  • The Remote Player, a class from the Senza client library that manages video streaming to the cloud connector.

The UnifiedPlayer class is designed to expose the same interface as a typical video player such as Shaka, for example to load and play videos. It also lets you switch between the two players, and handles the timecode synchronization for you. See the Reference Integration page for more details.

Playing video with Senza

Now for the fun part! We're going to use the Senza client library to set up both local and remote video playback of our favorite bunny video. Let's add some more code to index.js.

First, import the things we'll need from the Senza library, as well as the Shaka player. Also define a constant with the URL for our video resource.

import { init, uiReady } from "senza-sdk";
import { UnifiedPlayer } from "./unifiedPlayer.js";

const TEST_VIDEO = "https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd";

let unifiedPlayer;

When the page loads, we'll call the init() function from the client library and wait for it to complete. We'll create an instance of UnifiedPlayer with our video tag. Then we'll tell the player to start playing the video.

When we're all done, we'll call the Hyperscale library's uiReady() function to let it know that we're all done with the initial setup and the user interface is ready.

window.addEventListener("load", async () => {
  try {
    await init();
    unifiedPlayer = new UnifiedPlayer(video);
    await unifiedPlayer.load(TEST_VIDEO);
    unifiedPlayer.play();
    uiReady();
  } catch (error) {
    console.error(error);
  }
});

Then we can listen for button presses on the remote control.

document.addEventListener("keydown", async function (event) {
  switch (event.key) {
    case "Enter": await togglePlayback(); break;
    case "Escape": playPause(); break;
    case "ArrowLeft": skip(-30); break;
    case "ArrowRight": skip(30); break;
    default: return;
  }
  event.preventDefault();
});

The remote control buttons will do the following:

  • The OK button (enter key) will toggle between foreground and background modes. When the app is in the foreground the video plays in the local player, and when it is in the background the video plays in the remote player.
  • The back button (escape key) will pause or play the video.
  • The left and right arrow keys will skip backwards and forwards by 30 seconds.

Here are a few helper functions that we'll use to toggle back and forth between different states:

async function togglePlayback() {
  if (unifiedPlayer.sInRemotePlayback) {
    await unifiedPlayer.moveToLocalPlayback();
  } else {
    unifiedPlayer.moveToRemotePlayback();
  }
}

function playPause() {
  if (unifiedPlayer.paused) {
    unifiedPlayer.play();
  } else {
    unifiedPlayer.pause();
  }
}

function skip(seconds) {
  unifiedPlayer.currentTime = unifiedPlayer.currentTime + seconds;
}

That's really about it for the implementation of the app! Most of the details are handled by the UnfiedPlayer. See the Reference Integration page for more details on the implementation.

Try it out

Try viewing your app in the device simulator or on a cloud connector device to see how it works! When you load the page you'll see the video start playing. Try pressing OK to toggle between foreground and background modes, back to pause or play the video, left to skip backwards, and right to skip forwards.

Conclusion

That's it! You've learned in this demo how easy it can be to play video in the local player using the web browser, to stream the video directly to the device using the local player, and to switch back and forth.


What’s Next