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 <stdio.h> 30 #include <errno.h> 31 #include <unistd.h> 32 #include <sys/stat.h> 33 #include <sys/param.h> 34 #include <netinet/in.h> 35 36 #include <bluetooth/bluetooth.h> 37 #include <bluetooth/hci.h> 38 #include <bluetooth/hci_lib.h> 39 #include <bluetooth/sdp.h> 40 #include <bluetooth/sdp_lib.h> 41 42 #include <glib.h> 43 #include <dbus/dbus.h> 44 #include <gdbus.h> 45 46 #include "logging.h" 47 #include "textfile.h" 48 #include "../src/adapter.h" 49 #include "../src/device.h" 50 51 #include "error.h" 52 #include "ipc.h" 53 #include "dbus-common.h" 54 #include "device.h" 55 #include "unix.h" 56 #include "avdtp.h" 57 #include "control.h" 58 #include "headset.h" 59 #include "gateway.h" 60 #include "sink.h" 61 #include "source.h" 62 63 #define AUDIO_INTERFACE "org.bluez.Audio" 64 65 #define CONTROL_CONNECT_TIMEOUT 2 66 #define AVDTP_CONNECT_TIMEOUT 1 67 #define HEADSET_CONNECT_TIMEOUT 1 68 69 typedef enum { 70 AUDIO_STATE_DISCONNECTED, 71 AUDIO_STATE_CONNECTING, 72 AUDIO_STATE_CONNECTED, 73 } audio_state_t; 74 75 struct service_auth { 76 service_auth_cb cb; 77 void *user_data; 78 }; 79 80 struct dev_priv { 81 audio_state_t state; 82 83 headset_state_t hs_state; 84 sink_state_t sink_state; 85 avctp_state_t avctp_state; 86 GSList *auths; 87 88 DBusMessage *conn_req; 89 DBusMessage *dc_req; 90 91 guint control_timer; 92 guint avdtp_timer; 93 guint headset_timer; 94 95 gboolean authorized; 96 guint auth_idle_id; 97 }; 98 99 static unsigned int sink_callback_id = 0; 100 static unsigned int avctp_callback_id = 0; 101 static unsigned int avdtp_callback_id = 0; 102 static unsigned int headset_callback_id = 0; 103 104 static void device_free(struct audio_device *dev) 105 { 106 struct dev_priv *priv = dev->priv; 107 108 if (dev->conn) 109 dbus_connection_unref(dev->conn); 110 111 btd_device_unref(dev->btd_dev); 112 113 if (priv) { 114 if (priv->control_timer) 115 g_source_remove(priv->control_timer); 116 if (priv->avdtp_timer) 117 g_source_remove(priv->avdtp_timer); 118 if (priv->headset_timer) 119 g_source_remove(priv->headset_timer); 120 if (priv->dc_req) 121 dbus_message_unref(priv->dc_req); 122 if (priv->conn_req) 123 dbus_message_unref(priv->conn_req); 124 g_free(priv); 125 } 126 127 g_free(dev->path); 128 g_free(dev); 129 } 130 131 static const char *state2str(audio_state_t state) 132 { 133 switch (state) { 134 case AUDIO_STATE_DISCONNECTED: 135 return "disconnected"; 136 case AUDIO_STATE_CONNECTING: 137 return "connecting"; 138 case AUDIO_STATE_CONNECTED: 139 return "connected"; 140 default: 141 error("Invalid audio state %d", state); 142 return NULL; 143 } 144 } 145 146 static void device_set_state(struct audio_device *dev, audio_state_t new_state) 147 { 148 struct dev_priv *priv = dev->priv; 149 const char *state_str; 150 DBusMessage *reply = NULL; 151 152 state_str = state2str(new_state); 153 if (!state_str) 154 return; 155 156 if (new_state == AUDIO_STATE_DISCONNECTED) 157 priv->authorized = FALSE; 158 159 if (dev->priv->state == new_state) { 160 debug("state change attempted from %s to %s", 161 state_str, state_str); 162 return; 163 } 164 165 dev->priv->state = new_state; 166 167 if (priv->dc_req && new_state == AUDIO_STATE_DISCONNECTED) { 168 reply = dbus_message_new_method_return(priv->dc_req); 169 dbus_message_unref(priv->dc_req); 170 priv->dc_req = NULL; 171 g_dbus_send_message(dev->conn, reply); 172 } 173 174 if (priv->conn_req && new_state != AUDIO_STATE_CONNECTING) { 175 if (new_state == AUDIO_STATE_CONNECTED) 176 reply = dbus_message_new_method_return(priv->conn_req); 177 else 178 reply = g_dbus_create_error(priv->conn_req, 179 ERROR_INTERFACE 180 ".ConnectFailed", 181 "Connecting failed"); 182 dbus_message_unref(priv->conn_req); 183 priv->conn_req = NULL; 184 g_dbus_send_message(dev->conn, reply); 185 } 186 187 emit_property_changed(dev->conn, dev->path, 188 AUDIO_INTERFACE, "State", 189 DBUS_TYPE_STRING, &state_str); 190 } 191 192 static gboolean control_connect_timeout(gpointer user_data) 193 { 194 struct audio_device *dev = user_data; 195 196 dev->priv->control_timer = 0; 197 198 if (dev->control) 199 avrcp_connect(dev); 200 201 return FALSE; 202 } 203 204 static gboolean device_set_control_timer(struct audio_device *dev) 205 { 206 struct dev_priv *priv = dev->priv; 207 208 if (!dev->control) 209 return FALSE; 210 211 if (priv->control_timer) 212 return FALSE; 213 214 priv->control_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT, 215 control_connect_timeout, 216 dev); 217 218 return TRUE; 219 } 220 221 static void device_remove_control_timer(struct audio_device *dev) 222 { 223 if (dev->priv->control_timer) 224 g_source_remove(dev->priv->control_timer); 225 dev->priv->control_timer = 0; 226 } 227 228 static gboolean avdtp_connect_timeout(gpointer user_data) 229 { 230 struct audio_device *dev = user_data; 231 232 dev->priv->avdtp_timer = 0; 233 234 if (dev->sink) { 235 struct avdtp *session = avdtp_get(&dev->src, &dev->dst); 236 237 if (!session) 238 return FALSE; 239 240 sink_setup_stream(dev->sink, session); 241 avdtp_unref(session); 242 } 243 244 return FALSE; 245 } 246 247 static gboolean device_set_avdtp_timer(struct audio_device *dev) 248 { 249 struct dev_priv *priv = dev->priv; 250 251 if (!dev->sink) 252 return FALSE; 253 254 if (priv->avdtp_timer) 255 return FALSE; 256 257 priv->avdtp_timer = g_timeout_add_seconds(AVDTP_CONNECT_TIMEOUT, 258 avdtp_connect_timeout, 259 dev); 260 261 return TRUE; 262 } 263 264 static void device_remove_avdtp_timer(struct audio_device *dev) 265 { 266 if (dev->priv->avdtp_timer) 267 g_source_remove(dev->priv->avdtp_timer); 268 dev->priv->avdtp_timer = 0; 269 } 270 271 static gboolean headset_connect_timeout(gpointer user_data) 272 { 273 struct audio_device *dev = user_data; 274 struct dev_priv *priv = dev->priv; 275 276 dev->priv->headset_timer = 0; 277 278 if (dev->headset == NULL) 279 return FALSE; 280 281 if (headset_config_stream(dev, FALSE, NULL, NULL) == 0) { 282 if (priv->state != AUDIO_STATE_CONNECTED && 283 (priv->sink_state == SINK_STATE_CONNECTED || 284 priv->sink_state == SINK_STATE_PLAYING)) 285 device_set_state(dev, AUDIO_STATE_CONNECTED); 286 } 287 288 return FALSE; 289 } 290 291 static gboolean device_set_headset_timer(struct audio_device *dev) 292 { 293 struct dev_priv *priv = dev->priv; 294 295 if (!dev->headset) 296 return FALSE; 297 298 if (priv->headset_timer) 299 return FALSE; 300 301 priv->headset_timer = g_timeout_add_seconds(HEADSET_CONNECT_TIMEOUT, 302 headset_connect_timeout, dev); 303 304 return TRUE; 305 } 306 307 static void device_remove_headset_timer(struct audio_device *dev) 308 { 309 if (dev->priv->headset_timer) 310 g_source_remove(dev->priv->headset_timer); 311 dev->priv->headset_timer = 0; 312 } 313 314 static void device_avdtp_cb(struct audio_device *dev, struct avdtp *session, 315 avdtp_session_state_t old_state, 316 avdtp_session_state_t new_state, 317 void *user_data) 318 { 319 if (!dev->sink || !dev->control) 320 return; 321 322 if (new_state == AVDTP_SESSION_STATE_CONNECTED) { 323 if (avdtp_stream_setup_active(session)) 324 device_set_control_timer(dev); 325 else 326 avrcp_connect(dev); 327 } 328 } 329 330 static void device_sink_cb(struct audio_device *dev, 331 sink_state_t old_state, 332 sink_state_t new_state, 333 void *user_data) 334 { 335 struct dev_priv *priv = dev->priv; 336 337 if (!dev->sink) 338 return; 339 340 priv->sink_state = new_state; 341 342 switch (new_state) { 343 case SINK_STATE_DISCONNECTED: 344 if (dev->control) { 345 device_remove_control_timer(dev); 346 avrcp_disconnect(dev); 347 } 348 if (priv->hs_state == HEADSET_STATE_DISCONNECTED) 349 device_set_state(dev, AUDIO_STATE_DISCONNECTED); 350 else if (old_state == SINK_STATE_CONNECTING) { 351 switch (priv->hs_state) { 352 case HEADSET_STATE_CONNECTED: 353 case HEADSET_STATE_PLAY_IN_PROGRESS: 354 case HEADSET_STATE_PLAYING: 355 device_set_state(dev, AUDIO_STATE_CONNECTED); 356 default: 357 break; 358 } 359 } 360 break; 361 case SINK_STATE_CONNECTING: 362 device_remove_avdtp_timer(dev); 363 if (priv->hs_state == HEADSET_STATE_DISCONNECTED) 364 device_set_state(dev, AUDIO_STATE_CONNECTING); 365 break; 366 case SINK_STATE_CONNECTED: 367 if (old_state == SINK_STATE_PLAYING) 368 break; 369 #ifdef ANDROID 370 android_set_high_priority(&dev->dst); 371 #endif 372 if (dev->auto_connect) { 373 if (!dev->headset) 374 device_set_state(dev, AUDIO_STATE_CONNECTED); 375 if (priv->hs_state == HEADSET_STATE_DISCONNECTED) 376 device_set_headset_timer(dev); 377 else if (priv->hs_state == HEADSET_STATE_CONNECTED) 378 device_set_state(dev, AUDIO_STATE_CONNECTED); 379 } else if (priv->hs_state != HEADSET_STATE_CONNECTED) 380 device_set_state(dev, AUDIO_STATE_CONNECTED); 381 break; 382 case SINK_STATE_PLAYING: 383 break; 384 } 385 } 386 387 static void device_avctp_cb(struct audio_device *dev, 388 avctp_state_t old_state, 389 avctp_state_t new_state, 390 void *user_data) 391 { 392 if (!dev->control) 393 return; 394 395 dev->priv->avctp_state = new_state; 396 397 switch (new_state) { 398 case AVCTP_STATE_DISCONNECTED: 399 break; 400 case AVCTP_STATE_CONNECTING: 401 device_remove_control_timer(dev); 402 break; 403 case AVCTP_STATE_CONNECTED: 404 break; 405 } 406 } 407 408 static void device_headset_cb(struct audio_device *dev, 409 headset_state_t old_state, 410 headset_state_t new_state, 411 void *user_data) 412 { 413 struct dev_priv *priv = dev->priv; 414 415 if (!dev->headset) 416 return; 417 418 priv->hs_state = new_state; 419 420 switch (new_state) { 421 case HEADSET_STATE_DISCONNECTED: 422 device_remove_avdtp_timer(dev); 423 if (priv->sink_state != SINK_STATE_DISCONNECTED && 424 dev->sink && priv->dc_req) { 425 sink_shutdown(dev->sink); 426 break; 427 } 428 if (priv->sink_state == SINK_STATE_DISCONNECTED) 429 device_set_state(dev, AUDIO_STATE_DISCONNECTED); 430 else if (old_state == HEADSET_STATE_CONNECT_IN_PROGRESS && 431 (priv->sink_state == SINK_STATE_CONNECTED || 432 priv->sink_state == SINK_STATE_PLAYING)) 433 device_set_state(dev, AUDIO_STATE_CONNECTED); 434 break; 435 case HEADSET_STATE_CONNECT_IN_PROGRESS: 436 device_remove_headset_timer(dev); 437 if (priv->sink_state == SINK_STATE_DISCONNECTED) 438 device_set_state(dev, AUDIO_STATE_CONNECTING); 439 break; 440 case HEADSET_STATE_CONNECTED: 441 if (old_state == HEADSET_STATE_CONNECTED || 442 old_state == HEADSET_STATE_PLAY_IN_PROGRESS || 443 old_state == HEADSET_STATE_PLAYING) 444 break; 445 if (dev->auto_connect) { 446 if (!dev->sink) 447 device_set_state(dev, AUDIO_STATE_CONNECTED); 448 else if (priv->sink_state == SINK_STATE_DISCONNECTED) 449 device_set_avdtp_timer(dev); 450 else if (priv->sink_state == SINK_STATE_CONNECTED) 451 device_set_state(dev, AUDIO_STATE_CONNECTED); 452 } else if (priv->sink_state != SINK_STATE_CONNECTED) 453 device_set_state(dev, AUDIO_STATE_CONNECTED); 454 break; 455 case HEADSET_STATE_PLAY_IN_PROGRESS: 456 break; 457 case HEADSET_STATE_PLAYING: 458 break; 459 } 460 } 461 462 static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, 463 void *data) 464 { 465 struct audio_device *dev = data; 466 struct dev_priv *priv = dev->priv; 467 468 if (priv->state == AUDIO_STATE_CONNECTING) 469 return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", 470 "Connect in Progress"); 471 else if (priv->state == AUDIO_STATE_CONNECTED) 472 return g_dbus_create_error(msg, ERROR_INTERFACE 473 ".AlreadyConnected", 474 "Already Connected"); 475 476 dev->auto_connect = TRUE; 477 478 if (dev->headset) 479 headset_config_stream(dev, FALSE, NULL, NULL); 480 481 if (priv->state != AUDIO_STATE_CONNECTING && dev->sink) { 482 struct avdtp *session = avdtp_get(&dev->src, &dev->dst); 483 484 if (!session) 485 return g_dbus_create_error(msg, ERROR_INTERFACE 486 ".Failed", 487 "Failed to get AVDTP session"); 488 489 sink_setup_stream(dev->sink, session); 490 avdtp_unref(session); 491 } 492 493 /* The previous calls should cause a call to the state callback to 494 * indicate AUDIO_STATE_CONNECTING */ 495 if (priv->state != AUDIO_STATE_CONNECTING) 496 return g_dbus_create_error(msg, ERROR_INTERFACE 497 ".ConnectFailed", 498 "Headset connect failed"); 499 500 priv->conn_req = dbus_message_ref(msg); 501 502 return NULL; 503 } 504 505 static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg, 506 void *data) 507 { 508 struct audio_device *dev = data; 509 struct dev_priv *priv = dev->priv; 510 511 if (priv->state == AUDIO_STATE_DISCONNECTED) 512 return g_dbus_create_error(msg, ERROR_INTERFACE ".NotConnected", 513 "Not connected"); 514 515 if (priv->dc_req) 516 return dbus_message_new_method_return(msg); 517 518 priv->dc_req = dbus_message_ref(msg); 519 520 if (priv->hs_state != HEADSET_STATE_DISCONNECTED) 521 headset_shutdown(dev); 522 else if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) 523 sink_shutdown(dev->sink); 524 else { 525 dbus_message_unref(priv->dc_req); 526 priv->dc_req = NULL; 527 return dbus_message_new_method_return(msg); 528 } 529 530 return NULL; 531 } 532 533 static DBusMessage *dev_get_properties(DBusConnection *conn, DBusMessage *msg, 534 void *data) 535 { 536 struct audio_device *device = data; 537 DBusMessage *reply; 538 DBusMessageIter iter; 539 DBusMessageIter dict; 540 const char *state; 541 542 reply = dbus_message_new_method_return(msg); 543 if (!reply) 544 return NULL; 545 546 dbus_message_iter_init_append(reply, &iter); 547 548 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 549 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 550 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 551 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 552 553 /* State */ 554 state = state2str(device->priv->state); 555 if (state) 556 dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); 557 558 dbus_message_iter_close_container(&iter, &dict); 559 560 return reply; 561 } 562 563 static GDBusMethodTable dev_methods[] = { 564 { "Connect", "", "", dev_connect, 565 G_DBUS_METHOD_FLAG_ASYNC }, 566 { "Disconnect", "", "", dev_disconnect }, 567 { "GetProperties", "", "a{sv}",dev_get_properties }, 568 { NULL, NULL, NULL, NULL } 569 }; 570 571 static GDBusSignalTable dev_signals[] = { 572 { "PropertyChanged", "sv" }, 573 { NULL, NULL } 574 }; 575 576 struct audio_device *audio_device_register(DBusConnection *conn, 577 struct btd_device *device, 578 const char *path, const bdaddr_t *src, 579 const bdaddr_t *dst) 580 { 581 struct audio_device *dev; 582 583 if (!conn || !path) 584 return NULL; 585 586 dev = g_new0(struct audio_device, 1); 587 588 dev->btd_dev = btd_device_ref(device); 589 dev->path = g_strdup(path); 590 bacpy(&dev->dst, dst); 591 bacpy(&dev->src, src); 592 dev->conn = dbus_connection_ref(conn); 593 dev->priv = g_new0(struct dev_priv, 1); 594 dev->priv->state = AUDIO_STATE_DISCONNECTED; 595 596 if (!g_dbus_register_interface(dev->conn, dev->path, 597 AUDIO_INTERFACE, 598 dev_methods, dev_signals, NULL, 599 dev, NULL)) { 600 error("Unable to register %s on %s", AUDIO_INTERFACE, 601 dev->path); 602 device_free(dev); 603 return NULL; 604 } 605 606 debug("Registered interface %s on path %s", AUDIO_INTERFACE, 607 dev->path); 608 609 if (sink_callback_id == 0) 610 sink_callback_id = sink_add_state_cb(device_sink_cb, NULL); 611 612 if (avdtp_callback_id == 0) 613 avdtp_callback_id = avdtp_add_state_cb(device_avdtp_cb, NULL); 614 if (avctp_callback_id == 0) 615 avctp_callback_id = avctp_add_state_cb(device_avctp_cb, NULL); 616 617 if (headset_callback_id == 0) 618 headset_callback_id = headset_add_state_cb(device_headset_cb, 619 NULL); 620 621 return dev; 622 } 623 624 gboolean audio_device_is_active(struct audio_device *dev, 625 const char *interface) 626 { 627 if (!interface) { 628 if ((dev->sink || dev->source) && 629 avdtp_is_connected(&dev->src, &dev->dst)) 630 return TRUE; 631 632 if (dev->headset && headset_is_active(dev)) 633 return TRUE; 634 } 635 else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink && 636 avdtp_is_connected(&dev->src, &dev->dst)) 637 return TRUE; 638 else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source && 639 avdtp_is_connected(&dev->src, &dev->dst)) 640 return TRUE; 641 else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset && 642 headset_is_active(dev)) 643 return TRUE; 644 else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->control && 645 control_is_active(dev)) 646 return TRUE; 647 else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway && 648 gateway_is_connected(dev)) 649 return TRUE; 650 651 return FALSE; 652 } 653 654 void audio_device_unregister(struct audio_device *device) 655 { 656 unix_device_removed(device); 657 658 if (device->headset) 659 headset_unregister(device); 660 661 if (device->sink) 662 sink_unregister(device); 663 664 if (device->source) 665 source_unregister(device); 666 667 if (device->control) 668 control_unregister(device); 669 670 g_dbus_unregister_interface(device->conn, device->path, 671 AUDIO_INTERFACE); 672 673 device_free(device); 674 } 675 676 static void auth_cb(DBusError *derr, void *user_data) 677 { 678 struct audio_device *dev = user_data; 679 struct dev_priv *priv = dev->priv; 680 681 if (derr == NULL) 682 priv->authorized = TRUE; 683 684 while (priv->auths) { 685 struct service_auth *auth = priv->auths->data; 686 687 auth->cb(derr, auth->user_data); 688 priv->auths = g_slist_remove(priv->auths, auth); 689 g_free(auth); 690 } 691 } 692 693 static gboolean auth_idle_cb(gpointer user_data) 694 { 695 struct audio_device *dev = user_data; 696 struct dev_priv *priv = dev->priv; 697 698 priv->auth_idle_id = 0; 699 700 auth_cb(NULL, dev); 701 702 return FALSE; 703 } 704 705 static gboolean audio_device_is_connected(struct audio_device *dev) 706 { 707 if (dev->headset) { 708 headset_state_t state = headset_get_state(dev); 709 710 if (state == HEADSET_STATE_CONNECTED || 711 state == HEADSET_STATE_PLAY_IN_PROGRESS || 712 state == HEADSET_STATE_PLAYING) 713 return TRUE; 714 } 715 716 if (dev->sink) { 717 sink_state_t state = sink_get_state(dev); 718 719 if (state == SINK_STATE_CONNECTED || 720 state == SINK_STATE_PLAYING) 721 return TRUE; 722 } 723 724 if (dev->source) { 725 source_state_t state = source_get_state(dev); 726 727 if (state == SOURCE_STATE_CONNECTED || 728 state == SOURCE_STATE_PLAYING) 729 return TRUE; 730 } 731 732 return FALSE; 733 } 734 735 int audio_device_request_authorization(struct audio_device *dev, 736 const char *uuid, service_auth_cb cb, 737 void *user_data) 738 { 739 struct dev_priv *priv = dev->priv; 740 struct service_auth *auth; 741 int err; 742 743 auth = g_try_new0(struct service_auth, 1); 744 if (!auth) 745 return -ENOMEM; 746 747 auth->cb = cb; 748 auth->user_data = user_data; 749 750 priv->auths = g_slist_append(priv->auths, auth); 751 if (g_slist_length(priv->auths) > 1) 752 return 0; 753 754 if (priv->authorized || audio_device_is_connected(dev)) { 755 priv->auth_idle_id = g_idle_add(auth_idle_cb, dev); 756 return 0; 757 } 758 759 err = btd_request_authorization(&dev->src, &dev->dst, uuid, auth_cb, 760 dev); 761 if (err < 0) { 762 priv->auths = g_slist_remove(priv->auths, auth); 763 g_free(auth); 764 } 765 766 return err; 767 } 768 769 int audio_device_cancel_authorization(struct audio_device *dev, 770 authorization_cb cb, void *user_data) 771 { 772 struct dev_priv *priv = dev->priv; 773 GSList *l, *next; 774 775 for (l = priv->auths; l != NULL; l = next) { 776 struct service_auth *auth = priv->auths->data; 777 778 next = g_slist_next(l); 779 780 if (cb && auth->cb != cb) 781 continue; 782 783 if (user_data && auth->user_data != user_data) 784 continue; 785 786 priv->auths = g_slist_remove(priv->auths, auth); 787 g_free(auth); 788 } 789 790 if (g_slist_length(priv->auths) == 0) { 791 if (priv->auth_idle_id > 0) { 792 g_source_remove(priv->auth_idle_id); 793 priv->auth_idle_id = 0; 794 } else 795 btd_cancel_authorization(&dev->src, &dev->dst); 796 } 797 798 return 0; 799 } 800