Merge pull request #27858 from element-hq/t3chguy/fix-jitsi

Fix Jitsi by updating device mute updates over postMessage API
pull/27881/head
Michael Telatynski 2024-07-25 19:18:42 +00:00 committed by GitHub
commit 31345ddd36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 36 additions and 27 deletions

View File

@ -34,7 +34,6 @@ import type {
JitsiMeetExternalAPIConstructor, JitsiMeetExternalAPIConstructor,
ExternalAPIEventCallbacks, ExternalAPIEventCallbacks,
JitsiMeetExternalAPI as _JitsiMeetExternalAPI, JitsiMeetExternalAPI as _JitsiMeetExternalAPI,
AudioMuteStatusChangedEvent,
LogEvent, LogEvent,
VideoMuteStatusChangedEvent, VideoMuteStatusChangedEvent,
ExternalAPIOptions as _ExternalAPIOptions, ExternalAPIOptions as _ExternalAPIOptions,
@ -103,6 +102,14 @@ let widgetApi: WidgetApi | undefined;
let meetApi: _JitsiMeetExternalAPI | undefined; let meetApi: _JitsiMeetExternalAPI | undefined;
let skipOurWelcomeScreen = false; let skipOurWelcomeScreen = false;
async function checkAudioVideoEnabled(): Promise<[audioEnabled: boolean, videoEnabled: boolean]> {
if (!meetApi) return [false, false];
const [audioEnabled, videoEnabled] = (await Promise.all([meetApi.isAudioMuted(), meetApi.isVideoMuted()])).map(
(muted) => !muted,
);
return [audioEnabled, videoEnabled];
}
const setupCompleted = (async (): Promise<string | void> => { const setupCompleted = (async (): Promise<string | void> => {
try { try {
// Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with // Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with
@ -159,7 +166,7 @@ const setupCompleted = (async (): Promise<string | void> => {
const handleAction = ( const handleAction = (
action: WidgetApiAction, action: WidgetApiAction,
handler: (request: IWidgetApiRequestData) => Promise<void>, handler: (request: IWidgetApiRequestData) => Promise<IWidgetApiResponseData | void>,
): void => { ): void => {
widgetApi!.on(`action:${action}`, async (ev: CustomEvent<IWidgetApiRequest>) => { widgetApi!.on(`action:${action}`, async (ev: CustomEvent<IWidgetApiRequest>) => {
ev.preventDefault(); ev.preventDefault();
@ -167,8 +174,7 @@ const setupCompleted = (async (): Promise<string | void> => {
let response: IWidgetApiResponseData; let response: IWidgetApiResponseData;
try { try {
await handler(ev.detail.data); response = (await handler(ev.detail.data)) ?? {};
response = {};
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
response = { error: { message: e.message } }; response = { error: { message: e.message } };
@ -194,25 +200,26 @@ const setupCompleted = (async (): Promise<string | void> => {
meetApi?.executeCommand("hangup"); meetApi?.executeCommand("hangup");
} }
}); });
handleAction(ElementWidgetActions.MuteAudio, async () => { handleAction(ElementWidgetActions.DeviceMute, async (params) => {
if (meetApi && !(await meetApi.isAudioMuted())) { if (!meetApi) return;
const [audioEnabled, videoEnabled] = await checkAudioVideoEnabled();
if (Object.keys(params).length === 0) {
// Handle query
return {
audio_enabled: audioEnabled,
video_enabled: videoEnabled,
};
}
if (params.audio_enabled !== audioEnabled) {
meetApi.executeCommand("toggleAudio"); meetApi.executeCommand("toggleAudio");
} }
}); if (params.video_enabled !== videoEnabled) {
handleAction(ElementWidgetActions.UnmuteAudio, async () => {
if (meetApi && (await meetApi.isAudioMuted())) {
meetApi.executeCommand("toggleAudio");
}
});
handleAction(ElementWidgetActions.MuteVideo, async () => {
if (meetApi && !(await meetApi.isVideoMuted())) {
meetApi.executeCommand("toggleVideo");
}
});
handleAction(ElementWidgetActions.UnmuteVideo, async () => {
if (meetApi && (await meetApi.isVideoMuted())) {
meetApi.executeCommand("toggleVideo"); meetApi.executeCommand("toggleVideo");
} }
return params;
}); });
handleAction(ElementWidgetActions.TileLayout, async () => { handleAction(ElementWidgetActions.TileLayout, async () => {
meetApi?.executeCommand("setTileView", true); meetApi?.executeCommand("setTileView", true);
@ -473,7 +480,7 @@ async function joinConference(audioInput?: string | null, videoInput?: string |
meetApi.on("videoConferenceLeft", onVideoConferenceLeft); meetApi.on("videoConferenceLeft", onVideoConferenceLeft);
meetApi.on("readyToClose", closeConference as ExternalAPIEventCallbacks["readyToClose"]); meetApi.on("readyToClose", closeConference as ExternalAPIEventCallbacks["readyToClose"]);
meetApi.on("errorOccurred", onErrorOccurred); meetApi.on("errorOccurred", onErrorOccurred);
meetApi.on("audioMuteStatusChanged", onAudioMuteStatusChanged); meetApi.on("audioMuteStatusChanged", onMuteStatusChanged);
meetApi.on("videoMuteStatusChanged", onVideoMuteStatusChanged); meetApi.on("videoMuteStatusChanged", onVideoMuteStatusChanged);
(["videoConferenceJoined", "participantJoined", "participantLeft"] as const).forEach((event) => { (["videoConferenceJoined", "participantJoined", "participantLeft"] as const).forEach((event) => {
@ -523,9 +530,13 @@ const onErrorOccurred = ({ error }: Parameters<ExternalAPIEventCallbacks["errorO
} }
}; };
const onAudioMuteStatusChanged = ({ muted }: AudioMuteStatusChangedEvent): void => { const onMuteStatusChanged = async (): Promise<void> => {
const action = muted ? ElementWidgetActions.MuteAudio : ElementWidgetActions.UnmuteAudio; if (!meetApi) return;
void widgetApi?.transport.send(action, {}); const [audioEnabled, videoEnabled] = await checkAudioVideoEnabled();
void widgetApi?.transport.send(ElementWidgetActions.DeviceMute, {
audio_enabled: audioEnabled,
video_enabled: videoEnabled,
});
}; };
const onVideoMuteStatusChanged = ({ muted }: VideoMuteStatusChangedEvent): void => { const onVideoMuteStatusChanged = ({ muted }: VideoMuteStatusChangedEvent): void => {
@ -534,11 +545,9 @@ const onVideoMuteStatusChanged = ({ muted }: VideoMuteStatusChangedEvent): void
// hanging up, which we need to ignore by padding the timeout here, // hanging up, which we need to ignore by padding the timeout here,
// otherwise the React SDK will mistakenly think the user turned off // otherwise the React SDK will mistakenly think the user turned off
// their video by hand // their video by hand
setTimeout(() => { setTimeout(() => onMuteStatusChanged, 200);
if (meetApi) void widgetApi?.transport.send(ElementWidgetActions.MuteVideo, {});
}, 200);
} else { } else {
void widgetApi?.transport.send(ElementWidgetActions.UnmuteVideo, {}); void onMuteStatusChanged();
} }
}; };