From 50eeb2f16dfa4342d50086404da068f5426cbe3c Mon Sep 17 00:00:00 2001 From: Marvin W Date: Wed, 9 Apr 2025 20:02:55 +0200 Subject: RTP: Tear down most of GStreamer while not in a call. This includes #1679 and works around an upstream bug in pipewire causing #1685 --- plugins/rtp/src/plugin.vala | 66 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 15 deletions(-) (limited to 'plugins/rtp/src/plugin.vala') diff --git a/plugins/rtp/src/plugin.vala b/plugins/rtp/src/plugin.vala index 58ce871c..a94c0ba0 100644 --- a/plugins/rtp/src/plugin.vala +++ b/plugins/rtp/src/plugin.vala @@ -12,12 +12,12 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object { private Gee.List streams = new ArrayList(); private Gee.List devices = new ArrayList(); + private int64 last_devices_refresh = 0; // private Gee.List participants = new ArrayList(); public void registered(Dino.Application app) { this.app = app; this.codec_util = new CodecUtil(); - app.startup.connect(startup); app.add_option_group(Gst.init_get_option_group()); app.stream_interactor.module_manager.initialize_account_modules.connect((account, list) => { list.add(new Module(this)); @@ -42,22 +42,54 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object { if (pause_count < 0) warning("Pause count below zero!"); } - private void init_device_monitor() { + private void handle_existing_devices(Gst.DeviceMonitor device_monitor) { + var new_devices = new ArrayList(); + foreach (Gst.Device device in device_monitor.get_devices()) { + if (device.properties == null) continue; + if (device.properties.has_name("pipewire-proplist") && device.has_classes("Audio")) continue; + if (device.properties.get_string("device.class") == "monitor") continue; + var pre_device = devices.first_match((it) => it.matches(device)); + if (pre_device != null) { + if (!new_devices.contains(pre_device)) new_devices.add(pre_device); + continue; + } + var new_device = new Device(this, device); + devices.add(new_device); + new_devices.add(new_device); + } + devices.retain_all(new_devices); + } + + private void refresh_devices() { + if (device_monitor != null) return; // No manual refresh needed, we're monitoring actively. + if (last_devices_refresh > 0 && last_devices_refresh + 5000000 > get_monotonic_time()) return; // Already current + var device_monitor = new Gst.DeviceMonitor(); + device_monitor.show_all = true; + device_monitor.start(); + handle_existing_devices(device_monitor); + device_monitor.stop(); + last_devices_refresh = get_monotonic_time(); + } + + private void start_device_monitor() { if (device_monitor != null) return; device_monitor = new Gst.DeviceMonitor(); device_monitor.show_all = true; device_monitor.get_bus().add_watch(Priority.DEFAULT, on_device_monitor_message); device_monitor.start(); - foreach (Gst.Device device in device_monitor.get_devices()) { - if (device.properties.has_name("pipewire-proplist") && device.has_classes("Audio")) continue; - if (device.properties.get_string("device.class") == "monitor") continue; - if (devices.any_match((it) => it.matches(device))) continue; - devices.add(new Device(this, device)); - } + handle_existing_devices(device_monitor); + } + + private void stop_device_monitor() { + if (device_monitor == null) return; + device_monitor.stop(); + device_monitor = null; } private void init_call_pipe() { if (pipe != null) return; + debug("Creating call pipe."); + start_device_monitor(); pipe = new Gst.Pipeline(null); // RTP @@ -90,6 +122,12 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object { pipe.set_state(Gst.State.PLAYING); } + public void destroy_call_pipe_if_unused() { + if (streams.is_empty && !VideoWidget.has_instances()) { + destroy_call_pipe(); + } + } + private void destroy_call_pipe() { if (pipe == null) return; pipe.set_state(Gst.State.NULL); @@ -98,10 +136,8 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object { echoprobe = null; #endif pipe = null; - } - - public void startup() { - init_device_monitor(); + stop_device_monitor(); + debug("Call pipe destroyed"); } private static Gst.Caps? request_pt_map(Gst.Element rtpbin, uint session, uint pt, Plugin plugin) { @@ -269,12 +305,11 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object { public void close_stream(Stream stream) { streams.remove(stream); stream.destroy(); + destroy_call_pipe_if_unused(); } public void shutdown() { - if (device_monitor != null) { - device_monitor.stop(); - } + stop_device_monitor(); destroy_call_pipe(); Gst.deinit(); } @@ -292,6 +327,7 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object { } public Gee.List get_devices(string media, bool incoming) { + refresh_devices(); Gee.List devices; if (media == "video" && !incoming) { devices = get_video_sources(); -- cgit v1.3