1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2013 João Paulo Rechi Vita 5 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. 10 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. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <errno.h> 25#include <poll.h> 26 27#include <pulsecore/core-util.h> 28#include <pulsecore/dbus-shared.h> 29#include <pulsecore/shared.h> 30#include <pulsecore/core-error.h> 31 32#include "bluez5-util.h" 33 34#define HFP_AUDIO_CODEC_CVSD 0x01 35#define HFP_AUDIO_CODEC_MSBC 0x02 36 37#define OFONO_SERVICE "org.ofono" 38#define HF_AUDIO_AGENT_INTERFACE OFONO_SERVICE ".HandsfreeAudioAgent" 39#define HF_AUDIO_MANAGER_INTERFACE OFONO_SERVICE ".HandsfreeAudioManager" 40 41#define HF_AUDIO_AGENT_PATH "/HandsfreeAudioAgent" 42 43#define HF_AUDIO_AGENT_XML \ 44 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ 45 "<node>" \ 46 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">" \ 47 " <method name=\"Introspect\">" \ 48 " <arg direction=\"out\" type=\"s\" />" \ 49 " </method>" \ 50 " </interface>" \ 51 " <interface name=\"" HF_AUDIO_AGENT_INTERFACE "\">" \ 52 " <method name=\"Release\">" \ 53 " </method>" \ 54 " <method name=\"NewConnection\">" \ 55 " <arg direction=\"in\" type=\"o\" name=\"card_path\" />" \ 56 " <arg direction=\"in\" type=\"h\" name=\"sco_fd\" />" \ 57 " <arg direction=\"in\" type=\"y\" name=\"codec\" />" \ 58 " </method>" \ 59 " </interface>" \ 60 "</node>" 61 62struct hf_audio_card { 63 pa_bluetooth_backend *backend; 64 char *path; 65 char *remote_address; 66 char *local_address; 67 68 bool connecting; 69 int fd; 70 int (*acquire)(struct hf_audio_card *card); 71 72 pa_bluetooth_transport *transport; 73 pa_hook_slot *device_unlink_slot; 74}; 75 76struct pa_bluetooth_backend { 77 pa_core *core; 78 pa_bluetooth_discovery *discovery; 79 pa_dbus_connection *connection; 80 pa_hashmap *cards; 81 char *ofono_bus_id; 82 83 PA_LLIST_HEAD(pa_dbus_pending, pending); 84}; 85 86static ssize_t sco_transport_write(pa_bluetooth_transport *t, int fd, const void* buffer, size_t size, size_t write_mtu) { 87 ssize_t l = 0; 88 size_t written = 0; 89 size_t write_size; 90 91 pa_assert(t); 92 93 /* since SCO setup is symmetric, fix write MTU to be size of last read packet */ 94 if (t->last_read_size) 95 write_mtu = PA_MIN(t->last_read_size, write_mtu); 96 97 /* if encoder buffer has less data than required to make complete packet */ 98 if (size < write_mtu) 99 return 0; 100 101 /* write out MTU sized chunks only */ 102 while (written < size) { 103 write_size = PA_MIN(size - written, write_mtu); 104 if (write_size < write_mtu) 105 break; 106 l = pa_write(fd, buffer + written, write_size, &t->stream_write_type); 107 if (l < 0) 108 break; 109 written += l; 110 } 111 112 if (l < 0) { 113 if (errno == EAGAIN) { 114 /* Hmm, apparently the socket was not writable, give up for now */ 115 pa_log_debug("Got EAGAIN on write() after POLLOUT, probably there is a temporary connection loss."); 116 /* Drain write buffer */ 117 written = size; 118 } else if (errno == EINVAL && t->last_read_size == 0) { 119 /* Likely write_link_mtu is still wrong, retry after next successful read */ 120 pa_log_debug("got write EINVAL, next successful read should fix MTU"); 121 /* Drain write buffer */ 122 written = size; 123 } else { 124 pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno)); 125 /* Report error from write call */ 126 return -1; 127 } 128 } 129 130 /* if too much data left discard it all */ 131 if (size - written >= write_mtu) { 132 pa_log_warn("Wrote memory block to socket only partially! %lu written, discarding pending write size %lu larger than write_mtu %lu", 133 written, size, write_mtu); 134 /* Drain write buffer */ 135 written = size; 136 } 137 138 return written; 139} 140 141static pa_dbus_pending* hf_dbus_send_and_add_to_pending(pa_bluetooth_backend *backend, DBusMessage *m, 142 DBusPendingCallNotifyFunction func, void *call_data) { 143 pa_dbus_pending *p; 144 DBusPendingCall *call; 145 146 pa_assert(backend); 147 pa_assert(m); 148 149 pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1)); 150 151 p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data); 152 PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p); 153 dbus_pending_call_set_notify(call, func, p, NULL); 154 155 return p; 156} 157 158static DBusMessage *card_send(struct hf_audio_card *card, const char *method, DBusError *err) 159{ 160 pa_bluetooth_transport *t = card->transport; 161 DBusMessage *m, *r; 162 163 pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", method)); 164 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(card->backend->connection), m, -1, err); 165 dbus_message_unref(m); 166 167 return r; 168} 169 170static int card_connect(struct hf_audio_card *card) { 171 DBusMessage *r; 172 DBusError err; 173 174 if (card->connecting) 175 return -EAGAIN; 176 177 card->connecting = true; 178 179 dbus_error_init(&err); 180 r = card_send(card, "Connect", &err); 181 182 if (!r) { 183 pa_log_error("Failed to connect %s: %s", err.name, err.message); 184 card->connecting = false; 185 dbus_error_free(&err); 186 return -1; 187 } 188 189 dbus_message_unref(r); 190 191 if (card->connecting) 192 return -EAGAIN; 193 194 return 0; 195} 196 197static int card_acquire(struct hf_audio_card *card) { 198 int fd; 199 uint8_t codec; 200 DBusMessage *r; 201 DBusError err; 202 203 /* Try acquiring the stream first which was introduced in 1.21 */ 204 dbus_error_init(&err); 205 r = card_send(card, "Acquire", &err); 206 207 if (!r) { 208 if (!pa_streq(err.name, DBUS_ERROR_UNKNOWN_METHOD)) { 209 pa_log_error("Failed to acquire %s: %s", err.name, err.message); 210 dbus_error_free(&err); 211 return -1; 212 } 213 dbus_error_free(&err); 214 /* Fallback to Connect as this might be an old version of ofono */ 215 card->acquire = card_connect; 216 return card_connect(card); 217 } 218 219 if ((dbus_message_get_args(r, NULL, DBUS_TYPE_UNIX_FD, &fd, 220 DBUS_TYPE_BYTE, &codec, 221 DBUS_TYPE_INVALID) == true)) { 222 dbus_message_unref(r); 223 224 if (codec == HFP_AUDIO_CODEC_CVSD) { 225 pa_bluetooth_transport_reconfigure(card->transport, pa_bluetooth_get_hf_codec("CVSD"), sco_transport_write, NULL); 226 } else if (codec == HFP_AUDIO_CODEC_MSBC) { 227 /* oFono is expected to set up socket BT_VOICE_TRANSPARENT option */ 228 pa_bluetooth_transport_reconfigure(card->transport, pa_bluetooth_get_hf_codec("mSBC"), sco_transport_write, NULL); 229 } else { 230 pa_assert_fp(codec != HFP_AUDIO_CODEC_CVSD && codec != HFP_AUDIO_CODEC_MSBC); 231 pa_log_error("Invalid codec: %u", codec); 232 /* shutdown to make sure connection is dropped immediately */ 233 shutdown(fd, SHUT_RDWR); 234 close(fd); 235 return -1; 236 } 237 238 card->fd = fd; 239 return 0; 240 } 241 242 pa_log_error("Unable to acquire"); 243 dbus_message_unref(r); 244 return -1; 245} 246 247static void hf_audio_agent_card_removed(pa_bluetooth_backend *backend, const char *path); 248 249static pa_hook_result_t device_unlink_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct hf_audio_card *card) { 250 pa_assert(d); 251 pa_assert(card); 252 253 if (d != card->transport->device) 254 return PA_HOOK_OK; 255 256 hf_audio_agent_card_removed(card->backend, card->path); 257 258 return PA_HOOK_OK; 259} 260 261static struct hf_audio_card *hf_audio_card_new(pa_bluetooth_backend *backend, const char *path) { 262 struct hf_audio_card *card = pa_xnew0(struct hf_audio_card, 1); 263 264 card->path = pa_xstrdup(path); 265 card->backend = backend; 266 card->fd = -1; 267 card->acquire = card_acquire; 268 269 card->device_unlink_slot = pa_hook_connect(pa_bluetooth_discovery_hook(backend->discovery, PA_BLUETOOTH_HOOK_DEVICE_UNLINK), 270 PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_cb, card); 271 272 return card; 273} 274 275static void hf_audio_card_free(struct hf_audio_card *card) { 276 pa_assert(card); 277 278 if (card->device_unlink_slot) 279 pa_hook_slot_free(card->device_unlink_slot); 280 281 if (card->transport) 282 pa_bluetooth_transport_free(card->transport); 283 284 pa_xfree(card->path); 285 pa_xfree(card->remote_address); 286 pa_xfree(card->local_address); 287 pa_xfree(card); 288} 289 290static int socket_accept(int sock) 291{ 292 char c; 293 struct pollfd pfd; 294 295 if (sock < 0) 296 return -ENOTCONN; 297 298 memset(&pfd, 0, sizeof(pfd)); 299 pfd.fd = sock; 300 pfd.events = POLLOUT; 301 302 if (poll(&pfd, 1, 0) < 0) 303 return -errno; 304 305 /* 306 * If socket already writable then it is not in defer setup state, 307 * otherwise it needs to be read to authorize the connection. 308 */ 309 if ((pfd.revents & POLLOUT)) 310 return 0; 311 312 /* Enable socket by reading 1 byte */ 313 if (read(sock, &c, 1) < 0) 314 return -errno; 315 316 return 0; 317} 318 319static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) { 320 struct hf_audio_card *card = t->userdata; 321 int err; 322 323 pa_assert(card); 324 325 if (!optional && card->fd < 0) { 326 err = card->acquire(card); 327 if (err < 0) 328 return err; 329 } 330 331 /* The correct block size should take into account the SCO MTU from 332 * the Bluetooth adapter and (for adapters in the USB bus) the MxPS 333 * value from the Isoc USB endpoint in use by btusb and should be 334 * made available to userspace by the Bluetooth kernel subsystem. 335 * 336 * Set initial MTU to max known payload length of HCI packet 337 * in USB Alternate Setting 5 (144 bytes) 338 * See also pa_bluetooth_transport::last_read_size handling 339 * and comment about MTU size in bt_prepare_encoder_buffer() 340 */ 341 if (imtu) 342 *imtu = 144; 343 if (omtu) 344 *omtu = 144; 345 346 err = socket_accept(card->fd); 347 if (err < 0) { 348 pa_log_error("Deferred setup failed on fd %d: %s", card->fd, pa_cstrerror(-err)); 349 return -1; 350 } 351 352 return card->fd; 353} 354 355static void hf_audio_agent_transport_release(pa_bluetooth_transport *t) { 356 struct hf_audio_card *card = t->userdata; 357 358 pa_assert(card); 359 360 if (card->fd < 0) { 361 pa_log_info("Transport %s already released", t->path); 362 return; 363 } 364 365 /* shutdown to make sure connection is dropped immediately */ 366 shutdown(card->fd, SHUT_RDWR); 367 close(card->fd); 368 card->fd = -1; 369} 370 371static void hf_audio_agent_card_found(pa_bluetooth_backend *backend, const char *path, DBusMessageIter *props_i) { 372 DBusMessageIter i, value_i; 373 const char *key, *value; 374 struct hf_audio_card *card; 375 pa_bluetooth_device *d; 376 pa_bluetooth_profile_t p = PA_BLUETOOTH_PROFILE_HFP_AG; 377 378 pa_assert(backend); 379 pa_assert(path); 380 pa_assert(props_i); 381 382 pa_log_debug("New HF card found: %s", path); 383 384 card = hf_audio_card_new(backend, path); 385 386 while (dbus_message_iter_get_arg_type(props_i) != DBUS_TYPE_INVALID) { 387 char c; 388 389 dbus_message_iter_recurse(props_i, &i); 390 391 dbus_message_iter_get_basic(&i, &key); 392 dbus_message_iter_next(&i); 393 dbus_message_iter_recurse(&i, &value_i); 394 395 if ((c = dbus_message_iter_get_arg_type(&value_i)) != DBUS_TYPE_STRING) { 396 pa_log_error("Invalid properties for %s: expected 's', received '%c'", path, c); 397 goto fail; 398 } 399 400 dbus_message_iter_get_basic(&value_i, &value); 401 402 if (pa_streq(key, "RemoteAddress")) { 403 pa_xfree(card->remote_address); 404 card->remote_address = pa_xstrdup(value); 405 } else if (pa_streq(key, "LocalAddress")) { 406 pa_xfree(card->local_address); 407 card->local_address = pa_xstrdup(value); 408 } else if (pa_streq(key, "Type")) { 409 if (pa_streq(value, "gateway")) 410 p = PA_BLUETOOTH_PROFILE_HFP_HF; 411 } 412 413 pa_log_debug("%s: %s", key, value); 414 415 dbus_message_iter_next(props_i); 416 } 417 418 d = pa_bluetooth_discovery_get_device_by_address(backend->discovery, card->remote_address, card->local_address); 419 if (!d) { 420 pa_log_error("Device doesn't exist for %s", path); 421 goto fail; 422 } 423 424 card->transport = pa_bluetooth_transport_new(d, backend->ofono_bus_id, path, p, NULL, 0); 425 card->transport->acquire = hf_audio_agent_transport_acquire; 426 card->transport->release = hf_audio_agent_transport_release; 427 card->transport->userdata = card; 428 pa_bluetooth_transport_reconfigure(card->transport, pa_bluetooth_get_hf_codec("CVSD"), sco_transport_write, NULL); 429 430 pa_bluetooth_transport_put(card->transport); 431 pa_hashmap_put(backend->cards, card->path, card); 432 433 return; 434 435fail: 436 hf_audio_card_free(card); 437} 438 439static void hf_audio_agent_card_removed(pa_bluetooth_backend *backend, const char *path) { 440 struct hf_audio_card *card; 441 442 pa_assert(backend); 443 pa_assert(path); 444 445 pa_log_debug("HF card removed: %s", path); 446 447 card = pa_hashmap_remove(backend->cards, path); 448 if (!card) 449 return; 450 451 hf_audio_card_free(card); 452} 453 454static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userdata) { 455 DBusMessage *r; 456 pa_dbus_pending *p; 457 pa_bluetooth_backend *backend; 458 DBusMessageIter i, array_i, struct_i, props_i; 459 460 pa_assert_se(p = userdata); 461 pa_assert_se(backend = p->context_data); 462 pa_assert_se(r = dbus_pending_call_steal_reply(pending)); 463 464 if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { 465 pa_log_error("Failed to get a list of handsfree audio cards from ofono: %s: %s", 466 dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); 467 goto finish; 468 } 469 470 if (!dbus_message_iter_init(r, &i) || !pa_streq(dbus_message_get_signature(r), "a(oa{sv})")) { 471 pa_log_error("Invalid arguments in GetCards() reply"); 472 goto finish; 473 } 474 475 dbus_message_iter_recurse(&i, &array_i); 476 while (dbus_message_iter_get_arg_type(&array_i) != DBUS_TYPE_INVALID) { 477 const char *path; 478 479 dbus_message_iter_recurse(&array_i, &struct_i); 480 dbus_message_iter_get_basic(&struct_i, &path); 481 dbus_message_iter_next(&struct_i); 482 483 dbus_message_iter_recurse(&struct_i, &props_i); 484 485 hf_audio_agent_card_found(backend, path, &props_i); 486 487 dbus_message_iter_next(&array_i); 488 } 489 490finish: 491 dbus_message_unref(r); 492 493 PA_LLIST_REMOVE(pa_dbus_pending, backend->pending, p); 494 pa_dbus_pending_free(p); 495} 496 497static void hf_audio_agent_get_cards(pa_bluetooth_backend *hf) { 498 DBusMessage *m; 499 500 pa_assert(hf); 501 502 pa_assert_se(m = dbus_message_new_method_call(OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "GetCards")); 503 hf_dbus_send_and_add_to_pending(hf, m, hf_audio_agent_get_cards_reply, NULL); 504} 505 506static void ofono_bus_id_destroy(pa_bluetooth_backend *backend) { 507 pa_hashmap_remove_all(backend->cards); 508 509 if (backend->ofono_bus_id) { 510 pa_xfree(backend->ofono_bus_id); 511 backend->ofono_bus_id = NULL; 512 pa_bluetooth_discovery_set_ofono_running(backend->discovery, false); 513 } 514} 515 516static void hf_audio_agent_register_reply(DBusPendingCall *pending, void *userdata) { 517 DBusMessage *r; 518 pa_dbus_pending *p; 519 pa_bluetooth_backend *backend; 520 521 pa_assert_se(p = userdata); 522 pa_assert_se(backend = p->context_data); 523 pa_assert_se(r = dbus_pending_call_steal_reply(pending)); 524 525 if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { 526 pa_log_info("Failed to register as a handsfree audio agent with ofono: %s: %s", 527 dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); 528 goto finish; 529 } 530 531 backend->ofono_bus_id = pa_xstrdup(dbus_message_get_sender(r)); 532 533 hf_audio_agent_get_cards(backend); 534 535finish: 536 dbus_message_unref(r); 537 538 PA_LLIST_REMOVE(pa_dbus_pending, backend->pending, p); 539 pa_dbus_pending_free(p); 540 541 pa_bluetooth_discovery_set_ofono_running(backend->discovery, backend->ofono_bus_id != NULL); 542} 543 544static void hf_audio_agent_register(pa_bluetooth_backend *hf) { 545 DBusMessage *m; 546 uint8_t codecs[2]; 547 const uint8_t *pcodecs = codecs; 548 int ncodecs = 0; 549 const char *path = HF_AUDIO_AGENT_PATH; 550 551 pa_assert(hf); 552 553 pa_assert_se(m = dbus_message_new_method_call(OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "Register")); 554 555 codecs[ncodecs++] = HFP_AUDIO_CODEC_CVSD; 556 if (pa_bluetooth_discovery_get_enable_msbc(hf->discovery)) 557 codecs[ncodecs++] = HFP_AUDIO_CODEC_MSBC; 558 559 pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pcodecs, ncodecs, 560 DBUS_TYPE_INVALID)); 561 562 hf_dbus_send_and_add_to_pending(hf, m, hf_audio_agent_register_reply, NULL); 563} 564 565static void hf_audio_agent_unregister(pa_bluetooth_backend *backend) { 566 DBusMessage *m; 567 const char *path = HF_AUDIO_AGENT_PATH; 568 569 pa_assert(backend); 570 pa_assert(backend->connection); 571 572 if (backend->ofono_bus_id) { 573 pa_assert_se(m = dbus_message_new_method_call(backend->ofono_bus_id, "/", HF_AUDIO_MANAGER_INTERFACE, "Unregister")); 574 pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)); 575 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(backend->connection), m, NULL)); 576 577 ofono_bus_id_destroy(backend); 578 } 579} 580 581static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) { 582 const char *sender; 583 DBusError err; 584 pa_bluetooth_backend *backend = data; 585 586 pa_assert(bus); 587 pa_assert(m); 588 pa_assert(backend); 589 590 sender = dbus_message_get_sender(m); 591 if (!pa_safe_streq(backend->ofono_bus_id, sender) && !pa_streq(DBUS_SERVICE_DBUS, sender)) 592 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 593 594 dbus_error_init(&err); 595 596 if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { 597 const char *name, *old_owner, *new_owner; 598 599 if (!dbus_message_get_args(m, &err, 600 DBUS_TYPE_STRING, &name, 601 DBUS_TYPE_STRING, &old_owner, 602 DBUS_TYPE_STRING, &new_owner, 603 DBUS_TYPE_INVALID)) { 604 pa_log_error("Failed to parse " DBUS_INTERFACE_DBUS ".NameOwnerChanged: %s", err.message); 605 goto fail; 606 } 607 608 if (pa_streq(name, OFONO_SERVICE)) { 609 610 if (old_owner && *old_owner) { 611 pa_log_debug("oFono disappeared"); 612 ofono_bus_id_destroy(backend); 613 } 614 615 if (new_owner && *new_owner) { 616 pa_log_debug("oFono appeared"); 617 hf_audio_agent_register(backend); 618 } 619 } 620 621 } else if (dbus_message_is_signal(m, "org.ofono.HandsfreeAudioManager", "CardAdded")) { 622 const char *p; 623 DBusMessageIter arg_i, props_i; 624 625 if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sv}")) { 626 pa_log_error("Failed to parse org.ofono.HandsfreeAudioManager.CardAdded"); 627 goto fail; 628 } 629 630 dbus_message_iter_get_basic(&arg_i, &p); 631 632 pa_assert_se(dbus_message_iter_next(&arg_i)); 633 pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY); 634 635 dbus_message_iter_recurse(&arg_i, &props_i); 636 637 hf_audio_agent_card_found(backend, p, &props_i); 638 } else if (dbus_message_is_signal(m, "org.ofono.HandsfreeAudioManager", "CardRemoved")) { 639 const char *p; 640 641 if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID)) { 642 pa_log_error("Failed to parse org.ofono.HandsfreeAudioManager.CardRemoved: %s", err.message); 643 goto fail; 644 } 645 646 hf_audio_agent_card_removed(backend, p); 647 } 648 649fail: 650 dbus_error_free(&err); 651 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 652} 653 654static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, void *data) { 655 DBusMessage *r; 656 const char *sender; 657 pa_bluetooth_backend *backend = data; 658 659 pa_assert(backend); 660 661 sender = dbus_message_get_sender(m); 662 if (!pa_safe_streq(backend->ofono_bus_id, sender)) { 663 pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.NotAllowed", "Operation is not allowed by this sender")); 664 return r; 665 } 666 667 pa_log_debug("HF audio agent has been unregistered by oFono (%s)", backend->ofono_bus_id); 668 669 ofono_bus_id_destroy(backend); 670 671 pa_assert_se(r = dbus_message_new_method_return(m)); 672 673 return r; 674} 675 676static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage *m, void *data) { 677 DBusMessage *r; 678 const char *sender, *path; 679 int fd; 680 uint8_t codec; 681 struct hf_audio_card *card; 682 pa_bluetooth_backend *backend = data; 683 684 pa_assert(backend); 685 686 sender = dbus_message_get_sender(m); 687 if (!pa_safe_streq(backend->ofono_bus_id, sender)) { 688 pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.NotAllowed", "Operation is not allowed by this sender")); 689 return r; 690 } 691 692 if (dbus_message_get_args(m, NULL, 693 DBUS_TYPE_OBJECT_PATH, &path, 694 DBUS_TYPE_UNIX_FD, &fd, 695 DBUS_TYPE_BYTE, &codec, 696 DBUS_TYPE_INVALID) == FALSE) { 697 pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Invalid arguments in method call")); 698 return r; 699 } 700 701 card = pa_hashmap_get(backend->cards, path); 702 703 if (!card || (codec != HFP_AUDIO_CODEC_CVSD && codec != HFP_AUDIO_CODEC_MSBC) || card->fd >= 0) { 704 pa_log_warn("New audio connection invalid arguments (path=%s fd=%d, codec=%d)", path, fd, codec); 705 pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Invalid arguments in method call")); 706 shutdown(fd, SHUT_RDWR); 707 close(fd); 708 return r; 709 } 710 711 pa_log_debug("New audio connection on card %s (fd=%d, codec=%d)", path, fd, codec); 712 713 card->connecting = false; 714 card->fd = fd; 715 if (codec == HFP_AUDIO_CODEC_CVSD) { 716 pa_bluetooth_transport_reconfigure(card->transport, pa_bluetooth_get_hf_codec("CVSD"), sco_transport_write, NULL); 717 } else if (codec == HFP_AUDIO_CODEC_MSBC) { 718 /* oFono is expected to set up socket BT_VOICE_TRANSPARENT option */ 719 pa_bluetooth_transport_reconfigure(card->transport, pa_bluetooth_get_hf_codec("mSBC"), sco_transport_write, NULL); 720 } 721 722 pa_bluetooth_transport_set_state(card->transport, PA_BLUETOOTH_TRANSPORT_STATE_PLAYING); 723 724 pa_assert_se(r = dbus_message_new_method_return(m)); 725 726 return r; 727} 728 729static DBusHandlerResult hf_audio_agent_handler(DBusConnection *c, DBusMessage *m, void *data) { 730 pa_bluetooth_backend *backend = data; 731 DBusMessage *r = NULL; 732 const char *path, *interface, *member; 733 734 pa_assert(backend); 735 736 path = dbus_message_get_path(m); 737 interface = dbus_message_get_interface(m); 738 member = dbus_message_get_member(m); 739 740 if (!pa_streq(path, HF_AUDIO_AGENT_PATH)) 741 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 742 743 pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); 744 745 if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) { 746 const char *xml = HF_AUDIO_AGENT_XML; 747 748 pa_assert_se(r = dbus_message_new_method_return(m)); 749 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID)); 750 751 } else if (dbus_message_is_method_call(m, HF_AUDIO_AGENT_INTERFACE, "NewConnection")) 752 r = hf_audio_agent_new_connection(c, m, data); 753 else if (dbus_message_is_method_call(m, HF_AUDIO_AGENT_INTERFACE, "Release")) 754 r = hf_audio_agent_release(c, m, data); 755 else 756 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 757 758 if (r) { 759 pa_assert_se(dbus_connection_send(pa_dbus_connection_get(backend->connection), r, NULL)); 760 dbus_message_unref(r); 761 } 762 763 return DBUS_HANDLER_RESULT_HANDLED; 764} 765 766pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y) { 767 pa_bluetooth_backend *backend; 768 DBusError err; 769 static const DBusObjectPathVTable vtable_hf_audio_agent = { 770 .message_function = hf_audio_agent_handler, 771 }; 772 773 pa_assert(c); 774 775 backend = pa_xnew0(pa_bluetooth_backend, 1); 776 backend->core = c; 777 backend->discovery = y; 778 backend->cards = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, 779 (pa_free_cb_t) hf_audio_card_free); 780 781 dbus_error_init(&err); 782 783 if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) { 784 pa_log("Failed to get D-Bus connection: %s", err.message); 785 dbus_error_free(&err); 786 pa_xfree(backend); 787 return NULL; 788 } 789 790 /* dynamic detection of handsfree audio cards */ 791 if (!dbus_connection_add_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend, NULL)) { 792 pa_log_error("Failed to add filter function"); 793 pa_dbus_connection_unref(backend->connection); 794 pa_xfree(backend); 795 return NULL; 796 } 797 798 if (pa_dbus_add_matches(pa_dbus_connection_get(backend->connection), &err, 799 "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," 800 "arg0='" OFONO_SERVICE "'", 801 "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'", 802 "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardRemoved'", 803 NULL) < 0) { 804 pa_log("Failed to add oFono D-Bus matches: %s", err.message); 805 dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend); 806 pa_dbus_connection_unref(backend->connection); 807 pa_xfree(backend); 808 return NULL; 809 } 810 811 pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(backend->connection), HF_AUDIO_AGENT_PATH, 812 &vtable_hf_audio_agent, backend)); 813 814 hf_audio_agent_register(backend); 815 816 return backend; 817} 818 819void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *backend) { 820 pa_assert(backend); 821 822 pa_dbus_free_pending_list(&backend->pending); 823 824 hf_audio_agent_unregister(backend); 825 826 dbus_connection_unregister_object_path(pa_dbus_connection_get(backend->connection), HF_AUDIO_AGENT_PATH); 827 828 pa_dbus_remove_matches(pa_dbus_connection_get(backend->connection), 829 "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," 830 "arg0='" OFONO_SERVICE "'", 831 "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'", 832 "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardRemoved'", 833 NULL); 834 835 dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend); 836 837 pa_dbus_connection_unref(backend->connection); 838 839 pa_hashmap_free(backend->cards); 840 841 pa_xfree(backend); 842} 843