This article describes how to do screen share when using the TRTC Web SDK in Electron.
Introduction
Electron makes it easy to create windows and load web pages for use. Because Electron does not implement the browser-supported WebRTC standard getDisplayMedia interface, if a web page contains WebRTC screen share-related logic, it will not be possible to use the TRTC Web SDK for screen share in Electron as a normal browser.
The problem is that Electron does not implement the getDisplayMedia
interface for WebRTC, which is supported by the browser. This makes it impossible to use TRTC Web SDK for screen share directly in Electron.
How do I do screen share in Electron using the TRTC Web SDK?
Solutions
The preferred recommendation is to use the TRTC Electron SDK, and if you only want to use the TRTC Web SDK, the options are as follows.
To implement screen share, you need to use Electron's API:desktopCapturer.getSources({ types: ['window', 'screen'] })
- The main process
main.js
listens for the page to finish loading, gets the list of screen share sources viadesktopCapturer.getSources
, and sends the list of screen share sources to the rendering process. - The rendering process listens to the main process events to get a list of screen share sources.
- Create screen share streams and push them through the TRTC Web SDK.
- Get the screen-sharing
MediaStream
from the system API vianavigator.mediaDevices.getUserMedia()
. - Create a screen share stream to be published from the videoTrack obtained from the screen stream via the custom capture function of
TRTC.createStream()
. - Publish screen share stream
- Get the screen-sharing
// 【1】main.js Master process gets list of screen share sources
const { app, BrowserWindow, desktopCapturer, systemPreferences } = require('electron');
function createWindow () {
const win = new BrowserWindow({
// ……
});
win.loadFile('./src/index.html');
win.webContents.on('did-finish-load', async () => {
if (win) {
desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
win.webContents.send('SEND_SCREEN_SHARE_SOURCES', sources);
});
}
});
}
// 【2】Render process listens to main process events to get a list of screen share sources
const { ipcRenderer } = require('electron');
let shareSourceList = [];
ipcRenderer.on('SEND_SCREEN_SHARE_SOURCES', async (event, sources) => {
const selectContainer = window.document.getElementById('screen-share-select');
shareSourceList = sources;
sources.forEach(obj => {
const optionElement = document.createElement('option');
optionElement.innerText = `${obj.name}`;
selectContainer.appendChild(optionElement);
});
})
// 【3】Rendering process push screen share
async function startScreenShare() {
const selectContainer = document.getElementById('screen-share-select');
const selectValue = selectContainer.options[selectContainer.selectedIndex].value;
const [ source ] = shareSourceList.filter(obj => obj.name === `${selectValue}`);
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: source.id, // screen share source id
minWidth: 1280,
maxWidth: 1280,
minHeight: 720,
maxHeight: 720
}
}
});
const shareClient = TRTC.createClient({
// ……
});
const shareStream = TRTC.createStream({
videoSource: stream.getVideoTracks()[0]
});
await shareStream.initialize();
await shareClient.join({ roomId: parseInt(roomId) });
shareStream && await shareClient.publish(shareStream);
} catch (error) {
console.error('start screen share error = ', error)
}
}
Common Problems
- macOS Monterey(12.2.1), device permissions need to be requested in the master process
async function checkAndApplyDeviceAccessPrivilege() { const cameraPrivilege = systemPreferences.getMediaAccessStatus('camera'); console.log( `checkAndApplyDeviceAccessPrivilege before apply cameraPrivilege: ${cameraPrivilege}` ); if (cameraPrivilege !== 'granted') { await systemPreferences.askForMediaAccess('camera'); } const micPrivilege = systemPreferences.getMediaAccessStatus('microphone'); console.log( `checkAndApplyDeviceAccessPrivilege before apply micPrivilege: ${micPrivilege}` ); if (micPrivilege !== 'granted') { await systemPreferences.askForMediaAccess('microphone'); } const screenPrivilege = systemPreferences.getMediaAccessStatus('screen'); console.log( `checkAndApplyDeviceAccessPrivilege before apply screenPrivilege: ${screenPrivilege}` ); }