2 This file is part of PulseAudio.
4 Copyright 2008-2013 João Paulo Rechi Vita
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <pulse/xmalloc.h>
28 #include <pulsecore/core.h>
29 #include <pulsecore/core-util.h>
30 #include <pulsecore/dbus-shared.h>
31 #include <pulsecore/log.h>
32 #include <pulsecore/macro.h>
33 #include <pulsecore/refcnt.h>
34 #include <pulsecore/shared.h>
36 #include "bluez5-util.h"
38 #define BLUEZ_SERVICE "org.bluez"
40 struct pa_bluetooth_discovery
{
44 pa_dbus_connection
*connection
;
47 pa_hook hooks
[PA_BLUETOOTH_HOOK_MAX
];
51 static pa_bluetooth_adapter
* adapter_create(pa_bluetooth_discovery
*y
, const char *path
) {
52 pa_bluetooth_adapter
*a
;
57 a
= pa_xnew0(pa_bluetooth_adapter
, 1);
59 a
->path
= pa_xstrdup(path
);
61 pa_hashmap_put(y
->adapters
, a
->path
, a
);
66 static void adapter_remove_all(pa_bluetooth_discovery
*y
) {
67 pa_bluetooth_adapter
*a
;
71 while ((a
= pa_hashmap_steal_first(y
->adapters
))) {
78 pa_hook
* pa_bluetooth_discovery_hook(pa_bluetooth_discovery
*y
, pa_bluetooth_hook_t hook
) {
80 pa_assert(PA_REFCNT_VALUE(y
) > 0);
82 return &y
->hooks
[hook
];
85 static DBusHandlerResult
filter_cb(DBusConnection
*bus
, DBusMessage
*m
, void *userdata
) {
86 pa_bluetooth_discovery
*y
;
91 pa_assert_se(y
= userdata
);
93 dbus_error_init(&err
);
95 if (dbus_message_is_signal(m
, "org.freedesktop.DBus", "NameOwnerChanged")) {
96 const char *name
, *old_owner
, *new_owner
;
98 if (!dbus_message_get_args(m
, &err
,
99 DBUS_TYPE_STRING
, &name
,
100 DBUS_TYPE_STRING
, &old_owner
,
101 DBUS_TYPE_STRING
, &new_owner
,
102 DBUS_TYPE_INVALID
)) {
103 pa_log_error("Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err
.message
);
107 if (pa_streq(name
, BLUEZ_SERVICE
)) {
108 if (old_owner
&& *old_owner
) {
109 pa_log_debug("Bluetooth daemon disappeared");
110 /* TODO: remove all devices */
113 if (new_owner
&& *new_owner
) {
114 pa_log_debug("Bluetooth daemon appeared");
115 /* TODO: get managed objects */
119 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
123 dbus_error_free(&err
);
125 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
128 pa_bluetooth_discovery
* pa_bluetooth_discovery_get(pa_core
*c
) {
129 pa_bluetooth_discovery
*y
;
131 DBusConnection
*conn
;
134 if ((y
= pa_shared_get(c
, "bluetooth-discovery")))
135 return pa_bluetooth_discovery_ref(y
);
137 y
= pa_xnew0(pa_bluetooth_discovery
, 1);
140 y
->adapters
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
142 for (i
= 0; i
< PA_BLUETOOTH_HOOK_MAX
; i
++)
143 pa_hook_init(&y
->hooks
[i
], y
);
145 pa_shared_set(c
, "bluetooth-discovery", y
);
147 dbus_error_init(&err
);
149 if (!(y
->connection
= pa_dbus_bus_get(y
->core
, DBUS_BUS_SYSTEM
, &err
))) {
150 pa_log_error("Failed to get D-Bus connection: %s", err
.message
);
154 conn
= pa_dbus_connection_get(y
->connection
);
156 /* dynamic detection of bluetooth audio devices */
157 if (!dbus_connection_add_filter(conn
, filter_cb
, y
, NULL
)) {
158 pa_log_error("Failed to add filter function");
161 y
->filter_added
= true;
163 if (pa_dbus_add_matches(conn
, &err
,
164 "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
165 ",arg0='" BLUEZ_SERVICE
"'",
167 pa_log_error("Failed to add D-Bus matches: %s", err
.message
);
170 y
->matches_added
= true;
175 pa_bluetooth_discovery_unref(y
);
176 dbus_error_free(&err
);
181 pa_bluetooth_discovery
* pa_bluetooth_discovery_ref(pa_bluetooth_discovery
*y
) {
183 pa_assert(PA_REFCNT_VALUE(y
) > 0);
190 void pa_bluetooth_discovery_unref(pa_bluetooth_discovery
*y
) {
192 pa_assert(PA_REFCNT_VALUE(y
) > 0);
194 if (PA_REFCNT_DEC(y
) > 0)
198 adapter_remove_all(y
);
199 pa_hashmap_free(y
->adapters
);
204 if (y
->matches_added
)
205 pa_dbus_remove_matches(pa_dbus_connection_get(y
->connection
),
206 "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',"
207 "arg0='" BLUEZ_SERVICE
"'",
211 dbus_connection_remove_filter(pa_dbus_connection_get(y
->connection
), filter_cb
, y
);
213 pa_dbus_connection_unref(y
->connection
);
216 pa_shared_remove(y
->core
, "bluetooth-discovery");