desktop-capturer.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { EventEmitter } from 'events';
  2. const { createDesktopCapturer } = process.electronBinding('desktop_capturer');
  3. const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);
  4. let currentlyRunning: {
  5. options: ElectronInternal.GetSourcesOptions;
  6. getSources: Promise<ElectronInternal.GetSourcesResult[]>;
  7. }[] = [];
  8. export const getSources = (event: Electron.IpcMainEvent, options: ElectronInternal.GetSourcesOptions) => {
  9. for (const running of currentlyRunning) {
  10. if (deepEqual(running.options, options)) {
  11. // If a request is currently running for the same options
  12. // return that promise
  13. return running.getSources;
  14. }
  15. }
  16. const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
  17. let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer();
  18. const stopRunning = () => {
  19. if (capturer) {
  20. capturer.emit = null;
  21. capturer = null;
  22. }
  23. // Remove from currentlyRunning once we resolve or reject
  24. currentlyRunning = currentlyRunning.filter(running => running.options !== options);
  25. };
  26. const emitter = new EventEmitter();
  27. emitter.once('error', (event, error: string) => {
  28. stopRunning();
  29. reject(error);
  30. });
  31. emitter.once('finished', (event, sources: Electron.DesktopCapturerSource[], fetchWindowIcons: boolean) => {
  32. stopRunning();
  33. resolve(sources.map(source => ({
  34. id: source.id,
  35. name: source.name,
  36. thumbnail: source.thumbnail.toDataURL(),
  37. display_id: source.display_id,
  38. appIcon: (fetchWindowIcons && source.appIcon) ? source.appIcon.toDataURL() : null
  39. })));
  40. });
  41. capturer.emit = emitter.emit.bind(emitter);
  42. capturer.startHandling(options.captureWindow, options.captureScreen, options.thumbnailSize, options.fetchWindowIcons);
  43. // If the WebContents is destroyed before receiving result, just remove the
  44. // reference to emit and the capturer itself so that it never dispatches
  45. // back to the renderer
  46. event.sender.once('destroyed', () => stopRunning());
  47. });
  48. currentlyRunning.push({
  49. options,
  50. getSources
  51. });
  52. return getSources;
  53. };