bluetooth : Apply tizen patchsets 95/170395/5
authorDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 20 Feb 2018 00:26:17 +0000 (09:26 +0900)
committerDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 20 Feb 2018 06:40:16 +0000 (15:40 +0900)
Change-Id: Ib4ba5f9f90feeea33ff9f4247358254149273a19
Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
packaging/pulseaudio.spec
src/modules/bluetooth/a2dp-codecs.h
src/modules/bluetooth/bluez5-util.c
src/modules/bluetooth/bluez5-util.h
src/modules/bluetooth/module-bluetooth-discover.c
src/modules/bluetooth/module-bluetooth-policy.c
src/modules/bluetooth/module-bluez5-device.c
src/modules/bluetooth/module-bluez5-discover.c

index 35bee70..47a3a89 100644 (file)
@@ -17,7 +17,9 @@ BuildRequires:    pkgconfig(speexdsp)
 BuildRequires:    pkgconfig(sndfile)
 BuildRequires:    pkgconfig(alsa)
 BuildRequires:    pkgconfig(glib-2.0)
+%if "%{?TIZEN_PRODUCT_TV}" != "1"
 BuildRequires:    pkgconfig(sbc)
+%endif
 BuildRequires:    pkgconfig(dbus-1)
 BuildRequires:    pkgconfig(libudev)
 BuildRequires:    pkgconfig(openssl)
@@ -404,12 +406,14 @@ setcap -r /usr/bin/pulseaudio
 %files module-bluetooth
 %manifest %{name}.manifest
 %license LICENSE LGPL
+%if "%{?TIZEN_PRODUCT_TV}" != "1"
 %defattr(-,root,root,-)
 %{_libdir}/pulse-%{version}/modules/module-bluetooth-discover.so
 %{_libdir}/pulse-%{version}/modules/module-bluetooth-policy.so
 %{_libdir}/pulse-%{version}/modules/module-bluez5-discover.so
 %{_libdir}/pulse-%{version}/modules/module-bluez5-device.so
 %{_libdir}/pulse-%{version}/modules/libbluez5-util.so
+%endif
 
 %files module-raop
 %manifest %{name}.manifest
index 8afcfcb..a86c3f0 100644 (file)
 #define A2DP_CODEC_MPEG12              0x01
 #define A2DP_CODEC_MPEG24              0x02
 #define A2DP_CODEC_ATRAC               0x03
-
+#ifdef __TIZEN_BT__
+#define BLUETOOTH_APTX_SUPPORT         1
+#define A2DP_CODEC_VENDOR               0xFF
+#endif
+#define A2DP_CODEC_NON_A2DP            0xFF
 #define SBC_SAMPLING_FREQ_16000                (1 << 3)
 #define SBC_SAMPLING_FREQ_32000                (1 << 2)
 #define SBC_SAMPLING_FREQ_44100                (1 << 1)
 #define MPEG_SAMPLING_FREQ_44100       (1 << 1)
 #define MPEG_SAMPLING_FREQ_48000       1
 
+
+#if defined(__TIZEN_BT__) && defined(ADJUST_ANDROID_BITPOOL)
+#define MAX_BITPOOL 35
+#else
 #define MAX_BITPOOL 64
+#endif
 #define MIN_BITPOOL 2
 
+/*#define APTX_CHANNEL_MODE_STEREO                     2 */
+/*
+ * aptX codec for Bluetooth only supports stereo mode with value 2
+ * But we do have sink devices programmed to send capabilities with other channel mode support.
+ * So to handle the case and keeping codec symmetry with SBC etc., we do define other channel mode,
+ * and we always make sure to set configuration with APTX_CHANNEL_MODE_STEREO only.
+ *
+ * */
+
+#define APTX_CHANNEL_MODE_MONO                 (1 << 3)
+#define APTX_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define APTX_CHANNEL_MODE_STEREO               (1 << 1)
+#define APTX_CHANNEL_MODE_JOINT_STEREO 1
+
+#define APTX_VENDOR_ID0                0x4F /*APTX codec ID 79*/
+#define APTX_VENDOR_ID1                0x0
+#define APTX_VENDOR_ID2                0x0
+#define APTX_VENDOR_ID3                0x0
+
+#define APTX_CODEC_ID0         0x1
+#define APTX_CODEC_ID1         0x0
+
+#define APTX_SAMPLING_FREQ_16000       (1 << 3)
+#define APTX_SAMPLING_FREQ_32000       (1 << 2)
+#define APTX_SAMPLING_FREQ_44100       (1 << 1)
+#define APTX_SAMPLING_FREQ_48000       1
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 
 typedef struct {
@@ -88,6 +123,12 @@ typedef struct {
        uint16_t bitrate;
 } __attribute__ ((packed)) a2dp_mpeg_t;
 
+typedef struct {
+       uint8_t vendor_id[4];
+       uint8_t codec_id[2];
+       uint8_t channel_mode:4;
+       uint8_t frequency:4;
+} __attribute__ ((packed)) a2dp_aptx_t;
 #elif __BYTE_ORDER == __BIG_ENDIAN
 
 typedef struct {
@@ -110,6 +151,13 @@ typedef struct {
        uint16_t bitrate;
 } __attribute__ ((packed)) a2dp_mpeg_t;
 
+typedef struct {
+       uint8_t vendor_id[4];
+       uint8_t codec_id[2];
+       uint8_t frequency:4;
+       uint8_t channel_mode:4;
+} __attribute__ ((packed)) a2dp_aptx_t;
+
 #else
 #error "Unknown byte order"
 #endif
index c928323..5e352f6 100644 (file)
@@ -36,6 +36,9 @@
 #include "a2dp-codecs.h"
 
 #include "bluez5-util.h"
+#ifdef BLUETOOTH_APTX_SUPPORT
+#include <dlfcn.h>
+#endif
 
 #define WAIT_FOR_PROFILES_TIMEOUT_USEC (3 * PA_USEC_PER_SEC)
 
@@ -50,6 +53,9 @@
 
 #define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
 #define A2DP_SINK_ENDPOINT "/MediaEndpoint/A2DPSink"
+#ifdef BLUETOOTH_APTX_SUPPORT
+#define A2DP_APTX_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource_aptx"
+#endif
 
 #define ENDPOINT_INTROSPECT_XML                                         \
     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                           \
@@ -68,6 +74,8 @@
     "  </method>"                                                       \
     "  <method name=\"Release\">"                                       \
     "  </method>"                                                       \
+    "  <method name=\"SuspendMedia\">"                                  \
+    "  </method>"                                                       \
     " </interface>"                                                     \
     " <interface name=\"org.freedesktop.DBus.Introspectable\">"         \
     "  <method name=\"Introspect\">"                                    \
@@ -94,6 +102,56 @@ struct pa_bluetooth_discovery {
     PA_LLIST_HEAD(pa_dbus_pending, pending);
 };
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+static void *aptx_handle = NULL;
+
+int pa_unload_aptx(void)
+{
+    if (aptx_handle == NULL) {
+        pa_log_warn("Unable to unload apt-X library");
+        return -1;
+    }
+
+    dlclose(aptx_handle);
+    aptx_handle = NULL;
+
+    pa_log_debug("unloaded apt-X library successfully");
+    return 0;
+}
+
+int pa_load_aptx(const char *aptx_lib_name)
+{
+    char* lib_path = NULL ;
+
+    if(aptx_lib_name == NULL)
+        return -1;
+
+    lib_path = pa_sprintf_malloc("%s/%s", PA_DLSEARCHPATH, aptx_lib_name);
+
+    if (!lib_path)
+        return -1;
+
+    pa_log_info("aptx_lib_path = [%s]", lib_path);
+
+    aptx_handle = dlopen(lib_path, RTLD_LAZY);
+    if (aptx_handle == NULL) {
+        pa_log_warn("Unable to load apt-X library [%s]", dlerror());
+        pa_xfree(lib_path);
+        return -1;
+    }
+
+    pa_log_debug("loaded apt-X library successfully");
+    pa_xfree(lib_path);
+
+    return 0;
+}
+
+void* pa_aptx_get_handle(void)
+{
+    return aptx_handle;
+}
+#endif
+
 static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m,
                                                                   DBusPendingCallNotifyFunction func, void *call_data) {
     pa_dbus_pending *p;
@@ -440,6 +498,42 @@ bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d) {
     return false;
 }
 
+#ifdef __TIZEN_BT__
+bool pa_bluetooth_device_sink_transport_connected(const pa_bluetooth_device *d) {
+    unsigned i;
+
+    pa_assert(d);
+
+    if (!d->valid)
+        return false;
+
+    for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++)
+        if (d->transports[i] &&
+             d->transports[i]->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK &&
+              d->transports[i]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
+            return true;
+
+    return false;
+}
+
+bool pa_bluetooth_device_source_transport_connected(const pa_bluetooth_device *d) {
+    unsigned i;
+
+    pa_assert(d);
+
+    if (!d->valid)
+        return false;
+
+    for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++)
+        if (d->transports[i] &&
+             d->transports[i]->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE &&
+              d->transports[i]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
+            return true;
+
+    return false;
+}
+#endif
+
 static int transport_state_from_string(const char* value, pa_bluetooth_transport_state_t *state) {
     pa_assert(value);
     pa_assert(state);
@@ -889,6 +983,10 @@ static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const
     DBusMessageIter i, d;
     uint8_t codec = 0;
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    if(pa_streq(endpoint,A2DP_APTX_SOURCE_ENDPOINT))
+        codec = A2DP_CODEC_VENDOR;
+#endif
     pa_log_debug("Registering %s on adapter %s", endpoint, path);
 
     pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, path, BLUEZ_MEDIA_INTERFACE, "RegisterEndpoint"));
@@ -901,8 +999,37 @@ static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const
     pa_dbus_append_basic_variant_dict_entry(&d, "Codec", DBUS_TYPE_BYTE, &codec);
 
     if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE) || pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK)) {
+#ifdef __TIZEN_BT__
+    if (codec == A2DP_CODEC_SBC) {
+        a2dp_sbc_t capabilities;
+        capabilities.channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO |
+                                    SBC_CHANNEL_MODE_JOINT_STEREO;
+        capabilities.frequency = SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 |
+                                 SBC_SAMPLING_FREQ_48000;
+        capabilities.allocation_method = SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS;
+        capabilities.subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8;
+        capabilities.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16;
+        capabilities.min_bitpool = MIN_BITPOOL;
+        capabilities.max_bitpool = MAX_BITPOOL;
+        pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
+    }
+#ifdef BLUETOOTH_APTX_SUPPORT
+    if (codec == A2DP_CODEC_VENDOR ) {
+        /* aptx */
+        a2dp_aptx_t capabilities;
+        capabilities.vendor_id[0] = APTX_VENDOR_ID0;
+        capabilities.vendor_id[1] = APTX_VENDOR_ID1;
+        capabilities.vendor_id[2] = APTX_VENDOR_ID2;
+        capabilities.vendor_id[3] = APTX_VENDOR_ID3;
+        capabilities.codec_id[0] = APTX_CODEC_ID0;
+        capabilities.codec_id[1] = APTX_CODEC_ID1;
+        capabilities.channel_mode= APTX_CHANNEL_MODE_STEREO;
+        capabilities.frequency= APTX_SAMPLING_FREQ_44100;
+        pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
+    }
+#endif /* BLUETOOTH_APTX_SUPPORT */
+#else
         a2dp_sbc_t capabilities;
-
         capabilities.channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO |
                                     SBC_CHANNEL_MODE_JOINT_STEREO;
         capabilities.frequency = SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 |
@@ -912,8 +1039,8 @@ static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const
         capabilities.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16;
         capabilities.min_bitpool = MIN_BITPOOL;
         capabilities.max_bitpool = MAX_BITPOOL;
-
         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
+#endif /* __TIZEN_BT__ */
     }
 
     dbus_message_iter_close_container(&i, &d);
@@ -966,6 +1093,10 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
             register_endpoint(y, path, A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
             register_endpoint(y, path, A2DP_SINK_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SINK);
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+            if (aptx_handle)
+                register_endpoint(y, path, A2DP_APTX_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
+#endif
         } else if (pa_streq(interface, BLUEZ_DEVICE_INTERFACE)) {
 
             if ((d = pa_hashmap_get(y->devices, path))) {
@@ -1146,10 +1277,10 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")) {
         DBusMessageIter arg_i;
-
+#ifndef __TIZEN_BT__
         if (!y->objects_listed)
             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
-
+#endif
         if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sa{sv}}")) {
             pa_log_error("Invalid signature found in InterfacesAdded");
             goto fail;
@@ -1197,8 +1328,10 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
         DBusMessageIter arg_i;
         const char *iface;
 
+#ifndef __TIZEN_BT__
         if (!y->objects_listed)
             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* No reply received yet from GetManagedObjects */
+#endif
 
         if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "sa{sv}as")) {
             pa_log_error("Invalid signature found in PropertiesChanged");
@@ -1248,6 +1381,19 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
         }
 
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+#ifdef __TIZEN_BT__
+    } else if (dbus_message_is_signal(m, "org.bluez.ag_agent", "SuspendMedia")) {
+        pa_bluetooth_transport *t;
+
+        pa_log_debug("Signal from ag-agent to Suspend Media");
+
+        if (!(t = pa_hashmap_first(y->transports)))
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+        pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED], t);
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+#endif
     }
 
 fail:
@@ -1272,7 +1418,11 @@ static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
 
                 case SBC_CHANNEL_MODE_STEREO:
                 case SBC_CHANNEL_MODE_JOINT_STEREO:
+#if defined(__TIZEN_BT__) && defined(ADJUST_ANDROID_BITPOOL)
+                    return 35;
+#else
                     return 53;
+#endif
             }
 
             pa_log_warn("Invalid channel mode %u", mode);
@@ -1298,6 +1448,84 @@ static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
     return 53;
 }
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+static DBusMessage *endpoint_select_configuration_for_aptx(DBusConnection *c, DBusMessage *m, void *userdata) {
+    a2dp_aptx_t *cap;
+    a2dp_aptx_t config;
+    uint8_t *pconf = (uint8_t *) &config;
+    int size;
+    DBusMessage *r;
+    DBusError e;
+
+    dbus_error_init(&e);
+
+    if (!dbus_message_get_args(m, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
+        pa_log("org.bluez.MediaEndpoint.SelectConfiguration: %s", e.message);
+        dbus_error_free(&e);
+        goto fail;
+    }
+
+    pa_assert(size == sizeof(config));
+
+    memset(&config, 0, sizeof(config));
+
+    if (cap->vendor_id[0] == APTX_VENDOR_ID0 &&
+        cap->vendor_id[1] == APTX_VENDOR_ID1 &&
+        cap->vendor_id[2] == APTX_VENDOR_ID2 &&
+        cap->vendor_id[3] == APTX_VENDOR_ID3 &&
+         cap->codec_id[0] == APTX_CODEC_ID0  &&
+         cap->codec_id[1] == APTX_CODEC_ID1  )
+        pa_log_debug("A2DP_CODEC_NON_A2DP and this is APTX Codec");
+    else {
+        pa_log_debug("A2DP_CODEC_NON_A2DP but this is not APTX Codec");
+        goto fail;
+    }
+
+    memcpy(&config,cap, sizeof(config));
+
+/* The below code shuld be re-written by aptx */
+/* And we should configure pulseaudio freq */
+
+    if (cap->frequency & APTX_SAMPLING_FREQ_44100)
+        config.frequency = APTX_SAMPLING_FREQ_44100;
+    else if (cap->frequency & APTX_SAMPLING_FREQ_48000)
+        config.frequency = APTX_SAMPLING_FREQ_48000;
+    else if (cap->frequency & APTX_SAMPLING_FREQ_32000)
+        config.frequency = APTX_SAMPLING_FREQ_32000;
+    else if (cap->frequency & APTX_SAMPLING_FREQ_16000)
+        config.frequency = APTX_SAMPLING_FREQ_16000;
+    else {
+        pa_log_error("No aptx supported frequencies");
+        goto fail;
+    }
+
+    if (cap->channel_mode & APTX_CHANNEL_MODE_JOINT_STEREO)
+        config.channel_mode = APTX_CHANNEL_MODE_STEREO;
+    else if (cap->channel_mode & APTX_CHANNEL_MODE_STEREO)
+        config.channel_mode = APTX_CHANNEL_MODE_STEREO;
+    else if (cap->channel_mode & APTX_CHANNEL_MODE_DUAL_CHANNEL)
+        config.channel_mode = APTX_CHANNEL_MODE_STEREO;
+    else {
+        pa_log_error("No aptx supported channel modes");
+        goto fail;
+    }
+
+    pa_assert_se(r = dbus_message_new_method_return(m));
+
+    pa_assert_se(dbus_message_append_args(
+                                     r,
+                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pconf, size,
+                                     DBUS_TYPE_INVALID));
+
+    return r;
+
+fail:
+    pa_assert_se(r = (dbus_message_new_error(m, "org.bluez.MediaEndpoint.Error.InvalidArguments",
+                                                        "Unable to select configuration")));
+    return r;
+}
+#endif
+
 const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
     switch(profile) {
         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
@@ -1320,6 +1548,9 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
     pa_bluetooth_device *d;
     pa_bluetooth_transport *t;
     const char *sender, *path, *endpoint_path, *dev_path = NULL, *uuid = NULL;
+#ifdef __TIZEN_BT__
+    uint8_t codec = 0;
+#endif
     const uint8_t *config = NULL;
     int size = 0;
     pa_bluetooth_profile_t p = PA_BLUETOOTH_PROFILE_OFF;
@@ -1367,10 +1598,19 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
             dbus_message_iter_get_basic(&value, &uuid);
 
             endpoint_path = dbus_message_get_path(m);
+#ifdef BLUETOOTH_APTX_SUPPORT
+            if (pa_streq(endpoint_path, A2DP_SOURCE_ENDPOINT) ||
+                pa_streq(endpoint_path, A2DP_APTX_SOURCE_ENDPOINT)) {
+                if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
+                    p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
+            }
+#else
             if (pa_streq(endpoint_path, A2DP_SOURCE_ENDPOINT)) {
                 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
                     p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
-            } else if (pa_streq(endpoint_path, A2DP_SINK_ENDPOINT)) {
+            }
+#endif
+            else if (pa_streq(endpoint_path, A2DP_SINK_ENDPOINT)) {
                 if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK))
                     p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
             }
@@ -1379,6 +1619,15 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
                 pa_log_error("UUID %s of transport %s incompatible with endpoint %s", uuid, path, endpoint_path);
                 goto fail;
             }
+#ifdef __TIZEN_BT__
+        } else if (pa_streq(key, "Codec")) {
+            if (var != DBUS_TYPE_BYTE) {
+                pa_log_error("Property %s of wrong type %c", key, (char)var);
+                goto fail;
+            }
+
+            dbus_message_iter_get_basic(&value, &codec);
+#endif
         } else if (pa_streq(key, "Device")) {
             if (var != DBUS_TYPE_OBJECT_PATH) {
                 pa_log_error("Property %s of wrong type %c", key, (char)var);
@@ -1403,6 +1652,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
             }
 
             dbus_message_iter_get_fixed_array(&array, &config, &size);
+#ifndef BLUETOOTH_APTX_SUPPORT
             if (size != sizeof(a2dp_sbc_t)) {
                 pa_log_error("Configuration array of invalid size");
                 goto fail;
@@ -1437,6 +1687,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
                 pa_log_error("Invalid block length in configuration");
                 goto fail;
             }
+#endif
         }
 
         dbus_message_iter_next(&props);
@@ -1465,6 +1716,10 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
     dbus_message_unref(r);
 
     t = pa_bluetooth_transport_new(d, sender, path, p, config, size);
+#ifdef __TIZEN_BT__
+    t->codec = codec;
+    d->transports[p] = t;
+#endif
     t->acquire = bluez5_transport_acquire_cb;
     t->release = bluez5_transport_release_cb;
     pa_bluetooth_transport_put(t);
@@ -1499,6 +1754,11 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn, DBusMess
         { 48000U, SBC_SAMPLING_FREQ_48000 }
     };
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    if (dbus_message_has_path(m, A2DP_APTX_SOURCE_ENDPOINT))
+        return endpoint_select_configuration_for_aptx(conn ,m ,userdata);
+#endif
+
     dbus_error_init(&err);
 
     if (!dbus_message_get_args(m, &err, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
@@ -1648,6 +1908,28 @@ static DBusMessage *endpoint_release(DBusConnection *conn, DBusMessage *m, void
     return r;
 }
 
+#ifdef __TIZEN_BT__
+static DBusMessage *endpoint_suspend_media(DBusConnection *conn, DBusMessage *m, void *userdata) {
+    pa_bluetooth_discovery *y = userdata;
+    pa_bluetooth_transport *t;
+    DBusMessage *r;
+
+    pa_log_debug("dbus Call from to Suspend Media");
+    if (!(t = pa_hashmap_first(y->transports)))
+        goto fail;
+
+    pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED], t);
+
+    pa_assert_se(r = dbus_message_new_method_return(m));
+
+    return r;
+
+fail:
+    pa_assert_se(r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", "Unable to clear configuration"));
+    return r;
+}
+#endif
+
 static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, void *userdata) {
     struct pa_bluetooth_discovery *y = userdata;
     DBusMessage *r = NULL;
@@ -1661,8 +1943,14 @@ static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, voi
 
     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT)
+         && !pa_streq(path,A2DP_APTX_SOURCE_ENDPOINT))
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+#else
     if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT))
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+#endif /* BLUETOOTH_APTX_SUPPORT */
 
     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
         const char *xml = ENDPOINT_INTROSPECT_XML;
@@ -1678,6 +1966,10 @@ static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, voi
         r = endpoint_clear_configuration(c, m, userdata);
     else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "Release"))
         r = endpoint_release(c, m, userdata);
+#ifdef __TIZEN_BT__
+    else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SuspendMedia"))
+        endpoint_suspend_media(c, m, userdata);
+#endif
     else
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
@@ -1700,6 +1992,10 @@ static void endpoint_init(pa_bluetooth_discovery *y, pa_bluetooth_profile_t prof
         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
             pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SOURCE_ENDPOINT,
                                                               &vtable_endpoint, y));
+#ifdef BLUETOOTH_APTX_SUPPORT
+            pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_APTX_SOURCE_ENDPOINT,
+                                                              &vtable_endpoint, y));
+#endif
             break;
         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
             pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT,
@@ -1717,6 +2013,9 @@ static void endpoint_done(pa_bluetooth_discovery *y, pa_bluetooth_profile_t prof
     switch(profile) {
         case PA_BLUETOOTH_PROFILE_A2DP_SINK:
             dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SOURCE_ENDPOINT);
+#ifdef BLUETOOTH_APTX_SUPPORT
+            dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_APTX_SOURCE_ENDPOINT);
+#endif
             break;
         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
             dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT);
@@ -1757,7 +2056,13 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backe
     }
 
     conn = pa_dbus_connection_get(y->connection);
-
+#ifdef __TIZEN_BT__
+    if (dbus_bus_request_name(conn, "org.PulseAudio2", DBUS_NAME_FLAG_REPLACE_EXISTING, &err)
+         != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+        pa_log_error("Failed to set D-Bus name: %s", err.message);
+        goto fail;
+    }
+#endif
     /* dynamic detection of bluetooth audio devices */
     if (!dbus_connection_add_filter(conn, filter_cb, y, NULL)) {
         pa_log_error("Failed to add filter function");
@@ -1777,6 +2082,9 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backe
             ",arg0='" BLUEZ_DEVICE_INTERFACE "'",
             "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
             ",arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'",
+#ifdef __TIZEN_BT__
+            "type='signal',interface='org.bluez.ag_agent',member='SuspendMedia'",
+#endif
             NULL) < 0) {
         pa_log_error("Failed to add D-Bus matches: %s", err.message);
         goto fail;
@@ -1786,6 +2094,10 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backe
     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SINK);
     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
 
+#ifndef __TIZEN_BT__
+    y->hf_audio_agent = hf_audio_agent_init(c);
+#endif
+
     get_managed_objects(y);
 
     return y;
@@ -1831,6 +2143,11 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
         pa_hashmap_free(y->transports);
     }
 
+#ifndef __TIZEN_BT__
+    if (y->hf_audio_agent)
+        hf_audio_agent_done(y->hf_audio_agent);
+#endif
+
     if (y->connection) {
 
         if (y->matches_added)
@@ -1847,6 +2164,9 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
                 "member='PropertiesChanged',arg0='" BLUEZ_DEVICE_INTERFACE "'",
                 "type='signal',sender='" BLUEZ_SERVICE "',interface='org.freedesktop.DBus.Properties',"
                 "member='PropertiesChanged',arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'",
+#ifdef __TIZEN_BT__
+                 "type='signal',interface='org.bluez.ag_agent',member='SuspendMedia'",
+#endif
                 NULL);
 
         if (y->filter_added)
index a3e7bf3..7f4f674 100644 (file)
 #define PA_BLUETOOTH_UUID_HFP_HF      "0000111e-0000-1000-8000-00805f9b34fb"
 #define PA_BLUETOOTH_UUID_HFP_AG      "0000111f-0000-1000-8000-00805f9b34fb"
 
+#ifdef __TIZEN_BT__
+#ifdef pa_log_debug(...)
+#undef pa_log_debug(...)
+#define pa_log_debug(...)  pa_log_level_meta(PA_LOG_INFO,   __FILE__, __LINE__, __func__, __VA_ARGS__)
+#endif
+#endif
+
 typedef struct pa_bluetooth_transport pa_bluetooth_transport;
 typedef struct pa_bluetooth_device pa_bluetooth_device;
 typedef struct pa_bluetooth_adapter pa_bluetooth_adapter;
@@ -38,6 +45,9 @@ typedef struct pa_bluetooth_backend pa_bluetooth_backend;
 typedef enum pa_bluetooth_hook {
     PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED,          /* Call data: pa_bluetooth_device */
     PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED,            /* Call data: pa_bluetooth_transport */
+#ifdef __TIZEN_BT__
+    PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED,            /* Call data: pa_bluetooth_transport */
+#endif
     PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED,  /* Call data: pa_bluetooth_transport */
     PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED,     /* Call data: pa_bluetooth_transport */
     PA_BLUETOOTH_HOOK_MAX
@@ -149,6 +159,10 @@ void pa_bluetooth_transport_unlink(pa_bluetooth_transport *t);
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t);
 
 bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d);
+#ifdef __TIZEN_BT__
+bool pa_bluetooth_device_sink_transport_connected(const pa_bluetooth_device *d);
+bool pa_bluetooth_device_source_transport_connected(const pa_bluetooth_device *d);
+#endif
 
 pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_discovery *y, const char *path);
 pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local);
@@ -165,4 +179,11 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core, int headset_ba
 pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y);
 void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y);
 void pa_bluetooth_discovery_set_ofono_running(pa_bluetooth_discovery *y, bool is_running);
+
+#ifdef BLUETOOTH_APTX_SUPPORT
+int pa_load_aptx(const char *aptx_lib_name);
+int pa_unload_aptx(void);
+void* pa_aptx_get_handle(void);
+#endif
+
 #endif
index d69a77f..e1f7eb1 100644 (file)
 #include <pulsecore/core-util.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/module.h>
+#ifdef BLUETOOTH_APTX_SUPPORT
+#include <pulsecore/modargs.h>
+#include <dlfcn.h>
+#endif
 
 #include "module-bluetooth-discover-symdef.h"
 
@@ -34,19 +38,110 @@ PA_MODULE_LOAD_ONCE(true);
 PA_MODULE_USAGE(
     "headset=ofono|native|auto (bluez 5 only)"
     "autodetect_mtu=<boolean> (bluez 5 only)"
+#ifdef BLUETOOTH_APTX_SUPPORT
+    "aptx_lib_name=<name of aptx library name>"
+#endif
 );
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+static const char* const valid_modargs[] = {
+    "aptx_lib_name",
+#ifdef __TIZEN_BT__
+    "enable_scmst",
+#endif
+    NULL
+};
+#endif
+
 struct userdata {
     uint32_t bluez5_module_idx;
     uint32_t bluez4_module_idx;
 };
+#ifdef BLUETOOTH_APTX_SUPPORT
+int pa_load_aptx(const char *aptx_lib_name);
+int pa_unload_aptx(void);
+void* pa_aptx_get_handle(void);
+#endif
+
+#ifdef BLUETOOTH_APTX_SUPPORT
+static void *aptx_handle = NULL;
+
+int pa_unload_aptx(void)
+{
+    if (aptx_handle == NULL) {
+        pa_log_warn("Unable to unload apt-X library");
+        return -1;
+    }
+
+    dlclose(aptx_handle);
+    aptx_handle = NULL;
+
+    pa_log_debug("unloaded apt-X library successfully");
+    return 0;
+}
+
+int pa_load_aptx(const char *aptx_lib_name)
+{
+    char* lib_path = NULL ;
+
+    if(aptx_lib_name == NULL)
+        return -1;
+
+    lib_path = pa_sprintf_malloc("%s/%s", PA_DLSEARCHPATH, aptx_lib_name);
+
+    if (!lib_path)
+        return -1;
+
+    pa_log_info("aptx_lib_path = [%s]", lib_path);
+
+    aptx_handle = dlopen(lib_path, RTLD_LAZY);
+    if (aptx_handle == NULL) {
+        pa_log_warn("Unable to load apt-X library [%s]", dlerror());
+        pa_xfree(lib_path);
+        return -1;
+    }
+
+    pa_log_debug("loaded apt-X library successfully");
+    pa_xfree(lib_path);
+
+    return 0;
+}
+
+void* pa_aptx_get_handle(void)
+{
+       return aptx_handle;
+}
+#endif
 
 int pa__init(pa_module* m) {
     struct userdata *u;
     pa_module *mm;
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    pa_modargs *ma = NULL;
+    const char *aptx_lib_name = NULL;
+#endif
+
     pa_assert(m);
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments");
+        pa__done(m);
+        return -1;
+    }
+
+    if (pa_modargs_get_value(ma, "async", NULL))
+        pa_log_warn("The 'async' argument is deprecated and does nothing.");
+
+
+    aptx_lib_name = pa_modargs_get_value(ma, "aptx_lib_name", NULL);
+    if (aptx_lib_name)
+        pa_load_aptx(aptx_lib_name);
+    else
+        pa_log("Failed to parse aptx_lib_name argument.");
+#endif
+
     m->userdata = u = pa_xnew0(struct userdata, 1);
     u->bluez5_module_idx = PA_INVALID_INDEX;
     u->bluez4_module_idx = PA_INVALID_INDEX;
@@ -65,8 +160,14 @@ int pa__init(pa_module* m) {
 
     if (u->bluez5_module_idx == PA_INVALID_INDEX && u->bluez4_module_idx == PA_INVALID_INDEX) {
         pa_xfree(u);
+#ifdef BLUETOOTH_APTX_SUPPORT
+        pa_modargs_free(ma);
+#endif
         return -1;
     }
+#ifdef BLUETOOTH_APTX_SUPPORT
+    pa_modargs_free(ma);
+#endif
 
     return 0;
 }
@@ -85,5 +186,9 @@ void pa__done(pa_module* m) {
     if (u->bluez4_module_idx != PA_INVALID_INDEX)
         pa_module_unload_by_index(m->core, u->bluez4_module_idx, true);
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    pa_unload_aptx();
+#endif
+
     pa_xfree(u);
 }
index 316b9a8..df247ba 100644 (file)
@@ -88,7 +88,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
         return PA_HOOK_OK;
 
     if (u->enable_a2dp_source && pa_streq(s, "a2dp_source"))
+#ifdef __TIZEN__
+        role = "media";
+#else
         role = "music";
+#endif
     /* TODO: remove hfgw when we remove BlueZ 4 support */
     else if (u->enable_ag && (pa_streq(s, "hfgw") || pa_streq(s, "headset_audio_gateway")))
         role = "phone";
index 530207a..66ffa98 100644 (file)
 #include <arpa/inet.h>
 #include <sbc/sbc.h>
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+#include <dlfcn.h>
+#endif
+
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
 #include <pulse/utf8.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/time-smoother.h>
 
+#ifdef __TIZEN_BT__
+#include <pulsecore/sink.h>
+#include <pulsecore/namereg.h>
+#endif
+
 #include "a2dp-codecs.h"
 #include "bluez5-util.h"
 #include "rtp.h"
@@ -71,6 +80,10 @@ PA_MODULE_USAGE("path=<device object path>"
 static const char* const valid_modargs[] = {
     "path",
     "autodetect_mtu",
+#ifdef __TIZEN_BT__
+    "address",
+    "profile",
+#endif
     NULL
 };
 
@@ -102,7 +115,10 @@ typedef struct sbc_info {
     uint16_t seq_num;                    /* Cumulative packet sequence */
     uint8_t min_bitpool;
     uint8_t max_bitpool;
-
+#ifdef BLUETOOTH_APTX_SUPPORT
+    bool aptx_initialized;               /* Keep track if the encoder is initialized */
+    void *aptx;                          /* aptx Codec data */
+#endif
     void* buffer;                        /* Codec transfer buffer */
     size_t buffer_size;                  /* Size of the buffer */
 } sbc_info_t;
@@ -113,6 +129,9 @@ struct userdata {
 
     pa_hook_slot *device_connection_changed_slot;
     pa_hook_slot *transport_state_changed_slot;
+#ifdef __TIZEN_BT__
+    pa_hook_slot *sco_state_changed_slot;
+#endif
     pa_hook_slot *transport_speaker_gain_changed_slot;
     pa_hook_slot *transport_microphone_gain_changed_slot;
 
@@ -122,6 +141,9 @@ struct userdata {
     bool transport_acquired;
     bool stream_setup_done;
 
+#ifdef __TIZEN_BT__
+    bool transport_suspended_by_remote;
+#endif
     pa_card *card;
     pa_sink *sink;
     pa_source *source;
@@ -148,6 +170,10 @@ struct userdata {
     pa_memchunk write_memchunk;
     pa_sample_spec sample_spec;
     struct sbc_info sbc_info;
+
+#ifdef __TIZEN_BT__
+    pa_modargs *modargs;
+#endif
 };
 
 typedef enum pa_bluetooth_form_factor {
@@ -232,6 +258,42 @@ static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff) {
     pa_assert_not_reached();
 }
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+void* (*aptx_new)(short endian);
+int (*aptx_encode)(void* _state, void* _pcmL, void* _pcmR, void* _buffer);
+
+const char *aptx_new_name = "NewAptxEnc";
+const char *aptx_encode_name = "aptxbtenc_encodestereo";
+
+static bool pa_load_aptx_sym(void *handle )
+{
+    if (!handle)
+        return false;
+
+    aptx_new = (void* (*)(short endian))dlsym(handle, aptx_new_name);
+
+    if (aptx_new) {
+        pa_log_debug("Load Symbol(%s)", aptx_new_name);
+    } else {
+        pa_log_debug("Fail to Load Symbol(%s)", aptx_new_name);
+        return false;
+    }
+
+    aptx_encode = (int (*)(void* _state, void* _pcmL, void* _pcmR,
+    void* _buffer))
+    dlsym(handle, "aptxbtenc_encodestereo");
+
+    if (aptx_encode) {
+        pa_log_debug("Load Symbol(%s)", aptx_encode_name);
+    } else {
+        pa_log_debug("Fail to Load Symbol(%s)", aptx_encode_name);
+        return false;
+    }
+
+    return true;
+}
+#endif
+
 /* Run from main thread */
 static void connect_ports(struct userdata *u, void *new_data, pa_direction_t direction) {
     pa_device_port *port;
@@ -547,6 +609,144 @@ static int a2dp_process_render(struct userdata *u) {
     return ret;
 }
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+/* Run from IO thread */
+static int a2dp_aptx_process_render(struct userdata *u) {
+    struct sbc_info *a2dp;
+    size_t nbytes;
+    void *d;
+    const void *p;
+    size_t to_write, to_encode;
+    int ret = 0;
+
+    int pcmL[4],pcmR[4];
+    int i=0;
+    const uint8_t *mybuffer;
+
+    pa_assert(u);
+    pa_assert(u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK);
+    pa_assert(u->sink);
+
+    /* First, render some data */
+    if (!u->write_memchunk.memblock)
+        pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
+
+    pa_assert(u->write_memchunk.length == u->write_block_size);
+
+    a2dp_prepare_buffer(u);
+
+    a2dp = &u->sbc_info;
+
+    /* Try to create a packet of the full MTU */
+    p = (const uint8_t*) pa_memblock_acquire(u->write_memchunk.memblock) + u->write_memchunk.index;
+    to_encode = u->write_memchunk.length;
+
+    d = (uint8_t*) a2dp->buffer ;
+    to_write = a2dp->buffer_size;
+
+    while (PA_LIKELY(to_encode > 0 && to_write > 0)) {
+        size_t written;
+        ssize_t encoded;
+
+        mybuffer = (uint8_t *)p;
+
+        for (i = 0; i < 4; i += 1) {
+           pcmL[i] = mybuffer[2*i];
+           pcmR[i] = mybuffer[2*i+1];
+        }
+        /*(8 audio samples)16 bytes of audo data encoded to 4 bytes*/
+        aptx_encode(a2dp->aptx, pcmL, pcmR, (short*)d);
+
+        encoded=16;
+        written=4;
+
+        pa_assert_fp((size_t) encoded <= to_encode);
+        pa_assert_fp((size_t) written <= to_write);
+
+        p = (const uint8_t*) p + encoded;
+        to_encode -= encoded;
+
+        d = (uint8_t*) d + written;
+        to_write -= written;
+
+    }
+
+    pa_memblock_release(u->write_memchunk.memblock);
+
+    pa_assert(to_encode == 0);
+
+    PA_ONCE_BEGIN {
+        pa_log_debug("Using APTX encoder implementation");
+    } PA_ONCE_END;
+
+    nbytes = (uint8_t*) d - (uint8_t*) a2dp->buffer;
+
+    for (;;) {
+        ssize_t l;
+
+        l = pa_write(u->stream_fd, a2dp->buffer, nbytes, &u->stream_write_type);
+
+        pa_assert(l != 0);
+
+        if (l < 0) {
+
+            if (errno == EINTR)
+                /* Retry right away if we got interrupted */
+                continue;
+
+            else if (errno == EAGAIN)
+                /* Hmm, apparently the socket was not writable, give up for now */
+                break;
+
+            pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno));
+            ret  = -1;
+            break;
+        }
+
+        pa_assert((size_t) l <= nbytes);
+
+        if ((size_t) l != nbytes) {
+            pa_log_warn("Wrote memory block to socket only partially! %llu written, wanted to write %llu.",
+                        (unsigned long long) l,
+                        (unsigned long long) nbytes);
+            ret = -1;
+            break;
+        }
+
+        u->write_index += (uint64_t) u->write_memchunk.length;
+        pa_memblock_unref(u->write_memchunk.memblock);
+        pa_memchunk_reset(&u->write_memchunk);
+
+        ret = 1;
+
+        break;
+    }
+
+    return ret;
+}
+#endif
+
+#ifdef __TIZEN_BT__
+/* Run from IO thread */
+static int a2dp_process_null_render(struct userdata *u) {
+    pa_assert(u);
+    pa_assert(u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK);
+    pa_assert(u->sink);
+
+    /* First, render some data */
+    if (!u->write_memchunk.memblock)
+        pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
+
+    pa_assert(u->write_memchunk.length == u->write_block_size);
+
+    u->write_index += (uint64_t) u->write_memchunk.length;
+    pa_memblock_unref(u->write_memchunk.memblock);
+    pa_memchunk_reset(&u->write_memchunk);
+
+    return 1;
+}
+#endif
+
 /* Run from IO thread */
 static int a2dp_process_push(struct userdata *u) {
     int ret = 0;
@@ -756,6 +956,10 @@ static int transport_acquire(struct userdata *u, bool optional) {
         return u->stream_fd;
 
     u->transport_acquired = true;
+
+#ifdef __TIZEN_BT__
+    u->transport_suspended_by_remote = false;
+#endif
     pa_log_info("Transport %s acquired: fd %d", u->transport->path, u->stream_fd);
 
     return 0;
@@ -774,6 +978,12 @@ static void transport_release(struct userdata *u) {
 
     u->transport_acquired = false;
 
+#ifdef __TIZEN_BT__
+    /* The below code would be less effect for most of case */
+    if (u->transport_suspended_by_remote)
+        pa_log_info("Released by remote suspend request");
+#endif
+
     teardown_stream(u);
 
     /* Set transport state to idle if this was not already done by the remote end closing
@@ -797,7 +1007,12 @@ static void transport_config_mtu(struct userdata *u) {
             pa_log_debug("Got invalid write MTU: %lu, rounding down", u->write_block_size);
             u->write_block_size = pa_frame_align(u->write_block_size, &u->sink->sample_spec);
         }
+
+#ifdef __TIZEN_BT__
+    } else if(u->sbc_info.sbc_initialized) {
+#else
     } else {
+#endif
         u->read_block_size =
             (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
             / u->sbc_info.frame_length * u->sbc_info.codesize;
@@ -1079,7 +1294,15 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
                 case PA_SINK_RUNNING:
                     if (u->sink->thread_info.state != PA_SINK_SUSPENDED)
                         break;
-
+#ifdef __TIZEN_BT__
+                    /* Wait until PA_BLUETOOTH_TRANSPORT_IDLE */
+                    if ((u->transport != NULL) && (u->transport->state ==
+                          PA_BLUETOOTH_TRANSPORT_STATE_IDLE))
+                        pa_log_info("This is good time for(%d)",
+                        (pa_sink_state_t) PA_PTR_TO_UINT(data));
+                    else
+                        pa_log_info("Wait for PA_BLUETOOTH_TRANSPORT_STATE_IDLE");
+#endif
                     /* Resume the device if the source was suspended as well */
                     if (!u->source || !PA_SOURCE_IS_OPENED(u->source->thread_info.state))
                         failed = !setup_transport_and_stream(u);
@@ -1217,6 +1440,36 @@ static int add_sink(struct userdata *u) {
     return 0;
 }
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+/* should be implemeted */
+static void bt_transport_config_a2dp_for_aptx(struct userdata *u) {
+    const pa_bluetooth_transport *t;
+    struct sbc_info *a2dp = &u->sbc_info;
+
+    t = u->transport;
+    pa_assert(t);
+
+    u->sample_spec.format = PA_SAMPLE_S16LE;
+
+    if (!a2dp->aptx_initialized) {
+        #if __BYTE_ORDER==__LITTLE_ENDIAN
+            a2dp->aptx = aptx_new(1);
+        #elif __BYTE_ORDER==__BIG_ENDIAN
+            a2dp->aptx = aptx_new(0);
+        #else
+            #error "Unknown byte order"
+        #endif
+            a2dp->aptx_initialized = true;
+    }
+
+    pa_log_debug("aptx Encoder is intialized !!");
+
+    u->write_block_size =(size_t)(u->write_link_mtu/(size_t)16) *16*4 ;
+    pa_log_info("APTX parameters block_size(%d),link_mtu(%d)",u->write_block_size,u->write_link_mtu);
+
+}
+#endif
+
 /* Run from main thread */
 static void transport_config(struct userdata *u) {
     if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
@@ -1226,9 +1479,34 @@ static void transport_config(struct userdata *u) {
     } else {
         sbc_info_t *sbc_info = &u->sbc_info;
         a2dp_sbc_t *config;
+#ifdef BLUETOOTH_APTX_SUPPORT
+        const pa_bluetooth_transport *t;
+        a2dp_aptx_t *aptx_config;
+#endif
 
         pa_assert(u->transport);
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+        t = u->transport;
+        if (t->codec == A2DP_CODEC_VENDOR) {
+            aptx_config = (a2dp_aptx_t *) t->config;
+            if (aptx_config->vendor_id[0] == APTX_VENDOR_ID0 &&
+                aptx_config->vendor_id[1] == APTX_VENDOR_ID1 &&
+                 aptx_config->vendor_id[2] == APTX_VENDOR_ID2 &&
+                  aptx_config->vendor_id[3] == APTX_VENDOR_ID3 &&
+                   aptx_config->codec_id[0] == APTX_CODEC_ID0  &&
+                    aptx_config->codec_id[1] == APTX_CODEC_ID1  ){
+                pa_log("A2DP_CODEC_NON_A2DP and this is APTX Codec");
+
+                bt_transport_config_a2dp_for_aptx(u);
+                return;
+            } else {
+                pa_log("A2DP_CODEC_NON_A2DP but this is not APTX Codec");
+                return;
+            }
+        }
+#endif
+
         u->sample_spec.format = PA_SAMPLE_S16LE;
         config = (a2dp_sbc_t *) u->transport->config;
 
@@ -1529,10 +1807,26 @@ static void thread_func(void *userdata) {
 
                     if (u->write_index <= 0)
                         u->started_at = pa_rtclock_now();
-
+#ifdef __TIZEN_BT__
+                    if ((u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) &&
+                                           !u->transport_suspended_by_remote) {
+                        if(u->sbc_info.sbc_initialized) {
+                            if ((n_written = a2dp_process_render(u)) < 0)
+                                goto fail;
+                            } else {
+#ifdef BLUETOOTH_APTX_SUPPORT
+                                if ((n_written = a2dp_aptx_process_render(u)) < 0)
+                                    goto fail;
+                                #endif
+                            }
+                        } else if ((u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) &&
+                                     u->transport_suspended_by_remote) {
+                            a2dp_process_null_render(u);
+#else
                     if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
                         if ((n_written = a2dp_process_render(u)) < 0)
                             goto fail;
+#endif
                     } else {
                         if ((n_written = sco_process_render(u)) < 0)
                             goto fail;
@@ -1872,7 +2166,6 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
 
         p = PA_CARD_PROFILE_DATA(cp);
         break;
-
     case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
         cp = pa_card_profile_new(name, _("Headset Head Unit (HSP/HFP)"), sizeof(pa_bluetooth_profile_t));
         cp->priority = 20;
@@ -1898,7 +2191,6 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
 
         p = PA_CARD_PROFILE_DATA(cp);
         break;
-
     case PA_BLUETOOTH_PROFILE_OFF:
         pa_assert_not_reached();
     }
@@ -1980,6 +2272,9 @@ static int add_card(struct userdata *u) {
     pa_bluetooth_profile_t *p;
     const char *uuid;
     void *state;
+#ifdef __TIZEN_BT__
+    const char *default_profile;
+#endif
 
     pa_assert(u);
     pa_assert(u->device);
@@ -2031,6 +2326,22 @@ static int add_card(struct userdata *u) {
     *p = PA_BLUETOOTH_PROFILE_OFF;
     pa_hashmap_put(data.profiles, cp->name, cp);
 
+#ifdef __TIZEN_BT__
+/* Default profile was assigned in the previous tizen version. Because pa_card_new_data_set_profile function
+  * was removed pulseaudio 11.1 version. So we can't use these codes. If some problems occurs in later.
+  * We should use this code. */
+#if 0
+    if ((default_profile = pa_modargs_get_value(u->modargs, "profile", NULL))) {
+        pa_log_debug("default_profile: %s", default_profile);
+
+        if (pa_hashmap_get(data.profiles, default_profile))
+            pa_card_new_data_set_profile(&data, default_profile);
+        else
+            pa_log_warn("Profile '%s' not valid or not supported by device.", default_profile);
+    }
+#endif
+#endif
+
     u->card = pa_card_new(u->core, &data);
     pa_card_new_data_done(&data);
     if (!u->card) {
@@ -2044,6 +2355,7 @@ static int add_card(struct userdata *u) {
     pa_card_put(u->card);
 
     p = PA_CARD_PROFILE_DATA(u->card->active_profile);
+
     u->profile = *p;
 
     return 0;
@@ -2099,6 +2411,9 @@ static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot
         if (u->sink) {
             pa_log_debug("Resuming sink %s because its transport state changed to playing", u->sink->name);
 
+#ifdef __TIZEN_BT__
+            u->transport_suspended_by_remote = false;
+#endif
             /* Same comment as above */
             if (PA_SINK_IS_OPENED(u->sink->state))
                 pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_SETUP_STREAM, NULL, 0, NULL);
@@ -2122,7 +2437,13 @@ static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot
 
         if (u->sink) {
             pa_log_debug("Suspending sink %s because the remote end closed the stream", u->sink->name);
+#ifdef __TIZEN_BT__
+            /* if we change PA state as Suspend, PA client application
+                       * such as music app would face lock-up */
+            u->transport_suspended_by_remote = true;
+#else
             pa_sink_suspend(u->sink, true, PA_SUSPEND_USER);
+#endif
         }
     }
 }
@@ -2141,6 +2462,46 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y,
     return PA_HOOK_OK;
 }
 
+#ifdef __TIZEN_BT__
+static void dbus_sco_open_handler(struct userdata *u, struct pa_bluetooth_transport *t)
+{
+    if (u->sink) {
+        pa_sink *sink_null;
+        pa_sink_input *si;
+        uint32_t idx;
+
+        pa_log_info("Suspending sink %s to handle the SCO connection", u->sink->name);
+
+        if (pa_sink_check_suspend(u->sink, NULL, NULL) > 0) {
+            sink_null = (pa_sink *)pa_namereg_get(u->core, "null", 0);
+
+            if (sink_null) {
+                PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
+                    pa_sink_input_move_to(si, sink_null, false);
+                }
+            }
+        }
+
+        pa_sink_suspend(u->sink, true, PA_SUSPEND_INTERNAL);
+    }
+}
+
+/* Run from main thread */
+static pa_hook_result_t sco_state_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
+    pa_assert(t);
+    pa_assert(u);
+
+    if (t == u->transport && t->state <= PA_BLUETOOTH_TRANSPORT_STATE_IDLE)
+        return PA_HOOK_OK;
+
+    if (t->device == u->device)
+        dbus_sco_open_handler(u, t);
+
+    return PA_HOOK_OK;
+}
+#endif
+
+
 /* Run from main thread */
 static pa_hook_result_t transport_state_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
     pa_assert(t);
@@ -2237,6 +2598,9 @@ int pa__init(pa_module* m) {
     const char *path;
     pa_modargs *ma;
     bool autodetect_mtu;
+#ifdef BLUETOOTH_APTX_SUPPORT
+    void *handle;
+#endif
 
     pa_assert(m);
 
@@ -2249,6 +2613,11 @@ int pa__init(pa_module* m) {
         goto fail_free_modargs;
     }
 
+#ifdef __TIZEN_BT__
+    u->sample_spec = m->core->default_sample_spec;
+    u->modargs = ma;
+#endif
+
     if (!(path = pa_modargs_get_value(ma, "path", NULL))) {
         pa_log_error("Failed to get device path from module arguments");
         goto fail_free_modargs;
@@ -2274,7 +2643,9 @@ int pa__init(pa_module* m) {
 
     u->device->autodetect_mtu = autodetect_mtu;
 
+#ifndef __TIZEN_BT__
     pa_modargs_free(ma);
+#endif
 
     u->device_connection_changed_slot =
         pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED),
@@ -2290,6 +2661,12 @@ int pa__init(pa_module* m) {
     u->transport_microphone_gain_changed_slot =
         pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_microphone_gain_changed_cb, u);
 
+#ifdef __TIZEN_BT__
+    u->sco_state_changed_slot =
+        pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_SCO_STATE_CHANGED),
+                        PA_HOOK_NORMAL, (pa_hook_cb_t) sco_state_changed_cb, u);
+#endif
+
     if (add_card(u) < 0)
         goto fail;
 
@@ -2300,6 +2677,20 @@ int pa__init(pa_module* m) {
     u->msg->card = u->card;
     u->stream_setup_done = false;
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    handle = pa_aptx_get_handle();
+
+    if (handle) {
+        pa_log_debug("Aptx Library loaded\n");
+        pa_load_aptx_sym(handle);
+    }
+#endif
+
+#ifdef __TIZEN_BT__
+    pa_modargs_free(ma);
+    u->modargs = NULL;
+#endif
+
     if (u->profile != PA_BLUETOOTH_PROFILE_OFF)
         if (init_profile(u) < 0)
             goto off;
@@ -2348,6 +2739,11 @@ void pa__done(pa_module *m) {
     if (u->transport_speaker_gain_changed_slot)
         pa_hook_slot_free(u->transport_speaker_gain_changed_slot);
 
+#ifdef __TIZEN_BT__
+    if (u->sco_state_changed_slot)
+        pa_hook_slot_free(u->sco_state_changed_slot);
+#endif
+
     if (u->transport_microphone_gain_changed_slot)
         pa_hook_slot_free(u->transport_microphone_gain_changed_slot);
 
index c535ead..8133b4b 100644 (file)
@@ -27,7 +27,6 @@
 #include <pulsecore/module.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/shared.h>
-
 #include "bluez5-util.h"
 
 #include "module-bluez5-discover-symdef.h"
 PA_MODULE_AUTHOR("João Paulo Rechi Vita");
 PA_MODULE_DESCRIPTION("Detect available BlueZ 5 Bluetooth audio devices and load BlueZ 5 Bluetooth audio drivers");
 PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(true);
+#ifdef __TIZEN_BT__
+#define HAVE_BLUEZ_5_NATIVE_HEADSET
+
+PA_MODULE_USAGE("sco_sink=<name of sink> "
+        "sco_source=<name of source> "
+        "headset=ofono|native|auto"
+#ifdef BLUETOOTH_APTX_SUPPORT
+        "aptx_lib_name=<name of aptx library name>"
+#endif
+);
+#else
 PA_MODULE_USAGE(
     "headset=ofono|native|auto"
 );
+#endif
+PA_MODULE_LOAD_ONCE(true);
 
+#ifdef __TIZEN_BT__
 static const char* const valid_modargs[] = {
     "headset",
     "autodetect_mtu",
+    "sco_sink",
+    "sco_source",
+#ifdef BLUETOOTH_APTX_SUPPORT
+    "aptx_lib_name",
+#endif
     NULL
 };
+#else
+static const char* const valid_modargs[] = {
+    "headset",
+    "autodetect_mtu",
+    NULL
+};
+#endif
 
 struct userdata {
     pa_module *module;
@@ -73,7 +97,19 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y,
     if (!module_loaded && pa_bluetooth_device_any_transport_connected(d)) {
         /* a new device has been connected */
         pa_module *m;
+#ifdef __TIZEN_BT__
+        char *args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" autodetect_mtu=%i", d->address, d->path, (int)u->autodetect_mtu);
+#else
         char *args = pa_sprintf_malloc("path=%s autodetect_mtu=%i", d->path, (int)u->autodetect_mtu);
+#endif
+
+#ifdef __TIZEN_BT__
+        if (pa_bluetooth_device_sink_transport_connected(d) == true)
+            args = pa_sprintf_malloc("%s profile=\"a2dp_sink\"", args);
+
+        if (pa_bluetooth_device_source_transport_connected(d) == true)
+            args = pa_sprintf_malloc("%s profile=\"a2dp_source\"", args);
+#endif
 
         pa_log_debug("Loading module-bluez5-device %s", args);
         m = pa_module_load(u->module->core, "module-bluez5-device", args);
@@ -100,6 +136,9 @@ const char *default_headset_backend = "ofono";
 
 int pa__init(pa_module *m) {
     struct userdata *u;
+#ifdef BLUETOOTH_APTX_SUPPORT
+    const char *aptx_lib_name = NULL;
+#endif
     pa_modargs *ma;
     const char *headset_str;
     int headset_backend;
@@ -112,6 +151,14 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    aptx_lib_name = pa_modargs_get_value(ma, "aptx_lib_name", NULL);
+    if (aptx_lib_name)
+        pa_load_aptx(aptx_lib_name);
+    else
+        pa_log("Failed to parse aptx_lib_name argument.");
+#endif
+
     pa_assert_se(headset_str = pa_modargs_get_value(ma, "headset", default_headset_backend));
     if (pa_streq(headset_str, "ofono"))
         headset_backend = HEADSET_BACKEND_OFONO;
@@ -170,5 +217,9 @@ void pa__done(pa_module *m) {
     if (u->loaded_device_paths)
         pa_hashmap_free(u->loaded_device_paths);
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    pa_unload_aptx();
+#endif
+
     pa_xfree(u);
 }