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 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 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 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 */ 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 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 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 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 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 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 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 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 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