Screencasting (demo screen, screensharing) already works in Google Chrome. The technology allows capturing a window of the browser itself as well as windows of other applicaitons. For example, you can capture Firefox running in a separate window.

It’s fine, but there is a security issue. In the Chrome browser screencasting is turned off.

To enable screencasting, you need Chrome Desktop Capture API, and this article shows how to do this.

Screencasting extension

To make screencasting work, the user should install your Chrome extension designed specifically for your website (domain).

The very first run of screencasting requires the follows actions from a user:

  1. The user opens the website and clicks Start screensharingyour-own-extension
  2. The user is asked to add the extension for this action. screencasting-extension

The Chrome browsers asks to add the extension in a standard box, where a user can add the extension in just one click. The box notifies the user that the extension can capture the screen.

Your own extension

The next step is creating an extension for your domain. Let’s say your test domain is mysupercat.com. In this case, when creating the extension, you should put the domain name into the code.

Besides, your domain (the website on this domain) must work via HTTPS. Correspondingly, your screencasting page should opens something like this: https://mysupercat.com/screen-sharing.php

The domain and HTTPS are, basically, all you need to create your own extension for screencasting. And you don’t need to purchase SSL certificates. Self-signed certificates will do fine as long as your page does open via HTTPS, even if it’s read and strikethrough:

your-extension-in-chrome

Oh, and you need spare five bucks. This is what you need to pay to become a Chrome developer community.

Let’s conclude. To start creating and testing your own extension you need:

  • domain name
  • HTTPS hosting
  • 5 dollars on your credit card

five-dollars

Publishing the extension

  1. Go to Chrome Developer Dashboard and pay 5 bucks for membership. publishing-the-extension
  2. Prepare a ZIP containing files of the extension.To do this, download 2 files here.

Edit the manifest.json file and put your own:

  • name
  • author
  • description
  • homepage_url

For example:

"Name" : "My cool screen sharing extension",
"Author" : "I am",
"Description" : "The extensions shares screens from my website",
"Homepage_url" : "https://mysupercat.com",
{
  "name" : "Flashphoner Screen Sharing",
  "author": "Flashphoner",
  "version" : "1.4",
  "manifest_version" : 2,
  "minimum_chrome_version": "34",
  "description" : "This Chrome extension is developed for https://flashphoner.com WCS Api to enable screen capture.",
  "homepage_url": "https://flashphoner.com",
  "background": {
    "scripts": ["background-script.js"],
    "persistent": false
  },
  "externally_connectable": {
    "matches": [
      "https://flashphoner.com/*",
      "https://*.flashphoner.com/*",
      "*://localhost/*",
      "*://127.0.0.1/*"
    ]
  },
  "icons": {
    "16": "logo16.png",
    "48": "logo48.png",
    "128": "logo128.png"
  },
  "permissions": [
    "desktopCapture"
  ],
  "web_accessible_resources": [
    "logo48.png"
  ]
}

After that, change icons and substitute your own domain to externally_connectable

"externally_connectable": {
    "matches": [
      "https://mysupercat.com/*",
      "https://*.mysupercat.com/*",
      "*://localhost/*",
      "*://127.0.0.1/*"
    ]
  }

Here’s manifest.json you should end up with:

{
  "name" : "My cool screen sharing extension",
  "author": "I am",
  "version" : "1.0",
  "manifest_version" : 2,
  "minimum_chrome_version": "34",
  "description" : "The extensions shares screens from my website",
  "homepage_url": "https://mysupercat.com",
  "background": {
    "scripts": ["background-script.js"],
    "persistent": false
  },
  "externally_connectable": {
    "matches": [
      "https://mysupercat.com/*",
      "https://*.mysupercat.com/*",
      "*://localhost/*",
      "*://127.0.0.1/*"
    ]
  },
  "icons": {
    "16": "logo16.png",
    "48": "logo48.png",
    "128": "logo128.png"
  },
  "permissions": [
    "desktopCapture"
  ],
  "web_accessible_resources": [
    "logo48.png"
  ]
}

Pack these files to a ZIP archive with all the icons and other pictures. You can read more about icons here. Additional images are discussed here.

Then click Add new item.

publishing-extension

Then, after reading the agreement, upload your ZIP archive

publishing-extension-chrome

After the archive is uploaded, verify everything and save

publishing-extension-in-chrome

Now, you only need to publish the extension from the Dashboard by clicking the Publish button.

clicking-publish-button-in-chrome

The published extension looks like this in the Dashboard:

published-extension-in-dashboard

Done. The extension is packed, published and is available for installing to a browser.

In-line install

Without in-line install, your users would have to open Chrome Store and install your extension from there. Not a big deal, but:

  • This is not very convenient to a user.
  • The user can get lost on the extension installation page and never get back to your page.

In-line installing of an extension is that nifty standard box that allows a user to skip visiting Chrome Store:

in-line-install-chrome-store

To configure in-line install, you should have a control over the domain and hosting specified in the manifest (manifest.json file).

For example, if your domain is mysupercat.com, you will need to pass the standard verification procedure and confirm your ownership of this domain.

To enable in-line install, enable the This item uses in-line install flag on the configuration page of the extension.

in-line-install-configuration-page

Then, you add your own website.

in-line-install-add-your-website

Search Console will open in a new window where you can pass verification.

in-line-install-verification

The next step is to upload the identifier file to your hosting to confirm ownership of your domain / website

in-line-install-upload-identifier-file

Verification is successful.

in-line-install-verification-successful

The verified site is displayed in the list of websites available for this extension, and now you can use in-line installing for the extension

in-line-installing-for-extension

Integrating screencasting to the web page

The extension is read and configured for in-line installing. We only need to embed the code to invoke the extension to the HTML page and test it.

Screencasting in Google Chrome uses WebRTC API. So, to finish this test we need a WebRTC platform.

As a server-side WebRTc platform we will use Web Call Server and Web SDK – a set of API scripts for this server.

1. Create an HTML page for screencasting screen-sharing.html

The page is 16 lines of code looking as follows:

<html>
<head>   
    <script type="text/javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
    <script type="text/javascript" src="screen-sharing.js"></script>   
</head>
<body onload="init_api()">
<h1>Screen Sharing</h1>
<button id="installExtensionButton" type="button">Install Now</button>
<h2>Capture</h2>
<div id="localVideo" style="width: 320px; height: 240px; border: 1px solid;"></div>
<h2>Preview</h2>
<div id="remoteVideo" style="width: 320px; height: 240px; border: 1px solid;"></div>
<button id="publishBtn" type="button">Connect and share screen</button>
<p id="status"></p>
</body>
</html>

Let’s examine it line by line.

1) Load the API in flashphoner.js

<script type="text/javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>

2) Upload the screen-sharing.js script. We will examine it in detail later.

<script type="text/javascript" src="screen-sharing.js"></script>

3) Specify where to look for the screencasting extension.

4) Add a button to execute installing of the extension.

<button id="installExtensionButton" type="button">Install Now</button>

5) Add a div – the localVideo element that will display the captured screen locally

<div id="localVideo" style="width: 320px; height: 240px; border: 1px solid;">&nbsp;</div>

6) Add a div – the remoteVideo element that will act as a player displaying what was received from the server, that is it displays the video stream captured to localVideo and sent to the server.

<div id="remoteVideo" style="width: 320px; height: 240px; border: 1px solid;">&nbsp;</div>

7) The button that initiates screencasting and displays the status of the stream.

<button id="publishBtn" type="button">Connect and share screen</button>

Or page looks like this.

integrating-screencasting-to-the-web-page

2. Create JavaScript code for screencasting screen-sharing.js
The code is available for download here. The code is a couple of screens with 5 main functions.

var SESSION_STATUS = Flashphoner.constants.SESSION_STATUS;
var STREAM_STATUS = Flashphoner.constants.STREAM_STATUS;
var localVideo;
var remoteVideo;
var extensionId = "nlbaajplpmleofphigmgaifhoikjmbkg";
 
function init_page() {
   //init api
   try {
       Flashphoner.init({screenSharingExtensionId: extensionId});
   } catch (e) {
       //can't init
       return;
   }
 
   var interval = setInterval(function () {
       chrome.runtime.sendMessage(extensionId, {type: "isInstalled"}, function (response) {
           if (response) {
               document.getElementById("installExtensionButton").disabled = true;
               clearInterval(interval);
               localVideo = document.getElementById("localVideo");
               remoteVideo = document.getElementById("remoteVideo");
           } else {
               document.getElementById("installExtensionButton").disabled = false;
           }
       });
   }, 500);
 
}
 
function connectAndShareScreen() {
   var url = "wss://wcs5-eu.flashphoner.com:8443";
   console.log("Create new session with url " + url);
   Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
       //session connected, start streaming
       startStreaming(session);
   }).on(SESSION_STATUS.DISCONNECTED, function () {
       setStatus(SESSION_STATUS.DISCONNECTED);
   }).on(SESSION_STATUS.FAILED, function () {
       setStatus(SESSION_STATUS.FAILED);
   });
 
}
 
function startStreaming(session) {
   var streamName = "test123";
   var constraints = {
       video: {
           width: 320,
           height: 240,
           frameRate: 10,
           type: "screen"
       }
   };
   session.createStream({
       name: streamName,
       display: localVideo,
       constraints: constraints
   }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
       setStatus(STREAM_STATUS.PUBLISHING);
       //play preview
       session.createStream({
           name: streamName,
           display: remoteVideo
       }).on(STREAM_STATUS.PLAYING, function (previewStream) {
           //enable stop button
       }).on(STREAM_STATUS.STOPPED, function () {
           publishStream.stop();
       }).on(STREAM_STATUS.FAILED, function () {
           //preview failed, stop publishStream
           if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
               setStatus(STREAM_STATUS.FAILED);
               publishStream.stop();
           }
       }).play();
   }).on(STREAM_STATUS.UNPUBLISHED, function () {
       setStatus(STREAM_STATUS.UNPUBLISHED);
       //enable start button
   }).on(STREAM_STATUS.FAILED, function () {
       setStatus(STREAM_STATUS.FAILED);
   }).publish();
}
 
//show connection or local stream status
function setStatus(status) {
   var statusField = document.getElementById("status");
   statusField.innerHTML = status;
}
 
//install extension
function installExtension() {
   chrome.webstore.install();
}

Let’s examine this code in detail.

1) First, we declare several variables: statuses, localVideo and remoteVideo elements, and extensionId that contains the unique id of the screencasting extension.

var SESSION_STATUS = Flashphoner.constants.SESSION_STATUS;
var STREAM_STATUS = Flashphoner.constants.STREAM_STATUS;
var localVideo;
var remoteVideo;
var extensionId = "nlbaajplpmleofphigmgaifhoikjmbkg";

2) The we send extensionId to the Flashphoner API, as a result the API knows which extension is used for screencasting.

Flashphoner.init({screenSharingExtensionId: extensionId});

3) Periodically we check Chrome and see if the extension is installed. If the extension is installed, we don’t need the Install extension button any more and we can hide it.

chrome.runtime.sendMessage(extensionId, {type: "isInstalled"}, function (response) {...}

4) The connectAndShareScreen function establishes connection to the server, and as soon it does (ESTABLISHED) it begins capturing and sending the video stream by delegating control to the startStreaming function.

function connectAndShareScreen() {
   var url = "wss://wcs5-eu.flashphoner.com:8443";
   console.log("Create new session with url " + url);
   Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
       //session connected, start streaming
       startStreaming(session);
   }).on(SESSION_STATUS.DISCONNECTED, function () {
       setStatus(SESSION_STATUS.DISCONNECTED);
   }).on(SESSION_STATUS.FAILED, function () {
       setStatus(SESSION_STATUS.FAILED);
   });
}

5) Before screencasting starts, we set such stream parameters as video resoultion and FPS.

var constraints = {
       video: {
           width: 320,
           height: 240,
           frameRate: 10,
           type: "screen"
       }
   };

6) Then we create the stream itself and invoke the publish() method. Please note, the stream is named test123

session.createStream({
       name: streamName,
       display: localVideo,
       constraints: constraints
   }).publish();

7) After the test123 stream is successfull sent to the server, the execution is transferred to the handler of the PUBLISHING event.

on(STREAM_STATUS.PUBLISHING, function (publishStream) {...}

8) Now we only need to play the stream in the adjacent div remoteVideo. To do this, we invoke the play() function.

session.createStream({
           name: streamName,
           display: remoteVideo
       }).play();

The page and the script are ready for testing.

Preparing to testing

As a result we have the following files:

  • screen-sharing.html
  • screen-sharing.js
  • flashphoner.js

flashphoner.js is included to Web SDK build. The latest build is available for download here.

In addition to html and js files, we need the rebroadcasting server that accepts a video stream and broadcasts it to all others (in our case – back to the same page).

We use Web Call Server 5 for testing. So, we have several options:

Testing of screencasting follows the below diagram:

testing-screencasting-diagram

The same way we can broadcast the screencasting stream to multiple connected users

screencasting-stream-to-multiple-connected-users

Testing screencasting in Chrome

  1. Open the screen-sharing.html page via HTTPS in Google Chrome testing-screencasting-in-chrome
  2. Click the Install Now button to add the extension using in-line installing testing-screencasting-add-extension
  3. Click Add extension and start screencasting by clicking Connect and share screen. Chrome asks to choose what to capture. This can be a tab or a window of Chrome itself, or another appliciaton. testing-screencasting-connect-share-screen
  4. Click Share and end up enjoying the final result. The screen is captured, sent to the server via WebRTC and returns back when the Preview block displays it. testing-screencasting-WebRTC

Conclusion

Therefore we successfully tested screencasting using a simple test page screen-sharing.html in the Google Chrome browser. The test page contains the extension for screencasting that we published in Chrome Store and installed in one click without opening the Store.

During testing the page operated via the HTTPS protocol and have sent and received video via Web Call Server – a WebRTC media server to broadcast streaming video.

To integrate screencasting to the HTML page we used the flashphoner.js script that is a part of the Web SDK build for the WCS server.

References

Chrome API to capture video from the desktop
Developer Dashboard for Chrome
Minimum code for a screencasting extension
Packing icons to the extension
Packing additional icons to the extension
Download the sample code of screencasting
Installing Web Call Server to your own host
Run WCS on Amazon EC2
Web Call Server 5 demo server
Web Call Server
Web SDK