device.c revision 8e58667ef0a4cda88ac64137728da28d8fdf3f0f
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2010 Nokia Corporation 6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@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 "log.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 69typedef enum { 70 AUDIO_STATE_DISCONNECTED, 71 AUDIO_STATE_CONNECTING, 72 AUDIO_STATE_CONNECTED, 73} audio_state_t; 74 75struct service_auth { 76 service_auth_cb cb; 77 void *user_data; 78}; 79 80struct 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 99static unsigned int sink_callback_id = 0; 100static unsigned int avctp_callback_id = 0; 101static unsigned int avdtp_callback_id = 0; 102static unsigned int headset_callback_id = 0; 103 104static 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 131static 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 146static 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 DBG("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 192static 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 204static 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 221static 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 228static 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 247static 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 264static 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 271static 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 291static 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 307static 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 314static 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 330static 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 if (dev->auto_connect) { 370 if (!dev->headset) 371 device_set_state(dev, AUDIO_STATE_CONNECTED); 372 else if (priv->hs_state == HEADSET_STATE_DISCONNECTED) 373 device_set_headset_timer(dev); 374 else if (priv->hs_state == HEADSET_STATE_CONNECTED || 375 priv->hs_state == HEADSET_STATE_PLAY_IN_PROGRESS || 376 priv->hs_state == HEADSET_STATE_PLAYING) 377 device_set_state(dev, AUDIO_STATE_CONNECTED); 378 } else if (priv->hs_state == HEADSET_STATE_DISCONNECTED || 379 priv->hs_state == HEADSET_STATE_CONNECTING) 380 device_set_state(dev, AUDIO_STATE_CONNECTED); 381 break; 382 case SINK_STATE_PLAYING: 383 break; 384 } 385} 386 387static 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 408static 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_CONNECTING && 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_CONNECTING: 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 priv->sink_state == SINK_STATE_PLAYING) 452 device_set_state(dev, AUDIO_STATE_CONNECTED); 453 } else if (priv->sink_state == SINK_STATE_DISCONNECTED || 454 priv->sink_state == SINK_STATE_CONNECTING) 455 device_set_state(dev, AUDIO_STATE_CONNECTED); 456 break; 457 case HEADSET_STATE_PLAY_IN_PROGRESS: 458 break; 459 case HEADSET_STATE_PLAYING: 460 break; 461 } 462} 463 464static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, 465 void *data) 466{ 467 struct audio_device *dev = data; 468 struct dev_priv *priv = dev->priv; 469 470 if (priv->state == AUDIO_STATE_CONNECTING) 471 return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", 472 "Connect in Progress"); 473 else if (priv->state == AUDIO_STATE_CONNECTED) 474 return g_dbus_create_error(msg, ERROR_INTERFACE 475 ".AlreadyConnected", 476 "Already Connected"); 477 478 dev->auto_connect = TRUE; 479 480 if (dev->headset) 481 headset_config_stream(dev, FALSE, NULL, NULL); 482 483 if (priv->state != AUDIO_STATE_CONNECTING && dev->sink) { 484 struct avdtp *session = avdtp_get(&dev->src, &dev->dst); 485 486 if (!session) 487 return g_dbus_create_error(msg, ERROR_INTERFACE 488 ".Failed", 489 "Failed to get AVDTP session"); 490 491 sink_setup_stream(dev->sink, session); 492 avdtp_unref(session); 493 } 494 495 /* The previous calls should cause a call to the state callback to 496 * indicate AUDIO_STATE_CONNECTING */ 497 if (priv->state != AUDIO_STATE_CONNECTING) 498 return g_dbus_create_error(msg, ERROR_INTERFACE 499 ".ConnectFailed", 500 "Headset connect failed"); 501 502 priv->conn_req = dbus_message_ref(msg); 503 504 return NULL; 505} 506 507static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg, 508 void *data) 509{ 510 struct audio_device *dev = data; 511 struct dev_priv *priv = dev->priv; 512 513 if (priv->state == AUDIO_STATE_DISCONNECTED) 514 return g_dbus_create_error(msg, ERROR_INTERFACE ".NotConnected", 515 "Not connected"); 516 517 if (priv->dc_req) 518 return dbus_message_new_method_return(msg); 519 520 priv->dc_req = dbus_message_ref(msg); 521 522 if (priv->hs_state != HEADSET_STATE_DISCONNECTED) 523 headset_shutdown(dev); 524 else if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) 525 sink_shutdown(dev->sink); 526 else { 527 dbus_message_unref(priv->dc_req); 528 priv->dc_req = NULL; 529 return dbus_message_new_method_return(msg); 530 } 531 532 return NULL; 533} 534 535static DBusMessage *dev_get_properties(DBusConnection *conn, DBusMessage *msg, 536 void *data) 537{ 538 struct audio_device *device = data; 539 DBusMessage *reply; 540 DBusMessageIter iter; 541 DBusMessageIter dict; 542 const char *state; 543 544 reply = dbus_message_new_method_return(msg); 545 if (!reply) 546 return NULL; 547 548 dbus_message_iter_init_append(reply, &iter); 549 550 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 551 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 552 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 553 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 554 555 /* State */ 556 state = state2str(device->priv->state); 557 if (state) 558 dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); 559 560 dbus_message_iter_close_container(&iter, &dict); 561 562 return reply; 563} 564 565static GDBusMethodTable dev_methods[] = { 566 { "Connect", "", "", dev_connect, 567 G_DBUS_METHOD_FLAG_ASYNC }, 568 { "Disconnect", "", "", dev_disconnect }, 569 { "GetProperties", "", "a{sv}",dev_get_properties }, 570 { NULL, NULL, NULL, NULL } 571}; 572 573static GDBusSignalTable dev_signals[] = { 574 { "PropertyChanged", "sv" }, 575 { NULL, NULL } 576}; 577 578struct audio_device *audio_device_register(DBusConnection *conn, 579 struct btd_device *device, 580 const char *path, const bdaddr_t *src, 581 const bdaddr_t *dst) 582{ 583 struct audio_device *dev; 584 585 if (!conn || !path) 586 return NULL; 587 588 dev = g_new0(struct audio_device, 1); 589 590 dev->btd_dev = btd_device_ref(device); 591 dev->path = g_strdup(path); 592 bacpy(&dev->dst, dst); 593 bacpy(&dev->src, src); 594 dev->conn = dbus_connection_ref(conn); 595 dev->priv = g_new0(struct dev_priv, 1); 596 dev->priv->state = AUDIO_STATE_DISCONNECTED; 597 598 if (!g_dbus_register_interface(dev->conn, dev->path, 599 AUDIO_INTERFACE, 600 dev_methods, dev_signals, NULL, 601 dev, NULL)) { 602 error("Unable to register %s on %s", AUDIO_INTERFACE, 603 dev->path); 604 device_free(dev); 605 return NULL; 606 } 607 608 DBG("Registered interface %s on path %s", AUDIO_INTERFACE, 609 dev->path); 610 611 if (sink_callback_id == 0) 612 sink_callback_id = sink_add_state_cb(device_sink_cb, NULL); 613 614 if (avdtp_callback_id == 0) 615 avdtp_callback_id = avdtp_add_state_cb(device_avdtp_cb, NULL); 616 if (avctp_callback_id == 0) 617 avctp_callback_id = avctp_add_state_cb(device_avctp_cb, NULL); 618 619 if (headset_callback_id == 0) 620 headset_callback_id = headset_add_state_cb(device_headset_cb, 621 NULL); 622 623 return dev; 624} 625 626gboolean audio_device_is_active(struct audio_device *dev, 627 const char *interface) 628{ 629 if (!interface) { 630 if ((dev->sink || dev->source) && 631 avdtp_is_connected(&dev->src, &dev->dst)) 632 return TRUE; 633 if (dev->headset && headset_is_active(dev)) 634 return TRUE; 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 654void audio_device_unregister(struct audio_device *device) 655{ 656 unix_device_removed(device); 657 658 if (device->hs_preauth_id) { 659 g_source_remove(device->hs_preauth_id); 660 device->hs_preauth_id = 0; 661 } 662 663 if (device->headset) 664 headset_unregister(device); 665 666 if (device->gateway) 667 gateway_unregister(device); 668 669 if (device->sink) 670 sink_unregister(device); 671 672 if (device->source) 673 source_unregister(device); 674 675 if (device->control) 676 control_unregister(device); 677 678 g_dbus_unregister_interface(device->conn, device->path, 679 AUDIO_INTERFACE); 680 681 device_free(device); 682} 683 684static void auth_cb(DBusError *derr, void *user_data) 685{ 686 struct audio_device *dev = user_data; 687 struct dev_priv *priv = dev->priv; 688 689 if (derr == NULL) 690 priv->authorized = TRUE; 691 692 while (priv->auths) { 693 struct service_auth *auth = priv->auths->data; 694 695 auth->cb(derr, auth->user_data); 696 priv->auths = g_slist_remove(priv->auths, auth); 697 g_free(auth); 698 } 699} 700 701static gboolean auth_idle_cb(gpointer user_data) 702{ 703 struct audio_device *dev = user_data; 704 struct dev_priv *priv = dev->priv; 705 706 priv->auth_idle_id = 0; 707 708 auth_cb(NULL, dev); 709 710 return FALSE; 711} 712 713static gboolean audio_device_is_connected(struct audio_device *dev) 714{ 715 if (dev->headset) { 716 headset_state_t state = headset_get_state(dev); 717 718 if (state == HEADSET_STATE_CONNECTED || 719 state == HEADSET_STATE_PLAY_IN_PROGRESS || 720 state == HEADSET_STATE_PLAYING) 721 return TRUE; 722 } 723 724 if (dev->sink) { 725 sink_state_t state = sink_get_state(dev); 726 727 if (state == SINK_STATE_CONNECTED || 728 state == SINK_STATE_PLAYING) 729 return TRUE; 730 } 731 732 if (dev->source) { 733 source_state_t state = source_get_state(dev); 734 735 if (state == SOURCE_STATE_CONNECTED || 736 state == SOURCE_STATE_PLAYING) 737 return TRUE; 738 } 739 740 return FALSE; 741} 742 743int audio_device_request_authorization(struct audio_device *dev, 744 const char *uuid, service_auth_cb cb, 745 void *user_data) 746{ 747 struct dev_priv *priv = dev->priv; 748 struct service_auth *auth; 749 int err; 750 751 auth = g_try_new0(struct service_auth, 1); 752 if (!auth) 753 return -ENOMEM; 754 755 auth->cb = cb; 756 auth->user_data = user_data; 757 758 priv->auths = g_slist_append(priv->auths, auth); 759 if (g_slist_length(priv->auths) > 1) 760 return 0; 761 762 if (priv->authorized || audio_device_is_connected(dev)) { 763 priv->auth_idle_id = g_idle_add(auth_idle_cb, dev); 764 return 0; 765 } 766 767 err = btd_request_authorization(&dev->src, &dev->dst, uuid, auth_cb, 768 dev); 769 if (err < 0) { 770 priv->auths = g_slist_remove(priv->auths, auth); 771 g_free(auth); 772 } 773 774 return err; 775} 776 777int audio_device_cancel_authorization(struct audio_device *dev, 778 authorization_cb cb, void *user_data) 779{ 780 struct dev_priv *priv = dev->priv; 781 GSList *l, *next; 782 783 for (l = priv->auths; l != NULL; l = next) { 784 struct service_auth *auth = l->data; 785 786 next = g_slist_next(l); 787 788 if (cb && auth->cb != cb) 789 continue; 790 791 if (user_data && auth->user_data != user_data) 792 continue; 793 794 priv->auths = g_slist_remove(priv->auths, auth); 795 g_free(auth); 796 } 797 798 if (g_slist_length(priv->auths) == 0) { 799 if (priv->auth_idle_id > 0) { 800 g_source_remove(priv->auth_idle_id); 801 priv->auth_idle_id = 0; 802 } else 803 btd_cancel_authorization(&dev->src, &dev->dst); 804 } 805 806 return 0; 807} 808 809void audio_device_set_authorized(struct audio_device *dev, gboolean auth) 810{ 811 struct dev_priv *priv = dev->priv; 812 813 priv->authorized = auth; 814} 815