Ver código fonte

linux-v4l2: Use flatpak-spawn when inside a Flatpak sandbox

It is not possible to run host system executables like modinfo, pkexec,
and modprobe inside a Flatpak sandbox. However, Flatpak provides a way
to run command on the host system: the flatpak-spawn executable.

flatpak-spawn is a tiny helper that, when executed with the '--host'
parameter, talks to the org.freedesktop.Flatpak D-Bus interface to run
and retrieve the return value of the executable. This provides OBS Studio
a way to escape this sandbox limitation without opening large holes in
the sandbox.

Make v4l2's implementation of VirtualCam run system commands using
flatpak-spawn when inside a Flatpak sandbox. The detection of the sandbox
is done by checking the existence of the /.flatpak-info file, which is
created by Flatpak itself, and only exists inside the sandbox. If OBS
Studio is not running inside a Flatpak sandbox, run the exact same command
it used to run before this commit.

Add the permission to talk to the org.freedesktop.Flatpak D-Bus interface
to the Flatpak manifest, so we can run flatpak-spawn with the '--host'
parameter.

Notice that the same constraints apply with and without Flatpak: the host
system needs to have the v4l2loopback kernel module available for the v4l2
implementation of VirtualCam to work.
Georges Basile Stavracas Neto 4 anos atrás
pai
commit
7a87777225

+ 1 - 0
CI/flatpak/com.obsproject.Studio.json

@@ -14,6 +14,7 @@
     "--filesystem=xdg-run/pipewire-0",
     "--filesystem=host",
     "--talk-name=org.kde.StatusNotifierWatcher",
+    "--talk-name=org.freedesktop.Flatpak",
     "--talk-name=org.freedesktop.ScreenSaver",
     "--talk-name=org.freedesktop.PowerManagement.Inhibit",
     "--talk-name=org.freedesktop.Notifications",

+ 33 - 4
plugins/linux-v4l2/v4l2-output.c

@@ -1,4 +1,5 @@
 #include <obs-module.h>
+#include <util/dstr.h>
 #include <util/platform.h>
 #include <linux/videodev2.h>
 #include <sys/ioctl.h>
@@ -26,6 +27,35 @@ static void virtualcam_destroy(void *data)
 	bfree(data);
 }
 
+static bool is_flatpak_sandbox(void)
+{
+	static bool flatpak_info_exists = false;
+	static bool initialized = false;
+
+	if (!initialized) {
+		flatpak_info_exists = access("/.flatpak-info", F_OK) == 0;
+		initialized = true;
+	}
+
+	return flatpak_info_exists;
+}
+
+static int run_command(const char *command)
+{
+	struct dstr str;
+	int result;
+
+	dstr_init_copy(&str, "PATH=\"$PATH:/sbin\" ");
+
+	if (is_flatpak_sandbox())
+		dstr_cat(&str, "flatpak-spawn --host ");
+
+	dstr_cat(&str, command);
+	result = system(str.array);
+	dstr_free(&str);
+	return result;
+}
+
 static bool loopback_module_loaded()
 {
 	bool loaded = false;
@@ -56,8 +86,7 @@ bool loopback_module_available()
 		return true;
 	}
 
-	if (system("PATH=\"$PATH:/sbin\" modinfo v4l2loopback >/dev/null 2>&1") ==
-	    0) {
+	if (run_command("modinfo v4l2loopback >/dev/null 2>&1") == 0) {
 		return true;
 	}
 
@@ -66,8 +95,8 @@ bool loopback_module_available()
 
 static int loopback_module_load()
 {
-	return system(
-		"PATH=\"$PATH:/sbin\" pkexec modprobe v4l2loopback exclusive_caps=1 card_label='OBS Virtual Camera' && sleep 0.5");
+	return run_command(
+		"pkexec modprobe v4l2loopback exclusive_caps=1 card_label='OBS Virtual Camera' && sleep 0.5");
 }
 
 static void *virtualcam_create(obs_data_t *settings, obs_output_t *output)