# HG changeset patch # User Goffi # Date 1722980591 -7200 # Node ID a0ed5c976bf87c3f3cd99fc2ac3878fc785e093d # Parent 9447796408f609c44b96044613d8c765c8a3834c component conferences, plugin XEP-0167, XEP-0298: add stream user metadata: A/V conference now adds user metadata about the stream it is forwarding through XEP-0298. This is parsed and added to metadata during confirmation on client side. rel 448 diff -r 9447796408f6 -r a0ed5c976bf8 libervia/backend/plugins/plugin_comp_conferences/__init__.py --- a/libervia/backend/plugins/plugin_comp_conferences/__init__.py Mon Jul 29 03:49:26 2024 +0200 +++ b/libervia/backend/plugins/plugin_comp_conferences/__init__.py Tue Aug 06 23:43:11 2024 +0200 @@ -236,10 +236,22 @@ async def a_on_offer(self, data: dict) -> None: client: SatXMPPEntity = self.client.get_virtual_client(self.session["local_jid"]) + call_data = {"sdp": data["sdp"]} + try: + # FIXME: This assume that all username are coming from XMPP, "source" should + # be used instead to be sure to match XMPP users, and other ones should use + # a non "xmpp:" URL scheme. + user_jid = jid.JID(data["username"]) + if not user_jid.user: + raise ValueError("Missing user part.") + except Exception as e: + log.warning("Username is not a JID: {data['username']=}, {e}") + else: + call_data["metadata"] = {"user": user_jid} sid = await self._rtp.call_start( client, self.session["peer_jid"], - {"sdp": data["sdp"]}, + call_data, session_id=f"{self.client_id}-{data['id']}", ) session = self._j.get_session(client, sid) @@ -547,7 +559,6 @@ log.error(f"Can't run Galene process: {failure_.value}") - @implementer(iwokkel.IDisco) class ConferencesHandler(XMPPHandler): diff -r 9447796408f6 -r a0ed5c976bf8 libervia/backend/plugins/plugin_xep_0060.py --- a/libervia/backend/plugins/plugin_xep_0060.py Mon Jul 29 03:49:26 2024 +0200 +++ b/libervia/backend/plugins/plugin_xep_0060.py Tue Aug 06 23:43:11 2024 +0200 @@ -1539,7 +1539,7 @@ try: return { jid.JID(s["jid"]): s["subscription"] - for s in subscriptions_elt.elements((pubsub.NS_PUBSUB, "subscription")) + for s in subscriptions_elt.elements(pubsub.NS_PUBSUB, "subscription") } except KeyError: raise ValueError( diff -r 9447796408f6 -r a0ed5c976bf8 libervia/backend/plugins/plugin_xep_0167/__init__.py --- a/libervia/backend/plugins/plugin_xep_0167/__init__.py Mon Jul 29 03:49:26 2024 +0200 +++ b/libervia/backend/plugins/plugin_xep_0167/__init__.py Tue Aug 06 23:43:11 2024 +0200 @@ -41,7 +41,7 @@ NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_INFO, NS_JINGLE_RTP_VIDEO, - NS_AV_CONFERENCES + NS_AV_CONFERENCES, ) @@ -419,17 +419,22 @@ session["call_type"] = call_type cancellable_deferred = session.setdefault("cancellable_deferred", []) + action_extra = { + "session_id": session["id"], + "from_jid": peer_jid.full(), + "type": C.META_TYPE_CALL, + "sub_type": call_type, + } + try: + action_extra["metadata"] = {"user": session["metadata"]["peer_user"].full()} + except KeyError: + pass dialog_d = xml_tools.defer_dialog( self.host, _(CONFIRM).format(peer=peer_jid.userhost(), call_type=call_type), _(CONFIRM_TITLE), - action_extra={ - "session_id": session["id"], - "from_jid": peer_jid.full(), - "type": C.META_TYPE_CALL, - "sub_type": call_type, - }, + action_extra=action_extra, security_limit=SECURITY_LIMIT, profile=client.profile, ) @@ -596,26 +601,22 @@ answer_sdp_d.addTimeout(2 * 60, reactor) call_setup = session.get("call_setup_cb") + call_data = { + "role": session["role"], + "sdp": sdp, + } if call_setup is None: self.host.bridge.call_setup( session["id"], - data_format.serialise( - { - "role": session["role"], - "sdp": sdp, - } - ), + data_format.serialise(call_data), client.profile, ) else: await call_setup( client, session, - { - "role": session["role"], - "sdp": sdp, - }, + call_data, ) answer_sdp = await answer_sdp_d @@ -681,7 +682,7 @@ content_data = session["contents"][content_name] application_data = content_data["application_data"] if action == self._j.A_PREPARE_CONFIRMATION: - session["metadata"] = {} + session.setdefault("metadata", {}) session.setdefault("peer_metadata", {}) try: media = application_data["media"] = desc_elt["media"] diff -r 9447796408f6 -r a0ed5c976bf8 libervia/backend/plugins/plugin_xep_0298.py --- a/libervia/backend/plugins/plugin_xep_0298.py Mon Jul 29 03:49:26 2024 +0200 +++ b/libervia/backend/plugins/plugin_xep_0298.py Tue Aug 06 23:43:11 2024 +0200 @@ -20,6 +20,7 @@ from urllib.parse import quote, unquote from twisted.words.protocols.jabber import jid from twisted.words.xish import domish +from libervia.backend.core.core_types import SatXMPPEntity from libervia.backend.core.i18n import _ from libervia.backend.core.constants import Const as C from libervia.backend.core.log import getLogger @@ -27,6 +28,8 @@ from zope.interface import implementer from twisted.words.protocols.jabber.xmlstream import XMPPHandler +from libervia.backend.plugins.plugin_xep_0166 import XEP_0166 + log = getLogger(__name__) @@ -36,7 +39,7 @@ C.PI_TYPE: "XEP", C.PI_MODES: C.PLUG_MODE_BOTH, C.PI_PROTOCOLS: [], - C.PI_DEPENDENCIES: [], + C.PI_DEPENDENCIES: ["XEP-0167"], C.PI_MAIN: "XEP_0298", C.PI_HANDLER: "yes", C.PI_DESCRIPTION: _( @@ -55,10 +58,58 @@ def __init__(self, host): log.info(f"plugin {PLUGIN_INFO[C.PI_NAME]!r} initialization") self.host = host + self._j: XEP_0166 = host.plugins["XEP-0166"] + host.trigger.add( + "XEP-0167_jingle_session_init", self._jingle_session_init_trigger + ) + host.trigger.add("XEP-0167_jingle_handler", self._jingle_handler_trigger) def get_handler(self, client): return CoinHandler(self) + def _jingle_session_init_trigger( + self, + client: SatXMPPEntity, + session: dict, + content_name: str, + media: str, + media_data: dict, + desc_elt: domish.Element, + ) -> None: + """Check for the presence of "user" metadata, and add relevant elements.""" + if client.profile == "conferences": + if content_name != next(iter(session["contents"].keys())): + # We only apply metadata for the first content, as it is global. + return + try: + user = session["metadata"]["user"] + except KeyError: + return + jingle_elt = session["jingle_elt"] + conference_info_elt = self.add_conference_info(jingle_elt, True) + self.add_user(conference_info_elt, user) + + async def _jingle_handler_trigger( + self, + client: SatXMPPEntity, + action: str, + session: dict, + content_name: str, + desc_elt: domish.Element, + ) -> None: + # this is a session metadata, so we only generate it on the first content + if action == self._j.A_PREPARE_CONFIRMATION and content_name == next( + iter(session["contents"]) + ): + jingle_elt = session["jingle_elt"] + infos = self.parse(jingle_elt) + try: + user = infos["info"]["users"][0] + except (KeyError, IndexError): + pass + else: + session.setdefault("metadata", {})["peer_user"] = user + def add_conference_info( self, jingle_elt: domish.Element, is_focus: bool = False, **kwargs ) -> domish.Element: @@ -104,7 +155,7 @@ """ try: conference_info_elt = next( - jingle_elt.elements((NS_CONFERENCE_INFO, "conference-info")) + jingle_elt.elements(NS_CONFERENCE_INFO, "conference-info") ) except StopIteration: return {}