OSDN Git Service

7f4971bbead3cafc741fd2d93904bed9a89f9a05
[android-x86/external-bluetooth-bluez.git] / utils / audio / a2dp.c
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 <stdlib.h>
30 #include <errno.h>
31
32 #include <dbus/dbus.h>
33 #include <glib.h>
34
35 #include <bluetooth/bluetooth.h>
36 #include <bluetooth/sdp.h>
37 #include <bluetooth/sdp_lib.h>
38
39 #include "logging.h"
40 #include "device.h"
41 #include "manager.h"
42 #include "avdtp.h"
43 #include "sink.h"
44 #include "a2dp.h"
45 #include "sdpd.h"
46
47 /* The duration that streams without users are allowed to stay in
48  * STREAMING state. */
49 #define SUSPEND_TIMEOUT 5000
50 #define RECONFIGURE_TIMEOUT 500
51
52 #ifndef MIN
53 # define MIN(x, y) ((x) < (y) ? (x) : (y))
54 #endif
55
56 #ifndef MAX
57 # define MAX(x, y) ((x) > (y) ? (x) : (y))
58 #endif
59
60 struct a2dp_sep {
61         uint8_t type;
62         uint8_t codec;
63         struct avdtp_local_sep *sep;
64         struct avdtp *session;
65         struct avdtp_stream *stream;
66         guint suspend_timer;
67         gboolean locked;
68         gboolean suspending;
69         gboolean starting;
70 };
71
72 struct a2dp_setup_cb {
73         a2dp_config_cb_t config_cb;
74         a2dp_stream_cb_t resume_cb;
75         a2dp_stream_cb_t suspend_cb;
76         void *user_data;
77         int id;
78 };
79
80 struct a2dp_setup {
81         struct avdtp *session;
82         struct a2dp_sep *sep;
83         struct avdtp_stream *stream;
84         struct avdtp_error *err;
85         GSList *client_caps;
86         gboolean reconfigure;
87         gboolean canceled;
88         gboolean start;
89         GSList *cb;
90         int ref;
91 };
92
93 static DBusConnection *connection = NULL;
94
95 static GSList *sinks = NULL;
96 static GSList *sources = NULL;
97
98 static uint32_t source_record_id = 0;
99 static uint32_t sink_record_id = 0;
100
101 static GSList *setups = NULL;
102 static unsigned int cb_id = 0;
103
104 static struct a2dp_setup *setup_ref(struct a2dp_setup *setup)
105 {
106         setup->ref++;
107
108         debug("setup_ref(%p): ref=%d", setup, setup->ref);
109
110         return setup;
111 }
112
113 static void setup_free(struct a2dp_setup *s)
114 {
115         debug("setup_free(%p)", s);
116         setups = g_slist_remove(setups, s);
117         if (s->session)
118                 avdtp_unref(s->session);
119         g_slist_foreach(s->cb, (GFunc) g_free, NULL);
120         g_slist_free(s->cb);
121         g_free(s);
122 }
123
124 static void setup_unref(struct a2dp_setup *setup)
125 {
126         setup->ref--;
127
128         debug("setup_unref(%p): ref=%d", setup, setup->ref);
129
130         if (setup->ref <= 0)
131                 setup_free(setup);
132 }
133
134 static struct audio_device *a2dp_get_dev(struct avdtp *session)
135 {
136         bdaddr_t addr;
137
138         avdtp_get_peers(session, NULL, &addr);
139
140         return manager_device_connected(&addr, A2DP_SOURCE_UUID);
141 }
142
143 static gboolean finalize_config(struct a2dp_setup *s)
144 {
145         GSList *l;
146
147         setup_ref(s);
148         for (l = s->cb; l != NULL; l = l->next) {
149                 struct a2dp_setup_cb *cb = l->data;
150
151                 if (cb->config_cb) {
152                         cb->config_cb(s->session, s->sep, s->stream, s->err,
153                                         cb->user_data);
154                         cb->config_cb = NULL;
155                         setup_unref(s);
156                 }
157         }
158
159         setup_unref(s);
160         return FALSE;
161 }
162
163 static gboolean finalize_config_errno(struct a2dp_setup *s, int err)
164 {
165         struct avdtp_error avdtp_err;
166
167         avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
168         s->err = err ? &avdtp_err : NULL;
169
170         return finalize_config(s);
171 }
172
173 static gboolean finalize_resume(struct a2dp_setup *s)
174 {
175         GSList *l;
176
177         setup_ref(s);
178         for (l = s->cb; l != NULL; l = l->next) {
179                 struct a2dp_setup_cb *cb = l->data;
180
181                 if (cb && cb->resume_cb) {
182                         cb->resume_cb(s->session, s->err, cb->user_data);
183                         cb->resume_cb = NULL;
184                         setup_unref(s);
185                 }
186         }
187
188         setup_unref(s);
189         return FALSE;
190 }
191
192 static gboolean finalize_resume_errno(struct a2dp_setup *s, int err)
193 {
194         struct avdtp_error avdtp_err;
195
196         avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
197         s->err = err ? &avdtp_err : NULL;
198
199         return finalize_resume(s);
200 }
201
202 static gboolean finalize_suspend(struct a2dp_setup *s)
203 {
204         GSList *l;
205
206         setup_ref(s);
207         for (l = s->cb; l != NULL; l = l->next) {
208                 struct a2dp_setup_cb *cb = l->data;
209
210                 if (cb->suspend_cb) {
211                         cb->suspend_cb(s->session, s->err, cb->user_data);
212                         cb->suspend_cb = NULL;
213                         setup_unref(s);
214                 }
215         }
216
217         setup_unref(s);
218         return FALSE;
219 }
220
221 static gboolean finalize_suspend_errno(struct a2dp_setup *s, int err)
222 {
223         struct avdtp_error avdtp_err;
224
225         avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
226         s->err = err ? &avdtp_err : NULL;
227
228         return finalize_suspend(s);
229 }
230
231 static struct a2dp_setup *find_setup_by_session(struct avdtp *session)
232 {
233         GSList *l;
234
235         for (l = setups; l != NULL; l = l->next) {
236                 struct a2dp_setup *setup = l->data;
237
238                 if (setup->session == session)
239                         return setup;
240         }
241
242         return NULL;
243 }
244
245 static struct a2dp_setup *find_setup_by_dev(struct audio_device *dev)
246 {
247         GSList *l;
248
249         for (l = setups; l != NULL; l = l->next) {
250                 struct a2dp_setup *setup = l->data;
251                 struct audio_device *setup_dev = a2dp_get_dev(setup->session);
252
253                 if (setup_dev == dev)
254                         return setup;
255         }
256
257         return NULL;
258 }
259
260 static void stream_state_changed(struct avdtp_stream *stream,
261                                         avdtp_state_t old_state,
262                                         avdtp_state_t new_state,
263                                         struct avdtp_error *err,
264                                         void *user_data)
265 {
266         struct a2dp_sep *sep = user_data;
267
268         if (new_state != AVDTP_STATE_IDLE)
269                 return;
270
271         if (sep->suspend_timer) {
272                 g_source_remove(sep->suspend_timer);
273                 sep->suspend_timer = 0;
274         }
275
276         if (sep->session) {
277                 avdtp_unref(sep->session);
278                 sep->session = NULL;
279         }
280
281         sep->stream = NULL;
282
283 }
284
285 static gboolean sbc_setconf_ind(struct avdtp *session,
286                                 struct avdtp_local_sep *sep,
287                                 struct avdtp_stream *stream,
288                                 GSList *caps, uint8_t *err,
289                                 uint8_t *category, void *user_data)
290 {
291         struct a2dp_sep *a2dp_sep = user_data;
292         struct audio_device *dev;
293         struct avdtp_service_capability *cap;
294         struct avdtp_media_codec_capability *codec_cap;
295         struct sbc_codec_cap *sbc_cap;
296
297         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
298                 debug("Sink %p: Set_Configuration_Ind", sep);
299         else
300                 debug("Source %p: Set_Configuration_Ind", sep);
301
302         dev = a2dp_get_dev(session);
303         if (!dev) {
304                 *err = AVDTP_UNSUPPORTED_CONFIGURATION;
305                 *category = 0x00;
306                 return FALSE;
307         }
308
309         /* Check bipool range */
310         for (codec_cap = NULL; caps; caps = g_slist_next(caps)) {
311                 cap = caps->data;
312                 if (cap->category == AVDTP_MEDIA_CODEC) {
313                         codec_cap = (void *) cap->data;
314                         if (codec_cap->media_codec_type == A2DP_CODEC_SBC) {
315                                 sbc_cap = (void *) codec_cap;
316                                 if (sbc_cap->min_bitpool < MIN_BITPOOL ||
317                                         sbc_cap->max_bitpool > MAX_BITPOOL) {
318                                         *err = AVDTP_UNSUPPORTED_CONFIGURATION;
319                                         *category = AVDTP_MEDIA_CODEC;
320                                         return FALSE;
321                                 }
322                         }
323                         break;
324                 }
325         }
326
327         avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
328         a2dp_sep->stream = stream;
329
330         if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
331                 sink_new_stream(dev, session, stream);
332
333         return TRUE;
334 }
335
336 static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
337                                 GSList **caps, uint8_t *err, void *user_data)
338 {
339         struct a2dp_sep *a2dp_sep = user_data;
340         struct avdtp_service_capability *media_transport, *media_codec;
341         struct sbc_codec_cap sbc_cap;
342
343         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
344                 debug("Sink %p: Get_Capability_Ind", sep);
345         else
346                 debug("Source %p: Get_Capability_Ind", sep);
347
348         *caps = NULL;
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         memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap));
356
357         sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
358         sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
359
360 #ifdef ANDROID
361         sbc_cap.frequency = SBC_SAMPLING_FREQ_44100;
362 #else
363         sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 |
364                                 SBC_SAMPLING_FREQ_44100 |
365                                 SBC_SAMPLING_FREQ_32000 |
366                                 SBC_SAMPLING_FREQ_16000 );
367 #endif
368
369         sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO |
370                                         SBC_CHANNEL_MODE_STEREO |
371                                         SBC_CHANNEL_MODE_DUAL_CHANNEL |
372                                         SBC_CHANNEL_MODE_MONO );
373
374         sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 |
375                                         SBC_BLOCK_LENGTH_12 |
376                                         SBC_BLOCK_LENGTH_8 |
377                                         SBC_BLOCK_LENGTH_4 );
378
379         sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 );
380
381         sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS |
382                                         SBC_ALLOCATION_SNR );
383
384         sbc_cap.min_bitpool = MIN_BITPOOL;
385         sbc_cap.max_bitpool = MAX_BITPOOL;
386
387         media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
388                                                 sizeof(sbc_cap));
389
390         *caps = g_slist_append(*caps, media_codec);
391
392         return TRUE;
393 }
394
395 static gboolean mpeg_setconf_ind(struct avdtp *session,
396                                 struct avdtp_local_sep *sep,
397                                 struct avdtp_stream *stream,
398                                 GSList *caps, uint8_t *err,
399                                 uint8_t *category, void *user_data)
400 {
401         struct a2dp_sep *a2dp_sep = user_data;
402         struct audio_device *dev;
403
404         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
405                 debug("Sink %p: Set_Configuration_Ind", sep);
406         else
407                 debug("Source %p: Set_Configuration_Ind", sep);
408
409         dev = a2dp_get_dev(session);
410         if (!dev) {
411                 *err = AVDTP_UNSUPPORTED_CONFIGURATION;
412                 *category = 0x00;
413                 return FALSE;
414         }
415
416         avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
417         a2dp_sep->stream = stream;
418
419         if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
420                 sink_new_stream(dev, session, stream);
421
422         return TRUE;
423 }
424
425 static gboolean mpeg_getcap_ind(struct avdtp *session,
426                                 struct avdtp_local_sep *sep,
427                                 GSList **caps, uint8_t *err, void *user_data)
428 {
429         struct a2dp_sep *a2dp_sep = user_data;
430         struct avdtp_service_capability *media_transport, *media_codec;
431         struct mpeg_codec_cap mpeg_cap;
432
433         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
434                 debug("Sink %p: Get_Capability_Ind", sep);
435         else
436                 debug("Source %p: Get_Capability_Ind", sep);
437
438         *caps = NULL;
439
440         media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
441                                                 NULL, 0);
442
443         *caps = g_slist_append(*caps, media_transport);
444
445         memset(&mpeg_cap, 0, sizeof(struct mpeg_codec_cap));
446
447         mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
448         mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
449
450         mpeg_cap.frequency = ( MPEG_SAMPLING_FREQ_48000 |
451                                 MPEG_SAMPLING_FREQ_44100 |
452                                 MPEG_SAMPLING_FREQ_32000 |
453                                 MPEG_SAMPLING_FREQ_24000 |
454                                 MPEG_SAMPLING_FREQ_22050 |
455                                 MPEG_SAMPLING_FREQ_16000 );
456
457         mpeg_cap.channel_mode = ( MPEG_CHANNEL_MODE_JOINT_STEREO |
458                                         MPEG_CHANNEL_MODE_STEREO |
459                                         MPEG_CHANNEL_MODE_DUAL_CHANNEL |
460                                         MPEG_CHANNEL_MODE_MONO );
461
462         mpeg_cap.layer = ( MPEG_LAYER_MP3 | MPEG_LAYER_MP2 | MPEG_LAYER_MP1 );
463
464         mpeg_cap.bitrate = 0xFFFF;
465
466         media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
467                                                 sizeof(mpeg_cap));
468
469         *caps = g_slist_append(*caps, media_codec);
470
471         return TRUE;
472 }
473
474 static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
475                                 struct avdtp_stream *stream,
476                                 struct avdtp_error *err, void *user_data)
477 {
478         struct a2dp_sep *a2dp_sep = user_data;
479         struct a2dp_setup *setup;
480         struct audio_device *dev;
481         int ret;
482
483         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
484                 debug("Sink %p: Set_Configuration_Cfm", sep);
485         else
486                 debug("Source %p: Set_Configuration_Cfm", sep);
487
488         setup = find_setup_by_session(session);
489
490         if (err) {
491                 if (setup) {
492                         setup->err = err;
493                         finalize_config(setup);
494                 }
495                 return;
496         }
497
498         avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
499         a2dp_sep->stream = stream;
500
501         if (!setup)
502                 return;
503
504         dev = a2dp_get_dev(session);
505
506         /* Notify sink.c of the new stream */
507         sink_new_stream(dev, session, setup->stream);
508
509         ret = avdtp_open(session, stream);
510         if (ret < 0) {
511                 error("Error on avdtp_open %s (%d)", strerror(-ret),
512                                 -ret);
513                 setup->stream = NULL;
514                 finalize_config_errno(setup, ret);
515         }
516 }
517
518 static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
519                                 uint8_t *err, void *user_data)
520 {
521         struct a2dp_sep *a2dp_sep = user_data;
522
523         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
524                 debug("Sink %p: Get_Configuration_Ind");
525         else
526                 debug("Source %p: Get_Configuration_Ind");
527         return TRUE;
528 }
529
530 static void getconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
531                         struct avdtp_stream *stream, struct avdtp_error *err,
532                         void *user_data)
533 {
534         struct a2dp_sep *a2dp_sep = user_data;
535
536         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
537                 debug("Sink %p: Set_Configuration_Cfm", sep);
538         else
539                 debug("Source %p: Set_Configuration_Cfm", sep);
540 }
541
542 static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
543                                 struct avdtp_stream *stream, uint8_t *err,
544                                 void *user_data)
545 {
546         struct a2dp_sep *a2dp_sep = user_data;
547
548         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
549                 debug("Sink %p: Open_Ind", sep);
550         else
551                 debug("Source %p: Open_Ind", sep);
552         return TRUE;
553 }
554
555 static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
556                         struct avdtp_stream *stream, struct avdtp_error *err,
557                         void *user_data)
558 {
559         struct a2dp_sep *a2dp_sep = user_data;
560         struct a2dp_setup *setup;
561
562         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
563                 debug("Sink %p: Open_Cfm", sep);
564         else
565                 debug("Source %p: Open_Cfm", sep);
566
567         setup = find_setup_by_session(session);
568         if (!setup)
569                 return;
570
571         if (setup->canceled) {
572                 if (!err)
573                         avdtp_close(session, stream);
574                 setup_unref(setup);
575                 return;
576         }
577
578         if (setup->reconfigure)
579                 setup->reconfigure = FALSE;
580
581         if (err) {
582                 setup->stream = NULL;
583                 setup->err = err;
584                 finalize_config(setup);
585         }
586         else
587                 finalize_config_errno(setup, 0);
588 }
589
590 static gboolean suspend_timeout(struct a2dp_sep *sep)
591 {
592         if (avdtp_suspend(sep->session, sep->stream) == 0)
593                 sep->suspending = TRUE;
594
595         sep->suspend_timer = 0;
596
597         avdtp_unref(sep->session);
598         sep->session = NULL;
599
600         return FALSE;
601 }
602
603 static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
604                                 struct avdtp_stream *stream, uint8_t *err,
605                                 void *user_data)
606 {
607         struct a2dp_sep *a2dp_sep = user_data;
608
609         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
610                 debug("Sink %p: Start_Ind", sep);
611         else
612                 debug("Source %p: Start_Ind", sep);
613
614         if (!a2dp_sep->locked) {
615                 a2dp_sep->session = avdtp_ref(session);
616                 a2dp_sep->suspend_timer = g_timeout_add(SUSPEND_TIMEOUT,
617                                                 (GSourceFunc) suspend_timeout,
618                                                 a2dp_sep);
619         }
620
621         return TRUE;
622 }
623
624 static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
625                         struct avdtp_stream *stream, struct avdtp_error *err,
626                         void *user_data)
627 {
628         struct a2dp_sep *a2dp_sep = user_data;
629         struct a2dp_setup *setup;
630
631         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
632                 debug("Sink %p: Start_Cfm", sep);
633         else
634                 debug("Source %p: Start_Cfm", sep);
635
636         setup = find_setup_by_session(session);
637         if (!setup)
638                 return;
639
640         if (setup->canceled) {
641                 if (!err)
642                         avdtp_close(session, stream);
643                 setup_unref(setup);
644                 return;
645         }
646
647         if (err) {
648                 setup->stream = NULL;
649                 setup->err = err;
650                 finalize_resume(setup);
651         }
652         else
653                 finalize_resume_errno(setup, 0);
654 }
655
656 static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
657                                 struct avdtp_stream *stream, uint8_t *err,
658                                 void *user_data)
659 {
660         struct a2dp_sep *a2dp_sep = user_data;
661
662         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
663                 debug("Sink %p: Suspend_Ind", sep);
664         else
665                 debug("Source %p: Suspend_Ind", sep);
666
667         if (a2dp_sep->suspend_timer) {
668                 g_source_remove(a2dp_sep->suspend_timer);
669                 a2dp_sep->suspend_timer = 0;
670                 avdtp_unref(a2dp_sep->session);
671                 a2dp_sep->session = NULL;
672         }
673
674         return TRUE;
675 }
676
677 static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
678                         struct avdtp_stream *stream, struct avdtp_error *err,
679                         void *user_data)
680 {
681         struct a2dp_sep *a2dp_sep = user_data;
682         struct a2dp_setup *setup;
683         gboolean start;
684
685         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
686                 debug("Sink %p: Suspend_Cfm", sep);
687         else
688                 debug("Source %p: Suspend_Cfm", sep);
689
690         a2dp_sep->suspending = FALSE;
691
692         setup = find_setup_by_session(session);
693         if (!setup)
694                 return;
695
696         start = setup->start;
697         setup->start = FALSE;
698
699         if (err) {
700                 setup->stream = NULL;
701                 setup->err = err;
702                 finalize_suspend(setup);
703         }
704         else
705                 finalize_suspend_errno(setup, 0);
706
707         if (!start)
708                 return;
709
710         if (err) {
711                 setup->err = err;
712                 finalize_suspend(setup);
713         } else if (avdtp_start(session, a2dp_sep->stream) < 0) {
714                 struct avdtp_error start_err;
715                 error("avdtp_start failed");
716                 avdtp_error_init(&start_err, AVDTP_ERROR_ERRNO, EIO);
717                 setup->err = err;
718                 finalize_suspend(setup);
719         }
720 }
721
722 static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
723                                 struct avdtp_stream *stream, uint8_t *err,
724                                 void *user_data)
725 {
726         struct a2dp_sep *a2dp_sep = user_data;
727
728         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
729                 debug("Sink %p: Close_Ind", sep);
730         else
731                 debug("Source %p: Close_Ind", sep);
732
733         return TRUE;
734 }
735
736 static gboolean a2dp_reconfigure(gpointer data)
737 {
738         struct a2dp_setup *setup = data;
739         struct avdtp_local_sep *lsep;
740         struct avdtp_remote_sep *rsep;
741         struct avdtp_service_capability *cap;
742         struct avdtp_media_codec_capability *codec_cap = NULL;
743         GSList *l;
744         int posix_err;
745
746         for (l = setup->client_caps; l != NULL; l = l->next) {
747                 cap = l->data;
748
749                 if (cap->category != AVDTP_MEDIA_CODEC)
750                         continue;
751
752                 codec_cap = (void *) cap->data;
753                 break;
754         }
755
756         posix_err = avdtp_get_seps(setup->session, AVDTP_SEP_TYPE_SINK,
757                                         codec_cap->media_type,
758                                         codec_cap->media_codec_type,
759                                         &lsep, &rsep);
760         if (posix_err < 0) {
761                 error("No matching ACP and INT SEPs found");
762                 finalize_config_errno(setup, posix_err);
763         }
764
765         posix_err = avdtp_set_configuration(setup->session, rsep, lsep,
766                                                 setup->client_caps,
767                                                 &setup->stream);
768         if (posix_err < 0) {
769                 error("avdtp_set_configuration: %s",
770                         strerror(-posix_err));
771                 finalize_config_errno(setup, posix_err);
772         }
773
774         return FALSE;
775 }
776
777 static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
778                         struct avdtp_stream *stream, struct avdtp_error *err,
779                         void *user_data)
780 {
781         struct a2dp_sep *a2dp_sep = user_data;
782         struct a2dp_setup *setup;
783
784         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
785                 debug("Sink %p: Close_Cfm", sep);
786         else
787                 debug("Source %p: Close_Cfm", sep);
788
789         setup = find_setup_by_session(session);
790         if (!setup)
791                 return;
792
793         if (setup->canceled) {
794                 setup_unref(setup);
795                 return;
796         }
797
798         if (err) {
799                 setup->stream = NULL;
800                 setup->err = err;
801                 finalize_config(setup);
802                 return;
803         }
804
805         if (setup->reconfigure)
806                 g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
807 }
808
809 static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
810                                 struct avdtp_stream *stream, uint8_t *err,
811                                 void *user_data)
812 {
813         struct a2dp_sep *a2dp_sep = user_data;
814
815         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
816                 debug("Sink %p: Abort_Ind", sep);
817         else
818                 debug("Source %p: Abort_Ind", sep);
819
820         a2dp_sep->stream = NULL;
821
822         return TRUE;
823 }
824
825 static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
826                         struct avdtp_stream *stream, struct avdtp_error *err,
827                         void *user_data)
828 {
829         struct a2dp_sep *a2dp_sep = user_data;
830         struct a2dp_setup *setup;
831
832         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
833                 debug("Sink %p: Abort_Cfm", sep);
834         else
835                 debug("Source %p: Abort_Cfm", sep);
836
837         setup = find_setup_by_session(session);
838         if (!setup)
839                 return;
840
841         setup_unref(setup);
842 }
843
844 static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
845                                 uint8_t *err, void *user_data)
846 {
847         struct a2dp_sep *a2dp_sep = user_data;
848
849         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
850                 debug("Sink %p: ReConfigure_Ind", sep);
851         else
852                 debug("Source %p: ReConfigure_Ind", sep);
853         return TRUE;
854 }
855
856 static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
857                         struct avdtp_stream *stream, struct avdtp_error *err,
858                         void *user_data)
859 {
860         struct a2dp_sep *a2dp_sep = user_data;
861         struct a2dp_setup *setup;
862
863         if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
864                 debug("Sink %p: ReConfigure_Cfm", sep);
865         else
866                 debug("Source %p: ReConfigure_Cfm", sep);
867
868         setup = find_setup_by_session(session);
869         if (!setup)
870                 return;
871
872         if (setup->canceled) {
873                 if (!err)
874                         avdtp_close(session, stream);
875                 setup_unref(setup);
876                 return;
877         }
878
879         if (err) {
880                 setup->stream = NULL;
881                 setup->err = err;
882                 finalize_config(setup);
883         }
884         else
885                 finalize_config_errno(setup, 0);
886 }
887
888 static struct avdtp_sep_cfm cfm = {
889         .set_configuration      = setconf_cfm,
890         .get_configuration      = getconf_cfm,
891         .open                   = open_cfm,
892         .start                  = start_cfm,
893         .suspend                = suspend_cfm,
894         .close                  = close_cfm,
895         .abort                  = abort_cfm,
896         .reconfigure            = reconf_cfm
897 };
898
899 static struct avdtp_sep_ind sbc_ind = {
900         .get_capability         = sbc_getcap_ind,
901         .set_configuration      = sbc_setconf_ind,
902         .get_configuration      = getconf_ind,
903         .open                   = open_ind,
904         .start                  = start_ind,
905         .suspend                = suspend_ind,
906         .close                  = close_ind,
907         .abort                  = abort_ind,
908         .reconfigure            = reconf_ind
909 };
910
911 static struct avdtp_sep_ind mpeg_ind = {
912         .get_capability         = mpeg_getcap_ind,
913         .set_configuration      = mpeg_setconf_ind,
914         .get_configuration      = getconf_ind,
915         .open                   = open_ind,
916         .start                  = start_ind,
917         .suspend                = suspend_ind,
918         .close                  = close_ind,
919         .abort                  = abort_ind,
920         .reconfigure            = reconf_ind
921 };
922
923 static sdp_record_t *a2dp_source_record()
924 {
925         sdp_list_t *svclass_id, *pfseq, *apseq, *root;
926         uuid_t root_uuid, l2cap, avdtp, a2src;
927         sdp_profile_desc_t profile[1];
928         sdp_list_t *aproto, *proto[2];
929         sdp_record_t *record;
930         sdp_data_t *psm, *version, *features;
931         uint16_t lp = AVDTP_UUID, ver = 0x0100, feat = 0x000F;
932
933         record = sdp_record_alloc();
934         if (!record)
935                 return NULL;
936
937         sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
938         root = sdp_list_append(0, &root_uuid);
939         sdp_set_browse_groups(record, root);
940
941         sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
942         svclass_id = sdp_list_append(0, &a2src);
943         sdp_set_service_classes(record, svclass_id);
944
945         sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
946         profile[0].version = 0x0100;
947         pfseq = sdp_list_append(0, &profile[0]);
948         sdp_set_profile_descs(record, pfseq);
949
950         sdp_uuid16_create(&l2cap, L2CAP_UUID);
951         proto[0] = sdp_list_append(0, &l2cap);
952         psm = sdp_data_alloc(SDP_UINT16, &lp);
953         proto[0] = sdp_list_append(proto[0], psm);
954         apseq = sdp_list_append(0, proto[0]);
955
956         sdp_uuid16_create(&avdtp, AVDTP_UUID);
957         proto[1] = sdp_list_append(0, &avdtp);
958         version = sdp_data_alloc(SDP_UINT16, &ver);
959         proto[1] = sdp_list_append(proto[1], version);
960         apseq = sdp_list_append(apseq, proto[1]);
961
962         aproto = sdp_list_append(0, apseq);
963         sdp_set_access_protos(record, aproto);
964
965         features = sdp_data_alloc(SDP_UINT16, &feat);
966         sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
967
968         sdp_set_info_attr(record, "Audio Source", 0, 0);
969
970         free(psm);
971         free(version);
972         sdp_list_free(proto[0], 0);
973         sdp_list_free(proto[1], 0);
974         sdp_list_free(apseq, 0);
975         sdp_list_free(pfseq, 0);
976         sdp_list_free(aproto, 0);
977         sdp_list_free(root, 0);
978         sdp_list_free(svclass_id, 0);
979
980         return record;
981 }
982
983 static sdp_record_t *a2dp_sink_record()
984 {
985         return NULL;
986 }
987
988 static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
989                                         uint8_t codec)
990 {
991         struct a2dp_sep *sep;
992         GSList **l;
993         sdp_record_t *(*create_record)(void);
994         uint32_t *record_id;
995         sdp_record_t *record;
996         struct avdtp_sep_ind *ind;
997
998         sep = g_new0(struct a2dp_sep, 1);
999
1000         ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
1001         sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO, codec,
1002                                         ind, &cfm, sep);
1003         if (sep->sep == NULL) {
1004                 g_free(sep);
1005                 return NULL;
1006         }
1007
1008         sep->codec = codec;
1009         sep->type = type;
1010
1011         if (type == AVDTP_SEP_TYPE_SOURCE) {
1012                 l = &sources;
1013                 create_record = a2dp_source_record;
1014                 record_id = &source_record_id;
1015         } else {
1016                 l = &sinks;
1017                 create_record = a2dp_sink_record;
1018                 record_id = &sink_record_id;
1019         }
1020
1021         if (*record_id != 0)
1022                 goto add;
1023
1024         record = create_record();
1025         if (!record) {
1026                 error("Unable to allocate new service record");
1027                 avdtp_unregister_sep(sep->sep);
1028                 g_free(sep);
1029                 return NULL;
1030         }
1031
1032         if (add_record_to_server(BDADDR_ANY, record) < 0) {
1033                 error("Unable to register A2DP service record");\
1034                 sdp_record_free(record);
1035                 avdtp_unregister_sep(sep->sep);
1036                 g_free(sep);
1037                 return NULL;
1038         }
1039         *record_id = record->handle;
1040
1041 add:
1042         *l = g_slist_append(*l, sep);
1043
1044         return sep;
1045 }
1046
1047 int a2dp_init(DBusConnection *conn, GKeyFile *config)
1048 {
1049         int sbc_srcs = 1, sbc_sinks = 0;
1050         int mpeg12_srcs = 0, mpeg12_sinks = 0;
1051         gboolean source = TRUE, sink = TRUE;
1052         char *str;
1053         GError *err = NULL;
1054         int i;
1055
1056         if (!config)
1057                 goto proceed;
1058
1059         str = g_key_file_get_string(config, "General", "Disable", &err);
1060
1061         if (err) {
1062                 debug("audio.conf: %s", err->message);
1063                 g_error_free(err);
1064                 err = NULL;
1065         } else {
1066                 if (strstr(str, "Sink"))
1067                         source = FALSE;
1068                 if (strstr(str, "Source"))
1069                         sink = FALSE;
1070                 g_free(str);
1071         }
1072
1073         str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
1074         if (err) {
1075                 debug("audio.conf: %s", err->message);
1076                 g_error_free(err);
1077                 err = NULL;
1078         } else {
1079                 sbc_srcs = atoi(str);
1080                 g_free(str);
1081         }
1082
1083         str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
1084         if (err) {
1085                 debug("audio.conf: %s", err->message);
1086                 g_error_free(err);
1087                 err = NULL;
1088         } else {
1089                 mpeg12_srcs = atoi(str);
1090                 g_free(str);
1091         }
1092
1093         str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
1094         if (err) {
1095                 debug("audio.conf: %s", err->message);
1096                 g_error_free(err);
1097                 err = NULL;
1098         } else {
1099                 sbc_sinks = atoi(str);
1100                 g_free(str);
1101         }
1102
1103         str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
1104         if (err) {
1105                 debug("audio.conf: %s", err->message);
1106                 g_error_free(err);
1107                 err = NULL;
1108         } else {
1109                 mpeg12_sinks = atoi(str);
1110                 g_free(str);
1111         }
1112
1113 proceed:
1114         connection = dbus_connection_ref(conn);
1115
1116         avdtp_init(config);
1117
1118         if (source) {
1119                 for (i = 0; i < sbc_srcs; i++)
1120                         a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE,
1121                                         A2DP_CODEC_SBC);
1122
1123                 for (i = 0; i < mpeg12_srcs; i++)
1124                         a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE,
1125                                         A2DP_CODEC_MPEG12);
1126         }
1127
1128         if (sink) {
1129                 for (i = 0; i < sbc_sinks; i++)
1130                         a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK,
1131                                         A2DP_CODEC_SBC);
1132
1133                 for (i = 0; i < mpeg12_sinks; i++)
1134                         a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK,
1135                                         A2DP_CODEC_MPEG12);
1136         }
1137
1138         return 0;
1139 }
1140
1141 static void a2dp_unregister_sep(struct a2dp_sep *sep)
1142 {
1143         avdtp_unregister_sep(sep->sep);
1144         g_free(sep);
1145 }
1146
1147 void a2dp_exit()
1148 {
1149         g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL);
1150         g_slist_free(sinks);
1151         sinks = NULL;
1152
1153         g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL);
1154         g_slist_free(sources);
1155         sources = NULL;
1156
1157         if (source_record_id) {
1158                 remove_record_from_server(source_record_id);
1159                 source_record_id = 0;
1160         }
1161
1162         if (sink_record_id) {
1163                 remove_record_from_server(sink_record_id);
1164                 sink_record_id = 0;
1165         }
1166
1167         dbus_connection_unref(connection);
1168 }
1169
1170 gboolean a2dp_source_cancel(struct audio_device *dev, unsigned int id)
1171 {
1172         struct a2dp_setup_cb *cb_data;
1173         struct a2dp_setup *setup;
1174         GSList *l;
1175
1176         setup = find_setup_by_dev(dev);
1177         if (!setup)
1178                 return FALSE;
1179
1180         for (cb_data = NULL, l = setup->cb; l != NULL; l = g_slist_next(l)) {
1181                 struct a2dp_setup_cb *cb = l->data;
1182
1183                 if (cb->id == id) {
1184                         cb_data = cb;
1185                         break;
1186                 }
1187         }
1188
1189         if (!cb_data)
1190                 return FALSE;
1191
1192         setup->cb = g_slist_remove(setup->cb, cb_data);
1193         g_free(cb_data);
1194
1195         if (!setup->cb) {
1196                 setup->canceled = TRUE;
1197                 setup->sep = NULL;
1198         }
1199
1200         return TRUE;
1201 }
1202
1203 unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
1204                                 GSList *caps, void *user_data)
1205 {
1206         struct a2dp_setup_cb *cb_data;
1207         GSList *l;
1208         struct a2dp_setup *setup;
1209         struct a2dp_sep *sep = NULL, *tmp;
1210         struct avdtp_local_sep *lsep;
1211         struct avdtp_remote_sep *rsep;
1212         struct avdtp_service_capability *cap;
1213         struct avdtp_media_codec_capability *codec_cap = NULL;
1214         int posix_err;
1215
1216         for (l = caps; l != NULL; l = l->next) {
1217                 cap = l->data;
1218
1219                 if (cap->category != AVDTP_MEDIA_CODEC)
1220                         continue;
1221
1222                 codec_cap = (void *) cap->data;
1223                 break;
1224         }
1225
1226         if (!codec_cap)
1227                 return 0;
1228
1229         for (l = sources; l != NULL; l = l->next) {
1230                 tmp = l->data;
1231
1232                 if (tmp->locked)
1233                         continue;
1234
1235                 if (tmp->codec != codec_cap->media_codec_type)
1236                         continue;
1237
1238                 if (!tmp->stream || avdtp_has_stream(session, tmp->stream)) {
1239                         sep = tmp;
1240                         break;
1241                 }
1242         }
1243
1244         if (!sep) {
1245                 error("a2dp_source_cfg: no available SEP found");
1246                 return 0;
1247         }
1248
1249         debug("a2dp_source_config: selected SEP %p", sep->sep);
1250
1251         cb_data = g_new0(struct a2dp_setup_cb, 1);
1252         cb_data->config_cb = cb;
1253         cb_data->user_data = user_data;
1254         cb_data->id = ++cb_id;
1255
1256         setup = find_setup_by_session(session);
1257         if (!setup) {
1258                 setup = g_new0(struct a2dp_setup, 1);
1259                 setup->session = avdtp_ref(session);
1260                 setups = g_slist_append(setups, setup);
1261         }
1262
1263         setup_ref(setup);
1264         setup->cb = g_slist_append(setup->cb, cb_data);
1265         setup->sep = sep;
1266         setup->stream = sep->stream;
1267         setup->client_caps = caps;
1268
1269         switch (avdtp_sep_get_state(sep->sep)) {
1270         case AVDTP_STATE_IDLE:
1271                 for (l = sources; l != NULL; l = l->next) {
1272                         tmp = l->data;
1273
1274                         if (avdtp_has_stream(session, tmp->stream))
1275                                 break;
1276                 }
1277
1278                 if (l != NULL) {
1279                         setup->reconfigure = TRUE;
1280                         if (avdtp_close(session, tmp->stream) < 0) {
1281                                 error("avdtp_close failed");
1282                                 goto failed;
1283                         }
1284                         break;
1285                 }
1286
1287                 if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK,
1288                                 codec_cap->media_type,
1289                                 codec_cap->media_codec_type,
1290                                 &lsep, &rsep) < 0) {
1291                         error("No matching ACP and INT SEPs found");
1292                         goto failed;
1293                 }
1294
1295                 posix_err = avdtp_set_configuration(session, rsep, lsep,
1296                                                         caps, &setup->stream);
1297                 if (posix_err < 0) {
1298                         error("avdtp_set_configuration: %s",
1299                                 strerror(-posix_err));
1300                         goto failed;
1301                 }
1302                 break;
1303         case AVDTP_STATE_OPEN:
1304         case AVDTP_STATE_STREAMING:
1305                 if (avdtp_stream_has_capabilities(setup->stream, caps))
1306                         g_idle_add((GSourceFunc) finalize_config, setup);
1307                 else if (!setup->reconfigure) {
1308                         setup->reconfigure = TRUE;
1309                         if (avdtp_close(session, sep->stream) < 0) {
1310                                 error("avdtp_close failed");
1311                                 goto failed;
1312                         }
1313                 }
1314                 break;
1315         default:
1316                 error("SEP in bad state for requesting a new stream");
1317                 goto failed;
1318         }
1319
1320         return cb_data->id;
1321
1322 failed:
1323         setup_unref(setup);
1324         cb_id--;
1325         return 0;
1326 }
1327
1328 unsigned int a2dp_source_resume(struct avdtp *session, struct a2dp_sep *sep,
1329                                 a2dp_stream_cb_t cb, void *user_data)
1330 {
1331         struct a2dp_setup_cb *cb_data;
1332         struct a2dp_setup *setup;
1333
1334         cb_data = g_new0(struct a2dp_setup_cb, 1);
1335         cb_data->resume_cb = cb;
1336         cb_data->user_data = user_data;
1337         cb_data->id = ++cb_id;
1338
1339         setup = find_setup_by_session(session);
1340         if (!setup) {
1341                 setup = g_new0(struct a2dp_setup, 1);
1342                 setup->session = avdtp_ref(session);
1343                 setups = g_slist_append(setups, setup);
1344         }
1345
1346         setup_ref(setup);
1347         setup->cb = g_slist_append(setup->cb, cb_data);
1348         setup->sep = sep;
1349         setup->stream = sep->stream;
1350
1351         switch (avdtp_sep_get_state(sep->sep)) {
1352         case AVDTP_STATE_IDLE:
1353                 goto failed;
1354                 break;
1355         case AVDTP_STATE_OPEN:
1356                 if (avdtp_start(session, sep->stream) < 0) {
1357                         error("avdtp_start failed");
1358                         goto failed;
1359                 }
1360                 break;
1361         case AVDTP_STATE_STREAMING:
1362                 if (!sep->suspending && sep->suspend_timer) {
1363                         g_source_remove(sep->suspend_timer);
1364                         sep->suspend_timer = 0;
1365                         avdtp_unref(sep->session);
1366                         sep->session = NULL;
1367                 }
1368                 if (sep->suspending)
1369                         setup->start = TRUE;
1370                 else
1371                         g_idle_add((GSourceFunc) finalize_resume, setup);
1372                 break;
1373         default:
1374                 error("SEP in bad state");
1375                 goto failed;
1376         }
1377
1378         return cb_data->id;
1379
1380 failed:
1381         setup_unref(setup);
1382         cb_id--;
1383         return 0;
1384 }
1385
1386 unsigned int a2dp_source_suspend(struct avdtp *session, struct a2dp_sep *sep,
1387                                 a2dp_stream_cb_t cb, void *user_data)
1388 {
1389         struct a2dp_setup_cb *cb_data;
1390         struct a2dp_setup *setup;
1391
1392         cb_data = g_new0(struct a2dp_setup_cb, 1);
1393         cb_data->suspend_cb = cb;
1394         cb_data->user_data = user_data;
1395         cb_data->id = ++cb_id;
1396
1397         setup = find_setup_by_session(session);
1398         if (!setup) {
1399                 setup = g_new0(struct a2dp_setup, 1);
1400                 setup->session = avdtp_ref(session);
1401                 setups = g_slist_append(setups, setup);
1402         }
1403
1404         setup_ref(setup);
1405         setup->cb = g_slist_append(setup->cb, cb_data);
1406         setup->sep = sep;
1407         setup->stream = sep->stream;
1408
1409         switch (avdtp_sep_get_state(sep->sep)) {
1410         case AVDTP_STATE_IDLE:
1411                 error("a2dp_source_suspend: no stream to suspend");
1412                 goto failed;
1413                 break;
1414         case AVDTP_STATE_OPEN:
1415                 g_idle_add((GSourceFunc) finalize_suspend, setup);
1416                 break;
1417         case AVDTP_STATE_STREAMING:
1418                 if (avdtp_suspend(session, sep->stream) < 0) {
1419                         error("avdtp_suspend failed");
1420                         goto failed;
1421                 }
1422                 break;
1423         default:
1424                 error("SEP in bad state for resume");
1425                 goto failed;
1426         }
1427
1428         return cb_data->id;
1429
1430 failed:
1431         setup_unref(setup);
1432         cb_id--;
1433         return 0;
1434 }
1435
1436 gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session)
1437 {
1438         if (sep->locked)
1439                 return FALSE;
1440
1441         debug("SEP %p locked", sep->sep);
1442         sep->locked = TRUE;
1443
1444         return TRUE;
1445 }
1446
1447 gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session)
1448 {
1449         avdtp_state_t state;
1450
1451         state = avdtp_sep_get_state(sep->sep);
1452
1453         sep->locked = FALSE;
1454
1455         debug("SEP %p unlocked", sep->sep);
1456
1457         if (!sep->stream || state == AVDTP_STATE_IDLE)
1458                 return TRUE;
1459
1460         switch (state) {
1461         case AVDTP_STATE_OPEN:
1462                 /* Set timer here */
1463                 break;
1464         case AVDTP_STATE_STREAMING:
1465                 if (avdtp_suspend(session, sep->stream) == 0)
1466                         sep->suspending = TRUE;
1467                 break;
1468         default:
1469                 break;
1470         }
1471
1472         return TRUE;
1473 }