AC_SUBST(HAVE_BLUEZ)
AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
-## HAVE_BLUEZ_VENDOR_CODEC ##
-AS_IF([test "x$HAVE_BLUEZ_5" = "x1"], HAVE_BLUEZ_VENDOR_CODEC=1, HAVE_BLUEZ_VENDOR_CODEC=0)
-AC_SUBST(HAVE_BLUEZ_VENDOR_CODEC)
-AM_CONDITIONAL([HAVE_BLUEZ_VENDOR_CODEC], [test "x$HAVE_BLUEZ_VENDOR_CODEC" = x1])
-
## Bluetooth Headset profiles backend ##
AC_ARG_ENABLE([bluez5-ofono-headset],
AS_IF([test "x$HAVE_SYSTEMD_JOURNAL" = "x1"], ENABLE_SYSTEMD_JOURNAL=yes, ENABLE_SYSTEMD_JOURNAL=no)
AS_IF([test "x$HAVE_BLUEZ_4" = "x1"], ENABLE_BLUEZ_4=yes, ENABLE_BLUEZ_4=no)
AS_IF([test "x$HAVE_BLUEZ_5" = "x1"], ENABLE_BLUEZ_5=yes, ENABLE_BLUEZ_5=no)
-AS_IF([test "x$HAVE_BLUEZ_VENDOR_CODEC" = "x1"], HAVE_BLUEZ_VENDOR_CODEC=yes, HAVE_BLUEZ_VENDOR_CODEC=no)
AS_IF([test "x$HAVE_BLUEZ_5_OFONO_HEADSET" = "x1"], ENABLE_BLUEZ_5_OFONO_HEADSET=yes, ENABLE_BLUEZ_5_OFONO_HEADSET=no)
AS_IF([test "x$HAVE_BLUEZ_5_NATIVE_HEADSET" = "x1"], ENABLE_BLUEZ_5_NATIVE_HEADSET=yes, ENABLE_BLUEZ_5_NATIVE_HEADSET=no)
AS_IF([test "x$HAVE_HAL_COMPAT" = "x1"], ENABLE_HAL_COMPAT=yes, ENABLE_HAL_COMPAT=no)
%{_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/module-a2dp-vendor-codec-aptx.so
%{_libdir}/pulse-%{version}/modules/libbluez5-util.so
%endif
module-bluez5-device.la
endif
-if HAVE_BLUEZ_VENDOR_CODEC
-modlibexec_LTLIBRARIES += \
- module-a2dp-vendor-codec-aptx.la
-endif
-
# RAOP depends on RTP, and we don't support RTP on Windows, see comment at
# librtp.la above.
if !OS_IS_WIN32
module-esound-sink-symdef.h
endif
-if HAVE_BLUEZ_VENDOR_CODEC
-SYMDEF_FILES += \
- module-a2dp-vendor-aptx-symdef.h
-endif
-
EXTRA_DIST += $(SYMDEF_FILES)
BUILT_SOURCES += $(SYMDEF_FILES) builddirs
libbluez5_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-if HAVE_BLUEZ_VENDOR_CODEC
-module_a2dp_vendor_codec_aptx_la_SOURCES = \
- modules/bluetooth/module-a2dp-vendor-codec-aptx.c \
- modules/bluetooth/module-a2dp-vendor-codec.h \
- modules/bluetooth/a2dp-codecs.h
-module_a2dp_vendor_codec_aptx_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_a2dp_vendor_codec_aptx_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libbluez5-util.la
-module_a2dp_vendor_codec_aptx_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-endif
-
module_bluez5_discover_la_SOURCES = modules/bluetooth/module-bluez5-discover.c
module_bluez5_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
module_bluez5_discover_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libbluez5-util.la
#define A2DP_CODEC_MPEG24 0x02
#define A2DP_CODEC_ATRAC 0x03
#ifdef __TIZEN_BT__
-/* #define BLUETOOTH_APTX_SUPPORT 1 */
+#define BLUETOOTH_APTX_SUPPORT 1
#define A2DP_CODEC_VENDOR 0xFF
#endif
#define A2DP_CODEC_NON_A2DP 0xFF
#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)
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;
#endif
#ifdef BLUETOOTH_APTX_SUPPORT
- register_endpoint(y, path, A2DP_APTX_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
+ 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)) {
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
-#ifdef __TIZEN_BT__
-struct pa_bluetooth_vendor_codec_ops {
- const char *name;
- bool (*init)();
- bool (*deinit)();
- int (*transport_config)(void *data);
- int (*process_render)(void *data);
-};
#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright (C) 2018 Samsung Electronics Co., Ltd.
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "module-a2dp-vendor-codec.h"
-
-#define APTX_NEW_NAME "NewAptxEnc"
-#define APTX_ENCODE_NAME "aptxbtenc_encodestereo"
-#define APTX_LIB_NAME "libbtaptx-armv6L.so"
-
-typedef struct {
- void *aptx_handle;
- void *(*aptx_new)(short endian);
- int (*aptx_encode)(void *_state, void *_pcmL, void *_pcmR, void *_buffer);
- bool aptx_initialized; /* Keep track if the encoder is initialized */
- void *aptx_data; /* aptx Codec data */
-} aptx_userdata_t;
-static aptx_userdata_t ud;
-
-static bool aptx_init()
-{
- char *lib_path = NULL;
-
- lib_path = pa_sprintf_malloc("%s/%s", PA_DLSEARCHPATH, APTX_LIB_NAME);
- if (!lib_path)
- return false;
-
- pa_log_info("lib_path: %s", lib_path);
-
- ud.aptx_handle = dlopen(lib_path, RTLD_LAZY);
- if (!ud.aptx_handle) {
- pa_log_warn("Unable to load aptX library (%s)", dlerror());
- pa_xfree(lib_path);
- return false;
- }
-
- pa_log_debug("Loaded aptX library successfully");
- pa_xfree(lib_path);
-
- ud.aptx_new = (void *(*)(short endian))dlsym(ud.aptx_handle, APTX_NEW_NAME);
- if (ud.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;
- }
-
- ud.aptx_encode = (int (*)(void *_state, void *_pcmL, void *_pcmR, void *_buffer))dlsym(ud.aptx_handle, APTX_ENCODE_NAME);
- if (ud.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;
-}
-
-static bool aptx_deinit()
-{
- if (!ud.aptx_handle) {
- pa_log_warn("Unable to unload aptX");
- return false;
- }
-
- dlclose(ud.aptx_handle);
- ud.aptx_handle = NULL;
-
- pa_log_debug("Unloaded aptX successfully");
- return true;
-}
-
-static int aptx_transport_config(void *data)
-{
- struct userdata *u = data;
- const pa_bluetooth_transport *t;
-
- t = u->transport;
- pa_assert(t);
-
- u->sample_spec.format = PA_SAMPLE_S16LE;
-
- if (!ud.aptx_initialized) {
-#if __BYTE_ORDER==__LITTLE_ENDIAN
- ud.aptx_data = ud.aptx_new(1);
-#elif __BYTE_ORDER==__BIG_ENDIAN
- ud.aptx_data = ud.aptx_new(0);
-#else
-#error "Unknown byte order"
-#endif
- ud.aptx_initialized = true;
- }
-
- pa_log_debug("aptX Encoder is initialized!!");
-
- 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);
- return 0;
-}
-
-static void aptx_prepare_buffer(struct userdata *u)
-{
- size_t min_buffer_size = PA_MAX(u->read_link_mtu, u->write_link_mtu);
-
- pa_assert(u);
-
- if (u->sbc_info.buffer_size >= min_buffer_size)
- return;
-
- u->sbc_info.buffer_size = 2 * min_buffer_size;
- pa_xfree(u->sbc_info.buffer);
- u->sbc_info.buffer = pa_xmalloc(u->sbc_info.buffer_size);
-}
-
-/* Run from IO thread */
-#define APTX_PCM_LEN 4
-#define APTX_ENCODE_LEN_MAX 16
-#define APTX_WRITE_LEN_MAX 4
-static int aptx_process_render(void *data)
-{
- struct userdata *u = data;
- struct sbc_info *a2dp;
- size_t nbytes;
- void *d;
- const void *p;
- size_t to_write, to_encode;
- int ret = 0;
- int pcmL[APTX_PCM_LEN], pcmR[APTX_PCM_LEN];
- 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);
-
- aptx_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)) {
- 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 */
- ud.aptx_encode(ud.aptx_data, pcmL, pcmR, (short *)d);
-
- pa_assert_fp((size_t)APTX_ENCODE_LEN_MAX <= to_encode);
- pa_assert_fp((size_t)APTX_WRITE_LEN_MAX <= to_write);
-
- p = (const uint8_t *)p + APTX_ENCODE_LEN_MAX;
- to_encode -= APTX_ENCODE_LEN_MAX;
-
- d = (uint8_t *)d + APTX_WRITE_LEN_MAX;
- to_write -= APTX_WRITE_LEN_MAX;
- }
-
- 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;
-}
-
-struct pa_bluetooth_vendor_codec_ops vendor_codec_ops = {
- .name = "APTX",
- .init = aptx_init,
- .deinit = aptx_deinit,
- .transport_config = aptx_transport_config,
- .process_render = aptx_process_render,
-};
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright (C) 2018 Samsung Electronics Co., Ltd.
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
-***/
-
-#ifndef __MODULE_A2DP_VENDOR_CODEC_H__
-#define __MODULE_A2DP_VENDOR_CODEC_H__
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <sbc/sbc.h>
-#include <dlfcn.h>
-
-#include <pulsecore/core-error.h>
-#include <pulsecore/core-rtclock.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/module.h>
-#include <pulsecore/modargs.h>
-#include <pulsecore/thread.h>
-#include <pulsecore/thread-mq.h>
-#include <pulsecore/time-smoother.h>
-
-#include "bluez5-util.h"
-
-typedef struct bluetooth_msg {
- pa_msgobject parent;
- pa_card *card;
-} bluetooth_msg;
-
-typedef struct sbc_info {
- sbc_t sbc; /* Codec data */
- bool sbc_initialized; /* Keep track if the encoder is initialized */
- size_t codesize, frame_length; /* SBC Codesize, frame_length. We simply cache those values here */
- uint16_t seq_num; /* Cumulative packet sequence */
- uint8_t min_bitpool;
- uint8_t max_bitpool;
- void *buffer; /* Codec transfer buffer */
- size_t buffer_size; /* Size of the buffer */
-} sbc_info_t;
-
-struct userdata {
- pa_module *module;
- pa_core *core;
-
- pa_hook_slot *device_connection_changed_slot;
- pa_hook_slot *transport_state_changed_slot;
- pa_hook_slot *sco_state_changed_slot;
- pa_hook_slot *transport_speaker_gain_changed_slot;
- pa_hook_slot *transport_microphone_gain_changed_slot;
-
- pa_bluetooth_discovery *discovery;
- pa_bluetooth_device *device;
- pa_bluetooth_transport *transport;
- bool transport_acquired;
- bool stream_setup_done;
-
- bool transport_suspended_by_remote;
- pa_card *card;
- pa_sink *sink;
- pa_source *source;
- pa_bluetooth_profile_t profile;
- char *output_port_name;
- char *input_port_name;
-
- pa_thread *thread;
- pa_thread_mq thread_mq;
- pa_rtpoll *rtpoll;
- pa_rtpoll_item *rtpoll_item;
- bluetooth_msg *msg;
-
- int stream_fd;
- int stream_write_type;
- size_t read_link_mtu;
- size_t write_link_mtu;
- size_t read_block_size;
- size_t write_block_size;
- uint64_t read_index;
- uint64_t write_index;
- pa_usec_t started_at;
- pa_smoother *read_smoother;
- pa_memchunk write_memchunk;
- pa_sample_spec sample_spec;
- struct sbc_info sbc_info;
-
- pa_modargs *modargs;
- struct pa_bluetooth_vendor_codec_ops *selected_ops;
- pa_proplist *vendor_codec_list;
- bool is_aptx_supported;
-};
-
-#endif /* __MODULE_A2DP_VENDOR_CODEC_H__ */
#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);
}
#ifdef __TIZEN_BT__
#include <pulsecore/sink.h>
#include <pulsecore/namereg.h>
-#include <dirent.h>
-#include <dlfcn.h>
#endif
#include "a2dp-codecs.h"
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;
#ifdef __TIZEN_BT__
pa_modargs *modargs;
- struct pa_bluetooth_vendor_codec_ops *selected_ops;
- pa_proplist *vendor_codec_list;
- bool is_aptx_supported;
#endif
};
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) {
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 __TIZEN_BT__
- if (u->is_aptx_supported) {
- 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) {
- struct pa_bluetooth_vendor_codec_ops *ops = NULL;
- size_t size;
- pa_log("A2DP_CODEC_NON_A2DP and this is APTX Codec");
- pa_proplist_get(u->vendor_codec_list, "APTX", &ops, &size);
- if (ops) {
- ops->transport_config(u);
- u->selected_ops = ops;
- } else {
- pa_log_error("APTX ops is NULL");
- }
- return;
- } else {
- pa_log("A2DP_CODEC_NON_A2DP but this is not APTX Codec");
- return;
- }
+#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
}
if (writable && do_write > 0) {
- int n_written = 0;
+ int n_written;
if (u->write_index <= 0)
u->started_at = pa_rtclock_now();
if ((n_written = a2dp_process_render(u)) < 0)
goto fail;
} else {
- if (u->selected_ops)
- if ((n_written = u->selected_ops->process_render(u)) < 0)
- goto fail;
- else
+#ifdef BLUETOOTH_APTX_SUPPORT
+ if ((n_written = a2dp_aptx_process_render(u)) < 0)
goto fail;
+#else
+ goto fail;
+#endif
}
} else if ((u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) &&
u->transport_suspended_by_remote) {
return 0;
}
-#ifdef __TIZEN_BT__
-#define MODULE_A2DP_VENDOR_CODEC "module-a2dp-vendor-codec"
-static void initialize_vendor_codec(struct userdata *u)
-{
- DIR *dir = NULL;
- struct dirent *ent = NULL;
-
- dir = opendir(PA_DLSEARCHPATH);
- if (!dir)
- return;
-
- u->vendor_codec_list = pa_proplist_new();
-
- /* Search vendor codec module */
- while ((ent = readdir(dir)) != NULL) {
- void *handle = NULL;
- struct pa_bluetooth_vendor_codec_ops *ops = NULL;
-
- if (strlen(ent->d_name) <= strlen(MODULE_A2DP_VENDOR_CODEC)
- || strncmp(ent->d_name, MODULE_A2DP_VENDOR_CODEC, strlen(MODULE_A2DP_VENDOR_CODEC)))
- continue;
-
- pa_log("Vendor codec found (%s)", ent->d_name);
- handle = dlopen(ent->d_name, RTLD_LAZY);
- if (!handle) {
- pa_log("dlopen() is failed (%s)", dlerror());
- continue;
- }
-
- ops = dlsym(handle, "vendor_codec_ops");
- if (!ops) {
- pa_log("dlsym() is failed (%s)", dlerror());
- dlclose(handle);
- continue;
- }
-
- /* Initialize vendor codec */
- if (ops->init) {
- if (ops->init()) {
- pa_log("Codec is initialized successfully (%s)", ent->d_name);
- /* Store the vendor_codec_ops */
- pa_proplist_set(u->vendor_codec_list, ops->name, ops, sizeof(struct pa_bluetooth_vendor_codec_ops));
- if (strcasecmp(ops->name, "APTX") == 0)
- u->is_aptx_supported = true;
- } else {
- pa_log("ops->init() is failed");
- }
- } else {
- pa_log("ops->init is NULL");
- }
- dlclose(handle);
- }
- closedir(dir);
-}
-#endif
-
int pa__init(pa_module* m) {
struct userdata *u;
const char *path;
pa_modargs *ma;
bool autodetect_mtu;
+#ifdef BLUETOOTH_APTX_SUPPORT
+ void *handle;
+#endif
pa_assert(m);
u->msg->card = u->card;
u->stream_setup_done = false;
-#ifdef __TIZEN_BT__
- initialize_vendor_codec(u);
+#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__
void pa__done(pa_module *m) {
struct userdata *u;
-#ifdef __TIZEN_BT__
- const char *key = NULL;
- void *state = NULL;
- size_t size;
- struct pa_bluetooth_vendor_codec_ops *ops = NULL;
-#endif
pa_assert(m);
pa_hook_slot_free(u->sco_state_changed_slot);
#endif
-#ifdef __TIZEN_BT__
- while ((key = pa_proplist_iterate(u->vendor_codec_list, &state))) {
- pa_proplist_get(u->vendor_codec_list, key, &ops, &size);
- ops->deinit();
- }
- pa_proplist_free(u->vendor_codec_list);
-#endif
-
if (u->transport_microphone_gain_changed_slot)
pa_hook_slot_free(u->transport_microphone_gain_changed_slot);
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(
"autodetect_mtu",
"sco_sink",
"sco_source",
+#ifdef BLUETOOTH_APTX_SUPPORT
+ "aptx_lib_name",
+#endif
NULL
};
#else
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"))
if (u->loaded_device_paths)
pa_hashmap_free(u->loaded_device_paths);
+#ifdef BLUETOOTH_APTX_SUPPORT
+ pa_unload_aptx();
+#endif
+
pa_xfree(u);
}