black reformatting

This commit is contained in:
Goffi 2025-11-20 14:50:03 +01:00
commit f3f40848b3
8 changed files with 2093 additions and 646 deletions

View file

@ -734,7 +734,6 @@ class SatXMPPEntity(core_types.SatXMPPEntity):
await self.a_send(mess_data["xml"])
return mess_data
def sendMessage(
self,
to_jid: jid.JID,

View file

@ -458,7 +458,7 @@ class AdHocCommandHandler(XMPPHandler):
result["type"] = "result"
result["id"] = iq_elt["id"]
result["to"] = iq_elt["from"]
command_elt = result.addElement((NS_COMMANDS, "command" ))
command_elt = result.addElement((NS_COMMANDS, "command"))
command_elt["sessionid"] = session_id
command_elt["node"] = self.command.node
command_elt["status"] = status

View file

@ -95,7 +95,9 @@ class XEP_0176(BaseTransportHandler):
)
)
def build_transport(self, ice_data: dict, add_trickle: bool = False) -> domish.Element:
def build_transport(
self, ice_data: dict, add_trickle: bool = False
) -> domish.Element:
"""Generate <transport> element from ICE data
@param ice_data: a dict containing the following keys:
@ -155,7 +157,10 @@ class XEP_0176(BaseTransportHandler):
if add_trickle:
transport_elt.addElement(
("http://gultsch.de/xmpp/drafts/jingle/transports/ice-udp/option", "trickle")
(
"http://gultsch.de/xmpp/drafts/jingle/transports/ice-udp/option",
"trickle",
)
)
self.host.trigger.point("XEP-0176_build_transport", transport_elt, ice_data)

View file

@ -92,6 +92,7 @@ def partial(func, *fixed_args, **fixed_kwargs):
return method
def as_deferred(func, *args, **kwargs) -> defer.Deferred:
"""Call a method and return a Deferred

View file

@ -65,18 +65,12 @@ class Common(base.CommandBase):
default="auto",
help='Well-known sources to use (default: "auto").',
)
pipelines_group = self.parser.add_argument_group(
title = "Custom Pipelines"
pipelines_group = self.parser.add_argument_group(title="Custom Pipelines")
pipelines_group.add_argument(
"-V", "--video", help="GStreamer pipeline description for the video stream"
)
pipelines_group.add_argument(
"-V",
"--video",
help="GStreamer pipeline description for the video stream"
)
pipelines_group.add_argument(
"-A",
"--audio",
help="GStreamer pipeline description for the audio stream"
"-A", "--audio", help="GStreamer pipeline description for the audio stream"
)
def get_call_data_kw(self) -> dict[str, Any]:
@ -88,8 +82,7 @@ class Common(base.CommandBase):
"You can 't use --sources and --video or --audio at the same time."
)
kwargs["sources_data"] = SourcesPipeline(
video_pipeline=self.args.video,
audio_pipeline=self.args.audio
video_pipeline=self.args.video, audio_pipeline=self.args.audio
)
if self.args.sources == "test":

File diff suppressed because it is too large Load diff

View file

@ -161,8 +161,9 @@ class bridge(object):
def register_signal(self, functionName, handler, iface="core"):
self.signals_handler.register_signal(functionName, handler, iface)
def action_launch(self, callback_id, data, profile_key="@DEFAULT@", callback=None, errback=None):
def action_launch(
self, callback_id, data, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("action_launch", callback_id, data, profile_key)
if callback is not None:
d.addCallback(callback)
@ -189,7 +190,14 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def connect(self, profile_key="@DEFAULT@", password='', options={}, callback=None, errback=None):
def connect(
self,
profile_key="@DEFAULT@",
password="",
options={},
callback=None,
errback=None,
):
d = self.root.callRemote("connect", profile_key, password, options)
if callback is not None:
d.addCallback(callback)
@ -198,7 +206,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def contact_add(self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None):
def contact_add(
self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("contact_add", entity_jid, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -207,7 +217,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def contact_del(self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None):
def contact_del(
self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("contact_del", entity_jid, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -225,7 +237,15 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@", callback=None, errback=None):
def contact_update(
self,
entity_jid,
name,
groups,
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote("contact_update", entity_jid, name, groups, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -243,7 +263,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def contacts_get_from_group(self, group, profile_key="@DEFAULT@", callback=None, errback=None):
def contacts_get_from_group(
self, group, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("contacts_get_from_group", group, profile_key)
if callback is not None:
d.addCallback(callback)
@ -261,8 +283,30 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def disco_find_by_features(self, namespaces, identities, bare_jid=False, service=True, roster=True, own_jid=True, local_device=False, profile_key="@DEFAULT@", callback=None, errback=None):
d = self.root.callRemote("disco_find_by_features", namespaces, identities, bare_jid, service, roster, own_jid, local_device, profile_key)
def disco_find_by_features(
self,
namespaces,
identities,
bare_jid=False,
service=True,
roster=True,
own_jid=True,
local_device=False,
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"disco_find_by_features",
namespaces,
identities,
bare_jid,
service,
roster,
own_jid,
local_device,
profile_key,
)
if callback is not None:
d.addCallback(callback)
if errback is None:
@ -270,7 +314,15 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def disco_infos(self, entity_jid, node=u'', use_cache=True, profile_key="@DEFAULT@", callback=None, errback=None):
def disco_infos(
self,
entity_jid,
node="",
use_cache=True,
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote("disco_infos", entity_jid, node, use_cache, profile_key)
if callback is not None:
d.addCallback(callback)
@ -279,7 +331,15 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def disco_items(self, entity_jid, node=u'', use_cache=True, profile_key="@DEFAULT@", callback=None, errback=None):
def disco_items(
self,
entity_jid,
node="",
use_cache=True,
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote("disco_items", entity_jid, node, use_cache, profile_key)
if callback is not None:
d.addCallback(callback)
@ -315,8 +375,12 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def encryption_trust_ui_get(self, to_jid, namespace, profile_key, callback=None, errback=None):
d = self.root.callRemote("encryption_trust_ui_get", to_jid, namespace, profile_key)
def encryption_trust_ui_get(
self, to_jid, namespace, profile_key, callback=None, errback=None
):
d = self.root.callRemote(
"encryption_trust_ui_get", to_jid, namespace, profile_key
)
if callback is not None:
d.addCallback(callback)
if errback is None:
@ -351,8 +415,20 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def history_get(self, from_jid, to_jid, limit, between=True, filters='', profile="@NONE@", callback=None, errback=None):
d = self.root.callRemote("history_get", from_jid, to_jid, limit, between, filters, profile)
def history_get(
self,
from_jid,
to_jid,
limit,
between=True,
filters="",
profile="@NONE@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"history_get", from_jid, to_jid, limit, between, filters, profile
)
if callback is not None:
d.addCallback(callback)
if errback is None:
@ -378,7 +454,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def image_generate_preview(self, image_path, profile_key, callback=None, errback=None):
def image_generate_preview(
self, image_path, profile_key, callback=None, errback=None
):
d = self.root.callRemote("image_generate_preview", image_path, profile_key)
if callback is not None:
d.addCallback(callback)
@ -414,7 +492,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def main_resource_get(self, contact_jid, profile_key="@DEFAULT@", callback=None, errback=None):
def main_resource_get(
self, contact_jid, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("main_resource_get", contact_jid, profile_key)
if callback is not None:
d.addCallback(callback)
@ -432,8 +512,19 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def menu_launch(self, menu_type, path, data, security_limit, profile_key, callback=None, errback=None):
d = self.root.callRemote("menu_launch", menu_type, path, data, security_limit, profile_key)
def menu_launch(
self,
menu_type,
path,
data,
security_limit,
profile_key,
callback=None,
errback=None,
):
d = self.root.callRemote(
"menu_launch", menu_type, path, data, security_limit, profile_key
)
if callback is not None:
d.addCallback(callback)
if errback is None:
@ -459,8 +550,18 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def message_encryption_start(self, to_jid, namespace='', replace=False, profile_key="@NONE@", callback=None, errback=None):
d = self.root.callRemote("message_encryption_start", to_jid, namespace, replace, profile_key)
def message_encryption_start(
self,
to_jid,
namespace="",
replace=False,
profile_key="@NONE@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"message_encryption_start", to_jid, namespace, replace, profile_key
)
if callback is not None:
d.addCallback(lambda __: callback())
if errback is None:
@ -477,8 +578,20 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def message_send(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@", callback=None, errback=None):
d = self.root.callRemote("message_send", to_jid, message, subject, mess_type, extra, profile_key)
def message_send(
self,
to_jid,
message,
subject={},
mess_type="auto",
extra={},
profile_key="@NONE@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"message_send", to_jid, message, subject, mess_type, extra, profile_key
)
if callback is not None:
d.addCallback(lambda __: callback())
if errback is None:
@ -495,8 +608,34 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def notification_add(self, type_, body_plain, body_rich, title, is_global, requires_action, arg_6, priority, expire_at, extra, callback=None, errback=None):
d = self.root.callRemote("notification_add", type_, body_plain, body_rich, title, is_global, requires_action, arg_6, priority, expire_at, extra)
def notification_add(
self,
type_,
body_plain,
body_rich,
title,
is_global,
requires_action,
arg_6,
priority,
expire_at,
extra,
callback=None,
errback=None,
):
d = self.root.callRemote(
"notification_add",
type_,
body_plain,
body_rich,
title,
is_global,
requires_action,
arg_6,
priority,
expire_at,
extra,
)
if callback is not None:
d.addCallback(lambda __: callback())
if errback is None:
@ -504,7 +643,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def notification_delete(self, id_, is_global, profile_key, callback=None, errback=None):
def notification_delete(
self, id_, is_global, profile_key, callback=None, errback=None
):
d = self.root.callRemote("notification_delete", id_, is_global, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -513,8 +654,12 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def notifications_expired_clean(self, limit_timestamp, profile_key, callback=None, errback=None):
d = self.root.callRemote("notifications_expired_clean", limit_timestamp, profile_key)
def notifications_expired_clean(
self, limit_timestamp, profile_key, callback=None, errback=None
):
d = self.root.callRemote(
"notifications_expired_clean", limit_timestamp, profile_key
)
if callback is not None:
d.addCallback(lambda __: callback())
if errback is None:
@ -531,7 +676,15 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def param_get_a(self, name, category, attribute="value", profile_key="@DEFAULT@", callback=None, errback=None):
def param_get_a(
self,
name,
category,
attribute="value",
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote("param_get_a", name, category, attribute, profile_key)
if callback is not None:
d.addCallback(callback)
@ -540,8 +693,19 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def param_get_a_async(self, name, category, attribute="value", security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None):
d = self.root.callRemote("param_get_a_async", name, category, attribute, security_limit, profile_key)
def param_get_a_async(
self,
name,
category,
attribute="value",
security_limit=-1,
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"param_get_a_async", name, category, attribute, security_limit, profile_key
)
if callback is not None:
d.addCallback(callback)
if errback is None:
@ -549,8 +713,19 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def param_set(self, name, value, category, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None):
d = self.root.callRemote("param_set", name, value, category, security_limit, profile_key)
def param_set(
self,
name,
value,
category,
security_limit=-1,
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"param_set", name, value, category, security_limit, profile_key
)
if callback is not None:
d.addCallback(lambda __: callback())
if errback is None:
@ -558,7 +733,15 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def param_ui_get(self, security_limit=-1, app='', extra='', profile_key="@DEFAULT@", callback=None, errback=None):
def param_ui_get(
self,
security_limit=-1,
app="",
extra="",
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote("param_ui_get", security_limit, app, extra, profile_key)
if callback is not None:
d.addCallback(callback)
@ -576,7 +759,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def params_register_app(self, xml, security_limit=-1, app='', callback=None, errback=None):
def params_register_app(
self, xml, security_limit=-1, app="", callback=None, errback=None
):
d = self.root.callRemote("params_register_app", xml, security_limit, app)
if callback is not None:
d.addCallback(lambda __: callback())
@ -603,8 +788,24 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def params_values_from_category_get_async(self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@", callback=None, errback=None):
d = self.root.callRemote("params_values_from_category_get_async", category, security_limit, app, extra, profile_key)
def params_values_from_category_get_async(
self,
category,
security_limit=-1,
app="",
extra="",
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote(
"params_values_from_category_get_async",
category,
security_limit,
app,
extra,
profile_key,
)
if callback is not None:
d.addCallback(callback)
if errback is None:
@ -612,7 +813,15 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def presence_set(self, to_jid='', show='', statuses={}, profile_key="@DEFAULT@", callback=None, errback=None):
def presence_set(
self,
to_jid="",
show="",
statuses={},
profile_key="@DEFAULT@",
callback=None,
errback=None,
):
d = self.root.callRemote("presence_set", to_jid, show, statuses, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -648,7 +857,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def private_data_set(self, namespace, key, data, profile_key, callback=None, errback=None):
def private_data_set(
self, namespace, key, data, profile_key, callback=None, errback=None
):
d = self.root.callRemote("private_data_set", namespace, key, data, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -657,7 +868,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def profile_create(self, profile, password='', component='', callback=None, errback=None):
def profile_create(
self, profile, password="", component="", callback=None, errback=None
):
d = self.root.callRemote("profile_create", profile, password, component)
if callback is not None:
d.addCallback(lambda __: callback())
@ -675,7 +888,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def profile_is_session_started(self, profile_key="@DEFAULT@", callback=None, errback=None):
def profile_is_session_started(
self, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("profile_is_session_started", profile_key)
if callback is not None:
d.addCallback(callback)
@ -702,7 +917,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def profile_start_session(self, password='', profile_key="@DEFAULT@", callback=None, errback=None):
def profile_start_session(
self, password="", profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("profile_start_session", password, profile_key)
if callback is not None:
d.addCallback(callback)
@ -711,7 +928,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def profiles_list_get(self, clients=True, components=False, callback=None, errback=None):
def profiles_list_get(
self, clients=True, components=False, callback=None, errback=None
):
d = self.root.callRemote("profiles_list_get", clients, components)
if callback is not None:
d.addCallback(callback)
@ -783,7 +1002,9 @@ class bridge(object):
else:
d.addErrback(self._errback, ori_errback=errback)
def subscription(self, sub_type, entity, profile_key="@DEFAULT@", callback=None, errback=None):
def subscription(
self, sub_type, entity, profile_key="@DEFAULT@", callback=None, errback=None
):
d = self.root.callRemote("subscription", sub_type, entity, profile_key)
if callback is not None:
d.addCallback(lambda __: callback())
@ -802,7 +1023,6 @@ class bridge(object):
d.addErrback(self._errback, ori_errback=errback)
class AIOSignalsHandler(SignalsHandler):
def register_signal(self, name, handler, iface="core"):
@ -832,7 +1052,6 @@ class AIOBridge(bridge):
d = super().bridge_connect(callback=None, errback=None)
return await d.asFuture(asyncio.get_event_loop())
def action_launch(self, callback_id, data, profile_key="@DEFAULT@"):
d = self.root.callRemote("action_launch", callback_id, data, profile_key)
d.addErrback(self._errback)
@ -848,7 +1067,7 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def connect(self, profile_key="@DEFAULT@", password='', options={}):
def connect(self, profile_key="@DEFAULT@", password="", options={}):
d = self.root.callRemote("connect", profile_key, password, options)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -888,17 +1107,37 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def disco_find_by_features(self, namespaces, identities, bare_jid=False, service=True, roster=True, own_jid=True, local_device=False, profile_key="@DEFAULT@"):
d = self.root.callRemote("disco_find_by_features", namespaces, identities, bare_jid, service, roster, own_jid, local_device, profile_key)
def disco_find_by_features(
self,
namespaces,
identities,
bare_jid=False,
service=True,
roster=True,
own_jid=True,
local_device=False,
profile_key="@DEFAULT@",
):
d = self.root.callRemote(
"disco_find_by_features",
namespaces,
identities,
bare_jid,
service,
roster,
own_jid,
local_device,
profile_key,
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def disco_infos(self, entity_jid, node=u'', use_cache=True, profile_key="@DEFAULT@"):
def disco_infos(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"):
d = self.root.callRemote("disco_infos", entity_jid, node, use_cache, profile_key)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def disco_items(self, entity_jid, node=u'', use_cache=True, profile_key="@DEFAULT@"):
def disco_items(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"):
d = self.root.callRemote("disco_items", entity_jid, node, use_cache, profile_key)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -919,7 +1158,9 @@ class AIOBridge(bridge):
return d.asFuture(asyncio.get_event_loop())
def encryption_trust_ui_get(self, to_jid, namespace, profile_key):
d = self.root.callRemote("encryption_trust_ui_get", to_jid, namespace, profile_key)
d = self.root.callRemote(
"encryption_trust_ui_get", to_jid, namespace, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -938,8 +1179,12 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def history_get(self, from_jid, to_jid, limit, between=True, filters='', profile="@NONE@"):
d = self.root.callRemote("history_get", from_jid, to_jid, limit, between, filters, profile)
def history_get(
self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@"
):
d = self.root.callRemote(
"history_get", from_jid, to_jid, limit, between, filters, profile
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -984,7 +1229,9 @@ class AIOBridge(bridge):
return d.asFuture(asyncio.get_event_loop())
def menu_launch(self, menu_type, path, data, security_limit, profile_key):
d = self.root.callRemote("menu_launch", menu_type, path, data, security_limit, profile_key)
d = self.root.callRemote(
"menu_launch", menu_type, path, data, security_limit, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -998,8 +1245,12 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def message_encryption_start(self, to_jid, namespace='', replace=False, profile_key="@NONE@"):
d = self.root.callRemote("message_encryption_start", to_jid, namespace, replace, profile_key)
def message_encryption_start(
self, to_jid, namespace="", replace=False, profile_key="@NONE@"
):
d = self.root.callRemote(
"message_encryption_start", to_jid, namespace, replace, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1008,8 +1259,18 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def message_send(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@"):
d = self.root.callRemote("message_send", to_jid, message, subject, mess_type, extra, profile_key)
def message_send(
self,
to_jid,
message,
subject={},
mess_type="auto",
extra={},
profile_key="@NONE@",
):
d = self.root.callRemote(
"message_send", to_jid, message, subject, mess_type, extra, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1018,8 +1279,32 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def notification_add(self, type_, body_plain, body_rich, title, is_global, requires_action, arg_6, priority, expire_at, extra):
d = self.root.callRemote("notification_add", type_, body_plain, body_rich, title, is_global, requires_action, arg_6, priority, expire_at, extra)
def notification_add(
self,
type_,
body_plain,
body_rich,
title,
is_global,
requires_action,
arg_6,
priority,
expire_at,
extra,
):
d = self.root.callRemote(
"notification_add",
type_,
body_plain,
body_rich,
title,
is_global,
requires_action,
arg_6,
priority,
expire_at,
extra,
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1029,7 +1314,9 @@ class AIOBridge(bridge):
return d.asFuture(asyncio.get_event_loop())
def notifications_expired_clean(self, limit_timestamp, profile_key):
d = self.root.callRemote("notifications_expired_clean", limit_timestamp, profile_key)
d = self.root.callRemote(
"notifications_expired_clean", limit_timestamp, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1043,17 +1330,30 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def param_get_a_async(self, name, category, attribute="value", security_limit=-1, profile_key="@DEFAULT@"):
d = self.root.callRemote("param_get_a_async", name, category, attribute, security_limit, profile_key)
def param_get_a_async(
self,
name,
category,
attribute="value",
security_limit=-1,
profile_key="@DEFAULT@",
):
d = self.root.callRemote(
"param_get_a_async", name, category, attribute, security_limit, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def param_set(self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"):
d = self.root.callRemote("param_set", name, value, category, security_limit, profile_key)
def param_set(
self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"
):
d = self.root.callRemote(
"param_set", name, value, category, security_limit, profile_key
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def param_ui_get(self, security_limit=-1, app='', extra='', profile_key="@DEFAULT@"):
def param_ui_get(self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"):
d = self.root.callRemote("param_ui_get", security_limit, app, extra, profile_key)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1063,7 +1363,7 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def params_register_app(self, xml, security_limit=-1, app=''):
def params_register_app(self, xml, security_limit=-1, app=""):
d = self.root.callRemote("params_register_app", xml, security_limit, app)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1078,12 +1378,21 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def params_values_from_category_get_async(self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"):
d = self.root.callRemote("params_values_from_category_get_async", category, security_limit, app, extra, profile_key)
def params_values_from_category_get_async(
self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
):
d = self.root.callRemote(
"params_values_from_category_get_async",
category,
security_limit,
app,
extra,
profile_key,
)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def presence_set(self, to_jid='', show='', statuses={}, profile_key="@DEFAULT@"):
def presence_set(self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"):
d = self.root.callRemote("presence_set", to_jid, show, statuses, profile_key)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1108,7 +1417,7 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def profile_create(self, profile, password='', component=''):
def profile_create(self, profile, password="", component=""):
d = self.root.callRemote("profile_create", profile, password, component)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
@ -1133,7 +1442,7 @@ class AIOBridge(bridge):
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())
def profile_start_session(self, password='', profile_key="@DEFAULT@"):
def profile_start_session(self, password="", profile_key="@DEFAULT@"):
d = self.root.callRemote("profile_start_session", password, profile_key)
d.addErrback(self._errback)
return d.asFuture(asyncio.get_event_loop())

View file

@ -71,11 +71,13 @@ VIDEO_SOURCE_AUTO: Final = "v4l2src"
AUDIO_SOURCE_AUTO: Final = "pulsesrc"
NONE_NOT_IMPLEMENTED_MSG: Final = "None value is not handled yet."
class VideoConfig(NamedTuple):
fps: int
bitrate: int
keyframe_max: int
WEBCAM = VideoConfig(fps=24, bitrate=1200000, keyframe_max=60)
DESKTOP = VideoConfig(fps=15, bitrate=800000, keyframe_max=30)
MUTED = VideoConfig(fps=24, bitrate=100000, keyframe_max=60)
@ -106,7 +108,7 @@ class WebRTC:
target_size: tuple[int, int] | None = None,
call_start_cb: Callable[[str, dict, str], Awaitable[str]] | None = None,
dc_data_list: list[SourcesDataChannel | SinksDataChannel] | None = None,
record_fd: int | None = None
record_fd: int | None = None,
) -> None:
"""Initializes a new WebRTC instance.
@ -257,7 +259,6 @@ class WebRTC:
raise Exception("self._media_types_inv should not be None!")
return self._media_types_inv
@property
def remote_desc_set(self) -> bool:
return self._remote_desc_set
@ -279,11 +280,11 @@ class WebRTC:
self._send_buffered_local_candidates()
@property
def record_fd(self) -> int|None:
def record_fd(self) -> int | None:
return self._record_fd
@record_fd.setter
def record_fd(self, value: int|None) -> None:
def record_fd(self, value: int | None) -> None:
"""Set or unset the recording file descriptor.
When set during an active call, starts recording.
@ -627,7 +628,7 @@ class WebRTC:
local_video_sink_elt = ""
else:
local_video_sink_elt = "autovideosink"
case SinksNone()|SinksPipeline():
case SinksNone() | SinksPipeline():
local_video_sink_elt = ""
case _:
raise exceptions.InternalError(
@ -659,32 +660,38 @@ class WebRTC:
]
if video_source_elt:
video_elements.extend([
f"{video_source_elt} name=video_src",
"! queue max-size-buffers=3 leaky=downstream",
video_elements.extend(
[
f"{video_source_elt} name=video_src",
"! queue max-size-buffers=3 leaky=downstream",
"! video_selector.",
"",
]
)
video_elements.extend(
[
"videotestsrc name=muted_src is-live=true pattern=black",
"! queue leaky=downstream",
"! video_selector.",
"",
])
video_elements.extend([
"videotestsrc name=muted_src is-live=true pattern=black",
"! queue leaky=downstream",
"! video_selector.",
"",
"t.",
"! queue max-size-buffers=3 leaky=downstream",
"! videorate",
f"! capsfilter name=main_rate_caps caps=video/x-raw,framerate={WEBCAM.fps}/1",
"! videoconvert",
f"! vp8enc name=vp8enc deadline=1 keyframe-max-dist={WEBCAM.keyframe_max} cpu-used=5 target-bitrate={WEBCAM.bitrate} error-resilient=1",
"! rtpvp8pay picture-id-mode=15-bit mtu=1200",
f"! application/x-rtp,media=video,encoding-name=VP8,payload={video_pt}",
"! sendrecv.",
])
"t.",
"! queue max-size-buffers=3 leaky=downstream",
"! videorate",
f"! capsfilter name=main_rate_caps caps=video/x-raw,framerate={WEBCAM.fps}/1",
"! videoconvert",
f"! vp8enc name=vp8enc deadline=1 keyframe-max-dist={WEBCAM.keyframe_max} cpu-used=5 target-bitrate={WEBCAM.bitrate} error-resilient=1",
"! rtpvp8pay picture-id-mode=15-bit mtu=1200",
f"! application/x-rtp,media=video,encoding-name=VP8,payload={video_pt}",
"! sendrecv.",
]
)
gst_pipe_elements.append("\n".join(video_elements))
if local_video_sink_elt and (video_source_elt or isinstance(self.sources_data, SourcesStdin)):
if local_video_sink_elt and (
video_source_elt or isinstance(self.sources_data, SourcesStdin)
):
# Local video feedback.
gst_pipe_elements.append(
f"""
@ -700,23 +707,27 @@ class WebRTC:
audio_elements = []
if audio_source_elt:
audio_elements.extend([
f"{audio_source_elt} name=audio_src",
"! valve name=audio_valve",
])
audio_elements.extend(
[
f"{audio_source_elt} name=audio_src",
"! valve name=audio_valve",
]
)
else:
# For stdin, just create the valve for dynamic linking
audio_elements.append("valve name=audio_valve")
audio_elements.extend([
"! queue max-size-buffers=10 max-size-time=0 max-size-bytes=0 leaky=downstream",
"! audioconvert",
"! audioresample",
"! opusenc audio-type=voice bitrate=32000",
"! rtpopuspay",
f"! application/x-rtp,media=audio,encoding-name=OPUS,payload={audio_pt}",
"! sendrecv.",
])
audio_elements.extend(
[
"! queue max-size-buffers=10 max-size-time=0 max-size-bytes=0 leaky=downstream",
"! audioconvert",
"! audioresample",
"! opusenc audio-type=voice bitrate=32000",
"! rtpopuspay",
f"! application/x-rtp,media=audio,encoding-name=OPUS,payload={audio_pt}",
"! sendrecv.",
]
)
gst_pipe_elements.append("\n".join(audio_elements))
@ -988,9 +999,7 @@ class WebRTC:
return max_width, new_height
def on_video_pad_probe(
self,
pad: Gst.Pad,
info: Gst.PadProbeInfo
self, pad: Gst.Pad, info: Gst.PadProbeInfo
) -> Gst.PadProbeReturn:
"""Monitor video pad for GAP events indicating packet loss.
@ -1075,7 +1084,10 @@ class WebRTC:
depay_src_pad = element.get_static_pad("src")
if depay_src_pad:
peer_pad = depay_src_pad.get_peer()
if peer_pad and self._recording_muxer == peer_pad.get_parent():
if (
peer_pad
and self._recording_muxer == peer_pad.get_parent()
):
log.debug(f"Releasing muxer pad: {peer_pad.get_name()}")
self._recording_muxer.release_request_pad(peer_pad)
@ -1118,21 +1130,26 @@ class WebRTC:
queue = Gst.ElementFactory.make("queue")
if name.startswith('video/'):
if name.startswith("video/"):
log.debug("===> VIDEO OK")
self._remote_video_pad = pad
# Monitor for events to detect packet loss/corruption
pad.add_probe(
Gst.PadProbeType.EVENT_DOWNSTREAM,
self.on_video_pad_probe
)
pad.add_probe(Gst.PadProbeType.EVENT_DOWNSTREAM, self.on_video_pad_probe)
# Check and log the original size of the video
structure = caps.get_structure(0)
width = structure.get_int('width')[1] if structure.has_field('width') else self.target_width
height = structure.get_int('height')[1] if structure.has_field('height') else self.target_height
width = (
structure.get_int("width")[1]
if structure.has_field("width")
else self.target_width
)
height = (
structure.get_int("height")[1]
if structure.has_field("height")
else self.target_height
)
log.debug(f"Original video size: {width}x{height}")
log.debug(f"Target size: {self.target_width}x{self.target_height}")
@ -1147,7 +1164,6 @@ class WebRTC:
height = (height + 3) // 4 * 4
log.info(f"Adjusted video size: {width}x{height}")
convert = Gst.ElementFactory.make("videoconvert")
if self.merge_pip:
@ -1181,8 +1197,12 @@ class WebRTC:
elif isinstance(self.sinks_data, SinksApp):
# ``app`` sink without ``self.merge_pip`` set, be create the sink and
# connect it to the ``remote_video_cb``.
remote_video_sink = Gst.ElementFactory.make("appsink", "remote_video_sink")
remote_video_sink.set_property("caps", Gst.Caps.from_string("video/x-raw,format=RGB"))
remote_video_sink = Gst.ElementFactory.make(
"appsink", "remote_video_sink"
)
remote_video_sink.set_property(
"caps", Gst.Caps.from_string("video/x-raw,format=RGB")
)
remote_video_sink.set_property("emit-signals", True)
remote_video_sink.set_property("drop", True)
remote_video_sink.set_property("max-buffers", 10)
@ -1192,17 +1212,18 @@ class WebRTC:
remote_video_sink.set_property("qos", True)
if self.sinks_data.remote_video_cb:
remote_video_sink.connect("new-sample", self.sinks_data.remote_video_cb)
remote_video_sink.connect(
"new-sample", self.sinks_data.remote_video_cb
)
else:
log.error("sinks_data.remote_video_cb is not available! Cannot display remote video.")
log.error(
"sinks_data.remote_video_cb is not available! Cannot display remote video."
)
return
elif (
isinstance(self.sinks_data, SinksAuto)
or (
# We have custom sinks, but video is automatic.
isinstance(self.sinks_data, SinksPipeline)
and self.sinks_data.video_pipeline is None
)
elif isinstance(self.sinks_data, SinksAuto) or (
# We have custom sinks, but video is automatic.
isinstance(self.sinks_data, SinksPipeline)
and self.sinks_data.video_pipeline is None
):
# if ``self.merge_pip`` is not set, we create a dedicated
# ``autovideosink`` for remote stream.
@ -1213,7 +1234,9 @@ class WebRTC:
# Video sink is deactivated.
remote_video_sink = Gst.ElementFactory.make("fakesink")
else:
remote_video_sink = Gst.parse_bin_from_description(self.sinks_data.video_pipeline)
remote_video_sink = Gst.parse_bin_from_description(
self.sinks_data.video_pipeline
)
iterator = remote_video_sink.iterate_elements()
ret, first_element = iterator.next()
@ -1227,7 +1250,6 @@ class WebRTC:
f'Unhandled "sinks_data" value: {self.sinks_data!r}'
)
if adjust_resolution:
log.debug("Applying adjust resolution pipeline.")
videoscale = Gst.ElementFactory.make("videoscale")
@ -1241,7 +1263,9 @@ class WebRTC:
if self.merge_pip:
self.pipeline.add(queue, convert, videoscale, capsfilter)
else:
self.pipeline.add(queue, convert, videoscale, capsfilter, remote_video_sink)
self.pipeline.add(
queue, convert, videoscale, capsfilter, remote_video_sink
)
ret = pad.link(queue.get_static_pad("sink"))
if ret != Gst.PadLinkReturn.OK:
@ -1289,7 +1313,7 @@ class WebRTC:
log.info("Successfully linked remote video stream.")
elif name.startswith('audio/'):
elif name.startswith("audio/"):
log.debug("===> Audio OK")
# Create the audio sink chain: queue -> convert -> resample -> sink
if isinstance(self.sinks_data, SinksPipeline):
@ -1309,7 +1333,9 @@ class WebRTC:
log.info("Audio stream won't be played live.")
return
case _:
remote_audio_sink = Gst.parse_bin_from_description(self.sinks_data.audio_pipeline)
remote_audio_sink = Gst.parse_bin_from_description(
self.sinks_data.audio_pipeline
)
iterator = remote_audio_sink.iterate_elements()
ret, first_element = iterator.next()
@ -1379,7 +1405,7 @@ class WebRTC:
log.debug(f"Processing incoming {media_type} stream.")
current_state = self.pipeline.get_state(0)[1]
needs_state_restore = (current_state == Gst.State.PLAYING)
needs_state_restore = current_state == Gst.State.PLAYING
if needs_state_restore:
log.debug("Pausing pipeline for safe modification.")
@ -1430,7 +1456,10 @@ class WebRTC:
# Link tee -> decodebin (playback branch)
playback_pad = tee.get_request_pad("src_%u")
if playback_pad.link(decodebin.get_static_pad("sink")) != Gst.PadLinkReturn.OK:
if (
playback_pad.link(decodebin.get_static_pad("sink"))
!= Gst.PadLinkReturn.OK
):
log.error(f"Failed to link tee to decodebin for {media_type}.")
self.pipeline.remove(tee)
self.pipeline.remove(decodebin)
@ -1440,7 +1469,9 @@ class WebRTC:
# If recording is active, add recording branch from tee
if self._record_fd is not None:
log.info(f"Recording is active, adding recording branch for {media_type}.")
log.info(
f"Recording is active, adding recording branch for {media_type}."
)
recording_pad = tee.get_request_pad("src_%u")
if not self._add_rtp_recording_branch(recording_pad, media_type):
log.warning(f"Failed to add recording branch for {media_type}")
@ -1509,7 +1540,9 @@ class WebRTC:
if not self._recording_muxer.link(fdsink):
log.error("Failed to link muxer to sink")
self._cleanup_elements([self._recording_muxer, fdsink], self._recording_elements)
self._cleanup_elements(
[self._recording_muxer, fdsink], self._recording_elements
)
self._recording_muxer = None
return False
@ -1608,7 +1641,7 @@ class WebRTC:
log.info(f"Handling stdin decoded pad of type {name}")
log.info(f"Pad caps: {caps.to_string()}")
if name.startswith('video/'):
if name.startswith("video/"):
log.info("===> VIDEO (stdin)")
video_selector = self.pipeline.get_by_name("video_selector")
@ -1696,7 +1729,7 @@ class WebRTC:
state, _, _ = self.pipeline.get_state(0)
log.debug(f"Pipeline state: {state}.")
elif name.startswith('audio/'):
elif name.startswith("audio/"):
log.info("===> AUDIO (stdin)")
audio_valve = self.pipeline.get_by_name("audio_valve")
@ -1723,7 +1756,9 @@ class WebRTC:
sink_pad = clocksync.get_static_pad("sink")
link_result = pad.link(sink_pad)
if link_result != Gst.PadLinkReturn.OK:
log.error(f"Failed to link decodebin pad to clocksync sink: {link_result}")
log.error(
f"Failed to link decodebin pad to clocksync sink: {link_result}"
)
return
if not clocksync.link(queue):
@ -1733,7 +1768,9 @@ class WebRTC:
sink_pad = queue.get_static_pad("sink")
link_result = pad.link(sink_pad)
if link_result != Gst.PadLinkReturn.OK:
log.error(f"Failed to link decodebin pad to queue sink: {link_result}")
log.error(
f"Failed to link decodebin pad to queue sink: {link_result}"
)
return
link_result = queue.link(audio_valve)
@ -2089,7 +2126,9 @@ class WebRTC:
rate_caps_filter = self.pipeline.get_by_name("main_rate_caps")
if rate_caps_filter is None:
raise exceptions.InternalError("Can't find main_rate_caps, it should be here.")
raise exceptions.InternalError(
"Can't find main_rate_caps, it should be here."
)
config = VIDEO_CONFIG[source]
vp8enc.set_property("target-bitrate", config.bitrate)
@ -2156,9 +2195,7 @@ class WebRTC:
queue.set_property("max-size-buffers", 3)
queue.set_property("flush-on-eos", True)
desktop_elements = [
desktop_src, video_scale, video_convert, video_rate, queue
]
desktop_elements = [desktop_src, video_scale, video_convert, video_rate, queue]
for element in desktop_elements:
self.pipeline.add(element)
@ -2196,7 +2233,9 @@ class WebRTC:
self._cleanup_elements(desktop_elements)
return
log.debug(f"Requested and received pad {self.desktop_sink_pad.get_name()} from video_selector.")
log.debug(
f"Requested and received pad {self.desktop_sink_pad.get_name()} from video_selector."
)
queue_src_pad = queue.get_static_pad("src")
link_ret = queue_src_pad.link(self.desktop_sink_pad)
@ -2214,9 +2253,7 @@ class WebRTC:
log.debug("Desktop source pipeline successfully created and linked.")
def _cleanup_elements(
self,
elements: list[Gst.Element],
elements_list: list[Gst.Element]|None = None
self, elements: list[Gst.Element], elements_list: list[Gst.Element] | None = None
) -> None:
"""Helper to cleanup elements.
@ -2233,7 +2270,9 @@ class WebRTC:
if elements_list and element in elements_list:
elements_list.remove(element)
except Exception as e:
log.warning(f"Error cleaning up element {element.get_name() if element else 'Unknown'}: {e}")
log.warning(
f"Error cleaning up element {element.get_name() if element else 'Unknown'}: {e}"
)
def _remove_desktop_source(self, desktop_src: Gst.Element) -> None:
"""Remove the desktop source from the pipeline.
@ -2248,7 +2287,14 @@ class WebRTC:
queue = self.pipeline.get_by_name("desktop_queue")
# Unlink and remove in reverse order
elements = [queue, capsfilter, video_scale, video_rate, video_convert, desktop_src]
elements = [
queue,
capsfilter,
video_scale,
video_rate,
video_convert,
desktop_src,
]
self._cleanup_elements(elements)