From 205c846738a643cdecc49666e463cca65c3e2ac9 Mon Sep 17 00:00:00 2001 From: Axel Eriksson Date: Thu, 23 Jan 2025 13:25:21 +0100 Subject: [PATCH] Adding support for Windows to use navigator.mediaDevices.getDisplayMedia --- src/app/display-media-request-handler.ts | 94 +++++++++++++++++++++--- src/app/window-handler.ts | 2 +- 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/app/display-media-request-handler.ts b/src/app/display-media-request-handler.ts index 70231ea92..c6d8dec48 100644 --- a/src/app/display-media-request-handler.ts +++ b/src/app/display-media-request-handler.ts @@ -1,20 +1,94 @@ -import { session } from 'electron'; +import { desktopCapturer, ipcMain, session } from 'electron'; +import { + ICustomBrowserWindowConstructorOpts, + windowHandler, +} from './window-handler'; +import { createComponentWindow, windowExists } from './window-utils'; +import { logger } from '../common/logger'; +import { isDevEnv, isMac } from '../common/env'; +import { NOTIFICATION_WINDOW_TITLE } from '../common/api-interface'; /** - * This is currently supported only on macOS 15+. - * setDisplayMediaRequestHandler injects into navigator.mediaDevices.getDisplayMedia(). - * With the macOS-only option { useSystemPicker: true }, - * everyting is handled natively by the OS. + * For MacOS 15+ the { useSystemPicker: true } overrides the code set in the handler, + * and uses the native implementation. * - * For all other OSes and versions, the regular screen share flow will be used. + * But for other versions and OSes, the code is executed. */ export const setDisplayMediaRequestHandler = () => { const { defaultSession } = session; - defaultSession.setDisplayMediaRequestHandler( - async (_request, _callback) => { - // TODO - Add support for Windows. + async (_request, callback) => { + logger.info('display-media-request-handler: getting sources'); + const sources = await desktopCapturer.getSources({ + types: ['screen', 'window'], + thumbnailSize: { + height: 150, + width: 150, + }, + }); + + const updatedSources = sources + .filter((source) => source.name !== NOTIFICATION_WINDOW_TITLE) + .map((source) => { + return { + ...source, + ...{ + thumbnail: source.thumbnail.toDataURL(), + }, + }; + }); + + const browserWindowOptions: ICustomBrowserWindowConstructorOpts = + windowHandler.getWindowOpts( + { + alwaysOnTop: true, + autoHideMenuBar: true, + frame: false, + modal: false, + height: isMac ? 519 : 523, + width: 580, + show: false, + fullscreenable: false, + }, + { + devTools: isDevEnv, + }, + ); + const screenPickerWindow = createComponentWindow( + 'screen-picker', + browserWindowOptions, + ); + + screenPickerWindow.webContents.once('did-finish-load', () => { + if (!screenPickerWindow || !windowExists(screenPickerWindow)) { + return; + } + screenPickerWindow.webContents.send('screen-picker-data', { + sources: updatedSources, + }); + }); + + const mainWebContents = windowHandler.getMainWebContents(); + if (!mainWebContents) { + return; + } + mainWebContents.send('screen-picker-data', updatedSources); + ipcMain.on('screen-source-select', (_event, selectedSource) => { + // Draw screen share indicator and bring to front + logger.info( + 'display-media-request-handler: source selected', + selectedSource, + ); + }); + ipcMain.once('screen-source-selected', (_event, selectedSource) => { + screenPickerWindow.close(); + logger.info( + 'display-media-request-handler: source to be shared', + selectedSource, + ); + callback({ video: selectedSource }); + }); }, - { useSystemPicker: true }, + { useSystemPicker: false }, // TODO - Temporary, revert back to true. ); }; diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts index f00280d5f..6cd174553 100644 --- a/src/app/window-handler.ts +++ b/src/app/window-handler.ts @@ -2513,7 +2513,7 @@ export class WindowHandler { * @param windowOpts {Electron.BrowserWindowConstructorOptions} * @param webPreferences {Electron.WebPreferences} */ - private getWindowOpts( + public getWindowOpts( windowOpts: Electron.BrowserWindowConstructorOptions, webPreferences: Electron.WebPreferences, ): ICustomBrowserWindowConstructorOpts {