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