• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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