From 35875266857afa9c899c4966c1cb92134de38700 Mon Sep 17 00:00:00 2001 From: DoHyun Pyun Date: Fri, 29 May 2015 16:37:52 +0900 Subject: [PATCH] bluetooth: Add SuspendMedia method 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 Signed-off-by: Hyuk Lee --- src/modules/bluetooth/bluez5-util.c | 244 +++++++++++++++++++++--- src/modules/bluetooth/bluez5-util.h | 7 +- src/modules/bluetooth/module-bluetooth-policy.c | 10 +- src/modules/bluetooth/module-bluez5-device.c | 187 +++++++++++++++--- src/modules/bluetooth/module-bluez5-discover.c | 46 ++++- 5 files changed, 434 insertions(+), 60 deletions(-) diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 6ae4807..bc89707 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -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 @@ " " \ " " \ " " \ + " " \ + " " \ " " \ " " \ " " \ @@ -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); } diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index 9d6c4c4..6bd4c66 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -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 diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c index 06f9f1c..d7f8a85 100644 --- a/src/modules/bluetooth/module-bluetooth-policy.c +++ b/src/modules/bluetooth/module-bluetooth-policy.c @@ -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; diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 3f329d1..739c492 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -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); diff --git a/src/modules/bluetooth/module-bluez5-discover.c b/src/modules/bluetooth/module-bluez5-discover.c index 5930992..c59640c 100644 --- a/src/modules/bluetooth/module-bluez5-discover.c +++ b/src/modules/bluetooth/module-bluez5-discover.c @@ -41,6 +41,9 @@ PA_MODULE_VERSION(PACKAGE_VERSION); #ifdef __TIZEN_BT__ PA_MODULE_USAGE("sco_sink= " "sco_source= " +#ifdef BLUETOOTH_APTX_SUPPORT + "aptx_lib_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); } -- 2.7.4