bluetooth: Add SuspendMedia method 19/66619/8 accepted/tizen/common/20160513.123224 accepted/tizen/ivi/20160513.004147 accepted/tizen/mobile/20160513.004025 accepted/tizen/tv/20160513.004125 accepted/tizen/wearable/20160513.004052 submit/tizen/20160512.051443
authorDoHyun Pyun <dh79.pyun@samsung.com>
Fri, 29 May 2015 07:37:52 +0000 (16:37 +0900)
committerHyuk Lee <hyuk0512.lee@samsung.com>
Wed, 4 May 2016 05:32:46 +0000 (14:32 +0900)
In tizen 2.4 we consider the senairo with SCO open / close and A2DP suspend.
For this functionality apply the method and signal handlering code.

[Version] 5.0-65
[Profile] Common
[Issue Type] New feature

Change-Id: I5fc636549e941e0593639506591889aaeb9ac435
Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
Signed-off-by: Hyuk Lee <hyuk0512.lee@samsung.com>
src/modules/bluetooth/bluez5-util.c
src/modules/bluetooth/bluez5-util.h
src/modules/bluetooth/module-bluetooth-policy.c
src/modules/bluetooth/module-bluez5-device.c
src/modules/bluetooth/module-bluez5-discover.c

index 6ae4807..bc89707 100644 (file)
@@ -52,6 +52,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                           \
@@ -70,6 +73,8 @@
     "  </method>"                                                       \
     "  <method name=\"Release\">"                                       \
     "  </method>"                                                       \
+    "  <method name=\"SuspendMedia\">"                                  \
+    "  </method>"                                                       \
     " </interface>"                                                     \
     " <interface name=\"org.freedesktop.DBus.Introspectable\">"         \
     "  <method name=\"Introspect\">"                                    \
@@ -360,6 +365,23 @@ bool pa_bluetooth_device_sink_transport_connected(const pa_bluetooth_device *d)
 
     return false;
 }
+
+bool pa_bluetooth_device_source_transport_connected(const pa_bluetooth_device *d) {
+       unsigned i;
+
+       pa_assert(d);
+
+       if (d->device_info_valid != 1)
+               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) {
@@ -798,6 +820,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"));
@@ -824,19 +850,33 @@ static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const
        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 |
-                                 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));
+               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));
 #endif /* __TIZEN_BT__ */
        }
 
@@ -886,9 +926,12 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
             if (!a->address)
                 return;
 
-            register_endpoint(y, path, A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
-#ifndef __TIZEN_BT__
             register_endpoint(y, path, A2DP_SINK_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SINK);
+            register_endpoint(y, path, A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
+
+#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)) {
 
@@ -910,10 +953,7 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
         dbus_message_iter_next(&element_i);
     }
 
-    PA_HASHMAP_FOREACH(d, y->devices, state) {
-        if (d->device_info_valid != 0)
-            continue;
-
+    PA_HASHMAP_FOREACH(d, y->devices, state)
         if (!d->adapter && d->adapter_path) {
             d->adapter = pa_hashmap_get(d->discovery->adapters, d->adapter_path);
             if (!d->adapter || !d->adapter->address) {
@@ -922,7 +962,6 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa
             } else
                 set_device_info_valid(d, 1);
         }
-    }
 
     return;
 }
@@ -1134,6 +1173,16 @@ 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:
@@ -1188,6 +1237,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:
@@ -1260,10 +1387,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;
             }
@@ -1290,7 +1426,6 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
             dbus_message_iter_get_basic(&value, &dev_path);
         } else if (pa_streq(key, "Configuration")) {
             DBusMessageIter array;
-            a2dp_sbc_t *c;
 
             if (var != DBUS_TYPE_ARRAY) {
                 pa_log_error("Property %s of wrong type %c", key, (char)var);
@@ -1305,6 +1440,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;
@@ -1339,6 +1475,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);
@@ -1355,7 +1492,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
         d = device_create(y, dev_path);
     }
 
-    if (d->transports[p] != NULL) {
+    if (p == PA_BLUETOOTH_PROFILE_OFF || d->transports[p] != NULL) {
         pa_log_error("Cannot configure transport %s because profile %s is already used", path, pa_bluetooth_profile_to_string(p));
         goto fail2;
     }
@@ -1406,6 +1543,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)) {
@@ -1556,6 +1698,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;
@@ -1569,8 +1733,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;
@@ -1586,6 +1756,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;
 
@@ -1608,6 +1782,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,
@@ -1625,6 +1803,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);
@@ -1663,8 +1844,14 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
         goto fail;
     }
 
-    conn = pa_dbus_connection_get(y->connection);
-
+       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");
@@ -1684,6 +1871,9 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
             ",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;
@@ -1691,9 +1881,9 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
     y->matches_added = true;
 
     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SINK);
+    endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
 
 #ifndef __TIZEN_BT__
-    endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
     y->hf_audio_agent = hf_audio_agent_init(c);
 #endif
 
@@ -1758,6 +1948,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)
@@ -1765,9 +1958,8 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
 
         endpoint_done(y, PA_BLUETOOTH_PROFILE_A2DP_SINK);
 
-#ifndef __TIZEN_BT__
         endpoint_done(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
-#endif
+
         pa_dbus_connection_unref(y->connection);
     }
 
index 9d6c4c4..6bd4c66 100644 (file)
@@ -39,6 +39,9 @@ typedef struct pa_bluetooth_discovery pa_bluetooth_discovery;
 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_MAX
 } pa_bluetooth_hook_t;
 
@@ -110,6 +113,7 @@ 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);
@@ -123,11 +127,10 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);
 pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y);
 void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y);
 
-/*
 #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 06f9f1c..d7f8a85 100644 (file)
@@ -89,7 +89,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
     }
 
     /* Load module-loopback */
-    args = pa_sprintf_malloc("source=\"%s\" source_dont_move=\"true\" sink_input_properties=\"media.role=%s\"", source->name, role);
+#ifdef __TIZEN__
+    args = pa_sprintf_malloc("source=\"%s\" source_dont_move=\"true\" sink_input_properties=\"media.role=%s media.policy=auto media.tizen_volume_type=4\" adjust_time=0", source->name, role);
+#else
+    args = pa_sprintf_malloc("source=\"%s\" source_dont_move=\"true\" sink_input_properties=\"media.role=%s\" adjust_time=0", source->name, role);
+#endif
     (void) pa_module_load(c, "module-loopback", args);
     pa_xfree(args);
 
@@ -126,7 +130,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *
     }
 
     /* Load module-loopback */
-    args = pa_sprintf_malloc("sink=\"%s\" sink_dont_move=\"true\" source_output_properties=\"media.role=%s\"", sink->name, role);
+    args = pa_sprintf_malloc("sink=\"%s\" sink_dont_move=\"true\" source_output_properties=\"media.role=%s\" adjust_time=0", sink->name, role);
     (void) pa_module_load(c, "module-loopback", args);
     pa_xfree(args);
 
@@ -170,7 +174,7 @@ static pa_hook_result_t profile_available_hook_callback(pa_core *c, pa_card_prof
         return PA_HOOK_OK;
 
     /* Do not automatically switch profiles for headsets, just in case */
-    if (pa_streq(profile->name, "hsp") || pa_streq(profile->name, "a2dp"))
+    if (pa_streq(profile->name, "hsp") || pa_streq(profile->name, "a2dp_sink"))
         return PA_HOOK_OK;
 
     is_active_profile = card->active_profile == profile;
index 3f329d1..739c492 100644 (file)
@@ -100,12 +100,10 @@ typedef struct sbc_info {
     uint16_t seq_num;                    /* Cumulative packet sequence */
     uint8_t min_bitpool;
     uint8_t max_bitpool;
-#ifdef __TIZEN_BT__
 #ifdef BLUETOOTH_APTX_SUPPORT
     pa_bool_t aptx_initialized;          /* Keep track if the encoder is initialized */
     void *aptx;                          /* aptx Codec data */
 #endif
-#endif
     void* buffer;                        /* Codec transfer buffer */
     size_t buffer_size;                  /* Size of the buffer */
 } sbc_info_t;
@@ -116,6 +114,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_bluetooth_discovery *discovery;
     pa_bluetooth_device *device;
@@ -240,7 +241,6 @@ static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff) {
     pa_assert_not_reached();
 }
 
-#ifdef __TIZEN_BT__
 #ifdef BLUETOOTH_APTX_SUPPORT
 void* (*aptx_new)(short endian);
 int (*aptx_encode)(void* _state, void* _pcmL, void* _pcmR, void* _buffer);
@@ -276,7 +276,6 @@ static pa_bool_t pa_load_aptx_sym(void *handle )
        return true;
 }
 #endif
-#endif
 
 /* Run from main thread */
 static void connect_ports(struct userdata *u, void *new_data, pa_direction_t direction) {
@@ -615,7 +614,7 @@ static int a2dp_aptx_process_render(struct userdata *u) {
 
     int pcmL[4],pcmR[4];
     int i=0;
-    const short *mybuffer;
+    const uint8_t *mybuffer;
 
     pa_assert(u);
     pa_assert(u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK);
@@ -642,7 +641,7 @@ static int a2dp_aptx_process_render(struct userdata *u) {
         size_t written;
         ssize_t encoded;
 
-        mybuffer=(uint8_t *)p;
+        mybuffer = (uint8_t *)p;
 
         for (i = 0; i < 4; i += 1) {
            pcmL[i] = mybuffer[2*i];
@@ -1298,6 +1297,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) {
@@ -1307,9 +1336,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;
 
@@ -1491,7 +1545,23 @@ static void thread_func(void *userdata) {
         bool disable_timer = true;
 
         pollfd = u->rtpoll_item ? pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL) : NULL;
-
+#ifdef __TIZEN_BT__
+        if (pollfd && (pollfd->revents & ~(POLLOUT|POLLIN))) {
+            pa_log_info("FD error: %s%s%s%s",
+                        pollfd->revents & POLLERR ? "POLLERR " :"",
+                        pollfd->revents & POLLHUP ? "POLLHUP " :"",
+                        pollfd->revents & POLLPRI ? "POLLPRI " :"",
+                        pollfd->revents & POLLNVAL ? "POLLNVAL " :"");
+            if (pollfd->revents & POLLHUP) {
+                       pollfd = NULL;
+                       do_write = 0;
+                       pending_read_bytes = 0;
+                       writable = false;
+                       transport_release(u);
+            } else
+                goto fail;
+        }
+#endif
         if (u->source && PA_SOURCE_IS_LINKED(u->source->thread_info.state)) {
 
             /* We should send two blocks to the device before we expect
@@ -1509,7 +1579,11 @@ static void thread_func(void *userdata) {
                     n_read = a2dp_process_push(u);
 
                 if (n_read < 0)
-                    goto io_fail;
+#ifdef __TIZEN_BT__
+                       goto fail;
+#else
+                       goto io_fail;
+#endif
 
                 /* We just read something, so we are supposed to write something, too */
                 pending_read_bytes += n_read;
@@ -1570,28 +1644,23 @@ static void thread_func(void *userdata) {
                 }
 
                 if (writable && do_write > 0) {
-                    int n_written;
+                    int n_written = 0;
 
                     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 io_fail;
-                       }
-#ifdef BLUETOOTH_APTX_SUPPORT
-                       else {
-                           if ((n_written = a2dp_aptx_process_render(u)) < 0)
-                               goto io_fail;
-                       }
-#endif
+                               if(u->sbc_info.sbc_initialized) {
+                                   if ((n_written = a2dp_process_render(u)) < 0)
+                                       goto fail;
+                               } else {
+                                   if ((n_written = a2dp_aptx_process_render(u)) < 0)
+                                       goto fail;
+                               }
                     } else if ((u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) &&
                                            u->transport_suspended_by_remote) {
-#ifdef BLUETOOTH_APTX_SUPPORT
                         a2dp_process_null_render(u);
-#endif
 #else
                     if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK ) {
                         if ((n_written = a2dp_process_render(u)) < 0)
@@ -1599,7 +1668,11 @@ static void thread_func(void *userdata) {
 #endif
                     } else {
                         if ((n_written = sco_process_render(u)) < 0)
-                            goto io_fail;
+#ifdef __TIZEN_BT__
+                               goto fail;
+#else
+                               goto io_fail;
+#endif
                     }
 
                     if (n_written == 0)
@@ -1642,12 +1715,14 @@ static void thread_func(void *userdata) {
             pa_log_debug("pa_rtpoll_run failed with: %d", ret);
             goto fail;
         }
+
         if (ret == 0) {
             pa_log_debug("IO thread shutdown requested, stopping cleanly");
             transport_release(u);
             goto finish;
         }
 
+#ifndef __TIZEN_BT__
         pollfd = u->rtpoll_item ? pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL) : NULL;
 
         if (pollfd && (pollfd->revents & ~(POLLOUT|POLLIN))) {
@@ -1671,8 +1746,10 @@ io_fail:
         writable = false;
 
         transport_release(u);
+#endif
     }
 
+
 fail:
     /* If this was no regular exit from the loop we have to continue processing messages until we receive PA_MESSAGE_SHUTDOWN */
     pa_log_debug("IO thread failed");
@@ -1741,9 +1818,9 @@ static void stop_thread(struct userdata *u) {
     }
 
     if (u->rtpoll) {
-        pa_thread_mq_done(&u->thread_mq);
         pa_rtpoll_free(u->rtpoll);
         u->rtpoll = NULL;
+        pa_thread_mq_done(&u->thread_mq);
     }
 
     if (u->transport) {
@@ -1863,6 +1940,7 @@ static pa_available_t transport_state_to_availability(pa_bluetooth_transport_sta
 static void create_card_ports(struct userdata *u, pa_hashmap *ports) {
     pa_device_port *port;
     pa_device_port_new_data port_data;
+
     const char *name_prefix, *input_description, *output_description;
 
     pa_assert(u);
@@ -1974,7 +2052,6 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
 
         p = PA_CARD_PROFILE_DATA(cp);
         *p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
-#ifndef __TIZEN_BT__
     } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE)) {
         cp = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP Source)"), sizeof(pa_bluetooth_profile_t));
         cp->priority = 10;
@@ -1986,6 +2063,7 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
 
         p = PA_CARD_PROFILE_DATA(cp);
         *p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
+#ifndef __TIZEN_BT__
     } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) {
        /* TODO: Change this profile's name to headset_head_unit, to reflect the remote
          * device's role and be consistent with the other profiles */
@@ -2247,6 +2325,46 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y,
     return PA_HOOK_OK;
 }
 
+#ifdef __TIZEN_BT__
+void dbus_sco_open_handler(struct userdata *u, struct pa_bluetooth_transport *t)
+{
+    if (u->sink) {
+            pa_log_info("Suspending sink %s to handle the SCO connection", u->sink->name);
+
+            pa_sink *sink_null = NULL;
+            pa_sink_input *si;
+            uint32_t idx;
+
+            if (pa_sink_check_suspend(u->sink) > 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);
@@ -2286,6 +2404,9 @@ int pa__init(pa_module* m) {
     struct userdata *u;
     const char *path;
     pa_modargs *ma;
+#ifdef BLUETOOTH_APTX_SUPPORT
+    void *handle;
+#endif
 
     pa_assert(m);
 
@@ -2331,6 +2452,11 @@ int pa__init(pa_module* m) {
     u->transport_state_changed_slot =
         pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED),
                         PA_HOOK_NORMAL, (pa_hook_cb_t) transport_state_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;
@@ -2344,6 +2470,15 @@ int pa__init(pa_module* m) {
     u->msg->parent.process_msg = device_process_msg;
     u->msg->card = u->card;
 
+#ifdef BLUETOOTH_APTX_SUPPORT
+    handle = pa_aptx_get_handle();
+
+    if (handle) {
+           pa_log_debug("Aptx Library loaded\n");
+           pa_load_aptx_sym(handle);
+    }
+#endif
+
     if (u->profile != PA_BLUETOOTH_PROFILE_OFF)
         if (init_profile(u) < 0)
             goto off;
@@ -2386,6 +2521,10 @@ void pa__done(pa_module *m) {
 
     if (u->transport_state_changed_slot)
         pa_hook_slot_free(u->transport_state_changed_slot);
+#ifdef __TIZEN_BT__
+    if (u->sco_state_changed_slot)
+        pa_hook_slot_free(u->sco_state_changed_slot);
+#endif
 
     if (u->sbc_info.buffer)
         pa_xfree(u->sbc_info.buffer);
index 5930992..c59640c 100644 (file)
@@ -41,6 +41,9 @@ PA_MODULE_VERSION(PACKAGE_VERSION);
 #ifdef __TIZEN_BT__
 PA_MODULE_USAGE("sco_sink=<name of sink> "
                                        "sco_source=<name of source> "
+#ifdef BLUETOOTH_APTX_SUPPORT
+                                       "aptx_lib_name=<name of aptx library name>"
+#endif
 );
 #endif
 PA_MODULE_LOAD_ONCE(true);
@@ -49,6 +52,9 @@ PA_MODULE_LOAD_ONCE(true);
 static const char* const valid_modargs[] = {
     "sco_sink",
     "sco_source",
+#ifdef BLUETOOTH_APTX_SUPPORT
+    "aptx_lib_name",
+#endif
     NULL
 };
 #endif
@@ -87,11 +93,11 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y,
 #endif
 
 #ifdef __TIZEN_BT__
-       if (pa_bluetooth_device_sink_transport_connected(d) == true) {
-               char *tmp = pa_sprintf_malloc("%s profile=\"a2dp_sink\"", args);
-               pa_xfree(args);
-               args = tmp;
-       }
+       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);
@@ -113,9 +119,29 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y,
 
 int pa__init(pa_module *m) {
     struct userdata *u;
+#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");
+        goto fail;
+    }
+
+    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->module = m;
     u->core = m->core;
@@ -128,9 +154,15 @@ int pa__init(pa_module *m) {
         pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED),
                         PA_HOOK_NORMAL, (pa_hook_cb_t) device_connection_changed_cb, u);
 
+    if (ma)
+           pa_modargs_free(ma);
+
     return 0;
 
 fail:
+    if (ma)
+           pa_modargs_free(ma);
+
     pa__done(m);
     return -1;
 }
@@ -152,5 +184,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);
 }