Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(WIP): Add an option to export media to a pre-configured WS url. #1171

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import org.jitsi.xmpp.extensions.colibri2.Colibri2Error
import org.jitsi.xmpp.extensions.colibri2.Colibri2Relay
import org.jitsi.xmpp.extensions.colibri2.ConferenceModifiedIQ
import org.jitsi.xmpp.extensions.colibri2.ConferenceModifyIQ
import org.jitsi.xmpp.extensions.colibri2.Connect
import org.jitsi.xmpp.extensions.colibri2.Endpoints
import org.jitsi.xmpp.extensions.colibri2.InitialLastN
import org.jitsi.xmpp.extensions.colibri2.Media
Expand All @@ -48,6 +49,7 @@ import org.jivesoftware.smack.StanzaCollector
import org.jivesoftware.smack.packet.ErrorIQ
import org.jivesoftware.smack.packet.IQ
import org.jivesoftware.smackx.muc.MUCRole
import java.net.URI
import java.util.Collections.singletonList
import java.util.UUID

Expand All @@ -57,6 +59,7 @@ class Colibri2Session(
val bridge: Bridge,
// Whether the session was constructed for the purpose of visitor nodes
val visitor: Boolean,
val audioRecordUrl: URI?,
parentLogger: Logger
) : CascadeNode<Colibri2Session, Colibri2Session.Relay> {
private val logger = createChildLogger(parentLogger).apply {
Expand Down Expand Up @@ -196,6 +199,17 @@ class Colibri2Session(
setCreate(true)
setConferenceName(colibriSessionManager.conferenceName)
setRtcstatsEnabled(colibriSessionManager.rtcStatsEnabled)
audioRecordUrl?.let {
logger.warn("Adding export to colibri iq url=$it")
addConnect(
Connect(
url = it,
type = Connect.Types.RECORDER,
protocol = Connect.Protocols.MEDIAJSON,
audio = true
)
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import org.jivesoftware.smack.packet.StanzaError.Condition.conflict
import org.jivesoftware.smack.packet.StanzaError.Condition.item_not_found
import org.jivesoftware.smack.packet.StanzaError.Condition.service_unavailable
import org.json.simple.JSONArray
import java.net.URI
import java.util.Collections.singletonList

/**
Expand All @@ -68,6 +69,7 @@ class ColibriV2SessionManager(
*/
internal val meetingId: String,
internal val rtcStatsEnabled: Boolean,
private val audioRecordUrl: URI?,
private val bridgeVersion: String?,
parentLogger: Logger
) : ColibriSessionManager, Cascade<Colibri2Session, Colibri2Session.Relay> {
Expand All @@ -81,6 +83,8 @@ class ColibriV2SessionManager(
logger.info("Using ${it.javaClass.name}")
}

private var sessionForAudioRecording: Colibri2Session? = null

/**
* The colibri2 sessions that are currently active, mapped by the relayId of the [Bridge] that they use.
*/
Expand Down Expand Up @@ -241,7 +245,16 @@ class ColibriV2SessionManager(
return Pair(session, false)
}

session = Colibri2Session(this, bridge, visitor, logger)
session = Colibri2Session(
this,
bridge,
visitor,
if (audioRecordUrl != null && sessionForAudioRecording == null) audioRecordUrl else null,
logger
)
if (audioRecordUrl != null && sessionForAudioRecording == null) {
sessionForAudioRecording = session
}
return Pair(session, true)
}

Expand Down
5 changes: 5 additions & 0 deletions jicofo-selector/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,11 @@ jicofo {
# via the room-metadata service
enable-live-room = false
}
recording {
# A templated URL to use for audio recording. The string "MEEETING_ID" will be replaced with the actual meeting ID.
# Note: if this is set all conferences will automatically be recorded using the specified URL.
//multi-track-recorder-url-template = "wss://example.com/recorder/MEETING_ID"
}

xmpp {
// Whether to use JitsiXmppStringprep to validate JIDs. If set to false uses the default validation in Smack.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.jivesoftware.smackx.caps.packet.*;
import org.jxmpp.jid.*;

import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
Expand Down Expand Up @@ -328,15 +329,23 @@ private ColibriSessionManager getColibriSessionManager()
{
// We initialize colibriSessionManager only after having joined the room, so meetingId must be set.
String meetingId = Objects.requireNonNull(this.meetingId);
URI multiTrackRecorderUrl = RecordingConfig.config.multiTrackRecorderUrl(meetingId);

colibriSessionManager = new ColibriV2SessionManager(
jicofoServices.getXmppServices().getServiceConnection().getXmppConnection(),
jicofoServices.getBridgeSelector(),
getRoomName().toString(),
meetingId,
config.getRtcStatsEnabled(),
multiTrackRecorderUrl,
jvbVersion,
logger);
colibriSessionManager.addListener(colibriSessionManagerListener);

if (multiTrackRecorderUrl != null)
{
setConferenceProperty(ConferenceProperties.KEY_AUDIO_RECORDING_ENABLED, Boolean.TRUE.toString());
}
}
return colibriSessionManager;
}
Expand Down
39 changes: 39 additions & 0 deletions jicofo/src/main/kotlin/org/jitsi/jicofo/RecordingConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Jicofo, the Jitsi Conference Focus.
*
* Copyright @ 2024 - 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

import org.jitsi.config.JitsiConfig
import org.jitsi.metaconfig.optionalconfig
import java.net.URI

class RecordingConfig private constructor() {
private val multiTrackRecorderUrlTemplate: String? by optionalconfig {
"jicofo.recording.multi-track-recorder-url-template".from(JitsiConfig.newConfig)
}

fun multiTrackRecorderUrl(meetingId: String): URI? = multiTrackRecorderUrlTemplate?.let {
URI(it.replace(MEETING_ID_TEMPLATE, meetingId))
}

companion object {
@JvmField
val config = RecordingConfig()

const val MEETING_ID_TEMPLATE = "MEETING_ID"
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jitsi-xmpp-extensions</artifactId>
<version>1.0-80-g0ce9883</version>
<version>1.0-82-ge8aacab</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Loading