Skip to content

Commit 31345dd

Browse files
authored
Merge pull request #27858 from element-hq/t3chguy/fix-jitsi
Fix Jitsi by updating device mute updates over postMessage API
2 parents 334d268 + 88ddf05 commit 31345dd

File tree

1 file changed

+35
-26
lines changed

1 file changed

+35
-26
lines changed

src/vector/jitsi/index.ts

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import type {
3434
JitsiMeetExternalAPIConstructor,
3535
ExternalAPIEventCallbacks,
3636
JitsiMeetExternalAPI as _JitsiMeetExternalAPI,
37-
AudioMuteStatusChangedEvent,
3837
LogEvent,
3938
VideoMuteStatusChangedEvent,
4039
ExternalAPIOptions as _ExternalAPIOptions,
@@ -103,6 +102,14 @@ let widgetApi: WidgetApi | undefined;
103102
let meetApi: _JitsiMeetExternalAPI | undefined;
104103
let skipOurWelcomeScreen = false;
105104

105+
async function checkAudioVideoEnabled(): Promise<[audioEnabled: boolean, videoEnabled: boolean]> {
106+
if (!meetApi) return [false, false];
107+
const [audioEnabled, videoEnabled] = (await Promise.all([meetApi.isAudioMuted(), meetApi.isVideoMuted()])).map(
108+
(muted) => !muted,
109+
);
110+
return [audioEnabled, videoEnabled];
111+
}
112+
106113
const setupCompleted = (async (): Promise<string | void> => {
107114
try {
108115
// Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with
@@ -159,16 +166,15 @@ const setupCompleted = (async (): Promise<string | void> => {
159166

160167
const handleAction = (
161168
action: WidgetApiAction,
162-
handler: (request: IWidgetApiRequestData) => Promise<void>,
169+
handler: (request: IWidgetApiRequestData) => Promise<IWidgetApiResponseData | void>,
163170
): void => {
164171
widgetApi!.on(`action:${action}`, async (ev: CustomEvent<IWidgetApiRequest>) => {
165172
ev.preventDefault();
166173
await setupCompleted;
167174

168175
let response: IWidgetApiResponseData;
169176
try {
170-
await handler(ev.detail.data);
171-
response = {};
177+
response = (await handler(ev.detail.data)) ?? {};
172178
} catch (e) {
173179
if (e instanceof Error) {
174180
response = { error: { message: e.message } };
@@ -194,25 +200,26 @@ const setupCompleted = (async (): Promise<string | void> => {
194200
meetApi?.executeCommand("hangup");
195201
}
196202
});
197-
handleAction(ElementWidgetActions.MuteAudio, async () => {
198-
if (meetApi && !(await meetApi.isAudioMuted())) {
199-
meetApi.executeCommand("toggleAudio");
203+
handleAction(ElementWidgetActions.DeviceMute, async (params) => {
204+
if (!meetApi) return;
205+
206+
const [audioEnabled, videoEnabled] = await checkAudioVideoEnabled();
207+
208+
if (Object.keys(params).length === 0) {
209+
// Handle query
210+
return {
211+
audio_enabled: audioEnabled,
212+
video_enabled: videoEnabled,
213+
};
200214
}
201-
});
202-
handleAction(ElementWidgetActions.UnmuteAudio, async () => {
203-
if (meetApi && (await meetApi.isAudioMuted())) {
215+
216+
if (params.audio_enabled !== audioEnabled) {
204217
meetApi.executeCommand("toggleAudio");
205218
}
206-
});
207-
handleAction(ElementWidgetActions.MuteVideo, async () => {
208-
if (meetApi && !(await meetApi.isVideoMuted())) {
209-
meetApi.executeCommand("toggleVideo");
210-
}
211-
});
212-
handleAction(ElementWidgetActions.UnmuteVideo, async () => {
213-
if (meetApi && (await meetApi.isVideoMuted())) {
219+
if (params.video_enabled !== videoEnabled) {
214220
meetApi.executeCommand("toggleVideo");
215221
}
222+
return params;
216223
});
217224
handleAction(ElementWidgetActions.TileLayout, async () => {
218225
meetApi?.executeCommand("setTileView", true);
@@ -473,7 +480,7 @@ async function joinConference(audioInput?: string | null, videoInput?: string |
473480
meetApi.on("videoConferenceLeft", onVideoConferenceLeft);
474481
meetApi.on("readyToClose", closeConference as ExternalAPIEventCallbacks["readyToClose"]);
475482
meetApi.on("errorOccurred", onErrorOccurred);
476-
meetApi.on("audioMuteStatusChanged", onAudioMuteStatusChanged);
483+
meetApi.on("audioMuteStatusChanged", onMuteStatusChanged);
477484
meetApi.on("videoMuteStatusChanged", onVideoMuteStatusChanged);
478485

479486
(["videoConferenceJoined", "participantJoined", "participantLeft"] as const).forEach((event) => {
@@ -523,9 +530,13 @@ const onErrorOccurred = ({ error }: Parameters<ExternalAPIEventCallbacks["errorO
523530
}
524531
};
525532

526-
const onAudioMuteStatusChanged = ({ muted }: AudioMuteStatusChangedEvent): void => {
527-
const action = muted ? ElementWidgetActions.MuteAudio : ElementWidgetActions.UnmuteAudio;
528-
void widgetApi?.transport.send(action, {});
533+
const onMuteStatusChanged = async (): Promise<void> => {
534+
if (!meetApi) return;
535+
const [audioEnabled, videoEnabled] = await checkAudioVideoEnabled();
536+
void widgetApi?.transport.send(ElementWidgetActions.DeviceMute, {
537+
audio_enabled: audioEnabled,
538+
video_enabled: videoEnabled,
539+
});
529540
};
530541

531542
const onVideoMuteStatusChanged = ({ muted }: VideoMuteStatusChangedEvent): void => {
@@ -534,11 +545,9 @@ const onVideoMuteStatusChanged = ({ muted }: VideoMuteStatusChangedEvent): void
534545
// hanging up, which we need to ignore by padding the timeout here,
535546
// otherwise the React SDK will mistakenly think the user turned off
536547
// their video by hand
537-
setTimeout(() => {
538-
if (meetApi) void widgetApi?.transport.send(ElementWidgetActions.MuteVideo, {});
539-
}, 200);
548+
setTimeout(() => onMuteStatusChanged, 200);
540549
} else {
541-
void widgetApi?.transport.send(ElementWidgetActions.UnmuteVideo, {});
550+
void onMuteStatusChanged();
542551
}
543552
};
544553

0 commit comments

Comments
 (0)