~ubuntu-branches/ubuntu/wily/bluez/wily

« back to all changes in this revision

Viewing changes to audio/source.c

ImportĀ upstreamĀ versionĀ 4.81

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
                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
 
 
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
 
 
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
 
 
209
static DBusHandlerResult error_failed(DBusConnection *conn,
 
210
                                        DBusMessage *msg, const char * desc)
 
211
{
 
212
        return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc);
 
213
}
 
214
 
 
215
static gboolean stream_setup_retry(gpointer user_data)
 
216
{
 
217
        struct source *source = user_data;
 
218
        struct pending_request *pending = source->connect;
 
219
 
 
220
        source->retry_id = 0;
 
221
 
 
222
        if (source->stream_state >= AVDTP_STATE_OPEN) {
 
223
                DBG("Stream successfully created, after XCASE connect:connect");
 
224
                if (pending->msg) {
 
225
                        DBusMessage *reply;
 
226
                        reply = dbus_message_new_method_return(pending->msg);
 
227
                        g_dbus_send_message(pending->conn, reply);
 
228
                }
 
229
        } else {
 
230
                DBG("Stream setup failed, after XCASE connect:connect");
 
231
                if (pending->msg)
 
232
                        error_failed(pending->conn, pending->msg, "Stream setup failed");
 
233
        }
 
234
 
 
235
        source->connect = NULL;
 
236
        pending_request_free(source->dev, pending);
 
237
 
 
238
        return FALSE;
 
239
}
 
240
 
 
241
static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
 
242
                                        struct avdtp_stream *stream,
 
243
                                        struct avdtp_error *err, void *user_data)
 
244
{
 
245
        struct source *source = user_data;
 
246
        struct pending_request *pending;
 
247
 
 
248
        pending = source->connect;
 
249
 
 
250
        pending->id = 0;
 
251
 
 
252
        if (stream) {
 
253
                DBG("Stream successfully created");
 
254
 
 
255
                if (pending->msg) {
 
256
                        DBusMessage *reply;
 
257
                        reply = dbus_message_new_method_return(pending->msg);
 
258
                        g_dbus_send_message(pending->conn, reply);
 
259
                }
 
260
 
 
261
                source->connect = NULL;
 
262
                pending_request_free(source->dev, pending);
 
263
 
 
264
                return;
 
265
        }
 
266
 
 
267
        avdtp_unref(source->session);
 
268
        source->session = NULL;
 
269
        if (avdtp_error_category(err) == AVDTP_ERRNO
 
270
                        && avdtp_error_posix_errno(err) != EHOSTDOWN) {
 
271
                DBG("connect:connect XCASE detected");
 
272
                source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
 
273
                                                        stream_setup_retry,
 
274
                                                        source);
 
275
        } else {
 
276
                if (pending->msg)
 
277
                        error_failed(pending->conn, pending->msg, "Stream setup failed");
 
278
                source->connect = NULL;
 
279
                pending_request_free(source->dev, pending);
 
280
                DBG("Stream setup failed : %s", avdtp_strerror(err));
 
281
        }
 
282
}
 
283
 
 
284
static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
 
285
                        GSList *caps, void *user_data)
 
286
{
 
287
        struct source *source = user_data;
 
288
        struct pending_request *pending;
 
289
        int id;
 
290
 
 
291
        pending = source->connect;
 
292
 
 
293
        pending->id = 0;
 
294
 
 
295
        if (caps == NULL)
 
296
                goto failed;
 
297
 
 
298
        id = a2dp_config(session, sep, stream_setup_complete, caps, source);
 
299
        if (id == 0)
 
300
                goto failed;
 
301
 
 
302
        pending->id = id;
 
303
        return;
 
304
 
 
305
failed:
 
306
        if (pending->msg)
 
307
                error_failed(pending->conn, pending->msg, "Stream setup failed");
 
308
        pending_request_free(source->dev, pending);
 
309
        source->connect = NULL;
 
310
        avdtp_unref(source->session);
 
311
        source->session = NULL;
 
312
}
 
313
 
 
314
static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
 
315
                                void *user_data)
 
316
{
 
317
        struct source *source = user_data;
 
318
        struct pending_request *pending;
 
319
        int id;
 
320
 
 
321
        pending = source->connect;
 
322
 
 
323
        if (err) {
 
324
                avdtp_unref(source->session);
 
325
                source->session = NULL;
 
326
                if (avdtp_error_category(err) == AVDTP_ERRNO
 
327
                                && avdtp_error_posix_errno(err) != EHOSTDOWN) {
 
328
                        DBG("connect:connect XCASE detected");
 
329
                        source->retry_id =
 
330
                                g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
 
331
                                                        stream_setup_retry,
 
332
                                                        source);
 
333
                } else
 
334
                        goto failed;
 
335
                return;
 
336
        }
 
337
 
 
338
        DBG("Discovery complete");
 
339
 
 
340
        id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
 
341
                                                select_complete, source);
 
342
        if (id == 0)
 
343
                goto failed;
 
344
 
 
345
        pending->id = id;
 
346
        return;
 
347
 
 
348
failed:
 
349
        if (pending->msg)
 
350
                error_failed(pending->conn, pending->msg, "Stream setup failed");
 
351
        pending_request_free(source->dev, pending);
 
352
        source->connect = NULL;
 
353
        avdtp_unref(source->session);
 
354
        source->session = NULL;
 
355
}
 
356
 
 
357
gboolean source_setup_stream(struct source *source, struct avdtp *session)
 
358
{
 
359
        if (source->connect || source->disconnect)
 
360
                return FALSE;
 
361
 
 
362
        if (session && !source->session)
 
363
                source->session = avdtp_ref(session);
 
364
 
 
365
        if (!source->session)
 
366
                return FALSE;
 
367
 
 
368
        avdtp_set_auto_disconnect(source->session, FALSE);
 
369
 
 
370
        if (avdtp_discover(source->session, discovery_complete, source) < 0)
 
371
                return FALSE;
 
372
 
 
373
        source->connect = g_new0(struct pending_request, 1);
 
374
 
 
375
        return TRUE;
 
376
}
 
377
 
 
378
static DBusMessage *source_connect(DBusConnection *conn,
 
379
                                DBusMessage *msg, void *data)
 
380
{
 
381
        struct audio_device *dev = data;
 
382
        struct source *source = dev->source;
 
383
        struct pending_request *pending;
 
384
 
 
385
        if (!source->session)
 
386
                source->session = avdtp_get(&dev->src, &dev->dst);
 
387
 
 
388
        if (!source->session)
 
389
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
390
                                                "Unable to get a session");
 
391
 
 
392
        if (source->connect || source->disconnect)
 
393
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
394
                                                "%s", strerror(EBUSY));
 
395
 
 
396
        if (source->stream_state >= AVDTP_STATE_OPEN)
 
397
                return g_dbus_create_error(msg, ERROR_INTERFACE
 
398
                                                ".AlreadyConnected",
 
399
                                                "Device Already Connected");
 
400
 
 
401
        if (!source_setup_stream(source, NULL))
 
402
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
403
                                                "Failed to create a stream");
 
404
 
 
405
        dev->auto_connect = FALSE;
 
406
 
 
407
        pending = source->connect;
 
408
 
 
409
        pending->conn = dbus_connection_ref(conn);
 
410
        pending->msg = dbus_message_ref(msg);
 
411
 
 
412
        DBG("stream creation in progress");
 
413
 
 
414
        return NULL;
 
415
}
 
416
 
 
417
static DBusMessage *source_disconnect(DBusConnection *conn,
 
418
                                        DBusMessage *msg, void *data)
 
419
{
 
420
        struct audio_device *device = data;
 
421
        struct source *source = device->source;
 
422
        struct pending_request *pending;
 
423
        int err;
 
424
 
 
425
        if (!source->session)
 
426
                return g_dbus_create_error(msg, ERROR_INTERFACE
 
427
                                                ".NotConnected",
 
428
                                                "Device not Connected");
 
429
 
 
430
        if (source->connect || source->disconnect)
 
431
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
432
                                                "%s", strerror(EBUSY));
 
433
 
 
434
        if (source->stream_state < AVDTP_STATE_OPEN) {
 
435
                DBusMessage *reply = dbus_message_new_method_return(msg);
 
436
                if (!reply)
 
437
                        return NULL;
 
438
                avdtp_unref(source->session);
 
439
                source->session = NULL;
 
440
                return reply;
 
441
        }
 
442
 
 
443
        err = avdtp_close(source->session, source->stream, FALSE);
 
444
        if (err < 0)
 
445
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
446
                                                "%s", strerror(-err));
 
447
 
 
448
        pending = g_new0(struct pending_request, 1);
 
449
        pending->conn = dbus_connection_ref(conn);
 
450
        pending->msg = dbus_message_ref(msg);
 
451
        source->disconnect = pending;
 
452
 
 
453
        return NULL;
 
454
}
 
455
 
 
456
static DBusMessage *source_get_properties(DBusConnection *conn,
 
457
                                        DBusMessage *msg, void *data)
 
458
{
 
459
        struct audio_device *device = data;
 
460
        struct source *source = device->source;
 
461
        DBusMessage *reply;
 
462
        DBusMessageIter iter;
 
463
        DBusMessageIter dict;
 
464
        const char *state;
 
465
 
 
466
        reply = dbus_message_new_method_return(msg);
 
467
        if (!reply)
 
468
                return NULL;
 
469
 
 
470
        dbus_message_iter_init_append(reply, &iter);
 
471
 
 
472
        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
 
473
                        DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
 
474
                        DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
 
475
                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
476
 
 
477
        /* State */
 
478
        state = state2str(source->state);
 
479
        if (state)
 
480
                dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
 
481
 
 
482
        dbus_message_iter_close_container(&iter, &dict);
 
483
 
 
484
        return reply;
 
485
}
 
486
 
 
487
static GDBusMethodTable source_methods[] = {
 
488
        { "Connect",            "",     "",     source_connect,
 
489
                                                G_DBUS_METHOD_FLAG_ASYNC },
 
490
        { "Disconnect",         "",     "",     source_disconnect,
 
491
                                                G_DBUS_METHOD_FLAG_ASYNC },
 
492
        { "GetProperties",      "",     "a{sv}",source_get_properties },
 
493
        { NULL, NULL, NULL, NULL }
 
494
};
 
495
 
 
496
static GDBusSignalTable source_signals[] = {
 
497
        { "PropertyChanged",            "sv"    },
 
498
        { NULL, NULL }
 
499
};
 
500
 
 
501
static void source_free(struct audio_device *dev)
 
502
{
 
503
        struct source *source = dev->source;
 
504
 
 
505
        if (source->cb_id)
 
506
                avdtp_stream_remove_cb(source->session, source->stream,
 
507
                                        source->cb_id);
 
508
 
 
509
        if (source->session)
 
510
                avdtp_unref(source->session);
 
511
 
 
512
        if (source->connect)
 
513
                pending_request_free(dev, source->connect);
 
514
 
 
515
        if (source->disconnect)
 
516
                pending_request_free(dev, source->disconnect);
 
517
 
 
518
        if (source->retry_id)
 
519
                g_source_remove(source->retry_id);
 
520
 
 
521
        g_free(source);
 
522
        dev->source = NULL;
 
523
}
 
524
 
 
525
static void path_unregister(void *data)
 
526
{
 
527
        struct audio_device *dev = data;
 
528
 
 
529
        DBG("Unregistered interface %s on path %s",
 
530
                AUDIO_SOURCE_INTERFACE, dev->path);
 
531
 
 
532
        source_free(dev);
 
533
}
 
534
 
 
535
void source_unregister(struct audio_device *dev)
 
536
{
 
537
        g_dbus_unregister_interface(dev->conn, dev->path,
 
538
                AUDIO_SOURCE_INTERFACE);
 
539
}
 
540
 
 
541
struct source *source_init(struct audio_device *dev)
 
542
{
 
543
        struct source *source;
 
544
 
 
545
        if (!g_dbus_register_interface(dev->conn, dev->path,
 
546
                                        AUDIO_SOURCE_INTERFACE,
 
547
                                        source_methods, source_signals, NULL,
 
548
                                        dev, path_unregister))
 
549
                return NULL;
 
550
 
 
551
        DBG("Registered interface %s on path %s",
 
552
                AUDIO_SOURCE_INTERFACE, dev->path);
 
553
 
 
554
        if (avdtp_callback_id == 0)
 
555
                avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
 
556
                                                                        NULL);
 
557
 
 
558
        source = g_new0(struct source, 1);
 
559
 
 
560
        source->dev = dev;
 
561
 
 
562
        return source;
 
563
}
 
564
 
 
565
gboolean source_is_active(struct audio_device *dev)
 
566
{
 
567
        struct source *source = dev->source;
 
568
 
 
569
        if (source->session)
 
570
                return TRUE;
 
571
 
 
572
        return FALSE;
 
573
}
 
574
 
 
575
avdtp_state_t source_get_state(struct audio_device *dev)
 
576
{
 
577
        struct source *source = dev->source;
 
578
 
 
579
        return source->stream_state;
 
580
}
 
581
 
 
582
gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
 
583
                                struct avdtp_stream *stream)
 
584
{
 
585
        struct source *source = dev->source;
 
586
 
 
587
        if (source->stream)
 
588
                return FALSE;
 
589
 
 
590
        if (!source->session)
 
591
                source->session = avdtp_ref(session);
 
592
 
 
593
        source->stream = stream;
 
594
 
 
595
        source->cb_id = avdtp_stream_add_cb(session, stream,
 
596
                                                stream_state_changed, dev);
 
597
 
 
598
        return TRUE;
 
599
}
 
600
 
 
601
gboolean source_shutdown(struct source *source)
 
602
{
 
603
        if (!source->stream)
 
604
                return FALSE;
 
605
 
 
606
        if (avdtp_close(source->session, source->stream, FALSE) < 0)
 
607
                return FALSE;
 
608
 
 
609
        return TRUE;
 
610
}
 
611
 
 
612
unsigned int source_add_state_cb(source_state_cb cb, void *user_data)
 
613
{
 
614
        struct source_state_callback *state_cb;
 
615
        static unsigned int id = 0;
 
616
 
 
617
        state_cb = g_new(struct source_state_callback, 1);
 
618
        state_cb->cb = cb;
 
619
        state_cb->user_data = user_data;
 
620
        state_cb->id = ++id;
 
621
 
 
622
        source_callbacks = g_slist_append(source_callbacks, state_cb);
 
623
 
 
624
        return state_cb->id;
 
625
}
 
626
 
 
627
gboolean source_remove_state_cb(unsigned int id)
 
628
{
 
629
        GSList *l;
 
630
 
 
631
        for (l = source_callbacks; l != NULL; l = l->next) {
 
632
                struct source_state_callback *cb = l->data;
 
633
                if (cb && cb->id == id) {
 
634
                        source_callbacks = g_slist_remove(source_callbacks, cb);
 
635
                        g_free(cb);
 
636
                        return TRUE;
 
637
                }
 
638
        }
 
639
 
 
640
        return FALSE;
 
641
}