X Tutup
Skip to content

Commit 4fd7c2a

Browse files
nornagonminiak
andauthored
feat: make desktopCapturer main-process-only (electron#30720)
* feat: make desktopCapturer main-process-only * remove --enable-api-filtering-logging * remove test * merge lib/browser/api/desktop-capturer.ts with lib/browser/desktop-capturer.ts * remove desktop-capturer-get-sources event * fix specs * getSources needs to be async Co-authored-by: Milan Burda <milan.burda@gmail.com>
1 parent 6db8d79 commit 4fd7c2a

File tree

17 files changed

+149
-312
lines changed

17 files changed

+149
-312
lines changed

docs/api/app.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -500,16 +500,6 @@ gets emitted.
500500
**Note:** Extra command line arguments might be added by Chromium,
501501
such as `--original-process-start-time`.
502502

503-
### Event: 'desktop-capturer-get-sources'
504-
505-
Returns:
506-
507-
* `event` Event
508-
* `webContents` [WebContents](web-contents.md)
509-
510-
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
511-
Calling `event.preventDefault()` will make it return empty sources.
512-
513503
## Methods
514504

515505
The `app` object has the following methods:

docs/api/command-line-switches.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ throttling in one window, you can take the hack of
6161

6262
Forces the maximum disk space to be used by the disk cache, in bytes.
6363

64-
### --enable-api-filtering-logging
65-
66-
Enables caller stack logging for the following APIs (filtering events):
67-
68-
* `desktopCapturer.getSources()` / `desktop-capturer-get-sources`
69-
7064
### --enable-logging[=file]
7165

7266
Prints Chromium's logging to stderr (or a log file).

docs/api/desktop-capturer.md

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,49 @@
33
> Access information about media sources that can be used to capture audio and
44
> video from the desktop using the [`navigator.mediaDevices.getUserMedia`] API.
55
6-
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
6+
Process: [Main](../glossary.md#main-process)
77

88
The following example shows how to capture video from a desktop window whose
99
title is `Electron`:
1010

1111
```javascript
12-
// In the renderer process.
12+
// In the main process.
1313
const { desktopCapturer } = require('electron')
1414

1515
desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
1616
for (const source of sources) {
1717
if (source.name === 'Electron') {
18-
try {
19-
const stream = await navigator.mediaDevices.getUserMedia({
20-
audio: false,
21-
video: {
22-
mandatory: {
23-
chromeMediaSource: 'desktop',
24-
chromeMediaSourceId: source.id,
25-
minWidth: 1280,
26-
maxWidth: 1280,
27-
minHeight: 720,
28-
maxHeight: 720
29-
}
30-
}
31-
})
32-
handleStream(stream)
33-
} catch (e) {
34-
handleError(e)
35-
}
18+
mainWindow.webContents.send('SET_SOURCE', source.id)
3619
return
3720
}
3821
}
3922
})
23+
```
24+
25+
```javascript
26+
// In the preload script.
27+
const { ipcRenderer } = require('electron')
28+
29+
ipcRenderer.on('SET_SOURCE', async (event, sourceId) => {
30+
try {
31+
const stream = await navigator.mediaDevices.getUserMedia({
32+
audio: false,
33+
video: {
34+
mandatory: {
35+
chromeMediaSource: 'desktop',
36+
chromeMediaSourceId: sourceId,
37+
minWidth: 1280,
38+
maxWidth: 1280,
39+
minHeight: 720,
40+
maxHeight: 720
41+
}
42+
}
43+
})
44+
handleStream(stream)
45+
} catch (e) {
46+
handleError(e)
47+
}
48+
})
4049

4150
function handleStream (stream) {
4251
const video = document.querySelector('video')

docs/api/web-contents.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -856,15 +856,6 @@ Returns:
856856

857857
Emitted when the renderer process sends a synchronous message via `ipcRenderer.sendSync()`.
858858

859-
#### Event: 'desktop-capturer-get-sources'
860-
861-
Returns:
862-
863-
* `event` Event
864-
865-
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
866-
Calling `event.preventDefault()` will make it return empty sources.
867-
868859
#### Event: 'preferred-size-changed'
869860

870861
Returns:

filenames.auto.gni

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ auto_filenames = {
142142
"lib/common/web-view-methods.ts",
143143
"lib/renderer/api/context-bridge.ts",
144144
"lib/renderer/api/crash-reporter.ts",
145-
"lib/renderer/api/desktop-capturer.ts",
146145
"lib/renderer/api/ipc-renderer.ts",
147146
"lib/renderer/api/web-frame.ts",
148147
"lib/renderer/inspector.ts",
@@ -224,7 +223,6 @@ auto_filenames = {
224223
"lib/browser/api/web-contents.ts",
225224
"lib/browser/api/web-frame-main.ts",
226225
"lib/browser/default-menu.ts",
227-
"lib/browser/desktop-capturer.ts",
228226
"lib/browser/devtools.ts",
229227
"lib/browser/guest-view-manager.ts",
230228
"lib/browser/guest-window-manager.ts",
@@ -271,7 +269,6 @@ auto_filenames = {
271269
"lib/common/webpack-provider.ts",
272270
"lib/renderer/api/context-bridge.ts",
273271
"lib/renderer/api/crash-reporter.ts",
274-
"lib/renderer/api/desktop-capturer.ts",
275272
"lib/renderer/api/exports/electron.ts",
276273
"lib/renderer/api/ipc-renderer.ts",
277274
"lib/renderer/api/module-list.ts",
@@ -309,7 +306,6 @@ auto_filenames = {
309306
"lib/common/webpack-provider.ts",
310307
"lib/renderer/api/context-bridge.ts",
311308
"lib/renderer/api/crash-reporter.ts",
312-
"lib/renderer/api/desktop-capturer.ts",
313309
"lib/renderer/api/exports/electron.ts",
314310
"lib/renderer/api/ipc-renderer.ts",
315311
"lib/renderer/api/module-list.ts",
Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,72 @@
1-
import { getSourcesImpl } from '@electron/internal/browser/desktop-capturer';
1+
const { createDesktopCapturer } = process._linkedBinding('electron_browser_desktop_capturer');
22

3-
export async function getSources (options: Electron.SourcesOptions) {
4-
return getSourcesImpl(null, options);
3+
const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);
4+
5+
let currentlyRunning: {
6+
options: ElectronInternal.GetSourcesOptions;
7+
getSources: Promise<ElectronInternal.GetSourcesResult[]>;
8+
}[] = [];
9+
10+
// |options.types| can't be empty and must be an array
11+
function isValid (options: Electron.SourcesOptions) {
12+
const types = options ? options.types : undefined;
13+
return Array.isArray(types);
14+
}
15+
16+
export async function getSources (args: Electron.SourcesOptions) {
17+
if (!isValid(args)) throw new Error('Invalid options');
18+
19+
const captureWindow = args.types.includes('window');
20+
const captureScreen = args.types.includes('screen');
21+
22+
const { thumbnailSize = { width: 150, height: 150 } } = args;
23+
const { fetchWindowIcons = false } = args;
24+
25+
const options = {
26+
captureWindow,
27+
captureScreen,
28+
thumbnailSize,
29+
fetchWindowIcons
30+
};
31+
32+
for (const running of currentlyRunning) {
33+
if (deepEqual(running.options, options)) {
34+
// If a request is currently running for the same options
35+
// return that promise
36+
return running.getSources;
37+
}
38+
}
39+
40+
const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
41+
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer();
42+
43+
const stopRunning = () => {
44+
if (capturer) {
45+
delete capturer._onerror;
46+
delete capturer._onfinished;
47+
capturer = null;
48+
}
49+
// Remove from currentlyRunning once we resolve or reject
50+
currentlyRunning = currentlyRunning.filter(running => running.options !== options);
51+
};
52+
53+
capturer._onerror = (error: string) => {
54+
stopRunning();
55+
reject(error);
56+
};
57+
58+
capturer._onfinished = (sources: Electron.DesktopCapturerSource[]) => {
59+
stopRunning();
60+
resolve(sources);
61+
};
62+
63+
capturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons);
64+
});
65+
66+
currentlyRunning.push({
67+
options,
68+
getSources
69+
});
70+
71+
return getSources;
572
}

lib/browser/desktop-capturer.ts

Lines changed: 0 additions & 82 deletions
This file was deleted.

lib/browser/rpc-server.ts

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,9 @@
1-
import { app } from 'electron/main';
2-
import type { WebContents } from 'electron/main';
31
import { clipboard } from 'electron/common';
42
import * as fs from 'fs';
53
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
64
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
75
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
86

9-
import type * as desktopCapturerModule from '@electron/internal/browser/desktop-capturer';
10-
11-
const eventBinding = process._linkedBinding('electron_browser_event');
12-
13-
const emitCustomEvent = function (contents: WebContents, eventName: string, ...args: any[]) {
14-
const event = eventBinding.createWithSender(contents);
15-
16-
app.emit(eventName, event, contents, ...args);
17-
contents.emit(eventName, event, ...args);
18-
19-
return event;
20-
};
21-
22-
const logStack = function (contents: WebContents, code: string, stack: string) {
23-
if (stack) {
24-
console.warn(`WebContents (${contents.id}): ${code}`, stack);
25-
}
26-
};
27-
287
// Implements window.close()
298
ipcMainInternal.on(IPC_MESSAGES.BROWSER_WINDOW_CLOSE, function (event) {
309
const window = event.sender.getOwnerBrowserWindow();
@@ -58,22 +37,6 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, function (event, me
5837
return (clipboard as any)[method](...args);
5938
});
6039

61-
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
62-
const desktopCapturer = require('@electron/internal/browser/desktop-capturer') as typeof desktopCapturerModule;
63-
64-
ipcMainInternal.handle(IPC_MESSAGES.DESKTOP_CAPTURER_GET_SOURCES, async function (event, options: Electron.SourcesOptions, stack: string) {
65-
logStack(event.sender, 'desktopCapturer.getSources()', stack);
66-
const customEvent = emitCustomEvent(event.sender, 'desktop-capturer-get-sources');
67-
68-
if (customEvent.defaultPrevented) {
69-
console.error('Blocked desktopCapturer.getSources()');
70-
return [];
71-
}
72-
73-
return await desktopCapturer.getSourcesImpl(event.sender, options);
74-
});
75-
}
76-
7740
const getPreloadScript = async function (preloadPath: string) {
7841
let preloadSrc = null;
7942
let preloadError = null;

lib/common/ipc-messages.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,4 @@ export const enum IPC_MESSAGES {
2828
INSPECTOR_CONFIRM = 'INSPECTOR_CONFIRM',
2929
INSPECTOR_CONTEXT_MENU = 'INSPECTOR_CONTEXT_MENU',
3030
INSPECTOR_SELECT_FILE = 'INSPECTOR_SELECT_FILE',
31-
32-
DESKTOP_CAPTURER_GET_SOURCES = 'DESKTOP_CAPTURER_GET_SOURCES',
3331
}

lib/renderer/api/desktop-capturer.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)
X Tutup