1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <dbus/dbus.h>
7 #include <errno.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <syslog.h>
12
13 #include "cras_bt_constants.h"
14 #include "cras_bt_manager.h"
15 #include "cras_bt_adapter.h"
16 #include "cras_bt_device.h"
17 #include "cras_bt_endpoint.h"
18 #include "cras_bt_player.h"
19 #include "cras_bt_profile.h"
20 #include "cras_bt_transport.h"
21 #include "utlist.h"
22
23
cras_bt_interface_added(DBusConnection * conn,const char * object_path,const char * interface_name,DBusMessageIter * properties_array_iter)24 static void cras_bt_interface_added(DBusConnection *conn,
25 const char *object_path,
26 const char *interface_name,
27 DBusMessageIter *properties_array_iter)
28 {
29 if (strcmp(interface_name, BLUEZ_INTERFACE_ADAPTER) == 0) {
30 struct cras_bt_adapter *adapter;
31
32 adapter = cras_bt_adapter_get(object_path);
33 if (adapter) {
34 cras_bt_adapter_update_properties(
35 adapter, properties_array_iter, NULL);
36 } else {
37 adapter = cras_bt_adapter_create(object_path);
38 if (adapter) {
39 cras_bt_adapter_update_properties(
40 adapter, properties_array_iter, NULL);
41 cras_bt_register_endpoints(conn, adapter);
42 cras_bt_register_player(conn, adapter);
43 cras_bt_register_profiles(conn);
44
45 syslog(LOG_INFO, "Bluetooth Adapter: %s added",
46 cras_bt_adapter_address(adapter));
47 } else {
48 syslog(LOG_WARNING,
49 "Failed to create Bluetooth Adapter: %s",
50 object_path);
51 }
52 }
53
54 } else if (strcmp(interface_name, BLUEZ_INTERFACE_DEVICE) == 0) {
55 struct cras_bt_device *device;
56
57 device = cras_bt_device_get(object_path);
58 if (device) {
59 cras_bt_device_update_properties(
60 device, properties_array_iter, NULL);
61 } else {
62 device = cras_bt_device_create(conn, object_path);
63 if (device) {
64 cras_bt_device_update_properties(
65 device, properties_array_iter, NULL);
66
67 syslog(LOG_INFO, "Bluetooth Device: %s added",
68 cras_bt_device_address(device));
69 } else {
70 syslog(LOG_WARNING,
71 "Failed to create Bluetooth Device: %s",
72 object_path);
73 }
74 }
75
76 } else if (strcmp(interface_name,
77 BLUEZ_INTERFACE_MEDIA_TRANSPORT) == 0) {
78 struct cras_bt_transport *transport;
79
80 transport = cras_bt_transport_get(object_path);
81 if (transport) {
82 cras_bt_transport_update_properties(
83 transport, properties_array_iter, NULL);
84 } else {
85 transport = cras_bt_transport_create(conn, object_path);
86 if (transport) {
87 cras_bt_transport_update_properties(
88 transport, properties_array_iter, NULL);
89
90 syslog(LOG_INFO,
91 "Bluetooth Transport: %s added",
92 cras_bt_transport_object_path(transport));
93 } else {
94 syslog(LOG_WARNING,
95 "Failed to create Bluetooth Transport: "
96 "%s",
97 object_path);
98 }
99 }
100
101 }
102 }
103
cras_bt_interface_removed(DBusConnection * conn,const char * object_path,const char * interface_name)104 static void cras_bt_interface_removed(DBusConnection *conn,
105 const char *object_path,
106 const char *interface_name)
107 {
108 if (strcmp(interface_name, BLUEZ_INTERFACE_ADAPTER) == 0) {
109 struct cras_bt_adapter *adapter;
110
111 adapter = cras_bt_adapter_get(object_path);
112 if (adapter) {
113 syslog(LOG_INFO, "Bluetooth Adapter: %s removed",
114 cras_bt_adapter_address(adapter));
115 cras_bt_adapter_destroy(adapter);
116 }
117
118 } else if (strcmp(interface_name, BLUEZ_INTERFACE_DEVICE) == 0) {
119 struct cras_bt_device *device;
120
121 device = cras_bt_device_get(object_path);
122 if (device) {
123 syslog(LOG_INFO, "Bluetooth Device: %s removed",
124 cras_bt_device_address(device));
125 cras_bt_device_destroy(device);
126 }
127
128 } else if (strcmp(interface_name,
129 BLUEZ_INTERFACE_MEDIA_TRANSPORT) == 0) {
130 struct cras_bt_transport *transport;
131
132 transport = cras_bt_transport_get(object_path);
133 if (transport) {
134 syslog(LOG_INFO, "Bluetooth Transport: %s removed",
135 cras_bt_transport_object_path(transport));
136 cras_bt_transport_destroy(transport);
137 }
138
139 }
140 }
141
cras_bt_update_properties(DBusConnection * conn,const char * object_path,const char * interface_name,DBusMessageIter * properties_array_iter,DBusMessageIter * invalidated_array_iter)142 static void cras_bt_update_properties(DBusConnection *conn,
143 const char *object_path,
144 const char *interface_name,
145 DBusMessageIter *properties_array_iter,
146 DBusMessageIter *invalidated_array_iter)
147 {
148 if (strcmp(interface_name, BLUEZ_INTERFACE_ADAPTER) == 0) {
149 struct cras_bt_adapter *adapter;
150
151 adapter = cras_bt_adapter_get(object_path);
152 if (adapter) {
153 cras_bt_adapter_update_properties(
154 adapter, properties_array_iter,
155 invalidated_array_iter);
156 }
157
158 } else if (strcmp(interface_name, BLUEZ_INTERFACE_DEVICE) == 0) {
159 struct cras_bt_device *device;
160
161 device = cras_bt_device_get(object_path);
162 if (device) {
163 cras_bt_device_update_properties(
164 device, properties_array_iter,
165 invalidated_array_iter);
166 }
167
168 } else if (strcmp(interface_name,
169 BLUEZ_INTERFACE_MEDIA_TRANSPORT) == 0) {
170 struct cras_bt_transport *transport;
171
172 transport = cras_bt_transport_get(object_path);
173 if (transport) {
174 cras_bt_transport_update_properties(
175 transport, properties_array_iter,
176 invalidated_array_iter);
177 }
178
179 }
180 }
181
182 /* Destroys all bt related stuff. The reset functions must be called in
183 * reverse order of the adapter -> device -> profile(s) hierarchy.
184 */
cras_bt_reset()185 static void cras_bt_reset()
186 {
187 cras_bt_endpoint_reset();
188 cras_bt_transport_reset();
189 cras_bt_profile_reset();
190 cras_bt_device_reset();
191 cras_bt_adapter_reset();
192 }
193
194
cras_bt_on_get_managed_objects(DBusPendingCall * pending_call,void * data)195 static void cras_bt_on_get_managed_objects(DBusPendingCall *pending_call,
196 void *data)
197 {
198 DBusConnection *conn = (DBusConnection *)data;
199 DBusMessage *reply;
200 DBusMessageIter message_iter, object_array_iter;
201
202 reply = dbus_pending_call_steal_reply(pending_call);
203 dbus_pending_call_unref(pending_call);
204
205 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
206 syslog(LOG_WARNING, "GetManagedObjects returned error: %s",
207 dbus_message_get_error_name(reply));
208 dbus_message_unref(reply);
209 return;
210 }
211
212 if (!dbus_message_has_signature(reply, "a{oa{sa{sv}}}")) {
213 syslog(LOG_WARNING, "Bad GetManagedObjects reply received");
214 dbus_message_unref(reply);
215 return;
216 }
217
218 dbus_message_iter_init(reply, &message_iter);
219 dbus_message_iter_recurse(&message_iter, &object_array_iter);
220
221 while (dbus_message_iter_get_arg_type(&object_array_iter) !=
222 DBUS_TYPE_INVALID) {
223 DBusMessageIter object_dict_iter, interface_array_iter;
224 const char *object_path;
225
226 dbus_message_iter_recurse(&object_array_iter,
227 &object_dict_iter);
228
229 dbus_message_iter_get_basic(&object_dict_iter, &object_path);
230 dbus_message_iter_next(&object_dict_iter);
231
232 dbus_message_iter_recurse(&object_dict_iter,
233 &interface_array_iter);
234
235 while (dbus_message_iter_get_arg_type(&interface_array_iter) !=
236 DBUS_TYPE_INVALID) {
237 DBusMessageIter interface_dict_iter;
238 DBusMessageIter properties_array_iter;
239 const char *interface_name;
240
241 dbus_message_iter_recurse(&interface_array_iter,
242 &interface_dict_iter);
243
244 dbus_message_iter_get_basic(&interface_dict_iter,
245 &interface_name);
246 dbus_message_iter_next(&interface_dict_iter);
247
248 dbus_message_iter_recurse(&interface_dict_iter,
249 &properties_array_iter);
250
251 cras_bt_interface_added(conn,
252 object_path, interface_name,
253 &properties_array_iter);
254
255 dbus_message_iter_next(&interface_array_iter);
256 }
257
258 dbus_message_iter_next(&object_array_iter);
259 }
260
261 dbus_message_unref(reply);
262 }
263
cras_bt_get_managed_objects(DBusConnection * conn)264 static int cras_bt_get_managed_objects(DBusConnection *conn)
265 {
266 DBusMessage *method_call;
267 DBusPendingCall *pending_call;
268
269 method_call = dbus_message_new_method_call(
270 BLUEZ_SERVICE,
271 "/",
272 DBUS_INTERFACE_OBJECT_MANAGER,
273 "GetManagedObjects");
274 if (!method_call)
275 return -ENOMEM;
276
277 pending_call = NULL;
278 if (!dbus_connection_send_with_reply(conn, method_call,
279 &pending_call,
280 DBUS_TIMEOUT_USE_DEFAULT)) {
281 dbus_message_unref(method_call);
282 return -ENOMEM;
283 }
284
285 dbus_message_unref(method_call);
286 if (!pending_call)
287 return -EIO;
288
289 if (!dbus_pending_call_set_notify(pending_call,
290 cras_bt_on_get_managed_objects,
291 conn, NULL)) {
292 dbus_pending_call_cancel(pending_call);
293 dbus_pending_call_unref(pending_call);
294 return -ENOMEM;
295 }
296
297 return 0;
298 }
299
300
cras_bt_handle_name_owner_changed(DBusConnection * conn,DBusMessage * message,void * arg)301 static DBusHandlerResult cras_bt_handle_name_owner_changed(DBusConnection *conn,
302 DBusMessage *message,
303 void *arg)
304 {
305 DBusError dbus_error;
306 const char *service_name, *old_owner, *new_owner;
307
308 if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
309 "NameOwnerChanged"))
310 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
311
312 dbus_error_init(&dbus_error);
313 if (!dbus_message_get_args(message, &dbus_error,
314 DBUS_TYPE_STRING, &service_name,
315 DBUS_TYPE_STRING, &old_owner,
316 DBUS_TYPE_STRING, &new_owner,
317 DBUS_TYPE_INVALID)) {
318 syslog(LOG_WARNING, "Bad NameOwnerChanged signal received: %s",
319 dbus_error.message);
320 dbus_error_free(&dbus_error);
321 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
322 }
323
324 syslog(LOG_INFO, "Bluetooth daemon disconnected from the bus.");
325 cras_bt_reset();
326
327 if (strlen(new_owner) > 0)
328 cras_bt_get_managed_objects(conn);
329
330 return DBUS_HANDLER_RESULT_HANDLED;
331 }
332
cras_bt_handle_interfaces_added(DBusConnection * conn,DBusMessage * message,void * arg)333 static DBusHandlerResult cras_bt_handle_interfaces_added(DBusConnection *conn,
334 DBusMessage *message,
335 void *arg)
336 {
337 DBusMessageIter message_iter, interface_array_iter;
338 const char *object_path;
339
340 if (!dbus_message_is_signal(message, DBUS_INTERFACE_OBJECT_MANAGER,
341 "InterfacesAdded"))
342 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
343
344 if (!dbus_message_has_signature(message, "oa{sa{sv}}")) {
345 syslog(LOG_WARNING, "Bad InterfacesAdded signal received");
346 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
347 }
348
349 dbus_message_iter_init(message, &message_iter);
350
351 dbus_message_iter_get_basic(&message_iter, &object_path);
352 dbus_message_iter_next(&message_iter);
353
354 dbus_message_iter_recurse(&message_iter, &interface_array_iter);
355
356 while (dbus_message_iter_get_arg_type(&interface_array_iter) !=
357 DBUS_TYPE_INVALID) {
358 DBusMessageIter interface_dict_iter, properties_array_iter;
359 const char *interface_name;
360
361 dbus_message_iter_recurse(&interface_array_iter,
362 &interface_dict_iter);
363
364 dbus_message_iter_get_basic(&interface_dict_iter,
365 &interface_name);
366 dbus_message_iter_next(&interface_dict_iter);
367
368 dbus_message_iter_recurse(&interface_dict_iter,
369 &properties_array_iter);
370
371 cras_bt_interface_added(conn, object_path, interface_name,
372 &properties_array_iter);
373
374 dbus_message_iter_next(&interface_array_iter);
375 }
376
377 return DBUS_HANDLER_RESULT_HANDLED;
378 }
379
cras_bt_handle_interfaces_removed(DBusConnection * conn,DBusMessage * message,void * arg)380 static DBusHandlerResult cras_bt_handle_interfaces_removed(DBusConnection *conn,
381 DBusMessage *message,
382 void *arg)
383 {
384 DBusMessageIter message_iter, interface_array_iter;
385 const char *object_path;
386
387 if (!dbus_message_is_signal(message, DBUS_INTERFACE_OBJECT_MANAGER,
388 "InterfacesRemoved"))
389 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
390
391 if (!dbus_message_has_signature(message, "oas")) {
392 syslog(LOG_WARNING, "Bad InterfacesRemoved signal received");
393 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
394 }
395
396 dbus_message_iter_init(message, &message_iter);
397
398 dbus_message_iter_get_basic(&message_iter, &object_path);
399 dbus_message_iter_next(&message_iter);
400
401 dbus_message_iter_recurse(&message_iter, &interface_array_iter);
402
403 while (dbus_message_iter_get_arg_type(&interface_array_iter) !=
404 DBUS_TYPE_INVALID) {
405 const char *interface_name;
406
407 dbus_message_iter_get_basic(&interface_array_iter,
408 &interface_name);
409
410 cras_bt_interface_removed(conn, object_path, interface_name);
411
412 dbus_message_iter_next(&interface_array_iter);
413 }
414
415 return DBUS_HANDLER_RESULT_HANDLED;
416 }
417
cras_bt_handle_properties_changed(DBusConnection * conn,DBusMessage * message,void * arg)418 static DBusHandlerResult cras_bt_handle_properties_changed(DBusConnection *conn,
419 DBusMessage *message,
420 void *arg)
421 {
422 DBusMessageIter message_iter, properties_array_iter;
423 DBusMessageIter invalidated_array_iter;
424 const char *object_path, *interface_name;
425
426 if (!dbus_message_is_signal(message, DBUS_INTERFACE_PROPERTIES,
427 "PropertiesChanged"))
428 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
429
430 if (!dbus_message_has_signature(message, "sa{sv}as")) {
431 syslog(LOG_WARNING, "Bad PropertiesChanged signal received");
432 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
433 }
434
435 object_path = dbus_message_get_path(message);
436
437 dbus_message_iter_init(message, &message_iter);
438
439 dbus_message_iter_get_basic(&message_iter, &interface_name);
440 dbus_message_iter_next(&message_iter);
441
442 dbus_message_iter_recurse(&message_iter, &properties_array_iter);
443 dbus_message_iter_next(&message_iter);
444
445 dbus_message_iter_recurse(&message_iter, &invalidated_array_iter);
446
447 cras_bt_update_properties(conn, object_path, interface_name,
448 &properties_array_iter,
449 &invalidated_array_iter);
450
451 return DBUS_HANDLER_RESULT_HANDLED;
452 }
453
454
cras_bt_start(DBusConnection * conn)455 void cras_bt_start(DBusConnection *conn)
456 {
457 DBusError dbus_error;
458
459 dbus_error_init(&dbus_error);
460
461 /* Inform the bus daemon which signals we wish to receive. */
462 dbus_bus_add_match(conn,
463 "type='signal',"
464 "sender='" DBUS_SERVICE_DBUS "',"
465 "interface='" DBUS_INTERFACE_DBUS "',"
466 "member='NameOwnerChanged',"
467 "arg0='" BLUEZ_SERVICE "'",
468 &dbus_error);
469 if (dbus_error_is_set(&dbus_error))
470 goto add_match_error;
471
472 dbus_bus_add_match(conn,
473 "type='signal',"
474 "sender='" BLUEZ_SERVICE "',"
475 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
476 "member='InterfacesAdded'",
477 &dbus_error);
478 if (dbus_error_is_set(&dbus_error))
479 goto add_match_error;
480
481 dbus_bus_add_match(conn,
482 "type='signal',"
483 "sender='" BLUEZ_SERVICE "',"
484 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
485 "member='InterfacesRemoved'",
486 &dbus_error);
487 if (dbus_error_is_set(&dbus_error))
488 goto add_match_error;
489
490 dbus_bus_add_match(conn,
491 "type='signal',"
492 "sender='" BLUEZ_SERVICE "',"
493 "interface='" DBUS_INTERFACE_PROPERTIES "',"
494 "member='PropertiesChanged'",
495 &dbus_error);
496 if (dbus_error_is_set(&dbus_error))
497 goto add_match_error;
498
499 /* Install filter functions to handle the signals we receive. */
500 if (!dbus_connection_add_filter(conn, cras_bt_handle_name_owner_changed,
501 NULL, NULL))
502 goto add_filter_error;
503
504 if (!dbus_connection_add_filter(conn, cras_bt_handle_interfaces_added,
505 NULL, NULL))
506 goto add_filter_error;
507
508 if (!dbus_connection_add_filter(conn, cras_bt_handle_interfaces_removed,
509 NULL, NULL))
510 goto add_filter_error;
511
512 if (!dbus_connection_add_filter(conn, cras_bt_handle_properties_changed,
513 NULL, NULL))
514 goto add_filter_error;
515
516 cras_bt_get_managed_objects(conn);
517 return;
518
519 add_match_error:
520 syslog(LOG_WARNING, "Couldn't setup Bluetooth device monitoring: %s",
521 dbus_error.message);
522 dbus_error_free(&dbus_error);
523 cras_bt_stop(conn);
524 return;
525
526 add_filter_error:
527 syslog(LOG_WARNING, "Couldn't setup Bluetooth device monitoring: %s",
528 strerror(ENOMEM));
529 cras_bt_stop(conn);
530 return;
531 }
532
cras_bt_stop(DBusConnection * conn)533 void cras_bt_stop(DBusConnection *conn)
534 {
535 cras_bt_reset();
536
537 dbus_bus_remove_match(conn,
538 "type='signal',"
539 "sender='" DBUS_SERVICE_DBUS "',"
540 "interface='" DBUS_INTERFACE_DBUS "',"
541 "member='NameOwnerChanged',"
542 "arg0='" BLUEZ_SERVICE "'",
543 NULL);
544 dbus_bus_remove_match(conn,
545 "type='signal',"
546 "sender='" BLUEZ_SERVICE "',"
547 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
548 "member='InterfacesAdded'",
549 NULL);
550 dbus_bus_remove_match(conn,
551 "type='signal',"
552 "sender='" BLUEZ_SERVICE "',"
553 "interface='" DBUS_INTERFACE_OBJECT_MANAGER "',"
554 "member='InterfacesRemoved'",
555 NULL);
556 dbus_bus_remove_match(conn,
557 "type='signal',"
558 "sender='" BLUEZ_SERVICE "',"
559 "interface='" DBUS_INTERFACE_PROPERTIES "',"
560 "member='PropertiesChanged'",
561 NULL);
562
563 dbus_connection_remove_filter(conn, cras_bt_handle_name_owner_changed,
564 NULL);
565 dbus_connection_remove_filter(conn, cras_bt_handle_interfaces_added,
566 NULL);
567 dbus_connection_remove_filter(conn, cras_bt_handle_interfaces_removed,
568 NULL);
569 dbus_connection_remove_filter(conn, cras_bt_handle_properties_changed,
570 NULL);
571 }
572