1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2007 Nokia Corporation 6 * Copyright (C) 2004-2009 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #endif 28 29 #include <errno.h> 30 31 #include <glib.h> 32 #include <gdbus.h> 33 34 #include "../src/adapter.h" 35 #include "../src/dbus-common.h" 36 37 #include "log.h" 38 #include "error.h" 39 #include "device.h" 40 #include "avdtp.h" 41 #include "media.h" 42 #include "transport.h" 43 #include "a2dp.h" 44 #include "headset.h" 45 46 #ifndef DBUS_TYPE_UNIX_FD 47 #define DBUS_TYPE_UNIX_FD -1 48 #endif 49 50 #define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport" 51 52 struct media_request { 53 DBusMessage *msg; 54 guint id; 55 }; 56 57 struct media_owner { 58 struct media_transport *transport; 59 struct media_request *pending; 60 char *name; 61 char *accesstype; 62 guint watch; 63 }; 64 65 struct media_transport { 66 DBusConnection *conn; 67 char *path; /* Transport object path */ 68 struct audio_device *device; /* Transport device */ 69 struct avdtp *session; /* Signalling session (a2dp only) */ 70 struct media_endpoint *endpoint; /* Transport endpoint */ 71 GSList *owners; /* Transport owners */ 72 uint8_t *configuration; /* Transport configuration */ 73 int size; /* Transport configuration size */ 74 int fd; /* Transport file descriptor */ 75 uint16_t imtu; /* Transport input mtu */ 76 uint16_t omtu; /* Transport output mtu */ 77 uint16_t delay; /* Transport delay (a2dp only) */ 78 unsigned int nrec_id; /* Transport nrec watch (headset only) */ 79 gboolean read_lock; 80 gboolean write_lock; 81 gboolean in_use; 82 guint (*resume) (struct media_transport *transport, 83 struct media_owner *owner); 84 guint (*suspend) (struct media_transport *transport, 85 struct media_owner *owner); 86 void (*cancel) (struct media_transport *transport, 87 guint id); 88 void (*get_properties) ( 89 struct media_transport *transport, 90 DBusMessageIter *dict); 91 int (*set_property) ( 92 struct media_transport *transport, 93 const char *property, 94 DBusMessageIter *value); 95 }; 96 97 void media_transport_destroy(struct media_transport *transport) 98 { 99 char *path; 100 101 path = g_strdup(transport->path); 102 103 g_dbus_unregister_interface(transport->conn, path, 104 MEDIA_TRANSPORT_INTERFACE); 105 106 g_free(path); 107 } 108 109 static struct media_request *media_request_create(DBusMessage *msg, guint id) 110 { 111 struct media_request *req; 112 113 req = g_new0(struct media_request, 1); 114 req->msg = dbus_message_ref(msg); 115 req->id = id; 116 117 DBG("Request created: method=%s id=%u", dbus_message_get_member(msg), 118 id); 119 120 return req; 121 } 122 123 static void media_request_reply(struct media_request *req, 124 DBusConnection *conn, int err) 125 { 126 DBusMessage *reply; 127 128 DBG("Request %s Reply %s", dbus_message_get_member(req->msg), 129 strerror(err)); 130 131 if (!err) 132 reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID); 133 else 134 reply = g_dbus_create_error(req->msg, 135 ERROR_INTERFACE ".Failed", 136 "%s", strerror(err)); 137 138 g_dbus_send_message(conn, reply); 139 } 140 141 static gboolean media_transport_release(struct media_transport *transport, 142 const char *accesstype) 143 { 144 if (g_strstr_len(accesstype, -1, "r") != NULL) { 145 transport->read_lock = FALSE; 146 DBG("Transport %s: read lock released", transport->path); 147 } 148 149 if (g_strstr_len(accesstype, -1, "w") != NULL) { 150 transport->write_lock = FALSE; 151 DBG("Transport %s: write lock released", transport->path); 152 } 153 154 return TRUE; 155 } 156 157 static void media_owner_remove(struct media_owner *owner) 158 { 159 struct media_transport *transport = owner->transport; 160 struct media_request *req = owner->pending; 161 162 if (!req) 163 return; 164 165 DBG("Owner %s Request %s", owner->name, 166 dbus_message_get_member(req->msg)); 167 168 if (req->id) 169 transport->cancel(transport, req->id); 170 171 owner->pending = NULL; 172 if (req->msg) 173 dbus_message_unref(req->msg); 174 175 g_free(req); 176 } 177 178 static void media_owner_free(struct media_owner *owner) 179 { 180 DBG("Owner %s", owner->name); 181 182 media_owner_remove(owner); 183 184 g_free(owner->name); 185 g_free(owner->accesstype); 186 g_free(owner); 187 } 188 189 static void media_transport_remove(struct media_transport *transport, 190 struct media_owner *owner) 191 { 192 DBG("Transport %s Owner %s", transport->path, owner->name); 193 194 media_transport_release(transport, owner->accesstype); 195 196 /* Reply if owner has a pending request */ 197 if (owner->pending) 198 media_request_reply(owner->pending, transport->conn, EIO); 199 200 transport->owners = g_slist_remove(transport->owners, owner); 201 202 if (owner->watch) 203 g_dbus_remove_watch(transport->conn, owner->watch); 204 205 media_owner_free(owner); 206 207 /* Suspend if there is no longer any owner */ 208 if (transport->owners == NULL && transport->in_use) 209 transport->suspend(transport, NULL); 210 } 211 212 static gboolean media_transport_set_fd(struct media_transport *transport, 213 int fd, uint16_t imtu, uint16_t omtu) 214 { 215 if (transport->fd == fd) 216 return TRUE; 217 218 transport->fd = fd; 219 transport->imtu = imtu; 220 transport->omtu = omtu; 221 222 info("%s: fd(%d) ready", transport->path, fd); 223 224 return TRUE; 225 } 226 227 static void a2dp_resume_complete(struct avdtp *session, 228 struct avdtp_error *err, void *user_data) 229 { 230 struct media_owner *owner = user_data; 231 struct media_request *req = owner->pending; 232 struct media_transport *transport = owner->transport; 233 struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); 234 struct avdtp_stream *stream; 235 int fd; 236 uint16_t imtu, omtu; 237 gboolean ret; 238 239 req->id = 0; 240 241 if (err) 242 goto fail; 243 244 stream = a2dp_sep_get_stream(sep); 245 if (stream == NULL) 246 goto fail; 247 248 ret = avdtp_stream_get_transport(stream, &fd, &imtu, &omtu, NULL); 249 if (ret == FALSE) 250 goto fail; 251 252 media_transport_set_fd(transport, fd, imtu, omtu); 253 254 if (g_strstr_len(owner->accesstype, -1, "r") == NULL) 255 imtu = 0; 256 257 if (g_strstr_len(owner->accesstype, -1, "w") == NULL) 258 omtu = 0; 259 260 ret = g_dbus_send_reply(transport->conn, req->msg, 261 DBUS_TYPE_UNIX_FD, &fd, 262 DBUS_TYPE_UINT16, &imtu, 263 DBUS_TYPE_UINT16, &omtu, 264 DBUS_TYPE_INVALID); 265 if (ret == FALSE) 266 goto fail; 267 268 media_owner_remove(owner); 269 270 return; 271 272 fail: 273 media_transport_remove(transport, owner); 274 } 275 276 static guint resume_a2dp(struct media_transport *transport, 277 struct media_owner *owner) 278 { 279 struct media_endpoint *endpoint = transport->endpoint; 280 struct audio_device *device = transport->device; 281 struct a2dp_sep *sep = media_endpoint_get_sep(endpoint); 282 283 if (transport->session == NULL) { 284 transport->session = avdtp_get(&device->src, &device->dst); 285 if (transport->session == NULL) 286 return 0; 287 } 288 289 if (transport->in_use == TRUE) 290 goto done; 291 292 transport->in_use = a2dp_sep_lock(sep, transport->session); 293 if (transport->in_use == FALSE) 294 return 0; 295 296 done: 297 return a2dp_resume(transport->session, sep, a2dp_resume_complete, 298 owner); 299 } 300 301 static void a2dp_suspend_complete(struct avdtp *session, 302 struct avdtp_error *err, void *user_data) 303 { 304 struct media_owner *owner = user_data; 305 struct media_transport *transport = owner->transport; 306 struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); 307 308 /* Release always succeeds */ 309 if (owner->pending) { 310 owner->pending->id = 0; 311 media_request_reply(owner->pending, transport->conn, 0); 312 media_owner_remove(owner); 313 } 314 315 a2dp_sep_unlock(sep, transport->session); 316 transport->in_use = FALSE; 317 media_transport_remove(transport, owner); 318 } 319 320 static guint suspend_a2dp(struct media_transport *transport, 321 struct media_owner *owner) 322 { 323 struct media_endpoint *endpoint = transport->endpoint; 324 struct a2dp_sep *sep = media_endpoint_get_sep(endpoint); 325 326 if (!owner) { 327 a2dp_sep_unlock(sep, transport->session); 328 transport->in_use = FALSE; 329 return 0; 330 } 331 332 return a2dp_suspend(transport->session, sep, a2dp_suspend_complete, 333 owner); 334 } 335 336 static void cancel_a2dp(struct media_transport *transport, guint id) 337 { 338 a2dp_cancel(transport->device, id); 339 } 340 341 static void headset_resume_complete(struct audio_device *dev, void *user_data) 342 { 343 struct media_owner *owner = user_data; 344 struct media_request *req = owner->pending; 345 struct media_transport *transport = owner->transport; 346 int fd; 347 uint16_t imtu, omtu; 348 gboolean ret; 349 350 req->id = 0; 351 352 if (dev == NULL) 353 goto fail; 354 355 fd = headset_get_sco_fd(dev); 356 if (fd < 0) 357 goto fail; 358 359 imtu = 48; 360 omtu = 48; 361 362 media_transport_set_fd(transport, fd, imtu, omtu); 363 364 if (g_strstr_len(owner->accesstype, -1, "r") == NULL) 365 imtu = 0; 366 367 if (g_strstr_len(owner->accesstype, -1, "w") == NULL) 368 omtu = 0; 369 370 ret = g_dbus_send_reply(transport->conn, req->msg, 371 DBUS_TYPE_UNIX_FD, &fd, 372 DBUS_TYPE_UINT16, &imtu, 373 DBUS_TYPE_UINT16, &omtu, 374 DBUS_TYPE_INVALID); 375 if (ret == FALSE) 376 goto fail; 377 378 media_owner_remove(owner); 379 380 return; 381 382 fail: 383 media_transport_remove(transport, owner); 384 } 385 386 static guint resume_headset(struct media_transport *transport, 387 struct media_owner *owner) 388 { 389 struct audio_device *device = transport->device; 390 391 if (transport->in_use == TRUE) 392 goto done; 393 394 transport->in_use = headset_lock(device, HEADSET_LOCK_READ | 395 HEADSET_LOCK_WRITE); 396 if (transport->in_use == FALSE) 397 return 0; 398 399 done: 400 return headset_request_stream(device, headset_resume_complete, 401 owner); 402 } 403 404 static void headset_suspend_complete(struct audio_device *dev, void *user_data) 405 { 406 struct media_owner *owner = user_data; 407 struct media_transport *transport = owner->transport; 408 409 /* Release always succeeds */ 410 if (owner->pending) { 411 owner->pending->id = 0; 412 media_request_reply(owner->pending, transport->conn, 0); 413 media_owner_remove(owner); 414 } 415 416 headset_unlock(dev, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE); 417 transport->in_use = FALSE; 418 media_transport_remove(transport, owner); 419 } 420 421 static guint suspend_headset(struct media_transport *transport, 422 struct media_owner *owner) 423 { 424 struct audio_device *device = transport->device; 425 426 if (!owner) { 427 headset_unlock(device, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE); 428 transport->in_use = FALSE; 429 return 0; 430 } 431 432 return headset_suspend_stream(device, headset_suspend_complete, owner); 433 } 434 435 static void cancel_headset(struct media_transport *transport, guint id) 436 { 437 headset_cancel_stream(transport->device, id); 438 } 439 440 static void media_owner_exit(DBusConnection *connection, void *user_data) 441 { 442 struct media_owner *owner = user_data; 443 444 owner->watch = 0; 445 446 media_owner_remove(owner); 447 448 media_transport_remove(owner->transport, owner); 449 } 450 451 static gboolean media_transport_acquire(struct media_transport *transport, 452 const char *accesstype) 453 { 454 gboolean read_lock = FALSE, write_lock = FALSE; 455 456 if (g_strstr_len(accesstype, -1, "r") != NULL) { 457 if (transport->read_lock == TRUE) 458 return FALSE; 459 read_lock = TRUE; 460 } 461 462 if (g_strstr_len(accesstype, -1, "w") != NULL) { 463 if (transport->write_lock == TRUE) 464 return FALSE; 465 write_lock = TRUE; 466 } 467 468 /* Check invalid accesstype */ 469 if (read_lock == FALSE && write_lock == FALSE) 470 return FALSE; 471 472 if (read_lock) { 473 transport->read_lock = read_lock; 474 DBG("Transport %s: read lock acquired", transport->path); 475 } 476 477 if (write_lock) { 478 transport->write_lock = write_lock; 479 DBG("Transport %s: write lock acquired", transport->path); 480 } 481 482 483 return TRUE; 484 } 485 486 static void media_transport_add(struct media_transport *transport, 487 struct media_owner *owner) 488 { 489 DBG("Transport %s Owner %s", transport->path, owner->name); 490 transport->owners = g_slist_append(transport->owners, owner); 491 owner->transport = transport; 492 } 493 494 static struct media_owner *media_owner_create(DBusConnection *conn, 495 DBusMessage *msg, 496 const char *accesstype) 497 { 498 struct media_owner *owner; 499 500 owner = g_new0(struct media_owner, 1); 501 owner->name = g_strdup(dbus_message_get_sender(msg)); 502 owner->accesstype = g_strdup(accesstype); 503 owner->watch = g_dbus_add_disconnect_watch(conn, owner->name, 504 media_owner_exit, 505 owner, NULL); 506 507 DBG("Owner created: sender=%s accesstype=%s", owner->name, 508 accesstype); 509 510 return owner; 511 } 512 513 static void media_owner_add(struct media_owner *owner, 514 struct media_request *req) 515 { 516 DBG("Owner %s Request %s", owner->name, 517 dbus_message_get_member(req->msg)); 518 519 owner->pending = req; 520 } 521 522 static struct media_owner *media_transport_find_owner( 523 struct media_transport *transport, 524 const char *name) 525 { 526 GSList *l; 527 528 for (l = transport->owners; l; l = l->next) { 529 struct media_owner *owner = l->data; 530 531 if (g_strcmp0(owner->name, name) == 0) 532 return owner; 533 } 534 535 return NULL; 536 } 537 538 static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg, 539 void *data) 540 { 541 struct media_transport *transport = data; 542 struct media_owner *owner; 543 struct media_request *req; 544 const char *accesstype, *sender; 545 guint id; 546 547 if (!dbus_message_get_args(msg, NULL, 548 DBUS_TYPE_STRING, &accesstype, 549 DBUS_TYPE_INVALID)) 550 return NULL; 551 552 sender = dbus_message_get_sender(msg); 553 554 owner = media_transport_find_owner(transport, sender); 555 if (owner != NULL) 556 return btd_error_not_authorized(msg); 557 558 if (media_transport_acquire(transport, accesstype) == FALSE) 559 return btd_error_not_authorized(msg); 560 561 owner = media_owner_create(conn, msg, accesstype); 562 id = transport->resume(transport, owner); 563 if (id == 0) { 564 media_owner_free(owner); 565 return btd_error_not_authorized(msg); 566 } 567 568 req = media_request_create(msg, id); 569 media_owner_add(owner, req); 570 media_transport_add(transport, owner); 571 572 return NULL; 573 } 574 575 static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, 576 void *data) 577 { 578 struct media_transport *transport = data; 579 struct media_owner *owner; 580 const char *accesstype, *sender; 581 struct media_request *req; 582 583 if (!dbus_message_get_args(msg, NULL, 584 DBUS_TYPE_STRING, &accesstype, 585 DBUS_TYPE_INVALID)) 586 return NULL; 587 588 sender = dbus_message_get_sender(msg); 589 590 owner = media_transport_find_owner(transport, sender); 591 if (owner == NULL) 592 return btd_error_not_authorized(msg); 593 594 if (g_strcmp0(owner->accesstype, accesstype) == 0) { 595 guint id; 596 597 /* Not the last owner, no need to suspend */ 598 if (g_slist_length(transport->owners) != 1) { 599 media_transport_remove(transport, owner); 600 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 601 } 602 603 if (owner->pending) { 604 const char *member; 605 606 member = dbus_message_get_member(owner->pending->msg); 607 /* Cancel Acquire request if that exist */ 608 if (g_str_equal(member, "Acquire")) 609 media_owner_remove(owner); 610 else 611 return btd_error_in_progress(msg); 612 } 613 614 id = transport->suspend(transport, owner); 615 if (id == 0) { 616 media_transport_remove(transport, owner); 617 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 618 } 619 620 req = media_request_create(msg, id); 621 media_owner_add(owner, req); 622 623 return NULL; 624 } else if (g_strstr_len(owner->accesstype, -1, accesstype) != NULL) { 625 media_transport_release(transport, accesstype); 626 g_strdelimit(owner->accesstype, accesstype, ' '); 627 } else 628 return btd_error_not_authorized(msg); 629 630 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 631 } 632 633 static int set_property_a2dp(struct media_transport *transport, 634 const char *property, 635 DBusMessageIter *value) 636 { 637 if (g_strcmp0(property, "Delay") == 0) { 638 if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) 639 return -EINVAL; 640 dbus_message_iter_get_basic(value, &transport->delay); 641 642 /* FIXME: send new delay */ 643 return 0; 644 } 645 646 return -EINVAL; 647 } 648 649 static int set_property_headset(struct media_transport *transport, 650 const char *property, 651 DBusMessageIter *value) 652 { 653 if (g_strcmp0(property, "NREC") == 0) { 654 gboolean nrec; 655 656 if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) 657 return -EINVAL; 658 dbus_message_iter_get_basic(value, &nrec); 659 660 /* FIXME: set new nrec */ 661 return 0; 662 } else if (g_strcmp0(property, "InbandRingtone") == 0) { 663 gboolean inband; 664 665 if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) 666 return -EINVAL; 667 dbus_message_iter_get_basic(value, &inband); 668 669 /* FIXME: set new inband */ 670 return 0; 671 } 672 673 return -EINVAL; 674 } 675 676 static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, 677 void *data) 678 { 679 struct media_transport *transport = data; 680 DBusMessageIter iter; 681 DBusMessageIter value; 682 const char *property, *sender; 683 GSList *l; 684 int err; 685 686 if (!dbus_message_iter_init(msg, &iter)) 687 return btd_error_invalid_args(msg); 688 689 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) 690 return btd_error_invalid_args(msg); 691 692 dbus_message_iter_get_basic(&iter, &property); 693 dbus_message_iter_next(&iter); 694 695 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) 696 return btd_error_invalid_args(msg); 697 dbus_message_iter_recurse(&iter, &value); 698 699 sender = dbus_message_get_sender(msg); 700 err = -EINVAL; 701 702 /* Check if sender has acquired the transport */ 703 for (l = transport->owners; l; l = l->next) { 704 struct media_owner *owner = l->data; 705 706 if (g_strcmp0(owner->name, sender) == 0) { 707 err = transport->set_property(transport, property, 708 &value); 709 break; 710 } 711 } 712 713 if (err < 0) { 714 if (err == -EINVAL) 715 return btd_error_invalid_args(msg); 716 return btd_error_failed(msg, strerror(-err)); 717 } 718 719 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 720 } 721 722 static void get_properties_a2dp(struct media_transport *transport, 723 DBusMessageIter *dict) 724 { 725 dict_append_entry(dict, "Delay", DBUS_TYPE_UINT16, &transport->delay); 726 } 727 728 static void get_properties_headset(struct media_transport *transport, 729 DBusMessageIter *dict) 730 { 731 gboolean nrec, inband; 732 const char *routing; 733 734 nrec = headset_get_nrec(transport->device); 735 dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &nrec); 736 737 inband = headset_get_inband(transport->device); 738 dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband); 739 740 routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM"; 741 dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing); 742 } 743 744 void transport_get_properties(struct media_transport *transport, 745 DBusMessageIter *iter) 746 { 747 DBusMessageIter dict; 748 const char *uuid; 749 uint8_t codec; 750 751 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, 752 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 753 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 754 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 755 756 /* Device */ 757 dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, 758 &transport->device->path); 759 760 uuid = media_endpoint_get_uuid(transport->endpoint); 761 dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid); 762 763 codec = media_endpoint_get_codec(transport->endpoint); 764 dict_append_entry(&dict, "Codec", DBUS_TYPE_BYTE, &codec); 765 766 dict_append_array(&dict, "Configuration", DBUS_TYPE_BYTE, 767 &transport->configuration, transport->size); 768 769 if (transport->get_properties) 770 transport->get_properties(transport, &dict); 771 772 dbus_message_iter_close_container(iter, &dict); 773 } 774 775 static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, 776 void *data) 777 { 778 struct media_transport *transport = data; 779 DBusMessage *reply; 780 DBusMessageIter iter; 781 782 reply = dbus_message_new_method_return(msg); 783 if (!reply) 784 return NULL; 785 786 dbus_message_iter_init_append(reply, &iter); 787 788 transport_get_properties(transport, &iter); 789 790 return reply; 791 } 792 793 static GDBusMethodTable transport_methods[] = { 794 { "GetProperties", "", "a{sv}", get_properties }, 795 { "Acquire", "s", "h", acquire, 796 G_DBUS_METHOD_FLAG_ASYNC}, 797 { "Release", "s", "", release, 798 G_DBUS_METHOD_FLAG_ASYNC}, 799 { "SetProperty", "sv", "", set_property }, 800 { }, 801 }; 802 803 static GDBusSignalTable transport_signals[] = { 804 { "PropertyChanged", "sv" }, 805 { } 806 }; 807 808 static void media_transport_free(void *data) 809 { 810 struct media_transport *transport = data; 811 GSList *l; 812 813 for (l = transport->owners; l; l = l->next) 814 media_transport_remove(transport, l->data); 815 816 g_slist_free(transport->owners); 817 818 if (transport->session) 819 avdtp_unref(transport->session); 820 821 if (transport->nrec_id) 822 headset_remove_nrec_cb(transport->device, transport->nrec_id); 823 824 if (transport->conn) 825 dbus_connection_unref(transport->conn); 826 827 g_free(transport->configuration); 828 g_free(transport->path); 829 g_free(transport); 830 } 831 832 static void headset_nrec_changed(struct audio_device *dev, gboolean nrec, 833 void *user_data) 834 { 835 struct media_transport *transport = user_data; 836 837 DBG(""); 838 839 emit_property_changed(transport->conn, transport->path, 840 MEDIA_TRANSPORT_INTERFACE, "NREC", 841 DBUS_TYPE_BOOLEAN, &nrec); 842 } 843 844 struct media_transport *media_transport_create(DBusConnection *conn, 845 struct media_endpoint *endpoint, 846 struct audio_device *device, 847 uint8_t *configuration, 848 size_t size) 849 { 850 struct media_transport *transport; 851 const char *uuid; 852 static int fd = 0; 853 854 transport = g_new0(struct media_transport, 1); 855 transport->conn = dbus_connection_ref(conn); 856 transport->device = device; 857 transport->endpoint = endpoint; 858 transport->configuration = g_new(uint8_t, size); 859 memcpy(transport->configuration, configuration, size); 860 transport->size = size; 861 transport->path = g_strdup_printf("%s/fd%d", device->path, fd++); 862 transport->fd = -1; 863 864 uuid = media_endpoint_get_uuid(endpoint); 865 if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0 || 866 strcasecmp(uuid, A2DP_SINK_UUID) == 0) { 867 transport->resume = resume_a2dp; 868 transport->suspend = suspend_a2dp; 869 transport->cancel = cancel_a2dp; 870 transport->get_properties = get_properties_a2dp; 871 transport->set_property = set_property_a2dp; 872 } else if (strcasecmp(uuid, HFP_AG_UUID) == 0 || 873 strcasecmp(uuid, HSP_AG_UUID) == 0) { 874 transport->resume = resume_headset; 875 transport->suspend = suspend_headset; 876 transport->cancel = cancel_headset; 877 transport->get_properties = get_properties_headset; 878 transport->set_property = set_property_headset; 879 transport->nrec_id = headset_add_nrec_cb(device, 880 headset_nrec_changed, 881 transport); 882 } else 883 goto fail; 884 885 if (g_dbus_register_interface(transport->conn, transport->path, 886 MEDIA_TRANSPORT_INTERFACE, 887 transport_methods, transport_signals, NULL, 888 transport, media_transport_free) == FALSE) { 889 error("Could not register transport %s", transport->path); 890 goto fail; 891 } 892 893 return transport; 894 895 fail: 896 media_transport_free(transport); 897 return NULL; 898 } 899 900 const char *media_transport_get_path(struct media_transport *transport) 901 { 902 return transport->path; 903 } 904 905 void media_transport_update_delay(struct media_transport *transport, 906 uint16_t delay) 907 { 908 /* Check if delay really changed */ 909 if (transport->delay == delay) 910 return; 911 912 transport->delay = delay; 913 914 emit_property_changed(transport->conn, transport->path, 915 MEDIA_TRANSPORT_INTERFACE, "Delay", 916 DBUS_TYPE_UINT16, &transport->delay); 917 } 918