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)
%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
#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 {
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 {
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
#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)
#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 \
" </method>" \
" <method name=\"Release\">" \
" </method>" \
+ " <method name=\"SuspendMedia\">" \
+ " </method>" \
" </interface>" \
" <interface name=\"org.freedesktop.DBus.Introspectable\">" \
" <method name=\"Introspect\">" \
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;
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);
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"));
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 |
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);
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))) {
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;
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");
}
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:
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);
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:
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;
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;
}
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);
}
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;
pa_log_error("Invalid block length in configuration");
goto fail;
}
+#endif
}
dbus_message_iter_next(&props);
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);
{ 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)) {
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;
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;
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;
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,
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);
}
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");
",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;
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;
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)
"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)
#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;
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
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);
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
#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"
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;
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;
}
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);
}
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";
#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"
static const char* const valid_modargs[] = {
"path",
"autodetect_mtu",
+#ifdef __TIZEN_BT__
+ "address",
+ "profile",
+#endif
NULL
};
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;
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;
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;
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 {
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;
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;
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;
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
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;
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);
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) {
} 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;
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;
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;
p = PA_CARD_PROFILE_DATA(cp);
break;
-
case PA_BLUETOOTH_PROFILE_OFF:
pa_assert_not_reached();
}
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);
*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) {
pa_card_put(u->card);
p = PA_CARD_PROFILE_DATA(u->card->active_profile);
+
u->profile = *p;
return 0;
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);
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
}
}
}
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);
const char *path;
pa_modargs *ma;
bool autodetect_mtu;
+#ifdef BLUETOOTH_APTX_SUPPORT
+ void *handle;
+#endif
pa_assert(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;
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),
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;
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;
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);
#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;
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);
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;
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;
if (u->loaded_device_paths)
pa_hashmap_free(u->loaded_device_paths);
+#ifdef BLUETOOTH_APTX_SUPPORT
+ pa_unload_aptx();
+#endif
+
pa_xfree(u);
}