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@holtmann.org>
7 * Copyright (C) 2009-2010 Motorola Inc.
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 <stdint.h>
30 #include <errno.h>
31
32 #include <bluetooth/bluetooth.h>
33 #include <bluetooth/sdp.h>
34
35 #include <glib.h>
36 #include <dbus/dbus.h>
37 #include <gdbus.h>
38
39 #include "log.h"
40
41 #include "device.h"
42 #include "avdtp.h"
43 #include "media.h"
44 #include "a2dp.h"
45 #include "error.h"
46 #include "sink.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 sink {
60 struct audio_device *dev;
61 struct avdtp *session;
62 struct avdtp_stream *stream;
63 unsigned int cb_id;
64 guint retry_id;
65 avdtp_session_state_t session_state;
66 avdtp_state_t stream_state;
67 sink_state_t state;
68 struct pending_request *connect;
69 struct pending_request *disconnect;
70 DBusConnection *conn;
71 };
72
73 struct sink_state_callback {
74 sink_state_cb cb;
75 void *user_data;
76 unsigned int id;
77 };
78
79 static GSList *sink_callbacks = NULL;
80
81 static unsigned int avdtp_callback_id = 0;
82
83 static char *str_state[] = {
84 "SINK_STATE_DISCONNECTED",
85 "SINK_STATE_CONNECTING",
86 "SINK_STATE_CONNECTED",
87 "SINK_STATE_PLAYING",
88 };
89
state2str(sink_state_t state)90 static const char *state2str(sink_state_t state)
91 {
92 switch (state) {
93 case SINK_STATE_DISCONNECTED:
94 return "disconnected";
95 case SINK_STATE_CONNECTING:
96 return "connecting";
97 case SINK_STATE_CONNECTED:
98 return "connected";
99 case SINK_STATE_PLAYING:
100 return "playing";
101 default:
102 error("Invalid sink state %d", state);
103 return NULL;
104 }
105 }
106
sink_set_state(struct audio_device * dev,sink_state_t new_state)107 static void sink_set_state(struct audio_device *dev, sink_state_t new_state)
108 {
109 struct sink *sink = dev->sink;
110 const char *state_str;
111 sink_state_t old_state = sink->state;
112 GSList *l;
113
114 sink->state = new_state;
115
116 state_str = state2str(new_state);
117 if (state_str)
118 emit_property_changed(dev->conn, dev->path,
119 AUDIO_SINK_INTERFACE, "State",
120 DBUS_TYPE_STRING, &state_str);
121
122 DBG("State changed %s: %s -> %s", dev->path, str_state[old_state],
123 str_state[new_state]);
124
125 for (l = sink_callbacks; l != NULL; l = l->next) {
126 struct sink_state_callback *cb = l->data;
127 cb->cb(dev, old_state, new_state, cb->user_data);
128 }
129 }
130
avdtp_state_callback(struct audio_device * dev,struct avdtp * session,avdtp_session_state_t old_state,avdtp_session_state_t new_state,void * user_data)131 static void avdtp_state_callback(struct audio_device *dev,
132 struct avdtp *session,
133 avdtp_session_state_t old_state,
134 avdtp_session_state_t new_state,
135 void *user_data)
136 {
137 struct sink *sink = dev->sink;
138
139 if (sink == NULL)
140 return;
141
142 switch (new_state) {
143 case AVDTP_SESSION_STATE_DISCONNECTED:
144 if (sink->state != SINK_STATE_CONNECTING) {
145 gboolean value = FALSE;
146 g_dbus_emit_signal(dev->conn, dev->path,
147 AUDIO_SINK_INTERFACE, "Disconnected",
148 DBUS_TYPE_INVALID);
149 emit_property_changed(dev->conn, dev->path,
150 AUDIO_SINK_INTERFACE, "Connected",
151 DBUS_TYPE_BOOLEAN, &value);
152 }
153 sink_set_state(dev, SINK_STATE_DISCONNECTED);
154 break;
155 case AVDTP_SESSION_STATE_CONNECTING:
156 sink_set_state(dev, SINK_STATE_CONNECTING);
157 break;
158 case AVDTP_SESSION_STATE_CONNECTED:
159 break;
160 }
161
162 sink->session_state = new_state;
163 }
164
pending_request_free(struct audio_device * dev,struct pending_request * pending)165 static void pending_request_free(struct audio_device *dev,
166 struct pending_request *pending)
167 {
168 if (pending->conn)
169 dbus_connection_unref(pending->conn);
170 if (pending->msg)
171 dbus_message_unref(pending->msg);
172 if (pending->id)
173 a2dp_cancel(dev, pending->id);
174
175 g_free(pending);
176 }
177
stream_state_changed(struct avdtp_stream * stream,avdtp_state_t old_state,avdtp_state_t new_state,struct avdtp_error * err,void * user_data)178 static void stream_state_changed(struct avdtp_stream *stream,
179 avdtp_state_t old_state,
180 avdtp_state_t new_state,
181 struct avdtp_error *err,
182 void *user_data)
183 {
184 struct audio_device *dev = user_data;
185 struct sink *sink = dev->sink;
186 gboolean value;
187
188 if (err)
189 return;
190
191 switch (new_state) {
192 case AVDTP_STATE_IDLE:
193 if (sink->disconnect) {
194 DBusMessage *reply;
195 struct pending_request *p;
196
197 p = sink->disconnect;
198 sink->disconnect = NULL;
199
200 reply = dbus_message_new_method_return(p->msg);
201 g_dbus_send_message(p->conn, reply);
202 pending_request_free(dev, p);
203 }
204
205 if (sink->session) {
206 avdtp_unref(sink->session);
207 sink->session = NULL;
208 }
209 sink->stream = NULL;
210 sink->cb_id = 0;
211 break;
212 case AVDTP_STATE_OPEN:
213 if (old_state == AVDTP_STATE_CONFIGURED &&
214 sink->state == SINK_STATE_CONNECTING) {
215 value = TRUE;
216 g_dbus_emit_signal(dev->conn, dev->path,
217 AUDIO_SINK_INTERFACE,
218 "Connected",
219 DBUS_TYPE_INVALID);
220 emit_property_changed(dev->conn, dev->path,
221 AUDIO_SINK_INTERFACE,
222 "Connected",
223 DBUS_TYPE_BOOLEAN, &value);
224 } else if (old_state == AVDTP_STATE_STREAMING) {
225 value = FALSE;
226 g_dbus_emit_signal(dev->conn, dev->path,
227 AUDIO_SINK_INTERFACE,
228 "Stopped",
229 DBUS_TYPE_INVALID);
230 emit_property_changed(dev->conn, dev->path,
231 AUDIO_SINK_INTERFACE,
232 "Playing",
233 DBUS_TYPE_BOOLEAN, &value);
234 }
235 sink_set_state(dev, SINK_STATE_CONNECTED);
236 break;
237 case AVDTP_STATE_STREAMING:
238 value = TRUE;
239 g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE,
240 "Playing", DBUS_TYPE_INVALID);
241 emit_property_changed(dev->conn, dev->path,
242 AUDIO_SINK_INTERFACE, "Playing",
243 DBUS_TYPE_BOOLEAN, &value);
244 sink_set_state(dev, SINK_STATE_PLAYING);
245 break;
246 case AVDTP_STATE_CONFIGURED:
247 case AVDTP_STATE_CLOSING:
248 case AVDTP_STATE_ABORTING:
249 default:
250 break;
251 }
252
253 sink->stream_state = new_state;
254 }
255
error_failed(DBusConnection * conn,DBusMessage * msg,const char * desc)256 static void error_failed(DBusConnection *conn, DBusMessage *msg,
257 const char *desc)
258 {
259 DBusMessage *reply = btd_error_failed(msg, desc);
260 g_dbus_send_message(conn, reply);
261 }
262
stream_setup_retry(gpointer user_data)263 static gboolean stream_setup_retry(gpointer user_data)
264 {
265 struct sink *sink = user_data;
266 struct pending_request *pending = sink->connect;
267
268 sink->retry_id = 0;
269
270 if (sink->stream_state >= AVDTP_STATE_OPEN) {
271 DBG("Stream successfully created, after XCASE connect:connect");
272 if (pending->msg) {
273 DBusMessage *reply;
274 reply = dbus_message_new_method_return(pending->msg);
275 g_dbus_send_message(pending->conn, reply);
276 }
277 } else {
278 DBG("Stream setup failed, after XCASE connect:connect");
279 if (pending->msg)
280 error_failed(pending->conn, pending->msg, "Stream setup failed");
281 }
282
283 sink->connect = NULL;
284 pending_request_free(sink->dev, pending);
285
286 return FALSE;
287 }
288
stream_setup_complete(struct avdtp * session,struct a2dp_sep * sep,struct avdtp_stream * stream,struct avdtp_error * err,void * user_data)289 static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
290 struct avdtp_stream *stream,
291 struct avdtp_error *err, void *user_data)
292 {
293 struct sink *sink = user_data;
294 struct pending_request *pending;
295
296 pending = sink->connect;
297
298 pending->id = 0;
299
300 if (stream) {
301 DBG("Stream successfully created");
302
303 if (pending->msg) {
304 DBusMessage *reply;
305 reply = dbus_message_new_method_return(pending->msg);
306 g_dbus_send_message(pending->conn, reply);
307 }
308
309 sink->connect = NULL;
310 pending_request_free(sink->dev, pending);
311
312 return;
313 }
314
315 avdtp_unref(sink->session);
316 sink->session = NULL;
317 if (avdtp_error_category(err) == AVDTP_ERRNO
318 && avdtp_error_posix_errno(err) != EHOSTDOWN) {
319 DBG("connect:connect XCASE detected");
320 sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
321 stream_setup_retry,
322 sink);
323 } else {
324 if (pending->msg)
325 error_failed(pending->conn, pending->msg, "Stream setup failed");
326 sink->connect = NULL;
327 pending_request_free(sink->dev, pending);
328 DBG("Stream setup failed : %s", avdtp_strerror(err));
329 }
330 }
331
select_complete(struct avdtp * session,struct a2dp_sep * sep,GSList * caps,void * user_data)332 static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
333 GSList *caps, void *user_data)
334 {
335 struct sink *sink = user_data;
336 struct pending_request *pending;
337 int id;
338
339 pending = sink->connect;
340 pending->id = 0;
341
342 id = a2dp_config(session, sep, stream_setup_complete, caps, sink);
343 if (id == 0)
344 goto failed;
345
346 pending->id = id;
347 return;
348
349 failed:
350 if (pending->msg)
351 error_failed(pending->conn, pending->msg, "Stream setup failed");
352 pending_request_free(sink->dev, pending);
353 sink->connect = NULL;
354 avdtp_unref(sink->session);
355 sink->session = NULL;
356 }
357
discovery_complete(struct avdtp * session,GSList * seps,struct avdtp_error * err,void * user_data)358 static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
359 void *user_data)
360 {
361 struct sink *sink = user_data;
362 struct pending_request *pending;
363 int id;
364
365 if (!sink->connect) {
366 avdtp_unref(sink->session);
367 sink->session = NULL;
368 return;
369 }
370
371 pending = sink->connect;
372
373 if (err) {
374 avdtp_unref(sink->session);
375 sink->session = NULL;
376 if (avdtp_error_category(err) == AVDTP_ERRNO
377 && avdtp_error_posix_errno(err) != EHOSTDOWN) {
378 DBG("connect:connect XCASE detected");
379 sink->retry_id =
380 g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
381 stream_setup_retry,
382 sink);
383 } else
384 goto failed;
385 return;
386 }
387
388 DBG("Discovery complete");
389
390 id = a2dp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL,
391 select_complete, sink);
392 if (id == 0)
393 goto failed;
394
395 pending->id = id;
396 return;
397
398 failed:
399 if (pending->msg)
400 error_failed(pending->conn, pending->msg, "Stream setup failed");
401 pending_request_free(sink->dev, pending);
402 sink->connect = NULL;
403 avdtp_unref(sink->session);
404 sink->session = NULL;
405 }
406
sink_setup_stream(struct sink * sink,struct avdtp * session)407 gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
408 {
409 if (sink->connect || sink->disconnect)
410 return FALSE;
411
412 if (session && !sink->session)
413 sink->session = avdtp_ref(session);
414
415 if (!sink->session)
416 return FALSE;
417
418 avdtp_set_auto_disconnect(sink->session, FALSE);
419
420 if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
421 return FALSE;
422
423 sink->connect = g_new0(struct pending_request, 1);
424
425 return TRUE;
426 }
427
sink_connect(DBusConnection * conn,DBusMessage * msg,void * data)428 static DBusMessage *sink_connect(DBusConnection *conn,
429 DBusMessage *msg, void *data)
430 {
431 struct audio_device *dev = data;
432 struct sink *sink = dev->sink;
433 struct pending_request *pending;
434
435 if (!sink->session)
436 sink->session = avdtp_get(&dev->src, &dev->dst);
437
438 if (!sink->session)
439 return btd_error_failed(msg, "Unable to get a session");
440
441 if (sink->connect || sink->disconnect)
442 return btd_error_busy(msg);
443
444 if (sink->stream_state >= AVDTP_STATE_OPEN)
445 return btd_error_already_connected(msg);
446
447 if (!sink_setup_stream(sink, NULL))
448 return btd_error_failed(msg, "Failed to create a stream");
449
450 dev->auto_connect = FALSE;
451
452 pending = sink->connect;
453
454 pending->conn = dbus_connection_ref(conn);
455 pending->msg = dbus_message_ref(msg);
456
457 DBG("stream creation in progress");
458
459 return NULL;
460 }
461
sink_disconnect(DBusConnection * conn,DBusMessage * msg,void * data)462 static DBusMessage *sink_disconnect(DBusConnection *conn,
463 DBusMessage *msg, void *data)
464 {
465 struct audio_device *device = data;
466 struct sink *sink = device->sink;
467 struct pending_request *pending;
468 int err;
469
470 if (!sink->session)
471 return btd_error_not_connected(msg);
472
473 if (sink->connect || sink->disconnect)
474 return btd_error_busy(msg);
475
476 if (sink->stream_state < AVDTP_STATE_OPEN) {
477 DBusMessage *reply = dbus_message_new_method_return(msg);
478 if (!reply)
479 return NULL;
480 avdtp_unref(sink->session);
481 sink->session = NULL;
482 return reply;
483 }
484
485 err = avdtp_close(sink->session, sink->stream, FALSE);
486 if (err < 0)
487 return btd_error_failed(msg, strerror(-err));
488
489 pending = g_new0(struct pending_request, 1);
490 pending->conn = dbus_connection_ref(conn);
491 pending->msg = dbus_message_ref(msg);
492 sink->disconnect = pending;
493
494 return NULL;
495 }
496
sink_suspend(DBusConnection * conn,DBusMessage * msg,void * data)497 static DBusMessage *sink_suspend(DBusConnection *conn,
498 DBusMessage *msg, void *data)
499 {
500 struct audio_device *device = data;
501 struct sink *sink = device->sink;
502 struct pending_request *pending;
503 int err;
504
505 if (!sink->session)
506 return g_dbus_create_error(msg, ERROR_INTERFACE
507 ".NotConnected",
508 "Device not Connected");
509
510 if (sink->connect || sink->disconnect)
511 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
512 "%s", strerror(EBUSY));
513
514 if (sink->state < AVDTP_STATE_OPEN) {
515 DBusMessage *reply = dbus_message_new_method_return(msg);
516 if (!reply)
517 return NULL;
518 avdtp_unref(sink->session);
519 sink->session = NULL;
520 return reply;
521 }
522
523 err = avdtp_suspend(sink->session, sink->stream);
524 if (err < 0)
525 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
526 "%s", strerror(-err));
527
528 return NULL;
529 }
530
sink_resume(DBusConnection * conn,DBusMessage * msg,void * data)531 static DBusMessage *sink_resume(DBusConnection *conn,
532 DBusMessage *msg, void *data)
533 {
534 struct audio_device *device = data;
535 struct sink *sink = device->sink;
536 struct pending_request *pending;
537 int err;
538
539 if (!sink->session)
540 return g_dbus_create_error(msg, ERROR_INTERFACE
541 ".NotConnected",
542 "Device not Connected");
543
544 if (sink->connect || sink->disconnect)
545 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
546 "%s", strerror(EBUSY));
547
548 if (sink->state < AVDTP_STATE_OPEN) {
549 DBusMessage *reply = dbus_message_new_method_return(msg);
550 if (!reply)
551 return NULL;
552 avdtp_unref(sink->session);
553 sink->session = NULL;
554 return reply;
555 }
556
557 err = avdtp_start(sink->session, sink->stream);
558 if (err < 0)
559 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
560 "%s", strerror(-err));
561
562 return NULL;
563 }
564
sink_is_connected(DBusConnection * conn,DBusMessage * msg,void * data)565 static DBusMessage *sink_is_connected(DBusConnection *conn,
566 DBusMessage *msg,
567 void *data)
568 {
569 struct audio_device *device = data;
570 struct sink *sink = device->sink;
571 DBusMessage *reply;
572 dbus_bool_t connected;
573
574 reply = dbus_message_new_method_return(msg);
575 if (!reply)
576 return NULL;
577
578 connected = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
579
580 dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
581 DBUS_TYPE_INVALID);
582
583 return reply;
584 }
585
sink_get_properties(DBusConnection * conn,DBusMessage * msg,void * data)586 static DBusMessage *sink_get_properties(DBusConnection *conn,
587 DBusMessage *msg, void *data)
588 {
589 struct audio_device *device = data;
590 struct sink *sink = device->sink;
591 DBusMessage *reply;
592 DBusMessageIter iter;
593 DBusMessageIter dict;
594 const char *state;
595 gboolean value;
596
597 reply = dbus_message_new_method_return(msg);
598 if (!reply)
599 return NULL;
600
601 dbus_message_iter_init_append(reply, &iter);
602
603 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
604 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
605 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
606 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
607
608 /* Playing */
609 value = (sink->stream_state == AVDTP_STATE_STREAMING);
610 dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value);
611
612 /* Connected */
613 value = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
614 dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
615
616 /* State */
617 state = state2str(sink->state);
618 if (state)
619 dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
620
621 dbus_message_iter_close_container(&iter, &dict);
622
623 return reply;
624 }
625
626 static GDBusMethodTable sink_methods[] = {
627 { "Connect", "", "", sink_connect,
628 G_DBUS_METHOD_FLAG_ASYNC },
629 { "Disconnect", "", "", sink_disconnect,
630 G_DBUS_METHOD_FLAG_ASYNC },
631 { "Suspend", "", "", sink_suspend,
632 G_DBUS_METHOD_FLAG_ASYNC },
633 { "Resume", "", "", sink_resume,
634 G_DBUS_METHOD_FLAG_ASYNC },
635 { "IsConnected", "", "b", sink_is_connected,
636 G_DBUS_METHOD_FLAG_DEPRECATED },
637 { "GetProperties", "", "a{sv}",sink_get_properties },
638 { NULL, NULL, NULL, NULL }
639 };
640
641 static GDBusSignalTable sink_signals[] = {
642 { "Connected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
643 { "Disconnected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
644 { "Playing", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
645 { "Stopped", "", G_DBUS_SIGNAL_FLAG_DEPRECATED },
646 { "PropertyChanged", "sv" },
647 { NULL, NULL }
648 };
649
sink_free(struct audio_device * dev)650 static void sink_free(struct audio_device *dev)
651 {
652 struct sink *sink = dev->sink;
653
654 if (sink->cb_id)
655 avdtp_stream_remove_cb(sink->session, sink->stream,
656 sink->cb_id);
657
658 if (sink->session)
659 avdtp_unref(sink->session);
660
661 if (sink->connect)
662 pending_request_free(dev, sink->connect);
663
664 if (sink->disconnect)
665 pending_request_free(dev, sink->disconnect);
666
667 if (sink->retry_id)
668 g_source_remove(sink->retry_id);
669
670 g_free(sink);
671 dev->sink = NULL;
672 }
673
path_unregister(void * data)674 static void path_unregister(void *data)
675 {
676 struct audio_device *dev = data;
677
678 DBG("Unregistered interface %s on path %s",
679 AUDIO_SINK_INTERFACE, dev->path);
680
681 sink_free(dev);
682 }
683
sink_unregister(struct audio_device * dev)684 void sink_unregister(struct audio_device *dev)
685 {
686 g_dbus_unregister_interface(dev->conn, dev->path,
687 AUDIO_SINK_INTERFACE);
688 }
689
sink_init(struct audio_device * dev)690 struct sink *sink_init(struct audio_device *dev)
691 {
692 struct sink *sink;
693
694 if (!g_dbus_register_interface(dev->conn, dev->path,
695 AUDIO_SINK_INTERFACE,
696 sink_methods, sink_signals, NULL,
697 dev, path_unregister))
698 return NULL;
699
700 DBG("Registered interface %s on path %s",
701 AUDIO_SINK_INTERFACE, dev->path);
702
703 if (avdtp_callback_id == 0)
704 avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
705 NULL);
706
707 sink = g_new0(struct sink, 1);
708
709 sink->dev = dev;
710
711 return sink;
712 }
713
sink_is_active(struct audio_device * dev)714 gboolean sink_is_active(struct audio_device *dev)
715 {
716 struct sink *sink = dev->sink;
717
718 if (sink->session)
719 return TRUE;
720
721 return FALSE;
722 }
723
sink_get_state(struct audio_device * dev)724 avdtp_state_t sink_get_state(struct audio_device *dev)
725 {
726 struct sink *sink = dev->sink;
727
728 return sink->stream_state;
729 }
730
sink_new_stream(struct audio_device * dev,struct avdtp * session,struct avdtp_stream * stream)731 gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
732 struct avdtp_stream *stream)
733 {
734 struct sink *sink = dev->sink;
735
736 if (sink->stream)
737 return FALSE;
738
739 if (!sink->session)
740 sink->session = avdtp_ref(session);
741
742 sink->stream = stream;
743
744 sink->cb_id = avdtp_stream_add_cb(session, stream,
745 stream_state_changed, dev);
746
747 return TRUE;
748 }
749
sink_shutdown(struct sink * sink)750 gboolean sink_shutdown(struct sink *sink)
751 {
752 if (!sink->session)
753 return FALSE;
754
755 avdtp_set_device_disconnect(sink->session, TRUE);
756
757 /* cancel pending connect */
758 if (sink->connect) {
759 struct pending_request *pending = sink->connect;
760
761 if (pending->msg)
762 error_failed(pending->conn, pending->msg,
763 "Stream setup failed");
764 pending_request_free(sink->dev, pending);
765 sink->connect = NULL;
766
767 avdtp_unref(sink->session);
768 sink->session = NULL;
769
770 return TRUE;
771 }
772
773 /* disconnect already ongoing */
774 if (sink->disconnect)
775 return TRUE;
776
777 if (!sink->stream)
778 return FALSE;
779
780 if (avdtp_close(sink->session, sink->stream, FALSE) < 0)
781 return FALSE;
782
783 return TRUE;
784 }
785
sink_add_state_cb(sink_state_cb cb,void * user_data)786 unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data)
787 {
788 struct sink_state_callback *state_cb;
789 static unsigned int id = 0;
790
791 state_cb = g_new(struct sink_state_callback, 1);
792 state_cb->cb = cb;
793 state_cb->user_data = user_data;
794 state_cb->id = ++id;
795
796 sink_callbacks = g_slist_append(sink_callbacks, state_cb);
797
798 return state_cb->id;
799 }
800
sink_remove_state_cb(unsigned int id)801 gboolean sink_remove_state_cb(unsigned int id)
802 {
803 GSList *l;
804
805 for (l = sink_callbacks; l != NULL; l = l->next) {
806 struct sink_state_callback *cb = l->data;
807 if (cb && cb->id == id) {
808 sink_callbacks = g_slist_remove(sink_callbacks, cb);
809 g_free(cb);
810 return TRUE;
811 }
812 }
813
814 return FALSE;
815 }
816