proper dbus device reservation
[ardour.git] / libs / ardouralsautil / request_device.c
1 /*
2  * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <errno.h>
26
27 #include "ardouralsautil/reserve.h"
28
29 static int run = 1;
30
31 static void wearedone(int sig) {
32         (void) sig; // skip 'unused variable' compiler warning;
33         fprintf(stderr, "caught signal - shutting down.\n");
34         run=0;
35 }
36
37 static int stdin_available(void) {
38         errno = 0;
39         if (fcntl(STDIN_FILENO, F_GETFD) == 1) return 0;
40         return errno != EBADF;
41 }
42
43 static void usage(int status) {
44         printf ("ardour-request-device - DBus Audio Reservation Utility.\n");
45         printf ("Usage: ardour-request-device [ OPTIONS ] <Audio-Device-ID>\n");
46         printf ("Options:\n\
47       -h, --help                 display this help and exit\n\
48       -V, --version              print version information and exit\n\
49 ");
50
51         printf ("\n\
52 This tool issues a dbus request to reserve an ALSA Audio-device.\n\
53 If successful other users of the device (e.g. pulseaudio) will\n\
54 release the device so that ardour can access it.\n\
55 \n\
56 ardour-request-device announces itself as \"Ardour ALSA Backend\" and uses the\n\
57 maximum possible priority for requesting the device.\n\
58 \n\
59 The audio-device-id is a string e.g. 'Audio1'\n\
60 \n\
61 Examples:\n\
62 ardour-request-device Audio0\n\
63 \n");
64
65         printf ("Report bugs to Robin Gareus <robin@gareus.org>\n");
66         exit (status);
67 }
68
69 static void print_version(void) {
70         printf ("ardour-request-device 0.1\n\n");
71         printf (
72                         "Copyright (C) 2014 Robin Gareus <robin@gareus.org>\n"
73                         "This is free software; see the source for copying conditions.  There is NO\n"
74                         "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
75                         );
76         exit (0);
77 }
78
79 int main(int argc, char **argv) {
80         DBusConnection* dbus_connection = NULL;
81         rd_device * reserved_device = NULL;
82         DBusError error;
83         int ret;
84
85         if (argc < 2 || argc > 2) {
86                 usage(EXIT_FAILURE);
87         }
88         if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
89                 print_version();
90         }
91         if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
92                 usage(EXIT_SUCCESS);
93         }
94
95         const char *device_name = argv[1];
96
97         dbus_error_init(&error);
98
99         if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SESSION, &error))) {
100                 fprintf(stderr, "Failed to connect to session bus for device reservation: %s\n", error.message ? error.message : "unknown error.");
101                 dbus_error_free(&error);
102                 return EXIT_FAILURE;
103         }
104
105         if ((ret = rd_acquire (
106                                         &reserved_device,
107                                         dbus_connection,
108                                         device_name,
109                                         "Ardour ALSA Backend",
110                                         INT32_MAX,
111                                         NULL,
112                                         &error)) < 0)
113         {
114                 fprintf(stderr, "Failed to acquire device: '%s'\n%s\n", device_name, (error.message ? error.message : strerror(-ret)));
115                 dbus_error_free(&error);
116                 dbus_connection_unref(dbus_connection);
117                 return EXIT_FAILURE;
118         }
119
120         fprintf(stdout, "Acquired audio-card '%s'\n", device_name);
121         fprintf(stdout, "Press Ctrl+C or close stdin to release the device.\n");
122         fflush(stdout);
123
124         signal(SIGTERM, wearedone);
125         signal(SIGINT, wearedone);
126
127         while (run && dbus_connection_read_write_dispatch (dbus_connection, 200)) {
128                 if (!stdin_available()) {
129                         fprintf(stderr, "stdin closed - shutting down.\n");
130                         break;
131                 }
132         }
133
134         rd_release (reserved_device);
135         fprintf(stdout, "Released audio-card '%s'\n", device_name);
136         dbus_error_free(&error);
137         dbus_connection_unref(dbus_connection);
138         return EXIT_SUCCESS;
139 }