[MM-60227] Allow plugins to ask for desktop sources for screen sharing (#3135)
* Allow plugins to ask for desktop sources for screen sharing * Remove unnecessary logging in case of throwing errors * Remove more redundant logging
This commit is contained in:
parent
42a0bc4759
commit
d4e70db999
|
@ -556,7 +556,6 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
|
||||
describe('handleGetDesktopSources', () => {
|
||||
const callsWidgetWindow = new CallsWidgetWindow();
|
||||
callsWidgetWindow.options = {callID: 'callID'};
|
||||
callsWidgetWindow.win = {
|
||||
webContents: {
|
||||
send: jest.fn(),
|
||||
|
@ -618,6 +617,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
PermissionsManager.doPermissionRequest.mockReturnValue(Promise.resolve(true));
|
||||
ViewManager.getViewByWebContentsId.mockImplementation((id) => [...views.values()].find((view) => view.webContentsId === id));
|
||||
callsWidgetWindow.mainView = views.get('server-1_view-1');
|
||||
callsWidgetWindow.options = {callID: 'callID'};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -625,6 +625,34 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
callsWidgetWindow.missingScreensharePermissions = undefined;
|
||||
});
|
||||
|
||||
it('should send sources back - uninitialized', async () => {
|
||||
callsWidgetWindow.mainView = undefined;
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([
|
||||
{
|
||||
id: 'screen0',
|
||||
thumbnail: {
|
||||
toDataURL: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'window0',
|
||||
thumbnail: {
|
||||
toDataURL: jest.fn(),
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const sources = await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
expect(sources).toEqual([
|
||||
{
|
||||
id: 'screen0',
|
||||
},
|
||||
{
|
||||
id: 'window0',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should send sources back', async () => {
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([
|
||||
{
|
||||
|
@ -652,15 +680,28 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('should send error with no sources', async () => {
|
||||
it('should throw and send error with no sources', async () => {
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([]);
|
||||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
|
||||
await expect(callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null)).rejects.toThrow('permissions denied');
|
||||
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should send error with no permissions', async () => {
|
||||
it('should throw but not send calls error when uninitialized', async () => {
|
||||
callsWidgetWindow.options = undefined;
|
||||
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([]);
|
||||
|
||||
await expect(callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null)).rejects.toThrow('permissions denied');
|
||||
|
||||
expect(callsWidgetWindow.win.webContents.send).not.toHaveBeenCalled();
|
||||
expect(views.get('server-1_view-1').sendToRenderer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw and send error with no permissions', async () => {
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([
|
||||
{
|
||||
id: 'screen0',
|
||||
|
@ -671,7 +712,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
]);
|
||||
jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied');
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
await expect(callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null)).rejects.toThrow('permissions denied');
|
||||
|
||||
expect(systemPreferences.getMediaAccessStatus).toHaveBeenCalledWith('screen');
|
||||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
|
@ -680,6 +721,27 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw but not send error with no permissions when uninitialized', async () => {
|
||||
callsWidgetWindow.options = undefined;
|
||||
|
||||
jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([
|
||||
{
|
||||
id: 'screen0',
|
||||
thumbnail: {
|
||||
toDataURL: jest.fn(),
|
||||
},
|
||||
},
|
||||
]);
|
||||
jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied');
|
||||
|
||||
await expect(callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null)).rejects.toThrow('permissions denied');
|
||||
|
||||
expect(systemPreferences.getMediaAccessStatus).toHaveBeenCalledWith('screen');
|
||||
|
||||
expect(callsWidgetWindow.win.webContents.send).not.toHaveBeenCalled();
|
||||
expect(views.get('server-1_view-1').sendToRenderer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('macos - no permissions', async () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
|
@ -696,7 +758,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
]);
|
||||
jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied');
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
await expect(callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null)).rejects.toThrow('permissions denied');
|
||||
|
||||
expect(callsWidgetWindow.missingScreensharePermissions).toBe(true);
|
||||
expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(1);
|
||||
|
@ -704,7 +766,7 @@ describe('main/windows/callsWidgetWindow', () => {
|
|||
expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', 'screen-permissions', 'callID');
|
||||
|
||||
await callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null);
|
||||
await expect(callsWidgetWindow.handleGetDesktopSources({sender: {id: 1}}, null)).rejects.toThrow('permissions denied');
|
||||
|
||||
expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(2);
|
||||
expect(openScreensharePermissionsSettingsMacOS).toHaveBeenCalledTimes(1);
|
||||
|
|
|
@ -378,15 +378,15 @@ export class CallsWidgetWindow {
|
|||
private handleGetDesktopSources = async (event: IpcMainInvokeEvent, opts: Electron.SourcesOptions) => {
|
||||
log.debug('handleGetDesktopSources', opts);
|
||||
|
||||
if (event.sender.id !== this.mainView?.webContentsId) {
|
||||
log.warn('handleGetDesktopSources', 'Blocked on wrong webContentsId');
|
||||
return [];
|
||||
// For Calls we make an extra check to ensure the event is coming from the expected window (main view).
|
||||
// Otherwise we want to allow for other plugins to ask for screen sharing sources.
|
||||
if (this.mainView && event.sender.id !== this.mainView.webContentsId) {
|
||||
throw new Error('handleGetDesktopSources: blocked on wrong webContentsId');
|
||||
}
|
||||
|
||||
const view = ViewManager.getViewByWebContentsId(event.sender.id);
|
||||
if (!view) {
|
||||
log.error('handleGetDesktopSources: view not found');
|
||||
return [];
|
||||
throw new Error('handleGetDesktopSources: view not found');
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin' && systemPreferences.getMediaAccessStatus('screen') === 'denied') {
|
||||
|
@ -407,8 +407,7 @@ export class CallsWidgetWindow {
|
|||
}
|
||||
|
||||
if (!await PermissionsManager.doPermissionRequest(view.webContentsId, 'screenShare', {requestingUrl: view.view.server.url.toString(), isMainFrame: false})) {
|
||||
log.warn('screen share permissions disallowed', view.webContentsId, view.view.server.url.toString());
|
||||
return [];
|
||||
throw new Error('permissions denied');
|
||||
}
|
||||
|
||||
const screenPermissionsErrArgs = ['screen-permissions', this.callID];
|
||||
|
@ -425,10 +424,7 @@ export class CallsWidgetWindow {
|
|||
}
|
||||
|
||||
if (!hasScreenPermissions || !sources.length) {
|
||||
log.info('missing screen permissions');
|
||||
view.sendToRenderer(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
this.win?.webContents.send(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
return [];
|
||||
throw new Error('handleGetDesktopSources: permissions denied');
|
||||
}
|
||||
|
||||
const message = sources.map((source) => {
|
||||
|
@ -441,12 +437,14 @@ export class CallsWidgetWindow {
|
|||
|
||||
return message;
|
||||
}).catch((err) => {
|
||||
log.error('desktopCapturer.getSources failed', err);
|
||||
|
||||
// Only send calls error if this window has been initialized (i.e. we are in a call).
|
||||
// The rest of the logic is shared so that other plugins can request screen sources.
|
||||
if (this.callID) {
|
||||
view.sendToRenderer(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
this.win?.webContents.send(CALLS_ERROR, ...screenPermissionsErrArgs);
|
||||
}
|
||||
|
||||
return [];
|
||||
throw new Error(`handleGetDesktopSources: desktopCapturer.getSources failed: ${err}`);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue