WebRTC For Beginners - Part 4: Screen Share

ethand91

Ethan

Posted on January 27, 2022

WebRTC For Beginners - Part 4: Screen Share

Contents:

  1. Part 1: Introduction to WebRTC and creating the signaling server Link
  2. Part 2: Understanding the MediaDevices API and getting access to the user’s media devices Link
  3. Part 3: Creating the peers and sending/receiving media Link
  4. Part 4: Sharing and sending the user’s display and changing tracks Link
  5. Part 5: Data Channels basics Link
  6. Part 5.5: Building the WebRTC Android Library Link
  7. Part 6: Android native peer Link
  8. Part 7: iOS native peer
  9. Part 8: Where to go from here

Welcome back! Here in part 4 we will be learning how to get the user’s screen and how to switch media tracks so that instead of the camera the screen will be sent instead.

This part technically doesn’t need the previous parts, if you already have a signaling server feel free to use that instead.

Keep in mind that the variety of screens/tabs/windows that can be shared depends on the browser being used.

First we will need to edit the public/index.html file, open it and add the following one line:

<button id="screenShareButton" onclick="shareScreen();" disabled>Share Screen</button>
Enter fullscreen mode Exit fullscreen mode

Screen sharing will be started when the user clicks this button.

Next we need to modify public/main.js, open it up and add the following:

First we need to get a reference to the screen share button.

const screenShareButton = document.getElementById('screenShareButton');
Enter fullscreen mode Exit fullscreen mode

We will enable the button once the RTCPeerConnection is initialized (same as the call button), at the end of the “initializePeerConnection” function add the following:

screenShareButton.disabled = false;
Enter fullscreen mode Exit fullscreen mode

Next we need to disable the button again when the session has finished so in the “stop” function add the following:

screenShareButton.disabled = true;
Enter fullscreen mode Exit fullscreen mode

Now we can create the new functions that will allow the user to share their screen.

const shareScreen = async () => {
  const mediaStream = await getLocalScreenCaptureStream();

  const screenTrack = mediaStream.getVideoTracks()[0];

  if (screenTrack) {
    console.log('replace camera track with screen track');
    replaceTrack(screenTrack);
  }
};
Enter fullscreen mode Exit fullscreen mode

This function calls a helper function which will be implemented shortly, but basically what it does is get the screen track and replaces the track being sent to the remote peer.

Next we will define the two helper functions, the first being “getLocalScreenCaptureStream”

const getLocalScreenCaptureStream = async () => {
  try {
    const constraints = { video: { cursor: 'always' }, audio: false };
    const screenCaptureStream = await navigator.mediaDevices.getDisplayMedia(constraints);

    return screenCaptureStream;
  } catch (error) {
    console.error('failed to get local screen', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

Here we get the user’s screen by calling “getDisplayMedia”, this API uses slightly different constraints than the “getUserMedia” API. Here I’ve told it to also show the cursor when screen sharing. Also we already have the user’s microphone so we don’t need any audio.

Next we define the function that replaces the camera track with the screen track.

const replaceTrack = (newTrack) => {
  const sender = peerConnection.getSenders().find(sender =>
    sender.track.kind === newTrack.kind 
  );

  if (!sender) {
    console.warn('failed to find sender');

    return;
  }

  sender.replaceTrack(newTrack);
}
Enter fullscreen mode Exit fullscreen mode

This function takes a newTrack parameter, this is the track that is to replace the old track.
First we need to get the relevant RTCRtpSender so we call RTCPeerConnection.getSenders, this returns an array of RTCRtpSender objects, next we filter the senders based on the kind of the newTrack(which is audio or video).
Since we are replacing the camera track with the screen track we should get the video RTCRtpSender object.
Finally we replace the sender’s track with the screen track.

Next we need to stop the track when the session ends, so add the following to the “stop” function:

for (const sender of peerConnection.getSenders()) {
  sender.track.stop();
}
Enter fullscreen mode Exit fullscreen mode

This loops through all the RtcRtpSender’s of the RTCPeerConnection and stops their track.

Done :) if done correctly the remote peer should now be getting the shared screen.

Now let’s see it in action. First start the server:

npm start
Enter fullscreen mode Exit fullscreen mode

Next open 2 tabs/browsers to “https://localhost:3000”

Follow the steps from the previous part to initialize the call and click on the “Share Screen” button. You should see the following prompt: (I’m using Chrome but if you are using a different browser the prompt will be different). Also the language may vary.

Share Screen Prompt

Feel free to pick whatever you wanna share and click OK.

Once done look at the remote peer and you should see the shared screen in the remote video like so:

Remote Screen

The track should also be released when the session ends.

Phew. That’s this part done next we will be looking into Data Channels. Hope to see you there!

Github Repo:
https://github.com/ethand91/webrtc-tutorial


Bonus - Things to consider:

  • What are the other constraints that could be passed to the getDisplay API.
  • Mobile devices cannot share the screen, can you detect if the user is using a mobile device?
  • In newer MacOS’s the user needs to enable the browser to use the screen via the privacy settings, can that be handled?

Bonus Materials:
RTCRtpSender - Web APIs | MDN
MediaDevices.getDisplayMedia() - Web APIs | MDN


Like me work? Any support is appreciated. :)
“Buy Me A Coffee”

💖 💪 🙅 🚩
ethand91
Ethan

Posted on January 27, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related