@@ -54,6 +54,7 @@ static bool start_monitor = false;
static int num_devs = 0;
static const char *qemu_binary = NULL;
static const char *kernel_image = NULL;
+static char *audio_server;
static const char *qemu_table[] = {
"qemu-system-x86_64",
@@ -252,11 +253,11 @@ static void start_qemu(void)
"TESTHOME=%s TESTDBUS=%u TESTDAEMON=%u "
"TESTDBUSSESSION=%u XDG_RUNTIME_DIR=/run/user/0 "
"TESTMONITOR=%u TESTEMULATOR=%u TESTDEVS=%d "
- "TESTAUTO=%u TESTARGS=\'%s\'",
+ "TESTAUTO=%u TESTAUDIO='%s' TESTARGS=\'%s\'",
initcmd, cwd, start_dbus, start_daemon,
start_dbus_session,
start_monitor, start_emulator, num_devs,
- run_auto, testargs);
+ run_auto, audio_server, testargs);
argv = alloca(sizeof(qemu_argv) +
(sizeof(char *) * (4 + (num_devs * 4))));
@@ -723,13 +724,120 @@ static pid_t start_btvirt(const char *home)
return pid;
}
+static int create_pipewire_conf(void)
+{
+ static const char *const dirs[] = {
+ "/run/conf",
+ "/run/conf/wireplumber",
+ "/run/conf/wireplumber/bluetooth.lua.d",
+ "/run/conf/wireplumber/main.lua.d",
+ NULL
+ };
+ int i;
+ FILE *f;
+
+ for (i = 0; dirs[i]; ++i)
+ mkdir(dirs[i], 0755);
+
+ /* Enable only Bluetooth part, disable whatever requires user DBus */
+ f = fopen("/run/conf/wireplumber/main.lua.d/51-custom.lua", "w");
+ if (!f)
+ goto fail;
+
+ fprintf(f, "alsa_monitor.enabled = false\n"
+ "v4l2_monitor.enabled = false\n"
+ "libcamera_monitor.enabled = false\n"
+ "default_access.properties[\"enable-flatpak-portal\"]"
+ " = false\n");
+ fclose(f);
+
+ f = fopen("/run/conf/wireplumber/bluetooth.lua.d/51-custom.lua", "w");
+ if (!f)
+ goto fail;
+
+ fprintf(f, "bluez_monitor.properties[\"with-logind\"] = false\n"
+ "bluez_midi_monitor.enabled = false\n");
+ fclose(f);
+
+ return 0;
+
+fail:
+ perror("Failed to create Pipewire config");
+ return -1;
+}
+
+static int start_audio_server(pid_t pids[2])
+{
+ char *daemons[2] = {NULL, NULL};
+ char wp_exe[PATH_MAX];
+ char *ptr;
+ char *envp[5];
+ int i;
+
+ daemons[0] = audio_server;
+
+ ptr = strrchr(audio_server, '/');
+ if (ptr && !strcmp(ptr, "/pipewire")) {
+ if (create_pipewire_conf())
+ return -1;
+
+ snprintf(wp_exe, sizeof(wp_exe), "%.*s/wireplumber",
+ (int)(ptr - audio_server), audio_server);
+ daemons[1] = wp_exe;
+
+ setenv("PIPEWIRE_RUNTIME_DIR", "/run", 1);
+ }
+
+ envp[0] = "DBUS_SYSTEM_BUS_ADDRESS=unix:"
+ "path=/run/dbus/system_bus_socket";
+ envp[1] = "XDG_CONFIG_HOME=/run/conf";
+ envp[2] = "XDG_STATE_HOME=/run";
+ envp[3] = "XDG_RUNTIME_DIR=/run";
+ envp[4] = NULL;
+
+ for (i = 0; i < 2; ++i)
+ pids[i] = -1;
+
+ for (i = 0; i < 2; ++i) {
+ const char *daemon = daemons[i];
+ char *argv[2];
+ pid_t pid;
+
+ if (!daemon)
+ continue;
+
+ printf("Starting audio server %s\n", daemon);
+
+ argv[0] = (char *) daemon;
+ argv[1] = NULL;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("Failed to fork new process");
+ return -1;
+ }
+
+ if (pid == 0) {
+ execve(argv[0], argv, envp);
+ exit(EXIT_SUCCESS);
+ }
+
+ pids[i] = pid;
+
+ printf("Audio server process %d created\n", pid);
+ }
+
+ return 0;
+}
+
static void run_command(char *cmdname, char *home)
{
char *argv[9], *envp[3];
int pos = 0, idx = 0;
int serial_fd;
pid_t pid, dbus_pid, daemon_pid, monitor_pid, emulator_pid,
- dbus_session_pid;
+ dbus_session_pid, audio_pid[2];
+ int i;
if (!home) {
perror("Invalid parameter: TESTHOME");
@@ -777,6 +885,11 @@ static void run_command(char *cmdname, char *home)
else
emulator_pid = -1;
+ if (audio_server)
+ start_audio_server(audio_pid);
+ else
+ audio_pid[0] = audio_pid[1] = -1;
+
start_next:
if (run_auto) {
if (chdir(home + 5) < 0) {
@@ -878,6 +991,13 @@ start_next:
monitor_pid = -1;
}
+ for (i = 0; i < 2; ++i) {
+ if (corpse == audio_pid[i]) {
+ printf("Audio server %d terminated\n", i);
+ audio_pid[i] = -1;
+ }
+ }
+
if (corpse == pid)
break;
}
@@ -887,6 +1007,11 @@ start_next:
goto start_next;
}
+ for (i = 0; i < 2; ++i) {
+ if (audio_pid[i] > 0)
+ kill(audio_pid[i], SIGTERM);
+ }
+
if (daemon_pid > 0)
kill(daemon_pid, SIGTERM);
@@ -982,6 +1107,17 @@ static void run_tests(void)
start_emulator = true;
}
+ ptr = strstr(cmdline, "TESTAUDIO='");
+ if (ptr) {
+ const char *start = ptr + 11;
+ const char *end = strchr(start, '\'');
+
+ if (end) {
+ audio_server = strndup(start, end - start);
+ printf("Audio server %s requested\n", audio_server);
+ }
+ }
+
ptr = strstr(cmdline, "TESTHOME=");
if (ptr) {
home = ptr + 4;
@@ -1005,6 +1141,7 @@ static void usage(void)
"\t-d, --daemon Start bluetoothd\n"
"\t-m, --monitor Start btmon\n"
"\t-l, --emulator Start btvirt\n"
+ "\t-A, --audio[=path] Start audio server\n"
"\t-u, --unix [path] Provide serial device\n"
"\t-q, --qemu <path> QEMU binary\n"
"\t-k, --kernel <image> Kernel image (bzImage)\n"
@@ -1022,6 +1159,7 @@ static const struct option main_options[] = {
{ "monitor", no_argument, NULL, 'm' },
{ "qemu", required_argument, NULL, 'q' },
{ "kernel", required_argument, NULL, 'k' },
+ { "audio", optional_argument, NULL, 'A' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
@@ -1041,7 +1179,7 @@ int main(int argc, char *argv[])
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "aubdslmq:k:vh", main_options,
+ opt = getopt_long(argc, argv, "aubdslmq:k:A::vh", main_options,
NULL);
if (opt < 0)
break;
@@ -1075,6 +1213,9 @@ int main(int argc, char *argv[])
case 'k':
kernel_image = optarg;
break;
+ case 'A':
+ audio_server = optarg ? optarg : "/usr/bin/pipewire";
+ break;
case 'v':
printf("%s\n", VERSION);
return EXIT_SUCCESS;