diff options
author | 2024-05-02 17:38:48 +0100 | |
---|---|---|
committer | 2024-05-02 17:38:48 +0100 | |
commit | 92d845adc3c07bcea290eb6fefe0a998cd8f7a98 (patch) | |
tree | 1133efe2b1bd9f678cf912bb83f87e8e005bf1f1 /src/webview/screenshare.ts | |
parent | Upgrade electron to '30.0.2' (diff) | |
download | ferdium-app-92d845adc3c07bcea290eb6fefe0a998cd8f7a98.tar.gz ferdium-app-92d845adc3c07bcea290eb6fefe0a998cd8f7a98.tar.zst ferdium-app-92d845adc3c07bcea290eb6fefe0a998cd8f7a98.zip |
fix: screenshare feature not working on Teams (#1733)
Diffstat (limited to 'src/webview/screenshare.ts')
-rw-r--r-- | src/webview/screenshare.ts | 154 |
1 files changed, 28 insertions, 126 deletions
diff --git a/src/webview/screenshare.ts b/src/webview/screenshare.ts index e631ce52f..521f95bd6 100644 --- a/src/webview/screenshare.ts +++ b/src/webview/screenshare.ts | |||
@@ -1,139 +1,41 @@ | |||
1 | import { ipcRenderer } from 'electron'; | 1 | import { ipcRenderer } from 'electron'; |
2 | import { v4 as uuidV4 } from 'uuid'; | ||
2 | 3 | ||
3 | const CANCEL_ID = 'desktop-capturer-selection__cancel'; | 4 | const debug = require('../preload-safe-debug')('Ferdium:Screenshare'); |
4 | 5 | ||
5 | export async function getDisplayMediaSelector() { | 6 | export async function getDisplayMediaSelector() { |
6 | const sources = await ipcRenderer.invoke('get-desktop-capturer-sources'); | 7 | return new Promise((resolve, reject) => { |
7 | return `<div class="desktop-capturer-selection__scroller"> | 8 | const trackerId = uuidV4(); |
8 | <ul class="desktop-capturer-selection__list"> | 9 | debug('New screenshare request', trackerId); |
9 | ${sources | ||
10 | .map( | ||
11 | ({ id, name, thumbnail }) => ` | ||
12 | <li class="desktop-capturer-selection__item"> | ||
13 | <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> | ||
14 | <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> | ||
15 | <span class="desktop-capturer-selection__name">${name}</span> | ||
16 | </button> | ||
17 | </li> | ||
18 | `, | ||
19 | ) | ||
20 | .join('')} | ||
21 | <li class="desktop-capturer-selection__item"> | ||
22 | <button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel"> | ||
23 | <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span> | ||
24 | </button> | ||
25 | </li> | ||
26 | </ul> | ||
27 | </div>`; | ||
28 | } | ||
29 | 10 | ||
30 | export const screenShareCss = ` | 11 | ipcRenderer.sendToHost('load-available-displays', { |
31 | .desktop-capturer-selection { | 12 | trackerId, |
32 | position: fixed; | 13 | }); |
33 | top: 0; | 14 | |
34 | left: 0; | 15 | ipcRenderer.once(`selected-media-source:${trackerId}`, (_e, data) => { |
35 | width: 100%; | 16 | if (data.mediaSourceId === 'desktop-capturer-selection__cancel') { |
36 | height: 100vh; | 17 | return reject(new Error('Cancelled by user')); |
37 | background: rgba(30,30,30,.75); | 18 | } |
38 | color: #fff; | 19 | |
39 | z-index: 10000000; | 20 | return resolve(data.mediaSourceId); |
40 | display: flex; | 21 | }); |
41 | align-items: center; | 22 | }); |
42 | justify-content: center; | ||
43 | } | ||
44 | .desktop-capturer-selection__scroller { | ||
45 | width: 100%; | ||
46 | max-height: 100vh; | ||
47 | overflow-y: auto; | ||
48 | } | ||
49 | .desktop-capturer-selection__list { | ||
50 | max-width: calc(100% - 100px); | ||
51 | margin: 50px; | ||
52 | padding: 0; | ||
53 | display: flex; | ||
54 | flex-wrap: wrap; | ||
55 | list-style: none; | ||
56 | overflow: hidden; | ||
57 | justify-content: center; | ||
58 | } | ||
59 | .desktop-capturer-selection__item { | ||
60 | display: flex; | ||
61 | margin: 4px; | ||
62 | } | ||
63 | .desktop-capturer-selection__btn { | ||
64 | display: flex; | ||
65 | flex-direction: column; | ||
66 | align-items: stretch; | ||
67 | width: 145px; | ||
68 | margin: 0; | ||
69 | border: 0; | ||
70 | border-radius: 3px; | ||
71 | padding: 4px; | ||
72 | background: #252626; | ||
73 | text-align: left; | ||
74 | @media (prefers-reduced-motion: no-preference) { | ||
75 | transition: background-color .15s, box-shadow .15s, color .15s; | ||
76 | } | ||
77 | color: #dedede; | ||
78 | } | ||
79 | .desktop-capturer-selection__btn:hover, | ||
80 | .desktop-capturer-selection__btn:focus { | ||
81 | background: rgba(98,100,167,.8); | ||
82 | box-shadow: 0 0 4px rgba(0,0,0,0.45), 0 0 2px rgba(0,0,0,0.25); | ||
83 | color: #fff; | ||
84 | } | ||
85 | .desktop-capturer-selection__thumbnail { | ||
86 | width: 100%; | ||
87 | height: 81px; | ||
88 | object-fit: cover; | ||
89 | } | ||
90 | .desktop-capturer-selection__name { | ||
91 | margin: 6px 0; | ||
92 | white-space: nowrap; | ||
93 | text-overflow: ellipsis; | ||
94 | text-align: center; | ||
95 | overflow: hidden; | ||
96 | } | ||
97 | .desktop-capturer-selection__name--cancel { | ||
98 | margin: auto 0; | ||
99 | } | 23 | } |
100 | `; | ||
101 | 24 | ||
102 | export const screenShareJs = ` | 25 | export const screenShareJs = ` |
103 | window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve, reject) => { | 26 | window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve, reject) => { |
104 | try { | 27 | try { |
105 | const selectionElem = document.createElement('div'); | 28 | const displayId = await window.ferdium.getDisplayMediaSelector(); |
106 | selectionElem.classList = ['desktop-capturer-selection']; | 29 | const stream = await window.navigator.mediaDevices.getUserMedia({ |
107 | selectionElem.innerHTML = await window.ferdium.getDisplayMediaSelector(); | 30 | audio: false, |
108 | document.body.appendChild(selectionElem); | 31 | video: { |
109 | 32 | mandatory: { | |
110 | document | 33 | chromeMediaSource: 'desktop', |
111 | .querySelectorAll('.desktop-capturer-selection__btn') | 34 | chromeMediaSourceId: displayId, |
112 | .forEach((button) => { | 35 | }, |
113 | button.addEventListener('click', async () => { | 36 | }, |
114 | try { | 37 | }); |
115 | const id = button.getAttribute('data-id'); | 38 | resolve(stream); |
116 | if (id === '${CANCEL_ID}') { | ||
117 | reject(new Error('Cancelled by user')); | ||
118 | } else { | ||
119 | const stream = await window.navigator.mediaDevices.getUserMedia({ | ||
120 | audio: false, | ||
121 | video: { | ||
122 | mandatory: { | ||
123 | chromeMediaSource: 'desktop', | ||
124 | chromeMediaSourceId: id, | ||
125 | }, | ||
126 | }, | ||
127 | }); | ||
128 | resolve(stream); | ||
129 | } | ||
130 | } catch (err) { | ||
131 | reject(err); | ||
132 | } finally { | ||
133 | selectionElem.remove(); | ||
134 | } | ||
135 | }); | ||
136 | }); | ||
137 | } catch (err) { | 39 | } catch (err) { |
138 | reject(err); | 40 | reject(err); |
139 | } | 41 | } |