本文主要介绍 Electron 中使用 TRTC Web SDK 时,如何进行屏幕分享。
简介
Electron 可以方便的创建窗口,加载网页进行使用。因为 Electron 未实现浏览器支持的 WebRTC 标准的 getDisplayMedia 接口,所以如果网页中包含了 WebRTC 屏幕分享相关的逻辑,将无法在 Electron 中像普通浏览器一样正常使用 TRTC Web SDK 进行屏幕分享。
问题在于 Electron 未实现浏览器支持的 WebRTC 的 getDisplayMedia 接口,导致无法直接在 Electron 中使用 TRTC Web SDK 进行屏幕分享。
在 Electron 中使用 TRTC Web SDK 如何进行屏幕分享呢?
方案
优先建议使用 TRTC Electron SDK,如果只想使用 TRTC Web SDK,方案如下。
实现屏幕分享,需要使用到 Electron 的 API:desktopCapturer.getSources({ types: ['window', 'screen'] })
- 主进程 main.js监听页面加载完成后,通过desktopCapturer.getSources获取屏幕分享源列表,并将屏幕分享源列表发送给渲染进程
- 渲染进程监听主进程事件,从而获取屏幕分享源列表
- 创建屏幕分享流并通过 TRTC Web SDK 进行推流
              - 通过 navigator.mediaDevices.getUserMedia()从系统 API 获取屏幕分享的MediaStream
- 通过 TRTC.createStream()的自定义采集功能,从屏幕流拿到的 videoTrack 创建要发布的屏幕分享流
- 推屏幕分享流
 
- 通过 
// 【1】main.js 主进程获取屏幕分享源列表
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】渲染进程监听主进程事件拿到屏幕分享源列表
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】渲染进程推屏幕分享
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, // 屏幕分享源 id
          minWidth: 1280,
          maxWidth: 1280,
          minHeight: 720,
          maxHeight: 720
        }
      }
    });
    const shareClient = TRTC.create({
      // ……
    });
    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)
  }
}
常见问题
- macOS Monterey(12.2.1), 需在主进程中请求设备权限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}` ); }