desktop-capturer.ts 2.5 KB

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