Build an in browser video chat with screen sharing using Twilio Video
Tags: webrtc, javascript, screensharing, twilio
Published: 2018-02-13 06:07:39

---
title: Build an in browser video chat with screen sharing using Twilio Video
published: true
description: Screen sharing improves collaboration in web applications. In this post we implement screen sharing in Twilio Video applications in Chrome and Firefox.
tags: webrtc, javascript, screen-sharing, twilio
cover_image: https://thepracticaldev.s3.amazonaws.com/i/kne389u8ip7cdjxahbak.png
canonical_url: https://www.twilio.com/blog/2018/01/screen-sharing-twilio-video.html
---

In recent posts we've seen how to capture a user's screen in <a href="https://dev.to/philnash/screen-capture-in-google-chrome-bjo">Chrome</a> and <a href="https://dev.to/philnash/screen-capture-in-firefox-bma">Firefox</a>. Now it's time to combine this with a real video chat application and share screens as part of a video chat.

##  What we're building

In this post we'll take the <a href="https://github.com/twilio/video-quickstart-js">Twilio Video quickstart application</a> and add screen sharing to it. When we are done your application will let you make calls between browsers and share screens from one to the other.

<img src="https://twilioinc.wpengine.com/wp-content/uploads/2018/01/screen-share2.gif" alt="Successfully sharing a screen from one video chat to another and then back again using Firefox and Chrome" width="480" height="270" class="aligncenter size-full wp-image-22756" />

## What you'll need

To build this application you will need a few things:

* A Twilio account - you can <a href="https://www.twilio.com/try-twilio">sign up for free here
* <a href="https://nodejs.org">Node.js</a> - we need to run a server to generate access tokens for the Twilio Video service
* <a href="https://dev.to/philnash/screen-capture-in-google-chrome-bjo">The Chrome extension we built in the first post</a> (if you didn't follow this post, there will be <a href="https://github.com/philnash/screen-capture">a copy of the extension in the repo</a> later)
* <a href="https://ngrok.com">Ngrok</a> for <a href="https://dev.to/philnash/screen-capture-in-firefox-bma">testing in Firefox like last time</a>

To get started, clone the repo from GitHub and checkout the `building-screen-sharing` branch:

```bash
git clone -b building-screen-sharing https://github.com/philnash/screen-capture.git
cd screen-capture
```

This repo is slightly different to the <a href="https://github.com/twilio/video-quickstart-js">quickstart repo</a>, it includes the work from the last two blog posts, including the Chrome extension needed for screen capture in Chrome. You can follow <a href="https://dev.to/philnash/screen-capture-in-google-chrome-bjo">the instructions for installing the extension from the blog post</a>.

To prepare the video chat app change into the `video-chat` directory and install the dependencies:

```bash
cd video-chat
npm install
```

Once that is complete, add some credentials so that we can connect to the <a href="https://www.twilio.com/video">Twilio Video</a> service. First, copy the file `.env.example` to `.env`. Open `.env` and fill in the details. You'll need your Twilio Account Sid from the <a href="https://www.twilio.com/console">Twilio console</a> and an <a href="https://www.twilio.com/console/video/runtime/api-keys">API key and secret</a>.

When that is complete, run:

```bash
npm start
```

Open <a href="http://localhost:3000/">http://localhost:3000/</a> and you should be able to enter a username then a room name to join that room. Repeat the process in another browser and you'll be in a video chat with yourself. If that's all working you're ready to start adding the screen sharing feature.

<img src="https://twilioinc.wpengine.com/wp-content/uploads/2018/01/video-chat2.gif" alt="A successful video chat between Chrome and Firefox" width="480" height="270" class="aligncenter size-full wp-image-22755" />

## Adding screen sharing

To add the screen sharing there are a few tasks ahead. Firstly, check that the browser has support for capturing the screen first, otherwise we won't do anything else. Then when a user wants to share their screen we need to work out which browser they are using and use the code from the previous two posts to get the stream. Then add the stream to the room and finally we should make a way to stop the screen sharing too.

Let's get started.

### Checking for support

Normally I like to write progressively enhanced, standards based JavaScript to detect features like this. However, as you've seen in the blog posts leading up to this, screen  capture is not standardised yet, so we need to write some… "dirty code".

Support for screen capture in Firefox is based on the support of the `mediaSource` constraint in the `mediaDevices` API. We can test for that with:

```javascript
!!navigator.mediaDevices.getSupportedConstraints().mediaSource
```

This is a good feature test, sadly it doesn't do the whole job. Firefox will report that `mediaSource` is supported as far back as version 33, however that support was whitelisted to a trusted set of sites. So, we also need to check that the version of Firefox we have is 52 or higher. We can read this data from the user agent with a regular expression.

```javascript
var matchData = navigator.userAgent.match(/Firefox/(d )/);
var firefoxVersion = 0;
if (matchData &amp;&amp; matchData[1]) {
  firefoxVersion = parseInt(matchData[1], 10);
}
```

Open `video-chat/src/index.js` and add the full function to test for Firefox support at the top.

```javascript
// src/index.js
var roomName;

function isFirefox() {
  var mediaSourceSupport = !!navigator.mediaDevices.getSupportedConstraints().mediaSource;
  var matchData = navigator.userAgent.match(/Firefox/(d )/);
  var firefoxVersion = 0;
  if (matchData &amp;&amp; matchData[1]) {
    firefoxVersion = parseInt(matchData[1], 10);
  }
  return mediaSourceSupport &amp;&amp; firefoxVersion &gt;= 52;
}
```

There are a number of <a href="https://stackoverflow.com/questions/6293498/check-whether-user-has-a-chrome-extension-installed">ways to detect if a Chrome extension is installed</a> but they are beyond the scope of this blog post. Look out for a further post in which we explore this. For the purposes of this post I'm going to check that we can make calls against the `chrome` object on the `window`.

```javascript
  return mediaSourceSupport &amp;&amp; firefoxVersion &gt;= 52;
}

function isChrome() {
  return 'chrome' in window;
}
```

We also need a way to tell whether we can use screen capture at all.

```javascript
  return 'chrome' in window;
}

function canScreenShare() {
  return isFirefox() || isChrome();
}
```

### Getting the user's screen

Using the functions above and the knowledge from the previous two posts we can now get the user's screen in browsers that support it. You'll need the ID of your Chrome extension for this part. Add the following lines to your `video-chat/src/index.js` file and replace the `YOUR_EXTENSION_ID` placeholder with your ID:

```javascript
function getUserScreen() {
  var extensionId = 'YOUR_EXTENSION_ID';
  if (!canScreenShare()) {
    return;
  }
  if (isChrome()) {
    return new Promise((resolve, reject) =&gt; {
      const request = {
        sources: ['screen']
      };
      chrome.runtime.sendMessage(extensionId, request, response =&gt; {
        if (response &amp;&amp; response.type === 'success') {
          resolve({ streamId: response.streamId });
        } else {
          reject(new Error('Could not get stream'));
        }
      });
    }).then(response =&gt; {
      return navigator.mediaDevices.getUserMedia({
        video: {
          mandatory: {
            chromeMediaSource: 'desktop',
            chromeMediaSourceId: response.streamId
          }
        }
      });
    });
  } else if (isFirefox()) {
    return navigator.mediaDevices.getUserMedia({
      video: {
        mediaSource: 'screen'
      }
    });
  }
}
```

Now we can use this function when the user wants to share their screen.

### Putting it all together

For the final parts of this, we'll hook up the interface to the function above. There is a hidden button which will be activated when we join a room. In the `roomJoined` function there is already some hiding and showing of buttons, add to that:

```javascript
  document.getElementById('button-join').style.display = 'none';
  document.getElementById('button-leave').style.display = 'inline';
  if (canScreenShare()) {
    document.getElementById('button-share-screen').style.display = 'inline';
  }
```

Under the event handler for the leave room button, create handlers for the share and unshare buttons:

```javascript
    document.getElementById('button-leave').onclick = function() {
      log('Leaving room...');
      activeRoom.disconnect();
    };
    
    document.getElementById('button-share-screen').onclick = function() {
    };

    document.getElementById('button-unshare-screen').onclick = function() {
    };
```

Within the handler for the share button we want to use our `getUserScreen` function to get the media stream from the user's screen and get the video track. We'll then publish that track for the `localParticipant` in the room. If that is all successful we'll change the buttons around.

```javascript
    document.getElementById('button-share-screen').onclick = function() {
      getUserScreen().then(function(stream) {
        var screenTrack = stream.getVideoTracks()[0];
        activeRoom.localParticipant.publishTrack(screenTrack);
        document.getElementById('button-share-screen').style.display = 'none';
        document.getElementById('button-unshare-screen').style.display = 'inline';
      });
    };
```

For the unshare button we want to be able to unpublish the track again. For this, we'll need a reference to the screen track. At the top of the file, declare a new `screenTrack` variable.

```javascript
var activeRoom;
var previewTracks;
var identity;
var roomName;
var screenTrack;
```

In the callback to `getUserScreen` remove the `var` keyword.

```javascript
    document.getElementById('button-share-screen').onclick = function() {
      getUserScreen().then(function(stream) {
        screenTrack = stream.getVideoTracks()[0];
        activeRoom.localParticipant.publishTrack(screenTrack);
        document.getElementById('button-share-screen').style.display = 'none';
        document.getElementById('button-unshare-screen').style.display = 'inline';
      });
    };
```

For the unshare button handler, use the `screenTrack` variable to unpublish the track from the `localParticipant`.

```javascript
    document.getElementById('button-unshare-screen').onclick = function() {
      activeRoom.localParticipant.unpublishTrack(screenTrack);
      screenTrack = null;
      document.getElementById('button-share-screen').style.display = 'inline';
      document.getElementById('button-unshare-screen').style.display = 'none';
    };
```

And that's all the code!

## Share that screen

Start the application again, if it's not already running, with `npm start`. If you want to test this in Firefox, it requires the page to be served over HTTPS. You can get this easily by running <a href="http://ngrok.com/">ngrok</a> and using the HTTPS URL to tunnel through to your localhost. If you're in Chrome you can just go to <a href="http://localhost:3000">http://localhost:3000</a>.

Set up a video chat with a friend (you can send them the ngrok link) or yourself across two browsers. Once you're in, hit the share screen button and once you've selected which screen to share it will appear in the other video chat. 

<img src="https://twilioinc.wpengine.com/wp-content/uploads/2018/01/screen-share2.gif" alt="Successfully sharing a screen from one video chat to another and then back again using Firefox and Chrome" width="480" height="270" class="aligncenter size-full wp-image-22756" />

## Screen share all you like, within the right browsers

With the techniques from these three blog posts you can now screen share in your video chats in Firefox and Chrome (and Opera, with the same Chrome extension, as it happens).

There are loads of things you can do with this, from building a collaborative presentation app to augmenting customer support with browser based screen sharing. An easy feature to start with would be adding a local preview of the user's screen so that they can see what they are sharing.

Check out <a href="http://github.com/philnash/screen-capture">the repo on GitHub</a> for all the code from this and the previous blog posts and go add more collaboration to your video chat apps!

I'd love to hear what you build with this feature. Let me know in the comments, drop me an email at <a href="mailto:philnash@twilio.com">philnash@twilio.com</a> or hit me up on Twitter at <a href="https://twitter.com/philnash">@philnash</a>.

___

[Build an in browser video chat with screen sharing using Twilio Video](https://www.twilio.com/blog/2018/01/screen-sharing-twilio-video.html) was originally published on the [Twilio blog](https://www.twilio.com/blog) on January 28, 2018._