From 6af5c5e5bb8993a05a4997aa84ccbce7e4633ca9 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 30 Aug 2024 08:57:28 -0500 Subject: [PATCH 1/5] feat(transcription): Drops TranscriberManager and expects dialIQ. --- .../conference/JitsiMeetConferenceImpl.java | 21 -- .../jicofo/jigasi/TranscriberManager.java | 291 ------------------ .../org/jitsi/jicofo/xmpp/JigasiIqHandler.kt | 8 +- 3 files changed, 7 insertions(+), 313 deletions(-) delete mode 100644 jicofo/src/main/java/org/jitsi/jicofo/jigasi/TranscriberManager.java diff --git a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java index 3b5139da8d..90248ddd59 100644 --- a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java +++ b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java @@ -150,12 +150,6 @@ public class JitsiMeetConferenceImpl */ private JibriSipGateway jibriSipGateway; - /** - * The {@link TranscriberManager} who listens for participants requesting - * transcription and, when necessary, dialing the transcriber instance. - */ - private TranscriberManager transcriberManager; - private ChatRoomRoleManager chatRoomRoleManager; /** @@ -502,15 +496,6 @@ private void joinTheRoom() this.chatRoom = chatRoom; chatRoom.addListener(chatRoomListener); - transcriberManager = new TranscriberManager( - jicofoServices.getXmppServices().getXmppConnectionByName( - JigasiConfig.config.xmppConnectionName() - ), - this, - chatRoom, - jicofoServices.getXmppServices().getJigasiDetector(), - logger); - ChatRoomInfo chatRoomInfo = chatRoom.join(); if (chatRoomInfo.getMeetingId() == null) { @@ -651,11 +636,6 @@ private void leaveTheRoom() chatRoom.removeListener(chatRoomRoleManager); chatRoomRoleManager.stop(); } - if (transcriberManager != null) - { - transcriberManager.dispose(); - transcriberManager = null; - } chatRoom.leave(); @@ -1545,7 +1525,6 @@ private OrderedJsonObject getDebugState(boolean full) o.put("participants", participantsJson); //o.put("jibri_recorder", jibriRecorder.getDebugState()); //o.put("jibri_sip_gateway", jibriSipGateway.getDebugState()); - //o.put("transcriber_manager", transcriberManager.getDebugState()); ChatRoomRoleManager chatRoomRoleManager = this.chatRoomRoleManager; o.put("chat_room_role_manager", chatRoomRoleManager == null ? "null" : chatRoomRoleManager.getDebugState()); o.put("started", started.get()); diff --git a/jicofo/src/main/java/org/jitsi/jicofo/jigasi/TranscriberManager.java b/jicofo/src/main/java/org/jitsi/jicofo/jigasi/TranscriberManager.java deleted file mode 100644 index dfca0a0a24..0000000000 --- a/jicofo/src/main/java/org/jitsi/jicofo/jigasi/TranscriberManager.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Jicofo, the Jitsi Conference Focus. - * - * Copyright @ 2018 - present 8x8, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jitsi.jicofo.jigasi; - -import org.jetbrains.annotations.*; -import org.jitsi.jicofo.conference.*; -import org.jitsi.jicofo.xmpp.*; -import org.jitsi.jicofo.xmpp.muc.*; -import org.jitsi.utils.logging2.*; -import org.jitsi.xmpp.extensions.jitsimeet.*; -import org.jitsi.xmpp.extensions.rayo.*; -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.packet.*; -import org.jxmpp.jid.*; - -import java.util.*; -import java.util.concurrent.*; - -/** - * The {@link TranscriberManager} class is responsible for listening to presence updates to see whether a - * {@link ChatRoomMember} is requesting a transcriber by adding a - * {@link TranscriptionLanguageExtension} to their {@link Presence}. - * - * @author Nik Vaessen - */ -public class TranscriberManager -{ - /** - * The logger of this class. - */ - @NotNull - private final Logger logger; - - /** - * The {@link ChatRoom} of the conference this class is managing - */ - @NotNull - private final ChatRoom chatRoom; - @NotNull - private final JitsiMeetConferenceImpl conference; - - @NotNull - private final ChatRoomListener chatRoomListener = new ChatRoomListenerImpl(); - - /** - * The {@link JigasiDetector} responsible for determining which Jigasi - * to dial to when inviting the transcriber. - */ - private final JigasiDetector jigasiDetector; - - /** - * The {@link XMPPConnection} used to Dial Jigasi. - */ - @NotNull - private final AbstractXMPPConnection connection; - - /** - * The transcription status; either active or inactive based on this boolean - */ - private volatile boolean active; - - /** - * A single-threaded {@link ExecutorService} to offload inviting the - * Transcriber from the smack thread updating presence. It's important that requests are handled sequentially to - * prevent multiple jigasis being invited. - */ - private final ExecutorService executorService = Executors.newSingleThreadExecutor(); - - /** - * Create a {@link TranscriberManager} responsible for inviting Jigasi as - * a transcriber when this is desired. - * - * @param jigasiDetector detector for Jigasi instances which can be dialed - * to invite a transcriber - */ - public TranscriberManager(@NotNull XmppProvider xmppProvider, - @NotNull JitsiMeetConferenceImpl conference, - @NotNull ChatRoom chatRoom, - JigasiDetector jigasiDetector, - @NotNull Logger parentLogger) - { - this.logger = parentLogger.createChildLogger(getClass().getName()); - // TODO: handle the connection changing (reconnect) - this.connection = xmppProvider.getXmppConnection(); - - this.conference = conference; - this.chatRoom = chatRoom; - chatRoom.addListener(chatRoomListener); - this.jigasiDetector = jigasiDetector; - } - - public void dispose() - { - executorService.shutdown(); - chatRoom.removeListener(chatRoomListener); - - logger.debug("disposed transcriber manager"); - } - - private void memberPresenceChanged(@NotNull ChatRoomMember member) - { - Presence presence = member.getPresence(); - - if (presence == null) - { - return; - } - - TranscriptionStatusExtension transcriptionStatusExtension = getTranscriptionStatus(presence); - if (transcriptionStatusExtension != null - && TranscriptionStatusExtension.Status.OFF.equals(transcriptionStatusExtension.getStatus())) - { - active = false; - logger.info("detected transcription status being turned off."); - } - if (isRequestingTranscriber(presence) && !active) - { - tryToStart(); - } - } - - private void tryToStart() - { - if (jigasiDetector == null) - { - logger.warn("Transcription requested, but jigasiDetector is not configured."); - return; - } - - if (active) - { - return; - } - - executorService.execute(() -> { - if (active) - { - return; - } - - // We need a modifiable list for the "exclude" parameter. - selectTranscriber(2, new ArrayList<>(), conference.getBridgeRegions()); - }); - } - - /** - * Returns the {@link TranscriptionStatusExtension} if any from - * the given {@link Presence}. - * - * @param p the given {@link Presence} to check - * @return Returns the {@link TranscriptionStatusExtension} if any. - */ - private TranscriptionStatusExtension getTranscriptionStatus(Presence p) - { - return p.getExtension(TranscriptionStatusExtension.class); - } - - /** - * Method which is able to invite the transcriber by dialing Jigasi - * @param preferredRegions a list of preferred regions. - */ - private void startTranscribing(@NotNull Collection preferredRegions) - { - } - - /** - * Sends the dial iq to the selected jigasi (from brewery muc). - * @param retryCount the number of attempts to be made for sending this iq, - * if no reply is received from the remote side. - * @param exclude null or a list of jigasi Jids which - * we already tried sending in attempt to retry. - * @param preferredRegions a list of preferred regions. - */ - private void selectTranscriber( - int retryCount, - @NotNull List exclude, - @NotNull Collection preferredRegions) - { - logger.info("Attempting to invite transcriber"); - - Jid jigasiJid = jigasiDetector.selectTranscriber(exclude, preferredRegions); - - if (jigasiJid == null) - { - logger.warn("Unable to invite transcriber due to no Jigasi instances being available"); - return; - } - - DialIq dialIq = new DialIq(); - dialIq.setDestination("jitsi_meet_transcribe"); - dialIq.setTo(jigasiJid); - dialIq.setType(IQ.Type.set); - dialIq.setHeader("JvbRoomName", chatRoom.getRoomJid().toString()); - - try - { - IQ response = UtilKt.sendIqAndGetResponse(connection, dialIq); - - boolean retry = false; - if (response != null) - { - if (response.getError() == null) - { - active = true; - logger.info("transcriber was successfully invited"); - } - else - { - logger.warn("failed to invite transcriber. Got error: " + response.getError().getErrorGenerator()); - retry = true; - } - } - else - { - logger.warn("failed to invite transcriber; lack of response from XmmpConnection"); - retry = true; - } - - if (retry && retryCount > 0) - { - exclude.add(jigasiJid); - - selectTranscriber(retryCount - 1, exclude, preferredRegions); - } - } - catch (SmackException.NotConnectedException e) - { - logger.error("Failed sending dialIq to transcriber", e); - } - } - - /** - * Checks whether the given {@link Presence} indicates a conference - * participant is requesting transcription - * - * @param presence the presence to check - * @return true when the participant of the {@link Presence} is requesting - * transcription, false otherwise - */ - private boolean isRequestingTranscriber(Presence presence) - { - if (presence == null) - { - return false; - } - - TranscriptionRequestExtension ext = presence.getExtension(TranscriptionRequestExtension.class); - - if (ext == null) - { - return false; - } - - return Boolean.parseBoolean(ext.getText()); - } - - private class ChatRoomListenerImpl extends DefaultChatRoomListener - { - @Override - public void memberPresenceChanged(@NotNull ChatRoomMember member) - { - TranscriberManager.this.memberPresenceChanged(member); - } - - @Override - public void transcriptionRequestedChanged(boolean transcriptionRequested) - { - if (transcriptionRequested) - { - logger.info("Transcription requested from the room."); - tryToStart(); - } - } - } -} diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt index 283d478cae..386ea25673 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt @@ -100,8 +100,14 @@ class JigasiIqHandler( retryCount: Int = 2, exclude: List = emptyList() ) { + val selector = if (request.iq.destination == "jitsi_meet_transcribe") { + jigasiDetector::selectTranscriber + } else { + jigasiDetector::selectSipJigasi + } + // Check if Jigasi is available - val jigasiJid = jigasiDetector.selectSipJigasi(exclude, conferenceRegions) ?: run { + val jigasiJid = selector(exclude, conferenceRegions) ?: run { logger.warn("Request failed, no instances available: ${request.iq.toStringOpt()}") request.connection.tryToSendStanza( IQ.createErrorResponse( From b2bffe6932db593c18a702c6a5002b9a71d975c9 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 30 Aug 2024 08:58:48 -0500 Subject: [PATCH 2/5] feat(transcription,recording): Adds option to disable moderator checks. Default behavior is not changed. --- jicofo-selector/src/main/resources/reference.conf | 3 +++ .../jitsi/jicofo/conference/JitsiMeetConferenceImpl.java | 7 ++++++- .../src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt | 4 ++++ .../src/main/kotlin/org/jitsi/jicofo/jibri/BaseJibri.kt | 9 ++++++--- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/jicofo-selector/src/main/resources/reference.conf b/jicofo-selector/src/main/resources/reference.conf index b470415bc8..fcba5ec292 100644 --- a/jicofo-selector/src/main/resources/reference.conf +++ b/jicofo-selector/src/main/resources/reference.conf @@ -186,6 +186,9 @@ jicofo { // the next in line when the current owner leaves). enable-auto-owner = true + // Can be used to disable moderator checks for starting a recording or placing a call + enable-moderator-checks = true + // How long to wait for the initial participant in a conference. initial-timeout = 15 seconds diff --git a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java index 90248ddd59..d84a5b6508 100644 --- a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java +++ b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java @@ -2138,7 +2138,12 @@ public IqProcessingResult handleJibriRequest(@NotNull IqRequest request @Override public boolean acceptJigasiRequest(@NotNull Jid from) { - return MemberRoleKt.hasModeratorRights(getRoleForMucJid(from)); + if (ConferenceConfig.config.getEnableModeratorChecks()) + { + return MemberRoleKt.hasModeratorRights(getRoleForMucJid(from)); + } + + return true; } @Override diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt index b63afabb8a..2370b95cc5 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt @@ -38,6 +38,10 @@ class ConferenceConfig private constructor() { } fun enableAutoOwner(): Boolean = enableAutoOwner + val enableModeratorChecks: Boolean by config { + "jicofo.conference.enable-moderator-checks".from(newConfig) + } + val maxSsrcsPerUser: Int by config { "org.jitsi.jicofo.MAX_SSRC_PER_USER".from(legacyConfig) "jicofo.conference.max-ssrcs-per-user".from(newConfig) diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/jibri/BaseJibri.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/jibri/BaseJibri.kt index 434c7c68d1..06b612ea5e 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/jibri/BaseJibri.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/jibri/BaseJibri.kt @@ -17,6 +17,7 @@ */ package org.jitsi.jicofo.jibri +import org.jitsi.jicofo.ConferenceConfig import org.jitsi.jicofo.TaskPools import org.jitsi.jicofo.conference.JitsiMeetConferenceImpl import org.jitsi.jicofo.jibri.JibriSession.StateListener @@ -156,9 +157,11 @@ abstract class BaseJibri internal constructor( return session.processJibriIqRequestFromJibri(iq) } - verifyModeratorRole(iq)?.let { - logger.warn("Ignored Jibri request from non-moderator.") - return IQ.createErrorResponse(iq, it) + if (ConferenceConfig.config.enableModeratorChecks) { + verifyModeratorRole(iq)?.let { + logger.warn("Ignored Jibri request from non-moderator.") + return IQ.createErrorResponse(iq, it) + } } return when (iq.action) { From c9cf2c1a872803268f81b3ece307df31c6d79adf Mon Sep 17 00:00:00 2001 From: Boris Grozev Date: Thu, 5 Sep 2024 08:05:04 -0500 Subject: [PATCH 3/5] ref: Remove unused transcription code. --- .../kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoom.kt | 3 --- .../org/jitsi/jicofo/xmpp/muc/ChatRoomImpl.kt | 10 ---------- .../org/jitsi/jicofo/xmpp/muc/ChatRoomListener.kt | 1 - .../org/jitsi/jicofo/xmpp/muc/RoomMetadata.kt | 5 +---- .../org/jitsi/jicofo/xmpp/muc/RoomMetadataTest.kt | 14 ++++++-------- .../jicofo/conference/JitsiMeetConferenceImpl.java | 5 ----- .../src/main/kotlin/org/jitsi/jicofo/xmpp/Smack.kt | 13 +------------ 7 files changed, 8 insertions(+), 43 deletions(-) diff --git a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoom.kt b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoom.kt index 082d337568..825a5719b0 100644 --- a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoom.kt +++ b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoom.kt @@ -65,9 +65,6 @@ interface ChatRoom { * Read from the MUC config form. */ val participantsSoftLimit: Int? - /** Whether the room is configured to require transcription. */ - val transcriptionRequested: Boolean - val debugState: OrderedJsonObject /** Returns the number of members that currently have their audio sources unmuted. */ diff --git a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomImpl.kt b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomImpl.kt index 5e95f6ac80..a4bb683cc3 100644 --- a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomImpl.kt +++ b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomImpl.kt @@ -163,15 +163,6 @@ class ChatRoomImpl( } } - override var transcriptionRequested: Boolean = false - private set(value) { - if (value != field) { - logger.info("transcriptionRequested is now $value.") - field = value - eventEmitter.fireEvent { transcriptionRequestedChanged(value) } - } - } - private val avModerationByMediaType = ConcurrentHashMap() /** The emitter used to fire events. */ @@ -297,7 +288,6 @@ class ChatRoomImpl( } override fun setRoomMetadata(roomMetadata: RoomMetadata) { - transcriptionRequested = roomMetadata.metadata?.recording?.isTranscribingEnabled == true visitorsLive = roomMetadata.metadata?.visitors?.live == true } diff --git a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomListener.kt b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomListener.kt index 79f6f20591..6a2af2706f 100644 --- a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomListener.kt +++ b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/ChatRoomListener.kt @@ -29,7 +29,6 @@ interface ChatRoomListener { fun localRoleChanged(newRole: MemberRole) {} fun numAudioSendersChanged(numAudioSenders: Int) {} fun numVideoSendersChanged(numVideoSenders: Int) {} - fun transcriptionRequestedChanged(transcriptionRequested: Boolean) {} } /** A class with the default kotlin method implementations (to avoid using @JvmDefault) **/ diff --git a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadata.kt b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadata.kt index e17a6aaafe..b7d9805d19 100644 --- a/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadata.kt +++ b/jicofo-common/src/main/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadata.kt @@ -35,10 +35,7 @@ data class RoomMetadata( val metadata: Metadata? ) { @JsonIgnoreProperties(ignoreUnknown = true) - data class Metadata(val recording: Recording?, val visitors: Visitors?) { - @JsonIgnoreProperties(ignoreUnknown = true) - data class Recording(val isTranscribingEnabled: Boolean?) - + data class Metadata(val visitors: Visitors?) { @JsonIgnoreProperties(ignoreUnknown = true) data class Visitors(val live: Boolean?) } diff --git a/jicofo-common/src/test/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadataTest.kt b/jicofo-common/src/test/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadataTest.kt index 07079b1155..47f42f1a88 100644 --- a/jicofo-common/src/test/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadataTest.kt +++ b/jicofo-common/src/test/kotlin/org/jitsi/jicofo/xmpp/muc/RoomMetadataTest.kt @@ -19,21 +19,20 @@ package org.jitsi.jicofo.xmpp.muc import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.ShouldSpec -import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf class RoomMetadataTest : ShouldSpec() { init { context("Valid") { - context("With isTranscribingEnabled set") { + context("With visitors.live set") { val parsed = RoomMetadata.parse( """ { "type": "room_metadata", "metadata": { - "recording": { - "isTranscribingEnabled": true, + "visitors": { + "live": true, "anotherField": 123 }, "anotherField": {} @@ -42,9 +41,9 @@ class RoomMetadataTest : ShouldSpec() { """.trimIndent() ) parsed.shouldBeInstanceOf() - parsed.metadata!!.recording!!.isTranscribingEnabled shouldBe true + parsed.metadata!!.visitors!!.live shouldBe true } - context("With no recording included") { + context("With no visitors included") { val parsed = RoomMetadata.parse( """ @@ -60,8 +59,7 @@ class RoomMetadataTest : ShouldSpec() { """.trimIndent() ) parsed.shouldBeInstanceOf() - parsed.metadata.shouldNotBeNull() - parsed.metadata?.recording shouldBe null + parsed.metadata!!.visitors shouldBe null } } context("Invalid") { diff --git a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java index d84a5b6508..415b1dcdcb 100644 --- a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java +++ b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java @@ -2402,11 +2402,6 @@ public void memberPresenceChanged(@NotNull ChatRoomMember member) { } - @Override - public void transcriptionRequestedChanged(boolean transcriptionRequested) - { - } - @Override public void numAudioSendersChanged(int numAudioSenders) { diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/Smack.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/Smack.kt index 5aeeebea13..90eec11773 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/Smack.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/Smack.kt @@ -45,7 +45,6 @@ import org.jitsi.xmpp.extensions.jitsimeet.MuteIqProvider import org.jitsi.xmpp.extensions.jitsimeet.MuteVideoIqProvider import org.jitsi.xmpp.extensions.jitsimeet.StartMutedProvider import org.jitsi.xmpp.extensions.jitsimeet.StatsId -import org.jitsi.xmpp.extensions.jitsimeet.TranscriptionRequestExtension import org.jitsi.xmpp.extensions.jitsimeet.TranscriptionStatusExtension import org.jitsi.xmpp.extensions.jitsimeet.UserInfoPacketExt import org.jitsi.xmpp.extensions.jitsimeet.VideoMutedExtension @@ -109,12 +108,7 @@ fun registerXmppExtensions() { DefaultPacketExtensionProvider(JitsiParticipantCodecList::class.java) ) - // Add the extensions used for handling the inviting of transcriber - ProviderManager.addExtensionProvider( - TranscriptionRequestExtension.ELEMENT, - TranscriptionRequestExtension.NAMESPACE, - DefaultPacketExtensionProvider(TranscriptionRequestExtension::class.java) - ) + // The extension used for detecting a transcriber ProviderManager.addExtensionProvider( TranscriptionStatusExtension.ELEMENT, TranscriptionStatusExtension.NAMESPACE, @@ -146,11 +140,6 @@ fun registerXmppExtensions() { MuteIqProvider.registerMuteIqProvider() MuteVideoIqProvider.registerMuteVideoIqProvider() StartMutedProvider.registerStartMutedProvider() - ProviderManager.addExtensionProvider( - TranscriptionStatusExtension.ELEMENT, - TranscriptionStatusExtension.NAMESPACE, - DefaultPacketExtensionProvider(TranscriptionStatusExtension::class.java) - ) ProviderManager.addExtensionProvider( AudioMutedExtension.ELEMENT, From 24453fc688c7c6fbf605c3262a056b3dc6889c44 Mon Sep 17 00:00:00 2001 From: damencho Date: Sat, 7 Sep 2024 10:54:38 -0500 Subject: [PATCH 4/5] feat(transcription): Returns an error if transcriber is already in room. --- .../org/jitsi/jicofo/jigasi/JigasiDetector.kt | 9 +++++++++ .../org/jitsi/jicofo/xmpp/JigasiIqHandler.kt | 18 ++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt index d63ff38f8a..ad950f0152 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt @@ -21,6 +21,7 @@ import org.jitsi.jicofo.JicofoConfig import org.jitsi.jicofo.metrics.JicofoMetricsContainer import org.jitsi.jicofo.xmpp.BaseBrewery import org.jitsi.jicofo.xmpp.XmppProvider +import org.jitsi.jicofo.xmpp.muc.ChatRoom import org.jitsi.utils.OrderedJsonObject import org.jitsi.utils.logging2.createLogger import org.jitsi.xmpp.extensions.colibri.ColibriStatsExtension @@ -96,6 +97,14 @@ open class JigasiDetector( transcriberCount.set(getInstanceCount { it.supportsTranscription() }.toLong()) } + fun hasTranscriber(chatRoom: ChatRoom?): Boolean { + chatRoom?.let { + chatRoom.members.firstOrNull { member -> member.isTranscriber } != null + } + + return false + } + /** * The companion object is necessary for the implicit call to this.createLogger() in the super constructor! */ diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt index 386ea25673..fbf9773c3c 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/JigasiIqHandler.kt @@ -19,6 +19,7 @@ package org.jitsi.jicofo.xmpp import org.jitsi.jicofo.ConferenceStore import org.jitsi.jicofo.TaskPools +import org.jitsi.jicofo.conference.JitsiMeetConference import org.jitsi.jicofo.jigasi.JigasiDetector import org.jitsi.jicofo.metrics.JicofoMetricsContainer import org.jitsi.jicofo.xmpp.IqProcessingResult.AcceptedWithNoResponse @@ -79,7 +80,7 @@ class JigasiIqHandler( TaskPools.ioPool.execute { try { - inviteJigasi(request, conference.bridgeRegions) + inviteJigasi(request, conference) } catch (e: Exception) { logger.warn("Failed to invite jigasi", e) request.connection.tryToSendStanza( @@ -96,18 +97,26 @@ class JigasiIqHandler( */ private fun inviteJigasi( request: IqRequest, - conferenceRegions: Set, + conference: JitsiMeetConference, retryCount: Int = 2, exclude: List = emptyList() ) { val selector = if (request.iq.destination == "jitsi_meet_transcribe") { + if (jigasiDetector.hasTranscriber(conference.chatRoom)) { + logger.warn("Request failed, transcriber already available: ${request.iq.toStringOpt()}") + IQ.createErrorResponse( + request.iq, + StanzaError.getBuilder(StanzaError.Condition.conflict).build() + ) + return + } jigasiDetector::selectTranscriber } else { jigasiDetector::selectSipJigasi } // Check if Jigasi is available - val jigasiJid = selector(exclude, conferenceRegions) ?: run { + val jigasiJid = selector(exclude, conference.bridgeRegions) ?: run { logger.warn("Request failed, no instances available: ${request.iq.toStringOpt()}") request.connection.tryToSendStanza( IQ.createErrorResponse( @@ -148,7 +157,7 @@ class JigasiIqHandler( logger.info("Will retry up to $retryCount more times.") Stats.retries.inc() // Do not try the same instance again. - inviteJigasi(request, conferenceRegions, retryCount - 1, exclude + jigasiJid) + inviteJigasi(request, conference, retryCount - 1, exclude + jigasiJid) } else { val condition = if (responseFromJigasi == null) { StanzaError.Condition.remote_server_timeout @@ -163,6 +172,7 @@ class JigasiIqHandler( } } else -> { + logger.info("response from jigasi: ${responseFromJigasi.toStringOpt()}") // Successful response from Jigasi, forward it as the response to the client. request.connection.tryToSendStanza( responseFromJigasi.apply { From b3cc809360dedcf3f0c681661181446b5040c1b2 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 13 Sep 2024 10:27:03 -0500 Subject: [PATCH 5/5] squash: Fixes comments. --- .../main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt index ad950f0152..5695eb3973 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/jigasi/JigasiDetector.kt @@ -98,11 +98,8 @@ open class JigasiDetector( } fun hasTranscriber(chatRoom: ChatRoom?): Boolean { - chatRoom?.let { - chatRoom.members.firstOrNull { member -> member.isTranscriber } != null - } - - return false + return chatRoom?.members?.any { member -> member.isTranscriber } + ?: false } /**