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 (at) holtmann.org> 7 * Copyright (C) 2009 Joao Paulo Rechi Vita 8 * 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 */ 25 26 #ifdef HAVE_CONFIG_H 27 #include <config.h> 28 #endif 29 30 #include <stdint.h> 31 #include <errno.h> 32 33 #include <bluetooth/bluetooth.h> 34 #include <bluetooth/sdp.h> 35 36 #include <glib.h> 37 #include <dbus/dbus.h> 38 #include <gdbus.h> 39 40 #include "log.h" 41 42 #include "device.h" 43 #include "avdtp.h" 44 #include "a2dp.h" 45 #include "error.h" 46 #include "source.h" 47 #include "dbus-common.h" 48 #include "../src/adapter.h" 49 #include "../src/device.h" 50 51 #define STREAM_SETUP_RETRY_TIMER 2 52 53 struct pending_request { 54 DBusConnection *conn; 55 DBusMessage *msg; 56 unsigned int id; 57 }; 58 59 struct source { 60 struct audio_device *dev; 61 struct avdtp *session; 62 struct avdtp_stream *stream; 63 unsigned int cb_id; 64 guint dc_id; 65 guint retry_id; 66 avdtp_session_state_t session_state; 67 avdtp_state_t stream_state; 68 source_state_t state; 69 struct pending_request *connect; 70 struct pending_request *disconnect; 71 DBusConnection *conn; 72 }; 73 74 struct source_state_callback { 75 source_state_cb cb; 76 void *user_data; 77 unsigned int id; 78 }; 79 80 static GSList *source_callbacks = NULL; 81 82 static unsigned int avdtp_callback_id = 0; 83 84 static const char *state2str(source_state_t state) 85 { 86 switch (state) { 87 case SOURCE_STATE_DISCONNECTED: 88 return "disconnected"; 89 case SOURCE_STATE_CONNECTING: 90 return "connecting"; 91 case SOURCE_STATE_CONNECTED: 92 return "connected"; 93 case SOURCE_STATE_PLAYING: 94 return "playing"; 95 default: 96 error("Invalid source state %d", state); 97 return NULL; 98 } 99 } 100 101 static void source_set_state(struct audio_device *dev, source_state_t new_state) 102 { 103 struct source *source = dev->source; 104 const char *state_str; 105 source_state_t old_state = source->state; 106 GSList *l; 107 108 source->state = new_state; 109 110 state_str = state2str(new_state); 111 if (state_str) 112 emit_property_changed(dev->conn, dev->path, 113 AUDIO_SOURCE_INTERFACE, "State", 114 DBUS_TYPE_STRING, &state_str); 115 116 for (l = source_callbacks; l != NULL; l = l->next) { 117 struct source_state_callback *cb = l->data; 118 cb->cb(dev, old_state, new_state, cb->user_data); 119 } 120 } 121 122 static void avdtp_state_callback(struct audio_device *dev, 123 struct avdtp *session, 124 avdtp_session_state_t old_state, 125 avdtp_session_state_t new_state, 126 void *user_data) 127 { 128 struct source *source = dev->source; 129 130 if (source == NULL) 131 return; 132 133 switch (new_state) { 134 case AVDTP_SESSION_STATE_DISCONNECTED: 135 if (source->state != SOURCE_STATE_CONNECTING && 136 source->dc_id) { 137 device_remove_disconnect_watch(dev->btd_dev, 138 source->dc_id); 139 source->dc_id = 0; 140 } 141 source_set_state(dev, SOURCE_STATE_DISCONNECTED); 142 break; 143 case AVDTP_SESSION_STATE_CONNECTING: 144 source_set_state(dev, SOURCE_STATE_CONNECTING); 145 break; 146 case AVDTP_SESSION_STATE_CONNECTED: 147 break; 148 } 149 150 source->session_state = new_state; 151 } 152 153 static void pending_request_free(struct audio_device *dev, 154 struct pending_request *pending) 155 { 156 if (pending->conn) 157 dbus_connection_unref(pending->conn); 158 if (pending->msg) 159 dbus_message_unref(pending->msg); 160 if (pending->id) 161 a2dp_cancel(dev, pending->id); 162 163 g_free(pending); 164 } 165 166 static void disconnect_cb(struct btd_device *btd_dev, gboolean removal, 167 void *user_data) 168 { 169 struct audio_device *device = user_data; 170 struct source *source = device->source; 171 172 DBG("Source: disconnect %s", device->path); 173 174 avdtp_close(source->session, source->stream, TRUE); 175 } 176 177 static void stream_state_changed(struct avdtp_stream *stream, 178 avdtp_state_t old_state, 179 avdtp_state_t new_state, 180 struct avdtp_error *err, 181 void *user_data) 182 { 183 struct audio_device *dev = user_data; 184 struct source *source = dev->source; 185 186 if (err) 187 return; 188 189 switch (new_state) { 190 case AVDTP_STATE_IDLE: 191 if (source->disconnect) { 192 DBusMessage *reply; 193 struct pending_request *p; 194 195 p = source->disconnect; 196 source->disconnect = NULL; 197 198 reply = dbus_message_new_method_return(p->msg); 199 g_dbus_send_message(p->conn, reply); 200 pending_request_free(dev, p); 201 } 202 203 if (source->dc_id) { 204 device_remove_disconnect_watch(dev->btd_dev, 205 source->dc_id); 206 source->dc_id = 0; 207 } 208 209 if (source->session) { 210 avdtp_unref(source->session); 211 source->session = NULL; 212 } 213 source->stream = NULL; 214 source->cb_id = 0; 215 break; 216 case AVDTP_STATE_OPEN: 217 if (old_state == AVDTP_STATE_CONFIGURED && 218 source->state == SOURCE_STATE_CONNECTING) { 219 source->dc_id = device_add_disconnect_watch(dev->btd_dev, 220 disconnect_cb, 221 dev, NULL); 222 } 223 source_set_state(dev, SOURCE_STATE_CONNECTED); 224 break; 225 case AVDTP_STATE_STREAMING: 226 source_set_state(dev, SOURCE_STATE_PLAYING); 227 break; 228 case AVDTP_STATE_CONFIGURED: 229 case AVDTP_STATE_CLOSING: 230 case AVDTP_STATE_ABORTING: 231 default: 232 break; 233 } 234 235 source->stream_state = new_state; 236 } 237 238 static DBusHandlerResult error_failed(DBusConnection *conn, 239 DBusMessage *msg, const char * desc) 240 { 241 return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc); 242 } 243 244 static gboolean stream_setup_retry(gpointer user_data) 245 { 246 struct source *source = user_data; 247 struct pending_request *pending = source->connect; 248 249 source->retry_id = 0; 250 251 if (source->stream_state >= AVDTP_STATE_OPEN) { 252 DBG("Stream successfully created, after XCASE connect:connect"); 253 if (pending->msg) { 254 DBusMessage *reply; 255 reply = dbus_message_new_method_return(pending->msg); 256 g_dbus_send_message(pending->conn, reply); 257 } 258 } else { 259 DBG("Stream setup failed, after XCASE connect:connect"); 260 if (pending->msg) 261 error_failed(pending->conn, pending->msg, "Stream setup failed"); 262 } 263 264 source->connect = NULL; 265 pending_request_free(source->dev, pending); 266 267 return FALSE; 268 } 269 270 static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep, 271 struct avdtp_stream *stream, 272 struct avdtp_error *err, void *user_data) 273 { 274 struct source *source = user_data; 275 struct pending_request *pending; 276 277 pending = source->connect; 278 279 pending->id = 0; 280 281 if (stream) { 282 DBG("Stream successfully created"); 283 284 if (pending->msg) { 285 DBusMessage *reply; 286 reply = dbus_message_new_method_return(pending->msg); 287 g_dbus_send_message(pending->conn, reply); 288 } 289 290 source->connect = NULL; 291 pending_request_free(source->dev, pending); 292 293 return; 294 } 295 296 avdtp_unref(source->session); 297 source->session = NULL; 298 if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO 299 && avdtp_error_posix_errno(err) != EHOSTDOWN) { 300 DBG("connect:connect XCASE detected"); 301 source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, 302 stream_setup_retry, 303 source); 304 } else { 305 if (pending->msg) 306 error_failed(pending->conn, pending->msg, "Stream setup failed"); 307 source->connect = NULL; 308 pending_request_free(source->dev, pending); 309 DBG("Stream setup failed : %s", avdtp_strerror(err)); 310 } 311 } 312 313 static uint8_t default_bitpool(uint8_t freq, uint8_t mode) 314 { 315 switch (freq) { 316 case SBC_SAMPLING_FREQ_16000: 317 case SBC_SAMPLING_FREQ_32000: 318 return 53; 319 case SBC_SAMPLING_FREQ_44100: 320 switch (mode) { 321 case SBC_CHANNEL_MODE_MONO: 322 case SBC_CHANNEL_MODE_DUAL_CHANNEL: 323 return 31; 324 case SBC_CHANNEL_MODE_STEREO: 325 case SBC_CHANNEL_MODE_JOINT_STEREO: 326 return 53; 327 default: 328 error("Invalid channel mode %u", mode); 329 return 53; 330 } 331 case SBC_SAMPLING_FREQ_48000: 332 switch (mode) { 333 case SBC_CHANNEL_MODE_MONO: 334 case SBC_CHANNEL_MODE_DUAL_CHANNEL: 335 return 29; 336 case SBC_CHANNEL_MODE_STEREO: 337 case SBC_CHANNEL_MODE_JOINT_STEREO: 338 return 51; 339 default: 340 error("Invalid channel mode %u", mode); 341 return 51; 342 } 343 default: 344 error("Invalid sampling freq %u", freq); 345 return 53; 346 } 347 } 348 349 static gboolean select_sbc_params(struct sbc_codec_cap *cap, 350 struct sbc_codec_cap *supported) 351 { 352 unsigned int max_bitpool, min_bitpool; 353 354 memset(cap, 0, sizeof(struct sbc_codec_cap)); 355 356 cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; 357 cap->cap.media_codec_type = A2DP_CODEC_SBC; 358 359 if (supported->frequency & SBC_SAMPLING_FREQ_44100) 360 cap->frequency = SBC_SAMPLING_FREQ_44100; 361 else if (supported->frequency & SBC_SAMPLING_FREQ_48000) 362 cap->frequency = SBC_SAMPLING_FREQ_48000; 363 else if (supported->frequency & SBC_SAMPLING_FREQ_32000) 364 cap->frequency = SBC_SAMPLING_FREQ_32000; 365 else if (supported->frequency & SBC_SAMPLING_FREQ_16000) 366 cap->frequency = SBC_SAMPLING_FREQ_16000; 367 else { 368 error("No supported frequencies"); 369 return FALSE; 370 } 371 372 if (supported->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) 373 cap->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO; 374 else if (supported->channel_mode & SBC_CHANNEL_MODE_STEREO) 375 cap->channel_mode = SBC_CHANNEL_MODE_STEREO; 376 else if (supported->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) 377 cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; 378 else if (supported->channel_mode & SBC_CHANNEL_MODE_MONO) 379 cap->channel_mode = SBC_CHANNEL_MODE_MONO; 380 else { 381 error("No supported channel modes"); 382 return FALSE; 383 } 384 385 if (supported->block_length & SBC_BLOCK_LENGTH_16) 386 cap->block_length = SBC_BLOCK_LENGTH_16; 387 else if (supported->block_length & SBC_BLOCK_LENGTH_12) 388 cap->block_length = SBC_BLOCK_LENGTH_12; 389 else if (supported->block_length & SBC_BLOCK_LENGTH_8) 390 cap->block_length = SBC_BLOCK_LENGTH_8; 391 else if (supported->block_length & SBC_BLOCK_LENGTH_4) 392 cap->block_length = SBC_BLOCK_LENGTH_4; 393 else { 394 error("No supported block lengths"); 395 return FALSE; 396 } 397 398 if (supported->subbands & SBC_SUBBANDS_8) 399 cap->subbands = SBC_SUBBANDS_8; 400 else if (supported->subbands & SBC_SUBBANDS_4) 401 cap->subbands = SBC_SUBBANDS_4; 402 else { 403 error("No supported subbands"); 404 return FALSE; 405 } 406 407 if (supported->allocation_method & SBC_ALLOCATION_LOUDNESS) 408 cap->allocation_method = SBC_ALLOCATION_LOUDNESS; 409 else if (supported->allocation_method & SBC_ALLOCATION_SNR) 410 cap->allocation_method = SBC_ALLOCATION_SNR; 411 412 min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool); 413 max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode), 414 supported->max_bitpool); 415 416 cap->min_bitpool = min_bitpool; 417 cap->max_bitpool = max_bitpool; 418 419 return TRUE; 420 } 421 422 static gboolean select_capabilities(struct avdtp *session, 423 struct avdtp_remote_sep *rsep, 424 GSList **caps) 425 { 426 struct avdtp_service_capability *media_transport, *media_codec; 427 struct sbc_codec_cap sbc_cap; 428 429 media_codec = avdtp_get_codec(rsep); 430 if (!media_codec) 431 return FALSE; 432 433 select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data); 434 435 media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, 436 NULL, 0); 437 438 *caps = g_slist_append(*caps, media_transport); 439 440 media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap, 441 sizeof(sbc_cap)); 442 443 *caps = g_slist_append(*caps, media_codec); 444 445 446 return TRUE; 447 } 448 449 static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, 450 void *user_data) 451 { 452 struct source *source = user_data; 453 struct pending_request *pending; 454 struct avdtp_local_sep *lsep; 455 struct avdtp_remote_sep *rsep; 456 struct a2dp_sep *sep; 457 GSList *caps = NULL; 458 int id; 459 460 pending = source->connect; 461 462 if (err) { 463 avdtp_unref(source->session); 464 source->session = NULL; 465 if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO 466 && avdtp_error_posix_errno(err) != EHOSTDOWN) { 467 DBG("connect:connect XCASE detected"); 468 source->retry_id = 469 g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, 470 stream_setup_retry, 471 source); 472 } else 473 goto failed; 474 return; 475 } 476 477 DBG("Discovery complete"); 478 479 if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO, 480 A2DP_CODEC_SBC, &lsep, &rsep) < 0) { 481 error("No matching ACP and INT SEPs found"); 482 goto failed; 483 } 484 485 if (!select_capabilities(session, rsep, &caps)) { 486 error("Unable to select remote SEP capabilities"); 487 goto failed; 488 } 489 490 sep = a2dp_get(session, rsep); 491 if (!sep) { 492 error("Unable to get a local sink SEP"); 493 goto failed; 494 } 495 496 id = a2dp_config(source->session, sep, stream_setup_complete, caps, 497 source); 498 if (id == 0) 499 goto failed; 500 501 pending->id = id; 502 return; 503 504 failed: 505 if (pending->msg) 506 error_failed(pending->conn, pending->msg, "Stream setup failed"); 507 pending_request_free(source->dev, pending); 508 source->connect = NULL; 509 avdtp_unref(source->session); 510 source->session = NULL; 511 } 512 513 gboolean source_setup_stream(struct source *source, struct avdtp *session) 514 { 515 if (source->connect || source->disconnect) 516 return FALSE; 517 518 if (session && !source->session) 519 source->session = avdtp_ref(session); 520 521 if (!source->session) 522 return FALSE; 523 524 avdtp_set_auto_disconnect(source->session, FALSE); 525 526 if (avdtp_discover(source->session, discovery_complete, source) < 0) 527 return FALSE; 528 529 source->connect = g_new0(struct pending_request, 1); 530 531 return TRUE; 532 } 533 534 static DBusMessage *source_connect(DBusConnection *conn, 535 DBusMessage *msg, void *data) 536 { 537 struct audio_device *dev = data; 538 struct source *source = dev->source; 539 struct pending_request *pending; 540 541 if (!source->session) 542 source->session = avdtp_get(&dev->src, &dev->dst); 543 544 if (!source->session) 545 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 546 "Unable to get a session"); 547 548 if (source->connect || source->disconnect) 549 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 550 "%s", strerror(EBUSY)); 551 552 if (source->stream_state >= AVDTP_STATE_OPEN) 553 return g_dbus_create_error(msg, ERROR_INTERFACE 554 ".AlreadyConnected", 555 "Device Already Connected"); 556 557 if (!source_setup_stream(source, NULL)) 558 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 559 "Failed to create a stream"); 560 561 dev->auto_connect = FALSE; 562 563 pending = source->connect; 564 565 pending->conn = dbus_connection_ref(conn); 566 pending->msg = dbus_message_ref(msg); 567 568 DBG("stream creation in progress"); 569 570 return NULL; 571 } 572 573 static DBusMessage *source_disconnect(DBusConnection *conn, 574 DBusMessage *msg, void *data) 575 { 576 struct audio_device *device = data; 577 struct source *source = device->source; 578 struct pending_request *pending; 579 int err; 580 581 if (!source->session) 582 return g_dbus_create_error(msg, ERROR_INTERFACE 583 ".NotConnected", 584 "Device not Connected"); 585 586 if (source->connect || source->disconnect) 587 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 588 "%s", strerror(EBUSY)); 589 590 if (source->stream_state < AVDTP_STATE_OPEN) { 591 DBusMessage *reply = dbus_message_new_method_return(msg); 592 if (!reply) 593 return NULL; 594 avdtp_unref(source->session); 595 source->session = NULL; 596 return reply; 597 } 598 599 err = avdtp_close(source->session, source->stream, FALSE); 600 if (err < 0) 601 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 602 "%s", strerror(-err)); 603 604 pending = g_new0(struct pending_request, 1); 605 pending->conn = dbus_connection_ref(conn); 606 pending->msg = dbus_message_ref(msg); 607 source->disconnect = pending; 608 609 return NULL; 610 } 611 612 static DBusMessage *source_get_properties(DBusConnection *conn, 613 DBusMessage *msg, void *data) 614 { 615 struct audio_device *device = data; 616 struct source *source = device->source; 617 DBusMessage *reply; 618 DBusMessageIter iter; 619 DBusMessageIter dict; 620 const char *state; 621 622 reply = dbus_message_new_method_return(msg); 623 if (!reply) 624 return NULL; 625 626 dbus_message_iter_init_append(reply, &iter); 627 628 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 629 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 630 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 631 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 632 633 /* State */ 634 state = state2str(source->state); 635 if (state) 636 dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); 637 638 dbus_message_iter_close_container(&iter, &dict); 639 640 return reply; 641 } 642 643 static GDBusMethodTable source_methods[] = { 644 { "Connect", "", "", source_connect, 645 G_DBUS_METHOD_FLAG_ASYNC }, 646 { "Disconnect", "", "", source_disconnect, 647 G_DBUS_METHOD_FLAG_ASYNC }, 648 { "GetProperties", "", "a{sv}",source_get_properties }, 649 { NULL, NULL, NULL, NULL } 650 }; 651 652 static GDBusSignalTable source_signals[] = { 653 { "PropertyChanged", "sv" }, 654 { NULL, NULL } 655 }; 656 657 static void source_free(struct audio_device *dev) 658 { 659 struct source *source = dev->source; 660 661 if (source->cb_id) 662 avdtp_stream_remove_cb(source->session, source->stream, 663 source->cb_id); 664 665 if (source->dc_id) 666 device_remove_disconnect_watch(dev->btd_dev, source->dc_id); 667 668 if (source->session) 669 avdtp_unref(source->session); 670 671 if (source->connect) 672 pending_request_free(dev, source->connect); 673 674 if (source->disconnect) 675 pending_request_free(dev, source->disconnect); 676 677 if (source->retry_id) 678 g_source_remove(source->retry_id); 679 680 g_free(source); 681 dev->source = NULL; 682 } 683 684 static void path_unregister(void *data) 685 { 686 struct audio_device *dev = data; 687 688 DBG("Unregistered interface %s on path %s", 689 AUDIO_SOURCE_INTERFACE, dev->path); 690 691 source_free(dev); 692 } 693 694 void source_unregister(struct audio_device *dev) 695 { 696 g_dbus_unregister_interface(dev->conn, dev->path, 697 AUDIO_SOURCE_INTERFACE); 698 } 699 700 struct source *source_init(struct audio_device *dev) 701 { 702 struct source *source; 703 704 if (!g_dbus_register_interface(dev->conn, dev->path, 705 AUDIO_SOURCE_INTERFACE, 706 source_methods, source_signals, NULL, 707 dev, path_unregister)) 708 return NULL; 709 710 DBG("Registered interface %s on path %s", 711 AUDIO_SOURCE_INTERFACE, dev->path); 712 713 if (avdtp_callback_id == 0) 714 avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback, 715 NULL); 716 717 source = g_new0(struct source, 1); 718 719 source->dev = dev; 720 721 return source; 722 } 723 724 gboolean source_is_active(struct audio_device *dev) 725 { 726 struct source *source = dev->source; 727 728 if (source->session) 729 return TRUE; 730 731 return FALSE; 732 } 733 734 avdtp_state_t source_get_state(struct audio_device *dev) 735 { 736 struct source *source = dev->source; 737 738 return source->stream_state; 739 } 740 741 gboolean source_new_stream(struct audio_device *dev, struct avdtp *session, 742 struct avdtp_stream *stream) 743 { 744 struct source *source = dev->source; 745 746 if (source->stream) 747 return FALSE; 748 749 if (!source->session) 750 source->session = avdtp_ref(session); 751 752 source->stream = stream; 753 754 source->cb_id = avdtp_stream_add_cb(session, stream, 755 stream_state_changed, dev); 756 757 return TRUE; 758 } 759 760 gboolean source_shutdown(struct source *source) 761 { 762 if (!source->stream) 763 return FALSE; 764 765 if (avdtp_close(source->session, source->stream, FALSE) < 0) 766 return FALSE; 767 768 return TRUE; 769 } 770 771 unsigned int source_add_state_cb(source_state_cb cb, void *user_data) 772 { 773 struct source_state_callback *state_cb; 774 static unsigned int id = 0; 775 776 state_cb = g_new(struct source_state_callback, 1); 777 state_cb->cb = cb; 778 state_cb->user_data = user_data; 779 state_cb->id = ++id; 780 781 source_callbacks = g_slist_append(source_callbacks, state_cb); 782 783 return state_cb->id; 784 } 785 786 gboolean source_remove_state_cb(unsigned int id) 787 { 788 GSList *l; 789 790 for (l = source_callbacks; l != NULL; l = l->next) { 791 struct source_state_callback *cb = l->data; 792 if (cb && cb->id == id) { 793 source_callbacks = g_slist_remove(source_callbacks, cb); 794 g_free(cb); 795 return TRUE; 796 } 797 } 798 799 return FALSE; 800 } 801