Screencasting in Chrome
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 applications. 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 following actions from a user:
- The user opens the website and clicks Start screensharing.
- The user is asked to add the extension for this action.
The Chrome browser 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 open 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:
Oh, and you need to 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
Publishing the Extension
- Go to Chrome Developer Dashboard and pay 5 bucks for membership.
- 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
http://flashphoner.com WCS Api to enable screen capture.",
"homepage_url": "http://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"
]
}
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.
Then, after reading the agreement, upload your ZIP archive.
After the archive is uploaded, verify everything and save.
Now, you only need to publish the extension from the Dashboard by clicking the Publish button.
The published extension looks like this in the 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:
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.
Then, you add your own website.
Search Console will open in a new window where you can pass verification.
The next step is to upload the identifier file to your hosting to confirm ownership of your domain / website.
Verification is 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.
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.
- Create an HTML page for screencasting screen-sharing.html. The page is 20 lines of code that looks as follows:
<p><title></p>
<h1>Screen Sharing</h1>
<p>Install Now</p>
<h2>Capture</h2>
<div id="localVideo" style="width: 320px; height: 240px"> </div>
<h2>Preview</h2>
<div id="remoteVideo" style="width: 320px; height: 240px"> </div>
<p>Connect and share screen</p>
<p id="status"> </p>
- Upload the screen-sharing.js script. We will examine it in detail later.
<script type="text/javascript" src="screen-sharing.js"></script>
- Specify where to look for the screencasting extension.
<link rel="chrome-webstore-item"
href="https://chrome.google.com/webstore/detail/nlbaajplpmleofphigmgaifhoikjmbkg">
- Add a button to execute installing of the extension.
<button id="installExtensionButton" onclick="installExtension()" type="button">Install Now</button>
- Add a
div
- the localVideo
element that will display the captured screen locally.
<div id="localVideo" style="width: 320px; height: 240px"> </div>
- 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"> </div>
- The button that initiates screencasting and displays the status of the stream.
<button id="publishBtn" onclick="connectAndShareScreen()" type="button">Connect and share screen</button>
<p id="status"> </p>
Or page looks like this:
- 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() {
try {
Flashphoner.init({screenSharingExtensionId: extensionId});
} catch (e) {
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) {
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);
session.createStream({
name: streamName,
display: remoteVideo
}).on(STREAM_STATUS.PLAYING, function (previewStream) {
}).on(STREAM_STATUS.STOPPED, function () {
publishStream.stop();
}).on(STREAM_STATUS.FAILED, function () {
if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
setStatus(STREAM_STATUS.FAILED);
publishStream.stop();
}
}).play();
}).on(STREAM_STATUS.UNPUBLISHED, function () {
setStatus(STREAM_STATUS.UNPUBLISHED);
}).on(STREAM_STATUS.FAILED, function () {
setStatus(STREAM_STATUS.FAILED);
}).publish();
}
function setStatus(status) {
var statusField = document.getElementById("status");
statusField.innerHTML = status;
}
function installExtension() {
chrome.webstore.install();
}
Let's examine this code in detail.
- 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"
- Then, we send
extensionId
to the Flashphoner
API, as a result the API knows which extension is used for screencasting.
Flashphoner.init({screenSharingExtensionId: extensionId});
- 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) {...}
- 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) {
startStreaming(session);
}).on(SESSION_STATUS.DISCONNECTED, function () {
setStatus(SESSION_STATUS.DISCONNECTED);
}).on(SESSION_STATUS.FAILED, function () {
setStatus(SESSION_STATUS.FAILED);
});
}
- Before screencasting starts, we set such stream parameters as video resolution and FPS.
var constraints = {
video: {
width: 320,
height: 240,
frameRate: 10,
type: "screen"
}
};
- 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();
- After the
test123 stream
is successfully sent to the server, the execution is transferred to the handler of the PUBLISHING
event.
on(STREAM_STATUS.PUBLISHING, function (publishStream) {...}
- 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 Test
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).
Testing of screencasting follows the below diagram:
The same way, we can broadcast the screencasting stream to multiple connected users:
Testing Screencasting in Chrome
- Open the screen-sharing.html page via HTTPS in Google Chrome:
- Click the Install Now button to add the extension using in-line installing:
- 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 application.
- 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.
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