Skip to content

Commit

Permalink
feat: add support for system picker in setDisplayMediaRequestHandler (e…
Browse files Browse the repository at this point in the history
…lectron#43581)

* tmp

* feat: add support for system picker in setDisplayMediaRequestHandler

* oops

* Apply suggestions from code review

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* stuff

* well...

* seems legit

* chore: update patch to handle screenCapturer

* feat: modify API to use useSystemPicker

* fix: gate ScreenCaptureKitPicker to macos 15 or higher

* fix: don't use native picker with legacy media selection

* chore: code review, boolean set & docs update

* fix: add cancelCallback

* docs: clarify session & desktopCapturer docs

---------

Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
Co-authored-by: Samuel Attard <sam@electronjs.org>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
  • Loading branch information
4 people authored Sep 10, 2024
1 parent a3df950 commit 309d5da
Show file tree
Hide file tree
Showing 16 changed files with 432 additions and 6 deletions.
6 changes: 5 additions & 1 deletion docs/api/desktop-capturer.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ app.whenReady().then(() => {
// Grant access to the first screen found.
callback({ video: sources[0], audio: 'loopback' })
})
})
// If true, use the system picker if available.
// Note: this is currently experimental. If the system picker
// is available, it will be used and the media request handler
// will not be invoked.
}, { useSystemPicker: true })

mainWindow.loadFile('index.html')
})
Expand Down
14 changes: 12 additions & 2 deletions docs/api/session.md
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
})
```
#### `ses.setDisplayMediaRequestHandler(handler)`
#### `ses.setDisplayMediaRequestHandler(handler[, opts])`
* `handler` Function | null
* `request` Object
Expand All @@ -980,12 +980,18 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
and this is set to `true`, then local playback of audio will not be muted (e.g. using `MediaRecorder`
to record `WebFrameMain` with this flag set to `true` will allow audio to pass through to the speakers
while recording). Default is `false`.
* `opts` Object (optional) _macOS_ _Experimental_
* `useSystemPicker` Boolean - true if the available native system picker should be used. Default is `false`. _macOS_ _Experimental_
This handler will be called when web content requests access to display media
via the `navigator.mediaDevices.getDisplayMedia` API. Use the
[desktopCapturer](desktop-capturer.md) API to choose which stream(s) to grant
access to.
`useSystemPicker` allows an application to use the system picker instead of providing a specific video source from `getSources`.
This option is experimental, and currently available for MacOS 15+ only. If the system picker is available and `useSystemPicker`
is set to `true`, the handler will not be invoked.
```js
const { session, desktopCapturer } = require('electron')

Expand All @@ -994,7 +1000,11 @@ session.defaultSession.setDisplayMediaRequestHandler((request, callback) => {
// Grant access to the first screen found.
callback({ video: sources[0] })
})
})
// Use the system picker if available.
// Note: this is currently experimental. If the system picker
// is available, it will be used and the media request handler
// will not be invoked.
}, { useSystemPicker: true })
```
Passing a [WebFrameMain](web-frame-main.md) object as a video or audio stream
Expand Down
1 change: 1 addition & 0 deletions filenames.gni
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ filenames = {
"shell/browser/api/electron_api_debugger.h",
"shell/browser/api/electron_api_desktop_capturer.cc",
"shell/browser/api/electron_api_desktop_capturer.h",
"shell/browser/api/electron_api_desktop_capturer_mac.mm",
"shell/browser/api/electron_api_dialog.cc",
"shell/browser/api/electron_api_download_item.cc",
"shell/browser/api/electron_api_download_item.h",
Expand Down
4 changes: 3 additions & 1 deletion lib/browser/api/desktop-capturer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BrowserWindow } from 'electron/main';
const { createDesktopCapturer } = process._linkedBinding('electron_browser_desktop_capturer');
const { createDesktopCapturer, isDisplayMediaSystemPickerAvailable } = process._linkedBinding('electron_browser_desktop_capturer');

const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);

Expand All @@ -13,6 +13,8 @@ function isValid (options: Electron.SourcesOptions) {
return Array.isArray(options?.types);
}

export { isDisplayMediaSystemPickerAvailable };

export async function getSources (args: Electron.SourcesOptions) {
if (!isValid(args)) throw new Error('Invalid options');

Expand Down
26 changes: 26 additions & 0 deletions lib/browser/api/session.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
import { fetchWithSession } from '@electron/internal/browser/api/net-fetch';
import { net } from 'electron/main';
const { fromPartition, fromPath, Session } = process._linkedBinding('electron_browser_session');
const { isDisplayMediaSystemPickerAvailable } = process._linkedBinding('electron_browser_desktop_capturer');

// Fake video source that activates the native system picker
// This is used to get around the need for a screen/window
// id in Chrome's desktopCapturer.
let fakeVideoSourceId = -1;
const systemPickerVideoSource = Object.create(null);
Object.defineProperty(systemPickerVideoSource, 'id', {
get () {
return `window:${fakeVideoSourceId--}:0`;
}
});
systemPickerVideoSource.name = '';
Object.freeze(systemPickerVideoSource);

Session.prototype.fetch = function (input: RequestInfo, init?: RequestInit) {
return fetchWithSession(input, init, this, net.request);
};

Session.prototype.setDisplayMediaRequestHandler = function (handler, opts) {
if (!handler) return this._setDisplayMediaRequestHandler(handler, opts);

this._setDisplayMediaRequestHandler(async (req, callback) => {
if (opts && opts.useSystemPicker && isDisplayMediaSystemPickerAvailable()) {
return callback({ video: systemPickerVideoSource });
}

return handler(req, callback);
}, opts);
};

export default {
fromPartition,
fromPath,
Expand Down
1 change: 1 addition & 0 deletions patches/chromium/.patches
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,4 @@ chore_remove_reference_to_chrome_browser_themes.patch
feat_enable_customizing_symbol_color_in_framecaptionbutton.patch
build_expose_webplugininfo_interface_to_electron.patch
osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch
feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch
Loading

0 comments on commit 309d5da

Please sign in to comment.