1 /*
2     Copyright (C) 2009 Grame
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.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program; if not, write to the Free Software
15     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 
17 */
18 
19 #include <string.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <assert.h>
25 #include <stdint.h>
26 
27 #include "reserve.h"
28 #include "audio_reserve.h"
29 #include "jack/control.h"
30 
31 #define DEVICE_MAX 2
32 
33 typedef struct reserved_audio_device {
34 
35      char device_name[64];
36      rd_device * reserved_device;
37 
38 } reserved_audio_device;
39 
40 static DBusConnection* gConnection = NULL;
41 static reserved_audio_device gReservedDevice[DEVICE_MAX];
42 static int gReserveCount = 0;
43 
audio_reservation_init()44 SERVER_EXPORT int audio_reservation_init()
45 {
46     DBusError error;
47     dbus_error_init(&error);
48 
49     if (!(gConnection = dbus_bus_get(DBUS_BUS_SESSION, &error))) {
50         jack_error("Failed to connect to session bus for device reservation: %s\n", error.message);
51         jack_info("To bypass device reservation via session bus, set JACK_NO_AUDIO_RESERVATION=1 prior to starting jackd.\n");
52         return -1;
53     }
54 
55     jack_info("audio_reservation_init");
56     return 0;
57 }
58 
audio_reservation_finish()59 SERVER_EXPORT int audio_reservation_finish()
60 {
61     if (gConnection) {
62         dbus_connection_unref(gConnection);
63         gConnection = NULL;
64         jack_info("audio_reservation_finish");
65     }
66     return 0;
67 }
68 
audio_acquire(const char * device_name)69 SERVER_EXPORT bool audio_acquire(const char * device_name)
70 {
71     DBusError error;
72     int ret;
73 
74     // Open DBus connection first time
75     if (gReserveCount == 0) {
76         if (audio_reservation_init() != 0) {
77             return false;
78         }
79     }
80 
81     assert(gReserveCount < DEVICE_MAX);
82 
83     dbus_error_init(&error);
84 
85     if ((ret= rd_acquire(
86                  &gReservedDevice[gReserveCount].reserved_device,
87                  gConnection,
88                  device_name,
89                  "Jack audio server",
90                  INT32_MAX,
91                  NULL,
92                  &error)) < 0) {
93 
94         jack_error("Failed to acquire device name : %s error : %s", device_name, (error.message ? error.message : strerror(-ret)));
95         dbus_error_free(&error);
96         return false;
97     }
98 
99     strcpy(gReservedDevice[gReserveCount].device_name, device_name);
100     gReserveCount++;
101     jack_info("Acquire audio card %s", device_name);
102     return true;
103 }
104 
audio_release(const char * device_name)105 SERVER_EXPORT void audio_release(const char * device_name)
106 {
107     int i;
108 
109     // Look for corresponding reserved device
110     for (i = 0; i < DEVICE_MAX; i++) {
111  	if (strcmp(gReservedDevice[i].device_name, device_name) == 0)
112 	    break;
113     }
114 
115     if (i < DEVICE_MAX) {
116         jack_info("Released audio card %s", device_name);
117         rd_release(gReservedDevice[i].reserved_device);
118     } else {
119         jack_error("Audio card %s not found!!", device_name);
120     }
121 
122     // Close DBus connection last time
123     gReserveCount--;
124     if (gReserveCount == 0)
125         audio_reservation_finish();
126 }
127 
audio_reserve_loop()128 SERVER_EXPORT void audio_reserve_loop()
129 {
130     if (gConnection != NULL) {
131        dbus_connection_read_write_dispatch (gConnection, 200);
132     }
133 }
134 
135