aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorMarvin W <git@larma.de>2022-02-08 21:57:48 +0100
committerMarvin W <git@larma.de>2022-02-08 21:58:18 +0100
commit43ea088f646a8b3a5c41699f48cf5f0b4e7d4107 (patch)
tree4354b0b23d98e9fbe31c1ca6696c9c73879d0216 /plugins
parent35526ab5a5e822f12bd6dd8ad3b49e242903ee00 (diff)
downloaddino-43ea088f646a8b3a5c41699f48cf5f0b4e7d4107.tar.gz
dino-43ea088f646a8b3a5c41699f48cf5f0b4e7d4107.zip
Calls: Device picker
Diffstat (limited to 'plugins')
-rw-r--r--plugins/rtp/src/device.vala28
-rw-r--r--plugins/rtp/src/plugin.vala149
-rw-r--r--plugins/rtp/src/stream.vala2
3 files changed, 100 insertions, 79 deletions
diff --git a/plugins/rtp/src/device.vala b/plugins/rtp/src/device.vala
index 97258d0c..e97a0d04 100644
--- a/plugins/rtp/src/device.vala
+++ b/plugins/rtp/src/device.vala
@@ -1,6 +1,14 @@
using Xmpp.Xep.JingleRtp;
using Gee;
+public enum Dino.Plugins.Rtp.DeviceProtocol {
+ OTHER,
+ PIPEWIRE,
+ V4L2,
+ PULSEAUDIO,
+ ALSA
+}
+
public class Dino.Plugins.Rtp.Device : MediaDevice, Object {
private const int[] common_widths = {320, 360, 400, 480, 640, 960, 1280, 1920, 2560, 3840};
@@ -8,10 +16,10 @@ public class Dino.Plugins.Rtp.Device : MediaDevice, Object {
public CodecUtil codec_util { get { return plugin.codec_util; } }
public Gst.Device device { get; private set; }
- public string id { get { return device_name; }}
- public string display_name { get { return device_display_name; }}
- public string detail_name { get {
- return device.properties.get_string("alsa.card_name") ?? device.properties.get_string("alsa.id") ?? id;
+ public string id { owned get { return device_name; }}
+ public string display_name { owned get { return device_display_name; }}
+ public string detail_name { owned get {
+ return device.properties.get_string("alsa.card_name") ?? device.properties.get_string("alsa.name") ?? device.properties.get_string("alsa.id") ?? device.properties.get_string("api.v4l2.cap.card") ?? id;
}}
public Gst.Pipeline pipe { get { return plugin.pipe; }}
@@ -26,6 +34,18 @@ public class Dino.Plugins.Rtp.Device : MediaDevice, Object {
}}
public bool is_source { get { return device.has_classes("Source"); }}
public bool is_sink { get { return device.has_classes("Sink"); }}
+ public bool is_monitor { get { return device.properties.get_string("device.class") == "monitor" || (protocol == DeviceProtocol.PIPEWIRE && device.has_classes("Stream")); } }
+ public bool is_default { get {
+ bool ret;
+ device.properties.get_boolean("is-default", out ret);
+ return ret;
+ }}
+ public DeviceProtocol protocol { get {
+ if (device.properties.has_name("pulse-proplist")) return DeviceProtocol.PULSEAUDIO;
+ if (device.properties.has_name("pipewire-proplist")) return DeviceProtocol.PIPEWIRE;
+ if (device.properties.has_name("v4l2deviceprovider")) return DeviceProtocol.V4L2;
+ return DeviceProtocol.OTHER;
+ }}
private string device_name;
private string device_display_name;
diff --git a/plugins/rtp/src/plugin.vala b/plugins/rtp/src/plugin.vala
index 0e519b37..e7ee7117 100644
--- a/plugins/rtp/src/plugin.vala
+++ b/plugins/rtp/src/plugin.vala
@@ -203,8 +203,6 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
switch (message.type) {
case Gst.MessageType.DEVICE_ADDED:
message.parse_device_added(out gst_device);
- if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
- if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
if (devices.any_match((it) => it.matches(gst_device))) return Source.CONTINUE;
device = new Device(this, gst_device);
devices.add(device);
@@ -212,16 +210,12 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
#if GST_1_16
case Gst.MessageType.DEVICE_CHANGED:
message.parse_device_changed(out gst_device, out old_gst_device);
- if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
- if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
device = devices.first_match((it) => it.matches(old_gst_device));
if (device != null) device.update(gst_device);
break;
#endif
case Gst.MessageType.DEVICE_REMOVED:
message.parse_device_removed(out gst_device);
- if (gst_device.properties.has_name("pipewire-proplist") && gst_device.has_classes("Audio")) return Source.CONTINUE;
- if (gst_device.properties.get_string("device.class") == "monitor") return Source.CONTINUE;
device = devices.first_match((it) => it.matches(gst_device));
if (device != null) devices.remove(device);
break;
@@ -310,46 +304,42 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
}
public Gee.List<MediaDevice> get_devices(string media, bool incoming) {
-
+ Gee.List<MediaDevice> devices;
if (media == "video" && !incoming) {
- return get_video_sources();
- }
-
- ArrayList<MediaDevice> result = new ArrayList<MediaDevice>();
- foreach (Device device in devices) {
- if (device.media == media && (incoming && device.is_sink || !incoming && device.is_source)) {
- result.add(device);
- }
+ devices = get_video_sources();
+ } else if (media == "audio") {
+ devices = get_audio_devices(incoming);
+ } else {
+ devices = new ArrayList<MediaDevice>();
+ devices.add_all_iterator(this.devices.filter(it => it.media == media && (incoming && it.is_sink || !incoming && it.is_source) && !it.is_monitor));
}
- if (media == "audio") {
- // Reorder sources
- result.sort((media_left, media_right) => {
- Device left = media_left as Device;
- Device right = media_right as Device;
- if (left == null) return 1;
- if (right == null) return -1;
-
- bool left_is_pipewire = left.device.properties.has_name("pipewire-proplist");
- bool right_is_pipewire = right.device.properties.has_name("pipewire-proplist");
+ devices.sort((media_left, media_right) => {
+ return strcmp(media_left.id, media_right.id);
+ });
- bool left_is_default = false;
- left.device.properties.get_boolean("is-default", out left_is_default);
- bool right_is_default = false;
- right.device.properties.get_boolean("is-default", out right_is_default);
+ return devices;
+ }
- // Prefer pipewire
- if (left_is_pipewire && !right_is_pipewire) return -1;
- if (right_is_pipewire && !left_is_pipewire) return 1;
+ public Gee.List<MediaDevice> get_audio_devices(bool incoming) {
+ ArrayList<MediaDevice> pulse_devices = new ArrayList<MediaDevice>();
+ ArrayList<MediaDevice> other_devices = new ArrayList<MediaDevice>();
- // Prefer pulse audio default device
- if (left_is_default && !right_is_default) return -1;
- if (right_is_default && !left_is_default) return 1;
+ foreach (Device device in devices) {
+ if (device.media != "audio") continue;
+ if (incoming && !device.is_sink || !incoming && !device.is_source) continue;
+ // Skip monitors
+ if (device.is_monitor) continue;
- return 0;
- });
+ if (device.protocol == DeviceProtocol.PULSEAUDIO) {
+ pulse_devices.add(device);
+ } else {
+ other_devices.add(device);
+ }
}
- return result;
+
+ // If we have any pulseaudio devices, present only those. Don't want duplicated devices from pipewire and pulseaudio.
+ return pulse_devices.size > 0 ? pulse_devices : other_devices;
}
public Gee.List<MediaDevice> get_video_sources() {
@@ -371,7 +361,10 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
// Don't allow grey-scale devices
if (!is_color) continue;
- if (device.device.properties.has_name("pipewire-proplist")) {
+ // Skip monitors
+ if (device.is_monitor) continue;
+
+ if (device.protocol == DeviceProtocol.PIPEWIRE) {
pipewire_devices.add(device);
} else {
other_devices.add(device);
@@ -379,46 +372,56 @@ public class Dino.Plugins.Rtp.Plugin : RootInterface, VideoCallPlugin, Object {
}
// If we have any pipewire devices, present only those. Don't want duplicated devices from pipewire and video for linux.
- ArrayList<MediaDevice> devices = pipewire_devices.size > 0 ? pipewire_devices : other_devices;
-
- // Reorder sources
- devices.sort((media_left, media_right) => {
- Device left = media_left as Device;
- Device right = media_right as Device;
- if (left == null) return 1;
- if (right == null) return -1;
-
- int left_fps = 0;
- for (int i = 0; i < left.device.caps.get_size(); i++) {
- unowned Gst.Structure structure = left.device.caps.get_structure(i);
- int num = 0, den = 0;
- if (structure.has_field("framerate") && structure.get_fraction("framerate", out num, out den)) left_fps = int.max(left_fps, num / den);
- }
-
- int right_fps = 0;
- for (int i = 0; i < left.device.caps.get_size(); i++) {
- unowned Gst.Structure structure = left.device.caps.get_structure(i);
- int num = 0, den = 0;
- if (structure.has_field("framerate") && structure.get_fraction("framerate", out num, out den)) right_fps = int.max(right_fps, num / den);
- }
-
- // More FPS is better
- if (left_fps > right_fps) return -1;
- if (right_fps > left_fps) return 1;
-
- return 0;
- });
+ return pipewire_devices.size > 0 ? pipewire_devices : other_devices;
+ }
- return devices;
+ private int get_max_fps(Device device) {
+ int fps = 0;
+ for (int i = 0; i < device.device.caps.get_size(); i++) {
+ unowned Gst.Structure structure = device.device.caps.get_structure(i);
+ int num = 0, den = 0;
+ if (structure.has_field("framerate") && structure.get_fraction("framerate", out num, out den)) fps = int.max(fps, num / den);
+ }
+ return fps;
}
public Device? get_preferred_device(string media, bool incoming) {
+ Gee.List<Device> devices = new ArrayList<Device>();
foreach (MediaDevice media_device in get_devices(media, incoming)) {
- Device? device = media_device as Device;
- if (device != null) return device;
+ if (media_device is Device) devices.add((Device)media_device);
+ }
+ if (devices.is_empty) {
+ warning("No preferred device for %s %s. Media will not be processed.", incoming ? "incoming" : "outgoing", media);
+ return null;
+ }
+
+ // Take default if present
+ foreach (Device device in devices) {
+ if (device.is_default) {
+ debug("Using %s for %s %s as it's default", device.display_name, incoming ? "incoming" : "outgoing", media);
+ return device;
+ }
+ }
+
+ if (media == "video") {
+ // Pick best FPS
+ int max_fps = 0;
+ Device? max_fps_device = null;
+ foreach (Device device in devices) {
+ int fps = get_max_fps(device);
+ if (fps > max_fps) {
+ max_fps = fps;
+ max_fps_device = device;
+ }
+ }
+ debug("Using %s for %s %s as it has max FPS (%d)", max_fps_device.display_name, incoming ? "incoming" : "outgoing", media, max_fps);
+ return max_fps_device;
+ } else {
+ // Pick any
+ Device? device = devices.first();
+ debug("Using %s for %s %s as it's first pick", device.display_name, incoming ? "incoming" : "outgoing", media);
+ return device;
}
- warning("No preferred device for %s %s. Media will not be processed.", incoming ? "incoming" : "outgoing", media);
- return null;
}
public MediaDevice? get_device(Xmpp.Xep.JingleRtp.Stream stream, bool incoming) {
diff --git a/plugins/rtp/src/stream.vala b/plugins/rtp/src/stream.vala
index dc712b61..2a236533 100644
--- a/plugins/rtp/src/stream.vala
+++ b/plugins/rtp/src/stream.vala
@@ -318,8 +318,6 @@ public class Dino.Plugins.Rtp.Stream : Xmpp.Xep.JingleRtp.Stream {
}
if (our_ssrc != buffer_ssrc) {
warning("Sending RTP %s buffer seq %u with SSRC %u when our ssrc is %u", media, buffer_seq, buffer_ssrc, our_ssrc);
- } else {
- debug("Sending RTP %s buffer seq %u with SSRC %u", media, buffer_seq, buffer_ssrc);
}
}