From d5269e881a25d68e78a70e625fd6d3a697101219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 2 Oct 2024 18:59:04 -0500 Subject: [PATCH] fix(transcribing): Handle transcriber status changed. * fix(subtitles): Handle errors to revert to default state. * fix(transcribing): Handle transcriber status changed. Drops potential transcribers and hidden participant actions and handling. Expect ljm to detect transcriptions on and off. * feat(transcriptions): Adds a notification if transcriber leaves abruptly. * squash: Renames action. * chore(deps) lib-jitsi-meet@latest https://github.com/jitsi/lib-jitsi-meet/compare/v1869.0.0+5671c5d6...v1872.0.0+8940b5c9 --- conference.js | 11 ++++ config.js | 2 +- lang/main.json | 2 +- package-lock.json | 10 ++-- package.json | 2 +- react/features/base/conference/actions.any.ts | 13 ++++- react/features/base/conference/functions.ts | 10 +--- .../features/base/participants/actionTypes.ts | 22 -------- react/features/base/participants/actions.ts | 38 -------------- react/features/subtitles/middleware.ts | 2 +- react/features/subtitles/reducer.ts | 6 +++ react/features/transcribing/actionTypes.ts | 16 +----- react/features/transcribing/actions.ts | 39 +++++---------- react/features/transcribing/middleware.ts | 50 ++++--------------- react/features/transcribing/reducer.ts | 30 +++-------- 15 files changed, 71 insertions(+), 182 deletions(-) diff --git a/conference.js b/conference.js index 4af2765d6c20..7002521aefc6 100644 --- a/conference.js +++ b/conference.js @@ -164,6 +164,7 @@ import { toggleScreenshotCaptureSummary } from './react/features/screenshot-capt import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect'; import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise'; import { handleToggleVideoMuted } from './react/features/toolbox/actions.any'; +import { transcriberJoined, transcriberLeft } from './react/features/transcribing/actions'; import { muteLocal } from './react/features/video-menu/actions.any'; const logger = Logger.getLogger(__filename); @@ -1684,6 +1685,16 @@ export default { } ); + room.on( + JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED, + (status, id, abruptly) => { + if (status === JitsiMeetJS.constants.transcriptionStatus.ON) { + APP.store.dispatch(transcriberJoined(id)); + } else if (status === JitsiMeetJS.constants.transcriptionStatus.OFF) { + APP.store.dispatch(transcriberLeft(id, abruptly)); + } + }); + room.on( JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (participant, data) => { diff --git a/config.js b/config.js index f8ea743d0563..090ab2947656 100644 --- a/config.js +++ b/config.js @@ -1721,7 +1721,7 @@ var config = { // 'toolbar.noAudioSignalTitle', // shown when a broken mic is detected // 'toolbar.noisyAudioInputTitle', // shown when noise is detected for the current microphone // 'toolbar.talkWhileMutedPopup', // shown when user tries to speak while muted - // 'transcribing.failedToStart', // shown when transcribing fails to start + // 'transcribing.failed', // shown when transcribing fails // ], // List of notifications to be disabled. Works in tandem with the above setting. diff --git a/lang/main.json b/lang/main.json index ff1991b6f842..1cd5e33fe276 100644 --- a/lang/main.json +++ b/lang/main.json @@ -1390,7 +1390,7 @@ "transcribing": { "ccButtonTooltip": "Start / Stop subtitles", "expandedLabel": "Transcribing is currently on", - "failedToStart": "Transcribing failed to start", + "failed": "Transcribing failed", "labelToolTip": "The meeting is being transcribed", "sourceLanguageDesc": "Currently the meeting language is set to {{sourceLanguage}}.
You can change it from ", "sourceLanguageHere": "here", diff --git a/package-lock.json b/package-lock.json index 3a2c5f0d76e6..c51fd29f96d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "js-md5": "0.6.1", "js-sha512": "0.8.0", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1869.0.0+5671c5d6/lib-jitsi-meet.tgz", + "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1872.0.0+8940b5c9/lib-jitsi-meet.tgz", "lodash-es": "4.17.21", "moment": "2.29.4", "moment-duration-format": "2.2.2", @@ -12498,8 +12498,8 @@ }, "node_modules/lib-jitsi-meet": { "version": "0.0.0", - "resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1869.0.0+5671c5d6/lib-jitsi-meet.tgz", - "integrity": "sha512-s2bAk8lq1SU/oQQxI9NTP2xOWI0yHFaFB7WjzL1E0gn6ntoaTH0FN1KQmJctfGGzm71I3lXy6SwgNHwi8hEtHA==", + "resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1872.0.0+8940b5c9/lib-jitsi-meet.tgz", + "integrity": "sha512-/pcCiU7XguZ9ooOQ/HSQhU52kG3mvGtD15TWMsH/fbJwHG8Vt6TOA0DECyK/8xkPnRy1VCI7qt2e6zhk7VBgUA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -28005,8 +28005,8 @@ } }, "lib-jitsi-meet": { - "version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1869.0.0+5671c5d6/lib-jitsi-meet.tgz", - "integrity": "sha512-s2bAk8lq1SU/oQQxI9NTP2xOWI0yHFaFB7WjzL1E0gn6ntoaTH0FN1KQmJctfGGzm71I3lXy6SwgNHwi8hEtHA==", + "version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1872.0.0+8940b5c9/lib-jitsi-meet.tgz", + "integrity": "sha512-/pcCiU7XguZ9ooOQ/HSQhU52kG3mvGtD15TWMsH/fbJwHG8Vt6TOA0DECyK/8xkPnRy1VCI7qt2e6zhk7VBgUA==", "requires": { "@jitsi/js-utils": "2.2.1", "@jitsi/logger": "2.0.2", diff --git a/package.json b/package.json index d3e6603d324a..974847bf2d80 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "js-md5": "0.6.1", "js-sha512": "0.8.0", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1869.0.0+5671c5d6/lib-jitsi-meet.tgz", + "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1872.0.0+8940b5c9/lib-jitsi-meet.tgz", "lodash-es": "4.17.21", "moment": "2.29.4", "moment-duration-format": "2.2.2", diff --git a/react/features/base/conference/actions.any.ts b/react/features/base/conference/actions.any.ts index 38fbed313100..0b2f94db1eb6 100644 --- a/react/features/base/conference/actions.any.ts +++ b/react/features/base/conference/actions.any.ts @@ -1,6 +1,7 @@ import { createStartMutedConfigurationEvent } from '../../analytics/AnalyticsEvents'; import { sendAnalytics } from '../../analytics/functions'; import { IReduxState, IStore } from '../../app/types'; +import { transcriberJoined, transcriberLeft } from '../../transcribing/actions'; import { setIAmVisitor } from '../../visitors/actions'; import { iAmVisitor } from '../../visitors/functions'; import { overwriteConfig } from '../config/actions'; @@ -8,7 +9,7 @@ import { getReplaceParticipant } from '../config/functions'; import { connect, disconnect, hangup } from '../connection/actions'; import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection/constants'; import { hasAvailableDevices } from '../devices/functions.any'; -import { JitsiConferenceEvents, JitsiE2ePingEvents } from '../lib-jitsi-meet'; +import JitsiMeetJS, { JitsiConferenceEvents, JitsiE2ePingEvents } from '../lib-jitsi-meet'; import { setAudioMuted, setAudioUnmutePermissions, @@ -276,6 +277,16 @@ function _addConferenceListeners(conference: IJitsiConference, dispatch: IStore[ botType }))); + conference.on( + JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED, + (status: string, id: string, abruptly: boolean) => { + if (status === JitsiMeetJS.constants.transcriptionStatus.ON) { + dispatch(transcriberJoined(id)); + } else if (status === JitsiMeetJS.constants.transcriptionStatus.OFF) { + dispatch(transcriberLeft(id, abruptly)); + } + }); + conference.addCommandListener( AVATAR_URL_COMMAND, (data: { value: string; }, id: string) => { diff --git a/react/features/base/conference/functions.ts b/react/features/base/conference/functions.ts index 14d86e281562..a080fe792d57 100644 --- a/react/features/base/conference/functions.ts +++ b/react/features/base/conference/functions.ts @@ -7,8 +7,6 @@ import { determineTranscriptionLanguage } from '../../transcribing/functions'; import { IStateful } from '../app/types'; import { JitsiTrackErrors } from '../lib-jitsi-meet'; import { - hiddenParticipantJoined, - hiddenParticipantLeft, participantJoined, participantLeft } from '../participants/actions'; @@ -85,9 +83,7 @@ export function commonUserJoinedHandling( const id = user.getId(); const displayName = user.getDisplayName(); - if (user.isHidden()) { - dispatch(hiddenParticipantJoined(id, displayName)); - } else { + if (!user.isHidden()) { const isReplacing = user?.isReplacing(); // the identity and avatar come from jwt and never change in the presence @@ -122,9 +118,7 @@ export function commonUserLeftHandling( user: any) { const id = user.getId(); - if (user.isHidden()) { - dispatch(hiddenParticipantLeft(id)); - } else { + if (!user.isHidden()) { const isReplaced = user.isReplaced?.(); dispatch(participantLeft(id, conference, { isReplaced })); diff --git a/react/features/base/participants/actionTypes.ts b/react/features/base/participants/actionTypes.ts index 3e48e734e900..b34cfa650e10 100644 --- a/react/features/base/participants/actionTypes.ts +++ b/react/features/base/participants/actionTypes.ts @@ -146,28 +146,6 @@ export const PARTICIPANT_UPDATED = 'PARTICIPANT_UPDATED'; */ export const PIN_PARTICIPANT = 'PIN_PARTICIPANT'; -/** - * Action to signal that a hidden participant has joined. - * - * { - * type: HIDDEN_PARTICIPANT_JOINED, - * participant: Participant - * } - */ -export const HIDDEN_PARTICIPANT_JOINED = 'HIDDEN_PARTICIPANT_JOINED'; - -/** - * Action to handle case when hidden participant leaves. - * - * { - * type: PARTICIPANT_LEFT, - * participant: { - * id: string - * } - * } - */ -export const HIDDEN_PARTICIPANT_LEFT = 'HIDDEN_PARTICIPANT_LEFT'; - /** * The type of Redux action which notifies the app that the loadable avatar URL has changed. * diff --git a/react/features/base/participants/actions.ts b/react/features/base/participants/actions.ts index 50e592454511..f9c041aff730 100644 --- a/react/features/base/participants/actions.ts +++ b/react/features/base/participants/actions.ts @@ -7,8 +7,6 @@ import { set } from '../redux/functions'; import { DOMINANT_SPEAKER_CHANGED, GRANT_MODERATOR, - HIDDEN_PARTICIPANT_JOINED, - HIDDEN_PARTICIPANT_LEFT, KICK_PARTICIPANT, LOCAL_PARTICIPANT_AUDIO_LEVEL_CHANGED, LOCAL_PARTICIPANT_RAISE_HAND, @@ -331,42 +329,6 @@ export function updateRemoteParticipantFeatures(jitsiParticipant: any) { }; } -/** - * Action to signal that a hidden participant has joined the conference. - * - * @param {string} id - The id of the participant. - * @param {string} displayName - The display name, or undefined when - * unknown. - * @returns {{ - * type: HIDDEN_PARTICIPANT_JOINED, - * displayName: string, - * id: string - * }} - */ -export function hiddenParticipantJoined(id: string, displayName: string) { - return { - type: HIDDEN_PARTICIPANT_JOINED, - id, - displayName - }; -} - -/** - * Action to signal that a hidden participant has left the conference. - * - * @param {string} id - The id of the participant. - * @returns {{ - * type: HIDDEN_PARTICIPANT_LEFT, - * id: string - * }} - */ -export function hiddenParticipantLeft(id: string) { - return { - type: HIDDEN_PARTICIPANT_LEFT, - id - }; -} - /** * Action to signal that a participant has left. * diff --git a/react/features/subtitles/middleware.ts b/react/features/subtitles/middleware.ts index 16d3795bfc7a..35231b51c2e0 100644 --- a/react/features/subtitles/middleware.ts +++ b/react/features/subtitles/middleware.ts @@ -259,7 +259,7 @@ function _requestingSubtitlesChange( logger.error('Error dialing', e); // let's back to the correct state - dispatch(setRequestingSubtitles(false, false)); + dispatch(setRequestingSubtitles(false, false, null)); }); } } diff --git a/react/features/subtitles/reducer.ts b/react/features/subtitles/reducer.ts index 1a679a14e76c..437a55b21aa0 100644 --- a/react/features/subtitles/reducer.ts +++ b/react/features/subtitles/reducer.ts @@ -1,4 +1,5 @@ import ReducerRegistry from '../base/redux/ReducerRegistry'; +import { TRANSCRIBER_LEFT } from '../transcribing/actionTypes'; import { REMOVE_TRANSCRIPT_MESSAGE, @@ -48,6 +49,11 @@ ReducerRegistry.register('features/subtitles', ( ...state, _requestingSubtitles: !state._requestingSubtitles }; + case TRANSCRIBER_LEFT: + return { + ...state, + ...defaultState + }; } return state; diff --git a/react/features/transcribing/actionTypes.ts b/react/features/transcribing/actionTypes.ts index f777d233670d..e5da70b8ee35 100644 --- a/react/features/transcribing/actionTypes.ts +++ b/react/features/transcribing/actionTypes.ts @@ -8,7 +8,7 @@ * } * @private */ -export const _TRANSCRIBER_JOINED = 'TRANSCRIBER_JOINED'; +export const TRANSCRIBER_JOINED = 'TRANSCRIBER_JOINED'; /** * The type of Redux action signalling that the transcriber has left @@ -19,16 +19,4 @@ export const _TRANSCRIBER_JOINED = 'TRANSCRIBER_JOINED'; * } * @private */ -export const _TRANSCRIBER_LEFT = 'TRANSCRIBER_LEFT'; - -/** - * The type of a Redux action signalling that a hidden participant has joined, - * which can be candidate for being a transcriber. - * - * { - * type: _POTENTIAL_TRANSCRIBER_JOINED, - * } - * @private - */ -export const _POTENTIAL_TRANSCRIBER_JOINED - = 'POTENTIAL_TRANSCRIBER_JOINED'; +export const TRANSCRIBER_LEFT = 'TRANSCRIBER_LEFT'; diff --git a/react/features/transcribing/actions.ts b/react/features/transcribing/actions.ts index 2c2ecc06d064..e95a0f048a28 100644 --- a/react/features/transcribing/actions.ts +++ b/react/features/transcribing/actions.ts @@ -1,7 +1,6 @@ import { - _POTENTIAL_TRANSCRIBER_JOINED, - _TRANSCRIBER_JOINED, - _TRANSCRIBER_LEFT + TRANSCRIBER_JOINED, + TRANSCRIBER_LEFT } from './actionTypes'; /** @@ -9,13 +8,13 @@ import { * * @param {string} participantId - The participant id of the transcriber. * @returns {{ - * type: _TRANSCRIBER_JOINED, + * type: TRANSCRIBER_JOINED, * participantId: string * }} */ export function transcriberJoined(participantId: string) { return { - type: _TRANSCRIBER_JOINED, + type: TRANSCRIBER_JOINED, transcriberJID: participantId }; } @@ -24,30 +23,18 @@ export function transcriberJoined(participantId: string) { * Notify that the transcriber, with a unique ID, has left. * * @param {string} participantId - The participant id of the transcriber. + * @param {boolean} abruptly - The transcriber did not exit the conference gracefully with switching off first. + * It maybe there was some backend problem, like network. * @returns {{ - * type: _TRANSCRIBER_LEFT, - * participantId: string - * }} - */ -export function transcriberLeft(participantId: string) { - return { - type: _TRANSCRIBER_LEFT, - transcriberJID: participantId - }; -} - -/** - * Notify that a potential transcriber, with a unique ID, has joined. - * - * @param {string} participantId - The participant id of the transcriber. - * @returns {{ - * type: _POTENTIAL_TRANSCRIBER_JOINED, - * participantId: string + * type: TRANSCRIBER_LEFT, + * participantId: string, + * abruptly: boolean * }} */ -export function potentialTranscriberJoined(participantId: string) { +export function transcriberLeft(participantId: string, abruptly: boolean) { return { - type: _POTENTIAL_TRANSCRIBER_JOINED, - transcriberJID: participantId + type: TRANSCRIBER_LEFT, + transcriberJID: participantId, + abruptly }; } diff --git a/react/features/transcribing/middleware.ts b/react/features/transcribing/middleware.ts index 7f0dba08e487..663a39b9514b 100644 --- a/react/features/transcribing/middleware.ts +++ b/react/features/transcribing/middleware.ts @@ -1,18 +1,8 @@ -import { - HIDDEN_PARTICIPANT_JOINED, - HIDDEN_PARTICIPANT_LEFT, - PARTICIPANT_UPDATED -} from '../base/participants/actionTypes'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { showErrorNotification } from '../notifications/actions'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants'; -import { - potentialTranscriberJoined, - transcriberJoined, - transcriberLeft -} from './actions'; -import './subscriber'; - -const TRANSCRIBER_DISPLAY_NAME = 'Transcriber'; +import { TRANSCRIBER_LEFT } from './actionTypes'; /** * Implements the middleware of the feature transcribing. @@ -20,37 +10,15 @@ const TRANSCRIBER_DISPLAY_NAME = 'Transcriber'; * @param {Store} store - The redux store. * @returns {Function} */ -// eslint-disable-next-line no-unused-vars -MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { - const { - transcriberJID, - potentialTranscriberJIDs - } = getState()['features/transcribing']; - +MiddlewareRegistry.register(({ dispatch }) => next => action => { switch (action.type) { - case HIDDEN_PARTICIPANT_JOINED: - if (action.displayName === TRANSCRIBER_DISPLAY_NAME) { - dispatch(transcriberJoined(action.id)); - } else { - dispatch(potentialTranscriberJoined(action.id)); - } - - break; - case HIDDEN_PARTICIPANT_LEFT: - if (action.id === transcriberJID) { - dispatch(transcriberLeft(action.id)); + case TRANSCRIBER_LEFT: + if (action.abruptly) { + dispatch(showErrorNotification({ + titleKey: 'transcribing.failed' + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } break; - case PARTICIPANT_UPDATED: { - const { participant } = action; - - if (potentialTranscriberJIDs.includes(participant.id) && participant.name === TRANSCRIBER_DISPLAY_NAME) { - dispatch(transcriberJoined(participant.id)); - } - - break; - } - } return next(action); diff --git a/react/features/transcribing/reducer.ts b/react/features/transcribing/reducer.ts index c219590b6375..07166139f4d9 100644 --- a/react/features/transcribing/reducer.ts +++ b/react/features/transcribing/reducer.ts @@ -1,9 +1,8 @@ import ReducerRegistry from '../base/redux/ReducerRegistry'; import { - _POTENTIAL_TRANSCRIBER_JOINED, - _TRANSCRIBER_JOINED, - _TRANSCRIBER_LEFT + TRANSCRIBER_JOINED, + TRANSCRIBER_LEFT } from './actionTypes'; /** @@ -11,8 +10,7 @@ import { * * @returns {{ * isTranscribing: boolean, - * transcriberJID: null, - * potentialTranscriberJIDs: Array + * transcriberJID: null * }} * @private */ @@ -31,20 +29,12 @@ function _getInitialState() { * * @type { string } */ - transcriberJID: null, - - /** - * A list containing potential JID's of transcriber participants. - * - * @type { Array } - */ - potentialTranscriberJIDs: [] + transcriberJID: null }; } export interface ITranscribingState { isTranscribing: boolean; - potentialTranscriberJIDs: string[]; transcriberJID?: string | null; } @@ -54,23 +44,17 @@ export interface ITranscribingState { ReducerRegistry.register('features/transcribing', (state = _getInitialState(), action): ITranscribingState => { switch (action.type) { - case _TRANSCRIBER_JOINED: + case TRANSCRIBER_JOINED: return { ...state, isTranscribing: true, transcriberJID: action.transcriberJID }; - case _TRANSCRIBER_LEFT: + case TRANSCRIBER_LEFT: return { ...state, isTranscribing: false, - transcriberJID: undefined, - potentialTranscriberJIDs: [] - }; - case _POTENTIAL_TRANSCRIBER_JOINED: - return { - ...state, - potentialTranscriberJIDs: [ action.transcriberJID, ...state.potentialTranscriberJIDs ] + transcriberJID: undefined }; default: return state;