• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *  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 "media.h"
45 #include "a2dp.h"
46 #include "error.h"
47 #include "source.h"
48 #include "dbus-common.h"
49 #include "../src/adapter.h"
50 #include "../src/device.h"
51 
52 #define STREAM_SETUP_RETRY_TIMER 2
53 
54 struct pending_request {
55 	DBusConnection *conn;
56 	DBusMessage *msg;
57 	unsigned int id;
58 };
59 
60 struct source {
61 	struct audio_device *dev;
62 	struct avdtp *session;
63 	struct avdtp_stream *stream;
64 	unsigned int cb_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 
state2str(source_state_t state)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 
source_set_state(struct audio_device * dev,source_state_t new_state)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 
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)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 		source_set_state(dev, SOURCE_STATE_DISCONNECTED);
136 		break;
137 	case AVDTP_SESSION_STATE_CONNECTING:
138 		source_set_state(dev, SOURCE_STATE_CONNECTING);
139 		break;
140 	case AVDTP_SESSION_STATE_CONNECTED:
141 		break;
142 	}
143 
144 	source->session_state = new_state;
145 }
146 
pending_request_free(struct audio_device * dev,struct pending_request * pending)147 static void pending_request_free(struct audio_device *dev,
148 					struct pending_request *pending)
149 {
150 	if (pending->conn)
151 		dbus_connection_unref(pending->conn);
152 	if (pending->msg)
153 		dbus_message_unref(pending->msg);
154 	if (pending->id)
155 		a2dp_cancel(dev, pending->id);
156 
157 	g_free(pending);
158 }
159 
stream_state_changed(struct avdtp_stream * stream,avdtp_state_t old_state,avdtp_state_t new_state,struct avdtp_error * err,void * user_data)160 static void stream_state_changed(struct avdtp_stream *stream,
161 					avdtp_state_t old_state,
162 					avdtp_state_t new_state,
163 					struct avdtp_error *err,
164 					void *user_data)
165 {
166 	struct audio_device *dev = user_data;
167 	struct source *source = dev->source;
168 
169 	if (err)
170 		return;
171 
172 	switch (new_state) {
173 	case AVDTP_STATE_IDLE:
174 		if (source->disconnect) {
175 			DBusMessage *reply;
176 			struct pending_request *p;
177 
178 			p = source->disconnect;
179 			source->disconnect = NULL;
180 
181 			reply = dbus_message_new_method_return(p->msg);
182 			g_dbus_send_message(p->conn, reply);
183 			pending_request_free(dev, p);
184 		}
185 
186 		if (source->session) {
187 			avdtp_unref(source->session);
188 			source->session = NULL;
189 		}
190 		source->stream = NULL;
191 		source->cb_id = 0;
192 		break;
193 	case AVDTP_STATE_OPEN:
194 		source_set_state(dev, SOURCE_STATE_CONNECTED);
195 		break;
196 	case AVDTP_STATE_STREAMING:
197 		source_set_state(dev, SOURCE_STATE_PLAYING);
198 		break;
199 	case AVDTP_STATE_CONFIGURED:
200 	case AVDTP_STATE_CLOSING:
201 	case AVDTP_STATE_ABORTING:
202 	default:
203 		break;
204 	}
205 
206 	source->stream_state = new_state;
207 }
208 
error_failed(DBusConnection * conn,DBusMessage * msg,const char * desc)209 static void error_failed(DBusConnection *conn, DBusMessage *msg,
210 							const char *desc)
211 {
212 	DBusMessage *reply = btd_error_failed(msg, desc);
213 	g_dbus_send_message(conn, reply);
214 }
215 
stream_setup_retry(gpointer user_data)216 static gboolean stream_setup_retry(gpointer user_data)
217 {
218 	struct source *source = user_data;
219 	struct pending_request *pending = source->connect;
220 
221 	source->retry_id = 0;
222 
223 	if (source->stream_state >= AVDTP_STATE_OPEN) {
224 		DBG("Stream successfully created, after XCASE connect:connect");
225 		if (pending->msg) {
226 			DBusMessage *reply;
227 			reply = dbus_message_new_method_return(pending->msg);
228 			g_dbus_send_message(pending->conn, reply);
229 		}
230 	} else {
231 		DBG("Stream setup failed, after XCASE connect:connect");
232 		if (pending->msg)
233 			error_failed(pending->conn, pending->msg, "Stream setup failed");
234 	}
235 
236 	source->connect = NULL;
237 	pending_request_free(source->dev, pending);
238 
239 	return FALSE;
240 }
241 
stream_setup_complete(struct avdtp * session,struct a2dp_sep * sep,struct avdtp_stream * stream,struct avdtp_error * err,void * user_data)242 static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
243 					struct avdtp_stream *stream,
244 					struct avdtp_error *err, void *user_data)
245 {
246 	struct source *source = user_data;
247 	struct pending_request *pending;
248 
249 	pending = source->connect;
250 
251 	pending->id = 0;
252 
253 	if (stream) {
254 		DBG("Stream successfully created");
255 
256 		if (pending->msg) {
257 			DBusMessage *reply;
258 			reply = dbus_message_new_method_return(pending->msg);
259 			g_dbus_send_message(pending->conn, reply);
260 		}
261 
262 		source->connect = NULL;
263 		pending_request_free(source->dev, pending);
264 
265 		return;
266 	}
267 
268 	avdtp_unref(source->session);
269 	source->session = NULL;
270 	if (avdtp_error_category(err) == AVDTP_ERRNO
271 			&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
272 		DBG("connect:connect XCASE detected");
273 		source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
274 							stream_setup_retry,
275 							source);
276 	} else {
277 		if (pending->msg)
278 			error_failed(pending->conn, pending->msg, "Stream setup failed");
279 		source->connect = NULL;
280 		pending_request_free(source->dev, pending);
281 		DBG("Stream setup failed : %s", avdtp_strerror(err));
282 	}
283 }
284 
select_complete(struct avdtp * session,struct a2dp_sep * sep,GSList * caps,void * user_data)285 static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
286 			GSList *caps, void *user_data)
287 {
288 	struct source *source = user_data;
289 	struct pending_request *pending;
290 	int id;
291 
292 	pending = source->connect;
293 
294 	pending->id = 0;
295 
296 	if (caps == NULL)
297 		goto failed;
298 
299 	id = a2dp_config(session, sep, stream_setup_complete, caps, source);
300 	if (id == 0)
301 		goto failed;
302 
303 	pending->id = id;
304 	return;
305 
306 failed:
307 	if (pending->msg)
308 		error_failed(pending->conn, pending->msg, "Stream setup failed");
309 	pending_request_free(source->dev, pending);
310 	source->connect = NULL;
311 	avdtp_unref(source->session);
312 	source->session = NULL;
313 }
314 
discovery_complete(struct avdtp * session,GSList * seps,struct avdtp_error * err,void * user_data)315 static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
316 				void *user_data)
317 {
318 	struct source *source = user_data;
319 	struct pending_request *pending;
320 	int id;
321 
322 	pending = source->connect;
323 
324 	if (err) {
325 		avdtp_unref(source->session);
326 		source->session = NULL;
327 		if (avdtp_error_category(err) == AVDTP_ERRNO
328 				&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
329 			DBG("connect:connect XCASE detected");
330 			source->retry_id =
331 				g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
332 							stream_setup_retry,
333 							source);
334 		} else
335 			goto failed;
336 		return;
337 	}
338 
339 	DBG("Discovery complete");
340 
341 	id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
342 						select_complete, source);
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(source->dev, pending);
353 	source->connect = NULL;
354 	avdtp_unref(source->session);
355 	source->session = NULL;
356 }
357 
source_setup_stream(struct source * source,struct avdtp * session)358 gboolean source_setup_stream(struct source *source, struct avdtp *session)
359 {
360 	if (source->connect || source->disconnect)
361 		return FALSE;
362 
363 	if (session && !source->session)
364 		source->session = avdtp_ref(session);
365 
366 	if (!source->session)
367 		return FALSE;
368 
369 	avdtp_set_auto_disconnect(source->session, FALSE);
370 
371 	if (avdtp_discover(source->session, discovery_complete, source) < 0)
372 		return FALSE;
373 
374 	source->connect = g_new0(struct pending_request, 1);
375 
376 	return TRUE;
377 }
378 
source_connect(DBusConnection * conn,DBusMessage * msg,void * data)379 static DBusMessage *source_connect(DBusConnection *conn,
380 				DBusMessage *msg, void *data)
381 {
382 	struct audio_device *dev = data;
383 	struct source *source = dev->source;
384 	struct pending_request *pending;
385 
386 	if (!source->session)
387 		source->session = avdtp_get(&dev->src, &dev->dst);
388 
389 	if (!source->session)
390 		return btd_error_failed(msg, "Unable to get a session");
391 
392 	if (source->connect || source->disconnect)
393 		return btd_error_busy(msg);
394 
395 	if (source->stream_state >= AVDTP_STATE_OPEN)
396 		return btd_error_already_connected(msg);
397 
398 	if (!source_setup_stream(source, NULL))
399 		return btd_error_failed(msg, "Failed to create a stream");
400 
401 	dev->auto_connect = FALSE;
402 
403 	pending = source->connect;
404 
405 	pending->conn = dbus_connection_ref(conn);
406 	pending->msg = dbus_message_ref(msg);
407 
408 	DBG("stream creation in progress");
409 
410 	return NULL;
411 }
412 
source_disconnect(DBusConnection * conn,DBusMessage * msg,void * data)413 static DBusMessage *source_disconnect(DBusConnection *conn,
414 					DBusMessage *msg, void *data)
415 {
416 	struct audio_device *device = data;
417 	struct source *source = device->source;
418 	struct pending_request *pending;
419 	int err;
420 
421 	if (!source->session)
422 		return btd_error_not_connected(msg);
423 
424 	if (source->connect || source->disconnect)
425 		return btd_error_busy(msg);
426 
427 	if (source->stream_state < AVDTP_STATE_OPEN) {
428 		DBusMessage *reply = dbus_message_new_method_return(msg);
429 		if (!reply)
430 			return NULL;
431 		avdtp_unref(source->session);
432 		source->session = NULL;
433 		return reply;
434 	}
435 
436 	err = avdtp_close(source->session, source->stream, FALSE);
437 	if (err < 0)
438 		return btd_error_failed(msg, strerror(-err));
439 
440 	pending = g_new0(struct pending_request, 1);
441 	pending->conn = dbus_connection_ref(conn);
442 	pending->msg = dbus_message_ref(msg);
443 	source->disconnect = pending;
444 
445 	return NULL;
446 }
447 
source_get_properties(DBusConnection * conn,DBusMessage * msg,void * data)448 static DBusMessage *source_get_properties(DBusConnection *conn,
449 					DBusMessage *msg, void *data)
450 {
451 	struct audio_device *device = data;
452 	struct source *source = device->source;
453 	DBusMessage *reply;
454 	DBusMessageIter iter;
455 	DBusMessageIter dict;
456 	const char *state;
457 
458 	reply = dbus_message_new_method_return(msg);
459 	if (!reply)
460 		return NULL;
461 
462 	dbus_message_iter_init_append(reply, &iter);
463 
464 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
465 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
466 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
467 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
468 
469 	/* State */
470 	state = state2str(source->state);
471 	if (state)
472 		dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
473 
474 	dbus_message_iter_close_container(&iter, &dict);
475 
476 	return reply;
477 }
478 
479 static GDBusMethodTable source_methods[] = {
480 	{ "Connect",		"",	"",	source_connect,
481 						G_DBUS_METHOD_FLAG_ASYNC },
482 	{ "Disconnect",		"",	"",	source_disconnect,
483 						G_DBUS_METHOD_FLAG_ASYNC },
484 	{ "GetProperties",	"",	"a{sv}",source_get_properties },
485 	{ NULL, NULL, NULL, NULL }
486 };
487 
488 static GDBusSignalTable source_signals[] = {
489 	{ "PropertyChanged",		"sv"	},
490 	{ NULL, NULL }
491 };
492 
source_free(struct audio_device * dev)493 static void source_free(struct audio_device *dev)
494 {
495 	struct source *source = dev->source;
496 
497 	if (source->cb_id)
498 		avdtp_stream_remove_cb(source->session, source->stream,
499 					source->cb_id);
500 
501 	if (source->session)
502 		avdtp_unref(source->session);
503 
504 	if (source->connect)
505 		pending_request_free(dev, source->connect);
506 
507 	if (source->disconnect)
508 		pending_request_free(dev, source->disconnect);
509 
510 	if (source->retry_id)
511 		g_source_remove(source->retry_id);
512 
513 	g_free(source);
514 	dev->source = NULL;
515 }
516 
path_unregister(void * data)517 static void path_unregister(void *data)
518 {
519 	struct audio_device *dev = data;
520 
521 	DBG("Unregistered interface %s on path %s",
522 		AUDIO_SOURCE_INTERFACE, dev->path);
523 
524 	source_free(dev);
525 }
526 
source_unregister(struct audio_device * dev)527 void source_unregister(struct audio_device *dev)
528 {
529 	g_dbus_unregister_interface(dev->conn, dev->path,
530 		AUDIO_SOURCE_INTERFACE);
531 }
532 
source_init(struct audio_device * dev)533 struct source *source_init(struct audio_device *dev)
534 {
535 	struct source *source;
536 
537 	if (!g_dbus_register_interface(dev->conn, dev->path,
538 					AUDIO_SOURCE_INTERFACE,
539 					source_methods, source_signals, NULL,
540 					dev, path_unregister))
541 		return NULL;
542 
543 	DBG("Registered interface %s on path %s",
544 		AUDIO_SOURCE_INTERFACE, dev->path);
545 
546 	if (avdtp_callback_id == 0)
547 		avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
548 									NULL);
549 
550 	source = g_new0(struct source, 1);
551 
552 	source->dev = dev;
553 
554 	return source;
555 }
556 
source_is_active(struct audio_device * dev)557 gboolean source_is_active(struct audio_device *dev)
558 {
559 	struct source *source = dev->source;
560 
561 	if (source->session)
562 		return TRUE;
563 
564 	return FALSE;
565 }
566 
source_get_state(struct audio_device * dev)567 avdtp_state_t source_get_state(struct audio_device *dev)
568 {
569 	struct source *source = dev->source;
570 
571 	return source->stream_state;
572 }
573 
source_new_stream(struct audio_device * dev,struct avdtp * session,struct avdtp_stream * stream)574 gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
575 				struct avdtp_stream *stream)
576 {
577 	struct source *source = dev->source;
578 
579 	if (source->stream)
580 		return FALSE;
581 
582 	if (!source->session)
583 		source->session = avdtp_ref(session);
584 
585 	source->stream = stream;
586 
587 	source->cb_id = avdtp_stream_add_cb(session, stream,
588 						stream_state_changed, dev);
589 
590 	return TRUE;
591 }
592 
source_shutdown(struct source * source)593 gboolean source_shutdown(struct source *source)
594 {
595 	if (!source->stream)
596 		return FALSE;
597 
598 	if (avdtp_close(source->session, source->stream, FALSE) < 0)
599 		return FALSE;
600 
601 	return TRUE;
602 }
603 
source_add_state_cb(source_state_cb cb,void * user_data)604 unsigned int source_add_state_cb(source_state_cb cb, void *user_data)
605 {
606 	struct source_state_callback *state_cb;
607 	static unsigned int id = 0;
608 
609 	state_cb = g_new(struct source_state_callback, 1);
610 	state_cb->cb = cb;
611 	state_cb->user_data = user_data;
612 	state_cb->id = ++id;
613 
614 	source_callbacks = g_slist_append(source_callbacks, state_cb);
615 
616 	return state_cb->id;
617 }
618 
source_remove_state_cb(unsigned int id)619 gboolean source_remove_state_cb(unsigned int id)
620 {
621 	GSList *l;
622 
623 	for (l = source_callbacks; l != NULL; l = l->next) {
624 		struct source_state_callback *cb = l->data;
625 		if (cb && cb->id == id) {
626 			source_callbacks = g_slist_remove(source_callbacks, cb);
627 			g_free(cb);
628 			return TRUE;
629 		}
630 	}
631 
632 	return FALSE;
633 }
634