For a list of the browsers that support screen sharing, see Browsers Supported. You can also use the TRTC.isScreenShareSupported API to check whether your current browser supports screen sharing.
This document describes how to implement the screen sharing feature in the TRTC web SDK.
Note:
- The TRTC web SDK does not support publishing substreams, and screen sharing streams are published as primary streams. Therefore, if a remote screen sharing stream is from a browser, the RemoteStream.getType() API will return
main
. We recommend you setuserId
in such a way that you can tell from the ID that a user is sharing the screen from a browser.- The TRTC SDKs for native applications (iOS, Android, macOS, Windows, etc.) support publishing substreams, and screen sharing streams are published as substreams. Therefore, if a remote screen sharing stream is from a native application, the RemoteStream.getType() API will return
auxiliary
.
Note:Follow the steps below to create a screen sharing stream and publish it.
A screen sharing stream includes an audio track and a video track, and an audio track includes mic audio and system audio.
// Good:
// Capture only video
const shareStream = TRTC.createStream({ audio: false, screen: true, userId });
// Capture mic audio and video
const shareStream = TRTC.createStream({ audio: true, screen: true, userId });
// Capture system audio and video
const shareStream = TRTC.createStream({ screenAudio: true, screen: true, userId });
// Bad:
const shareStream = TRTC.createStream({ camera: true, screen: true });
// or
const shareStream = TRTC.createStream({ camera: true, screenAudio: true });
Note:
- You cannot set both
audio
andscreenAudio
totrue
, nor can you set bothcamera
andscreenAudio
totrue
. For more information aboutscreenAudio
, see "Capturing System Audio During Screen Sharing" below.- You cannot set both
camera
andscreen
totrue
.
During initialization, the browser will ask the user’s permission to share the screen. If the user denies the permission or if the browser is not granted the permission by the system, the NotReadableError
or NotAllowedError
error will be returned. In such cases, you need to instruct the user to change the browser settings or grant the screen sharing permission and then initialize the screen sharing stream again.
Note:For Safari, you need to initialize the screen sharing stream from an onclick callback. For details, see FAQs.
try {
await shareStream.initialize();
} catch (error) {
// If the initialization of the screen sharing stream fails, notify the user and stop performing subsequent steps including room entry and stream publishing.
switch (error.name) {
case 'NotReadableError':
// Ask the user to check if the system has allowed the browser to record the screen.
return;
case 'NotAllowedError':
if (error.message.includes('Permission denied by system')) {
// Ask the user to check if the system has allowed the browser to record the screen.
} else {
// The user denies the permission or cancels screen sharing.
}
return;
default:
// An unknown error occurred during the initialization of the screen sharing stream. Ask the user to try again.
return;
}
}
We recommend you add the prefix share
to the userId
of the object to indicate that it is used for screen sharing.
const shareClient = TRTC.createClient({
mode: 'rtc',
sdkAppId,
userId, // Example: ‘share_teacher’
userSig
});
// The client object enters the room.
try {
await shareClient.join({ roomId });
// ShareClient join room success
} catch (error) {
// ShareClient join room failed
}
Use the client object created in step 1 to publish the stream. If it is successful, remote users will receive the stream.
try {
await shareClient.publish(shareStream);
} catch (error) {
// ShareClient failed to publish local stream
}
// We recommend you add the prefix `share` to the `userId` of the object to indicate that it is used for screen sharing.
const userId = 'share_userId';
const roomId = 'roomId';
// Capture only video
const shareStream = TRTC.createStream({ audio: false, screen: true, userId });
// Capture mic audio and video
// const shareStream = TRTC.createStream({ audio: true, screen: true, userId });
// Capture system audio and video
// const shareStream = TRTC.createStream({ screenAudio: true, screen: true, userId });
try {
await shareStream.initialize();
} catch (error) {
// If the initialization of the screen sharing stream fails, notify the user and stop performing subsequent steps including room entry and stream publishing.
switch (error.name) {
case 'NotReadableError':
// Ask the user to check if the system has allowed the browser to record the screen.
return;
case 'NotAllowedError':
if (error.message.includes('Permission denied by system')) {
// Ask the user to check if the system has allowed the browser to record the screen.
} else {
// The user denies the permission or cancels screen sharing.
}
return;
default:
// An unknown error occurred during the initialization of the screen sharing stream. Ask the user to try again.
return;
}
}
const shareClient = TRTC.createClient({
mode: 'rtc',
sdkAppId,
userId, // Example: ‘share_teacher’
userSig
});
// The client object enters the room.
try {
await shareClient.join({ roomId });
// ShareClient join room success
} catch (error) {
// ShareClient join room failed
}
try {
await shareClient.publish(shareStream);
} catch (error) {
// ShareClient failed to publish local stream
Screen sharing parameters include resolution, frame rate, and bitrate, which you can set using the setScreenProfile() API. Each profile value corresponds to a set of resolution, frame rate, and bitrate. The default value is 1080p
.
const shareStream = TRTC.createStream({ audio: false, screen: true, userId });
// For SetScreenProfile() to work, you must call it before you call initialize().
shareStream.setScreenProfile('1080p');
await shareStream.initialize();
You can also specify a custom value for the resolution, frame rate, and bitrate.
const shareStream = TRTC.createStream({ audio: false, screen: true, userId });
// For SetScreenProfile() to work, you must call it before you call initialize().
shareStream.setScreenProfile({ width: 1920, height: 1080, frameRate: 5, bitrate: 1600 /* kbps */});
await shareStream.initialize();
Profile | Resolution (W x H) | Frame Rate (fps) | Bitrate (Kbps) |
---|---|---|---|
480p | 640 x 480 | 5 | 900 |
480p_2 | 640 x 480 | 30 | 1000 |
720p | 1280 x 720 | 5 | 1200 |
720p_2 | 1280 x 720 | 30 | 3000 |
1080p | 1920 x 1080 | 5 | 1600 |
1080p_2 | 1920 x 1080 | 30 | 4000 |
Note:Setting the parameters too high may cause unexpected results. We recommend you use the above settings.
// The screen sharing client stops publishing the stream.
await shareClient.unpublish(shareStream);
// Close the screen sharing stream.
shareStream.close();
// Leave the room.
await shareClient.leave();
// The above three steps are optional. You can determine what code to use according to the actual situation. Normally, you need to add code to determine whether the user has entered the room and whether the stream has been published. For more code samples, see the [demo source code](https://github.com/LiteAVSDK/TRTC_Web/blob/main/base-js/js/share-client.js).
A user may also stop screen sharing by clicking a built-in button in the browser, so it’s necessary to listen for the screen sharing stopping event and, if the event occurs, take the necessary action.
// Listen for the screen sharing stopping event.
shareStream.on('screen-sharing-stopped', event => {
// Stop publishing the screen sharing stream.
await shareClient.unpublish(shareStream);
// Close the screen sharing stream.
shareStream.close();
// Leave the room.
await shareClient.leave();
});
A client can publish only one video track and one audio track. Therefore, to publish both the camera and screen sharing streams, you need to create two clients.
Below is an example:
shareClient
.Note:
- You need to disable automatic subscription for
shareClient
so that it does not subscribe to remote streams. For details, see the API document.- For
client
, you need to unsubscribe from the stream ofshareClient
.
Sample code:
const client = TRTC.createClient({ mode: 'rtc', sdkAppId, userId, userSig });
// Set autoSubscribe to false to disable automatic subscription for shareClient.
const shareClient = TRTC.createClient({ mode: 'rtc', sdkAppId, `share_${userId}`, userSig, autoSubscribe: false,});
// Unsubscribe from the stream of shareClient.
client.on('stream-added', event => {
const remoteStream = event.stream;
const remoteUserId = remoteStream.getUserId();
if (remoteUserId === `share_${userId}`) {
// Unsubscribe from the screen sharing stream.
client.unsubscribe(remoteStream);
} else {
// Subscribe to other remote streams.
client.subscribe(remoteStream);
}
});
await client.join({ roomId });
await shareClient.join({ roomId });
const localStream = TRTC.createStream({ audio: true, video: true, userId });
const shareStream = TRTC.createStream({ audio: false, screen: true, userId });
// The code for initialization and publishing is omitted. You can add the code based on your needs.
System audio capturing is supported only on Chrome M74 and later versions. On Chrome for Windows and Chrome OS, you can capture the audio of the entire system, while on Chrome for Linux and macOS, you can only capture the audio of Chrome tabs. Other Chrome versions, OS, and browsers do not support system audio capturing.
// Set screenAudio to true when creating the screen sharing stream. Don’t set audio to true because you cannot capture mic and system audio at the same time.
const shareStream = TRTC.createStream({ screenAudio: true, screen: true, userId });
await shareStream.initialize();
...
In the pop-up window, select Share audio, and the stream published will contain system audio.
What should I do if the error getDisplayMedia must be called from a user gesture handler
occurs on Safari?
Safari does not support the screen capturing API getDisplayMedia
. However, you can call it within one second of the callback for an onclick event. For details, see this WebKit Bugzilla page.
// Good
async function onClick() {
// We recommend you capture the stream first.
const screenStream = TRTC.createStream({ screen: true });
await screenStream.initialize();
await client.join({ roomId: 123123 });
}
// Bad
async function onClick() {
await client.join({ roomId: 123123 });
// If it takes longer than one second for the client to enter the room, capturing will fail.
const screenStream = TRTC.createStream({ screen: true });
await screenStream.initialize();
}
For other questions, see WebRTC Known Issues and Solutions.
Was this page helpful?