Stream Saver

Show a video screensaver after a period of inactivity.

Senza apps operate in two modes:

  1. Foreground mode, in which the viewer interacts with the web browser using the remote control.
  2. Background mode, in which video streams directly to the cloud connector.

Usage is metered according to how much time the web browser is running. However, if the viewer stops interacting with your app, it may continue running in foreground mode indefinitely. To avoid this situation, we can just switch to background mode by playing a video after a period of inactivity.

The app will show a countdown from 30 seconds. If the viewer presses any button on the remote, it will reset the countdown back to 30. If the countdown gets to zero, it will switch to playing a video. If the viewer presses any button again, it will switch back to showing the countdown.

App

We'll show a countdown composed of some image files with glowing numbers. The HTML will just have a main div with two img elements that we can update as the numbers change.

<!DOCTYPE html>
<html>
<head>
  <title>Stream Saver</title>
	<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="main">
	<img id="number10" src="digits/3.jpg"><img id="number1" src="digits/0.jpg">
</div>
</body>
<script src="https://senza-sdk.streaming.synamedia.com/latest/bundle.js"></script>
<script type="text/javascript" src="streamSaver.js"></script>
</html>

The CSS styles will be pretty simple:

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

#number10, #number1 {
  margin-top: 200px;
  width: 400px;
  height: 680px;
}

Script

In our JavaScript file, we'll start with some constants. We'll show the video stream in the link after a given number of seconds of inactivity.

const STREAM_SAVER_VIDEO = "https://d1pam9p7j3k6m8.cloudfront.net/streamsaver/hyperscale_1/dash/index.mpd";
const STREAM_SAVER_SECONDS = 30;

We'll call a function called countdown() when the app first loads, as well as whenever the video is finished playing in the remote player.

We also preload the screensaver video in the remote player when the app loads, since that is the only thing that this sample app plays. If you'll be playing other videos requested by the user, you'll want to load the screensaver video in the remote player just before you need it instead.

window.addEventListener("load", async () => {
  try {
    await senza.init();

    countdown();

    senza.remotePlayer.addEventListener("ended", () => {
      senza.lifecycle.moveToForeground();
      countdown();
    });

    await senza.remotePlayer.load(STREAM_SAVER_VIDEO);
    senza.uiReady();
  } catch (error) {
    console.error(error);
  }
});

If the viewer presses any key on the remote, we'll reset the countdown() again. We also move back to foreground mode if we were in the background.

document.addEventListener("keydown", async (event) => {
  const currentState = await senza.lifecycle.getState();
  if (currentState == "background" || currentState == "inTransitionToBackground") {
    senza.lifecycle.moveToForeground();
  }
	countdown();
  event.preventDefault();
});

Our countdown() function works with an interval set up by the setInterval() function. It counts down from 30 seconds, updating the displayed number, and then plays the video. If called repeatedly, it will clear the interval and start over.

let interval = null;
function countdown() {
  clearInterval(interval);
  let counter = STREAM_SAVER_SECONDS;
  showNumber(counter);
  
  interval = setInterval(() => {
    counter--;
    showNumber(counter);

    if (counter == 0) {
      clearInterval(interval);
      showStreamSaver();
    }
  }, 1000);
}

function showStreamSaver() {
  senza.remotePlayer.currentTime = 0;
  senza.remotePlayer.play();
}

The showNumber() function just displays the digits for the two digit number as images. Due to JavaScript's somewhat inaccurate way of doing integer division, we'll floor() the tens digit and round() the ones digit.

We'll also preload the image files to avoid any irregularity in displaying the countdown due to the time it takes to load the image for each digit.

function showNumber(counter) {
  let ten = Math.floor(counter / 10);
  let one = Math.round(counter % 10);
  number10.src = `digits/${ten}.jpg`;
  number1.src = `digits/${one}.jpg`;
}

function preloadImages() {
  for (let i = 0; i < 10; i++) {
    let img = new Image();
    img.src = `digits/${i}.jpg`;
  }
}

preloadImages()

Conclusion

In this tutorial we've learned how to show a video after a period of inactivity in order to save resources. In a production app, you can choose a timeout period that works for your interaction mode, and of course you wouldn't need to show the countdown to the viewer.

Coming soon, we will be introducing a feature that lets you put the browser to sleep without playing a video, freezing the most recent image generated by the browser. This will give you the benefit of saving resources consumed by the browser without using bandwidth to play a video. Then it will be your choice during periods of inactivity whether you want to play a video or just freeze the browser image.


What’s Next