bluetooth: Fix SVACE defect (DEREF_OF_NULL.RET.STAT)
[platform/upstream/pulseaudio.git] / src / modules / bluetooth / bluez5-util.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2008-2013 João Paulo Rechi Vita
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <pulse/rtclock.h>
25 #include <pulse/timeval.h>
26 #include <pulse/xmalloc.h>
27
28 #include <pulsecore/core.h>
29 #include <pulsecore/core-util.h>
30 #include <pulsecore/dbus-shared.h>
31 #include <pulsecore/log.h>
32 #include <pulsecore/macro.h>
33 #include <pulsecore/refcnt.h>
34 #include <pulsecore/shared.h>
35
36 #include "a2dp-codecs.h"
37
38 #include "bluez5-util.h"
39
40 #define WAIT_FOR_PROFILES_TIMEOUT_USEC (3 * PA_USEC_PER_SEC)
41
42 #define BLUEZ_SERVICE "org.bluez"
43 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1"
44 #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1"
45 #define BLUEZ_MEDIA_INTERFACE BLUEZ_SERVICE ".Media1"
46 #define BLUEZ_MEDIA_ENDPOINT_INTERFACE BLUEZ_SERVICE ".MediaEndpoint1"
47 #define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
48
49 #define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
50
51 #define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
52 #define A2DP_SINK_ENDPOINT "/MediaEndpoint/A2DPSink"
53
54 #ifdef TIZEN_BT_A2DP_MULTISTREAM
55 #define A2DP_SINK_ENDPOINT2 "/MediaEndpoint/A2DPSink2"
56 #endif
57
58 #ifdef BLUETOOTH_APTX_SUPPORT
59 #define A2DP_APTX_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource_aptx"
60 #endif
61
62 #define ENDPOINT_INTROSPECT_XML                                         \
63     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                           \
64     "<node>"                                                            \
65     " <interface name=\"" BLUEZ_MEDIA_ENDPOINT_INTERFACE "\">"          \
66     "  <method name=\"SetConfiguration\">"                              \
67     "   <arg name=\"transport\" direction=\"in\" type=\"o\"/>"          \
68     "   <arg name=\"properties\" direction=\"in\" type=\"ay\"/>"        \
69     "  </method>"                                                       \
70     "  <method name=\"SelectConfiguration\">"                           \
71     "   <arg name=\"capabilities\" direction=\"in\" type=\"ay\"/>"      \
72     "   <arg name=\"configuration\" direction=\"out\" type=\"ay\"/>"    \
73     "  </method>"                                                       \
74     "  <method name=\"ClearConfiguration\">"                            \
75     "   <arg name=\"transport\" direction=\"in\" type=\"o\"/>"          \
76     "  </method>"                                                       \
77     "  <method name=\"Release\">"                                       \
78     "  </method>"                                                       \
79     "  <method name=\"SuspendMedia\">"                                  \
80     "  </method>"                                                       \
81     " </interface>"                                                     \
82     " <interface name=\"org.freedesktop.DBus.Introspectable\">"         \
83     "  <method name=\"Introspect\">"                                    \
84     "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"              \
85     "  </method>"                                                       \
86     " </interface>"                                                     \
87     "</node>"
88
89 struct pa_bluetooth_discovery {
90     PA_REFCNT_DECLARE;
91
92     pa_core *core;
93     pa_dbus_connection *connection;
94     bool filter_added;
95     bool matches_added;
96     bool objects_listed;
97     pa_hook hooks[PA_BLUETOOTH_HOOK_MAX];
98     pa_hashmap *adapters;
99     pa_hashmap *devices;
100     pa_hashmap *transports;
101
102     int headset_backend;
103     pa_bluetooth_backend *ofono_backend, *native_backend;
104     PA_LLIST_HEAD(pa_dbus_pending, pending);
105 };
106
107 static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m,
108                                                                   DBusPendingCallNotifyFunction func, void *call_data) {
109     pa_dbus_pending *p;
110     DBusPendingCall *call;
111
112     pa_assert(y);
113     pa_assert(m);
114
115     pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(y->connection), m, &call, -1));
116
117     p = pa_dbus_pending_new(pa_dbus_connection_get(y->connection), m, call, y, call_data);
118     PA_LLIST_PREPEND(pa_dbus_pending, y->pending, p);
119     dbus_pending_call_set_notify(call, func, p, NULL);
120
121     return p;
122 }
123
124 static const char *check_variant_property(DBusMessageIter *i) {
125     const char *key;
126
127     pa_assert(i);
128
129     if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
130         pa_log_error("Property name not a string.");
131         return NULL;
132     }
133
134     dbus_message_iter_get_basic(i, &key);
135
136     if (!dbus_message_iter_next(i)) {
137         pa_log_error("Property value missing");
138         return NULL;
139     }
140
141     if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
142         pa_log_error("Property value not a variant.");
143         return NULL;
144     }
145
146     return key;
147 }
148
149 pa_bluetooth_transport *pa_bluetooth_transport_new(pa_bluetooth_device *d, const char *owner, const char *path,
150                                                    pa_bluetooth_profile_t p, const uint8_t *config, size_t size) {
151     pa_bluetooth_transport *t;
152
153     t = pa_xnew0(pa_bluetooth_transport, 1);
154     t->device = d;
155     t->owner = pa_xstrdup(owner);
156     t->path = pa_xstrdup(path);
157     t->profile = p;
158     t->config_size = size;
159
160     if (size > 0) {
161         t->config = pa_xnew(uint8_t, size);
162         memcpy(t->config, config, size);
163     }
164
165     return t;
166 }
167
168 static const char *transport_state_to_string(pa_bluetooth_transport_state_t state) {
169     switch(state) {
170         case PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED:
171             return "disconnected";
172         case PA_BLUETOOTH_TRANSPORT_STATE_IDLE:
173             return "idle";
174         case PA_BLUETOOTH_TRANSPORT_STATE_PLAYING:
175             return "playing";
176     }
177
178     return "invalid";
179 }
180
181 static bool device_supports_profile(pa_bluetooth_device *device, pa_bluetooth_profile_t profile) {
182     switch (profile) {
183         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
184             return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SINK);
185         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
186             return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SOURCE);
187         case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
188             return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS)
189                 || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF);
190         case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
191             return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG)
192                 || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG);
193         case PA_BLUETOOTH_PROFILE_OFF:
194             pa_assert_not_reached();
195     }
196
197     pa_assert_not_reached();
198 }
199
200 static bool device_is_profile_connected(pa_bluetooth_device *device, pa_bluetooth_profile_t profile) {
201     if (device->transports[profile] && device->transports[profile]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
202         return true;
203     else
204         return false;
205 }
206
207 static unsigned device_count_disconnected_profiles(pa_bluetooth_device *device) {
208     pa_bluetooth_profile_t profile;
209     unsigned count = 0;
210
211     for (profile = 0; profile < PA_BLUETOOTH_PROFILE_COUNT; profile++) {
212         if (!device_supports_profile(device, profile))
213             continue;
214
215         if (!device_is_profile_connected(device, profile))
216             count++;
217     }
218
219     return count;
220 }
221
222 static void device_stop_waiting_for_profiles(pa_bluetooth_device *device) {
223     if (!device->wait_for_profiles_timer)
224         return;
225
226     device->discovery->core->mainloop->time_free(device->wait_for_profiles_timer);
227     device->wait_for_profiles_timer = NULL;
228 }
229
230 static void wait_for_profiles_cb(pa_mainloop_api *api, pa_time_event* event, const struct timeval *tv, void *userdata) {
231     pa_bluetooth_device *device = userdata;
232     pa_strbuf *buf;
233     pa_bluetooth_profile_t profile;
234     bool first = true;
235     char *profiles_str;
236
237     device_stop_waiting_for_profiles(device);
238
239     buf = pa_strbuf_new();
240
241     for (profile = 0; profile < PA_BLUETOOTH_PROFILE_COUNT; profile++) {
242         if (device_is_profile_connected(device, profile))
243             continue;
244
245         if (!device_supports_profile(device, profile))
246             continue;
247
248         if (first)
249             first = false;
250         else
251             pa_strbuf_puts(buf, ", ");
252
253         pa_strbuf_puts(buf, pa_bluetooth_profile_to_string(profile));
254     }
255
256     profiles_str = pa_strbuf_to_string_free(buf);
257     pa_log_debug("Timeout expired, and device %s still has disconnected profiles: %s",
258                  device->path, profiles_str);
259     pa_xfree(profiles_str);
260     pa_hook_fire(&device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], device);
261 }
262
263 static void device_start_waiting_for_profiles(pa_bluetooth_device *device) {
264     pa_assert(!device->wait_for_profiles_timer);
265     device->wait_for_profiles_timer = pa_core_rttime_new(device->discovery->core,
266                                                          pa_rtclock_now() + WAIT_FOR_PROFILES_TIMEOUT_USEC,
267                                                          wait_for_profiles_cb, device);
268 }
269
270 void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_transport_state_t state) {
271     bool old_any_connected;
272     unsigned n_disconnected_profiles;
273     bool new_device_appeared;
274     bool device_disconnected;
275
276     pa_assert(t);
277
278     if (t->state == state)
279         return;
280
281     old_any_connected = pa_bluetooth_device_any_transport_connected(t->device);
282
283     pa_log_debug("Transport %s state: %s -> %s",
284                  t->path, transport_state_to_string(t->state), transport_state_to_string(state));
285
286     t->state = state;
287
288     pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED], t);
289
290     /* If there are profiles that are expected to get connected soon (based
291      * on the UUID list), we wait for a bit before announcing the new
292      * device, so that all profiles have time to get connected before the
293      * card object is created. If we didn't wait, the card would always
294      * have only one profile marked as available in the initial state,
295      * which would prevent module-card-restore from restoring the initial
296      * profile properly. */
297
298     n_disconnected_profiles = device_count_disconnected_profiles(t->device);
299
300     new_device_appeared = !old_any_connected && pa_bluetooth_device_any_transport_connected(t->device);
301     device_disconnected = old_any_connected && !pa_bluetooth_device_any_transport_connected(t->device);
302
303     if (new_device_appeared) {
304         if (n_disconnected_profiles > 0)
305             device_start_waiting_for_profiles(t->device);
306         else
307             pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);
308         return;
309     }
310
311     if (device_disconnected) {
312         if (t->device->wait_for_profiles_timer) {
313             /* If the timer is still running when the device disconnects, we
314              * never sent the notification of the device getting connected, so
315              * we don't need to send a notification about the disconnection
316              * either. Let's just stop the timer. */
317             device_stop_waiting_for_profiles(t->device);
318         } else
319             pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);
320         return;
321     }
322
323     if (n_disconnected_profiles == 0 && t->device->wait_for_profiles_timer) {
324         /* All profiles are now connected, so we can stop the wait timer and
325          * send a notification of the new device. */
326         device_stop_waiting_for_profiles(t->device);
327         pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);
328     }
329 }
330
331 void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
332     pa_assert(t);
333
334     t->device->transports[t->profile] = t;
335     pa_assert_se(pa_hashmap_put(t->device->discovery->transports, t->path, t) >= 0);
336     pa_bluetooth_transport_set_state(t, PA_BLUETOOTH_TRANSPORT_STATE_IDLE);
337 }
338
339 void pa_bluetooth_transport_unlink(pa_bluetooth_transport *t) {
340     pa_assert(t);
341
342     pa_bluetooth_transport_set_state(t, PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED);
343     pa_hashmap_remove(t->device->discovery->transports, t->path);
344     t->device->transports[t->profile] = NULL;
345 }
346
347 void pa_bluetooth_transport_free(pa_bluetooth_transport *t) {
348     pa_assert(t);
349
350     if (t->destroy)
351         t->destroy(t);
352     pa_bluetooth_transport_unlink(t);
353
354     pa_xfree(t->owner);
355     pa_xfree(t->path);
356     pa_xfree(t->config);
357     pa_xfree(t);
358 }
359
360 static int bluez5_transport_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
361     DBusMessage *m, *r;
362     DBusError err;
363     int ret;
364     uint16_t i, o;
365     const char *method = optional ? "TryAcquire" : "Acquire";
366
367     pa_assert(t);
368     pa_assert(t->device);
369     pa_assert(t->device->discovery);
370
371     pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, BLUEZ_MEDIA_TRANSPORT_INTERFACE, method));
372
373     dbus_error_init(&err);
374
375     r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
376     dbus_message_unref(m);
377     m = NULL;
378     if (!r) {
379         if (optional && pa_streq(err.name, "org.bluez.Error.NotAvailable"))
380             pa_log_info("Failed optional acquire of unavailable transport %s", t->path);
381         else
382             pa_log_error("Transport %s() failed for transport %s (%s)", method, t->path, err.message);
383
384         dbus_error_free(&err);
385         return -1;
386     }
387
388     if (!dbus_message_get_args(r, &err, DBUS_TYPE_UNIX_FD, &ret, DBUS_TYPE_UINT16, &i, DBUS_TYPE_UINT16, &o,
389                                DBUS_TYPE_INVALID)) {
390         pa_log_error("Failed to parse %s() reply: %s", method, err.message);
391         dbus_error_free(&err);
392         ret = -1;
393         goto finish;
394     }
395
396     if (imtu)
397         *imtu = i;
398
399     if (omtu)
400         *omtu = o;
401
402 finish:
403     dbus_message_unref(r);
404     return ret;
405 }
406
407 static void bluez5_transport_release_cb(pa_bluetooth_transport *t) {
408     DBusMessage *m, *r;
409     DBusError err;
410
411     pa_assert(t);
412     pa_assert(t->device);
413     pa_assert(t->device->discovery);
414
415     dbus_error_init(&err);
416
417     if (t->state <= PA_BLUETOOTH_TRANSPORT_STATE_IDLE) {
418         pa_log_info("Transport %s auto-released by BlueZ or already released", t->path);
419         return;
420     }
421
422     pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, BLUEZ_MEDIA_TRANSPORT_INTERFACE, "Release"));
423     r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err);
424     dbus_message_unref(m);
425     m = NULL;
426     if (r) {
427         dbus_message_unref(r);
428         r = NULL;
429     }
430
431     if (dbus_error_is_set(&err)) {
432         pa_log_error("Failed to release transport %s: %s", t->path, err.message);
433         dbus_error_free(&err);
434     } else
435         pa_log_info("Transport %s released", t->path);
436 }
437
438 bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d) {
439     unsigned i;
440
441     pa_assert(d);
442
443     if (!d->valid)
444         return false;
445
446     for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++)
447         if (d->transports[i] && d->transports[i]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
448             return true;
449
450     return false;
451 }
452
453 #ifdef __TIZEN_BT__
454 bool pa_bluetooth_device_sink_transport_connected(const pa_bluetooth_device *d) {
455     unsigned i;
456
457     pa_assert(d);
458
459     if (!d->valid)
460         return false;
461
462     for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++)
463         if (d->transports[i] &&
464              d->transports[i]->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK &&
465               d->transports[i]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
466             return true;
467
468     return false;
469 }
470
471 bool pa_bluetooth_device_source_transport_connected(const pa_bluetooth_device *d) {
472     unsigned i;
473
474     pa_assert(d);
475
476     if (!d->valid)
477         return false;
478
479     for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++)
480         if (d->transports[i] &&
481              d->transports[i]->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE &&
482               d->transports[i]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
483             return true;
484
485     return false;
486 }
487 #endif
488
489 static int transport_state_from_string(const char* value, pa_bluetooth_transport_state_t *state) {
490     pa_assert(value);
491     pa_assert(state);
492
493     if (pa_streq(value, "idle"))
494         *state = PA_BLUETOOTH_TRANSPORT_STATE_IDLE;
495     else if (pa_streq(value, "pending") || pa_streq(value, "active"))
496         *state = PA_BLUETOOTH_TRANSPORT_STATE_PLAYING;
497     else
498         return -1;
499
500     return 0;
501 }
502
503 static void parse_transport_property(pa_bluetooth_transport *t, DBusMessageIter *i) {
504     const char *key;
505     DBusMessageIter variant_i;
506
507     key = check_variant_property(i);
508     if (key == NULL)
509         return;
510
511     dbus_message_iter_recurse(i, &variant_i);
512
513     switch (dbus_message_iter_get_arg_type(&variant_i)) {
514
515         case DBUS_TYPE_STRING: {
516
517             const char *value;
518             dbus_message_iter_get_basic(&variant_i, &value);
519
520             if (pa_streq(key, "State")) {
521                 pa_bluetooth_transport_state_t state;
522
523                 if (transport_state_from_string(value, &state) < 0) {
524                     pa_log_error("Invalid state received: %s", value);
525                     return;
526                 }
527
528                 pa_bluetooth_transport_set_state(t, state);
529             }
530
531             break;
532         }
533     }
534
535     return;
536 }
537
538 static int parse_transport_properties(pa_bluetooth_transport *t, DBusMessageIter *i) {
539     DBusMessageIter element_i;
540
541     dbus_message_iter_recurse(i, &element_i);
542
543     while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
544         DBusMessageIter dict_i;
545
546         dbus_message_iter_recurse(&element_i, &dict_i);
547
548         parse_transport_property(t, &dict_i);
549
550         dbus_message_iter_next(&element_i);
551     }
552
553     return 0;
554 }
555
556 static pa_bluetooth_device* device_create(pa_bluetooth_discovery *y, const char *path) {
557     pa_bluetooth_device *d;
558
559     pa_assert(y);
560     pa_assert(path);
561
562     d = pa_xnew0(pa_bluetooth_device, 1);
563     d->discovery = y;
564     d->path = pa_xstrdup(path);
565     d->uuids = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
566
567     pa_hashmap_put(y->devices, d->path, d);
568
569     return d;
570 }
571
572 pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_discovery *y, const char *path) {
573     pa_bluetooth_device *d;
574
575     pa_assert(y);
576     pa_assert(PA_REFCNT_VALUE(y) > 0);
577     pa_assert(path);
578
579     if ((d = pa_hashmap_get(y->devices, path)) && d->valid)
580         return d;
581
582     return NULL;
583 }
584
585 pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local) {
586     pa_bluetooth_device *d;
587     void *state = NULL;
588
589     pa_assert(y);
590     pa_assert(PA_REFCNT_VALUE(y) > 0);
591     pa_assert(remote);
592     pa_assert(local);
593
594     while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
595         if (d->valid && pa_streq(d->address, remote) && pa_streq(d->adapter->address, local))
596             return d;
597
598     return NULL;
599 }
600
601 static void device_free(pa_bluetooth_device *d) {
602     unsigned i;
603
604     pa_assert(d);
605
606     device_stop_waiting_for_profiles(d);
607
608     for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++) {
609         pa_bluetooth_transport *t;
610
611         if (!(t = d->transports[i]))
612             continue;
613
614         pa_bluetooth_transport_free(t);
615     }
616
617     if (d->uuids)
618         pa_hashmap_free(d->uuids);
619
620     pa_xfree(d->path);
621     pa_xfree(d->alias);
622     pa_xfree(d->address);
623     pa_xfree(d->adapter_path);
624     pa_xfree(d);
625 }
626
627 static void device_remove(pa_bluetooth_discovery *y, const char *path) {
628     pa_bluetooth_device *d;
629
630     if (!(d = pa_hashmap_remove(y->devices, path)))
631         pa_log_warn("Unknown device removed %s", path);
632     else {
633         pa_log_debug("Device %s removed", path);
634         device_free(d);
635     }
636 }
637
638 static void device_set_valid(pa_bluetooth_device *device, bool valid) {
639     bool old_any_connected;
640
641     pa_assert(device);
642
643     if (valid == device->valid)
644         return;
645
646     old_any_connected = pa_bluetooth_device_any_transport_connected(device);
647     device->valid = valid;
648
649     if (pa_bluetooth_device_any_transport_connected(device) != old_any_connected)
650         pa_hook_fire(&device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], device);
651 }
652
653 static void device_update_valid(pa_bluetooth_device *d) {
654     pa_assert(d);
655
656     if (!d->properties_received) {
657         pa_assert(!d->valid);
658         return;
659     }
660
661     /* Check if mandatory properties are set. */
662     if (!d->address || !d->adapter_path || !d->alias) {
663         device_set_valid(d, false);
664         return;
665     }
666
667     if (!d->adapter || !d->adapter->valid) {
668         device_set_valid(d, false);
669         return;
670     }
671
672     device_set_valid(d, true);
673 }
674
675 static void device_set_adapter(pa_bluetooth_device *device, pa_bluetooth_adapter *adapter) {
676     pa_assert(device);
677
678     if (adapter == device->adapter)
679         return;
680
681     device->adapter = adapter;
682
683     device_update_valid(device);
684 }
685
686 static pa_bluetooth_adapter* adapter_create(pa_bluetooth_discovery *y, const char *path) {
687     pa_bluetooth_adapter *a;
688
689     pa_assert(y);
690     pa_assert(path);
691
692     a = pa_xnew0(pa_bluetooth_adapter, 1);
693     a->discovery = y;
694     a->path = pa_xstrdup(path);
695
696     pa_hashmap_put(y->adapters, a->path, a);
697
698     return a;
699 }
700
701 static void adapter_free(pa_bluetooth_adapter *a) {
702     pa_bluetooth_device *d;
703     void *state;
704
705     pa_assert(a);
706     pa_assert(a->discovery);
707
708     PA_HASHMAP_FOREACH(d, a->discovery->devices, state)
709         if (d->adapter == a)
710             device_set_adapter(d, NULL);
711
712     pa_xfree(a->path);
713     pa_xfree(a->address);
714     pa_xfree(a);
715 }
716
717 static void adapter_remove(pa_bluetooth_discovery *y, const char *path) {
718     pa_bluetooth_adapter *a;
719
720     if (!(a = pa_hashmap_remove(y->adapters, path)))
721         pa_log_warn("Unknown adapter removed %s", path);
722     else {
723         pa_log_debug("Adapter %s removed", path);
724         adapter_free(a);
725     }
726 }
727
728 static void parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i) {
729     const char *key;
730     DBusMessageIter variant_i;
731
732     pa_assert(d);
733
734     key = check_variant_property(i);
735     if (key == NULL) {
736         pa_log_error("Received invalid property for device %s", d->path);
737         return;
738     }
739
740     dbus_message_iter_recurse(i, &variant_i);
741
742     switch (dbus_message_iter_get_arg_type(&variant_i)) {
743
744         case DBUS_TYPE_STRING: {
745             const char *value;
746             dbus_message_iter_get_basic(&variant_i, &value);
747
748             if (pa_streq(key, "Alias")) {
749                 pa_xfree(d->alias);
750                 d->alias = pa_xstrdup(value);
751                 pa_log_debug("%s: %s", key, value);
752             } else if (pa_streq(key, "Address")) {
753                 if (d->properties_received) {
754                     pa_log_warn("Device property 'Address' expected to be constant but changed for %s, ignoring", d->path);
755                     return;
756                 }
757
758                 if (d->address) {
759                     pa_log_warn("Device %s: Received a duplicate 'Address' property, ignoring", d->path);
760                     return;
761                 }
762
763                 d->address = pa_xstrdup(value);
764                 pa_log_debug("%s: %s", key, value);
765             }
766
767             break;
768         }
769
770         case DBUS_TYPE_OBJECT_PATH: {
771             const char *value;
772             dbus_message_iter_get_basic(&variant_i, &value);
773
774             if (pa_streq(key, "Adapter")) {
775
776                 if (d->properties_received) {
777                     pa_log_warn("Device property 'Adapter' expected to be constant but changed for %s, ignoring", d->path);
778                     return;
779                 }
780
781                 if (d->adapter_path) {
782                     pa_log_warn("Device %s: Received a duplicate 'Adapter' property, ignoring", d->path);
783                     return;
784                 }
785
786                 d->adapter_path = pa_xstrdup(value);
787                 pa_log_debug("%s: %s", key, value);
788             }
789
790             break;
791         }
792
793         case DBUS_TYPE_UINT32: {
794             uint32_t value;
795             dbus_message_iter_get_basic(&variant_i, &value);
796
797             if (pa_streq(key, "Class")) {
798                 d->class_of_device = value;
799                 pa_log_debug("%s: %d", key, value);
800             }
801
802             break;
803         }
804
805         case DBUS_TYPE_ARRAY: {
806             DBusMessageIter ai;
807             dbus_message_iter_recurse(&variant_i, &ai);
808
809             if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING && pa_streq(key, "UUIDs")) {
810                 /* bluetoothd never removes UUIDs from a device object so we
811                  * don't need to check for disappeared UUIDs here. */
812                 while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
813                     const char *value;
814                     char *uuid;
815
816                     dbus_message_iter_get_basic(&ai, &value);
817
818                     if (pa_hashmap_get(d->uuids, value)) {
819                         dbus_message_iter_next(&ai);
820                         continue;
821                     }
822
823                     uuid = pa_xstrdup(value);
824                     pa_hashmap_put(d->uuids, uuid, uuid);
825
826                     pa_log_debug("%s: %s", key, value);
827                     dbus_message_iter_next(&ai);
828                 }
829             }
830
831             break;
832         }
833     }
834 }
835
836 static void parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i) {
837     DBusMessageIter element_i;
838
839     dbus_message_iter_recurse(i, &element_i);
840
841     while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
842         DBusMessageIter dict_i;
843
844         dbus_message_iter_recurse(&element_i, &dict_i);
845         parse_device_property(d, &dict_i);
846         dbus_message_iter_next(&element_i);
847     }
848
849     if (!d->properties_received) {
850         d->properties_received = true;
851         device_update_valid(d);
852
853         if (!d->address || !d->adapter_path || !d->alias)
854             pa_log_error("Non-optional information missing for device %s", d->path);
855     }
856 }
857
858 static void parse_adapter_properties(pa_bluetooth_adapter *a, DBusMessageIter *i, bool is_property_change) {
859     DBusMessageIter element_i;
860
861     pa_assert(a);
862
863     dbus_message_iter_recurse(i, &element_i);
864
865     while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
866         DBusMessageIter dict_i, variant_i;
867         const char *key;
868
869         dbus_message_iter_recurse(&element_i, &dict_i);
870
871         key = check_variant_property(&dict_i);
872         if (key == NULL) {
873             pa_log_error("Received invalid property for adapter %s", a->path);
874             return;
875         }
876
877         dbus_message_iter_recurse(&dict_i, &variant_i);
878
879         if (dbus_message_iter_get_arg_type(&variant_i) == DBUS_TYPE_STRING && pa_streq(key, "Address")) {
880             const char *value;
881
882             if (is_property_change) {
883                 pa_log_warn("Adapter property 'Address' expected to be constant but changed for %s, ignoring", a->path);
884                 return;
885             }
886
887             if (a->address) {
888                 pa_log_warn("Adapter %s received a duplicate 'Address' property, ignoring", a->path);
889                 return;
890             }
891
892             dbus_message_iter_get_basic(&variant_i, &value);
893             a->address = pa_xstrdup(value);
894             a->valid = true;
895         }
896
897         dbus_message_iter_next(&element_i);
898     }
899 }
900
901 static void register_endpoint_reply(DBusPendingCall *pending, void *userdata) {
902     DBusMessage *r;
903     pa_dbus_pending *p;
904     pa_bluetooth_discovery *y;
905     char *endpoint;
906
907     pa_assert(pending);
908     pa_assert_se(p = userdata);
909     pa_assert_se(y = p->context_data);
910     pa_assert_se(endpoint = p->call_data);
911     pa_assert_se(r = dbus_pending_call_steal_reply(pending));
912
913     if (dbus_message_is_error(r, BLUEZ_ERROR_NOT_SUPPORTED)) {
914         pa_log_info("Couldn't register endpoint %s because it is disabled in BlueZ", endpoint);
915         goto finish;
916     }
917
918     if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
919         pa_log_error(BLUEZ_MEDIA_INTERFACE ".RegisterEndpoint() failed: %s: %s", dbus_message_get_error_name(r),
920                      pa_dbus_get_error_message(r));
921         goto finish;
922     }
923
924 finish:
925     dbus_message_unref(r);
926
927     PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p);
928     pa_dbus_pending_free(p);
929
930     pa_xfree(endpoint);
931 }
932
933 static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const char *endpoint, const char *uuid) {
934     DBusMessage *m;
935     DBusMessageIter i, d;
936     uint8_t codec = 0;
937
938 #ifdef BLUETOOTH_APTX_SUPPORT
939     if(pa_streq(endpoint,A2DP_APTX_SOURCE_ENDPOINT))
940         codec = A2DP_CODEC_VENDOR;
941 #endif
942     pa_log_debug("Registering %s on adapter %s", endpoint, path);
943
944     pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, path, BLUEZ_MEDIA_INTERFACE, "RegisterEndpoint"));
945
946     dbus_message_iter_init_append(m, &i);
947     pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, &endpoint));
948     dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING
949                                          DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &d);
950     pa_dbus_append_basic_variant_dict_entry(&d, "UUID", DBUS_TYPE_STRING, &uuid);
951     pa_dbus_append_basic_variant_dict_entry(&d, "Codec", DBUS_TYPE_BYTE, &codec);
952
953     if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE) || pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK)) {
954 #ifdef __TIZEN_BT__
955     if (codec == A2DP_CODEC_SBC) {
956         a2dp_sbc_t capabilities;
957         capabilities.channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO |
958                                     SBC_CHANNEL_MODE_JOINT_STEREO;
959         capabilities.frequency = SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 |
960                                  SBC_SAMPLING_FREQ_48000;
961         capabilities.allocation_method = SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS;
962         capabilities.subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8;
963         capabilities.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16;
964         capabilities.min_bitpool = MIN_BITPOOL;
965         capabilities.max_bitpool = MAX_BITPOOL;
966         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
967     }
968 #ifdef BLUETOOTH_APTX_SUPPORT
969     if (codec == A2DP_CODEC_VENDOR ) {
970         /* aptx */
971         a2dp_aptx_t capabilities;
972         capabilities.vendor_id[0] = APTX_VENDOR_ID0;
973         capabilities.vendor_id[1] = APTX_VENDOR_ID1;
974         capabilities.vendor_id[2] = APTX_VENDOR_ID2;
975         capabilities.vendor_id[3] = APTX_VENDOR_ID3;
976         capabilities.codec_id[0] = APTX_CODEC_ID0;
977         capabilities.codec_id[1] = APTX_CODEC_ID1;
978         capabilities.channel_mode= APTX_CHANNEL_MODE_STEREO;
979         capabilities.frequency= APTX_SAMPLING_FREQ_44100;
980         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
981     }
982 #endif /* BLUETOOTH_APTX_SUPPORT */
983 #else
984         a2dp_sbc_t capabilities;
985         capabilities.channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO |
986                                     SBC_CHANNEL_MODE_JOINT_STEREO;
987         capabilities.frequency = SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 |
988                                  SBC_SAMPLING_FREQ_48000;
989         capabilities.allocation_method = SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS;
990         capabilities.subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8;
991         capabilities.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16;
992         capabilities.min_bitpool = MIN_BITPOOL;
993         capabilities.max_bitpool = MAX_BITPOOL;
994         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
995 #endif /* __TIZEN_BT__ */
996     }
997
998     dbus_message_iter_close_container(&i, &d);
999
1000     send_and_add_to_pending(y, m, register_endpoint_reply, pa_xstrdup(endpoint));
1001 }
1002
1003 static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessageIter *dict_i) {
1004     DBusMessageIter element_i;
1005     const char *path;
1006     void *state;
1007     pa_bluetooth_device *d;
1008
1009     pa_assert(dbus_message_iter_get_arg_type(dict_i) == DBUS_TYPE_OBJECT_PATH);
1010     dbus_message_iter_get_basic(dict_i, &path);
1011
1012     pa_assert_se(dbus_message_iter_next(dict_i));
1013     pa_assert(dbus_message_iter_get_arg_type(dict_i) == DBUS_TYPE_ARRAY);
1014
1015     dbus_message_iter_recurse(dict_i, &element_i);
1016
1017     while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
1018         DBusMessageIter iface_i;
1019         const char *interface;
1020
1021         dbus_message_iter_recurse(&element_i, &iface_i);
1022
1023         pa_assert(dbus_message_iter_get_arg_type(&iface_i) == DBUS_TYPE_STRING);
1024         dbus_message_iter_get_basic(&iface_i, &interface);
1025
1026         pa_assert_se(dbus_message_iter_next(&iface_i));
1027         pa_assert(dbus_message_iter_get_arg_type(&iface_i) == DBUS_TYPE_ARRAY);
1028
1029         if (pa_streq(interface, BLUEZ_ADAPTER_INTERFACE)) {
1030             pa_bluetooth_adapter *a;
1031
1032             if ((a = pa_hashmap_get(y->adapters, path))) {
1033                 pa_log_error("Found duplicated D-Bus path for adapter %s", path);
1034                 return;
1035             } else
1036                 a = adapter_create(y, path);
1037
1038             pa_log_debug("Adapter %s found", path);
1039
1040             parse_adapter_properties(a, &iface_i, false);
1041
1042             if (!a->valid)
1043                 return;
1044
1045             register_endpoint(y, path, A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
1046             register_endpoint(y, path, A2DP_SINK_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SINK);
1047 #ifdef TIZEN_BT_A2DP_MULTISTREAM
1048             register_endpoint(y, path, A2DP_SINK_ENDPOINT2, PA_BLUETOOTH_UUID_A2DP_SINK);
1049 #endif
1050
1051 #ifdef BLUETOOTH_APTX_SUPPORT
1052             register_endpoint(y, path, A2DP_APTX_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
1053 #endif
1054         } else if (pa_streq(interface, BLUEZ_DEVICE_INTERFACE)) {
1055
1056             if ((d = pa_hashmap_get(y->devices, path))) {
1057                 if (d->properties_received) {
1058                     pa_log_error("Found duplicated D-Bus path for device %s", path);
1059                     return;
1060                 }
1061             } else
1062                 d = device_create(y, path);
1063
1064             pa_log_debug("Device %s found", d->path);
1065
1066             parse_device_properties(d, &iface_i);
1067
1068         } else
1069             pa_log_debug("Unknown interface %s found, skipping", interface);
1070
1071         dbus_message_iter_next(&element_i);
1072     }
1073
1074     PA_HASHMAP_FOREACH(d, y->devices, state) {
1075         if (d->properties_received && !d->tried_to_link_with_adapter) {
1076             if (d->adapter_path) {
1077                 device_set_adapter(d, pa_hashmap_get(d->discovery->adapters, d->adapter_path));
1078
1079                 if (!d->adapter)
1080                     pa_log("Device %s points to a nonexistent adapter %s.", d->path, d->adapter_path);
1081                 else if (!d->adapter->valid)
1082                     pa_log("Device %s points to an invalid adapter %s.", d->path, d->adapter_path);
1083             }
1084
1085             d->tried_to_link_with_adapter = true;
1086         }
1087     }
1088
1089     return;
1090 }
1091
1092 void pa_bluetooth_discovery_set_ofono_running(pa_bluetooth_discovery *y, bool is_running) {
1093     pa_assert(y);
1094
1095     pa_log_debug("oFono is running: %s", pa_yes_no(is_running));
1096     if (y->headset_backend != HEADSET_BACKEND_AUTO)
1097         return;
1098
1099     /* If ofono starts running, all devices that might be connected to the HS role
1100      * need to be disconnected, so that the devices can be handled by ofono */
1101     if (is_running) {
1102         void *state;
1103         pa_bluetooth_device *d;
1104
1105         PA_HASHMAP_FOREACH(d, y->devices, state) {
1106             if (device_supports_profile(d, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)) {
1107                 DBusMessage *m;
1108
1109                 pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, d->path, "org.bluez.Device1", "Disconnect"));
1110                 dbus_message_set_no_reply(m, true);
1111                 dbus_connection_send(pa_dbus_connection_get(y->connection), m, NULL);
1112                 dbus_message_unref(m);
1113             }
1114         }
1115     }
1116
1117     pa_bluetooth_native_backend_enable_hs_role(y->native_backend, !is_running);
1118 }
1119
1120 static void get_managed_objects_reply(DBusPendingCall *pending, void *userdata) {
1121     pa_dbus_pending *p;
1122     pa_bluetooth_discovery *y;
1123     DBusMessage *r;
1124     DBusMessageIter arg_i, element_i;
1125
1126     pa_assert_se(p = userdata);
1127     pa_assert_se(y = p->context_data);
1128     pa_assert_se(r = dbus_pending_call_steal_reply(pending));
1129
1130     if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
1131         pa_log_warn("BlueZ D-Bus ObjectManager not available");
1132         goto finish;
1133     }
1134
1135     if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
1136         pa_log_error("GetManagedObjects() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r));
1137         goto finish;
1138     }
1139
1140     if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "a{oa{sa{sv}}}")) {
1141         pa_log_error("Invalid reply signature for GetManagedObjects()");
1142         goto finish;
1143     }
1144
1145     dbus_message_iter_recurse(&arg_i, &element_i);
1146     while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
1147         DBusMessageIter dict_i;
1148
1149         dbus_message_iter_recurse(&element_i, &dict_i);
1150
1151         parse_interfaces_and_properties(y, &dict_i);
1152
1153         dbus_message_iter_next(&element_i);
1154     }
1155
1156     y->objects_listed = true;
1157
1158     if (!y->native_backend && y->headset_backend != HEADSET_BACKEND_OFONO)
1159         y->native_backend = pa_bluetooth_native_backend_new(y->core, y, (y->headset_backend == HEADSET_BACKEND_NATIVE));
1160     if (!y->ofono_backend && y->headset_backend != HEADSET_BACKEND_NATIVE)
1161         y->ofono_backend = pa_bluetooth_ofono_backend_new(y->core, y);
1162
1163 finish:
1164     dbus_message_unref(r);
1165
1166     PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p);
1167     pa_dbus_pending_free(p);
1168 }
1169
1170 static void get_managed_objects(pa_bluetooth_discovery *y) {
1171     DBusMessage *m;
1172
1173     pa_assert(y);
1174
1175     pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, "/", "org.freedesktop.DBus.ObjectManager",
1176                                                   "GetManagedObjects"));
1177     send_and_add_to_pending(y, m, get_managed_objects_reply, NULL);
1178 }
1179
1180 pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y, pa_bluetooth_hook_t hook) {
1181     pa_assert(y);
1182     pa_assert(PA_REFCNT_VALUE(y) > 0);
1183
1184     return &y->hooks[hook];
1185 }
1186
1187 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
1188     pa_bluetooth_discovery *y;
1189     DBusError err;
1190
1191     pa_assert(bus);
1192     pa_assert(m);
1193     pa_assert_se(y = userdata);
1194
1195     dbus_error_init(&err);
1196
1197     if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
1198         const char *name, *old_owner, *new_owner;
1199
1200         if (!dbus_message_get_args(m, &err,
1201                                    DBUS_TYPE_STRING, &name,
1202                                    DBUS_TYPE_STRING, &old_owner,
1203                                    DBUS_TYPE_STRING, &new_owner,
1204                                    DBUS_TYPE_INVALID)) {
1205             pa_log_error("Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
1206             goto fail;
1207         }
1208
1209         if (pa_streq(name, BLUEZ_SERVICE)) {
1210             if (old_owner && *old_owner) {
1211                 pa_log_debug("Bluetooth daemon disappeared");
1212                 pa_hashmap_remove_all(y->devices);
1213                 pa_hashmap_remove_all(y->adapters);
1214                 y->objects_listed = false;
1215                 if (y->ofono_backend) {
1216                     pa_bluetooth_ofono_backend_free(y->ofono_backend);
1217                     y->ofono_backend = NULL;
1218                 }
1219                 if (y->native_backend) {
1220                     pa_bluetooth_native_backend_free(y->native_backend);
1221                     y->native_backend = NULL;
1222                 }
1223             }
1224
1225             if (new_owner && *new_owner) {
1226                 pa_log_debug("Bluetooth daemon appeared");
1227                 get_managed_objects(y);
1228             }
1229         }
1230
1231         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1232     } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")) {
1233         DBusMessageIter arg_i;
1234 #ifndef __TIZEN_BT__
1235         if (!y->objects_listed)
1236             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
1237 #endif
1238         if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sa{sv}}")) {
1239             pa_log_error("Invalid signature found in InterfacesAdded");
1240             goto fail;
1241         }
1242
1243         parse_interfaces_and_properties(y, &arg_i);
1244
1245         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1246     } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved")) {
1247         const char *p;
1248         DBusMessageIter arg_i;
1249         DBusMessageIter element_i;
1250
1251         if (!y->objects_listed)
1252             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
1253
1254         if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oas")) {
1255             pa_log_error("Invalid signature found in InterfacesRemoved");
1256             goto fail;
1257         }
1258
1259         dbus_message_iter_get_basic(&arg_i, &p);
1260
1261         pa_assert_se(dbus_message_iter_next(&arg_i));
1262         pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY);
1263
1264         dbus_message_iter_recurse(&arg_i, &element_i);
1265
1266         while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_STRING) {
1267             const char *iface;
1268
1269             dbus_message_iter_get_basic(&element_i, &iface);
1270
1271             if (pa_streq(iface, BLUEZ_DEVICE_INTERFACE))
1272                 device_remove(y, p);
1273             else if (pa_streq(iface, BLUEZ_ADAPTER_INTERFACE))
1274                 adapter_remove(y, p);
1275
1276             dbus_message_iter_next(&element_i);
1277         }
1278
1279         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1280
1281     } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
1282         DBusMessageIter arg_i;
1283         const char *iface;
1284
1285 #ifndef __TIZEN_BT__
1286         if (!y->objects_listed)
1287             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
1288 #endif
1289
1290         if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "sa{sv}as")) {
1291             pa_log_error("Invalid signature found in PropertiesChanged");
1292             goto fail;
1293         }
1294
1295         dbus_message_iter_get_basic(&arg_i, &iface);
1296
1297         pa_assert_se(dbus_message_iter_next(&arg_i));
1298         pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY);
1299
1300         if (pa_streq(iface, BLUEZ_ADAPTER_INTERFACE)) {
1301             pa_bluetooth_adapter *a;
1302
1303             pa_log_debug("Properties changed in adapter %s", dbus_message_get_path(m));
1304
1305             if (!(a = pa_hashmap_get(y->adapters, dbus_message_get_path(m)))) {
1306                 pa_log_warn("Properties changed in unknown adapter");
1307                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1308             }
1309
1310             parse_adapter_properties(a, &arg_i, true);
1311
1312         } else if (pa_streq(iface, BLUEZ_DEVICE_INTERFACE)) {
1313             pa_bluetooth_device *d;
1314
1315             pa_log_debug("Properties changed in device %s", dbus_message_get_path(m));
1316
1317             if (!(d = pa_hashmap_get(y->devices, dbus_message_get_path(m)))) {
1318                 pa_log_warn("Properties changed in unknown device");
1319                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1320             }
1321
1322             if (!d->properties_received)
1323                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1324
1325             parse_device_properties(d, &arg_i);
1326         } else if (pa_streq(iface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
1327             pa_bluetooth_transport *t;
1328
1329             pa_log_debug("Properties changed in transport %s", dbus_message_get_path(m));
1330
1331             if (!(t = pa_hashmap_get(y->transports, dbus_message_get_path(m))))
1332                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1333
1334             parse_transport_properties(t, &arg_i);
1335         }
1336
1337         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1338 #ifdef __TIZEN_BT__
1339     } else if (dbus_message_is_signal(m, "org.bluez.ag_agent", "SuspendMedia")) {
1340         pa_bluetooth_transport *t;
1341
1342         pa_log_debug("Signal from ag-agent to Suspend Media");
1343
1344         if (!(t = pa_hashmap_first(y->transports)))
1345             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1346
1347         pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED], t);
1348
1349         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1350 #endif
1351     }
1352
1353 fail:
1354     dbus_error_free(&err);
1355
1356     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1357 }
1358
1359 static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
1360     /* These bitpool values were chosen based on the A2DP spec recommendation */
1361     switch (freq) {
1362         case SBC_SAMPLING_FREQ_16000:
1363         case SBC_SAMPLING_FREQ_32000:
1364             return 53;
1365
1366         case SBC_SAMPLING_FREQ_44100:
1367
1368             switch (mode) {
1369                 case SBC_CHANNEL_MODE_MONO:
1370                 case SBC_CHANNEL_MODE_DUAL_CHANNEL:
1371                     return 31;
1372
1373                 case SBC_CHANNEL_MODE_STEREO:
1374                 case SBC_CHANNEL_MODE_JOINT_STEREO:
1375 #if defined(__TIZEN_BT__) && defined(ADJUST_ANDROID_BITPOOL)
1376                     return 35;
1377 #else
1378                     return 53;
1379 #endif
1380             }
1381
1382             pa_log_warn("Invalid channel mode %u", mode);
1383             return 53;
1384
1385         case SBC_SAMPLING_FREQ_48000:
1386
1387             switch (mode) {
1388                 case SBC_CHANNEL_MODE_MONO:
1389                 case SBC_CHANNEL_MODE_DUAL_CHANNEL:
1390                     return 29;
1391
1392                 case SBC_CHANNEL_MODE_STEREO:
1393                 case SBC_CHANNEL_MODE_JOINT_STEREO:
1394                     return 51;
1395             }
1396
1397             pa_log_warn("Invalid channel mode %u", mode);
1398             return 51;
1399     }
1400
1401     pa_log_warn("Invalid sampling freq %u", freq);
1402     return 53;
1403 }
1404
1405 #ifdef BLUETOOTH_APTX_SUPPORT
1406 static DBusMessage *endpoint_select_configuration_for_aptx(DBusConnection *c, DBusMessage *m, void *userdata) {
1407     a2dp_aptx_t *cap;
1408     a2dp_aptx_t config;
1409     uint8_t *pconf = (uint8_t *) &config;
1410     int size;
1411     DBusMessage *r;
1412     DBusError e;
1413
1414     dbus_error_init(&e);
1415
1416     if (!dbus_message_get_args(m, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
1417         pa_log("org.bluez.MediaEndpoint.SelectConfiguration: %s", e.message);
1418         dbus_error_free(&e);
1419         goto fail;
1420     }
1421
1422     pa_assert(size == sizeof(config));
1423
1424     memset(&config, 0, sizeof(config));
1425
1426     if (cap->vendor_id[0] == APTX_VENDOR_ID0 &&
1427         cap->vendor_id[1] == APTX_VENDOR_ID1 &&
1428         cap->vendor_id[2] == APTX_VENDOR_ID2 &&
1429         cap->vendor_id[3] == APTX_VENDOR_ID3 &&
1430          cap->codec_id[0] == APTX_CODEC_ID0  &&
1431          cap->codec_id[1] == APTX_CODEC_ID1  )
1432         pa_log_debug("A2DP_CODEC_NON_A2DP and this is APTX Codec");
1433     else {
1434         pa_log_debug("A2DP_CODEC_NON_A2DP but this is not APTX Codec");
1435         goto fail;
1436     }
1437
1438     memcpy(&config,cap, sizeof(config));
1439
1440 /* The below code shuld be re-written by aptx */
1441 /* And we should configure pulseaudio freq */
1442
1443     if (cap->frequency & APTX_SAMPLING_FREQ_44100)
1444         config.frequency = APTX_SAMPLING_FREQ_44100;
1445     else if (cap->frequency & APTX_SAMPLING_FREQ_48000)
1446         config.frequency = APTX_SAMPLING_FREQ_48000;
1447     else if (cap->frequency & APTX_SAMPLING_FREQ_32000)
1448         config.frequency = APTX_SAMPLING_FREQ_32000;
1449     else if (cap->frequency & APTX_SAMPLING_FREQ_16000)
1450         config.frequency = APTX_SAMPLING_FREQ_16000;
1451     else {
1452         pa_log_error("No aptx supported frequencies");
1453         goto fail;
1454     }
1455
1456     if (cap->channel_mode & APTX_CHANNEL_MODE_JOINT_STEREO)
1457         config.channel_mode = APTX_CHANNEL_MODE_STEREO;
1458     else if (cap->channel_mode & APTX_CHANNEL_MODE_STEREO)
1459         config.channel_mode = APTX_CHANNEL_MODE_STEREO;
1460     else if (cap->channel_mode & APTX_CHANNEL_MODE_DUAL_CHANNEL)
1461         config.channel_mode = APTX_CHANNEL_MODE_STEREO;
1462     else {
1463         pa_log_error("No aptx supported channel modes");
1464         goto fail;
1465     }
1466
1467     pa_assert_se(r = dbus_message_new_method_return(m));
1468
1469     pa_assert_se(dbus_message_append_args(
1470                                      r,
1471                                      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pconf, size,
1472                                      DBUS_TYPE_INVALID));
1473
1474     return r;
1475
1476 fail:
1477     pa_assert_se(r = (dbus_message_new_error(m, "org.bluez.MediaEndpoint.Error.InvalidArguments",
1478                                                         "Unable to select configuration")));
1479     return r;
1480 }
1481 #endif
1482
1483 const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
1484     switch(profile) {
1485         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
1486             return "a2dp_sink";
1487         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
1488             return "a2dp_source";
1489         case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
1490             return "headset_head_unit";
1491         case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
1492             return "headset_audio_gateway";
1493         case PA_BLUETOOTH_PROFILE_OFF:
1494             return "off";
1495     }
1496
1497     return NULL;
1498 }
1499
1500 static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) {
1501     pa_bluetooth_discovery *y = userdata;
1502     pa_bluetooth_device *d;
1503     pa_bluetooth_transport *t;
1504     const char *sender, *path, *endpoint_path, *dev_path = NULL, *uuid = NULL;
1505 #ifdef __TIZEN_BT__
1506     uint8_t codec = 0;
1507 #endif
1508     const uint8_t *config = NULL;
1509     int size = 0;
1510     pa_bluetooth_profile_t p = PA_BLUETOOTH_PROFILE_OFF;
1511     DBusMessageIter args, props;
1512     DBusMessage *r;
1513
1514     if (!dbus_message_iter_init(m, &args) || !pa_streq(dbus_message_get_signature(m), "oa{sv}")) {
1515         pa_log_error("Invalid signature for method SetConfiguration()");
1516         goto fail2;
1517     }
1518
1519     dbus_message_iter_get_basic(&args, &path);
1520
1521     if (pa_hashmap_get(y->transports, path)) {
1522         pa_log_error("Endpoint SetConfiguration(): Transport %s is already configured.", path);
1523         goto fail2;
1524     }
1525
1526     pa_assert_se(dbus_message_iter_next(&args));
1527
1528     dbus_message_iter_recurse(&args, &props);
1529     if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
1530         goto fail;
1531
1532     /* Read transport properties */
1533     while (dbus_message_iter_get_arg_type(&props) == DBUS_TYPE_DICT_ENTRY) {
1534         const char *key;
1535         DBusMessageIter value, entry;
1536         int var;
1537
1538         dbus_message_iter_recurse(&props, &entry);
1539         dbus_message_iter_get_basic(&entry, &key);
1540
1541         dbus_message_iter_next(&entry);
1542         dbus_message_iter_recurse(&entry, &value);
1543
1544         var = dbus_message_iter_get_arg_type(&value);
1545
1546         if (pa_streq(key, "UUID")) {
1547             if (var != DBUS_TYPE_STRING) {
1548                 pa_log_error("Property %s of wrong type %c", key, (char)var);
1549                 goto fail;
1550             }
1551
1552             dbus_message_iter_get_basic(&value, &uuid);
1553
1554             endpoint_path = dbus_message_get_path(m);
1555 #ifdef BLUETOOTH_APTX_SUPPORT
1556             if (pa_streq(endpoint_path, A2DP_SOURCE_ENDPOINT) ||
1557                 pa_streq(endpoint_path, A2DP_APTX_SOURCE_ENDPOINT)) {
1558                 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
1559                     p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
1560             }
1561 #else
1562             if (pa_streq(endpoint_path, A2DP_SOURCE_ENDPOINT)) {
1563                 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
1564                     p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
1565             }
1566 #endif
1567             else if (pa_streq(endpoint_path, A2DP_SINK_ENDPOINT)) {
1568                 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK))
1569                     p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
1570             }
1571 #ifdef TIZEN_BT_A2DP_MULTISTREAM
1572             else if (pa_streq(endpoint_path, A2DP_SINK_ENDPOINT2)) {
1573                 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK))
1574                     p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
1575             }
1576 #endif
1577
1578             if (p == PA_BLUETOOTH_PROFILE_OFF) {
1579                 pa_log_error("UUID %s of transport %s incompatible with endpoint %s", uuid, path, endpoint_path);
1580                 goto fail;
1581             }
1582 #ifdef __TIZEN_BT__
1583         } else if (pa_streq(key, "Codec")) {
1584             if (var != DBUS_TYPE_BYTE) {
1585                 pa_log_error("Property %s of wrong type %c", key, (char)var);
1586                 goto fail;
1587             }
1588
1589             dbus_message_iter_get_basic(&value, &codec);
1590 #endif
1591         } else if (pa_streq(key, "Device")) {
1592             if (var != DBUS_TYPE_OBJECT_PATH) {
1593                 pa_log_error("Property %s of wrong type %c", key, (char)var);
1594                 goto fail;
1595             }
1596
1597             dbus_message_iter_get_basic(&value, &dev_path);
1598         } else if (pa_streq(key, "Configuration")) {
1599             DBusMessageIter array;
1600 #ifndef BLUETOOTH_APTX_SUPPORT
1601             a2dp_sbc_t *c;
1602 #endif
1603
1604             if (var != DBUS_TYPE_ARRAY) {
1605                 pa_log_error("Property %s of wrong type %c", key, (char)var);
1606                 goto fail;
1607             }
1608
1609             dbus_message_iter_recurse(&value, &array);
1610             var = dbus_message_iter_get_arg_type(&array);
1611             if (var != DBUS_TYPE_BYTE) {
1612                 pa_log_error("%s is an array of wrong type %c", key, (char)var);
1613                 goto fail;
1614             }
1615
1616             dbus_message_iter_get_fixed_array(&array, &config, &size);
1617 #ifndef BLUETOOTH_APTX_SUPPORT
1618             if (size != sizeof(a2dp_sbc_t)) {
1619                 pa_log_error("Configuration array of invalid size");
1620                 goto fail;
1621             }
1622
1623             c = (a2dp_sbc_t *) config;
1624
1625             if (c->frequency != SBC_SAMPLING_FREQ_16000 && c->frequency != SBC_SAMPLING_FREQ_32000 &&
1626                 c->frequency != SBC_SAMPLING_FREQ_44100 && c->frequency != SBC_SAMPLING_FREQ_48000) {
1627                 pa_log_error("Invalid sampling frequency in configuration");
1628                 goto fail;
1629             }
1630
1631             if (c->channel_mode != SBC_CHANNEL_MODE_MONO && c->channel_mode != SBC_CHANNEL_MODE_DUAL_CHANNEL &&
1632                 c->channel_mode != SBC_CHANNEL_MODE_STEREO && c->channel_mode != SBC_CHANNEL_MODE_JOINT_STEREO) {
1633                 pa_log_error("Invalid channel mode in configuration");
1634                 goto fail;
1635             }
1636
1637             if (c->allocation_method != SBC_ALLOCATION_SNR && c->allocation_method != SBC_ALLOCATION_LOUDNESS) {
1638                 pa_log_error("Invalid allocation method in configuration");
1639                 goto fail;
1640             }
1641
1642             if (c->subbands != SBC_SUBBANDS_4 && c->subbands != SBC_SUBBANDS_8) {
1643                 pa_log_error("Invalid SBC subbands in configuration");
1644                 goto fail;
1645             }
1646
1647             if (c->block_length != SBC_BLOCK_LENGTH_4 && c->block_length != SBC_BLOCK_LENGTH_8 &&
1648                 c->block_length != SBC_BLOCK_LENGTH_12 && c->block_length != SBC_BLOCK_LENGTH_16) {
1649                 pa_log_error("Invalid block length in configuration");
1650                 goto fail;
1651             }
1652 #endif
1653         }
1654
1655         dbus_message_iter_next(&props);
1656     }
1657
1658     if ((d = pa_hashmap_get(y->devices, dev_path))) {
1659         if (!d->valid) {
1660             pa_log_error("Information about device %s is invalid", dev_path);
1661             goto fail2;
1662         }
1663     } else {
1664         /* InterfacesAdded signal is probably on its way, device_info_valid is kept as 0. */
1665         pa_log_warn("SetConfiguration() received for unknown device %s", dev_path);
1666         d = device_create(y, dev_path);
1667     }
1668
1669     if (d->transports[p] != NULL) {
1670         pa_log_error("Cannot configure transport %s because profile %s is already used", path, pa_bluetooth_profile_to_string(p));
1671         goto fail2;
1672     }
1673
1674     sender = dbus_message_get_sender(m);
1675
1676     pa_assert_se(r = dbus_message_new_method_return(m));
1677     pa_assert_se(dbus_connection_send(pa_dbus_connection_get(y->connection), r, NULL));
1678     dbus_message_unref(r);
1679
1680     t = pa_bluetooth_transport_new(d, sender, path, p, config, size);
1681 #ifdef __TIZEN_BT__
1682     t->codec = codec;
1683     d->transports[p] = t;
1684 #endif
1685     t->acquire = bluez5_transport_acquire_cb;
1686     t->release = bluez5_transport_release_cb;
1687     pa_bluetooth_transport_put(t);
1688
1689     pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile));
1690
1691     return NULL;
1692
1693 fail:
1694     pa_log_error("Endpoint SetConfiguration(): invalid arguments");
1695
1696 fail2:
1697     pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to set configuration"));
1698     return r;
1699 }
1700
1701 static DBusMessage *endpoint_select_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) {
1702     pa_bluetooth_discovery *y = userdata;
1703     a2dp_sbc_t *cap, config;
1704     uint8_t *pconf = (uint8_t *) &config;
1705     int i, size;
1706     DBusMessage *r;
1707     DBusError err;
1708
1709     static const struct {
1710         uint32_t rate;
1711         uint8_t cap;
1712     } freq_table[] = {
1713         { 16000U, SBC_SAMPLING_FREQ_16000 },
1714         { 32000U, SBC_SAMPLING_FREQ_32000 },
1715         { 44100U, SBC_SAMPLING_FREQ_44100 },
1716         { 48000U, SBC_SAMPLING_FREQ_48000 }
1717     };
1718
1719 #ifdef BLUETOOTH_APTX_SUPPORT
1720     if (dbus_message_has_path(m, A2DP_APTX_SOURCE_ENDPOINT))
1721         return endpoint_select_configuration_for_aptx(conn ,m ,userdata);
1722 #endif
1723
1724     dbus_error_init(&err);
1725
1726     if (!dbus_message_get_args(m, &err, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
1727         pa_log_error("Endpoint SelectConfiguration(): %s", err.message);
1728         dbus_error_free(&err);
1729         goto fail;
1730     }
1731
1732     if (size != sizeof(config)) {
1733         pa_log_error("Capabilities array has invalid size");
1734         goto fail;
1735     }
1736
1737     pa_zero(config);
1738
1739     /* Find the lowest freq that is at least as high as the requested sampling rate */
1740     for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++)
1741         if (freq_table[i].rate >= y->core->default_sample_spec.rate && (cap->frequency & freq_table[i].cap)) {
1742             config.frequency = freq_table[i].cap;
1743             break;
1744         }
1745
1746     if ((unsigned) i == PA_ELEMENTSOF(freq_table)) {
1747         for (--i; i >= 0; i--) {
1748             if (cap->frequency & freq_table[i].cap) {
1749                 config.frequency = freq_table[i].cap;
1750                 break;
1751             }
1752         }
1753
1754         if (i < 0) {
1755             pa_log_error("Not suitable sample rate");
1756             goto fail;
1757         }
1758     }
1759
1760     pa_assert((unsigned) i < PA_ELEMENTSOF(freq_table));
1761
1762     if (y->core->default_sample_spec.channels <= 1) {
1763         if (cap->channel_mode & SBC_CHANNEL_MODE_MONO)
1764             config.channel_mode = SBC_CHANNEL_MODE_MONO;
1765         else if (cap->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
1766             config.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
1767         else if (cap->channel_mode & SBC_CHANNEL_MODE_STEREO)
1768             config.channel_mode = SBC_CHANNEL_MODE_STEREO;
1769         else if (cap->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
1770             config.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
1771         else {
1772             pa_log_error("No supported channel modes");
1773             goto fail;
1774         }
1775     }
1776
1777     if (y->core->default_sample_spec.channels >= 2) {
1778         if (cap->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
1779             config.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
1780         else if (cap->channel_mode & SBC_CHANNEL_MODE_STEREO)
1781             config.channel_mode = SBC_CHANNEL_MODE_STEREO;
1782         else if (cap->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
1783             config.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
1784         else if (cap->channel_mode & SBC_CHANNEL_MODE_MONO)
1785             config.channel_mode = SBC_CHANNEL_MODE_MONO;
1786         else {
1787             pa_log_error("No supported channel modes");
1788             goto fail;
1789         }
1790     }
1791
1792     if (cap->block_length & SBC_BLOCK_LENGTH_16)
1793         config.block_length = SBC_BLOCK_LENGTH_16;
1794     else if (cap->block_length & SBC_BLOCK_LENGTH_12)
1795         config.block_length = SBC_BLOCK_LENGTH_12;
1796     else if (cap->block_length & SBC_BLOCK_LENGTH_8)
1797         config.block_length = SBC_BLOCK_LENGTH_8;
1798     else if (cap->block_length & SBC_BLOCK_LENGTH_4)
1799         config.block_length = SBC_BLOCK_LENGTH_4;
1800     else {
1801         pa_log_error("No supported block lengths");
1802         goto fail;
1803     }
1804
1805     if (cap->subbands & SBC_SUBBANDS_8)
1806         config.subbands = SBC_SUBBANDS_8;
1807     else if (cap->subbands & SBC_SUBBANDS_4)
1808         config.subbands = SBC_SUBBANDS_4;
1809     else {
1810         pa_log_error("No supported subbands");
1811         goto fail;
1812     }
1813
1814     if (cap->allocation_method & SBC_ALLOCATION_LOUDNESS)
1815         config.allocation_method = SBC_ALLOCATION_LOUDNESS;
1816     else if (cap->allocation_method & SBC_ALLOCATION_SNR)
1817         config.allocation_method = SBC_ALLOCATION_SNR;
1818
1819     config.min_bitpool = (uint8_t) PA_MAX(MIN_BITPOOL, cap->min_bitpool);
1820     config.max_bitpool = (uint8_t) PA_MIN(a2dp_default_bitpool(config.frequency, config.channel_mode), cap->max_bitpool);
1821
1822     if (config.min_bitpool > config.max_bitpool)
1823         goto fail;
1824
1825     pa_assert_se(r = dbus_message_new_method_return(m));
1826     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pconf, size, DBUS_TYPE_INVALID));
1827
1828     return r;
1829
1830 fail:
1831     pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to select configuration"));
1832     return r;
1833 }
1834
1835 static DBusMessage *endpoint_clear_configuration(DBusConnection *conn, DBusMessage *m, void *userdata) {
1836     pa_bluetooth_discovery *y = userdata;
1837     pa_bluetooth_transport *t;
1838     DBusMessage *r;
1839     DBusError err;
1840     const char *path;
1841
1842     dbus_error_init(&err);
1843
1844     if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
1845         pa_log_error("Endpoint ClearConfiguration(): %s", err.message);
1846         dbus_error_free(&err);
1847         goto fail;
1848     }
1849
1850     if ((t = pa_hashmap_get(y->transports, path))) {
1851         pa_log_debug("Clearing transport %s profile %s", t->path, pa_bluetooth_profile_to_string(t->profile));
1852         pa_bluetooth_transport_free(t);
1853     }
1854
1855     pa_assert_se(r = dbus_message_new_method_return(m));
1856
1857     return r;
1858
1859 fail:
1860     pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to clear configuration"));
1861     return r;
1862 }
1863
1864 static DBusMessage *endpoint_release(DBusConnection *conn, DBusMessage *m, void *userdata) {
1865     DBusMessage *r;
1866
1867     pa_assert_se(r = dbus_message_new_error(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE ".Error.NotImplemented",
1868                                             "Method not implemented"));
1869
1870     return r;
1871 }
1872
1873 #ifdef __TIZEN_BT__
1874 static DBusMessage *endpoint_suspend_media(DBusConnection *conn, DBusMessage *m, void *userdata) {
1875     pa_bluetooth_discovery *y = userdata;
1876     pa_bluetooth_transport *t;
1877     DBusMessage *r;
1878
1879     pa_log_debug("dbus Call from to Suspend Media");
1880     if (!(t = pa_hashmap_first(y->transports)))
1881         goto fail;
1882
1883     pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED], t);
1884
1885     pa_assert_se(r = dbus_message_new_method_return(m));
1886
1887     return r;
1888
1889 fail:
1890     pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to clear configuration"));
1891     return r;
1892 }
1893 #endif
1894
1895 static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
1896     struct pa_bluetooth_discovery *y = userdata;
1897     DBusMessage *r = NULL;
1898     const char *path, *interface, *member;
1899
1900     pa_assert(y);
1901
1902     path = dbus_message_get_path(m);
1903     interface = dbus_message_get_interface(m);
1904     member = dbus_message_get_member(m);
1905
1906     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
1907
1908 #ifdef __TIZEN_BT__
1909     pa_assert_se(path);
1910 #endif
1911
1912 #ifdef BLUETOOTH_APTX_SUPPORT
1913 #ifdef TIZEN_BT_A2DP_MULTISTREAM
1914     if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT2)
1915          && !pa_streq(path,A2DP_APTX_SOURCE_ENDPOINT))
1916         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1917 #else
1918      if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT) && !pa_streq(path,A2DP_APTX_SOURCE_ENDPOINT))
1919         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1920 #endif
1921 #else
1922 #ifdef TIZEN_BT_A2DP_MULTISTREAM
1923     if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT2))
1924         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1925 #else
1926     if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT))
1927         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1928 #endif
1929 #endif /* BLUETOOTH_APTX_SUPPORT */
1930
1931     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1932         const char *xml = ENDPOINT_INTROSPECT_XML;
1933
1934         pa_assert_se(r = dbus_message_new_method_return(m));
1935         pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
1936
1937     } else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SetConfiguration"))
1938         r = endpoint_set_configuration(c, m, userdata);
1939     else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SelectConfiguration"))
1940         r = endpoint_select_configuration(c, m, userdata);
1941     else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "ClearConfiguration"))
1942         r = endpoint_clear_configuration(c, m, userdata);
1943     else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "Release"))
1944         r = endpoint_release(c, m, userdata);
1945 #ifdef __TIZEN_BT__
1946     else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SuspendMedia"))
1947         endpoint_suspend_media(c, m, userdata);
1948 #endif
1949     else
1950         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1951
1952     if (r) {
1953         pa_assert_se(dbus_connection_send(pa_dbus_connection_get(y->connection), r, NULL));
1954         dbus_message_unref(r);
1955     }
1956
1957     return DBUS_HANDLER_RESULT_HANDLED;
1958 }
1959
1960 static void endpoint_init(pa_bluetooth_discovery *y, pa_bluetooth_profile_t profile) {
1961     static const DBusObjectPathVTable vtable_endpoint = {
1962         .message_function = endpoint_handler,
1963     };
1964
1965     pa_assert(y);
1966
1967     switch(profile) {
1968         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
1969             pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SOURCE_ENDPOINT,
1970                                                               &vtable_endpoint, y));
1971 #ifdef BLUETOOTH_APTX_SUPPORT
1972             pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_APTX_SOURCE_ENDPOINT,
1973                                                               &vtable_endpoint, y));
1974 #endif
1975             break;
1976         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
1977             pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT,
1978                                                               &vtable_endpoint, y));
1979 #ifdef TIZEN_BT_A2DP_MULTISTREAM
1980             pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT2,
1981                                                             &vtable_endpoint, y));
1982 #endif
1983             break;
1984         default:
1985             pa_assert_not_reached();
1986             break;
1987     }
1988 }
1989
1990 static void endpoint_done(pa_bluetooth_discovery *y, pa_bluetooth_profile_t profile) {
1991     pa_assert(y);
1992
1993     switch(profile) {
1994         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
1995             dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SOURCE_ENDPOINT);
1996 #ifdef BLUETOOTH_APTX_SUPPORT
1997             dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_APTX_SOURCE_ENDPOINT);
1998 #endif
1999             break;
2000         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
2001             dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT);
2002 #ifdef TIZEN_BT_A2DP_MULTISTREAM
2003             dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT2);
2004             break;
2005 #endif
2006         default:
2007             pa_assert_not_reached();
2008             break;
2009     }
2010 }
2011
2012 pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backend) {
2013     pa_bluetooth_discovery *y;
2014     DBusError err;
2015     DBusConnection *conn;
2016     unsigned i;
2017
2018     y = pa_xnew0(pa_bluetooth_discovery, 1);
2019     PA_REFCNT_INIT(y);
2020     y->core = c;
2021     y->headset_backend = headset_backend;
2022     y->adapters = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
2023                                       (pa_free_cb_t) adapter_free);
2024     y->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
2025                                      (pa_free_cb_t) device_free);
2026     y->transports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2027     PA_LLIST_HEAD_INIT(pa_dbus_pending, y->pending);
2028
2029     for (i = 0; i < PA_BLUETOOTH_HOOK_MAX; i++)
2030         pa_hook_init(&y->hooks[i], y);
2031
2032     pa_shared_set(c, "bluetooth-discovery", y);
2033
2034     dbus_error_init(&err);
2035
2036     if (!(y->connection = pa_dbus_bus_get(y->core, DBUS_BUS_SYSTEM, &err))) {
2037         pa_log_error("Failed to get D-Bus connection: %s", err.message);
2038         goto fail;
2039     }
2040
2041     conn = pa_dbus_connection_get(y->connection);
2042 #ifdef __TIZEN_BT__
2043     if (dbus_bus_request_name(conn, "org.PulseAudio2", DBUS_NAME_FLAG_REPLACE_EXISTING, &err)
2044          != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
2045         pa_log_error("Failed to set D-Bus name: %s", err.message);
2046         goto fail;
2047     }
2048 #endif
2049     /* dynamic detection of bluetooth audio devices */
2050     if (!dbus_connection_add_filter(conn, filter_cb, y, NULL)) {
2051         pa_log_error("Failed to add filter function");
2052         goto fail;
2053     }
2054     y->filter_added = true;
2055
2056     if (pa_dbus_add_matches(conn, &err,
2057             "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
2058             ",arg0='" BLUEZ_SERVICE "'",
2059             "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'",
2060             "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.ObjectManager',"
2061             "member='InterfacesRemoved'",
2062             "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
2063             ",arg0='" BLUEZ_ADAPTER_INTERFACE "'",
2064             "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
2065             ",arg0='" BLUEZ_DEVICE_INTERFACE "'",
2066             "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
2067             ",arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'",
2068 #ifdef __TIZEN_BT__
2069             "type='signal',interface='org.bluez.ag_agent',member='SuspendMedia'",
2070 #endif
2071             NULL) < 0) {
2072         pa_log_error("Failed to add D-Bus matches: %s", err.message);
2073         goto fail;
2074     }
2075     y->matches_added = true;
2076
2077     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SINK);
2078     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
2079
2080 #ifndef __TIZEN_BT__
2081     y->hf_audio_agent = hf_audio_agent_init(c);
2082 #endif
2083
2084     get_managed_objects(y);
2085
2086     return y;
2087
2088 fail:
2089     pa_bluetooth_discovery_unref(y);
2090     dbus_error_free(&err);
2091
2092     return NULL;
2093 }
2094
2095 pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y) {
2096     pa_assert(y);
2097     pa_assert(PA_REFCNT_VALUE(y) > 0);
2098
2099     PA_REFCNT_INC(y);
2100
2101     return y;
2102 }
2103
2104 void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
2105     pa_assert(y);
2106     pa_assert(PA_REFCNT_VALUE(y) > 0);
2107
2108     if (PA_REFCNT_DEC(y) > 0)
2109         return;
2110
2111     pa_dbus_free_pending_list(&y->pending);
2112
2113     if (y->ofono_backend)
2114         pa_bluetooth_ofono_backend_free(y->ofono_backend);
2115     if (y->native_backend)
2116         pa_bluetooth_native_backend_free(y->native_backend);
2117
2118     if (y->adapters)
2119         pa_hashmap_free(y->adapters);
2120
2121     if (y->devices)
2122         pa_hashmap_free(y->devices);
2123
2124     if (y->transports) {
2125         pa_assert(pa_hashmap_isempty(y->transports));
2126         pa_hashmap_free(y->transports);
2127     }
2128
2129 #ifndef __TIZEN_BT__
2130     if (y->hf_audio_agent)
2131         hf_audio_agent_done(y->hf_audio_agent);
2132 #endif
2133
2134     if (y->connection) {
2135
2136         if (y->matches_added)
2137             pa_dbus_remove_matches(pa_dbus_connection_get(y->connection),
2138                 "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',"
2139                 "arg0='" BLUEZ_SERVICE "'",
2140                 "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.ObjectManager',"
2141                 "member='InterfacesAdded'",
2142                 "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.ObjectManager',"
2143                 "member='InterfacesRemoved'",
2144                 "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',"
2145                 "member='PropertiesChanged',arg0='" BLUEZ_ADAPTER_INTERFACE "'",
2146                 "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',"
2147                 "member='PropertiesChanged',arg0='" BLUEZ_DEVICE_INTERFACE "'",
2148                 "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',"
2149                 "member='PropertiesChanged',arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'",
2150 #ifdef __TIZEN_BT__
2151                  "type='signal',interface='org.bluez.ag_agent',member='SuspendMedia'",
2152 #endif
2153                 NULL);
2154
2155         if (y->filter_added)
2156             dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y);
2157
2158         endpoint_done(y, PA_BLUETOOTH_PROFILE_A2DP_SINK);
2159         endpoint_done(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
2160
2161         pa_dbus_connection_unref(y->connection);
2162     }
2163
2164     pa_shared_remove(y->core, "bluetooth-discovery");
2165     pa_xfree(y);
2166 }