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

« back to all changes in this revision

Viewing changes to audio/sink.c

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2008-10-07 12:10:29 UTC
  • Revision ID: james.westby@ubuntu.com-20081007121029-4gup4fmmh2vfo5nh
Tags: upstream-4.12
ImportĀ upstreamĀ versionĀ 4.12

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-2007  Nokia Corporation
 
6
 *  Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
 
7
 *
 
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
 
 
34
#include <glib.h>
 
35
#include <dbus/dbus.h>
 
36
#include <gdbus.h>
 
37
 
 
38
#include "logging.h"
 
39
 
 
40
#include "avdtp.h"
 
41
#include "device.h"
 
42
#include "a2dp.h"
 
43
#include "error.h"
 
44
#include "sink.h"
 
45
#include "dbus-common.h"
 
46
 
 
47
#define STREAM_SETUP_RETRY_TIMER 2000
 
48
 
 
49
struct pending_request {
 
50
        DBusConnection *conn;
 
51
        DBusMessage *msg;
 
52
        unsigned int id;
 
53
};
 
54
 
 
55
struct sink {
 
56
        struct avdtp *session;
 
57
        struct avdtp_stream *stream;
 
58
        unsigned int cb_id;
 
59
        uint8_t state;
 
60
        struct pending_request *connect;
 
61
        struct pending_request *disconnect;
 
62
        DBusConnection *conn;
 
63
};
 
64
 
 
65
static void pending_request_free(struct pending_request *pending)
 
66
{
 
67
        if (pending->conn)
 
68
                dbus_connection_unref(pending->conn);
 
69
        if (pending->msg)
 
70
                dbus_message_unref(pending->msg);
 
71
        g_free(pending);
 
72
}
 
73
 
 
74
static void stream_state_changed(struct avdtp_stream *stream,
 
75
                                        avdtp_state_t old_state,
 
76
                                        avdtp_state_t new_state,
 
77
                                        struct avdtp_error *err,
 
78
                                        void *user_data)
 
79
{
 
80
        struct audio_device *dev = user_data;
 
81
        struct sink *sink = dev->sink;
 
82
        gboolean value;
 
83
 
 
84
        if (err)
 
85
                return;
 
86
 
 
87
        switch (new_state) {
 
88
        case AVDTP_STATE_IDLE:
 
89
                value = FALSE;
 
90
                g_dbus_emit_signal(dev->conn, dev->path,
 
91
                                                AUDIO_SINK_INTERFACE,
 
92
                                                "Disconnected",
 
93
                                                DBUS_TYPE_INVALID);
 
94
                dbus_connection_emit_property_changed(dev->conn, dev->path,
 
95
                                                AUDIO_SINK_INTERFACE,
 
96
                                                "Connected",
 
97
                                                DBUS_TYPE_BOOLEAN, &value);
 
98
                if (sink->disconnect) {
 
99
                        DBusMessage *reply;
 
100
                        struct pending_request *p;
 
101
 
 
102
                        p = sink->disconnect;
 
103
                        sink->disconnect = NULL;
 
104
 
 
105
                        reply = dbus_message_new_method_return(p->msg);
 
106
                        dbus_connection_send(p->conn, reply, NULL);
 
107
                        dbus_message_unref(reply);
 
108
                        pending_request_free(p);
 
109
                }
 
110
 
 
111
                if (sink->session) {
 
112
                        avdtp_unref(sink->session);
 
113
                        sink->session = NULL;
 
114
                }
 
115
                sink->stream = NULL;
 
116
                sink->cb_id = 0;
 
117
                break;
 
118
        case AVDTP_STATE_OPEN:
 
119
                if (old_state == AVDTP_STATE_CONFIGURED) {
 
120
                        value = TRUE;
 
121
                        g_dbus_emit_signal(dev->conn, dev->path,
 
122
                                                        AUDIO_SINK_INTERFACE,
 
123
                                                        "Connected",
 
124
                                                        DBUS_TYPE_INVALID);
 
125
                        dbus_connection_emit_property_changed(dev->conn,
 
126
                                                        dev->path,
 
127
                                                        AUDIO_SINK_INTERFACE,
 
128
                                                        "Connected",
 
129
                                                        DBUS_TYPE_BOOLEAN,
 
130
                                                        &value);
 
131
                } else if (old_state == AVDTP_STATE_STREAMING) {
 
132
                        value = FALSE;
 
133
                        g_dbus_emit_signal(dev->conn, dev->path,
 
134
                                                        AUDIO_SINK_INTERFACE,
 
135
                                                        "Stopped",
 
136
                                                        DBUS_TYPE_INVALID);
 
137
                        dbus_connection_emit_property_changed(dev->conn,
 
138
                                                        dev->path,
 
139
                                                        AUDIO_SINK_INTERFACE,
 
140
                                                        "Playing",
 
141
                                                        DBUS_TYPE_BOOLEAN,
 
142
                                                        &value);
 
143
                }
 
144
                break;
 
145
        case AVDTP_STATE_STREAMING:
 
146
                value = TRUE;
 
147
                g_dbus_emit_signal(dev->conn, dev->path,
 
148
                                                AUDIO_SINK_INTERFACE,
 
149
                                                "Playing",
 
150
                                                DBUS_TYPE_INVALID);
 
151
                dbus_connection_emit_property_changed(dev->conn, dev->path,
 
152
                                                AUDIO_SINK_INTERFACE,
 
153
                                                "Playing",
 
154
                                                DBUS_TYPE_BOOLEAN, &value);
 
155
                break;
 
156
        case AVDTP_STATE_CONFIGURED:
 
157
        case AVDTP_STATE_CLOSING:
 
158
        case AVDTP_STATE_ABORTING:
 
159
        default:
 
160
                break;
 
161
        }
 
162
 
 
163
        sink->state = new_state;
 
164
}
 
165
 
 
166
static DBusHandlerResult error_failed(DBusConnection *conn,
 
167
                                        DBusMessage *msg, const char * desc)
 
168
{
 
169
        return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc);
 
170
}
 
171
 
 
172
static gboolean stream_setup_retry(gpointer user_data)
 
173
{
 
174
        struct sink *sink = user_data;
 
175
        struct pending_request *pending = sink->connect;
 
176
 
 
177
        if (sink->state >= AVDTP_STATE_OPEN) {
 
178
                DBusMessage *reply;
 
179
                debug("Stream successfully created, after XCASE connect:connect");
 
180
                reply = dbus_message_new_method_return(pending->msg);
 
181
                dbus_connection_send(pending->conn, reply, NULL);
 
182
                dbus_message_unref(reply);
 
183
        } else {
 
184
                debug("Stream setup failed, after XCASE connect:connect");
 
185
                error_failed(pending->conn, pending->msg, "Stream setup failed");
 
186
        }
 
187
 
 
188
        sink->connect = NULL;
 
189
        pending_request_free(pending);
 
190
 
 
191
        return FALSE;
 
192
}
 
193
 
 
194
static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
 
195
                                        struct avdtp_stream *stream,
 
196
                                        struct avdtp_error *err, void *user_data)
 
197
{
 
198
        struct sink *sink = user_data;
 
199
        struct pending_request *pending;
 
200
 
 
201
        pending = sink->connect;
 
202
 
 
203
        if (stream) {
 
204
                DBusMessage *reply;
 
205
                sink->connect = NULL;
 
206
                reply = dbus_message_new_method_return(pending->msg);
 
207
                dbus_connection_send(pending->conn, reply, NULL);
 
208
                dbus_message_unref(reply);
 
209
                pending_request_free(pending);
 
210
                debug("Stream successfully created");
 
211
        } else {
 
212
                avdtp_unref(sink->session);
 
213
                sink->session = NULL;
 
214
                if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
 
215
                                && avdtp_error_posix_errno(err) != EHOSTDOWN) {
 
216
                        debug("connect:connect XCASE detected");
 
217
                        g_timeout_add(STREAM_SETUP_RETRY_TIMER,
 
218
                                        stream_setup_retry, sink);
 
219
                } else {
 
220
                        sink->connect = NULL;
 
221
                        error_failed(pending->conn, pending->msg, "Stream setup failed");
 
222
                        pending_request_free(pending);
 
223
                        debug("Stream setup failed : %s", avdtp_strerror(err));
 
224
                }
 
225
        }
 
226
}
 
227
 
 
228
static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
 
229
{
 
230
        switch (freq) {
 
231
        case SBC_SAMPLING_FREQ_16000:
 
232
        case SBC_SAMPLING_FREQ_32000:
 
233
                return 53;
 
234
        case SBC_SAMPLING_FREQ_44100:
 
235
                switch (mode) {
 
236
                case SBC_CHANNEL_MODE_MONO:
 
237
                case SBC_CHANNEL_MODE_DUAL_CHANNEL:
 
238
                        return 31;
 
239
                case SBC_CHANNEL_MODE_STEREO:
 
240
                case SBC_CHANNEL_MODE_JOINT_STEREO:
 
241
                        return 53;
 
242
                default:
 
243
                        error("Invalid channel mode %u", mode);
 
244
                        return 53;
 
245
                }
 
246
        case SBC_SAMPLING_FREQ_48000:
 
247
                switch (mode) {
 
248
                case SBC_CHANNEL_MODE_MONO:
 
249
                case SBC_CHANNEL_MODE_DUAL_CHANNEL:
 
250
                        return 29;
 
251
                case SBC_CHANNEL_MODE_STEREO:
 
252
                case SBC_CHANNEL_MODE_JOINT_STEREO:
 
253
                        return 51;
 
254
                default:
 
255
                        error("Invalid channel mode %u", mode);
 
256
                        return 51;
 
257
                }
 
258
        default:
 
259
                error("Invalid sampling freq %u", freq);
 
260
                return 53;
 
261
        }
 
262
}
 
263
 
 
264
static gboolean select_sbc_params(struct sbc_codec_cap *cap,
 
265
                                        struct sbc_codec_cap *supported)
 
266
{
 
267
        unsigned int max_bitpool, min_bitpool;
 
268
 
 
269
        memset(cap, 0, sizeof(struct sbc_codec_cap));
 
270
 
 
271
        cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
 
272
        cap->cap.media_codec_type = A2DP_CODEC_SBC;
 
273
 
 
274
        if (supported->frequency & SBC_SAMPLING_FREQ_44100)
 
275
                cap->frequency = SBC_SAMPLING_FREQ_44100;
 
276
        else if (supported->frequency & SBC_SAMPLING_FREQ_48000)
 
277
                cap->frequency = SBC_SAMPLING_FREQ_48000;
 
278
        else if (supported->frequency & SBC_SAMPLING_FREQ_32000)
 
279
                cap->frequency = SBC_SAMPLING_FREQ_32000;
 
280
        else if (supported->frequency & SBC_SAMPLING_FREQ_16000)
 
281
                cap->frequency = SBC_SAMPLING_FREQ_16000;
 
282
        else {
 
283
                error("No supported frequencies");
 
284
                return FALSE;
 
285
        }
 
286
 
 
287
        if (supported->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
 
288
                cap->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
 
289
        else if (supported->channel_mode & SBC_CHANNEL_MODE_STEREO)
 
290
                cap->channel_mode = SBC_CHANNEL_MODE_STEREO;
 
291
        else if (supported->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
 
292
                cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
 
293
        else if (supported->channel_mode & SBC_CHANNEL_MODE_MONO)
 
294
                cap->channel_mode = SBC_CHANNEL_MODE_MONO;
 
295
        else {
 
296
                error("No supported channel modes");
 
297
                return FALSE;
 
298
        }
 
299
 
 
300
        if (supported->block_length & SBC_BLOCK_LENGTH_16)
 
301
                cap->block_length = SBC_BLOCK_LENGTH_16;
 
302
        else if (supported->block_length & SBC_BLOCK_LENGTH_12)
 
303
                cap->block_length = SBC_BLOCK_LENGTH_12;
 
304
        else if (supported->block_length & SBC_BLOCK_LENGTH_8)
 
305
                cap->block_length = SBC_BLOCK_LENGTH_8;
 
306
        else if (supported->block_length & SBC_BLOCK_LENGTH_4)
 
307
                cap->block_length = SBC_BLOCK_LENGTH_4;
 
308
        else {
 
309
                error("No supported block lengths");
 
310
                return FALSE;
 
311
        }
 
312
 
 
313
        if (supported->subbands & SBC_SUBBANDS_8)
 
314
                cap->subbands = SBC_SUBBANDS_8;
 
315
        else if (supported->subbands & SBC_SUBBANDS_4)
 
316
                cap->subbands = SBC_SUBBANDS_4;
 
317
        else {
 
318
                error("No supported subbands");
 
319
                return FALSE;
 
320
        }
 
321
 
 
322
        if (supported->allocation_method & SBC_ALLOCATION_LOUDNESS)
 
323
                cap->allocation_method = SBC_ALLOCATION_LOUDNESS;
 
324
        else if (supported->allocation_method & SBC_ALLOCATION_SNR)
 
325
                cap->allocation_method = SBC_ALLOCATION_SNR;
 
326
 
 
327
        min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool);
 
328
        max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode),
 
329
                                                        supported->max_bitpool);
 
330
 
 
331
        cap->min_bitpool = min_bitpool;
 
332
        cap->max_bitpool = max_bitpool;
 
333
 
 
334
        return TRUE;
 
335
}
 
336
 
 
337
static gboolean select_capabilities(struct avdtp *session,
 
338
                                        struct avdtp_remote_sep *rsep,
 
339
                                        GSList **caps)
 
340
{
 
341
        struct avdtp_service_capability *media_transport, *media_codec;
 
342
        struct sbc_codec_cap sbc_cap;
 
343
 
 
344
        media_codec = avdtp_get_codec(rsep);
 
345
        if (!media_codec)
 
346
                return FALSE;
 
347
 
 
348
        select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data);
 
349
 
 
350
        media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
 
351
                                                NULL, 0);
 
352
 
 
353
        *caps = g_slist_append(*caps, media_transport);
 
354
 
 
355
        media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
 
356
                                                sizeof(sbc_cap));
 
357
 
 
358
        *caps = g_slist_append(*caps, media_codec);
 
359
 
 
360
 
 
361
        return TRUE;
 
362
}
 
363
 
 
364
static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
 
365
                                void *user_data)
 
366
{
 
367
        struct sink *sink = user_data;
 
368
        struct pending_request *pending;
 
369
        struct avdtp_local_sep *lsep;
 
370
        struct avdtp_remote_sep *rsep;
 
371
        GSList *caps = NULL;
 
372
        int id;
 
373
 
 
374
        pending = sink->connect;
 
375
 
 
376
        if (err) {
 
377
                avdtp_unref(sink->session);
 
378
                sink->session = NULL;
 
379
                if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
 
380
                                && avdtp_error_posix_errno(err) != EHOSTDOWN) {
 
381
                        debug("connect:connect XCASE detected");
 
382
                        g_timeout_add(STREAM_SETUP_RETRY_TIMER,
 
383
                                        stream_setup_retry, sink);
 
384
                } else
 
385
                        goto failed;
 
386
                return;
 
387
        }
 
388
 
 
389
        debug("Discovery complete");
 
390
 
 
391
        if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
 
392
                                A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
 
393
                error("No matching ACP and INT SEPs found");
 
394
                goto failed;
 
395
        }
 
396
 
 
397
        if (!select_capabilities(session, rsep, &caps)) {
 
398
                error("Unable to select remote SEP capabilities");
 
399
                goto failed;
 
400
        }
 
401
 
 
402
        id = a2dp_source_config(sink->session, stream_setup_complete,
 
403
                                caps, sink);
 
404
        if (id == 0)
 
405
                goto failed;
 
406
 
 
407
        pending->id = id;
 
408
        return;
 
409
 
 
410
failed:
 
411
        error_failed(pending->conn, pending->msg, "Stream setup failed");
 
412
        pending_request_free(pending);
 
413
        sink->connect = NULL;
 
414
        avdtp_unref(sink->session);
 
415
        sink->session = NULL;
 
416
}
 
417
 
 
418
static DBusMessage *sink_connect(DBusConnection *conn,
 
419
                                DBusMessage *msg, void *data)
 
420
{
 
421
        struct audio_device *dev = data;
 
422
        struct sink *sink = dev->sink;
 
423
        struct pending_request *pending;
 
424
 
 
425
        if (!sink->session)
 
426
                sink->session = avdtp_get(&dev->src, &dev->dst);
 
427
 
 
428
        if (!sink->session)
 
429
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
430
                                                "Unable to get a session");
 
431
 
 
432
        if (sink->connect || sink->disconnect)
 
433
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
434
                                                "%s", strerror(EBUSY));
 
435
 
 
436
        if (sink->state >= AVDTP_STATE_OPEN)
 
437
                return g_dbus_create_error(msg, ERROR_INTERFACE
 
438
                                                ".AlreadyConnected",
 
439
                                                "Device Already Connected");
 
440
 
 
441
        pending = g_new0(struct pending_request, 1);
 
442
        pending->conn = dbus_connection_ref(conn);
 
443
        pending->msg = dbus_message_ref(msg);
 
444
        sink->connect = pending;
 
445
 
 
446
        avdtp_discover(sink->session, discovery_complete, sink);
 
447
 
 
448
        debug("stream creation in progress");
 
449
 
 
450
        return NULL;
 
451
}
 
452
 
 
453
static DBusMessage *sink_disconnect(DBusConnection *conn,
 
454
                                        DBusMessage *msg, void *data)
 
455
{
 
456
        struct audio_device *device = data;
 
457
        struct sink *sink = device->sink;
 
458
        struct pending_request *pending;
 
459
        int err;
 
460
 
 
461
        if (!sink->session)
 
462
                return g_dbus_create_error(msg, ERROR_INTERFACE
 
463
                                                ".NotConnected",
 
464
                                                "Device not Connected");
 
465
 
 
466
        if (sink->connect || sink->disconnect)
 
467
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
468
                                                "%s", strerror(EBUSY));
 
469
 
 
470
        if (sink->state < AVDTP_STATE_OPEN) {
 
471
                DBusMessage *reply = dbus_message_new_method_return(msg);
 
472
                if (!reply)
 
473
                        return NULL;
 
474
                avdtp_unref(sink->session);
 
475
                sink->session = NULL;
 
476
                return reply;
 
477
        }
 
478
 
 
479
        err = avdtp_close(sink->session, sink->stream);
 
480
        if (err < 0)
 
481
                return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
482
                                                "%s", strerror(-err));
 
483
 
 
484
        pending = g_new0(struct pending_request, 1);
 
485
        pending->conn = dbus_connection_ref(conn);
 
486
        pending->msg = dbus_message_ref(msg);
 
487
        sink->disconnect = pending;
 
488
 
 
489
        return NULL;
 
490
}
 
491
 
 
492
static DBusMessage *sink_is_connected(DBusConnection *conn,
 
493
                                        DBusMessage *msg,
 
494
                                        void *data)
 
495
{
 
496
        struct audio_device *device = data;
 
497
        struct sink *sink = device->sink;
 
498
        DBusMessage *reply;
 
499
        dbus_bool_t connected;
 
500
 
 
501
        reply = dbus_message_new_method_return(msg);
 
502
        if (!reply)
 
503
                return NULL;
 
504
 
 
505
        connected = (sink->state >= AVDTP_STATE_CONFIGURED);
 
506
 
 
507
        dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
 
508
                                        DBUS_TYPE_INVALID);
 
509
 
 
510
        return reply;
 
511
}
 
512
 
 
513
static DBusMessage *sink_get_properties(DBusConnection *conn,
 
514
                                        DBusMessage *msg, void *data)
 
515
{
 
516
        struct audio_device *device = data;
 
517
        DBusMessage *reply;
 
518
        DBusMessageIter iter;
 
519
        DBusMessageIter dict;
 
520
        gboolean value;
 
521
 
 
522
        reply = dbus_message_new_method_return(msg);
 
523
        if (!reply)
 
524
                return NULL;
 
525
 
 
526
        dbus_message_iter_init_append(reply, &iter);
 
527
 
 
528
        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
 
529
                        DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
 
530
                        DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
 
531
                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
532
 
 
533
        /* Playing */
 
534
        value = (device->sink->state == AVDTP_STATE_STREAMING);
 
535
        dbus_message_iter_append_dict_entry(&dict, "Playing",
 
536
                                                DBUS_TYPE_BOOLEAN, &value);
 
537
 
 
538
        /* Connected */
 
539
        value = (device->sink->state >= AVDTP_STATE_CONFIGURED);
 
540
        dbus_message_iter_append_dict_entry(&dict, "Connected",
 
541
                                                DBUS_TYPE_BOOLEAN, &value);
 
542
 
 
543
        dbus_message_iter_close_container(&iter, &dict);
 
544
 
 
545
        return reply;
 
546
}
 
547
 
 
548
static GDBusMethodTable sink_methods[] = {
 
549
        { "Connect",            "",     "",     sink_connect,
 
550
                                                G_DBUS_METHOD_FLAG_ASYNC },
 
551
        { "Disconnect",         "",     "",     sink_disconnect,
 
552
                                                G_DBUS_METHOD_FLAG_ASYNC },
 
553
        { "IsConnected",        "",     "b",    sink_is_connected,
 
554
                                                G_DBUS_METHOD_FLAG_DEPRECATED },
 
555
        { "GetProperties",      "",     "a{sv}",sink_get_properties },
 
556
        { NULL, NULL, NULL, NULL }
 
557
};
 
558
 
 
559
static GDBusSignalTable sink_signals[] = {
 
560
        { "Connected",                  "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
 
561
        { "Disconnected",               "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
 
562
        { "Playing",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
 
563
        { "Stopped",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
 
564
        { "PropertyChanged",            "sv"    },
 
565
        { NULL, NULL }
 
566
};
 
567
 
 
568
static void sink_free(struct audio_device *dev)
 
569
{
 
570
        struct sink *sink = dev->sink;
 
571
 
 
572
        if (sink->cb_id)
 
573
                avdtp_stream_remove_cb(sink->session, sink->stream,
 
574
                                        sink->cb_id);
 
575
 
 
576
        if (sink->session)
 
577
                avdtp_unref(sink->session);
 
578
 
 
579
        if (sink->connect)
 
580
                pending_request_free(sink->connect);
 
581
 
 
582
        if (sink->disconnect)
 
583
                pending_request_free(sink->disconnect);
 
584
 
 
585
        g_free(sink);
 
586
        dev->sink = NULL;
 
587
}
 
588
 
 
589
static void path_unregister(void *data)
 
590
{
 
591
        struct audio_device *dev = data;
 
592
 
 
593
        info("Unregistered interface %s on path %s",
 
594
                AUDIO_SINK_INTERFACE, dev->path);
 
595
 
 
596
        sink_free(dev);
 
597
}
 
598
 
 
599
void sink_unregister(struct audio_device *dev)
 
600
{
 
601
        g_dbus_unregister_interface(dev->conn, dev->path,
 
602
                AUDIO_SINK_INTERFACE);
 
603
}
 
604
 
 
605
struct sink *sink_init(struct audio_device *dev)
 
606
{
 
607
        if (!g_dbus_register_interface(dev->conn, dev->path,
 
608
                                        AUDIO_SINK_INTERFACE,
 
609
                                        sink_methods, sink_signals, NULL,
 
610
                                        dev, path_unregister))
 
611
                return NULL;
 
612
 
 
613
        info("Registered interface %s on path %s",
 
614
                AUDIO_SINK_INTERFACE, dev->path);
 
615
 
 
616
        return g_new0(struct sink, 1);
 
617
}
 
618
 
 
619
gboolean sink_is_active(struct audio_device *dev)
 
620
{
 
621
        struct sink *sink = dev->sink;
 
622
 
 
623
        if (sink->session)
 
624
                return TRUE;
 
625
 
 
626
        return FALSE;
 
627
}
 
628
 
 
629
avdtp_state_t sink_get_state(struct audio_device *dev)
 
630
{
 
631
        struct sink *sink = dev->sink;
 
632
 
 
633
        return sink->state;
 
634
}
 
635
 
 
636
gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
 
637
                                struct avdtp_stream *stream)
 
638
{
 
639
        struct sink *sink = dev->sink;
 
640
 
 
641
        if (sink->stream)
 
642
                return FALSE;
 
643
 
 
644
        if (!sink->session)
 
645
                sink->session = avdtp_ref(session);
 
646
 
 
647
        sink->stream = stream;
 
648
 
 
649
        sink->cb_id = avdtp_stream_add_cb(session, stream,
 
650
                                                stream_state_changed, dev);
 
651
 
 
652
        return TRUE;
 
653
}