Skip to main content

Receive presentation

An important feature in any video conference application is screen sharing or "presentation". This feature allows the users to collaborate in a more flexible way. They can share any type of document or tools, such a whiteboard, powerpoint or even videos.

We have divided the lessons about presentation into two parts. We will start by receiving a presentation, and in the next lesson, we will learn how to send a presentation.

During this tutorial we will perform the following tasks:

  • Set handlers related for receiving a presentation.
  • Define a function to choose which video display in the main region (remote participants or presentation).
  • Define the useEffect hook to configure the initial state of the component after re-rendering.
  • Create the HTML Video element for the presentation.
  • Set the onClick listener for changing between the video with the remote participants and the presentation.

After all these changes, we will be able to receive a presentation and in the next lesson we will learn how to send it.

You can download the starter code from Step.04-Exercise-Receive-presentation.

App component

We will start the journey by editing the file src/App.tsx.

The first step is to define a state variable that will contain the MediaStream with the presentation:

const [presentationStream, setPresentationStream] =
useState<MediaStream | null>(null);

Next we need to add a handler to the onRemotePresentationStream signal that will set the value of the previous state:

useEffect(() => {
callSignals.onRemotePresentationStream.add((stream) => setPresentationStream(stream));
...
});

Next we pass the presentationStream to the conference:

<Conference
localStream={localStream}
remoteStream={remoteStream}
presentationStream={presentationStream}
onAudioMute={handleAudioMute}
onVideoMute={handleVideoMute}
onDisconnect={handleDisconnect}
/>

Conference component

Now we will edit the file src/components/Conference/Conference.tsx and in this file we will define a new HTML Video tag. This new tag will be used to display a secondary media stream. We also will exchange the video located in the main region if the user click on this video.

We need to update the list of props that the conference receives and add presentationStream:

interface ConferenceProps {
localStream: MediaStream | null;
remoteStream: MediaStream | null;
presentationStream: MediaStream | null;
onAudioMute: (mute: boolean) => void;
onVideoMute: (mute: boolean) => void;
onDisconnect: () => void;
}

Next we will define a state variable that will indicate which video stream will be displayed in the main region of the page. It could be the video with the remote participants or the presentation. The video that is not in the main region will be positioned in the top-left corner and it will be much smaller:

const [presentationInMain, setPresentationInMain] = useState(true);

Next we will define the function that will be triggered every time the user clicks over the video that is not in the main region:

const switchVideos = (event: React.MouseEvent<HTMLVideoElement>) => {
if (event.target instanceof HTMLVideoElement) {
if (event.target.className === 'presentation-video') {
setPresentationInMain(true);
} else {
setPresentationInMain(false);
}
}
};

Next we use the useCallback hook over the switchVideos function, since this will be avoid video flickering when the component is re-rendered:

const memoizedSwitchVideos = React.useCallback(switchVideos, []);

Next we create a new variable that will contain the class presentation-in-main if presentationInMain is true:

const additionalClasses =
presentationInMain && props.presentationStream ? ' presentation-in-main' : '';

And assign that class to the container:

<div className={'Conference' + additionalClasses}>

The next step is to use the useEffect hook to define what should happen when the component is re-rendered due to a change in the dependencies:

useEffect(() => {
if (!props.presentationStream) {
setPresentationInMain(true);
}
}, [props.presentationStream]);

With this modification, we will display by default the remote presentation in the main video region, and in case the user is the one that is sending the presentation (next lesson), they will see it in a small thumbnail.

Next we will modify the remote-video element and add the onClick attribute to call the memoized function that we have defined before:

<Video
className="remote-video"
mediaStream={props.remoteStream}
onClick={memoizedSwitchVideos}
/>

The last thing that we need is to define a new video that will contain the presentation that we will receive. In the similar way that before, we assign a function to the onClick event that will switch the video that is displayed in the main region:

{
props.presentationStream && (
<Video
className="presentation-video"
mediaStream={props.presentationStream}
onClick={memoizedSwitchVideos}
/>
);
}

With this last modification we have everything in place that we will need for receiving a presentation. In the next tutorial we will see how to share our screen with other participants.

Run the app

To test your new feature, you will need an application that already has the capability to send a presentation. Our recommendation is to test it with the Pexip Web App 3. This way, a participant will join to the conference using your app and a second participant will use the Web App 3.

You can compare your code with the solution in Step.04-Solution-Receive-presentation. You can also check the differences with the previous lesson in the git diff.

Receive Presentation