Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 37e613b

Browse files
authored
Fix embedded Element Call screen sharing (#9485)
* Fix embedded Element Call screen sharing Makes it a request in each direction rather than a request and reply since replies to requests time out and so can't wait for user interaction. * Fix tests
1 parent e4c44dc commit 37e613b

File tree

3 files changed

+50
-20
lines changed

3 files changed

+50
-20
lines changed

src/models/Call.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ export class ElementCall extends Call {
816816
this.messaging!.on(`action:${ElementWidgetActions.HangupCall}`, this.onHangup);
817817
this.messaging!.on(`action:${ElementWidgetActions.TileLayout}`, this.onTileLayout);
818818
this.messaging!.on(`action:${ElementWidgetActions.SpotlightLayout}`, this.onSpotlightLayout);
819-
this.messaging!.on(`action:${ElementWidgetActions.Screenshare}`, this.onScreenshare);
819+
this.messaging!.on(`action:${ElementWidgetActions.ScreenshareRequest}`, this.onScreenshareRequest);
820820
}
821821

822822
protected async performDisconnection(): Promise<void> {
@@ -832,7 +832,7 @@ export class ElementCall extends Call {
832832
this.messaging!.off(`action:${ElementWidgetActions.HangupCall}`, this.onHangup);
833833
this.messaging!.off(`action:${ElementWidgetActions.TileLayout}`, this.onTileLayout);
834834
this.messaging!.off(`action:${ElementWidgetActions.SpotlightLayout}`, this.onSpotlightLayout);
835-
this.messaging!.off(`action:${ElementWidgetActions.Screenshare}`, this.onSpotlightLayout);
835+
this.messaging!.off(`action:${ElementWidgetActions.ScreenshareRequest}`, this.onScreenshareRequest);
836836
super.setDisconnected();
837837
}
838838

@@ -952,19 +952,24 @@ export class ElementCall extends Call {
952952
await this.messaging!.transport.reply(ev.detail, {}); // ack
953953
};
954954

955-
private onScreenshare = async (ev: CustomEvent<IWidgetApiRequest>) => {
955+
private onScreenshareRequest = async (ev: CustomEvent<IWidgetApiRequest>) => {
956956
ev.preventDefault();
957957

958958
if (PlatformPeg.get().supportsDesktopCapturer()) {
959+
await this.messaging!.transport.reply(ev.detail, { pending: true });
960+
959961
const { finished } = Modal.createDialog(DesktopCapturerSourcePicker);
960962
const [source] = await finished;
961963

962-
await this.messaging!.transport.reply(ev.detail, {
963-
failed: !source,
964-
desktopCapturerSourceId: source,
965-
});
964+
if (source) {
965+
await this.messaging!.transport.send(ElementWidgetActions.ScreenshareStart, {
966+
desktopCapturerSourceId: source,
967+
});
968+
} else {
969+
await this.messaging!.transport.send(ElementWidgetActions.ScreenshareStop, {});
970+
}
966971
} else {
967-
await this.messaging!.transport.reply(ev.detail, {});
972+
await this.messaging!.transport.reply(ev.detail, { pending: false });
968973
}
969974
};
970975
}

src/stores/widgets/ElementWidgetActions.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,23 @@ export enum ElementWidgetActions {
2626
MuteVideo = "io.element.mute_video",
2727
UnmuteVideo = "io.element.unmute_video",
2828
StartLiveStream = "im.vector.start_live_stream",
29+
30+
// Element Call -> host requesting to start a screenshare
31+
// (ie. expects a ScreenshareStart once the user has picked a source)
32+
// replies with { pending } where pending is true if the host has asked
33+
// the user to choose a window and false if not (ie. if the host isn't
34+
// running within Electron)
35+
ScreenshareRequest = "io.element.screenshare_request",
36+
// host -> Element Call telling EC to start screen sharing with
37+
// the given source
38+
ScreenshareStart = "io.element.screenshare_start",
39+
// host -> Element Call telling EC to stop screen sharing, or that
40+
// the user cancelled when selecting a source after a ScreenshareRequest
41+
ScreenshareStop = "io.element.screenshare_stop",
42+
2943
// Actions for switching layouts
3044
TileLayout = "io.element.tile_layout",
3145
SpotlightLayout = "io.element.spotlight_layout",
32-
Screenshare = "io.element.screenshare",
3346

3447
OpenIntegrationManager = "integration_manager_open",
3548

test/models/Call-test.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -820,19 +820,25 @@ describe("ElementCall", () => {
820820
await call.connect();
821821

822822
messaging.emit(
823-
`action:${ElementWidgetActions.Screenshare}`,
823+
`action:${ElementWidgetActions.ScreenshareRequest}`,
824824
new CustomEvent("widgetapirequest", { detail: {} }),
825825
);
826826

827-
waitFor(() => {
827+
await waitFor(() => {
828828
expect(messaging!.transport.reply).toHaveBeenCalledWith(
829829
expect.objectContaining({}),
830-
expect.objectContaining({ desktopCapturerSourceId: sourceId }),
830+
expect.objectContaining({ pending: true }),
831+
);
832+
});
833+
834+
await waitFor(() => {
835+
expect(messaging!.transport.send).toHaveBeenCalledWith(
836+
"io.element.screenshare_start", expect.objectContaining({ desktopCapturerSourceId: sourceId }),
831837
);
832838
});
833839
});
834840

835-
it("passes failed if we couldn't get a source id", async () => {
841+
it("sends ScreenshareStop if we couldn't get a source id", async () => {
836842
jest.spyOn(Modal, "createDialog").mockReturnValue(
837843
{ finished: new Promise((r) => r([null])) } as IHandle<any[]>,
838844
);
@@ -841,32 +847,38 @@ describe("ElementCall", () => {
841847
await call.connect();
842848

843849
messaging.emit(
844-
`action:${ElementWidgetActions.Screenshare}`,
850+
`action:${ElementWidgetActions.ScreenshareRequest}`,
845851
new CustomEvent("widgetapirequest", { detail: {} }),
846852
);
847853

848-
waitFor(() => {
854+
await waitFor(() => {
849855
expect(messaging!.transport.reply).toHaveBeenCalledWith(
850856
expect.objectContaining({}),
851-
expect.objectContaining({ failed: true }),
857+
expect.objectContaining({ pending: true }),
858+
);
859+
});
860+
861+
await waitFor(() => {
862+
expect(messaging!.transport.send).toHaveBeenCalledWith(
863+
"io.element.screenshare_stop", expect.objectContaining({ }),
852864
);
853865
});
854866
});
855867

856-
it("passes an empty object if we don't support desktop capturer", async () => {
868+
it("replies with pending: false if we don't support desktop capturer", async () => {
857869
jest.spyOn(PlatformPeg.get(), "supportsDesktopCapturer").mockReturnValue(false);
858870

859871
await call.connect();
860872

861873
messaging.emit(
862-
`action:${ElementWidgetActions.Screenshare}`,
874+
`action:${ElementWidgetActions.ScreenshareRequest}`,
863875
new CustomEvent("widgetapirequest", { detail: {} }),
864876
);
865877

866-
waitFor(() => {
878+
await waitFor(() => {
867879
expect(messaging!.transport.reply).toHaveBeenCalledWith(
868880
expect.objectContaining({}),
869-
expect.objectContaining({}),
881+
expect.objectContaining({ pending: false }),
870882
);
871883
});
872884
});

0 commit comments

Comments
 (0)