Merge the 2019-08-01 SPL branch from AOSP-Partner
* security-aosp-nyc-mr2-release:
Revert "DO NOT MERGE Separate SDP procedure from bonding state (1/2)"
DO NOT MERGE Fix for Bluetooth connection being dropped after HCI Read Encryption Key Size
DO NOT MERGE Separate SDP procedure from bonding state (1/2)
DO NOT MERGE Send HCI Read Encryption Key properly
DO NOT MERGE Fix potential OOB read in sdpu_get_len_from_type
DO NOT MERGE Don't persist bonds using sample LTK
DO NOT MERGE Drop Bluetooth connection with weak encryption key
Change-Id: I12dcf97029e0bddd45b8ee1f269aa4f547b47c09
diff --git a/Android.mk b/Android.mk
index 29760e4..00e8261 100644
--- a/Android.mk
+++ b/Android.mk
@@ -9,6 +9,10 @@
bluetooth_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
endif
+ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+bluetooth_CFLAGS += -DQLOGKIT_USERDEBUG
+endif
+
ifneq ($(BOARD_BLUETOOTH_BDROID_HCILP_INCLUDED),)
bluetooth_CFLAGS += -DHCILP_INCLUDED=$(BOARD_BLUETOOTH_BDROID_HCILP_INCLUDED)
endif
@@ -17,6 +21,12 @@
bluetooth_CFLAGS += -DBLUEDROID_DEBUG
endif
+bluetooth_CFLAGS += -DUSE_AUDIO_TRACK
+
+ifeq ($(BOARD_USES_WIPOWER),true)
+bluetooth_CFLAGS += -DWIPOWER_SUPPORTED
+endif
+
bluetooth_CFLAGS += -DEXPORT_SYMBOL="__attribute__((visibility(\"default\")))"
#
@@ -41,6 +51,12 @@
-UNDEBUG \
-DLOG_NDEBUG=1
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPLIT_A2DP)),true)
+bluetooth_CFLAGS += -DBTA_AV_SPLIT_A2DP_ENABLED
+bluetooth_CFLAGS += -DBTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+bluetooth_CFLAGS += -DAPTX_48000
+endif
+
bluetooth_CONLYFLAGS += -std=c99
bluetooth_CPPFLAGS :=
diff --git a/audio_a2dp_hw/Android.mk b/audio_a2dp_hw/Android.mk
index 0dc1388..7581068 100644
--- a/audio_a2dp_hw/Android.mk
+++ b/audio_a2dp_hw/Android.mk
@@ -12,6 +12,7 @@
$(LOCAL_PATH)/../ \
$(LOCAL_PATH)/../utils/include
+LOCAL_CFLAGS = -DBT_HOST_IPC_ENABLED
LOCAL_MODULE := audio.a2dp.default
LOCAL_MODULE_RELATIVE_PATH := hw
@@ -25,3 +26,24 @@
LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
include $(BUILD_SHARED_LIBRARY)
+
+##########################################
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bthost_ipc.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bthost_ipc.h \
+ $(LOCAL_PATH)/../ \
+ $(LOCAL_PATH)/../utils/include
+
+LOCAL_CFLAGS = $(bdroid_CFLAGS)
+
+LOCAL_MODULE := libbthost_if
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libosi
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c
index fdd05e4..e901c26 100644
--- a/audio_a2dp_hw/audio_a2dp_hw.c
+++ b/audio_a2dp_hw/audio_a2dp_hw.c
@@ -1,5 +1,9 @@
/******************************************************************************
+ * Copyright (C) 2016, The Linux Foundation. All rights reserved.
*
+ * Not a Contribution
+ ******************************************************************************/
+/*****************************************************************************
* Copyright (C) 2009-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +27,12 @@
* Description: Implements hal for bluedroid a2dp audio device
*
*****************************************************************************/
+//#define BT_AUDIO_SYSTRACE_LOG
+
+#ifdef BT_AUDIO_SYSTRACE_LOG
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
+#define PERF_SYSTRACE 1
+#endif
#define LOG_TAG "bt_a2dp_hw"
@@ -50,6 +60,23 @@
#include "osi/include/osi.h"
#include "osi/include/socket_utils/sockets.h"
+#include <dlfcn.h>
+
+#ifdef BT_HOST_IPC_ENABLED
+#include "bthost_ipc.h"
+#endif
+
+#ifdef BT_AUDIO_SYSTRACE_LOG
+#include <cutils/trace.h>
+#endif
+
+//#define BT_AUDIO_SAMPLE_LOG
+
+#ifdef BT_AUDIO_SAMPLE_LOG
+FILE *outputpcmsamplefile;
+char btoutputfilename [50] = "/data/audio/output_sample";
+static int number =0;
+#endif
/*****************************************************************************
** Constants & Macros
******************************************************************************/
@@ -71,20 +98,10 @@
#define ERROR(fmt, ...) LOG_ERROR(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
-
+//#define BT_HOST_IPC_PATH "/system/lib/hw/bthost-ipc.so"
/*****************************************************************************
** Local type definitions
******************************************************************************/
-
-typedef enum {
- AUDIO_A2DP_STATE_STARTING,
- AUDIO_A2DP_STATE_STARTED,
- AUDIO_A2DP_STATE_STOPPING,
- AUDIO_A2DP_STATE_STOPPED,
- AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
- AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */
-} a2dp_state_t;
-
struct a2dp_stream_in;
struct a2dp_stream_out;
@@ -94,23 +111,6 @@
struct a2dp_stream_out *output;
};
-struct a2dp_config {
- uint32_t rate;
- uint32_t channel_flags;
- int format;
-};
-
-/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
-
-struct a2dp_stream_common {
- pthread_mutex_t lock;
- int ctrl_fd;
- int audio_fd;
- size_t buffer_sz;
- struct a2dp_config cfg;
- a2dp_state_t state;
-};
-
struct a2dp_stream_out {
struct audio_stream_out stream;
struct a2dp_stream_common common;
@@ -126,7 +126,10 @@
/*****************************************************************************
** Static variables
******************************************************************************/
-
+#ifdef BT_HOST_IPC_ENABLED
+static void *lib_handle = NULL;
+bt_host_ipc_interface_t *ipc_if = NULL;
+#endif
/*****************************************************************************
** Static functions
******************************************************************************/
@@ -142,8 +145,9 @@
******************************************************************************/
/* Function used only in debug mode */
static const char* dump_a2dp_ctrl_event(char event) __attribute__ ((unused));
+#ifndef BT_HOST_IPC_ENABLED
static void a2dp_open_ctrl_path(struct a2dp_stream_common *common);
-
+#endif
/*****************************************************************************
** Miscellaneous helper functions
******************************************************************************/
@@ -157,11 +161,45 @@
CASE_RETURN_STR(A2DP_CTRL_CMD_START)
CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_STREAM_STARTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED)
default:
return "UNKNOWN MSG ID";
}
}
+static int calc_audiotime(struct a2dp_config cfg, int bytes)
+{
+ int chan_count = popcount(cfg.channel_flags);
+ int bytes_per_sample = 4;
+
+ ASSERTC(cfg.format == AUDIO_FORMAT_PCM_8_24_BIT,
+ "unsupported sample sz", cfg.format);
+
+ return (int)(((int64_t)bytes * (1000000 / (chan_count * bytes_per_sample))) / cfg.rate);
+}
+
+static void ts_error_log(char *tag, int val, int buff_size, struct a2dp_config cfg)
+{
+ struct timespec now;
+ static struct timespec prev = {0,0};
+ unsigned long long now_us;
+ unsigned long long diff_us;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
+
+ diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+ prev = now;
+ if(diff_us > (unsigned long long)(calc_audiotime (cfg, buff_size) + 10000L))
+ {
+ ERROR("[%s] ts %08lld, diff %08lld, val %d %d", tag, now_us, diff_us, val, buff_size);
+ }
+}
+
+#ifndef BT_HOST_IPC_ENABLED
/* logs timestamp with microsec precision
pprev is optional in case a dedicated diff is required */
static void ts_log(char *tag, int val, struct timespec *pprev_opt)
@@ -191,16 +229,23 @@
}
}
-static int calc_audiotime(struct a2dp_config cfg, int bytes)
+
+static const char* dump_a2dp_hal_state(int event)
{
- int chan_count = popcount(cfg.channel_flags);
-
- ASSERTC(cfg.format == AUDIO_FORMAT_PCM_16_BIT,
- "unsupported sample sz", cfg.format);
-
- return (int)(((int64_t)bytes * (1000000 / (chan_count * 2))) / cfg.rate);
+ switch(event)
+ {
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STARTING)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STARTED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STOPPING)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STOPPED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_SUSPENDED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STANDBY)
+ default:
+ return "UNKNOWN STATE ID";
+ }
}
+//#ifndef BT_HOST_IPC_ENABLED
/*****************************************************************************
**
** bluedroid stack adaptation
@@ -365,7 +410,7 @@
{
char ack;
- DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd));
+ INFO("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd));
if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
INFO("recovering from previous error");
@@ -393,7 +438,7 @@
return -1;
}
- DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
+ INFO("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
if (ack == A2DP_CTRL_ACK_INCALL_FAILURE)
return ack;
@@ -407,6 +452,7 @@
static int check_a2dp_ready(struct a2dp_stream_common *common)
{
+ INFO("state %s", dump_a2dp_hal_state(common->state));
if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0)
{
ERROR("check a2dp ready failed");
@@ -493,10 +539,31 @@
{
INFO("state %d", common->state);
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ char trace_buf[512];
+ #endif
+
+ INFO("state %s", dump_a2dp_hal_state(common->state));
+
int oldstate = common->state;
common->state = AUDIO_A2DP_STATE_STARTING;
int a2dp_status = a2dp_command(common, A2DP_CTRL_CMD_START);
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ snprintf(trace_buf, 32, "start_audio_data_path:");
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_BEGIN(trace_buf);
+ }
+ #endif
+
+
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_END();
+ }
+ #endif
if (a2dp_status < 0)
{
ERROR("Audiopath start failed (status %d)", a2dp_status);
@@ -508,6 +575,7 @@
goto error;
}
+#ifndef BTA_AV_SPLIT_A2DP_ENABLED
/* connect socket if not yet connected */
if (common->audio_fd == AUDIO_SKT_DISCONNECTED)
{
@@ -517,8 +585,11 @@
ERROR("Audiopath start failed - error opening data socket");
goto error;
}
+ common->state = AUDIO_A2DP_STATE_STARTED;
}
+#else
common->state = AUDIO_A2DP_STATE_STARTED;
+#endif
return 0;
error:
@@ -530,7 +601,7 @@
{
int oldstate = common->state;
- INFO("state %d", common->state);
+ INFO("state %s", dump_a2dp_hal_state(common->state));
/* prevent any stray output writes from autostarting the stream
while stopping audiopath */
@@ -545,16 +616,18 @@
common->state = AUDIO_A2DP_STATE_STOPPED;
+#ifndef BTA_AV_SPLIT_A2DP_ENABLED
/* disconnect audio path */
skt_disconnect(common->audio_fd);
common->audio_fd = AUDIO_SKT_DISCONNECTED;
+#endif
return 0;
}
static int suspend_audio_datapath(struct a2dp_stream_common *common, bool standby)
{
- INFO("state %d", common->state);
+ INFO("state %s", dump_a2dp_hal_state(common->state));
if (common->state == AUDIO_A2DP_STATE_STOPPING)
return -1;
@@ -567,15 +640,28 @@
else
common->state = AUDIO_A2DP_STATE_SUSPENDED;
+#ifndef BTA_AV_SPLIT_A2DP_ENABLED
/* disconnect audio path */
skt_disconnect(common->audio_fd);
common->audio_fd = AUDIO_SKT_DISCONNECTED;
+#endif
return 0;
}
+static int check_a2dp_stream_started(struct a2dp_stream_out *out)
+{
+ if (a2dp_command(&out->common, A2DP_CTRL_CMD_CHECK_STREAM_STARTED) < 0)
+ {
+ INFO("Btif not in stream state");
+ return -1;
+ }
+ return 0;
+}
+#endif
+
/*****************************************************************************
**
** audio output callbacks
@@ -587,6 +673,9 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
int sent = -1;
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ char trace_buf[512];
+ #endif
DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd);
@@ -601,7 +690,11 @@
if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) ||
(out->common.state == AUDIO_A2DP_STATE_STANDBY))
{
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->start_audio_datapath(&out->common) < 0)
+#else
if (start_audio_datapath(&out->common) < 0)
+#endif
{
goto finish;
}
@@ -611,13 +704,46 @@
ERROR("stream not in stopped or standby");
goto finish;
}
+ #ifdef BT_AUDIO_SAMPLE_LOG
+ if (outputpcmsamplefile)
+ {
+ fwrite (buffer,1,bytes,outputpcmsamplefile);
+ }
+ #endif
+
+ ts_error_log("a2dp_out_write", bytes, out->common.buffer_sz, out->common.cfg);
pthread_mutex_unlock(&out->common.lock);
+
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ snprintf(trace_buf, 32, "out_write:");
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_BEGIN(trace_buf);
+ }
+ #endif
+
+#ifdef BT_HOST_IPC_ENABLED
+ sent = ipc_if->skt_write(out->common.audio_fd, buffer, bytes);
+#else
sent = skt_write(out->common.audio_fd, buffer, bytes);
+#endif
pthread_mutex_lock(&out->common.lock);
- if (sent == -1) {
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_END();
+ }
+ #endif
+
+ if (sent == -1)
+ {
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->skt_disconnect(out->common.audio_fd);
+#else
skt_disconnect(out->common.audio_fd);
+#endif
out->common.audio_fd = AUDIO_SKT_DISCONNECTED;
if ((out->common.state != AUDIO_A2DP_STATE_SUSPENDED) &&
(out->common.state != AUDIO_A2DP_STATE_STOPPING)) {
@@ -647,7 +773,7 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("rate %" PRIu32,out->common.cfg.rate);
+ INFO("rate %" PRIu32,out->common.cfg.rate);
return out->common.cfg.rate;
}
@@ -656,7 +782,7 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("out_set_sample_rate : %" PRIu32, rate);
+ INFO("out_set_sample_rate : %" PRIu32, rate);
if (rate != AUDIO_STREAM_DEFAULT_RATE)
{
@@ -676,7 +802,7 @@
const size_t period_size = out->common.buffer_sz / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS;
const size_t mixer_unit_size = 16 /* frames */ * 4 /* framesize */;
- DEBUG("socket buffer size: %zu period size: %zu", out->common.buffer_sz, period_size);
+ INFO("socket buffer size: %zu period size: %zu", out->common.buffer_sz, period_size);
if (period_size % mixer_unit_size != 0) {
ERROR("period size %zu not a multiple of %zu", period_size, mixer_unit_size);
}
@@ -688,7 +814,7 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_flags);
+ INFO("channels 0x%" PRIx32, out->common.cfg.channel_flags);
return out->common.cfg.channel_flags;
}
@@ -696,7 +822,7 @@
static audio_format_t out_get_format(const struct audio_stream *stream)
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- DEBUG("format 0x%x", out->common.cfg.format);
+ INFO("format 0x%x", out->common.cfg.format);
return out->common.cfg.format;
}
@@ -704,7 +830,7 @@
{
UNUSED(stream);
UNUSED(format);
- DEBUG("setting format not yet supported (0x%x)", format);
+ INFO("setting format not yet supported (0x%x)", format);
return -ENOSYS;
}
@@ -718,7 +844,11 @@
pthread_mutex_lock(&out->common.lock);
// Do nothing in SUSPENDED state.
if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
- retVal = suspend_audio_datapath(&out->common, true);
+#ifdef BT_HOST_IPC_ENABLED
+ retVal = ipc_if->suspend_audio_datapath(&out->common, true);
+#else
+ retVal = suspend_audio_datapath(&out->common, true);
+#endif
out->frames_rendered = 0; // rendered is reset, presented is not
pthread_mutex_unlock (&out->common.lock);
@@ -737,45 +867,129 @@
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- INFO("state %d", out->common.state);
+ INFO("out_set_parameters: state %d", out->common.state);
hash_map_t *params = hash_map_utils_new_from_string_params(kvpairs);
int status = 0;
-
+ char *keyval;
if (!params)
return status;
- pthread_mutex_lock(&out->common.lock);
-
/* dump params */
hash_map_utils_dump_string_keys_string_values(params);
- char *keyval = (char *)hash_map_get(params, "closing");
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ keyval = (char *)hash_map_get(params, "A2dpStarted");
+
+ if (keyval != NULL)
+ {
+ INFO("out_set_parameters, param: A2dpStarted");
+ if (strcmp(keyval, "true") == 0)
+ {
+ INFO("out_set_parameters, value: true");
+ pthread_mutex_lock(&out->common.lock);
+ if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ INFO("stream suspended");
+ status = -1;
+ }
+ else if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) ||
+ (out->common.state == AUDIO_A2DP_STATE_STANDBY))
+ {
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->start_audio_datapath(&out->common) < 0)
+#else
+ if (start_audio_datapath(&out->common) < 0)
+#endif
+ {
+ INFO("stream start failed");
+ status = -1;
+ }
+ }
+ else if (out->common.state != AUDIO_A2DP_STATE_STARTED)
+ {
+ ERROR("stream not in stopped or standby");
+ status = -1;
+ }
+ pthread_mutex_unlock(&out->common.lock);
+ INFO("stream start completes with status: %d", status);
+ }
+ else if (strcmp(keyval, "false") == 0)
+ {
+ INFO("out_set_parameters, value: false");
+ pthread_mutex_lock(&out->common.lock);
+ if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
+#ifdef BT_HOST_IPC_ENABLED
+ status = ipc_if->suspend_audio_datapath(&out->common, true);
+#else
+ status = suspend_audio_datapath(&out->common, true);
+#endif
+ else
+ {
+ ERROR("stream alreday suspended");
+ }
+ pthread_mutex_unlock(&out->common.lock);
+ INFO("stream stop completes with status: %d", status);
+ }
+ }
+#endif
+
+ keyval = (char *)hash_map_get(params, "closing");
if (keyval && strcmp(keyval, "true") == 0)
{
DEBUG("stream closing, disallow any writes");
+ pthread_mutex_lock(&out->common.lock);
out->common.state = AUDIO_A2DP_STATE_STOPPING;
+ pthread_mutex_unlock(&out->common.lock);
}
keyval = (char *)hash_map_get(params, "A2dpSuspended");
- if (keyval && strcmp(keyval, "true") == 0)
+ if (keyval)
{
- if (out->common.state == AUDIO_A2DP_STATE_STARTED)
- status = suspend_audio_datapath(&out->common, false);
- }
- else
- {
- /* Do not start the streaming automatically. If the phone was streaming
- * prior to being suspended, the next out_write shall trigger the
- * AVDTP start procedure */
- if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
- out->common.state = AUDIO_A2DP_STATE_STANDBY;
- /* Irrespective of the state, return 0 */
+ if (strcmp(keyval, "true") == 0)
+ {
+ pthread_mutex_lock(&out->common.lock);
+ if (out->common.state == AUDIO_A2DP_STATE_STARTED)
+#ifdef BT_HOST_IPC_ENABLED
+ status = ipc_if->suspend_audio_datapath(&out->common, false);
+#else
+ status = suspend_audio_datapath(&out->common, false);
+#endif
+ else
+ {
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->check_a2dp_stream_started(&out->common) == 0)
+#else
+ if (check_a2dp_stream_started(out) == 0)
+#endif
+ /*Btif and A2dp HAL state can be out of sync
+ *check state of btif and suspend audio.
+ *Happens when remote initiates start.*/
+#ifdef BT_HOST_IPC_ENABLED
+ status = ipc_if->suspend_audio_datapath(&out->common, false);
+#else
+ status = suspend_audio_datapath(&out->common, false);
+#endif
+ else
+ out->common.state = AUDIO_A2DP_STATE_SUSPENDED;
+ }
+ pthread_mutex_unlock(&out->common.lock);
+ }
+ else
+ {
+ pthread_mutex_lock(&out->common.lock);
+ /* Do not start the streaming automatically. If the phone was streaming
+ * prior to being suspended, the next out_write shall trigger the
+ * AVDTP start procedure */
+ if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
+ out->common.state = AUDIO_A2DP_STATE_STANDBY;
+ /* Irrespective of the state, return 0 */
+ pthread_mutex_unlock(&out->common.lock);
+ }
}
- pthread_mutex_unlock(&out->common.lock);
hash_map_free(params);
return status;
@@ -1007,7 +1221,11 @@
if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) ||
(in->common.state == AUDIO_A2DP_STATE_STANDBY))
{
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->start_audio_datapath(&in->common) < 0)
+#else
if (start_audio_datapath(&in->common) < 0)
+#endif
{
goto error;
}
@@ -1019,11 +1237,20 @@
}
pthread_mutex_unlock(&in->common.lock);
+#ifdef BT_HOST_IPC_ENABLED
+ read = ipc_if->skt_read(in->common.audio_fd, buffer, bytes);
+#else
read = skt_read(in->common.audio_fd, buffer, bytes);
+#endif
pthread_mutex_lock(&in->common.lock);
+
if (read == -1)
{
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->skt_disconnect(in->common.audio_fd);
+#else
skt_disconnect(in->common.audio_fd);
+#endif
in->common.audio_fd = AUDIO_SKT_DISCONNECTED;
if ((in->common.state != AUDIO_A2DP_STATE_SUSPENDED) &&
(in->common.state != AUDIO_A2DP_STATE_STOPPING)) {
@@ -1102,7 +1329,31 @@
if (!out)
return -ENOMEM;
+ #ifdef BT_AUDIO_SAMPLE_LOG
+ snprintf(btoutputfilename, sizeof(btoutputfilename), "%s%d%s", btoutputfilename, number,".pcm");
+ outputpcmsamplefile = fopen (btoutputfilename, "ab");
+ number++;
+ #endif
+#ifdef BT_HOST_IPC_ENABLED
+ lib_handle = dlopen("libbthost_if.so", RTLD_NOW);
+ if (!lib_handle)
+ {
+ INFO("Failed to load bthost-ipc library %s",dlerror());
+ ret = -1;
+ goto err_open;
+ }
+ else
+ {
+ ipc_if = (bt_host_ipc_interface_t*) dlsym(lib_handle,"BTHOST_IPC_INTERFACE");
+ if (!ipc_if)
+ {
+ ERROR("Failed to load BT IPC library symbol");
+ ret = -1;
+ goto err_open;
+ }
+ }
+#endif
out->stream.common.get_sample_rate = out_get_sample_rate;
out->stream.common.set_sample_rate = out_set_sample_rate;
out->stream.common.get_buffer_size = out_get_buffer_size;
@@ -1123,10 +1374,13 @@
/* initialize a2dp specifics */
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->a2dp_stream_common_init(&out->common);
+#else
a2dp_stream_common_init(&out->common);
-
+#endif
out->common.cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG;
- out->common.cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+ out->common.cfg.format = AUDIO_FORMAT_PCM_8_24_BIT;
out->common.cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
/* set output config values */
@@ -1139,7 +1393,11 @@
*stream_out = &out->stream;
a2dp_dev->output = out;
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->a2dp_open_ctrl_path(&out->common);
+#else
a2dp_open_ctrl_path(&out->common);
+#endif
if (out->common.ctrl_fd == AUDIO_SKT_DISCONNECTED)
{
ERROR("ctrl socket failed to connect (%s)", strerror(errno));
@@ -1147,10 +1405,17 @@
goto err_open;
}
- DEBUG("success");
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->a2dp_command(&out->common, A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED) == 0) {
+#else
+ if (a2dp_command(&out->common, A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED) == 0) {
+#endif
+ DEBUG("Streaming mode set successfully");
+ }
+ INFO("success");
/* Delay to ensure Headset is in proper state when START is initiated
from DUT immediately after the connection due to ongoing music playback. */
- usleep(250000);
+ usleep(1000000);
return 0;
err_open:
@@ -1171,17 +1436,31 @@
pthread_mutex_lock(&out->common.lock);
if ((out->common.state == AUDIO_A2DP_STATE_STARTED) ||
- (out->common.state == AUDIO_A2DP_STATE_STOPPING)) {
+ (out->common.state == AUDIO_A2DP_STATE_STOPPING))
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->stop_audio_datapath(&out->common);
+#else
stop_audio_datapath(&out->common);
- }
+#endif
+ #ifdef BT_AUDIO_SAMPLE_LOG
+ ALOGV("close file output");
+ fclose (outputpcmsamplefile);
+ #endif
+
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->skt_disconnect(out->common.ctrl_fd);
+#else
skt_disconnect(out->common.ctrl_fd);
+#endif
out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ if (lib_handle)
+ dlclose(lib_handle);
free(stream);
a2dp_dev->output = NULL;
pthread_mutex_unlock(&out->common.lock);
- DEBUG("done");
+ INFO("done");
}
static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
@@ -1193,7 +1472,7 @@
if (out == NULL)
return retval;
- INFO("state %d", out->common.state);
+
retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs);
@@ -1309,6 +1588,25 @@
if (!in)
return -ENOMEM;
+#ifdef BT_HOST_IPC_ENABLED
+ lib_handle = dlopen("libbthost_if.so", RTLD_NOW);
+ if (!lib_handle)
+ {
+ INFO("Failed to load bthost-ipc library %s",dlerror());
+ ret = -1;
+ goto err_open;
+ }
+ else
+ {
+ ipc_if = (bt_host_ipc_interface_t*) dlsym(lib_handle,"BTHOST_IPC_INTERFACE");
+ if (!ipc_if)
+ {
+ ERROR("Failed to load BT IPC library symbol");
+ ret = -1;
+ goto err_open;
+ }
+ }
+#endif
in->stream.common.get_sample_rate = in_get_sample_rate;
in->stream.common.set_sample_rate = in_set_sample_rate;
in->stream.common.get_buffer_size = in_get_buffer_size;
@@ -1326,12 +1624,19 @@
in->stream.get_input_frames_lost = in_get_input_frames_lost;
/* initialize a2dp specifics */
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->a2dp_stream_common_init(&in->common);
+#else
a2dp_stream_common_init(&in->common);
-
+#endif
*stream_in = &in->stream;
a2dp_dev->input = in;
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->a2dp_open_ctrl_path(&in->common);
+#else
a2dp_open_ctrl_path(&in->common);
+#endif
if (in->common.ctrl_fd == AUDIO_SKT_DISCONNECTED)
{
ERROR("ctrl socket failed to connect (%s)", strerror(errno));
@@ -1339,7 +1644,18 @@
goto err_open;
}
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->a2dp_command(&in->common, A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED) == 0) {
+#else
+ if (a2dp_command(&in->common, A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED) == 0) {
+#endif
+ DEBUG("Streaming mode set successfully");
+ }
+#ifdef BT_HOST_IPC_ENABLED
+ if (ipc_if->a2dp_read_audio_config(&in->common) < 0) {
+#else
if (a2dp_read_audio_config(&in->common) < 0) {
+#endif
ERROR("a2dp_read_audio_config failed (%s)", strerror(errno));
ret = -1;
goto err_open;
@@ -1366,13 +1682,22 @@
INFO("closing input (state %d)", state);
if ((state == AUDIO_A2DP_STATE_STARTED) || (state == AUDIO_A2DP_STATE_STOPPING))
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->stop_audio_datapath(&in->common);
+#else
stop_audio_datapath(&in->common);
+#endif
+#ifdef BT_HOST_IPC_ENABLED
+ ipc_if->skt_disconnect(in->common.ctrl_fd);
+#else
skt_disconnect(in->common.ctrl_fd);
+#endif
in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
free(stream);
a2dp_dev->input = NULL;
-
+ if (lib_handle)
+ dlclose(lib_handle);
DEBUG("done");
}
diff --git a/audio_a2dp_hw/audio_a2dp_hw.h b/audio_a2dp_hw/audio_a2dp_hw.h
index 11d438a..67fd212 100644
--- a/audio_a2dp_hw/audio_a2dp_hw.h
+++ b/audio_a2dp_hw/audio_a2dp_hw.h
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (C) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
+ *****************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
@@ -26,7 +31,7 @@
#ifndef AUDIO_A2DP_HW_H
#define AUDIO_A2DP_HW_H
-
+#include <pthread.h>
/*****************************************************************************
** Constants & Macros
******************************************************************************/
@@ -35,7 +40,12 @@
#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
#define AUDIO_STREAM_DEFAULT_RATE 44100
+#else
+#define AUDIO_STREAM_DEFAULT_RATE 48000
+#endif
+
#define AUDIO_STREAM_DEFAULT_FORMAT AUDIO_FORMAT_PCM_16_BIT
#define AUDIO_STREAM_DEFAULT_CHANNEL_FLAG AUDIO_CHANNEL_OUT_STEREO
@@ -55,7 +65,7 @@
// 20 * 512 is not sufficient size to smooth the variability for some BT devices,
// resulting in mixer sleep and throttling. We increase this to 28 * 512 to help
// reduce the effect of variable data consumption.
-#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28*512)
+#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28*1024)
// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is divided
// for AudioFlinger data delivery. The AudioFlinger mixer delivers data in chunks
@@ -80,21 +90,52 @@
typedef enum {
A2DP_CTRL_CMD_NONE,
A2DP_CTRL_CMD_CHECK_READY,
+ A2DP_CTRL_CMD_CHECK_STREAM_STARTED,
A2DP_CTRL_CMD_START,
A2DP_CTRL_CMD_STOP,
A2DP_CTRL_CMD_SUSPEND,
A2DP_CTRL_GET_AUDIO_CONFIG,
A2DP_CTRL_CMD_OFFLOAD_START,
+ A2DP_CTRL_CMD_OFFLOAD_SUPPORTED,
+ A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED,
} tA2DP_CTRL_CMD;
typedef enum {
A2DP_CTRL_ACK_SUCCESS,
A2DP_CTRL_ACK_FAILURE,
A2DP_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
+ A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS, /* Ack when Disconnection in Progress */
A2DP_CTRL_ACK_UNSUPPORTED
} tA2DP_CTRL_ACK;
+typedef enum {
+ AUDIO_A2DP_STATE_STARTING,
+ AUDIO_A2DP_STATE_STARTED,
+ AUDIO_A2DP_STATE_STOPPING,
+ AUDIO_A2DP_STATE_STOPPED,
+ AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
+ AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */
+} a2dp_state_t;
+
+struct a2dp_config {
+ uint32_t rate;
+ uint32_t channel_flags;
+ int format;
+};
+
+/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
+#define MAX_CODEC_CFG_SIZE 30
+
+struct a2dp_stream_common {
+ pthread_mutex_t lock;
+ int ctrl_fd;
+ int audio_fd;
+ size_t buffer_sz;
+ struct a2dp_config cfg;
+ a2dp_state_t state;
+ uint8_t codec_cfg[MAX_CODEC_CFG_SIZE];
+};
/*****************************************************************************
** Type definitions for callback functions
******************************************************************************/
diff --git a/audio_a2dp_hw/bthost_ipc.c b/audio_a2dp_hw/bthost_ipc.c
new file mode 100644
index 0000000..5137e94
--- /dev/null
+++ b/audio_a2dp_hw/bthost_ipc.c
@@ -0,0 +1,1262 @@
+/******************************************************************************
+ * Copyright (C) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
+ *****************************************************************************/
+/*****************************************************************************
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+/* bthost_ipc.c
+ *
+ * Description: Implements IPC interface between HAL and BT host
+ *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware/hardware.h>
+#include "bthost_ipc.h"
+#include "bt_utils.h"
+#include "osi/include/hash_map.h"
+#include "osi/include/hash_map_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "bthost_ipc"
+#include "osi/include/log.h"
+
+
+static int bt_split_a2dp_enabled = 0;
+static int open_ctrl_chnl_fail_count = 0;
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+/* Below two values adds up to 8 sec retry to address IOT issues*/
+#define STREAM_START_MAX_RETRY_COUNT 10
+#define STREAM_START_MAX_RETRY_LOOPER 8
+
+#define CTRL_CHAN_RETRY_COUNT 1
+#define USEC_PER_SEC 1000000L
+#define SOCK_SEND_TIMEOUT_MS 2000 /* Timeout for sending */
+#define SOCK_RECV_TIMEOUT_MS 5000 /* Timeout for receiving */
+
+// set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking sockets
+#define WRITE_POLL_MS 20
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+#define FNLOG() LOG_VERBOSE(LOG_TAG, "%s", __FUNCTION__);
+#define DEBUG(fmt, ...) LOG_VERBOSE(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define INFO(fmt, ...) LOG_INFO(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define WARN(fmt, ...) LOG_WARN(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define ERROR(fmt, ...) LOG_ERROR(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+
+#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+
+struct a2dp_stream_common audio_stream;
+
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+audio_sbc_encoder_config sbc_codec;
+audio_aptx_encoder_config aptx_codec;
+audio_aac_encoder_config aac_codec;
+/*****************************************************************************
+** Externs
+******************************************************************************/
+
+/*****************************************************************************
+** Functions
+******************************************************************************/
+static int check_a2dp_open_ready(struct a2dp_stream_common *common);
+void a2dp_open_ctrl_path(struct a2dp_stream_common *common);
+/*****************************************************************************
+** Miscellaneous helper functions
+******************************************************************************/
+static const char* dump_a2dp_ctrl_event(char event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_START)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_STREAM_STARTED)
+ CASE_RETURN_STR(A2DP_CTRL_GET_CODEC_CONFIG)
+ CASE_RETURN_STR(A2DP_CTRL_GET_MULTICAST_STATUS)
+ CASE_RETURN_STR(A2DP_CTRL_GET_CONNECTION_STATUS)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+/* logs timestamp with microsec precision
+ pprev is optional in case a dedicated diff is required */
+static void ts_log(char *tag, int val, struct timespec *pprev_opt)
+{
+ struct timespec now;
+ static struct timespec prev = {0,0};
+ unsigned long long now_us;
+ unsigned long long diff_us;
+ UNUSED(tag);
+ UNUSED(val);
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
+
+ if (pprev_opt)
+ {
+ diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+ *pprev_opt = now;
+ DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
+ }
+ else
+ {
+ diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+ prev = now;
+ DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
+ }
+}
+
+
+static const char* dump_a2dp_hal_state(int event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STARTING)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STARTED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STOPPING)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STOPPED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_SUSPENDED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STANDBY)
+ default:
+ return "UNKNOWN STATE ID";
+ }
+}
+static void* a2dp_codec_parser(uint8_t *codec_cfg, audio_format_t *codec_type)
+{
+ char byte,len;
+ uint8_t *p_cfg = codec_cfg;
+ INFO("%s",__func__);
+ if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_PCM)
+ {
+ *codec_type = AUDIO_FORMAT_PCM_16_BIT;
+ //For the time being Audio does not require any param to be passed for PCM so returning null
+ return NULL;
+ }
+ else if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_SBC)
+ {
+ memset(&sbc_codec,0,sizeof(audio_sbc_encoder_config));
+ p_cfg++;//skip dev idx
+ len = *p_cfg++;
+ p_cfg++;//skip media type
+ len--;
+ p_cfg++;
+ len--;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_SBC_FREQ_MASK)
+ {
+ case A2D_SBC_SAMP_FREQ_48:
+ sbc_codec.sampling_rate = 48000;
+ break;
+ case A2D_SBC_SAMP_FREQ_44:
+ sbc_codec.sampling_rate = 44100;
+ break;
+ case A2D_SBC_SAMP_FREQ_32:
+ sbc_codec.sampling_rate = 3200;
+ break;
+ case A2D_SBC_SAMP_FREQ_16:
+ sbc_codec.sampling_rate = 16000;
+ break;
+ default:
+ ERROR("Unkown sampling rate");
+ }
+
+ switch (byte & A2D_SBC_CHN_MASK)
+ {
+ case A2D_SBC_CH_MD_JOINT:
+ sbc_codec.channels = 3;
+ break;
+ case A2D_SBC_CH_MD_STEREO:
+ sbc_codec.channels = 2;
+ break;
+ case A2D_SBC_CH_MD_DUAL:
+ sbc_codec.channels = 1;
+ break;
+ case A2D_SBC_CH_MD_MONO:
+ sbc_codec.channels = 0;
+ break;
+ default:
+ ERROR("Unknow channel mode");
+ }
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_SBC_BLK_MASK)
+ {
+ case A2D_SBC_BLOCKS_16:
+ sbc_codec.blk_len = 16;
+ break;
+ case A2D_SBC_BLOCKS_12:
+ sbc_codec.blk_len = 12;
+ break;
+ case A2D_SBC_BLOCKS_8:
+ sbc_codec.blk_len = 8;
+ break;
+ case A2D_SBC_BLOCKS_4:
+ sbc_codec.blk_len = 4;
+ break;
+ default:
+ ERROR("Unknown block length");
+ }
+
+ switch (byte & A2D_SBC_SUBBAND_MASK)
+ {
+ case A2D_SBC_SUBBAND_8:
+ sbc_codec.subband = 8;
+ break;
+ case A2D_SBC_SUBBAND_4:
+ sbc_codec.subband = 4;
+ break;
+ default:
+ ERROR("Unknown subband");
+ }
+ switch (byte & A2D_SBC_ALLOC_MASK)
+ {
+ case A2D_SBC_ALLOC_MD_L:
+ sbc_codec.alloc = 1;
+ break;
+ case A2D_SBC_ALLOC_MD_S:
+ sbc_codec.alloc = 2;
+ default:
+ ERROR("Unknown alloc method");
+ }
+ sbc_codec.min_bitpool = *p_cfg++;
+ len--;
+ sbc_codec.max_bitpool = *p_cfg++;
+ len--;
+ if (len == 0)
+ INFO("Copied codec config");
+
+ p_cfg += 2; //skip mtu
+ sbc_codec.bitrate = *p_cfg++;
+ sbc_codec.bitrate |= (*p_cfg++ << 8);
+ sbc_codec.bitrate |= (*p_cfg++ << 16);
+ sbc_codec.bitrate |= (*p_cfg++ << 24);
+ *codec_type = AUDIO_FORMAT_SBC;
+ INFO("SBC: Done copying full codec config");
+ return ((void *)(&sbc_codec));
+ } else if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_AAC)
+ {
+ uint16_t aac_samp_freq = 0;
+ uint32_t aac_bit_rate = 0;
+ memset(&aac_codec,0,sizeof(audio_aac_encoder_config));
+ p_cfg++;//skip dev idx
+ len = *p_cfg++;
+ p_cfg++;//skip media type
+ len--;
+ p_cfg++;//skip codec type
+ len--;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_AAC_IE_OBJ_TYPE_MSK)
+ {
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_LC;
+ break;
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LC:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_LC;
+ break;
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LTP:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_LTP;
+ break;
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_SCA:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_SCALABLE;
+ break;
+ default:
+ ERROR("Unknown encoder mode");
+ }
+ //USE 0 (AAC_LC) as hardcoded value till Audio
+ //define constants
+ aac_codec.enc_mode = 0;
+ //USE LOAS(1) or LATM(4) hardcoded values till
+ //Audio define proper constants
+ aac_codec.format_flag = 4;
+ byte = *p_cfg++;
+ len--;
+ aac_samp_freq = byte << 8; //1st byte of sample_freq
+ byte = *p_cfg++;
+ len--;
+ aac_samp_freq |= byte & 0x00F0; //1st nibble of second byte of samp_freq
+
+ switch (aac_samp_freq) {
+ case 0x8000: aac_codec.sampling_rate = 8000; break;
+ case 0x4000: aac_codec.sampling_rate = 11025; break;
+ case 0x2000: aac_codec.sampling_rate = 12000; break;
+ case 0x1000: aac_codec.sampling_rate = 16000; break;
+ case 0x0800: aac_codec.sampling_rate = 22050; break;
+ case 0x0400: aac_codec.sampling_rate = 24000; break;
+ case 0x0200: aac_codec.sampling_rate = 32000; break;
+ case 0x0100: aac_codec.sampling_rate = 44100; break;
+ case 0x0080: aac_codec.sampling_rate = 48000; break;
+ case 0x0040: aac_codec.sampling_rate = 64000; break;
+ case 0x0020: aac_codec.sampling_rate = 88200; break;
+ case 0x0010: aac_codec.sampling_rate = 96000; break;
+ default:
+ ERROR("Invalid sample_freq: %x", aac_samp_freq);
+ }
+
+ switch (byte & A2D_AAC_IE_CHANNELS_MSK)
+ {
+ case A2D_AAC_IE_CHANNELS_1:
+ aac_codec.channels = 1;
+ break;
+ case A2D_AAC_IE_CHANNELS_2:
+ aac_codec.channels = 2;
+ break;
+ default:
+ ERROR("Unknow channel mode");
+ }
+ byte = *p_cfg++; //Move to VBR byte
+ len--;
+ switch (byte & A2D_AAC_IE_VBR_MSK)
+ {
+ case A2D_AAC_IE_VBR:
+ break;
+ default:
+ ERROR("VBR not supported");
+ }
+ aac_bit_rate = 0x7F&byte;
+ //Move it 2nd byte of 32 bit word. leaving the VBR bit
+ aac_bit_rate = aac_bit_rate << 16;
+ byte = *p_cfg++; //Move to 2nd byteof bitrate
+ len--;
+
+ //Move it to 3rd byte of 32bit word
+ aac_bit_rate |= 0x0000FF00 & (((uint32_t)byte)<<8);
+ byte = *p_cfg++; //Move to 3rd byte of bitrate
+ len--;
+
+ aac_bit_rate |= 0x000000FF & (((uint32_t)byte));
+ aac_codec.bitrate = aac_bit_rate;
+
+ *codec_type = AUDIO_FORMAT_AAC;
+ INFO("AAC: Done copying full codec config");
+ return ((void *)(&aac_codec));
+ }
+ else if (codec_cfg[CODEC_OFFSET] == NON_A2DP_CODEC_TYPE)
+ {
+ if (codec_cfg[VENDOR_ID_OFFSET] == VENDOR_APTX &&
+ codec_cfg[CODEC_ID_OFFSET] == APTX_CODEC_ID)
+ {
+ INFO("AptX-classic codec");
+ *codec_type = AUDIO_FORMAT_APTX;
+ }
+ if (codec_cfg[VENDOR_ID_OFFSET] == VENDOR_APTX_HD &&
+ codec_cfg[CODEC_ID_OFFSET] == APTX_HD_CODEC_ID)
+ {
+ INFO("AptX-HD codec");
+ *codec_type = AUDIO_FORMAT_APTX_HD;
+ }
+ memset(&aptx_codec,0,sizeof(audio_aptx_encoder_config));
+ p_cfg++; //skip dev_idx
+ len = *p_cfg++;//LOSC
+ p_cfg++; // Skip media type
+ len--;
+ p_cfg++; //codec_type
+ len--;
+ p_cfg+=4;//skip vendor id
+ len -= 4;
+ p_cfg += 2; //skip codec id
+ len -= 2;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_APTX_SAMP_FREQ_MASK)
+ {
+ case A2D_APTX_SAMP_FREQ_48:
+ aptx_codec.sampling_rate = 48000;
+ break;
+ case A2D_APTX_SAMP_FREQ_44:
+ aptx_codec.sampling_rate = 44100;
+ break;
+ default:
+ ERROR("Unknown sampling rate");
+ }
+ switch (byte & A2D_APTX_CHAN_MASK)
+ {
+ case A2D_APTX_CHAN_STEREO:
+ aptx_codec.channels = 2;
+ break;
+ case A2D_APTX_CHAN_MONO:
+ aptx_codec.channels = 1;
+ break;
+ default:
+ ERROR("Unknown channel mode");
+ }
+ if (*codec_type == AUDIO_FORMAT_APTX_HD) {
+ p_cfg += 4;
+ len -= 4;//ignore 4 bytes not used
+ }
+ if (len == 0)
+ INFO("Codec config copied");
+
+ p_cfg += 2; //skip mtu
+
+ aptx_codec.bitrate = *p_cfg++;
+ aptx_codec.bitrate |= (*p_cfg++ << 8);
+ aptx_codec.bitrate |= (*p_cfg++ << 16);
+ aptx_codec.bitrate |= (*p_cfg++ << 24);
+
+ INFO("APTx: Done copying full codec config");
+ return ((void *)&aptx_codec);
+ }
+ return NULL;
+}
+/*****************************************************************************
+**
+** bluedroid stack adaptation
+**
+*****************************************************************************/
+
+static int skt_connect(char *path, size_t buffer_sz)
+{
+ int ret;
+ int skt_fd;
+ int len;
+
+ INFO("connect to %s (sz %zu)", path, buffer_sz);
+
+ skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+ if(osi_socket_local_client_connect(skt_fd, path,
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
+ {
+ ERROR("failed to connect (%s)", strerror(errno));
+ close(skt_fd);
+ return -1;
+ }
+
+ len = buffer_sz;
+ ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
+ if (ret < 0)
+ ERROR("setsockopt failed (%s)", strerror(errno));
+
+ ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, (int)sizeof(len));
+ if (ret < 0)
+ ERROR("setsockopt failed (%s)", strerror(errno));
+
+ /* Socket send/receive timeout value */
+ struct timeval tv;
+ tv.tv_sec = SOCK_SEND_TIMEOUT_MS / 1000;
+ tv.tv_usec = (SOCK_SEND_TIMEOUT_MS % 1000) * 1000;
+
+ ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ if (ret < 0)
+ ERROR("setsockopt failed (%s)", strerror(errno));
+
+ tv.tv_sec = SOCK_RECV_TIMEOUT_MS / 1000;
+ tv.tv_usec = (SOCK_RECV_TIMEOUT_MS % 1000) * 1000;
+
+ ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ if (ret < 0)
+ ERROR("setsockopt failed (%s)", strerror(errno));
+
+ INFO("connected to stack fd = %d", skt_fd);
+
+ return skt_fd;
+}
+
+static int skt_read(int fd, void *p, size_t len)
+{
+ ssize_t read;
+
+ FNLOG();
+
+ ts_log("skt_read recv", len, NULL);
+
+ OSI_NO_INTR(read = recv(fd, p, len, MSG_NOSIGNAL));
+ if (read == -1)
+ ERROR("read failed with errno=%d\n", errno);
+
+ return (int)read;
+}
+
+static int skt_write(int fd, const void *p, size_t len)
+{
+ ssize_t sent;
+
+ FNLOG();
+
+ ts_log("skt_write", len, NULL);
+
+ if (WRITE_POLL_MS == 0) {
+ // do not poll, use blocking send
+ OSI_NO_INTR(sent = send(fd, p, len, MSG_NOSIGNAL));
+ if (sent == -1)
+ ERROR("write failed with error(%s)", strerror(errno));
+
+ return (int)sent;
+ }
+
+ // use non-blocking send, poll
+ int ms_timeout = SOCK_SEND_TIMEOUT_MS;
+ size_t count = 0;
+ while (count < len) {
+ OSI_NO_INTR(sent = send(fd, p, len - count, MSG_NOSIGNAL | MSG_DONTWAIT));
+ if (sent == -1) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ ERROR("write failed with error(%s)", strerror(errno));
+ return -1;
+ }
+ if (ms_timeout >= WRITE_POLL_MS) {
+ usleep(WRITE_POLL_MS * 1000);
+ ms_timeout -= WRITE_POLL_MS;
+ continue;
+ }
+ WARN("write timeout exceeded, sent %zu bytes", count);
+ return -1;
+ }
+ count += sent;
+ p = (const uint8_t *)p + sent;
+ }
+ return (int)count;
+}
+
+static int skt_disconnect(int fd)
+{
+ INFO("fd %d", fd);
+
+ if (fd != AUDIO_SKT_DISCONNECTED)
+ {
+ shutdown(fd, SHUT_RDWR);
+ close(fd);
+ }
+ return 0;
+}
+
+
+
+/*****************************************************************************
+**
+** AUDIO CONTROL PATH
+**
+*****************************************************************************/
+
+int a2dp_ctrl_receive(struct a2dp_stream_common *common, void* buffer, int length)
+{
+ ssize_t ret;
+ int i;
+
+ for (i = 0;; i++) {
+ OSI_NO_INTR(ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL));
+ if (ret > 0) {
+ break;
+ }
+ if (ret == 0) {
+ ERROR("ack failed: peer closed");
+ break;
+ }
+ if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ ERROR("ack failed: error(%s)", strerror(errno));
+ break;
+ }
+ if (i == (CTRL_CHAN_RETRY_COUNT + 1)) {
+ ERROR("ack failed: max retry count");
+ break;
+ }
+ INFO("ack failed (%s), retrying", strerror(errno));
+ }
+ if (ret <= 0) {
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
+ return ret;
+}
+
+int a2dp_command(struct a2dp_stream_common *common, char cmd)
+{
+ char ack;
+
+ INFO("A2DP COMMAND %s, fail count %d", dump_a2dp_ctrl_event(cmd),
+ open_ctrl_chnl_fail_count);
+
+ if ((common->ctrl_fd == AUDIO_SKT_DISCONNECTED)
+ && (open_ctrl_chnl_fail_count < 5)){
+ INFO("recovering from previous error");
+ a2dp_open_ctrl_path(common);
+ if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+ ERROR("failure to open ctrl path");
+ return -1;
+ }
+ }
+ else if (open_ctrl_chnl_fail_count >= 5)
+ {
+ WARN("control channel open alreday failed 5 times, bailing out");
+ return -1;
+ }
+
+ /* send command */
+ ssize_t sent;
+ OSI_NO_INTR(sent = send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL));
+ if (sent == -1)
+ {
+ ERROR("cmd failed (%s)", strerror(errno));
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ return -1;
+ }
+
+ /* wait for ack byte */
+ if (a2dp_ctrl_receive(common, &ack, 1) < 0) {
+ ERROR("A2DP COMMAND %s: no ACK", dump_a2dp_ctrl_event(cmd));
+ return -1;
+ }
+
+ INFO("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
+
+ if (ack == A2DP_CTRL_ACK_INCALL_FAILURE || ack == A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS)
+ return ack;
+ if (ack != A2DP_CTRL_ACK_SUCCESS) {
+ ERROR("A2DP COMMAND %s error %d", dump_a2dp_ctrl_event(cmd), ack);
+ return -1;
+ }
+ return 0;
+}
+
+int check_a2dp_ready(struct a2dp_stream_common *common)
+{
+ INFO("state %s", dump_a2dp_hal_state(common->state));
+ if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0)
+ {
+ ERROR("check a2dp ready failed");
+ return -1;
+ }
+ return 0;
+}
+
+int a2dp_read_audio_config(struct a2dp_stream_common *common)
+{
+ uint32_t sample_rate;
+ uint8_t channel_count;
+
+ if (a2dp_command(common, A2DP_CTRL_GET_AUDIO_CONFIG) < 0)
+ {
+ ERROR("check a2dp ready failed");
+ return -1;
+ }
+
+ if (a2dp_ctrl_receive(common, &sample_rate, 4) < 0)
+ return -1;
+ if (a2dp_ctrl_receive(common, &channel_count, 1) < 0)
+ return -1;
+
+ common->cfg.channel_flags = (channel_count == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO);
+ common->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+ common->cfg.rate = sample_rate;
+
+ INFO("got config %d %d", common->cfg.format, common->cfg.rate);
+
+ return 0;
+}
+
+int a2dp_read_codec_config(struct a2dp_stream_common *common,uint8_t idx)
+{
+ char cmd[2],ack;
+ int i,len = 0;
+ uint8_t *p_codec_cfg = common->codec_cfg;
+ cmd[0] = A2DP_CTRL_GET_CODEC_CONFIG;
+ cmd[1] = idx;
+ INFO("%s",__func__);
+ memset(p_codec_cfg,0,MAX_CODEC_CFG_SIZE);
+ INFO("%s",__func__);
+
+ if (send(common->ctrl_fd, cmd, 2, MSG_NOSIGNAL) == -1)
+ {
+ ERROR("cmd failed (%s)", strerror(errno));
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ return -1;
+ }
+
+ if (a2dp_ctrl_receive(common, &ack, 1) < 0)
+ return -1;
+
+ if (ack != A2DP_CTRL_ACK_SUCCESS)
+ {
+ ERROR("%s: Failed to get ack",__func__);
+ return -1;
+ }
+ if ((a2dp_ctrl_receive(common, &len, 1) < 0) ||
+ (len <= 0) || (len > MAX_CODEC_CFG_SIZE))
+ return -1;
+ if (a2dp_ctrl_receive(common, p_codec_cfg, len) < 0)
+ return -1;
+
+ INFO("got codec config");
+ p_codec_cfg = common->codec_cfg;
+
+ for (i=0;i<len;i++)
+ INFO("code_config[%d] = %d ", i,*p_codec_cfg++);
+
+ return 0;
+}
+
+int a2dp_get_multicast_status(struct a2dp_stream_common *common, uint8_t *mcast_status,
+ uint8_t *num_dev)
+{
+ INFO("%s",__func__);
+ if (a2dp_command(common,A2DP_CTRL_GET_MULTICAST_STATUS) < 0)
+ {
+ ERROR("check a2dp ready failed");
+ return -1;
+ }
+ INFO("a2dp_get_multicast_status acked fd = %d",common->ctrl_fd);
+ if (a2dp_ctrl_receive(common, mcast_status, 1) < 0)
+ return -1;
+ if (a2dp_ctrl_receive(common, num_dev, 1) < 0)
+ return -1;
+ INFO("%s: multicast status = %d, num_dev = %d",__func__,*mcast_status,*num_dev);
+ return 0;
+}
+
+void a2dp_open_ctrl_path(struct a2dp_stream_common *common)
+{
+ int i;
+
+ /* retry logic to catch any timing variations on control channel */
+ for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++)
+ {
+ /* connect control channel if not already connected */
+ if ((common->ctrl_fd = skt_connect(A2DP_CTRL_PATH, common->buffer_sz)) > 0)
+ {
+ /* success, now check if stack is ready */
+ if (check_a2dp_open_ready(common) == 0)
+ {
+ open_ctrl_chnl_fail_count = 0;
+ WARN("a2dp_open_ctrl_path : Fail count reset to 0");
+ return;
+ }
+ ERROR("a2dp_open_ctrl_path : No valid a2dp connection, abort");
+ usleep(100000);
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
+
+ /* ctrl channel not ready, wait a bit */
+ if (i < CTRL_CHAN_RETRY_COUNT - 1)
+ {
+ usleep(100000);
+ }
+ }
+ INFO("a2dp_open_ctrl_path : ctrl_fd: %d", common->ctrl_fd);
+ if (common->ctrl_fd <= 0)
+ {
+ open_ctrl_chnl_fail_count += 1;
+ WARN("a2dp_open_ctrl_path : Fail count raised to: %d",
+ open_ctrl_chnl_fail_count);
+ }
+}
+
+/*****************************************************************************
+**
+** AUDIO DATA PATH
+**
+*****************************************************************************/
+
+void a2dp_stream_common_init(struct a2dp_stream_common *common)
+{
+ pthread_mutexattr_t lock_attr;
+
+ FNLOG();
+
+ pthread_mutexattr_init(&lock_attr);
+ pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&common->lock, &lock_attr);
+
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ common->audio_fd = AUDIO_SKT_DISCONNECTED;
+ common->state = AUDIO_A2DP_STATE_STOPPED;
+
+ /* manages max capacity of socket pipe */
+ common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+ bt_split_a2dp_enabled = false;
+}
+
+int start_audio_datapath(struct a2dp_stream_common *common)
+{
+ INFO("state %d", common->state);
+ int ret = 0;
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ char trace_buf[512];
+ #endif
+
+ INFO("state %s", dump_a2dp_hal_state(common->state));
+
+ int oldstate = common->state;
+ common->state = AUDIO_A2DP_STATE_STARTING;
+
+ int a2dp_status = a2dp_command(common, A2DP_CTRL_CMD_START);
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ snprintf(trace_buf, 32, "start_audio_data_path:");
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_BEGIN(trace_buf);
+ }
+ #endif
+
+
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_END();
+ }
+ #endif
+ if (a2dp_status < 0)
+ {
+ ERROR("%s Audiopath start failed (status %d)", __func__, a2dp_status);
+ ret = -1;
+ goto error;
+ }
+ else if (a2dp_status == A2DP_CTRL_ACK_INCALL_FAILURE)
+ {
+ ERROR("%s Audiopath start failed - in call, move to suspended", __func__);
+ ret = a2dp_status;
+ goto error;
+ }
+ else if (a2dp_status == A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS)
+ {
+ ERROR("%s Audiopath start failed - disconnection in progress", __func__);
+ ret = a2dp_status;
+ goto error;
+ }
+ if (!bt_split_a2dp_enabled)
+ {
+ /* connect socket if not yet connected */
+ if (common->audio_fd == AUDIO_SKT_DISCONNECTED)
+ {
+ common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz);
+ if (common->audio_fd < 0)
+ {
+ common->state = oldstate;
+ goto error;
+ }
+
+ common->state = AUDIO_A2DP_STATE_STARTED;
+ }
+ }
+ else
+ {
+ common->state = AUDIO_A2DP_STATE_STARTED;
+ }
+
+ return 0;
+error:
+ common->state = oldstate;
+ if (bt_split_a2dp_enabled)
+ return ret;
+ else
+ return -1;
+}
+
+int stop_audio_datapath(struct a2dp_stream_common *common)
+{
+ int oldstate = common->state;
+
+ INFO("state %s", dump_a2dp_hal_state(common->state));
+
+ if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED)
+ return -1;
+
+ /* prevent any stray output writes from autostarting the stream
+ while stopping audiopath */
+ common->state = AUDIO_A2DP_STATE_STOPPING;
+
+ if (a2dp_command(common, A2DP_CTRL_CMD_STOP) < 0)
+ {
+ ERROR("audiopath stop failed");
+ common->state = oldstate;
+ return -1;
+ }
+
+ common->state = AUDIO_A2DP_STATE_STOPPED;
+
+ if (!bt_split_a2dp_enabled)
+ {
+ /* disconnect audio path */
+ skt_disconnect(common->audio_fd);
+ common->audio_fd = AUDIO_SKT_DISCONNECTED;
+ }
+
+ return 0;
+}
+
+int suspend_audio_datapath(struct a2dp_stream_common *common, bool standby)
+{
+ INFO("state %s", dump_a2dp_hal_state(common->state));
+
+
+ if (common->state == AUDIO_A2DP_STATE_STOPPING)
+ return -1;
+
+ if (a2dp_command(common, A2DP_CTRL_CMD_SUSPEND) < 0)
+ return -1;
+
+ if (standby)
+ common->state = AUDIO_A2DP_STATE_STANDBY;
+ else
+ common->state = AUDIO_A2DP_STATE_SUSPENDED;
+
+ if (!bt_split_a2dp_enabled)
+ {
+ /* disconnect audio path */
+ skt_disconnect(common->audio_fd);
+
+ common->audio_fd = AUDIO_SKT_DISCONNECTED;
+ }
+
+ return 0;
+}
+
+int check_a2dp_stream_started(struct a2dp_stream_common *common)
+{
+ if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_STREAM_STARTED) < 0)
+ {
+ INFO("Btif not in stream state");
+ return -1;
+ }
+ return 0;
+}
+static int check_a2dp_open_ready(struct a2dp_stream_common *common)
+{
+ if (a2dp_command(common, A2DP_CTRL_GET_CONNECTION_STATUS) < 0)
+ {
+ INFO("No active a2dp connection");
+ return -1;
+ }
+ return 0;
+}
+int audio_open_ctrl_path()
+{
+ INFO("%s",__func__);
+ a2dp_open_ctrl_path(&audio_stream);
+ if (audio_stream.ctrl_fd != AUDIO_SKT_DISCONNECTED)
+ {
+ INFO("control path opened successfull");
+ return 0;
+ }
+ else
+ INFO("control path open failed");
+ return -1;
+}
+
+int audio_start_stream()
+{
+ int i, status, j;
+ INFO("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ INFO("stream suspended");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+
+ if (audio_stream.state == AUDIO_A2DP_STATE_STARTED)
+ {
+ INFO("%s: stream alreday started", __func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+
+ /* Sanity check if the ctrl_fd is valid. If audio_stream_close is not called
+ * from audio hal previously when BT is turned off or device is disconnecte,
+ * and tries to start stream again.
+ */
+ if (check_a2dp_open_ready(&audio_stream) < 0)
+ {
+ if (audio_stream.ctrl_fd != AUDIO_SKT_DISCONNECTED)
+ {
+ ERROR("BTIF is not ready to start stream");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ /* Try to start stream to recover from ctrl skt disconnect*/
+ }
+
+ for (j = 0; j <STREAM_START_MAX_RETRY_LOOPER; j++) {
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ status = start_audio_datapath(&audio_stream);
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ INFO("a2dp stream started successfully");
+ goto end;
+ }
+ else if (status == A2DP_CTRL_ACK_INCALL_FAILURE)
+ {
+ INFO("a2dp stream start failed: call in progress");
+ goto end;
+ }
+ else if (status == A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS)
+ {
+ INFO("a2dp stream start failed: disconnection in progress");
+ goto end;
+ }
+ if (audio_stream.ctrl_fd == AUDIO_SKT_DISCONNECTED)
+ {
+ INFO("control path is disconnected");
+ goto end;
+ }
+ INFO("%s: a2dp stream not started,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ INFO("%s: Check if valid connection is still up or not", __func__);
+
+ // For every 1 sec check if a2dp is still up, to avoid
+ // blocking the audio thread forever if a2dp connection is closed
+ // for some reason
+ if (check_a2dp_open_ready (&audio_stream) < 0) {
+ ERROR("%s: No valid a2dp connection\n", __func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+end:
+ if (audio_stream.state != AUDIO_A2DP_STATE_STARTED)
+ {
+ ERROR("%s: Failed to start a2dp stream", __func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+}
+
+int audio_stream_open()
+{
+ INFO("%s",__func__);
+ a2dp_stream_common_init(&audio_stream);
+ open_ctrl_chnl_fail_count = 0;
+ a2dp_open_ctrl_path(&audio_stream);
+ bt_split_a2dp_enabled = true;
+ if (audio_stream.ctrl_fd != AUDIO_SKT_DISCONNECTED)
+ {
+ INFO("control path open successful");
+ /*Delay to ensure Headset is in proper state when START is initiated
+ from DUT immediately after the connection due to ongoing music playback. */
+ usleep(1000000);
+ a2dp_command(&audio_stream,A2DP_CTRL_CMD_OFFLOAD_SUPPORTED);
+ return 0;
+ }
+ else
+ INFO("control path open failed");
+
+ return -1;
+}
+
+int audio_stream_close()
+{
+ INFO("%s",__func__);
+
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_STARTED ||
+ audio_stream.state == AUDIO_A2DP_STATE_STOPPING)
+ {
+ INFO("%s: Suspending audio stream",__func__);
+ suspend_audio_datapath(&audio_stream,true);
+ }
+
+ skt_disconnect(audio_stream.ctrl_fd);
+ audio_stream.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+}
+int audio_stop_stream()
+{
+ INFO("%s state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ if (audio_stream.state != AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ pthread_mutex_lock(&audio_stream.lock);
+ if (suspend_audio_datapath(&audio_stream, true) == 0)
+ {
+ INFO("audio stop stream successful");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ return 0;
+}
+
+int audio_suspend_stream()
+{
+ INFO("%s state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ if (audio_stream.state != AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ pthread_mutex_lock(&audio_stream.lock);
+ if (suspend_audio_datapath(&audio_stream, false) == 0)
+ {
+ INFO("audio suspend stream successful");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ return 0;
+}
+
+void audio_handoff_triggered()
+{
+ INFO("%s state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state != AUDIO_A2DP_STATE_STOPPED ||
+ audio_stream.state != AUDIO_A2DP_STATE_STOPPING)
+ {
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+}
+
+void clear_a2dpsuspend_flag()
+{
+ INFO("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_SUSPENDED)
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ pthread_mutex_unlock(&audio_stream.lock);
+}
+
+void * audio_get_codec_config(uint8_t *multicast_status, uint8_t *num_dev,
+ audio_format_t *codec_type)
+{
+ int i, status, j;
+ INFO("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+
+ pthread_mutex_lock(&audio_stream.lock);
+ a2dp_get_multicast_status(&audio_stream, multicast_status,num_dev);
+
+ DEBUG("got multicast status = %d dev = %d",*multicast_status,*num_dev);
+
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ status = a2dp_read_codec_config(&audio_stream, 0);
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ pthread_mutex_unlock(&audio_stream.lock);
+ return (a2dp_codec_parser(&audio_stream.codec_cfg[0], codec_type));
+ }
+ INFO("%s: a2dp stream not configured,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return NULL;
+}
+
+void* audio_get_next_codec_config(uint8_t idx, audio_format_t *codec_type)
+{
+ int i, status, j;
+ INFO("%s",__func__);
+ pthread_mutex_lock(&audio_stream.lock);
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ status = a2dp_read_codec_config(&audio_stream, 0);
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ pthread_mutex_unlock(&audio_stream.lock);
+ return (a2dp_codec_parser(&audio_stream.codec_cfg[0], codec_type));
+ }
+ INFO("%s: a2dp stream not configured,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return NULL;
+}
+
+int audio_check_a2dp_ready()
+{
+ INFO("audio_check_a2dp_ready: state %s", dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ INFO("stream not ready to start");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ if (a2dp_command(&audio_stream, A2DP_CTRL_CMD_CHECK_READY) != 0)
+ {
+ INFO("audio_check_a2dp_ready: FAIL");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 1;
+}
+//Entry point for dynamic lib
+const bt_host_ipc_interface_t BTHOST_IPC_INTERFACE = {
+ sizeof(bt_host_ipc_interface_t),
+ a2dp_open_ctrl_path,
+ a2dp_stream_common_init,
+ start_audio_datapath,
+ suspend_audio_datapath,
+ stop_audio_datapath,
+ check_a2dp_stream_started,
+ check_a2dp_ready,
+ a2dp_read_audio_config,
+ skt_read,
+ skt_write,
+ skt_disconnect,
+ a2dp_command,
+ audio_stream_open,
+ audio_stream_close,
+ audio_start_stream,
+ audio_stop_stream,
+ audio_suspend_stream,
+ audio_get_codec_config,
+ audio_handoff_triggered,
+ clear_a2dpsuspend_flag,
+ audio_get_next_codec_config,
+ audio_check_a2dp_ready
+};
diff --git a/audio_a2dp_hw/bthost_ipc.h b/audio_a2dp_hw/bthost_ipc.h
new file mode 100644
index 0000000..d0a561a
--- /dev/null
+++ b/audio_a2dp_hw/bthost_ipc.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ * Copyright (C) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
+ *****************************************************************************/
+/*****************************************************************************
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: audio_a2dp_hw.h
+ *
+ * Description:
+ *
+ *****************************************************************************/
+#ifndef BT_HOST_IPC_H
+#define BT_HOST_IPC_H
+#include "audio_a2dp_hw.h"
+#include <system/audio.h>
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#define BT_AUDIO_HARDWARE_INTERFACE "libbthost"
+#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
+#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
+
+typedef enum {
+ A2DP_CTRL_GET_CODEC_CONFIG = 15,
+ A2DP_CTRL_GET_MULTICAST_STATUS,
+ A2DP_CTRL_GET_CONNECTION_STATUS,
+} tA2DP_CTRL_EXT_CMD;
+
+/*
+codec specific definitions
+*/
+#define CODEC_TYPE_SBC 0x00
+#define CODEC_TYPE_AAC 0x02
+#define NON_A2DP_CODEC_TYPE 0xFF
+#define CODEC_OFFSET 3
+#define VENDOR_ID_OFFSET 4
+#define CODEC_ID_OFFSET (VENDOR_ID_OFFSET + 4)
+#define CODEC_TYPE_PCM 0x05
+
+#ifndef VENDOR_APTX
+#define VENDOR_APTX 0x4F
+#endif
+#ifndef VENDOR_APTX_HD
+#define VENDOR_APTX_HD 0xD7
+#endif
+#ifndef VENDOR_APTX_LL
+#define VENDOR_APTX_LL 0x0A
+#endif
+#ifndef APTX_CODEC_ID
+#define APTX_CODEC_ID 0x01
+#endif
+#ifndef APTX_HD_CODEC_ID
+#define APTX_HD_CODEC_ID 0x24
+#endif
+
+#define A2D_SBC_FREQ_MASK 0xF0
+#define A2D_SBC_CHN_MASK 0x0F
+#define A2D_SBC_BLK_MASK 0xF0
+#define A2D_SBC_SUBBAND_MASK 0x0C
+#define A2D_SBC_ALLOC_MASK 0x03
+#define A2D_SBC_SAMP_FREQ_16 0x80 /* b7:16 kHz */
+#define A2D_SBC_SAMP_FREQ_32 0x40 /* b6:32 kHz */
+#define A2D_SBC_SAMP_FREQ_44 0x20 /* b5:44.1kHz */
+#define A2D_SBC_SAMP_FREQ_48 0x10 /* b4:48 kHz */
+#define A2D_SBC_CH_MD_MONO 0x08 /* b3: mono */
+#define A2D_SBC_CH_MD_DUAL 0x04 /* b2: dual */
+#define A2D_SBC_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2D_SBC_CH_MD_JOINT 0x01 /* b0: joint stereo */
+#define A2D_SBC_BLOCKS_4 0x80 /* 4 blocks */
+#define A2D_SBC_BLOCKS_8 0x40 /* 8 blocks */
+#define A2D_SBC_BLOCKS_12 0x20 /* 12blocks */
+#define A2D_SBC_BLOCKS_16 0x10 /* 16blocks */
+#define A2D_SBC_SUBBAND_4 0x08 /* b3: 4 */
+#define A2D_SBC_SUBBAND_8 0x04 /* b2: 8 */
+#define A2D_SBC_ALLOC_MD_S 0x02 /* b1: SNR */
+#define A2D_SBC_ALLOC_MD_L 0x01 /* b0: loundess */
+
+/* APTX bitmask helper */
+#define A2D_APTX_SAMP_FREQ_MASK 0xF0
+#define A2D_APTX_SAMP_FREQ_48 0x10
+#define A2D_APTX_SAMP_FREQ_44 0x20
+#define A2D_APTX_CHAN_MASK 0x0F
+#define A2D_APTX_CHAN_STEREO 0x02
+#define A2D_APTX_CHAN_MONO 0x01
+
+
+#define A2D_AAC_IE_OBJ_TYPE_MSK 0xF0 /* b7-b4 Object Type */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC 0x80 /* b7:MPEG-2 AAC LC */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LC 0x40 /* b7:MPEG-4 AAC LC */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LTP 0x20 /* b7:MPEG-4 AAC LTP */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_SCA 0x10 /* b7:MPEG-4 AAC SCALABLE */
+
+#define A2D_AAC_IE_CHANNELS_MSK 0x0C
+#define A2D_AAC_IE_CHANNELS_1 0x08 /* Channel 1 */
+#define A2D_AAC_IE_CHANNELS_2 0x04 /* Channel 2 */
+
+#define A2D_AAC_IE_VBR_MSK 0x80
+#define A2D_AAC_IE_VBR 0x80 /* supported */
+
+typedef struct {
+ uint8_t codec_type;
+ uint8_t dev_idx;
+ uint16_t sampling_rate; /*44.1khz,48khz*/
+ uint8_t chn; /*0(Mono),1(Dual),2(Stereo),3(JS)*/
+ uint8_t blk_len; /*4,8,12,16 */
+ uint8_t subband; /*4,8*/
+ uint8_t alloc; /*0(Loudness),1(SNR)*/
+ uint8_t min_bitpool; /* 2 */
+ uint8_t max_bitpool; /*53(44.1khz),51 (48khz) */
+ uint16_t mtu;
+ uint32_t bitrate;
+}tA2DP_SBC_CODEC;
+
+typedef struct {
+ uint8_t codec_type;
+ uint8_t dev_idx;
+ uint32_t vendor_id;
+ uint16_t codec_id;
+ uint16_t sampling_rate;
+ uint8_t chnl;
+ uint8_t cp;
+ uint16_t mtu;
+ uint32_t bitrate;
+}tA2DP_APTX_CODEC;
+
+typedef struct {
+ /** Set to sizeof(bt_host_ipc_interface_t) */
+ size_t size;
+ void (*a2dp_open_ctrl_path)(struct a2dp_stream_common *common);
+ void (*a2dp_stream_common_init)(struct a2dp_stream_common *common);
+ int (*start_audio_datapath)(struct a2dp_stream_common *common);
+ int (*suspend_audio_datapath)(struct a2dp_stream_common *common, bool standby);
+ int (*stop_audio_datapath)(struct a2dp_stream_common *common);
+ int (*check_a2dp_stream_started)(struct a2dp_stream_common *common);
+ int (*check_a2dp_ready)(struct a2dp_stream_common *common);
+ int (*a2dp_read_audio_config)(struct a2dp_stream_common *common);
+ int (*skt_read)(int fd,void *buf, size_t bytes);
+ int (*skt_write)(int fd,const void *buf, size_t bytes);
+ int (*skt_disconnect)(int fd);
+ int (*a2dp_command)(struct a2dp_stream_common *common,char cmd);
+ int (*audio_stream_open)(void);
+ int (*audio_stream_close)(void);
+ int (*audio_start_stream)(void);
+ int (*audio_stop_stream)(void);
+ int (*audio_suspend_stream)(void);
+ void* (*audio_get_codec_config)(uint8_t *mcast, uint8_t *num_dev, audio_format_t *codec_type);
+ void (*audio_handoff_triggered)(void);
+ void (*clear_a2dpsuspend_flag)(void);
+ void*(*audio_get_next_codec_config)(uint8_t idx, audio_format_t *codec_type);
+ int (*audio_check_a2dp_ready)(void);
+} bt_host_ipc_interface_t;
+#endif
diff --git a/bta/Android.mk b/bta/Android.mk
index 6dc6a3e..7512d64 100644
--- a/bta/Android.mk
+++ b/bta/Android.mk
@@ -57,6 +57,7 @@
./av/bta_av_cfg.c \
./av/bta_av_ssm.c \
./av/bta_av_sbc.c \
+ ./av/bta_av_aac.c \
./ar/bta_ar.c \
./hl/bta_hl_act.c \
./hl/bta_hl_api.c \
@@ -97,6 +98,14 @@
$(LOCAL_PATH)/../utils/include \
$(bluetooth_C_INCLUDES)
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_C_INCLUDES+= . \
+ vendor/qcom/opensource/bluetooth/system_bt_ext
+else
+LOCAL_C_INCLUDES+= . \
+ device/qcom/msm8909w/opensource/bluetooth/system_bt_ext
+endif
+
LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DBUILDCFG
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c
index e93acb2..3cacaf3 100644
--- a/bta/ag/bta_ag_act.c
+++ b/bta/ag/bta_ag_act.c
@@ -32,7 +32,9 @@
#include <string.h>
#include "bta_dm_int.h"
#include "l2c_api.h"
-
+#include <cutils/properties.h>
+#include <hardware/bluetooth.h>
+#include "device/include/interop.h"
/*****************************************************************************
** Constants
*****************************************************************************/
@@ -105,6 +107,12 @@
bdcpy(open.bd_addr, p_scb->peer_addr);
}
+ // if failure, dump logs
+ if (status != BTA_AG_SUCCESS) {
+ APPL_TRACE_WARNING("%s: there is failure in SDP/RFCOMM connection", __func__);
+ GENERATE_VND_LOGS();
+ }
+
(*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open);
}
@@ -200,6 +208,7 @@
void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
{
BD_ADDR pending_bd_addr;
+ tBTA_AG_RFC *p_buf;
/* store parameters */
if (p_data)
@@ -212,6 +221,26 @@
/* Check if RFCOMM has any incoming connection to avoid collision. */
if (PORT_IsOpening (pending_bd_addr))
{
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.bt.max.hs.connections", value, "") &&
+ !strcmp(value, "2") )
+ {
+ // Abort the outgoing connection if incoming connection is from the same device
+ if (bdcmp (pending_bd_addr, p_scb->peer_addr) == 0)
+ {
+ APPL_TRACE_WARNING("%s: p_scb %x, abort outgoing conn, there is"\
+ " an incoming conn from dev %x:%x:%x:%x:%x:%x", __func__,
+ p_scb, p_scb->peer_addr[0], p_scb->peer_addr[1],
+ p_scb->peer_addr[2], p_scb->peer_addr[3], p_scb->peer_addr[4],
+ p_scb->peer_addr[5]);
+ // send ourselves close event for clean up
+ p_buf = (tBTA_AG_RFC *) osi_malloc(sizeof(tBTA_AG_RFC));
+ p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+ bta_sys_sendmsg(p_buf);
+ return;
+ }
+ }
/* Let the incoming connection goes through. */
/* Issue collision for this scb for now. */
/* We will decide what to do when we find incoming connetion later. */
@@ -430,11 +459,9 @@
p_scb->post_sco = BTA_AG_POST_SCO_NONE;
p_scb->svc_conn = FALSE;
p_scb->hsp_version = HSP_VERSION_1_2;
+ p_scb->slc_pend_open = FALSE;
bta_ag_at_reinit(&p_scb->at_cb);
- memset(&(p_scb->peer_hf_indicators), 0, sizeof(p_scb->peer_hf_indicators));
- memset(&(p_scb->local_hf_indicators), 0, sizeof(p_scb->local_hf_indicators));
-
/* stop timers */
alarm_cancel(p_scb->ring_timer);
#if (BTM_WBS_INCLUDED == TRUE)
@@ -506,6 +533,9 @@
*******************************************************************************/
void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
{
+ int ag_conn_timeout = p_bta_ag_cfg->conn_tout;
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, p_scb->peer_addr);
/* initialize AT feature variables */
p_scb->clip_enabled = FALSE;
p_scb->ccwa_enabled = FALSE;
@@ -528,9 +558,15 @@
bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+ if (interop_match_addr(INTEROP_INCREASE_AG_CONN_TIMEOUT,
+ (const bt_bdaddr_t*)&remote_bdaddr)) {
+ /* use higher value for ag conn timeout */
+ ag_conn_timeout = 20000;
+ }
+ APPL_TRACE_DEBUG ("bta_ag_rfc_open: ag_conn_timeout: %d", ag_conn_timeout);
if (p_scb->conn_service == BTA_AG_HFP) {
/* if hfp start timer for service level conn */
- bta_sys_start_timer(p_scb->ring_timer, p_bta_ag_cfg->conn_tout,
+ bta_sys_start_timer(p_scb->ring_timer, ag_conn_timeout,
BTA_AG_SVC_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
} else {
/* else service level conn is open */
@@ -555,11 +591,12 @@
tBTA_AG_SCB *ag_scb, *other_scb;
BD_ADDR dev_addr;
int status;
+ tBTA_AG_RFC *p_buf;
/* set role */
p_scb->role = BTA_AG_ACP;
- APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+ APPL_TRACE_IMP ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
p_scb->serv_handle[0], p_scb->serv_handle[1]);
/* get bd addr of peer */
@@ -577,8 +614,30 @@
if (bdcmp (dev_addr, ag_scb->peer_addr) == 0)
{
- /* If incoming and outgoing device are same, nothing more to do. */
- /* Outgoing conn will be aborted because we have successful incoming conn. */
+ char value[PROPERTY_VALUE_MAX];
+ /* Read the property if multi hf is enabled */
+ if (property_get("persist.bt.max.hs.connections", value, "") &&
+ !strcmp(value, "2") )
+ {
+ /* If incoming and outgoing device are same, nothing more to do. */
+ /* Outgoing conn will be aborted because we have successful incoming conn. */
+ APPL_TRACE_WARNING("%s: p_scb %x, abort outgoing conn,"\
+ "there is an incoming conn from dev %x:%x:%x:%x:%x:%x",
+ __func__, ag_scb, dev_addr[0], dev_addr[1], dev_addr[2],
+ dev_addr[3], dev_addr[4], dev_addr[5]);
+ if (ag_scb->conn_handle)
+ {
+ RFCOMM_RemoveConnection(ag_scb->conn_handle);
+ }
+
+ // send ourselves close event for clean up
+ // move back to OPENING state from INIT state so that clean up is done
+ ag_scb->state = 1;
+ p_buf = (tBTA_AG_RFC *) osi_malloc(sizeof(tBTA_AG_RFC));
+ p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = bta_ag_scb_to_idx(ag_scb);
+ bta_sys_sendmsg(p_buf);
+ }
}
else
{
@@ -614,7 +673,7 @@
}
}
- APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+ APPL_TRACE_IMP ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
p_scb->conn_service, p_scb->conn_handle);
/* close any unopened server */
@@ -670,7 +729,7 @@
bta_ag_at_parse(&p_scb->at_cb, buf, len);
if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb))
{
- APPL_TRACE_DEBUG ("%s change link policy for SCO", __func__);
+ APPL_TRACE_IMP("bta_ag_rfc_data, change link policy for SCO");
bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
} else {
bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
@@ -866,7 +925,7 @@
PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb))
{
- APPL_TRACE_DEBUG ("bta_ag_rfc_data, change link policy for SCO");
+ APPL_TRACE_IMP("bta_ag_rfc_data, change link policy for SCO");
bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
}
else
@@ -912,6 +971,9 @@
#if (BTM_WBS_INCLUDED == TRUE )
tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
tBTA_AG_VAL val;
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ bdcpy(val.bd_addr, p_scb->peer_addr);
/* Check if the requested codec type is valid */
if((codec_type != BTA_AG_CODEC_NONE) &&
diff --git a/bta/ag/bta_ag_at.c b/bta/ag/bta_ag_at.c
index 952f1f8..6b4b657 100644
--- a/bta/ag/bta_ag_at.c
+++ b/bta/ag/bta_ag_at.c
@@ -156,14 +156,14 @@
{
(*p_cb->p_cmd_cback)(p_cb->p_user,
- p_cb->p_at_tbl[idx].command_id,
+ idx,
arg_type, p_arg, p_end, int_arg);
}
}
else
{
(*p_cb->p_cmd_cback)(p_cb->p_user,
- p_cb->p_at_tbl[idx].command_id,
+ idx,
arg_type, p_arg, p_end, int_arg);
}
}
diff --git a/bta/ag/bta_ag_at.h b/bta/ag/bta_ag_at.h
index b2dae6e..c0ba7fb 100644
--- a/bta/ag/bta_ag_at.h
+++ b/bta/ag/bta_ag_at.h
@@ -47,7 +47,6 @@
typedef struct
{
const char *p_cmd; /* AT command string */
- size_t command_id; /* passed to the callback on p_cmd match */
UINT8 arg_type; /* allowable argument type syntax */
UINT8 fmt; /* whether arg is int or string */
UINT8 min; /* minimum value for int arg */
@@ -55,7 +54,7 @@
} tBTA_AG_AT_CMD;
/* callback function executed when command is parsed */
-typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 command_id, UINT8 arg_type,
+typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type,
char *p_arg, char *p_end, INT16 int_arg);
/* callback function executed to send "ERROR" result code */
diff --git a/bta/ag/bta_ag_cfg.c b/bta/ag/bta_ag_cfg.c
index e5893e1..cfe298a 100644
--- a/bta/ag/bta_ag_cfg.c
+++ b/bta/ag/bta_ag_cfg.c
@@ -52,24 +52,9 @@
BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
#endif
-#ifndef BTA_AG_BIND_INFO
-#define BTA_AG_BIND_INFO "(1)"
-#endif
-
-const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[] =
-{
- /* The first row contains the number of indicators. Need to be updated accordingly */
- {BTA_AG_NUM_LOCAL_HF_IND, 0, 0, 0, 0},
-
- {1, 1, 1, 0, 1}, /* Enhanced Driver Status, supported, enabled, range 0 ~ 1 */
- {2, 1, 1, 0, 100} /* Battery Level Status, supported, enabled, range 0 ~ 100 */
-};
-
const tBTA_AG_CFG bta_ag_cfg =
{
BTA_AG_CIND_INFO,
- BTA_AG_BIND_INFO,
- BTA_AG_NUM_LOCAL_HF_IND,
BTA_AG_CONN_TIMEOUT,
BTA_AG_SCO_PKT_TYPES,
BTA_AG_CHLD_VAL_ECC,
diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c
index 7a882ec..c381011 100644
--- a/bta/ag/bta_ag_cmd.c
+++ b/bta/ag/bta_ag_cmd.c
@@ -16,11 +16,15 @@
*
******************************************************************************/
-#define LOG_TAG "bta_ag_cmd"
-
+/******************************************************************************
+ *
+ * This file contains functions for processing AT commands and results.
+ *
+ ******************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include "bt_target.h"
#include "bt_types.h"
@@ -31,10 +35,11 @@
#include "bta_sys.h"
#include "log/log.h"
#include "bt_common.h"
-#include "osi/include/log.h"
#include "port_api.h"
#include "utl.h"
-
+#include <cutils/properties.h>
+#include "device/include/interop.h"
+#include "btif/include/btif_storage.h"
/*****************************************************************************
** Constants
@@ -54,73 +59,116 @@
#define BTA_AG_CLIP_TYPE_DEFAULT 129
#define BTA_AG_CLIP_TYPE_VOIP 255
-#define COLON_IDX_4_VGSVGM 4
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+#define BTA_AG_AT_MULTI_LEN 2
+#define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;}
-/* Local events which will not trigger a higher layer callback */
+/* type for AT result code block */
+typedef struct
+{
+ UINT8 code;
+ char *p_arg;
+ INT16 int_arg;
+} tBTA_AG_RESULT_CB;
+
+/* type for multiple AT result codes block */
+typedef struct
+{
+ UINT8 num_result;
+ tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN];
+} tBTA_AG_MULTI_RESULT_CB;
+#endif
+
+/* enumeration of HSP AT commands matches HSP command interpreter table */
enum
{
- BTA_AG_LOCAL_EVT_FIRST = 0x100,
- BTA_AG_LOCAL_EVT_CCWA,
- BTA_AG_LOCAL_EVT_CLIP,
- BTA_AG_LOCAL_EVT_CMER,
- BTA_AG_LOCAL_EVT_BRSF,
- BTA_AG_LOCAL_EVT_CMEE,
- BTA_AG_LOCAL_EVT_BIA,
- BTA_AG_LOCAL_EVT_BCC,
+ BTA_AG_HS_CMD_CKPD,
+ BTA_AG_HS_CMD_VGS,
+ BTA_AG_HS_CMD_VGM
+};
+
+/* enumeration of HFP AT commands matches HFP command interpreter table */
+enum
+{
+ BTA_AG_HF_CMD_A,
+ BTA_AG_HF_CMD_D,
+ BTA_AG_HF_CMD_VGS,
+ BTA_AG_HF_CMD_VGM,
+ BTA_AG_HF_CMD_CCWA,
+ BTA_AG_HF_CMD_CHLD,
+ BTA_AG_HF_CMD_CHUP,
+ BTA_AG_HF_CMD_CIND,
+ BTA_AG_HF_CMD_CLIP,
+ BTA_AG_HF_CMD_CMER,
+ BTA_AG_HF_CMD_VTS,
+ BTA_AG_HF_CMD_BINP,
+ BTA_AG_HF_CMD_BLDN,
+ BTA_AG_HF_CMD_BVRA,
+ BTA_AG_HF_CMD_BRSF,
+ BTA_AG_HF_CMD_NREC,
+ BTA_AG_HF_CMD_CNUM,
+ BTA_AG_HF_CMD_BTRH,
+ BTA_AG_HF_CMD_CLCC,
+ BTA_AG_HF_CMD_COPS,
+ BTA_AG_HF_CMD_CMEE,
+ BTA_AG_HF_CMD_BIA,
+ BTA_AG_HF_CMD_CBC,
+ BTA_AG_HF_CMD_BCC,
+ BTA_AG_HF_CMD_BCS,
+ BTA_AG_HF_CMD_BAC,
+ BTA_AG_HF_CMD_BIND,
+ BTA_AG_HF_CMD_BIEV
};
/* AT command interpreter table for HSP */
const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] =
{
- {"+CKPD", BTA_AG_AT_CKPD_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
- {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
- {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
- /* End-of-table marker used to stop lookup iteration */
- {"", 0, 0, 0, 0, 0}
+ {"+CKPD", BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
+ {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
};
/* AT command interpreter table for HFP */
const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] =
{
- {"A", BTA_AG_AT_A_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
- {"D", BTA_AG_AT_D_EVT, BTA_AG_AT_NONE | BTA_AG_AT_FREE, BTA_AG_AT_STR, 0, 0},
- {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
- {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
- {"+CCWA", BTA_AG_LOCAL_EVT_CCWA, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"A", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"D", (BTA_AG_AT_NONE | BTA_AG_AT_FREE), BTA_AG_AT_STR, 0, 0},
+ {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+CCWA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
/* Consider CHLD as str to take care of indexes for ECC */
- {"+CHLD", BTA_AG_AT_CHLD_EVT, BTA_AG_AT_SET | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 4},
- {"+CHUP", BTA_AG_AT_CHUP_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
- {"+CIND", BTA_AG_AT_CIND_EVT, BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0},
- {"+CLIP", BTA_AG_LOCAL_EVT_CLIP, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
- {"+CMER", BTA_AG_LOCAL_EVT_CMER, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
- {"+VTS", BTA_AG_AT_VTS_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
- {"+BINP", BTA_AG_AT_BINP_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
- {"+BLDN", BTA_AG_AT_BLDN_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
- {"+BVRA", BTA_AG_AT_BVRA_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
- {"+BRSF", BTA_AG_LOCAL_EVT_BRSF, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
- {"+NREC", BTA_AG_AT_NREC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
- {"+CNUM", BTA_AG_AT_CNUM_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
- {"+BTRH", BTA_AG_AT_BTRH_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 2},
- {"+CLCC", BTA_AG_AT_CLCC_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
- {"+COPS", BTA_AG_AT_COPS_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
- {"+CMEE", BTA_AG_LOCAL_EVT_CMEE, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
- {"+BIA", BTA_AG_LOCAL_EVT_BIA, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
- {"+CBC", BTA_AG_AT_CBC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
- {"+BCC", BTA_AG_LOCAL_EVT_BCC, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
- {"+BCS", BTA_AG_AT_BCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
- {"+BIND", BTA_AG_AT_BIND_EVT, BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0},
- {"+BIEV", BTA_AG_AT_BIEV_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
- {"+BAC", BTA_AG_AT_BAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
- /* End-of-table marker used to stop lookup iteration */
- {"", 0, 0, 0, 0, 0}
+ {"+CHLD", (BTA_AG_AT_SET | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 4},
+ {"+CHUP", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+CIND", (BTA_AG_AT_READ | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 0},
+ {"+CLIP", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+CMER", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+VTS", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+BINP", BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
+ {"+BLDN", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BVRA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BRSF", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+NREC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
+ {"+CNUM", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BTRH", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_INT, 0, 2},
+ {"+CLCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+COPS", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_STR, 0, 0},
+ {"+CMEE", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BIA", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
+ {"+CBC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
+ {"+BCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BCS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+BAC", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+BIND", (BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 0},
+ {"+BIEV", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
};
/* AT result code table element */
typedef struct
{
- const char *result_string; /* AT result string */
- size_t result_id; /* Local or BTA result id */
- UINT8 arg_type; /* whether argument is int or string */
+ const char *p_res; /* AT result string */
+ UINT8 fmt; /* whether argument is int or string */
} tBTA_AG_RESULT;
/* AT result code argument types */
@@ -134,53 +182,60 @@
/* Local AT command result codes not defined in bta_ag_api.h */
enum
{
- BTA_AG_LOCAL_RES_FIRST = 0x0100,
- BTA_AG_LOCAL_RES_OK,
- BTA_AG_LOCAL_RES_ERROR,
- BTA_AG_LOCAL_RES_RING,
- BTA_AG_LOCAL_RES_CLIP,
- BTA_AG_LOCAL_RES_BRSF,
- BTA_AG_LOCAL_RES_CMEE,
- BTA_AG_LOCAL_RES_BCS
+ BTA_AG_RES_OK,
+ BTA_AG_RES_ERROR,
+ BTA_AG_RES_RING,
+ BTA_AG_RES_VGS,
+ BTA_AG_RES_VGM,
+ BTA_AG_RES_CCWA,
+ BTA_AG_RES_CHLD,
+ BTA_AG_RES_CIND,
+ BTA_AG_RES_CLIP,
+ BTA_AG_RES_CIEV,
+ BTA_AG_RES_BINP,
+ BTA_AG_RES_BVRA,
+ BTA_AG_RES_BRSF,
+ BTA_AG_RES_BSIR,
+ BTA_AG_RES_CNUM,
+ BTA_AG_RES_BTRH,
+ BTA_AG_RES_CLCC,
+ BTA_AG_RES_COPS,
+ BTA_AG_RES_CMEE,
+ BTA_AG_RES_BCS,
+ BTA_AG_RES_UNAT,
+ BTA_AG_RES_BIND
};
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+#define COLON_IDX_4_VGSVGM 4
+#endif
/* AT result code constant table */
const tBTA_AG_RESULT bta_ag_result_tbl[] =
{
- {"OK", BTA_AG_LOCAL_RES_OK, BTA_AG_RES_FMT_NONE},
- {"ERROR", BTA_AG_LOCAL_RES_ERROR, BTA_AG_RES_FMT_NONE},
- {"RING", BTA_AG_LOCAL_RES_RING, BTA_AG_RES_FMT_NONE},
- {"+VGS: ", BTA_AG_SPK_RES, BTA_AG_RES_FMT_INT},
- {"+VGM: ", BTA_AG_MIC_RES, BTA_AG_RES_FMT_INT},
- {"+CCWA: ", BTA_AG_CALL_WAIT_RES, BTA_AG_RES_FMT_STR},
- {"+CHLD: ", BTA_AG_IN_CALL_HELD_RES,BTA_AG_RES_FMT_STR},
- {"+CIND: ", BTA_AG_CIND_RES, BTA_AG_RES_FMT_STR},
- {"+CLIP: ", BTA_AG_LOCAL_RES_CLIP, BTA_AG_RES_FMT_STR},
- {"+CIEV: ", BTA_AG_IND_RES, BTA_AG_RES_FMT_STR},
- {"+BINP: ", BTA_AG_BINP_RES, BTA_AG_RES_FMT_STR},
- {"+BVRA: ", BTA_AG_BVRA_RES, BTA_AG_RES_FMT_INT},
- {"+BRSF: ", BTA_AG_LOCAL_RES_BRSF, BTA_AG_RES_FMT_INT},
- {"+BSIR: ", BTA_AG_INBAND_RING_RES, BTA_AG_RES_FMT_INT},
- {"+CNUM: ", BTA_AG_CNUM_RES, BTA_AG_RES_FMT_STR},
- {"+BTRH: ", BTA_AG_BTRH_RES, BTA_AG_RES_FMT_INT},
- {"+CLCC: ", BTA_AG_CLCC_RES, BTA_AG_RES_FMT_STR},
- {"+COPS: ", BTA_AG_COPS_RES, BTA_AG_RES_FMT_STR},
- {"+CME ERROR: ", BTA_AG_LOCAL_RES_CMEE, BTA_AG_RES_FMT_INT},
- {"+BCS: ", BTA_AG_LOCAL_RES_BCS, BTA_AG_RES_FMT_INT},
- {"+BIND: ", BTA_AG_BIND_RES, BTA_AG_RES_FMT_STR},
- {"", BTA_AG_UNAT_RES, BTA_AG_RES_FMT_STR}
+ {"OK", BTA_AG_RES_FMT_NONE},
+ {"ERROR", BTA_AG_RES_FMT_NONE},
+ {"RING", BTA_AG_RES_FMT_NONE},
+ {"+VGS: ", BTA_AG_RES_FMT_INT},
+ {"+VGM: ", BTA_AG_RES_FMT_INT},
+ {"+CCWA: ", BTA_AG_RES_FMT_STR},
+ {"+CHLD: ", BTA_AG_RES_FMT_STR},
+ {"+CIND: ", BTA_AG_RES_FMT_STR},
+ {"+CLIP: ", BTA_AG_RES_FMT_STR},
+ {"+CIEV: ", BTA_AG_RES_FMT_STR},
+ {"+BINP: ", BTA_AG_RES_FMT_STR},
+ {"+BVRA: ", BTA_AG_RES_FMT_INT},
+ {"+BRSF: ", BTA_AG_RES_FMT_INT},
+ {"+BSIR: ", BTA_AG_RES_FMT_INT},
+ {"+CNUM: ", BTA_AG_RES_FMT_STR},
+ {"+BTRH: ", BTA_AG_RES_FMT_INT},
+ {"+CLCC: ", BTA_AG_RES_FMT_STR},
+ {"+COPS: ", BTA_AG_RES_FMT_STR},
+ {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
+ {"+BCS: ", BTA_AG_RES_FMT_INT},
+ {"", BTA_AG_RES_FMT_STR},
+ {"+BIND: ", BTA_AG_RES_FMT_STR},
};
-static const tBTA_AG_RESULT* bta_ag_result_by_code(size_t code)
-{
- for (size_t i = 0; i != sizeof(bta_ag_result_tbl) /
- sizeof(bta_ag_result_tbl[0]); ++i)
- {
- if (code == bta_ag_result_tbl[i].result_id)
- return &bta_ag_result_tbl[i];
- }
- return 0;
-}
const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] =
{
@@ -188,31 +243,102 @@
bta_ag_hfp_cmd
};
-typedef struct
+/* callback event lookup table for HSP */
+const tBTA_AG_EVT bta_ag_hsp_cb_evt[] =
{
- size_t result_code;
- size_t indicator;
-} tBTA_AG_INDICATOR_MAP;
-
-/* callsetup indicator value lookup table */
-const tBTA_AG_INDICATOR_MAP callsetup_indicator_map[] =
-{
- {BTA_AG_IN_CALL_RES, BTA_AG_CALLSETUP_INCOMING},
- {BTA_AG_CALL_WAIT_RES, BTA_AG_CALLSETUP_INCOMING},
- {BTA_AG_OUT_CALL_ORIG_RES, BTA_AG_CALLSETUP_OUTGOING},
- {BTA_AG_OUT_CALL_ALERT_RES, BTA_AG_CALLSETUP_ALERTING}
+ BTA_AG_AT_CKPD_EVT, /* BTA_AG_HS_CMD_CKPD */
+ BTA_AG_SPK_EVT, /* BTA_AG_HS_CMD_VGS */
+ BTA_AG_MIC_EVT /* BTA_AG_HS_CMD_VGM */
};
-static size_t bta_ag_indicator_by_result_code(size_t code)
+/* callback event lookup table for HFP (Indexed by command) */
+const tBTA_AG_EVT bta_ag_hfp_cb_evt[] =
{
- for (size_t i = 0; i != sizeof(callsetup_indicator_map) /
- sizeof(callsetup_indicator_map[0]); ++i)
- {
- if (code == callsetup_indicator_map[i].result_code)
- return callsetup_indicator_map[i].indicator;
- }
- return BTA_AG_CALLSETUP_NONE;
-}
+ BTA_AG_AT_A_EVT, /* BTA_AG_HF_CMD_A */
+ BTA_AG_AT_D_EVT, /* BTA_AG_HF_CMD_D */
+ BTA_AG_SPK_EVT, /* BTA_AG_HF_CMD_VGS */
+ BTA_AG_MIC_EVT, /* BTA_AG_HF_CMD_VGM */
+ 0, /* BTA_AG_HF_CMD_CCWA */
+ BTA_AG_AT_CHLD_EVT, /* BTA_AG_HF_CMD_CHLD */
+ BTA_AG_AT_CHUP_EVT, /* BTA_AG_HF_CMD_CHUP */
+ BTA_AG_AT_CIND_EVT, /* BTA_AG_HF_CMD_CIND */
+ 0, /* BTA_AG_HF_CMD_CLIP */
+ 0, /* BTA_AG_HF_CMD_CMER */
+ BTA_AG_AT_VTS_EVT, /* BTA_AG_HF_CMD_VTS */
+ BTA_AG_AT_BINP_EVT, /* BTA_AG_HF_CMD_BINP */
+ BTA_AG_AT_BLDN_EVT, /* BTA_AG_HF_CMD_BLDN */
+ BTA_AG_AT_BVRA_EVT, /* BTA_AG_HF_CMD_BVRA */
+ 0, /* BTA_AG_HF_CMD_BRSF */
+ BTA_AG_AT_NREC_EVT, /* BTA_AG_HF_CMD_NREC */
+ BTA_AG_AT_CNUM_EVT, /* BTA_AG_HF_CMD_CNUM */
+ BTA_AG_AT_BTRH_EVT, /* BTA_AG_HF_CMD_BTRH */
+ BTA_AG_AT_CLCC_EVT, /* BTA_AG_HF_CMD_CLCC */
+ BTA_AG_AT_COPS_EVT, /* BTA_AG_HF_CMD_COPS */
+ 0, /* BTA_AG_HF_CMD_CMEE */
+ 0, /* BTA_AG_HF_CMD_BIA */
+ BTA_AG_AT_CBC_EVT, /* BTA_AG_HF_CMD_CBC */
+ 0, /* BTA_AG_HF_CMD_BCC */
+ BTA_AG_AT_BCS_EVT, /* BTA_AG_HF_CMD_BCS */
+ BTA_AG_AT_BAC_EVT, /* BTA_AG_HF_CMD_BAC */
+ BTA_AG_AT_BIND_EVT, /* BTA_AG_HF_CMD_BIND */
+ BTA_AG_AT_BIEV_EVT /* BTA_AG_HF_CMD_BIEV */
+};
+
+/* translation of API result code values to internal values */
+const UINT8 bta_ag_trans_result[] =
+{
+ BTA_AG_RES_VGS, /* BTA_AG_SPK_RES */
+ BTA_AG_RES_VGM, /* BTA_AG_MIC_RES */
+ BTA_AG_RES_BSIR, /* BTA_AG_INBAND_RING_RES */
+ BTA_AG_RES_CIND, /* BTA_AG_CIND_RES */
+ BTA_AG_RES_BINP, /* BTA_AG_BINP_RES */
+ BTA_AG_RES_CIEV, /* BTA_AG_IND_RES */
+ BTA_AG_RES_BVRA, /* BTA_AG_BVRA_RES */
+ BTA_AG_RES_CNUM, /* BTA_AG_CNUM_RES */
+ BTA_AG_RES_BTRH, /* BTA_AG_BTRH_RES */
+ BTA_AG_RES_CLCC, /* BTA_AG_CLCC_RES */
+ BTA_AG_RES_COPS, /* BTA_AG_COPS_RES */
+ 0, /* BTA_AG_IN_CALL_RES */
+ 0, /* BTA_AG_IN_CALL_CONN_RES */
+ BTA_AG_RES_CCWA, /* BTA_AG_CALL_WAIT_RES */
+ 0, /* BTA_AG_OUT_CALL_ORIG_RES */
+ 0, /* BTA_AG_OUT_CALL_ALERT_RES */
+ 0, /* BTA_AG_OUT_CALL_CONN_RES */
+ 0, /* BTA_AG_CALL_CANCEL_RES */
+ 0, /* BTA_AG_END_CALL_RES */
+ 0, /* BTA_AG_IN_CALL_HELD_RES */
+ BTA_AG_RES_UNAT, /* BTA_AG_UNAT_RES */
+ 0, /* BTA_AG_MULTI_CALL_RES */
+ BTA_AG_RES_BIND /* BTA_AG_BIND_RES */
+};
+
+/* callsetup indicator value lookup table */
+const UINT8 bta_ag_callsetup_ind_tbl[] =
+{
+ 0, /* BTA_AG_SPK_RES */
+ 0, /* BTA_AG_MIC_RES */
+ 0, /* BTA_AG_INBAND_RING_RES */
+ 0, /* BTA_AG_CIND_RES */
+ 0, /* BTA_AG_BINP_RES */
+ 0, /* BTA_AG_IND_RES */
+ 0, /* BTA_AG_BVRA_RES */
+ 0, /* BTA_AG_CNUM_RES */
+ 0, /* BTA_AG_BTRH_RES */
+ 0, /* BTA_AG_CLCC_RES */
+ 0, /* BTA_AG_COPS_RES */
+ BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_IN_CALL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_CONN_RES */
+ BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_CALL_WAIT_RES */
+ BTA_AG_CALLSETUP_OUTGOING, /* BTA_AG_OUT_CALL_ORIG_RES */
+ BTA_AG_CALLSETUP_ALERTING, /* BTA_AG_OUT_CALL_ALERT_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_OUT_CALL_CONN_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_CALL_CANCEL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_END_CALL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_HELD_RES */
+ 0, /* BTA_AG_UNAT_RES */
+ 0, /* BTA_AG_MULTI_CALL_RES */
+ 0, /* BTA_AG_BIND_RES */
+};
/*******************************************************************************
**
@@ -224,50 +350,49 @@
** Returns void
**
*******************************************************************************/
-static void bta_ag_send_result(tBTA_AG_SCB *p_scb, size_t code, char *p_arg,
+static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg,
INT16 int_arg)
{
- const tBTA_AG_RESULT *result = bta_ag_result_by_code(code);
- if (result == 0)
- {
- LOG_ERROR(LOG_TAG, "%s Unable to lookup result for code %zu", __func__, code);
- return;
- }
char buf[BTA_AG_AT_MAX_LEN + 16];
char *p = buf;
- memset(buf, 0, sizeof(buf));
-
+ UINT16 len;
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ memset(buf, NULL, sizeof(buf));
+#endif
/* init with \r\n */
*p++ = '\r';
*p++ = '\n';
/* copy result code string */
- strlcpy(p, result->result_string, sizeof(buf) - 2);
-
+ strlcpy(p, bta_ag_result_tbl[code].p_res, sizeof(buf) - 2);
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
if (p_scb->conn_service == BTA_AG_HSP)
{
/* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
switch(code)
{
- case BTA_AG_SPK_RES:
- case BTA_AG_MIC_RES:
+ case BTA_AG_RES_VGS:
+ case BTA_AG_RES_VGM:
if(*(p+COLON_IDX_4_VGSVGM) == ':')
{
+ #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("[HSP] ':'symbol is changed as '=' for HSP compatibility");
+ #endif
*(p+COLON_IDX_4_VGSVGM) = '=';
}
break;
}
}
-
- p += strlen(result->result_string);
+#endif
+ p += strlen(bta_ag_result_tbl[code].p_res);
/* copy argument if any */
- if (result->arg_type == BTA_AG_RES_FMT_INT)
+ if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT)
{
p += utl_itoa((UINT16) int_arg, p);
}
- else if (result->arg_type == BTA_AG_RES_FMT_STR)
+ else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR)
{
strcpy(p, p_arg);
p += strlen(p_arg);
@@ -277,11 +402,79 @@
*p++ = '\r';
*p++ = '\n';
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_IMP("bta_ag_send_result: %s", buf);
+#endif
+
/* send to RFCOMM */
- UINT16 len = 0;
PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
}
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_ag_send_multi_result
+**
+** Description Send multiple AT result codes.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb)
+{
+ char buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16];
+ char *p = buf;
+ UINT16 len;
+ UINT8 res_idx = 0;
+
+ if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN))
+ {
+ APPL_TRACE_DEBUG("m_res_cb is NULL or num_result is out of range.");
+ return;
+ }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ memset(buf, NULL, sizeof(buf));
+#endif
+
+ while(res_idx < m_res_cb->num_result)
+ {
+ /* init with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* copy result code string */
+ strcpy(p, bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+ p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+
+ /* copy argument if any */
+ if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT)
+ {
+ p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p);
+ }
+ else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR)
+ {
+ strcpy(p, m_res_cb->res_cb[res_idx].p_arg);
+ p += strlen(m_res_cb->res_cb[res_idx].p_arg);
+ }
+
+ /* finish with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ res_idx++;
+ }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("send_result: %s", buf);
+#endif
+
+ /* send to RFCOMM */
+ PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+#endif
+
/*******************************************************************************
**
** Function bta_ag_send_ok
@@ -294,7 +487,7 @@
*******************************************************************************/
static void bta_ag_send_ok(tBTA_AG_SCB *p_scb)
{
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_OK, NULL, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0);
}
/*******************************************************************************
@@ -312,9 +505,9 @@
{
/* If HFP and extended audio gateway error codes are enabled */
if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CMEE, NULL, errcode);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode);
else
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_ERROR, NULL, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0);
}
/*******************************************************************************
@@ -399,7 +592,7 @@
p += utl_itoa(id, p);
*p++ = ',';
utl_itoa(value, p);
- bta_ag_send_result(p_scb, BTA_AG_IND_RES, str, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0);
}
}
@@ -487,6 +680,68 @@
return (retval);
}
+/*******************************************************************************
+**
+** Function bta_ag_parse_biev
+**
+** Description Parse AT+BIEV parameter string.
+**
+**
+** Returns TRUE if parsed ok, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_parse_biev(tBTA_AG_SCB *p_scb, char *p_s)
+ {
+ INT32 token1;
+ long long int token2;
+ BOOLEAN cont = FALSE; /* Continue processing */
+ char *p, *end;
+ int i = 0;
+
+ while(p_s)
+ {
+ /* skip to comma delimiter */
+ for(p = p_s; *p != ',' && *p != 0; p++);
+
+ /* get integer value */
+ if (*p != 0)
+ {
+ *p = 0;
+ cont = TRUE;
+ }
+ else
+ cont = FALSE;
+
+ if (i > 1)
+ return FALSE;
+
+ if (i == 0)
+ {
+ token1 = utl_str2int32(p_s);
+ if (token1 == -1)
+ return FALSE;
+ }
+ else
+ {
+ token2 = strtoll(p_s, &end, 10);
+ if (*end != 0 || token2 < 0 || token2 > 0xFFFFFFFF)
+ return FALSE;
+ }
+
+ if (cont)
+ {
+ p_s = p + 1;
+ i++;
+ }
+ else
+ {
+ if (i == 0) return FALSE;
+ break;
+ }
+ }
+ return TRUE;
+ }
+
#if (BTM_WBS_INCLUDED == TRUE )
/*******************************************************************************
**
@@ -545,6 +800,61 @@
/*******************************************************************************
**
+** Function bta_ag_parse_bind
+**
+** Description Parse AT+BIND parameter string.
+**
+** Returns TRUE if parsed ok, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_parse_bind(tBTA_AG_SCB *p_scb, char *p_s)
+{
+ INT32 anum_hfind;
+ BOOLEAN cont = FALSE; /* Continue processing */
+ char *p;
+ int i = 0;
+
+ while(p_s)
+ {
+ /* skip to comma delimiter */
+ for(p = p_s; *p != ',' && *p != 0; p++);
+
+ /* get integre value */
+ if (*p != 0)
+ {
+ *p = 0;
+ cont = TRUE;
+ }
+ else
+ cont = FALSE;
+
+ anum_hfind = utl_str2int32(p_s);
+ if ((anum_hfind == -1) || (i == 20))
+ return FALSE;
+
+ switch(anum_hfind)
+ {
+ case BTA_AG_HFIND_ENHANCED_SAFETY:
+ APPL_TRACE_DEBUG("BTA_AG_HFIND_ENHANCED_SAFETY supported");
+ break;
+ default:
+ APPL_TRACE_ERROR("unknown HFIND");
+ break;
+ }
+
+ if (cont)
+ {
+ p_s = p + 1;
+ i++;
+ }
+ else
+ break;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
** Function bta_ag_process_unat_res
**
** Description Process the unat response data and remove extra carriage return
@@ -632,9 +942,10 @@
void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
{
UINT8 call = p_scb->call_ind;
+ UINT8 callsetup;
/* set new call and callsetup values based on BTA_AgResult */
- size_t callsetup = bta_ag_indicator_by_result_code(result);
+ callsetup = bta_ag_callsetup_ind_tbl[result];
if (result == BTA_AG_END_CALL_RES)
{
@@ -665,15 +976,16 @@
** Returns void
**
*******************************************************************************/
-void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 command_id, UINT8 arg_type,
+void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
char *p_arg, char *p_end, INT16 int_arg)
{
- APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type,
+ tBTA_AG_VAL val;
+ APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
int_arg, p_arg);
+ /* send OK */
bta_ag_send_ok(p_scb);
- tBTA_AG_VAL val;
val.hdr.handle = bta_ag_scb_to_idx(p_scb);
val.hdr.app_id = p_scb->app_id;
val.num = (UINT16) int_arg;
@@ -687,225 +999,8 @@
strlcpy(val.str, p_arg, sizeof(val.str));
/* call callback with event */
- (*bta_ag_cb.p_cback)(command_id, (tBTA_AG *) &val);
+ (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val);
}
-
-/*******************************************************************************
-**
-** Function bta_ag_find_empty_hf_ind)
-**
-** Description This function returns the index of an empty HF indicator
-** structure.
-**
-** Returns int : index of the empty HF indicator structure or
-** -1 if no empty indicator
-** is available.
-**
-*******************************************************************************/
-static int bta_ag_find_empty_hf_ind(tBTA_AG_SCB *p_scb)
-{
- for (int index = 0; index < BTA_AG_MAX_NUM_PEER_HF_IND; index++)
- {
- if (p_scb->peer_hf_indicators[index].ind_id == 0)
- return index;
- }
-
- return -1;
-}
-
-
-/*******************************************************************************
-**
-** Function bta_ag_find_hf_ind_by_id
-**
-** Description This function returns the index of the HF indicator
-** structure by the indicator id
-**
-** Returns int : index of the HF indicator structure
-** -1 if the indicator
-** was not found.
-**
-*******************************************************************************/
-static int bta_ag_find_hf_ind_by_id(tBTA_AG_HF_IND *p_hf_ind, int size, uint32_t ind_id)
-{
- for (int index = 0; index < size; index++)
- {
- if (p_hf_ind[index].ind_id == ind_id)
- return index;
- }
-
- return -1;
-}
-
-/*******************************************************************************
-**
-** Function bta_ag_parse_bind_set
-**
-** Description Parse AT+BIND set command and save the indicators
-**
-** Returns true if successful
-**
-*******************************************************************************/
-static bool bta_ag_parse_bind_set(tBTA_AG_SCB *p_scb, tBTA_AG_VAL val)
-{
- char *p_token = strtok(val.str, ",");
- if (p_token == NULL)
- return false;
-
- while (p_token != NULL)
- {
- uint16_t rcv_ind_id = atoi(p_token);
- int index = bta_ag_find_empty_hf_ind(p_scb);
- if (index == -1)
- {
- APPL_TRACE_WARNING("%s Can't save more indicators", __func__);
- return false;
- }
-
- p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id;
- APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id);
-
- p_token = strtok(NULL, ",");
- }
-
- return true;
-}
-
-/*******************************************************************************
-**
-** Function bta_ag_bind_response
-**
-** Description Send response for the AT+BIND command (HFP 1.7) received
-** from the headset based on the argument types.
-**
-** Returns Void
-**
-*******************************************************************************/
-static void bta_ag_bind_response(tBTA_AG_SCB *p_scb, uint8_t arg_type)
-{
- char buffer[BTA_AG_AT_MAX_LEN];
- memset(buffer, 0, BTA_AG_AT_MAX_LEN);
-
- if (arg_type == BTA_AG_AT_TEST)
- {
- int index = 0;
- buffer[index++] = '(';
-
- for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++)
- {
- if (bta_ag_local_hf_ind_cfg[i+1].is_supported == true)
- {
- /* Add ',' from second indicator */
- if (index > 1)
- buffer[index++] = ',';
- sprintf(&buffer[index++], "%d", bta_ag_local_hf_ind_cfg[i+1].ind_id);
- }
- }
-
- buffer[index++] = ')';
-
- bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
- bta_ag_send_ok(p_scb);
- }
- else if (arg_type == BTA_AG_AT_READ)
- {
- char *p = buffer;
-
- /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */
- for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++)
- {
- if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND)
- {
- APPL_TRACE_WARNING("%s No space for more HF indicators", __func__);
- break;
- }
-
- p_scb->local_hf_indicators[i].ind_id = bta_ag_local_hf_ind_cfg[i+1].ind_id;
- p_scb->local_hf_indicators[i].is_supported = bta_ag_local_hf_ind_cfg[i+1].is_supported;
- p_scb->local_hf_indicators[i].is_enable = bta_ag_local_hf_ind_cfg[i+1].is_enable;
-
- int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
- BTA_AG_MAX_NUM_PEER_HF_IND,
- p_scb->local_hf_indicators[i].ind_id);
-
- /* Check whether local and peer sides support this indicator */
- if (p_scb->local_hf_indicators[i].is_supported == true && peer_index != -1)
- {
- /* In the format of ind, state */
- p += utl_itoa((uint16_t) p_scb->local_hf_indicators[i].ind_id, p);
- *p++ = ',';
- p += utl_itoa((uint16_t) p_scb->local_hf_indicators[i].is_enable, p);
-
- bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
-
- memset(buffer, 0, sizeof(buffer));
- p = buffer;
- } else {
- /* If indicator is not supported, also set it to disable */
- p_scb->local_hf_indicators[i].is_enable = false;
- }
- }
-
- bta_ag_send_ok(p_scb);
-
- /* If the service level connection wan't already open, now it's open */
- if (!p_scb->svc_conn)
- bta_ag_svc_conn_open(p_scb, NULL);
- }
-}
-
-/*******************************************************************************
-**
-** Function bta_ag_parse_biev_response
-**
-** Description Send response for AT+BIEV command (HFP 1.7) received from
-** the headset based on the argument types.
-**
-** Returns true if the response was parsed successfully
-**
-*******************************************************************************/
-static bool bta_ag_parse_biev_response(tBTA_AG_SCB *p_scb, tBTA_AG_VAL *val)
-{
- char *p_token = strtok(val->str, ",");
- uint16_t rcv_ind_id = atoi(p_token);
-
- p_token = strtok(NULL, ",");
- uint16_t rcv_ind_val = atoi(p_token);
-
- APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id, rcv_ind_val);
-
- /* Check whether indicator ID is valid or not */
- if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND)
- {
- APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__, rcv_ind_id);
- return false;
- }
-
- /* Check this indicator is support or not and enabled or not */
- int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
- BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id);
- if (local_index == -1 ||
- p_scb->local_hf_indicators[local_index].is_supported != true ||
- p_scb->local_hf_indicators[local_index].is_enable != true)
- {
- APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__, rcv_ind_id);
- return false;
- }
-
- /* For each indicator ID, check whether the indicator value is in range */
- if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val ||
- rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val)
- {
- APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val);
- return false;
- }
-
- val->lidx = rcv_ind_id;
- val->num = rcv_ind_val;
-
- return true;
-}
-
/*******************************************************************************
**
** Function bta_ag_at_hfp_cback
@@ -920,9 +1015,12 @@
char *p_arg, char *p_end, INT16 int_arg)
{
tBTA_AG_VAL val;
+ tBTA_AG_EVT event;
tBTA_AG_SCB *ag_scb;
UINT32 i, ind_id;
UINT32 bia_masked_out;
+ tBTA_AG_FEAT features;
+ char value[PROPERTY_VALUE_MAX];
#if (BTM_WBS_INCLUDED == TRUE )
tBTA_AG_PEER_CODEC codec_type, codec_sent;
#endif
@@ -933,13 +1031,11 @@
return;
}
- APPL_TRACE_DEBUG("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+ APPL_TRACE_IMP("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
int_arg, p_arg);
- memset(&val, 0, sizeof(tBTA_AG_VAL));
val.hdr.handle = bta_ag_scb_to_idx(p_scb);
val.hdr.app_id = p_scb->app_id;
- val.hdr.status = BTA_AG_SUCCESS;
val.num = int_arg;
bdcpy(val.bd_addr, p_scb->peer_addr);
@@ -951,33 +1047,25 @@
}
strlcpy(val.str, p_arg, sizeof(val.str));
- /**
- * Unless this this is a local event, by default we'll forward
- * the event code to the application.
- * If |event| is 0 at the end of this function, the application
- * callback is NOT invoked.
- */
- tBTA_AG_EVT event = 0;
- if (cmd < BTA_AG_LOCAL_EVT_FIRST)
- event = cmd;
+ event = bta_ag_hfp_cb_evt[cmd];
switch (cmd)
{
- case BTA_AG_AT_A_EVT:
- case BTA_AG_SPK_EVT:
- case BTA_AG_MIC_EVT:
- case BTA_AG_AT_CHUP_EVT:
- case BTA_AG_AT_CBC_EVT:
+ case BTA_AG_HF_CMD_A:
+ case BTA_AG_HF_CMD_VGS:
+ case BTA_AG_HF_CMD_VGM:
+ case BTA_AG_HF_CMD_CHUP:
+ case BTA_AG_HF_CMD_CBC:
/* send OK */
bta_ag_send_ok(p_scb);
break;
- case BTA_AG_AT_BLDN_EVT:
+ case BTA_AG_HF_CMD_BLDN:
/* Do not send OK, App will send error or OK depending on
** last dial number enabled or not */
break;
- case BTA_AG_AT_D_EVT:
+ case BTA_AG_HF_CMD_D:
/* Do not send OK for Dial cmds
** Let application decide whether to send OK or ERROR*/
@@ -1011,7 +1099,7 @@
}
break;
- case BTA_AG_LOCAL_EVT_CCWA:
+ case BTA_AG_HF_CMD_CCWA:
/* store setting */
p_scb->ccwa_enabled = (BOOLEAN) int_arg;
@@ -1019,7 +1107,7 @@
bta_ag_send_ok(p_scb);
break;
- case BTA_AG_AT_CHLD_EVT:
+ case BTA_AG_HF_CMD_CHLD:
if (arg_type == BTA_AG_AT_TEST)
{
/* don't call callback */
@@ -1030,17 +1118,23 @@
if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
(p_scb->features & BTA_AG_FEAT_ECC) &&
(p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
- bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES,
- p_bta_ag_cfg->chld_val_ecc, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0);
else
- bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES,
- p_bta_ag_cfg->chld_val, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0);
/* send OK */
bta_ag_send_ok(p_scb);
- /* if service level conn. not already open, now it's open */
- bta_ag_svc_conn_open(p_scb, NULL);
+ /* if service level conn. not already open and our features and
+ ** peer features do not have Hf indicators, service level conn. now open
+ */
+ if (!p_scb->svc_conn &&
+ !((p_scb->features & BTA_AG_FEAT_HFIND) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND)))
+ {
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+
}
else
{
@@ -1084,66 +1178,38 @@
}
break;
- case BTA_AG_AT_BIND_EVT:
- APPL_TRACE_DEBUG("%s BTA_AG_AT_BIND_EVT arg_type: %d", __func__, arg_type);
- if (arg_type == BTA_AG_AT_SET)
- {
- if (bta_ag_parse_bind_set(p_scb, val))
- {
- bta_ag_send_ok(p_scb);
- } else {
- event = 0;/* don't call callback */
- bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
- }
- } else {
- bta_ag_bind_response(p_scb, arg_type);
-
- /* Need not pass this command beyond BTIF.*/
- /* Stack handles it internally */
- event = 0;/* don't call callback */
- }
- break;
-
- case BTA_AG_AT_BIEV_EVT:
- if (bta_ag_parse_biev_response(p_scb, &val))
- {
- bta_ag_send_ok(p_scb);
- } else {
- bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
- /* don't call callback receiving invalid indicator */
- event = 0;
- }
- break;
-
- case BTA_AG_AT_CIND_EVT:
+ case BTA_AG_HF_CMD_CIND:
if (arg_type == BTA_AG_AT_TEST)
{
/* don't call callback */
event = 0;
/* send CIND string, send OK */
- bta_ag_send_result(p_scb, BTA_AG_CIND_RES, p_bta_ag_cfg->cind_info, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0);
bta_ag_send_ok(p_scb);
}
break;
- case BTA_AG_LOCAL_EVT_CLIP:
+ case BTA_AG_HF_CMD_CLIP:
/* store setting, send OK */
p_scb->clip_enabled = (BOOLEAN) int_arg;
bta_ag_send_ok(p_scb);
break;
- case BTA_AG_LOCAL_EVT_CMER:
+ case BTA_AG_HF_CMD_CMER:
/* if parsed ok store setting, send OK */
if (bta_ag_parse_cmer(p_arg, p_end, &p_scb->cmer_enabled))
{
bta_ag_send_ok(p_scb);
/* if service level conn. not already open and our features and
- ** peer features do not have 3-way, service level conn. now open
+ ** peer features do not have 3-way and Hf indicators, service level conn. now open
*/
if (!p_scb->svc_conn &&
- !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY)))
+ !((p_scb->features & BTA_AG_FEAT_3WAY) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY)) &&
+ !((p_scb->features & BTA_AG_FEAT_HFIND) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND)))
{
bta_ag_svc_conn_open(p_scb, NULL);
}
@@ -1154,7 +1220,7 @@
}
break;
- case BTA_AG_AT_VTS_EVT:
+ case BTA_AG_HF_CMD_VTS:
/* check argument */
if (strlen(p_arg) == 1)
{
@@ -1167,7 +1233,7 @@
}
break;
- case BTA_AG_AT_BINP_EVT:
+ case BTA_AG_HF_CMD_BINP:
/* if feature not set don't call callback, send ERROR */
if (!(p_scb->features & BTA_AG_FEAT_VTAG))
{
@@ -1176,7 +1242,7 @@
}
break;
- case BTA_AG_AT_BVRA_EVT:
+ case BTA_AG_HF_CMD_BVRA:
/* if feature not supported don't call callback, send ERROR. App will send OK */
if (!(p_scb->features & BTA_AG_FEAT_VREC))
{
@@ -1185,27 +1251,75 @@
}
break;
- case BTA_AG_LOCAL_EVT_BRSF:
- {
- /* store peer features */
- p_scb->peer_features = (uint16_t) int_arg;
-
- tBTA_AG_FEAT features = p_scb->features;
- if (p_scb->peer_version < HFP_VERSION_1_7)
+ case BTA_AG_HF_CMD_BRSF:
+ /* store peer features. */
+ p_scb->peer_features = (UINT16) int_arg;
+ features = p_scb->features & BTA_AG_BSRF_FEAT_SPEC;
+ if (interop_match_addr(INTEROP_DISABLE_HF_INDICATOR,
+ (const bt_bdaddr_t*)p_scb->peer_addr))
{
- features &= HFP_1_6_FEAT_MASK;
+ if ((p_scb->peer_version < HFP_VERSION_1_7) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND))
+ {
+ APPL_TRACE_WARNING("hf indicator needs hfp 1.7 support,"
+ "thus remove remote device HF indicator bit");
+ p_scb->peer_features = p_scb->peer_features &(~BTA_AG_PEER_FEAT_HFIND);
+ }
+ }
+ /* if the devices does not support HFP 1.7, report DUT's HFP version as 1.6 */
+ if ((p_scb->peer_version < HFP_VERSION_1_7) &&
+ (!(p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND)))
+ {
+ /* For PTS keep flags as is. */
+ if (property_get("bt.pts.certification", value, "false") &&
+ strcmp(value, "true") != 0)
+ {
+ features = features & ~(BTA_AG_FEAT_HFIND | BTA_AG_FEAT_S4);
+ }
+ }
+ else if ((p_scb->peer_version == HFP_VERSION_1_7) &&
+ (!(p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND)))
+ {
+ APPL_TRACE_WARNING("%s: Remote is hfp 1.7 but does not support HF indicators" \
+ "unset hf indicator bit from BRSF", __func__);
+ /* For PTS keep flags as is. */
+ if (property_get("bt.pts.certification", value, "false") &&
+ strcmp(value, "true") != 0)
+ {
+ features = features & ~(BTA_AG_FEAT_HFIND);
+ }
}
- APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__,
- p_scb->peer_features, features);
+ bt_property_t prop_name;
+ bt_bdname_t bdname;
+ BOOLEAN remote_name = FALSE;
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property((bt_bdaddr_t*)p_scb->peer_addr,
+ &prop_name) == BT_STATUS_SUCCESS)
+ {
+ remote_name = TRUE;
+ }
+
+ if (interop_match_addr(INTEROP_DISABLE_CODEC_NEGOTIATION,
+ (const bt_bdaddr_t*)p_scb->peer_addr) ||
+ (remote_name && interop_match_name(INTEROP_DISABLE_CODEC_NEGOTIATION,
+ (const char *)bdname.name)))
+ {
+ APPL_TRACE_IMP("%s disable codec negotiation for phone, remote" \
+ "for blacklisted device", __func__);
+ features = features & ~(BTA_AG_FEAT_CODEC);
+ p_scb->peer_features = p_scb->peer_features & ~(BTA_AG_PEER_FEAT_CODEC);
+
+ }
/* send BRSF, send OK */
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t) features);
+ bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
+ (INT16) features);
bta_ag_send_ok(p_scb);
break;
- }
- case BTA_AG_AT_NREC_EVT:
+ case BTA_AG_HF_CMD_NREC:
/* if feature send OK, else don't call callback, send ERROR */
if (p_scb->features & BTA_AG_FEAT_ECNR)
{
@@ -1218,7 +1332,7 @@
}
break;
- case BTA_AG_AT_BTRH_EVT:
+ case BTA_AG_HF_CMD_BTRH:
/* if feature send BTRH, send OK:, else don't call callback, send ERROR */
if (p_scb->features & BTA_AG_FEAT_BTRH)
{
@@ -1229,7 +1343,7 @@
{
if (ag_scb->in_use)
{
- bta_ag_send_result(ag_scb, BTA_AG_BTRH_RES, NULL, int_arg);
+ bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg);
}
}
bta_ag_send_ok(p_scb);
@@ -1246,7 +1360,7 @@
}
break;
- case BTA_AG_AT_COPS_EVT:
+ case BTA_AG_HF_CMD_COPS:
if (arg_type == BTA_AG_AT_SET)
{
/* don't call callback */
@@ -1257,7 +1371,7 @@
}
break;
- case BTA_AG_LOCAL_EVT_CMEE:
+ case BTA_AG_HF_CMD_CMEE:
if (p_scb->features & BTA_AG_FEAT_EXTERR)
{
/* store setting */
@@ -1274,7 +1388,7 @@
event = 0;
break;
- case BTA_AG_LOCAL_EVT_BIA:
+ case BTA_AG_HF_CMD_BIA:
/* don't call callback */
event = 0;
@@ -1306,10 +1420,10 @@
bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
break;
- case BTA_AG_AT_CNUM_EVT:
+ case BTA_AG_HF_CMD_CNUM:
break;
- case BTA_AG_AT_CLCC_EVT:
+ case BTA_AG_HF_CMD_CLCC:
if(!(p_scb->features & BTA_AG_FEAT_ECS))
{
event = 0;
@@ -1318,7 +1432,7 @@
break;
#if (BTM_WBS_INCLUDED == TRUE )
- case BTA_AG_AT_BAC_EVT:
+ case BTA_AG_HF_CMD_BAC:
bta_ag_send_ok(p_scb);
/* store available codecs from the peer */
@@ -1354,7 +1468,7 @@
}
break;
- case BTA_AG_AT_BCS_EVT:
+ case BTA_AG_HF_CMD_BCS:
bta_ag_send_ok(p_scb);
alarm_cancel(p_scb->codec_negotiation_timer);
@@ -1382,12 +1496,66 @@
val.num = codec_sent;
break;
- case BTA_AG_LOCAL_EVT_BCC:
+ case BTA_AG_HF_CMD_BCC:
bta_ag_send_ok(p_scb);
+ p_scb->codec_updated = TRUE;
bta_ag_sco_open(p_scb, NULL);
break;
#endif
-
+ case BTA_AG_HF_CMD_BIND:
+ if ((p_scb->features & BTA_AG_FEAT_HFIND) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND))
+ {
+ val.num = arg_type;
+ if (arg_type == BTA_AG_AT_SET)
+ {
+ if (!bta_ag_parse_bind(p_scb, p_arg))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ else
+ {
+ bta_ag_send_ok (p_scb);
+ }
+ }
+ else if (arg_type == BTA_AG_AT_READ)
+ {
+ /* open SLC when response ok is sent from app*/
+ p_scb->slc_pend_open = true;
+ }
+ else if (arg_type == BTA_AG_AT_TEST)
+ {
+ /* get ag's list of supported hf indicators from app */
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
+ }
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+ case BTA_AG_HF_CMD_BIEV:
+ if ((p_scb->features & BTA_AG_FEAT_HFIND) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_HFIND))
+ {
+ if (!bta_ag_parse_biev(p_scb, p_arg))
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ }
+ else
+ {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
default:
bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
break;
@@ -1426,7 +1594,6 @@
{
val.hdr.handle = bta_ag_scb_to_idx(p_scb);
val.hdr.app_id = p_scb->app_id;
- val.hdr.status = BTA_AG_SUCCESS;
val.num = 0;
strlcpy(val.str, p_arg, BTA_AG_AT_MAX_LEN);
(*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
@@ -1449,13 +1616,14 @@
*******************************************************************************/
void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
{
+ UINT8 code = bta_ag_trans_result[p_result->result];
APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result);
switch(p_result->result)
{
case BTA_AG_SPK_RES:
case BTA_AG_MIC_RES:
- bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
break;
case BTA_AG_IN_CALL_RES:
@@ -1529,7 +1697,7 @@
{
if (p_result->data.str[0] != 0)
{
- bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
}
if (p_result->data.ok_flag == BTA_AG_OK_DONE)
@@ -1559,13 +1727,15 @@
*******************************************************************************/
void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
{
- APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
+ UINT8 code = bta_ag_trans_result[p_result->result];
+
+ APPL_TRACE_IMP("bta_ag_hfp_result : res = %d", p_result->result);
switch(p_result->result)
{
case BTA_AG_SPK_RES:
case BTA_AG_MIC_RES:
- bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
break;
case BTA_AG_IN_CALL_RES:
@@ -1620,6 +1790,16 @@
*/
bta_ag_send_call_inds(p_scb, p_result->result);
+ if (interop_match_addr(INTEROP_DELAY_SCO_FOR_MT_CALL,
+ (const bt_bdaddr_t*)p_scb->peer_addr))
+ {
+ /* Ensure that call active indicator is sent prior to SCO connection
+ request by adding some delay. Some remotes are very strict in the
+ order of call indicator and SCO connection request. */
+ APPL_TRACE_IMP("%s: sleeping 20msec before opening sco", __func__);
+ usleep(20*1000);
+ }
+
if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
{
if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
@@ -1722,7 +1902,7 @@
case BTA_AG_INBAND_RING_RES:
p_scb->inband_enabled = p_result->data.state;
APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
- bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
break;
case BTA_AG_CIND_RES:
@@ -1736,7 +1916,7 @@
p_scb->callheld_ind = p_result->data.str[12] - '0';
APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind);
- bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
bta_ag_send_ok(p_scb);
break;
@@ -1748,7 +1928,7 @@
{
if (p_result->data.str[0] != 0)
{
- bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
}
if (p_result->data.ok_flag == BTA_AG_OK_DONE)
@@ -1768,11 +1948,18 @@
{
bta_ag_process_unat_res(p_result->data.str);
APPL_TRACE_DEBUG("BTA_AG_RES :%s",p_result->data.str);
- bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
}
if (p_result->data.ok_flag == BTA_AG_OK_DONE)
bta_ag_send_ok(p_scb);
+
+ if (p_scb->slc_pend_open)
+ {
+ APPL_TRACE_DEBUG("opening SLC now after +BIND READ response");
+ bta_ag_svc_conn_open(p_scb, NULL);
+ p_scb->slc_pend_open = FALSE;
+ }
}
else
{
@@ -1783,7 +1970,7 @@
case BTA_AG_CALL_WAIT_RES:
if (p_scb->ccwa_enabled)
{
- bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
}
bta_ag_send_call_inds(p_scb, p_result->result);
break;
@@ -1793,7 +1980,7 @@
break;
case BTA_AG_BVRA_RES:
- bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
break;
case BTA_AG_BTRH_RES:
@@ -1802,7 +1989,7 @@
/* Don't respond to read if not in response & hold state */
if (p_result->data.num != BTA_AG_BTRH_NO_RESP)
{
- bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
}
/* In case of a response to a read request we need to send OK */
@@ -1815,52 +2002,15 @@
}
break;
- case BTA_AG_BIND_RES:
- {
- /* Find whether ind_id is supported by local device or not */
- int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
- BTA_AG_MAX_NUM_LOCAL_HF_IND, p_result->data.ind.id);
- if (local_index == -1)
- {
- APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
- p_result->data.ind.id);
- return;
- }
+ case BTA_AG_BIND_RES:
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ break;
- /* Find whether ind_id is supported by peer device or not */
- int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
- BTA_AG_MAX_NUM_PEER_HF_IND, p_result->data.ind.id);
- if (peer_index == -1)
- {
- APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
- p_result->data.ind.id);
- return;
- } else {
- /* If the current state is different from the one upper layer request
- change current state and send out the result */
- if (p_scb->local_hf_indicators[local_index].is_enable != p_result->data.ind.on_demand)
- {
- char buffer[BTA_AG_AT_MAX_LEN] = {0};
- char *p = buffer;
-
- p_scb->local_hf_indicators[local_index].is_enable = p_result->data.ind.on_demand;
- p += utl_itoa(p_result->data.ind.id, p);
- *p++ = ',';
- p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p);
-
- bta_ag_send_result(p_scb, p_result->result, buffer, 0);
- } else {
- APPL_TRACE_DEBUG("%s HF Indicator %d already %s", p_result->data.ind.id,
- (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled");
- }
- }
+ default:
break;
}
-
- default:
- break;
}
-}
+
/*******************************************************************************
**
@@ -1918,7 +2068,7 @@
/* send +BCS */
APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid);
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, NULL, codec_uuid);
+ bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid);
}
#endif
@@ -1937,14 +2087,41 @@
{
UNUSED(p_data);
+ if ((p_scb->conn_service == BTA_AG_HFP) &&
+ p_scb->callsetup_ind != BTA_AG_CALLSETUP_INCOMING)
+ {
+ APPL_TRACE_DEBUG("don't send the ring since there is no MT call setup");
+ return;
+ }
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+ tBTA_AG_MULTI_RESULT_CB m_res_cb;
+
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
+ {
+ memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB));
+
+ m_res_cb.num_result = 2;
+ AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0)
+ AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0)
+
+ bta_ag_send_multi_result(p_scb, &m_res_cb);
+ }
+ else
+ {
+ /* send RING ONLY */
+ bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+ }
+#else
/* send RING */
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_RING, NULL, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
/* if HFP and clip enabled and clip data send CLIP */
if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
{
- bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CLIP, p_scb->clip, 0);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0);
}
+#endif
bta_sys_start_timer(p_scb->ring_timer, BTA_AG_RING_TIMEOUT_MS,
BTA_AG_RING_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h
index eac98c2..fa32e67 100644
--- a/bta/ag/bta_ag_int.h
+++ b/bta/ag/bta_ag_int.h
@@ -28,10 +28,30 @@
#include "bta_api.h"
#include "bta_ag_api.h"
#include "bta_ag_at.h"
+#include "osi/include/log.h"
+
+/* Send RING & CLIP in one AT cmd */
+#ifndef BTA_AG_MULTI_RESULT_INCLUDED
+#define BTA_AG_MULTI_RESULT_INCLUDED FALSE
+#endif
+
+/* Replace : in VGS and VGM for HSP */
+#ifndef BTA_HSP_RESULT_REPLACE_COLON
+#define BTA_HSP_RESULT_REPLACE_COLON TRUE
+#endif
/*****************************************************************************
** Constants
*****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+#define HFP_VERSION_1_7 0x0107
+
+
+#define HSP_VERSION_1_0 0x0100
+#define HSP_VERSION_1_2 0x0102
+
/* Number of SCBs (AG service instances that can be registered) */
#ifndef BTA_AG_NUM_SCB
#define BTA_AG_NUM_SCB 2
@@ -45,10 +65,6 @@
/* RFCOMM MTU SIZE */
#define BTA_AG_MTU 256
-/* Max number of peer and local HF indicators */
-#define BTA_AG_MAX_NUM_PEER_HF_IND 20
-#define BTA_AG_MAX_NUM_LOCAL_HF_IND 4
-
/* Internal profile indexes */
#define BTA_AG_HSP 0 /* index for HSP */
#define BTA_AG_HFP 1 /* index for HFP */
@@ -64,7 +80,7 @@
BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | \
BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
- BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
+ BTA_AG_FEAT_HFIND| BTA_AG_FEAT_S4| \
BTA_AG_FEAT_VOIP)
#define BTA_AG_SDP_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \
@@ -285,11 +301,8 @@
BOOLEAN codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
tBTA_AG_SCO_MSBC_SETTINGS codec_msbc_settings; /* settings to be used for the impending eSCO */
#endif
+ BOOLEAN slc_pend_open; /* SLC is pending open */
- tBTA_AG_HF_IND peer_hf_indicators[BTA_AG_MAX_NUM_PEER_HF_IND]; /* Peer supported
- HF indicators */
- tBTA_AG_HF_IND local_hf_indicators[BTA_AG_MAX_NUM_LOCAL_HF_IND]; /* Local supported
- HF indicators */
} tBTA_AG_SCB;
/* type for sco data */
@@ -334,7 +347,6 @@
/* config struct */
extern tBTA_AG_CFG *p_bta_ag_cfg;
-extern tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[];
/*****************************************************************************
** Function prototypes
diff --git a/bta/ag/bta_ag_main.c b/bta/ag/bta_ag_main.c
index 3abd1ef..182985c 100644
--- a/bta/ag/bta_ag_main.c
+++ b/bta/ag/bta_ag_main.c
@@ -783,7 +783,7 @@
{
if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL)
{
- APPL_TRACE_DEBUG("bta_ag_api_result: p_scb 0x%08x ", p_scb);
+ APPL_TRACE_IMP("bta_ag_api_result: p_scb 0x%08x ", p_scb);
bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
}
}
@@ -815,23 +815,21 @@
tBTA_AG_ST_TBL state_table;
UINT8 action;
int i;
-
-#if BTA_AG_DEBUG == TRUE
UINT16 in_event = event;
UINT8 in_state = p_scb->state;
- /* Ignore displaying of AT results when not connected (Ignored in state machine) */
if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST)
{
- APPL_TRACE_EVENT("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
+ #if BTA_AG_DEBUG == TRUE
+ APPL_TRACE_IMP("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
bta_ag_scb_to_idx(p_scb),
p_scb->state, bta_ag_state_str(p_scb->state),
event, bta_ag_evt_str(event, p_data->api_result.result));
+ #else
+ APPL_TRACE_IMP("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
+ bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+ #endif
}
-#else
- APPL_TRACE_EVENT("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
- bta_ag_scb_to_idx(p_scb), p_scb->state, event);
-#endif
event &= 0x00FF;
if (event >= (BTA_AG_MAX_EVT & 0x00FF))
@@ -840,6 +838,9 @@
return;
}
+ /* If SLC time out, dump the logs */
+ if (event == BTA_AG_SVC_TIMEOUT_EVT)
+ GENERATE_VND_LOGS();
/* look up the state table for the current state */
state_table = bta_ag_st_tbl[p_scb->state];
@@ -849,7 +850,10 @@
/* execute action functions */
for (i = 0; i < BTA_AG_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != BTA_AG_IGNORE)
+ /* Fix for below klockwork issue.
+ * Klockwork issue: Possible attempt to access element 33..255 of array 'bta_ag_action'
+ * whose size is 32 */
+ if (((action = state_table[event][i]) < BTA_AG_IGNORE) && (action >= 0))
{
(*bta_ag_action[action])(p_scb, p_data);
}
@@ -858,15 +862,18 @@
break;
}
}
-#if BTA_AG_DEBUG == TRUE
if (p_scb->state != in_state)
{
- APPL_TRACE_EVENT("BTA AG State Change: [%s] -> [%s] after Event [%s]",
+ #if BTA_AG_DEBUG == TRUE
+ APPL_TRACE_IMP("BTA AG State Change: [%s] -> [%s] after Event [%s]",
bta_ag_state_str(in_state),
bta_ag_state_str(p_scb->state),
bta_ag_evt_str(in_event, p_data->api_result.result));
+ #else
+ APPL_TRACE_IMP("BTA AG State Change: [%d] -> [%d]",
+ in_state, p_scb->state);
+ #endif
}
-#endif
}
/*******************************************************************************
@@ -910,7 +917,7 @@
default:
if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL)
{
- APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", p_scb);
+ APPL_TRACE_IMP("bta_ag_hdl_event: p_scb 0x%08x ", p_scb);
bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
}
break;
@@ -958,6 +965,7 @@
case BTA_AG_CALL_CANCEL_RES: return ("AT Result BTA_AG_CALL_CANCEL_RES");
case BTA_AG_END_CALL_RES: return ("AT Result BTA_AG_END_CALL_RES");
case BTA_AG_UNAT_RES: return ("AT Result BTA_AG_UNAT_RES");
+ case BTA_AG_BIND_RES: return ("AT Result BTA_AG_BIND_RES");
default: return ("Unknown AG Result");
}
case BTA_AG_API_SETCODEC_EVT:
diff --git a/bta/ag/bta_ag_rfc.c b/bta/ag/bta_ag_rfc.c
index d3f2705..b0bf6b9 100644
--- a/bta/ag/bta_ag_rfc.c
+++ b/bta/ag/bta_ag_rfc.c
@@ -287,11 +287,12 @@
{
BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn);
-
+ /* Fix for below klockwork issue
+ * Array 'bta_ag_mgmt_cback_tbl' size is 3.
+ * Possible attempt to access element -1,3..USHRT_MAX-1 of array 'bta_ag_mgmt_cback_tbl'. */
bta_ag_port_status = RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn,
TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]),
- bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
-
+ bta_ag_mgmt_cback_tbl[(UINT16)(bta_ag_scb_to_idx(p_scb) - 1)]);
if( bta_ag_port_status == PORT_SUCCESS )
{
bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
@@ -369,13 +370,15 @@
{
BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service],
p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn);
-
+ /* Fix for below klockwork issue
+ * Array 'bta_ag_mgmt_cback_tbl' size is 3.
+ * Possible attempt to access element -1,3..USHRT_MAX-1 of array 'bta_ag_mgmt_cback_tbl' */
if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn,
FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle),
- bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS)
+ bta_ag_mgmt_cback_tbl[(UINT16)(bta_ag_scb_to_idx(p_scb) - 1)]) == PORT_SUCCESS)
{
bta_ag_setup_port(p_scb, p_scb->conn_handle);
- APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle);
+ APPL_TRACE_IMP("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle);
}
/* RFCOMM create connection failed; send ourselves RFCOMM close event */
else
diff --git a/bta/ag/bta_ag_sco.c b/bta/ag/bta_ag_sco.c
index 89e6f6c..8bbbe24 100644
--- a/bta/ag/bta_ag_sco.c
+++ b/bta/ag/bta_ag_sco.c
@@ -33,6 +33,8 @@
#include "btm_api.h"
#include "bt_common.h"
#include "utl.h"
+#include "device/include/interop.h"
+//#include "osi/include/log.h"
#ifndef BTA_AG_SCO_DEBUG
#define BTA_AG_SCO_DEBUG FALSE
@@ -40,10 +42,11 @@
/* Codec negotiation timeout */
#ifndef BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS
-#define BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS (3 * 1000) /* 3 seconds */
+#define BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS (5 * 1000) /* 5 seconds */
#endif
extern fixed_queue_t *btu_bta_alarm_queue;
+extern void bta_dm_pm_set_sniff_policy_toggle(BD_ADDR peer_addr, BOOLEAN bDisable);
#if BTA_AG_SCO_DEBUG == TRUE
static char *bta_ag_sco_evt_str(UINT8 event);
@@ -73,19 +76,36 @@
};
#if (BTM_WBS_INCLUDED == TRUE )
-#define BTA_AG_NUM_CODECS 3
-#define BTA_AG_ESCO_SETTING_IDX_CVSD 0 /* eSCO setting for CVSD */
-#define BTA_AG_ESCO_SETTING_IDX_T1 1 /* eSCO setting for mSBC T1 */
-#define BTA_AG_ESCO_SETTING_IDX_T2 2 /* eSCO setting for mSBC T2 */
+#define BTA_AG_NUM_CODECS 4
+#define BTA_AG_ESCO_SETTING_IDX_CVSD_S4 0 /* eSCO S4 setting for CVSD */
+#define BTA_AG_ESCO_SETTING_IDX_CVSD_S3 1 /* eSCO S3 setting for CVSD */
+#define BTA_AG_ESCO_SETTING_IDX_T1 2 /* eSCO setting for mSBC T1 */
+#define BTA_AG_ESCO_SETTING_IDX_T2 3 /* eSCO setting for mSBC T2 */
static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] =
{
- /* CVSD */
+ /* CVSD S4 */
{
BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
0x000c, /* 12 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+ },
+ /* CVSD S3 */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
(BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
BTM_SCO_PKT_TYPES_MASK_HV2 +
BTM_SCO_PKT_TYPES_MASK_HV3 +
@@ -94,7 +114,7 @@
BTM_SCO_PKT_TYPES_MASK_EV5 +
BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
- BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+ BTM_ESCO_RETRANS_POWER /* Retransmission effort */
},
/* mSBC T1 */
{
@@ -124,21 +144,40 @@
};
#else
/* WBS not included, CVSD by default */
-static const tBTM_ESCO_PARAMS bta_ag_esco_params =
+static const tBTM_ESCO_PARAMS bta_ag_esco_params[] =
{
- BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
- BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
- 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
- 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
- (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
- BTM_SCO_PKT_TYPES_MASK_HV2 +
- BTM_SCO_PKT_TYPES_MASK_HV3 +
- BTM_SCO_PKT_TYPES_MASK_EV3 +
- BTM_SCO_PKT_TYPES_MASK_EV4 +
- BTM_SCO_PKT_TYPES_MASK_EV5 +
- BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
- BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
- BTM_ESCO_RETRANS_POWER /* Retransmission effort */
+ /* CVSD S4 */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000c, /* 12 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+ },
+ /* CVSD S3 */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission effort */
+ }
};
#endif
@@ -199,7 +238,7 @@
{
UINT16 handle = 0;
- APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
+ APPL_TRACE_IMP("bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
&bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx, bta_ag_cb.scb[0].state);
@@ -231,13 +270,17 @@
/* Restore settings */
if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC)
{
+#if (BLUETOOTH_QTI_SW == FALSE) /* This change is not needed.*/
/* set_sco_codec(BTM_SCO_CODEC_NONE); we should get a close */
BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+#endif
- /* If SCO open was initiated by AG and failed for mSBC, then attempt
- mSBC with T1 settings i.e. 'Safe Settings'. If this fails, then switch to CVSD */
+ /* If SCO open was initiated by AG and failed for mSBC,then switch to CVSD
+ as our BT SOC has already tried the T1 safe setting for SCO failure before
+ updating to the BT HOST.*/
if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb))
{
+#if (BLUETOOTH_QTI_SW == FALSE) /* This change is not needed.*/
if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2)
{
APPL_TRACE_DEBUG("Fallback to mSBC T1 settings");
@@ -248,6 +291,12 @@
APPL_TRACE_DEBUG("Fallback to CVSD settings");
bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
}
+#else
+ {
+ APPL_TRACE_DEBUG("Fallback to CVSD settings");
+ bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
+ }
+#endif
}
}
@@ -258,6 +307,10 @@
p_buf->event = BTA_AG_SCO_CLOSE_EVT;
p_buf->layer_specific = handle;
bta_sys_sendmsg(p_buf);
+ if (interop_match_addr(INTEROP_DISABLE_SNIFF_POLICY_DURING_SCO,
+ (const bt_bdaddr_t *)&bta_ag_cb.sco.p_curr_scb->peer_addr)) {
+ bta_dm_pm_set_sniff_policy_toggle(bta_ag_cb.sco.p_curr_scb->peer_addr, false);
+ }
} else {
/* no match found */
APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
@@ -314,7 +367,7 @@
{
status = BTM_RemoveSco(p_scb->sco_idx);
- APPL_TRACE_DEBUG("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
+ APPL_TRACE_IMP("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
if (status == BTM_CMD_STARTED)
{
@@ -361,7 +414,7 @@
/* If no other SCO active, allow this one */
if (!bta_ag_cb.sco.p_curr_scb)
{
- APPL_TRACE_EVENT("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
+ APPL_TRACE_IMP("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
@@ -370,7 +423,7 @@
}
else /* Begin a transfer: Close current SCO before responding */
{
- APPL_TRACE_DEBUG("bta_ag_esco_connreq_cback: Begin XFER");
+ APPL_TRACE_IMP("bta_ag_esco_connreq_cback: Begin XFER");
bta_ag_cb.sco.p_xfer_scb = p_scb;
bta_ag_cb.sco.conn_data = p_data->conn_evt;
bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
@@ -438,9 +491,9 @@
tBTM_STATUS status;
UINT8 *p_bd_addr = NULL;
tBTM_ESCO_PARAMS params;
+ int codec_index = (p_scb->peer_features & BTA_AG_PEER_FEAT_S4) ? 0 : 1;
#if (BTM_WBS_INCLUDED == TRUE )
tBTA_AG_PEER_CODEC esco_codec = BTM_SCO_CODEC_CVSD;
- int codec_index = 0;
#endif
#if (BTM_SCO_HCI_INCLUDED == TRUE )
tBTM_SCO_ROUTE_TYPE sco_route;
@@ -487,7 +540,7 @@
params = bta_ag_esco_params[codec_index];
#else
/* When WBS is not included, use CVSD by default */
- params = bta_ag_esco_params;
+ params = bta_ag_esco_params[codec_index];
#endif
if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
@@ -551,6 +604,7 @@
bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
#if (BTM_WBS_INCLUDED == TRUE )
+#if (BLUETOOTH_QTI_SW == FALSE) /* These changes are not needed*/
/* Allow any platform specific pre-SCO set up to take place */
bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP,
esco_codec);
@@ -561,6 +615,7 @@
BTM_WriteVoiceSettings (BTM_VOICE_SETTING_TRANS);
else
BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+#endif
/* save the current codec because sco_codec can be updated while SCO is open. */
p_scb->inuse_codec = esco_codec;
#else
@@ -606,7 +661,7 @@
}
}
- APPL_TRACE_API("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+ APPL_TRACE_IMP("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
is_orig, p_scb->sco_idx, status, params.packet_types);
}
@@ -644,6 +699,10 @@
{
tBTA_AG_SCB *p_scb = (tBTA_AG_SCB *)data;
+ APPL_TRACE_IMP("codec negotiation timedout, aborting SCO/eSCO creation");
+
+ GENERATE_VND_LOGS();
+
/* Announce that codec negotiation failed. */
bta_ag_sco_codec_nego(p_scb, FALSE);
@@ -710,15 +769,15 @@
#if (BTM_SCO_HCI_INCLUDED == TRUE )
BT_HDR *p_buf;
#endif
-#if BTA_AG_SCO_DEBUG == TRUE
UINT8 in_state = p_sco->state;
- APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
+#if BTA_AG_SCO_DEBUG == TRUE
+ APPL_TRACE_IMP("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
p_scb->sco_idx,
p_sco->state, bta_ag_sco_state_str(p_sco->state),
event, bta_ag_sco_evt_str(event));
#else
- APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
+ APPL_TRACE_IMP("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
p_scb->sco_idx, p_sco->state, event);
#endif
@@ -773,9 +832,17 @@
bta_ag_remove_sco(p_scb, FALSE);
#if (BTM_WBS_INCLUDED == TRUE )
- /* start codec negotiation */
- p_sco->state = BTA_AG_SCO_CODEC_ST;
- p_cn_scb = p_scb;
+ if (p_scb->peer_codecs != BTA_AG_CODEC_NONE)
+ {
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+ }
+ else
+ {
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ }
#else
/* create sco connection to peer */
bta_ag_create_sco(p_scb, TRUE);
@@ -899,15 +966,19 @@
break;
case BTA_AG_SCO_SHUTDOWN_E:
- /* If not opening scb, just close it */
- if (p_scb != p_sco->p_curr_scb)
- {
- /* remove listening connection */
- bta_ag_remove_sco(p_scb, FALSE);
- }
- else
- p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->p_curr_scb = NULL;
+ }
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
break;
case BTA_AG_SCO_CONN_OPEN_E:
@@ -941,15 +1012,19 @@
break;
case BTA_AG_SCO_SHUTDOWN_E:
- /* If not opening scb, just close it */
- if (p_scb != p_sco->p_curr_scb)
- {
- /* remove listening connection */
- bta_ag_remove_sco(p_scb, FALSE);
- }
- else
- p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->p_curr_scb = NULL;
+ }
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
break;
case BTA_AG_SCO_CONN_OPEN_E:
@@ -1120,9 +1195,17 @@
case BTA_AG_SCO_CONN_CLOSE_E:
#if (BTM_WBS_INCLUDED == TRUE )
- /* start codec negotiation */
- p_sco->state = BTA_AG_SCO_CODEC_ST;
- p_cn_scb = p_scb;
+ if (p_scb->peer_codecs != BTA_AG_CODEC_NONE)
+ {
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+ }
+ else
+ {
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ }
#else
/* open sco connection */
bta_ag_create_sco(p_scb, TRUE);
@@ -1175,10 +1258,19 @@
bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE);
#if (BTM_WBS_INCLUDED == TRUE )
- /* start codec negotiation */
- p_sco->state = BTA_AG_SCO_CODEC_ST;
- p_cn_scb = p_sco->p_xfer_scb;
- p_sco->p_xfer_scb = NULL;
+ if (p_scb->peer_codecs != BTA_AG_CODEC_NONE)
+ {
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_sco->p_xfer_scb;
+ p_sco->p_xfer_scb = NULL;
+ }
+ else
+ {
+ bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
+ p_sco->p_xfer_scb = NULL;
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ }
#else
/* create sco connection to peer */
bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
@@ -1261,15 +1353,19 @@
default:
break;
}
-#if BTA_AG_SCO_DEBUG == TRUE
+
if (p_sco->state != in_state)
{
- APPL_TRACE_EVENT("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
- bta_ag_sco_state_str(in_state),
- bta_ag_sco_state_str(p_sco->state),
- bta_ag_sco_evt_str(event));
+ #if BTA_AG_SCO_DEBUG == TRUE
+ APPL_TRACE_IMP("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+ bta_ag_sco_state_str(in_state),
+ bta_ag_sco_state_str(p_sco->state),
+ bta_ag_sco_evt_str(event));
+ #else
+ APPL_TRACE_IMP("BTA AG SCO State Change: [%d] -> [%d] after Event [%d]",
+ in_state, p_sco->state, event);
+ #endif
}
-#endif
#if (BTM_WBS_INCLUDED == TRUE )
if (p_cn_scb)
@@ -1384,7 +1480,7 @@
if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
#endif
{
- APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+ APPL_TRACE_IMP("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
}
}
@@ -1575,9 +1671,19 @@
{
resp.rx_bw = BTM_64KBITS_RATE;
resp.tx_bw = BTM_64KBITS_RATE;
- resp.max_latency = 12;
+ if ((p_scb->peer_features & BTA_AG_PEER_FEAT_S4) &&
+ (p_scb->features & BTA_AG_PEER_FEAT_S4))
+ {
+ APPL_TRACE_WARNING("bta_ag_sco_conn_rsp with S4 link settings");
+ resp.max_latency = 12;
+ resp.retrans_effort = BTM_ESCO_RETRANS_QUALITY;
+ }
+ else
+ {
+ resp.max_latency = 10;
+ resp.retrans_effort = BTM_ESCO_RETRANS_POWER;
+ }
resp.voice_contfmt = 0x60;
- resp.retrans_effort = BTM_ESCO_RETRANS_QUALITY;
if (p_data->link_type == BTM_LINK_TYPE_SCO)
{
diff --git a/bta/ag/bta_ag_sdp.c b/bta/ag/bta_ag_sdp.c
index aa43c02..b25dd9c 100644
--- a/bta/ag/bta_ag_sdp.c
+++ b/bta/ag/bta_ag_sdp.c
@@ -23,6 +23,9 @@
*
******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
#include <string.h>
#include "bta_api.h"
#include "bta_sys.h"
@@ -32,6 +35,8 @@
#include "btm_api.h"
#include "bt_common.h"
#include "utl.h"
+#include "bt_utils.h"
+#include "device/include/interop_config.h"
/* Number of protocol elements in protocol element list. */
#define BTA_AG_NUM_PROTO_ELEMS 2
@@ -159,7 +164,7 @@
if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE)
{
profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
- version = BTA_HFP_VERSION;
+ version = HFP_VERSION_1_6;
}
else
{
@@ -322,7 +327,8 @@
}
else
{
- return result;
+ uuid = UUID_SERVCLASS_HEADSET_HS;
+ p_scb->peer_version = 0x0100; /* Default version */
}
/* loop through all records we found */
@@ -371,6 +377,16 @@
if (p_scb->peer_features == 0)
p_scb->peer_features = p_attr->attr_value.v.u16;
}
+
+ /* Remote supports 1.7, store it in the file */
+ if (p_scb->peer_version == HFP_VERSION_1_7)
+ {
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, p_scb->peer_addr);
+ interop_database_add_addr(INTEROP_HFP_1_7_BLACKLIST,
+ (bt_bdaddr_t *)&remote_bdaddr, 3);
+ }
+
}
else /* HSP */
{
@@ -445,10 +461,21 @@
num_uuid = 2;
}
}
- /* HSP acceptor; no discovery */
+ /* HSP acceptor; get features */
else
{
- return;
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+ num_attr = 4;
+
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */
+ if (p_scb->hsp_version >= HSP_VERSION_1_2)
+ {
+ uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+ num_uuid = 2;
+ }
}
/* allocate buffer for sdp database */
@@ -462,8 +489,11 @@
if(db_inited)
{
/*Service discovery not initiated */
+ /*Fix for below Klockwork issue
+ *Array 'bta_ag_sdp_cback_tbl' size is 3
+ *Possible attempt to access element -1,3..USHRT_MAX-1 of array 'bta_ag_sdp_cback_tbl' */
db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db,
- bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+ bta_ag_sdp_cback_tbl[(UINT16)(bta_ag_scb_to_idx(p_scb) - 1)]);
}
if(!db_inited)
diff --git a/bta/av/bta_av_aac.c b/bta/av/bta_av_aac.c
new file mode 100644
index 0000000..d358a6c
--- /dev/null
+++ b/bta/av/bta_av_aac.c
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#include "a2d_api.h"
+#include "a2d_aac.h"
+#include "bta_av_aac.h"
+#include "utl.h"
+
+/*******************************************************************************
+**
+** Function bta_av_aac_cfg_in_cap
+**
+** Description Checks if AAC codec config is allowed for given caps.
+** codec config bits are also checked for sanity
+**
+** Returns 0 if ok, nonzero if error.
+**
+*******************************************************************************/
+UINT8 bta_av_aac_cfg_in_cap(UINT8 *p_cfg, tA2D_AAC_CIE *p_cap)
+{
+ UINT8 status = 0;
+ tA2D_AAC_CIE cfg_cie;
+
+ /* parse configuration */
+ if ((status = A2D_ParsAacInfo(&cfg_cie, p_cfg, FALSE)) != 0)
+ {
+ APPL_TRACE_DEBUG("bta_av_aac_cfg_in_cap can't parse %d", status);
+ return status;
+ }
+
+ /* object type */
+ if ((cfg_cie.object_type & p_cap->object_type) == 0)
+ {
+ status = A2D_NS_OBJ_TYPE;
+ }
+ /* frequency */
+ else if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0)
+ {
+ status = A2D_NS_SAMP_FREQ;
+ }
+ /* channels */
+ else if ((cfg_cie.channels & p_cap->channels) == 0)
+ {
+ status = A2D_NS_CHANNEL;
+ }
+ /* bitrate */
+ else if ((cfg_cie.bit_rate & p_cap->bit_rate || cfg_cie.bit_rate < p_cap->bit_rate ) == 0)
+ {
+ status = A2D_NS_BIT_RATE;
+ }
+ APPL_TRACE_DEBUG("bta_av_aac_cfg_in_cap return %d", status);
+ return status;
+}
+
diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c
index 1e73fa6..92188d5 100644
--- a/bta/av/bta_av_aact.c
+++ b/bta/av/bta_av_aact.c
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2004-2012 Broadcom Corporation
*
@@ -33,6 +38,8 @@
#include "avdt_api.h"
#include "bta_av_int.h"
#include "bt_utils.h"
+#include "a2d_aptx.h"
+#include "a2d_aptx_hd.h"
#include "l2cdefs.h"
#include "l2c_api.h"
#include "osi/include/properties.h"
@@ -43,6 +50,7 @@
#include "bta_ar_api.h"
#endif
+extern BOOLEAN is_sniff_disabled;
/*****************************************************************************
** Constants
*****************************************************************************/
@@ -62,14 +70,20 @@
#define BTA_AV_RECONFIG_RETRY 6
#endif
+static const size_t SBC_MIN_BITPOOL_OFFSET = 5;
+static const size_t SBC_MAX_BITPOOL_OFFSET = 6;
+
+#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+static const size_t SBC_MAX_BITPOOL = 51;
+#else
+static const size_t SBC_MAX_BITPOOL = 53;
+#endif
+
/* ACL quota we are letting FW use for A2DP Offload Tx. */
#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
-static const size_t SBC_MAX_BITPOOL_OFFSET = 6;
-static const size_t SBC_MAX_BITPOOL = 53;
-
/* state machine states */
enum
{
@@ -94,7 +108,9 @@
bta_av_co_audio_start,
bta_av_co_audio_stop,
bta_av_co_audio_src_data_path,
- bta_av_co_audio_delay
+ bta_av_co_audio_delay,
+ bta_av_co_audio_is_offload_supported,
+ bta_av_co_audio_is_codec_supported
};
/* ssm action functions for audio stream */
@@ -252,10 +268,34 @@
***********************************************/
static UINT8 bta_av_get_scb_handle(tBTA_AV_SCB *p_scb, UINT8 local_sep)
{
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
- if ((p_scb->seps[i].tsep == local_sep) &&
- (p_scb->seps[i].codec_type == p_scb->codec_type))
- return (p_scb->seps[i].av_handle);
+ UINT8 xx =0;
+ for (xx = 0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if ((p_scb->seps[xx].tsep == local_sep) &&
+ (p_scb->seps[xx].codec_type == p_scb->codec_type))
+ {
+ if (p_scb->seps[xx].codec_type != A2D_NON_A2DP_MEDIA_CT)
+ return (p_scb->seps[xx].av_handle);
+ else {
+ UINT8 losc = p_scb->cfg.codec_info[0];
+ if (losc == A2D_APTX_CODEC_LEN)
+ {
+ tA2D_APTX_CIE aptx_config;
+ if (A2D_ParsAptxInfo(&aptx_config, p_scb->cfg.codec_info, FALSE) == A2D_SUCCESS)
+ if ((aptx_config.codecId == p_scb->seps[xx].codecId) &&
+ (aptx_config.vendorId == p_scb->seps[xx].vendorId))
+ return (p_scb->seps[xx].av_handle);
+ } else if (losc == A2D_APTX_HD_CODEC_LEN)
+ {
+ tA2D_APTX_HD_CIE aptx_config;
+ if (A2D_ParsAptx_hdInfo(&aptx_config, p_scb->cfg.codec_info, FALSE) == A2D_SUCCESS)
+ if ((aptx_config.codecId == p_scb->seps[xx].codecId) &&
+ (aptx_config.vendorId == p_scb->seps[xx].vendorId))
+ return (p_scb->seps[xx].av_handle);
+ } else
+ APPL_TRACE_DEBUG("%s: Invalid aptX Losc", __func__)
+ }
+ }
}
APPL_TRACE_DEBUG(" bta_av_get_scb_handle appropiate sep_type not found")
return 0; /* return invalid handle */
@@ -272,9 +312,11 @@
***********************************************/
static UINT8 bta_av_get_scb_sep_type(tBTA_AV_SCB *p_scb, UINT8 tavdt_handle)
{
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
- if (p_scb->seps[i].av_handle == tavdt_handle)
- return (p_scb->seps[i].tsep);
+ UINT8 xx =0;
+ for (xx = 0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if (p_scb->seps[xx].av_handle == tavdt_handle)
+ return (p_scb->seps[xx].tsep);
}
APPL_TRACE_DEBUG(" bta_av_get_scb_sep_type appropiate handle not found")
return 3; /* return invalid sep type */
@@ -396,7 +438,7 @@
/* we got a stream; get its capabilities */
if (p_scb->p_cap == NULL)
p_scb->p_cap = (tAVDT_CFG *)osi_malloc(sizeof(tAVDT_CFG));
- if (p_scb->avdt_version >= AVDT_VERSION_SYNC)
+ if ((p_scb->avdt_version >= AVDT_VERSION_SYNC) && (a2d_get_avdt_sdp_ver() >= AVDT_VERSION_SYNC) )
{
p_req = AVDT_GetAllCapReq;
}
@@ -404,11 +446,15 @@
{
p_req = AVDT_GetCapReq;
}
- (*p_req)(p_scb->peer_addr,
+ if ((*p_req)(p_scb->peer_addr,
p_scb->sep_info[i].seid,
- p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]);
- sent_cmd = TRUE;
- break;
+ p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]) == AVDT_SUCCESS)
+ {
+ sent_cmd = TRUE;
+ break;
+ }
+ else
+ APPL_TRACE_ERROR("bta_av_next_getcap command could not be sent because of resource constraint");
}
}
@@ -435,6 +481,8 @@
{
UINT16 sec_len = 0;
tBTA_AV_SCB *p_scb = bta_av_cb.p_scb[index];
+ int xx;
+ APPL_TRACE_VERBOSE("bta_av_proc_stream_evt on the index : %d", index);
if (p_data)
{
@@ -487,7 +535,11 @@
* If we already have a signalling connection with the bd_addr and the streaming
* SST is at INIT state, change it to INCOMING state to handle the signalling
* from the 2nd SEP. */
- if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
+ /* Fix for below klockwork issue
+ * Pointer 'bd_addr' checked for NULL at line 465 may be passed to function and
+ * may be dereferenced there by passing argument 1 to function 'bta_av_find_lcb' at line 500
+ * added another null check for below condition to get rid of kw error */
+ if (bd_addr != NULL && (bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
{
bta_av_set_scb_sst_incoming (p_scb);
@@ -495,11 +547,14 @@
* Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to
* incoming which we do it above.
* We also have to set the old p_scb state to init to be used later */
- for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
- if ((bta_av_cb.p_scb[i]) && (i != index)) {
- if (bta_av_cb.p_scb[i]->state == BTA_AV_INCOMING_SST) {
- bta_av_cb.p_scb[i]->state = BTA_AV_INIT_SST;
- bta_av_cb.p_scb[i]->coll_mask = 0;
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if ((bta_av_cb.p_scb[xx]) && (xx != index))
+ {
+ if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST)
+ {
+ bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+ bta_av_cb.p_scb[xx]->coll_mask = 0;
break;
}
}
@@ -556,11 +611,14 @@
/* coverity[var_deref_model] */
/* false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event
* these 2 events always have associated p_data */
- if (p_data)
+/* Fix for below klockwork issue
+ * Pointer 'bd_addr' checked for NULL at line 465 may be passed to function and may be dereferenced there
+ * by passing argument 2 to function 'bta_av_conn_cback'. */
+ if (p_data && bd_addr)
{
bta_av_conn_cback(handle, bd_addr, event, p_data);
}
- else
+ else if (!p_data)
{
APPL_TRACE_ERROR("%s: p_data is null", __func__);
}
@@ -727,6 +785,9 @@
p_msg->hdr.layer_specific = bta_av_cb.handle;
bta_sys_sendmsg(p_msg);
+ if (!found)
+ APPL_TRACE_ERROR ("bta_av_a2d_sdp_cback, SDP record not found");
+ bta_sys_conn_close(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
}
/*******************************************************************************
@@ -740,16 +801,56 @@
*******************************************************************************/
static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb, UINT8 avdt_handle)
{
+ int xx;
APPL_TRACE_DEBUG("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type);
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
APPL_TRACE_DEBUG("av_handle: %d codec_type: %d",
- p_scb->seps[i].av_handle, p_scb->seps[i].codec_type);
- if((p_scb->seps[i].av_handle && p_scb->codec_type == p_scb->seps[i].codec_type)
- && (p_scb->seps[i].av_handle == avdt_handle))
+ p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type);
+ if((p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type)
+ && (p_scb->seps[xx].av_handle == avdt_handle))
{
- p_scb->sep_idx = i;
- p_scb->avdt_handle = p_scb->seps[i].av_handle;
- break;
+ if (p_scb->seps[xx].codec_type != A2D_NON_A2DP_MEDIA_CT)
+ {
+ p_scb->sep_idx = xx;
+ p_scb->avdt_handle = p_scb->seps[xx].av_handle;
+ break;
+ }
+ else {
+ UINT8 losc = p_scb->cfg.codec_info[0];
+ if (losc == A2D_APTX_CODEC_LEN)
+ {
+ tA2D_APTX_CIE aptx_config;
+ if (A2D_ParsAptxInfo(&aptx_config, p_scb->cfg.codec_info, FALSE) == A2D_SUCCESS) {
+ APPL_TRACE_DEBUG("%s vendorId: %x codecId: %x", __func__, p_scb->seps[xx].vendorId, p_scb->seps[xx].codecId);
+ if ((aptx_config.codecId == p_scb->seps[xx].codecId) &&
+ (aptx_config.vendorId == p_scb->seps[xx].vendorId)) {
+ APPL_TRACE_DEBUG("%s p_scb->sep_idx: %d", __func__, p_scb->sep_idx);
+ p_scb->sep_idx = xx;
+ p_scb->avdt_handle = p_scb->seps[xx].av_handle;
+ APPL_TRACE_DEBUG("%s p_scb->sep_idx: %d", __func__, p_scb->sep_idx);
+ APPL_TRACE_DEBUG("%s p_scb->avdt_handle: %d", __func__, p_scb->avdt_handle);
+ break;
+ }
+ }
+ } else if (losc == A2D_APTX_HD_CODEC_LEN)
+ {
+ tA2D_APTX_HD_CIE aptx_config;
+ if (A2D_ParsAptx_hdInfo(&aptx_config, p_scb->cfg.codec_info, FALSE) == A2D_SUCCESS) {
+ APPL_TRACE_DEBUG("%s vendorId: %x codecId: %x", __func__, p_scb->seps[xx].vendorId, p_scb->seps[xx].codecId);
+ if ((aptx_config.codecId == p_scb->seps[xx].codecId) &&
+ (aptx_config.vendorId == p_scb->seps[xx].vendorId)) {
+ APPL_TRACE_DEBUG("%s p_scb->sep_idx: %d", __func__, p_scb->sep_idx);
+ p_scb->sep_idx = xx;
+ p_scb->avdt_handle = p_scb->seps[xx].av_handle;
+ APPL_TRACE_DEBUG("%s p_scb->sep_idx: %d", __func__, p_scb->sep_idx);
+ APPL_TRACE_DEBUG("%s p_scb->avdt_handle: %d", __func__, p_scb->avdt_handle);
+ break;
+ }
+ }
+ } else
+ APPL_TRACE_DEBUG("%s: Invalid aptX Losc", __func__)
+ }
}
}
}
@@ -824,11 +925,32 @@
BOOLEAN initiator = FALSE;
tBTA_AV_START start;
tBTA_AV_OPEN av_open;
+ tBTA_AV_ROLE_CHANGED role_changed;
+
+ UINT8 cur_role = BTM_ROLE_UNDEFINED;
APPL_TRACE_DEBUG("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role);
if (p_scb->role & BTA_AV_ROLE_START_INT)
initiator = TRUE;
+ /* Multicast: update BTIF about role switch
+ * If role switch succeeded, we need to update multicast state
+ * from BTIF.
+ */
+ if (p_data->role_res.hci_status == HCI_SUCCESS)
+ {
+ APPL_TRACE_DEBUG("bta_av_role_res: Master update upper layer");
+
+ bdcpy(role_changed.bd_addr, p_scb->peer_addr);
+ role_changed.hndl = p_scb->hndl;
+
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ role_changed.new_role = cur_role;
+ }
+ (*bta_av_cb.p_cback)(BTA_AV_ROLE_CHANGED_EVT, (tBTA_AV *)&role_changed);
+ }
+
if (p_scb->q_tag == BTA_AV_Q_TAG_START)
{
if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED)
@@ -837,7 +959,7 @@
if (p_data->role_res.hci_status != HCI_SUCCESS)
{
p_scb->role &= ~BTA_AV_ROLE_START_INT;
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
/* start failed because of role switch. */
start.chnl = p_scb->chnl;
start.status = BTA_AV_FAIL_ROLE;
@@ -866,6 +988,11 @@
bdcpy(av_open.bd_addr, p_scb->peer_addr);
av_open.chnl = p_scb->chnl;
av_open.hndl = p_scb->hndl;
+ // update Master/Slave Role for open event
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ av_open.role = cur_role;
+ }
start.status = BTA_AV_FAIL_ROLE;
if(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC )
av_open.sep = AVDT_TSEP_SNK;
@@ -996,7 +1123,7 @@
p_scb->sec_mask = p_data->api_open.sec_mask;
p_scb->use_rc = p_data->api_open.use_rc;
- bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if (p_scb->skip_sdp == TRUE)
{
@@ -1010,30 +1137,32 @@
bta_av_a2d_sdp_cback(TRUE, &a2d_ser);
return;
}
+ else
+ {
+ /* only one A2D find service is active at a time */
+ bta_av_cb.handle = p_scb->hndl;
- /* only one A2D find service is active at a time */
- bta_av_cb.handle = p_scb->hndl;
+ /* set up parameters */
+ db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+ db_params.num_attr = 3;
+ db_params.p_attrs = attr_list;
+ p_scb->uuid_int = p_data->api_open.uuid;
+ p_scb->sdp_discovery_started = TRUE;
+ if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+ sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+ else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+ sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
- /* set up parameters */
- db_params.db_len = BTA_AV_DISC_BUF_SIZE;
- db_params.num_attr = 3;
- db_params.p_attrs = attr_list;
- p_scb->uuid_int = p_data->api_open.uuid;
- p_scb->sdp_discovery_started = TRUE;
- if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
- sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
- else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
- sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
-
- APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
+ APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
p_scb->uuid_int, sdp_uuid);
- if (A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
+ if (A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
bta_av_a2d_sdp_cback) == A2D_SUCCESS)
- return;
+ return;
- /* when the code reaches here, either the DB is NULL
- * or A2D_FindService is not successful */
- bta_av_a2d_sdp_cback(FALSE, NULL);
+ /* when the code reaches here, either the DB is NULL
+ * or A2D_FindService is not successful */
+ bta_av_a2d_sdp_cback(FALSE, NULL);
+ }
}
/*******************************************************************************
@@ -1048,7 +1177,8 @@
void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
{
tBTA_AV_CONN_CHG msg;
- UINT8 role = BTA_AV_ROLE_AD_INT;
+ int xx;
+ UINT8 role = BTA_AV_ROLE_AD_INT;
UNUSED(p_data);
APPL_TRACE_DEBUG("bta_av_cleanup");
@@ -1064,6 +1194,7 @@
/* if de-registering shut everything down */
msg.hdr.layer_specific = p_scb->hndl;
p_scb->started = FALSE;
+ p_scb->suspend_local_sent = FALSE;
p_scb->cong = FALSE;
p_scb->role = role;
p_scb->cur_psc_mask = 0;
@@ -1078,15 +1209,18 @@
(*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
}
p_scb->offload_start_pending = FALSE;
+ p_scb->skip_sdp = FALSE;
+ p_scb->coll_mask = 0;
p_scb->skip_sdp = FALSE;
if (p_scb->deregistring)
{
/* remove stream */
- for (int i = 0; i < BTA_AV_MAX_SEPS; i++) {
- if (p_scb->seps[i].av_handle)
- AVDT_RemoveStream(p_scb->seps[i].av_handle);
- p_scb->seps[i].av_handle = 0;
+ for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
+ {
+ if(p_scb->seps[xx].av_handle)
+ AVDT_RemoveStream(p_scb->seps[xx].av_handle);
+ p_scb->seps[xx].av_handle = 0;
}
bta_av_dereg_comp((tBTA_AV_DATA *) &msg);
@@ -1140,8 +1274,17 @@
p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX];
bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
- /* Clear collision mask */
- p_scb->coll_mask = 0;
+ if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED)
+ {
+ APPL_TRACE_DEBUG(" bta_av_config_ind ReSetting collision mask ");
+ /* Clear collision mask */
+ p_scb->coll_mask = 0;
+ }
+ else
+ {
+ APPL_TRACE_WARNING(" bta_av_config_ind config_ind called before Open");
+ p_scb->coll_mask |= BTA_AV_COLL_SETCONFIG_IND;
+ }
alarm_cancel(bta_av_cb.accept_signalling_timer);
/* if no codec parameters in configuration, fail */
@@ -1325,22 +1468,13 @@
p_scb->avdt_version = AVDT_VERSION_SYNC;
- if (p_scb->codec_type == BTA_AV_CODEC_SBC || num > 1)
- {
- /* if SBC is used by the SNK as INT, discover req is not sent in bta_av_config_ind.
- * call disc_res now */
- /* this is called in A2DP SRC path only, In case of SINK we don't need it */
- if (local_sep == AVDT_TSEP_SRC)
- p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr,
- UUID_SERVCLASS_AUDIO_SOURCE);
- }
- else
- {
- /* we do not know the peer device and it is using non-SBC codec
- * we need to know all the SEPs on SNK */
- bta_av_discover_req(p_scb, NULL);
- return;
- }
+ /* For any codec used by the SNK as INT, discover req is not sent in bta_av_config_ind.
+ * This is done since we saw an IOT issue with APTX codec. Thus, we now take same
+ * path for all codecs as for SBC. call disc_res now */
+ /* this is called in A2DP SRC path only, In case of SINK we don't need it */
+ if (local_sep == AVDT_TSEP_SRC)
+ p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr,
+ UUID_SERVCLASS_AUDIO_SOURCE);
for (i = 1; i < num; i++)
{
@@ -1358,6 +1492,8 @@
/* Make sure UUID has been initialized... */
if (p_scb->uuid_int == 0)
p_scb->uuid_int = p_scb->open_api.uuid;
+ if (p_scb->uuid_int == 0)
+ p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE;
bta_av_next_getcap(p_scb, p_data);
}
}
@@ -1378,6 +1514,7 @@
tBTA_AV_OPEN open;
UINT8 *p;
UINT16 mtu;
+ UINT8 cur_role;
msg.hdr.layer_specific = p_scb->hndl;
msg.is_up = TRUE;
@@ -1387,7 +1524,7 @@
/* set the congestion flag, so AV would not send media packets by accident */
p_scb->cong = TRUE;
p_scb->offload_start_pending = FALSE;
-
+ p_scb->suspend_local_sent = FALSE;
p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
@@ -1396,17 +1533,17 @@
if(mtu == 0 || mtu > p_scb->stream_mtu)
mtu = p_scb->stream_mtu;
- /* Set the media channel as medium priority */
- L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
+ /* Set the media channel as high priority */
+ L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_HIGH);
L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE);
- bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
p_scb->l2c_bufs = 0;
p_scb->p_cos->open(p_scb->hndl,
p_scb->codec_type, p_scb->cfg.codec_info, mtu);
-
+ bta_av_cb.codec_type = p_scb->codec_type;
{
/* TODO check if other audio channel is open.
* If yes, check if reconfig is needed
@@ -1423,6 +1560,14 @@
open.status = BTA_AV_SUCCESS;
open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ open.stream_chnl_id = AVDT_GetStreamingDestChannelId(p_scb->l2c_cid);
+#endif
+ // update Master/Slave Role for start
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ open.role = cur_role;
+ }
if( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr)))
{
if(HCI_EDR_ACL_2MPS_SUPPORTED(p))
@@ -1454,6 +1599,23 @@
AVDT_AbortReq(p_scb->avdt_handle);
}
}
+/*******************************************************************************
+**
+** Function bta_av_get_codec_type
+**
+** Description Returns the codec_type from the most recently used scb
+**
+** Returns bta_av_cb.codec_type
+**
+*******************************************************************************/
+UINT8 bta_av_get_codec_type(tBTA_AV_HNDL hndl)
+{
+ APPL_TRACE_DEBUG("%s: hdl = %x", __func__, hndl);
+ tBTA_AV_SCB *p_scb = bta_av_hndl_to_scb(hndl);
+ bta_av_cb.codec_type = p_scb->codec_type;
+ APPL_TRACE_DEBUG("%s [bta_av_cb.codec_type] %x", __func__, bta_av_cb.codec_type);
+ return bta_av_cb.codec_type;
+}
/*******************************************************************************
**
@@ -1536,6 +1698,7 @@
/* close stream */
p_scb->started = FALSE;
+ p_scb->suspend_local_sent = FALSE;
/* drop the buffers queued in L2CAP */
L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
@@ -1560,6 +1723,7 @@
*******************************************************************************/
void bta_av_connect_req(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
{
+ UINT16 result;
UNUSED(p_data);
p_scb->sdp_discovery_started = FALSE;
@@ -1574,7 +1738,17 @@
return;
}
- AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+ result = AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
+ if(result != AVDT_SUCCESS)
+ {
+ /* AVDT connect failed because of resource issue
+ * trigger the SDP fail event to enable the cleanup
+ * and set the stream to proper state.
+ */
+ p_scb->open_status = BTA_AV_FAIL_RESOURCES;
+ APPL_TRACE_ERROR("bta_av_connect_req: AVDT_ConnectReq failed: %d", result);
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
+ }
}
/*******************************************************************************
@@ -1591,7 +1765,7 @@
if (!p_scb->open_status)
p_scb->open_status = BTA_AV_FAIL_SDP;
- p_scb->sdp_discovery_started = FALSE;
+ p_scb->sdp_discovery_started = TRUE;
bta_av_str_closed(p_scb, p_data);
}
@@ -1805,6 +1979,7 @@
tBTA_AV_SCB * p_opened_scb = NULL;
UINT8 idx;
tBTA_AV_OPEN open;
+ UINT8 cur_role;
APPL_TRACE_DEBUG("bta_av_open_failed");
p_scb->open_status = BTA_AV_FAIL_STREAM;
@@ -1829,6 +2004,15 @@
open.status = BTA_AV_FAIL_GET_CAP;
open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ open.stream_chnl_id = 0;
+#endif
+ // update Master/Slave Role for open event
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ open.role = cur_role;
+ }
+
/* set the state back to initial state */
bta_av_set_scb_sst_init(p_scb);
@@ -1924,6 +2108,15 @@
cfg.codec_info[SBC_MAX_BITPOOL_OFFSET] = SBC_MAX_BITPOOL;
}
+ if ((uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) &&
+ (cfg.codec_info[SBC_MIN_BITPOOL_OFFSET] > cfg.codec_info[SBC_MAX_BITPOOL_OFFSET]))
+ {
+ APPL_TRACE_WARNING("%s min bitpool value received for SBC is more than DUT supported Max bitpool"
+ "Clamping the max bitpool configuration further from %d to %d.", __func__,
+ cfg.codec_info[SBC_MAX_BITPOOL_OFFSET], cfg.codec_info[SBC_MIN_BITPOOL_OFFSET]);
+ cfg.codec_info[SBC_MAX_BITPOOL_OFFSET] = cfg.codec_info[SBC_MIN_BITPOOL_OFFSET];
+ }
+
/* open the stream */
AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
@@ -1980,8 +2173,11 @@
UNUSED(p_data);
/* send avdtp discover request */
-
- AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
+ if (AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]) != AVDT_SUCCESS)
+ {
+ APPL_TRACE_ERROR("bta_av_discover_req command could not be sent because of resource constraint");
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+ }
}
/*******************************************************************************
@@ -2034,7 +2230,7 @@
if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0))
{
p_scb->role |= BTA_AV_ROLE_START_INT;
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_busy(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
AVDT_StartReq(&p_scb->avdt_handle, 1);
}
@@ -2044,7 +2240,9 @@
if ( p_scb->wait == 0 ) {
if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
notify_start_failed(p_scb);
- } else {
+ }
+ else
+ {
bta_av_start_ok(p_scb, NULL);
}
}
@@ -2069,10 +2267,13 @@
BT_HDR *p_buf;
UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+ if (is_sniff_disabled == true)
+ policy = 0;
+
APPL_TRACE_ERROR("bta_av_str_stopped:audio_open_cnt=%d, p_data %x",
bta_av_cb.audio_open_cnt, p_data);
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
@@ -2114,16 +2315,18 @@
if (p_data && p_data->api_stop.suspend)
{
- APPL_TRACE_DEBUG("suspending: %d, sup:%d", start, p_scb->suspend_sup);
- if ((start) && (p_scb->suspend_sup))
+ APPL_TRACE_DEBUG("suspending: %d, sup:%d, suspend_local_sent = %d",
+ start, p_scb->suspend_sup,p_scb->suspend_local_sent);
+ if ((start) && (p_scb->suspend_sup) && (!p_scb->suspend_local_sent))
{
+ p_scb->suspend_local_sent = TRUE;
sus_evt = FALSE;
p_scb->l2c_bufs = 0;
AVDT_SuspendReq(&p_scb->avdt_handle, 1);
}
/* send SUSPEND_EVT event only if not in reconfiguring state and sus_evt is TRUE*/
- if ((sus_evt)&&(p_scb->state != BTA_AV_RCFG_SST))
+ if ((sus_evt) && ((p_scb->suspend_local_sent) || (p_scb->state != BTA_AV_RCFG_SST)))
{
suspend_rsp.status = BTA_AV_SUCCESS;
suspend_rsp.initiator = TRUE;
@@ -2159,6 +2362,7 @@
{
tAVDT_CFG *p_cfg;
tBTA_AV_API_STOP stop;
+ tBTA_AV_RECONFIG evt;
tBTA_AV_API_RCFG *p_rcfg = &p_data->api_reconfig;
APPL_TRACE_DEBUG("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)",
@@ -2169,7 +2373,19 @@
/* store the new configuration in control block */
if (p_scb->p_cap == NULL)
p_scb->p_cap = (tAVDT_CFG *)osi_malloc(sizeof(tAVDT_CFG));
- p_cfg = p_scb->p_cap;
+ if((p_cfg = p_scb->p_cap) == NULL)
+ {
+ /* report failure */
+ evt.status = BTA_AV_FAIL_RESOURCES;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
+
+ /* this event is not possible in this state.
+ * use it to bring the SSM back to open state */
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL);
+ return;
+ }
alarm_cancel(p_scb->avrc_ct_timer);
@@ -2334,7 +2550,9 @@
UINT8 new_role = p_scb->role;
BT_HDR hdr;
UINT8 policy = HCI_ENABLE_SNIFF_MODE;
- UINT8 cur_role;
+ /* Fix for below klockwork issue
+ * 'cur_role' might be used uninitialized in this function */
+ UINT8 cur_role = BTM_ROLE_UNDEFINED;
APPL_TRACE_DEBUG("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role);
@@ -2368,7 +2586,7 @@
p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
if (p_data->hdr.offset == BTA_AV_RS_FAIL)
{
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
start.chnl = p_scb->chnl;
start.status = BTA_AV_FAIL_ROLE;
start.hndl = p_scb->hndl;
@@ -2407,9 +2625,9 @@
}
/* tell role manager to check M/S role */
- bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_open(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_busy(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if(p_scb->media_type == AVDT_MEDIA_AUDIO)
{
@@ -2435,7 +2653,24 @@
}
else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT))
{
- suspend = TRUE;
+
+ if (bta_av_is_multicast_enabled() == TRUE &&
+ (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ && (cur_role == BTM_ROLE_MASTER))
+ {
+ /* If playing on other stream, dont suspend this. */
+ if (bta_av_chk_start(p_scb))
+ {
+ suspend = FALSE;
+ APPL_TRACE_DEBUG("cur_role: %d suspend: %d", cur_role, suspend);
+ }
+ }
+ else
+ {
+ suspend = TRUE;
+ APPL_TRACE_DEBUG("cur_role: %d suspend: %d", cur_role, suspend);
+
+ }
}
if (!suspend)
@@ -2476,6 +2711,11 @@
start.chnl = p_scb->chnl;
start.status = BTA_AV_SUCCESS;
start.hndl = p_scb->hndl;
+ // update Master/Slave Role for start event
+ if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS)
+ {
+ start.role = cur_role;
+ }
(*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
if(suspend)
@@ -2507,11 +2747,16 @@
if(p_scb->started == FALSE && p_scb->co_started == FALSE)
{
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
notify_start_failed(p_scb);
}
- bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE|HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr);
+ // if sniff is disabled in hf client, don't enable it again
+ if (is_sniff_disabled == true)
+ bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scb->peer_addr);
+ else
+ bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE|HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr);
+
p_scb->sco_suspend = FALSE;
}
@@ -2531,6 +2776,9 @@
UINT16 mtu;
UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+ if (is_sniff_disabled == true)
+ policy = 0;
+
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
@@ -2556,7 +2804,7 @@
event = BTA_AV_OPEN_EVT;
p_scb->open_status = BTA_AV_SUCCESS;
- bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_close(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
bta_av_cleanup(p_scb, p_data);
(*bta_av_cb.p_cback)(event, &data);
}
@@ -2577,7 +2825,7 @@
data.close.hndl = p_scb->hndl;
event = BTA_AV_CLOSE_EVT;
- bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_sys_conn_close(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
bta_av_cleanup(p_scb, p_data);
(*bta_av_cb.p_cback)(event, &data);
}
@@ -2615,9 +2863,12 @@
tBTA_AV_SUSPEND suspend_rsp;
UINT8 err_code = p_data->str_msg.msg.hdr.err_code;
UINT8 policy = HCI_ENABLE_SNIFF_MODE;
+ p_scb->suspend_local_sent = FALSE;
+ if (is_sniff_disabled == true)
+ policy = 0;
- APPL_TRACE_DEBUG ("bta_av_suspend_cfm:audio_open_cnt = %d, err_code = %d",
- bta_av_cb.audio_open_cnt, err_code);
+ APPL_TRACE_DEBUG ("%s:audio_open_cnt = %d, err_code = %d, scb_started = %d",
+ __func__,bta_av_cb.audio_open_cnt,err_code,p_scb->started);
if (p_scb->started == FALSE)
{
@@ -2656,9 +2907,10 @@
p_scb->cong = FALSE;
}
- bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ bta_sys_idle(BTA_ID_AV, p_scb->hdi, p_scb->peer_addr);
if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+
bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
/* in case that we received suspend_ind, we may need to call co_stop here */
@@ -2835,7 +3087,7 @@
{
UINT8 err_code = p_data->str_msg.msg.hdr.err_code;
tBTA_AV_RECONFIG evt;
-
+ p_scb->suspend_local_sent = FALSE;
p_scb->started = FALSE;
p_scb->cong = FALSE;
if (err_code)
@@ -2890,7 +3142,7 @@
*/
if (err_code)
{
- APPL_TRACE_ERROR("reconfig rejected, try close");
+ APPL_TRACE_ERROR("reconfig rejected, try close with error code = %d", err_code);
/* Disable reconfiguration feature only with explicit rejection(not with timeout) */
if (err_code != AVDT_ERR_TIMEOUT)
{
@@ -2923,7 +3175,7 @@
{
UNUSED(p_data);
- APPL_TRACE_DEBUG("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks);
+ APPL_TRACE_DEBUG("%s: bta_av_rcfg_open, num_disc_snks = %d", __func__, p_scb->num_disc_snks);
if (p_scb->num_disc_snks == 0)
{
@@ -2940,7 +3192,7 @@
/* we may choose to use a different SEP at reconfig.
* adjust the sep_idx now */
bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
-
+ bta_av_cb.codec_type = p_scb->codec_type;
/* open the stream with the new config */
p_scb->sep_info_idx = p_scb->rcfg_idx;
AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
@@ -2983,7 +3235,9 @@
BOOLEAN new_started = FALSE;
UNUSED(p_data);
- if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2))
+ APPL_TRACE_DEBUG("%s\n", __func__);
+ if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2) &&
+ bta_av_is_multicast_enabled())
{
/* more than one audio channel is connected */
if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT))
@@ -3098,8 +3352,22 @@
*******************************************************************************/
void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
{
+ if (!p_scb)
+ {
+ APPL_TRACE_WARNING("scb is NULL, bailing out!");
+ return;
+ }
+
memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+ if (p_scb->coll_mask & BTA_AV_COLL_SETCONFIG_IND)
+ {
+ APPL_TRACE_WARNING(" SetConfig is already called, timer stopped");
+ /* make mask 0, timer shld have already been closed in setconfig_ind */
+ p_scb->coll_mask = 0;
+ return;
+ }
+
if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
{
p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
@@ -3111,6 +3379,7 @@
{
/* SNK did not start signalling, API was called N seconds timeout. */
/* We need to switch to INIT state and start opening connection. */
+ APPL_TRACE_ERROR(" bta_av_open_at_inc ReSetting collision mask ");
p_scb->coll_mask = 0;
bta_av_set_scb_sst_init(p_scb);
diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
old mode 100644
new mode 100755
index 7154865..1a4148c
--- a/bta/av/bta_av_act.c
+++ b/bta/av/bta_av_act.c
@@ -29,6 +29,9 @@
#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "avdt_api.h"
@@ -37,10 +40,14 @@
#include "l2c_api.h"
#include "log/log.h"
#include "osi/include/list.h"
+#include "bt_utils.h"
+#include <errno.h>
+
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
#include "utl.h"
+#include "device/include/interop.h"
#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
@@ -60,9 +67,36 @@
#define BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS (2 * 1000) /* 2 seconds */
#endif
+#ifndef AVRC_CONNECT_RETRY_DELAY_MS
+#define AVRC_CONNECT_RETRY_DELAY_MS 2000
+#endif
+
extern fixed_queue_t *btu_bta_alarm_queue;
static void bta_av_accept_signalling_timer_cback(void *data);
+struct blacklist_entry
+{
+ int ver;
+ char addr[3];
+};
+
+
+#ifndef AVRC_MIN_META_CMD_LEN
+#define AVRC_MIN_META_CMD_LEN 20
+#endif
+
+#define AVRC_L2CAP_MIN_CONN_FAILURE_CODE 2 /*same as L2CAP_CONN_NO_PSM*/
+
+/* state machine states */
+enum
+{
+ BTA_AV_INIT_SST,
+ BTA_AV_INCOMING_SST,
+ BTA_AV_OPENING_SST,
+ BTA_AV_OPEN_SST,
+ BTA_AV_RCFG_SST,
+ BTA_AV_CLOSING_SST
+};
/*******************************************************************************
**
@@ -216,13 +250,24 @@
static void bta_av_rc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, BD_ADDR peer_addr)
{
UINT16 msg_event = 0;
- UNUSED(result);
#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE)
APPL_TRACE_EVENT("rc_ctrl handle: %d event=0x%x", handle, event);
#else
- APPL_TRACE_EVENT("bta_av_rc_ctrl_cback handle: %d event=0x%x", handle, event);
+ BTIF_TRACE_IMP("bta_av_rc_ctrl_cback handle: %d event=0x%x", handle, event);
#endif
+ if (((event == AVRC_OPEN_IND_EVT) || (event == AVRC_CLOSE_IND_EVT))
+ && (result >= AVRC_L2CAP_MIN_CONN_FAILURE_CODE))
+ {
+ APPL_TRACE_WARNING("AVRCP connection encountered error=%x", result);
+ tBTA_AV_RC_COLLISSION_DETECTED *p_msg =
+ (tBTA_AV_RC_COLLISSION_DETECTED *)osi_malloc(sizeof(tBTA_AV_RC_COLLISSION_DETECTED));
+ p_msg->hdr.event = BTA_AV_RC_COLLISSION_DETECTED_EVT;
+ p_msg->handle = handle;
+ if (peer_addr)
+ bdcpy(p_msg->peer_addr, peer_addr);
+ bta_sys_sendmsg(p_msg);
+ }
if (event == AVRC_OPEN_IND_EVT)
{
/* save handle of opened connection
@@ -260,7 +305,7 @@
UINT8 *p_data_src = NULL;
UINT16 data_len = 0;
- APPL_TRACE_DEBUG("%s handle: %u opcode=0x%x", __func__, handle, opcode);
+ BTIF_TRACE_IMP("%s handle: %u opcode=0x%x", __func__, handle, opcode);
/* Determine the size of the buffer we need */
if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) {
@@ -269,8 +314,13 @@
} else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) {
p_data_src = p_msg->pass.p_pass_data;
data_len = (UINT16) p_msg->pass.pass_len;
+ } else if (opcode == AVRC_OP_BROWSE && p_msg->browse.p_browse_data != NULL) {
+ APPL_TRACE_EVENT("bta_av_rc_msg_cback Browse Data");
+ p_data_src = p_msg->browse.p_browse_data;
+ data_len = (UINT16) p_msg->browse.browse_len;
}
+
/* Create a copy of the message */
tBTA_AV_RC_MSG *p_buf =
(tBTA_AV_RC_MSG *)osi_malloc(sizeof(tBTA_AV_RC_MSG) + data_len);
@@ -287,6 +337,8 @@
p_buf->msg.vendor.p_vendor_data = p_data_dst;
else if (opcode == AVRC_OP_PASS_THRU)
p_buf->msg.pass.p_pass_data = p_data_dst;
+ else if (opcode == AVRC_OP_BROWSE)
+ p_buf->msg.browse.p_browse_data = p_data_dst;
}
bta_sys_sendmsg(p_buf);
@@ -306,13 +358,14 @@
tAVRC_CONN_CB ccb;
BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any;
UINT8 status = BTA_AV_RC_ROLE_ACP;
- tBTA_AV_SCB *p_scb = p_cb->p_scb[shdl - 1];
+ tBTA_AV_SCB *p_scb;
int i;
UINT8 rc_handle;
tBTA_AV_RCB *p_rcb;
if (role == AVCT_INT)
{
+ p_scb = p_cb->p_scb[shdl - 1];
bda = p_scb->peer_addr;
status = BTA_AV_RC_ROLE_INT;
}
@@ -353,9 +406,9 @@
/* this LIDX is reserved for the AVRCP ACP connection */
p_cb->rc_acp_handle = p_rcb->handle;
p_cb->rc_acp_idx = (i + 1);
- APPL_TRACE_DEBUG("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ APPL_TRACE_IMP("rc_acp_handle: %d idx: %d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
}
- APPL_TRACE_DEBUG("create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x",
+ APPL_TRACE_IMP("bta_av_rc_create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x",
i, role, shdl, p_rcb->handle, lidx, p_rcb->status);
return rc_handle;
@@ -569,12 +622,16 @@
if (rc_open.peer_features == 0)
{
/* we have not done SDP on peer RC capabilities.
- * peer must have initiated the RC connection
- * We Don't have SDP records of Peer, so we by
- * default will take values depending upon registered
- * features */
- if (p_cb->features & BTA_AV_FEAT_RCTG)
+ * peer must have initiated the RC connection */
+ /*To update default features based on the local features we support*/
+ if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ {
rc_open.peer_features |= BTA_AV_FEAT_RCCT;
+ }
+ if (bta_av_cb.features & BTA_AV_FEAT_RCCT)
+ {
+ rc_open.peer_features |= BTA_AV_FEAT_RCTG;
+ }
bta_av_rc_disc(disc);
}
(*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
@@ -673,7 +730,9 @@
(!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT)) )
{
p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
- if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+ /* Fix for below Klockwork Issue
+ * Array 'avrc_cb.fcb' of size 5 may use index value(s) 0..254 */
+ if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->handle < AVCT_NUM_CONN)) {
AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label,
p_data->api_meta_rsp.rsp_code,
p_data->api_meta_rsp.p_pkt);
@@ -769,15 +828,25 @@
tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg, UINT8 *p_ctype)
{
tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
- UINT8 u8, pdu, *p;
+ UINT8 u8, pdu, *p, i;
UINT16 u16;
tAVRC_MSG_VENDOR *p_vendor = &p_msg->msg.vendor;
+ BD_ADDR addr;
+ BOOLEAN is_dev_avrcpv_blacklisted = FALSE;
#if (AVRC_METADATA_INCLUDED == TRUE)
pdu = *(p_vendor->p_vendor_data);
p_rc_rsp->pdu = pdu;
*p_ctype = AVRC_RSP_REJ;
+ /* Check for valid Meta Length, AVRCP minimum Meta command length 20 */
+ if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE)
+ {
+ /* reject it */
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
+ APPL_TRACE_ERROR("Bailing out: Invalid meta-command length: %d", p_vendor->vendor_len);
+ return 0;
+ }
/* Metadata messages only use PANEL sub-unit type */
if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL)
{
@@ -829,8 +898,31 @@
{
*p_ctype = AVRC_RSP_IMPL_STBL;
p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
- memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids,
- p_bta_av_cfg->num_evt_ids);
+ /* DUT has blacklisted few remote dev for Avrcp Version hence
+ * respose for event supported should not have AVRCP 1.5/1.4
+ * version events
+ */
+ if (avct_get_peer_addr_by_ccb(p_msg->handle, addr) == TRUE)
+ {
+ is_dev_avrcpv_blacklisted = SDP_Dev_Blacklisted_For_Avrcp15(addr);
+ BTIF_TRACE_ERROR("Blacklist for AVRCP1.5 = %d", is_dev_avrcpv_blacklisted);
+ }
+ BTIF_TRACE_DEBUG("Blacklist for AVRCP1.5 = %d", is_dev_avrcpv_blacklisted);
+ if (is_dev_avrcpv_blacklisted == TRUE)
+ {
+ for (i = 0; i <= p_bta_av_cfg->num_evt_ids; ++i)
+ {
+ if (p_bta_av_cfg->p_meta_evt_ids[i] == AVRC_EVT_AVAL_PLAYERS_CHANGE)
+ break;
+ }
+ p_rc_rsp->get_caps.count = i;
+ memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids, i);
+ }
+ else
+ {
+ memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids,
+ p_bta_av_cfg->num_evt_ids);
+ }
}
else
{
@@ -851,7 +943,7 @@
}
}
#else
- APPL_TRACE_DEBUG("AVRCP 1.3 Metadata not supporteed. Reject command.");
+ BTIF_TRACE_IMP("AVRCP 1.3 Metadata not supporteed. Reject command.");
/* reject invalid message without reporting to app */
evt = 0;
p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
@@ -860,6 +952,40 @@
return evt;
}
+/*****************************************************************************
+**
+** Function bta_av_proc_browse_cmd
+**
+** Description Process and AVRCP browse command from the peer
+**
+** Returns status
+**
+****************************************************************************/
+tBTA_AV_EVT bta_av_proc_browse_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg)
+{
+ tBTA_AV_EVT evt = BTA_AV_BROWSE_MSG_EVT;
+ UINT8 pdu;
+ tAVRC_MSG_BROWSE *p_browse = &p_msg->msg.browse;
+
+ pdu = p_browse->p_browse_data[0];
+ APPL_TRACE_DEBUG("bta_av_proc_browse_cmd browse cmd: %x", pdu);
+ switch (pdu)
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ case AVRC_PDU_CHANGE_PATH:
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ case AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS:
+ break;
+ default:
+ evt = 0;
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+ APPL_TRACE_ERROR("### Not supported cmd: %x", pdu);
+ break;
+ }
+ return evt;
+}
+
/*******************************************************************************
**
** Function bta_av_rc_msg
@@ -884,6 +1010,7 @@
rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
#endif
+ APPL_TRACE_DEBUG("bta_av_rc_msg opcode: %x",p_data->rc_msg.opcode);
if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
{
@@ -1024,6 +1151,25 @@
AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor);
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE )
+ {
+ APPL_TRACE_DEBUG("browse len PDU :%x",p_data->rc_msg.msg.browse.browse_len);
+ APPL_TRACE_DEBUG("browse data:%x",p_data->rc_msg.msg.browse.p_browse_data[0]);
+ av.browse_msg.label = p_data->rc_msg.label;
+ av.browse_msg.p_msg = &p_data->rc_msg.msg;
+
+ evt = bta_av_proc_browse_cmd(&rc_rsp, &p_data->rc_msg);
+ if (evt == 0)
+ {
+ APPL_TRACE_ERROR("Browse PDU not supported");
+ rc_rsp.rsp.pdu = AVRC_PDU_GENERAL_REJECT;
+ rc_rsp.rsp.status = AVRC_STS_BAD_CMD;
+ ctype = 0;
+ AVRC_BldBrowseResponse(0, &rc_rsp, &p_pkt);
+ }
+ }
+#endif
#if (AVRC_METADATA_INCLUDED == TRUE)
if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP)
{
@@ -1207,7 +1353,10 @@
BOOLEAN chk_restore = FALSE;
/* Validate array index*/
- if (index < BTA_AV_NUM_STRS)
+ /* Fix for below klockwork issue
+ * Array 'p_scb' size is 2.
+ * Possible attempt to access element -1 of array 'p_scb' */
+ if (index >= 0 && index < BTA_AV_NUM_STRS)
{
p_scb = p_cb->p_scb[index];
}
@@ -1408,7 +1557,10 @@
bta_av_close_all_rc(p_cb);
- osi_free_and_reset((void **)&p_cb->p_disc_db);
+ if(p_cb->p_disc_db) {
+ (void)SDP_CancelServiceSearch (p_cb->p_disc_db);
+ osi_free_and_reset((void **)&p_cb->p_disc_db);
+ }
/* disable audio/video - de-register all channels,
* expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
@@ -1456,21 +1608,55 @@
UINT8 mask;
tBTA_AV_LCB *p_lcb = NULL;
- APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event);
- if (event == AVDT_CONNECT_IND_EVT)
+ BTIF_TRACE_IMP("%s bta_av_sig_chg event: %d",
+ __FUNCTION__, event);
+ if(event == AVDT_CONNECT_IND_EVT)
{
p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
if (!p_lcb)
{
+ if (p_cb->conn_lcb > 0)
+ {
+ APPL_TRACE_DEBUG("Already connected to LCBs: 0x%x", p_cb->conn_lcb);
+ }
+ /* Check if busy processing a connection, if yes, Reject the
+ * new incoming connection.
+ * This is very rare case to happen as the timeout to start
+ * signalling procedure is just 2 sec.
+ * Also sink initiators will have retry machanism.
+ * Even though busy flag is set during outgoing connection to
+ * reject incoming connection at L2CAP connect request, there
+ * is a chance to get here if the incoming connection has passed
+ * the L2CAP connection stage.
+ */
+ if((p_data->hdr.offset == AVDT_ACP) && (AVDT_GetServiceBusyState() == TRUE))
+ {
+ APPL_TRACE_ERROR("%s Incoming conn while processing another.. Reject",
+ __FUNCTION__);
+ AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL);
+ return;
+ }
+
/* if the address does not have an LCB yet, alloc one */
for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
{
mask = 1 << xx;
- APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+ APPL_TRACE_DEBUG("The current conn_lcb: 0x%x", p_cb->conn_lcb);
/* look for a p_lcb with its p_scb registered */
if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
{
+ /* Check if the SCB is Free before using for
+ * ACP connection
+ */
+ if ((p_data->hdr.offset == AVDT_ACP) &&
+ (p_cb->p_scb[xx]->state != BTA_AV_INIT_SST))
+ {
+ APPL_TRACE_DEBUG("SCB in use %d", xx);
+ continue;
+ }
+
+ APPL_TRACE_DEBUG("Found a free p_lcb : 0x%x", xx);
p_lcb = &p_cb->lcb[xx];
p_lcb->lidx = xx + 1;
bdcpy(p_lcb->addr, p_data->str_msg.bd_addr);
@@ -1497,6 +1683,9 @@
*/
bta_av_signalling_timer(NULL);
+ APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__);
+ bta_sys_conn_open(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
+ p_cb->p_scb[xx]->peer_addr);
/* Possible collision : need to avoid outgoing processing while the timer is running */
p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
alarm_set_on_queue(p_cb->accept_signalling_timer,
@@ -1538,6 +1727,13 @@
/* clean up ssm */
for(xx=0; xx < BTA_AV_NUM_STRS; xx++)
{
+
+ if ((p_cb->p_scb[xx]) &&
+ (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0))
+ {
+ APPL_TRACE_DEBUG("%s: Closing timer for AVDTP service", __func__);
+ bta_sys_conn_close(BTA_ID_AV, p_cb->p_scb[xx]->app_id,p_cb->p_scb[xx]->peer_addr);
+ }
mask = 1 << (xx + 1);
if (((mask & p_lcb->conn_msk) || bta_av_cb.conn_lcb) && (p_cb->p_scb[xx]) &&
(bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0))
@@ -1585,6 +1781,9 @@
BTA_AV_SIGNALLING_TIMEOUT_MS,
BTA_AV_SIGNALLING_TIMER_EVT, 0);
bdcpy(pend.bd_addr, p_lcb->addr);
+ APPL_TRACE_DEBUG("bta_av_sig_timer on IDX = %d",xx);
+ //Copy the handle of SCB
+ pend.hndl = p_cb->p_scb[xx]->hndl;
(*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV *) &pend);
}
}
@@ -1606,6 +1805,7 @@
UINT32 inx = PTR_TO_UINT(data);
tBTA_AV_CB *p_cb = &bta_av_cb;
tBTA_AV_SCB *p_scb = NULL;
+
if (inx < BTA_AV_NUM_STRS)
{
p_scb = p_cb->p_scb[inx];
@@ -1660,6 +1860,58 @@
}
}
+BOOLEAN bta_av_check_store_avrc_tg_version(BD_ADDR addr, UINT16 ver)
+{
+ BOOLEAN is_present = FALSE;
+ struct blacklist_entry data;
+ FILE *fp;
+ BOOLEAN is_file_updated = FALSE;
+
+ APPL_TRACE_DEBUG("%s target BD Addr: %x:%x:%x", __func__,\
+ addr[0], addr[1], addr[2]);
+ fp = fopen(AVRC_PEER_VERSION_CONF_FILE, "rb");
+ if (!fp)
+ {
+ APPL_TRACE_ERROR("%s unable to open AVRC Conf file for read: error: (%s)",\
+ __func__, strerror(errno));
+ }
+ else
+ {
+ while (fread(&data, sizeof(data), 1, fp) != 0)
+ {
+ APPL_TRACE_DEBUG("Entry: addr = %x:%x:%x, ver = 0x%x",\
+ data.addr[0], data.addr[1], data.addr[2], data.ver);
+ if(!memcmp(addr, data.addr, 3))
+ {
+ is_present = TRUE;
+ APPL_TRACE_DEBUG("Entry alreday present, bailing out");
+ break;
+ }
+ }
+ fclose(fp);
+ }
+
+ if (is_present == FALSE)
+ {
+ fp = fopen(AVRC_PEER_VERSION_CONF_FILE, "ab");
+ if (!fp)
+ {
+ APPL_TRACE_ERROR("%s unable to open AVRC Conf file for write: error: (%s)",\
+ __func__, strerror(errno));
+ }
+ else
+ {
+ data.ver = ver;
+ memcpy(data.addr, (const char *)addr, 3);
+ APPL_TRACE_DEBUG("Avrcp version to store = 0x%x", ver);
+ fwrite(&data, sizeof(data), 1, fp);
+ fclose(fp);
+ is_file_updated = TRUE;
+ }
+ }
+ return is_file_updated;
+}
+
/*******************************************************************************
**
** Function bta_av_check_peer_features
@@ -1676,7 +1928,7 @@
tBTA_AV_CB *p_cb = &bta_av_cb;
tSDP_DISC_REC *p_rec = NULL;
tSDP_DISC_ATTR *p_attr;
- UINT16 peer_rc_version=0;
+ UINT16 peer_rc_version=0; /*Assuming Default peer version as 1.3*/
UINT16 categories = 0;
APPL_TRACE_DEBUG("bta_av_check_peer_features service_uuid:x%x", service_uuid);
@@ -1707,6 +1959,22 @@
/* get profile version (if failure, version parameter is not updated) */
SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
&peer_rc_version);
+
+ if (interop_match_addr(INTEROP_ADV_AVRCP_VER_1_3,
+ (const bt_bdaddr_t*) p_rec->remote_bd_addr))
+ {
+ peer_rc_version = AVRC_REV_1_3;
+ APPL_TRACE_DEBUG("changing peer_rc_version as part of blacklisting to 0x%x",
+ peer_rc_version);
+ }
+ else if (interop_match_addr(INTEROP_STORE_REMOTE_AVRCP_VERSION_1_4,
+ (const bt_bdaddr_t*) p_rec->remote_bd_addr))
+ {
+ peer_rc_version = AVRC_REV_1_4;
+ APPL_TRACE_DEBUG("changing peer_rc_version as part of blacklisting to 0x%x",
+ peer_rc_version);
+ }
+
APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version);
if (peer_rc_version >= AVRC_REV_1_3)
@@ -1721,9 +1989,39 @@
{
categories = p_attr->attr_value.v.u16;
if (categories & AVRC_SUPF_CT_BROWSE)
+ {
peer_features |= (BTA_AV_FEAT_BROWSE);
+ APPL_TRACE_DEBUG("peer supports browsing");
+ }
+ if (categories & AVRC_SUPF_CT_COVER_ART_GET_IMAGE &
+ AVRC_SUPF_CT_COVER_ART_GET_THUMBNAIL)
+ {
+ peer_features |= BTA_AV_FEAT_CA;
+ APPL_TRACE_DEBUG("peer supports cover art");
+ }
}
}
+#if ((defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE)) || \
+ (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE)))
+ if ((peer_rc_version >= AVRC_REV_1_4) &&
+ ((peer_features & BTA_AV_FEAT_BROWSE) || (peer_features & BTA_AV_FEAT_CA)))
+ {
+ BOOLEAN ret = FALSE;
+ APPL_TRACE_DEBUG("peer version to update: 0x%x", peer_rc_version);
+ ret = bta_av_check_store_avrc_tg_version(p_rec->remote_bd_addr, peer_rc_version);
+ if (ret == TRUE)
+ {
+ peer_features |= BTA_AV_FEAT_AVRC_UI_UPDATE;
+ APPL_TRACE_DEBUG("update UI on peer repair request: 0x%x",
+ peer_features);
+ }
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("No need to store peer version: 0x%x", peer_rc_version);
+ /*No need to update peer version as we send the default version as 1.3*/
+ }
+#endif
}
}
APPL_TRACE_DEBUG("peer_features:x%x", peer_features);
@@ -1744,61 +2042,64 @@
{
tBTA_AV_FEAT peer_features = 0;
tBTA_AV_CB *p_cb = &bta_av_cb;
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ UINT16 peer_rc_version = 0;
+ UINT16 categories = 0;
+ BOOLEAN val;
APPL_TRACE_DEBUG("%s service_uuid:x%x", __FUNCTION__, service_uuid);
-
- /* loop through all records we found */
- tSDP_DISC_REC *p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL);
- while (p_rec)
+ /* get next record; if none found, we're done */
+ p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
+ if (p_rec != NULL)
{
- APPL_TRACE_DEBUG("%s found Service record for x%x", __FUNCTION__, service_uuid);
+ APPL_TRACE_DEBUG(" %s found Service record for x%x", __FUNCTION__, service_uuid);
+ if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ peer_features |= BTA_AV_FEAT_RCCT;
+ else if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+ peer_features |= BTA_AV_FEAT_RCTG;
- if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL)
- {
- /* find peer features */
- if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL))
- {
- peer_features |= BTA_AV_FEAT_RCCT;
- }
- if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL))
- {
- peer_features |= BTA_AV_FEAT_RCTG;
- }
+ if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
+ {
+ /* profile version (if failure, version parameter is not updated) */
+ val = SDP_FindProfileVersionInRec(p_rec,
+ UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+ APPL_TRACE_DEBUG("%s rc_version for TG 0x%x, profile_found %d", __FUNCTION__,
+ peer_rc_version, val);
+
+ if (peer_rc_version < AVRC_REV_1_3)
+ return peer_features;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr == NULL)
+ return peer_features;
+
+ categories = p_attr->attr_value.v.u16;
+
+ if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+ {
+ peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+ /* get supported categories */
+ if (categories & AVRC_SUPF_CT_BROWSE)
+ peer_features |= BTA_AV_FEAT_BROWSE;
+ if (categories & AVRC_SUPF_CT_APP_SETTINGS)
+ peer_features |= BTA_AV_FEAT_APP_SETTING;
+ }
+ /*
+ * Absolute Volume came after in 1.4 and above.
+ * but there are few devices in market which supports.
+ * absoluteVolume and they are still 1.3 To avoid inter-operatibility issuses with.
+ * those devices, we check for 1.3 as minimum version.
+ */
+ else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ {
+ if (categories & AVRC_SUPF_CT_CAT2)
+ {
+ APPL_TRACE_DEBUG(" %s Remote supports ABS Vol", __FUNCTION__);
+ peer_features |= BTA_AV_FEAT_ADV_CTRL;
+ }
+ }
}
-
- if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
- {
- /* get profile version (if failure, version parameter is not updated) */
- UINT16 peer_rc_version = 0;
- BOOLEAN val = SDP_FindProfileVersionInRec(
- p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
- APPL_TRACE_DEBUG("%s peer_rc_version for TG 0x%x, profile_found %d",
- __FUNCTION__, peer_rc_version, val);
-
- if (peer_rc_version >= AVRC_REV_1_3)
- peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
-
- /*
- * Though Absolute Volume came after in 1.4 and above, but there are few devices
- * in market which supports absolute Volume and they are still 1.3
- * TO avoid IOT issuses with those devices, we check for 1.3 as minimum version
- */
- if (peer_rc_version >= AVRC_REV_1_3)
- {
- /* get supported categories */
- tSDP_DISC_ATTR *p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
- if (p_attr != NULL)
- {
- UINT16 categories = p_attr->attr_value.v.u16;
- if (categories & AVRC_SUPF_CT_CAT2)
- peer_features |= (BTA_AV_FEAT_ADV_CTRL);
- if (categories & AVRC_SUPF_CT_APP_SETTINGS)
- peer_features |= (BTA_AV_FEAT_APP_SETTING);
- }
- }
- }
- /* get next record; if none found, we're done */
- p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
}
APPL_TRACE_DEBUG("%s peer_features:x%x", __FUNCTION__, peer_features);
return peer_features;
@@ -1839,7 +2140,10 @@
else
{
/* Validate array index*/
- if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS)
+ /* Fix for below klockwork issue
+ * Array 'p_scb' size is 2
+ * Possible attempt to access element -1 of array 'p_scb' */
+ if ((((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) && (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) >= 0))
{
p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
}
@@ -1855,13 +2159,22 @@
}
APPL_TRACE_DEBUG("%s rc_handle %d", __FUNCTION__, rc_handle);
+ if (rc_handle == BTA_AV_RC_HANDLE_NONE)
+ {
+ if (AVRC_CheckIncomingConn(p_scb->peer_addr) == TRUE)
+ {
+ bta_sys_start_timer(p_scb->avrc_ct_timer, AVRC_CONNECT_RETRY_DELAY_MS,
+ BTA_AV_SDP_AVRC_DISC_EVT,p_scb->hndl);
+ }
+ }
+
#if (BTA_AV_SINK_INCLUDED == TRUE)
if (p_cb->sdp_a2d_snk_handle)
{
/* This is Sink + CT + TG(Abs Vol) */
- peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
- if (BTA_AV_FEAT_ADV_CTRL & bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
- peer_features |= (BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCCT);
+ peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL);
+ peer_features |= bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ APPL_TRACE_DEBUG("final rc_features %x", peer_features);
}
else
#endif
@@ -1896,7 +2209,22 @@
if (p_lcb)
{
rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
- p_cb->rcb[rc_handle].peer_features = peer_features;
+ /* Fix for below Klockwork Issue
+ * Array 'rcb' of size 4 may use index value(s) 4..254 */
+ if((rc_handle != BTA_AV_RC_HANDLE_NONE) && (rc_handle < BTA_AV_NUM_RCB))
+ {
+ p_cb->rcb[rc_handle].peer_features = peer_features;
+ }
+ else
+ {
+ /* cannot create valid rc_handle for current device */
+ APPL_TRACE_ERROR(" No link resources available");
+ p_scb->use_rc = FALSE;
+ bdcpy(rc_open.peer_addr, p_scb->peer_addr);
+ rc_open.peer_features = 0;
+ rc_open.status = BTA_AV_FAIL_RESOURCES;
+ (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_open);
+ }
}
#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE)
else
@@ -1918,7 +2246,10 @@
}
else
{
- p_cb->rcb[rc_handle].peer_features = peer_features;
+ /* Fix for below Klockwork Issue
+ * Array 'rcb' of size 4 may use index value(s) 4..254 */
+ if (rc_handle < BTA_AV_NUM_RCB)
+ p_cb->rcb[rc_handle].peer_features = peer_features;
rc_feat.rc_handle = rc_handle;
rc_feat.peer_features = peer_features;
if (p_scb == NULL)
@@ -1938,6 +2269,26 @@
/*******************************************************************************
**
+** Function bta_av_rc_collission_detected
+**
+** Description Update App on collision detected case
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_rc_collission_detected(tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+ tBTA_AV_RC_COLL_DETECTED rc_coll;
+ tBTA_AV_RC_COLLISSION_DETECTED *p_msg = (tBTA_AV_RC_COLLISSION_DETECTED *)p_data;
+ rc_coll.rc_handle = p_msg->handle;
+ bdcpy(rc_coll.peer_addr, p_msg->peer_addr);
+ (*p_cb->p_cback)(BTA_AV_RC_COLL_DETECTED_EVT, (tBTA_AV *) &rc_coll);
+}
+
+/*******************************************************************************
+**
** Function bta_av_rc_closed
**
** Description Set AVRCP state to closed.
@@ -2008,10 +2359,6 @@
{
/* AVCT CCB is still there. dealloc */
bta_av_del_rc(p_rcb);
-
- /* if the AVRCP is no longer listening, create the listening channel */
- if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG)
- bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
}
}
else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
@@ -2033,6 +2380,9 @@
bdcpy(rc_close.peer_addr, p_msg->peer_addr);
}
(*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_close);
+ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE
+ && bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
}
/*******************************************************************************
diff --git a/bta/av/bta_av_api.c b/bta/av/bta_av_api.c
index 5a033c9..60e3eb9 100644
--- a/bta/av/bta_av_api.c
+++ b/bta/av/bta_av_api.c
@@ -223,11 +223,12 @@
** Returns void
**
*******************************************************************************/
-void BTA_AvStart(void)
+void BTA_AvStart(tBTA_AV_HNDL handle)
{
BT_HDR *p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR));
p_buf->event = BTA_AV_API_START_EVT;
+ p_buf->layer_specific = handle;
bta_sys_sendmsg(p_buf);
}
@@ -305,7 +306,7 @@
** Returns void
**
*******************************************************************************/
-void BTA_AvStop(BOOLEAN suspend)
+void BTA_AvStop(BOOLEAN suspend, tBTA_AV_HNDL handle)
{
tBTA_AV_API_STOP *p_buf =
(tBTA_AV_API_STOP *)osi_malloc(sizeof(tBTA_AV_API_STOP));
@@ -313,12 +314,55 @@
p_buf->hdr.event = BTA_AV_API_STOP_EVT;
p_buf->flush = TRUE;
p_buf->suspend = suspend;
+ p_buf->hdr.layer_specific = handle;
bta_sys_sendmsg(p_buf);
}
/*******************************************************************************
**
+** Function BTA_AvEnableMultiCast
+**
+** Description Enable/Disable Avdtp MultiCast
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvEnableMultiCast(BOOLEAN state, tBTA_AV_HNDL handle)
+{
+ tBTA_AV_ENABLE_MULTICAST *p_buf;
+
+ if ((p_buf = (tBTA_AV_ENABLE_MULTICAST *) osi_malloc(sizeof(tBTA_AV_ENABLE_MULTICAST))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_ENABLE_MULTICAST_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->is_multicast_enabled = state;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvUpdateMaxAVClient
+**
+** Description Update max av connections supported simultaneously
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvUpdateMaxAVClient(UINT8 max_clients)
+{
+ tBTA_AV_MAX_CLIENT *p_buf;
+
+ if ((p_buf = (tBTA_AV_MAX_CLIENT *) osi_malloc(sizeof(tBTA_AV_MAX_CLIENT))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_UPDATE_MAX_AV_CLIENTS_EVT;
+ p_buf->max_clients = max_clients;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
** Function BTA_AvReconfig
**
** Description Reconfigure the audio/video stream.
diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c
index e2a8aa8..0c3011b 100644
--- a/bta/av/bta_av_cfg.c
+++ b/bta/av/bta_av_cfg.c
@@ -41,6 +41,8 @@
/* AVRCP cupported categories */
#if (AVRC_CTLR_INCLUDED == TRUE)
+#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_CAT2)
+#else
#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2)
#endif
@@ -68,21 +70,37 @@
/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */
/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */
#if AVRC_METADATA_INCLUDED == TRUE
-#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
+
+#if AVCT_BROWSE_INCLUDED == TRUE
+#if (defined(AVCT_COVER_ART_INCLUDED) && (AVCT_COVER_ART_INCLUDED == TRUE))
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_BROWSE | AVRC_SUPF_TG_APP_SETTINGS | AVRC_SUPF_TG_PLAYER_COVER_ART)
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_BROWSE | AVRC_SUPF_TG_APP_SETTINGS)
+#endif
+
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_APP_SETTINGS)
+#endif
+
#else
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
#endif
/*
* If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed.
+ * AVRCP 1.3 specific events to be added before AVCT_BROWSE_INCLUDED.
*/
const UINT8 bta_av_meta_caps_evt_ids[] = {
AVRC_EVT_PLAY_STATUS_CHANGE,
AVRC_EVT_TRACK_CHANGE,
AVRC_EVT_PLAY_POS_CHANGED,
- /* TODO: Add support for these events
AVRC_EVT_APP_SETTING_CHANGE,
- */
+#if AVCT_BROWSE_INCLUDED == TRUE
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+ AVRC_EVT_AVAL_PLAYERS_CHANGE,
+ AVRC_EVT_ADDR_PLAYER_CHANGE,
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+#endif
};
#ifndef BTA_AV_NUM_RC_EVT_IDS
#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
index dbe4c77..a751f14 100644
--- a/bta/av/bta_av_int.h
+++ b/bta/av/bta_av_int.h
@@ -1,4 +1,10 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
+/******************************************************************************
*
* Copyright (C) 2004-2012 Broadcom Corporation
*
@@ -106,7 +112,10 @@
BTA_AV_AVDT_RPT_CONN_EVT,
#endif
BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as the *AP_*EVT */
- BTA_AV_API_STOP_EVT
+ BTA_AV_API_STOP_EVT,
+ BTA_AV_UPDATE_MAX_AV_CLIENTS_EVT,
+ BTA_AV_ENABLE_MULTICAST_EVT, /* Event for enable and disable multicast */
+ BTA_AV_RC_COLLISSION_DETECTED_EVT
};
/* events for AV control block state machine */
@@ -118,13 +127,13 @@
/* events that do not go through state machine */
#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT
-#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT
+#define BTA_AV_LAST_NSM_EVT BTA_AV_ENABLE_MULTICAST_EVT
/* API events passed to both SSMs (by bta_av_api_to_ssm) */
#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT
#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT
-#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT
+#define BTA_AV_LAST_EVT BTA_AV_ENABLE_MULTICAST_EVT
/* maximum number of SEPS in stream discovery results */
#define BTA_AV_NUM_SEPS 32
@@ -154,7 +163,6 @@
#define BTA_AV_MULTI_AV_SUPPORTED 0x01
#define BTA_AV_MULTI_AV_IN_USE 0x02
-
/*****************************************************************************
** Data types
*****************************************************************************/
@@ -180,6 +188,8 @@
typedef void * (*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type,
UINT32 *p_len, UINT32 *p_timestamp);
typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay);
+typedef BOOLEAN (*tBTA_AV_CO_OFFLOAD_SUPPORT) (void);
+typedef BOOLEAN (*tBTA_AV_CO_OFFLOAD_CAP) (int codec);
/* the call-out functions for one stream */
typedef struct
@@ -194,6 +204,8 @@
tBTA_AV_CO_STOP stop;
tBTA_AV_CO_DATAPATH data;
tBTA_AV_CO_DELAY delay;
+ tBTA_AV_CO_OFFLOAD_SUPPORT offload;
+ tBTA_AV_CO_OFFLOAD_CAP cap;
} tBTA_AV_CO_FUNCTS;
/* data type for BTA_AV_API_ENABLE_EVT */
@@ -243,6 +255,20 @@
BOOLEAN flush;
} tBTA_AV_API_STOP;
+/* data type for BTA_AV_ENABLE_MULTICAST_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BOOLEAN is_multicast_enabled;
+} tBTA_AV_ENABLE_MULTICAST;
+
+/* data type for BTA_AV_UPDATE_MAX_AV_CLIENTS_EVTT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 max_clients;
+} tBTA_AV_MAX_CLIENT;
+
/* data type for BTA_AV_API_DISCONNECT_EVT */
typedef struct
{
@@ -359,6 +385,14 @@
UINT8 handle;
} tBTA_AV_RC_CONN_CHG;
+/* data type for BTA_AV_AVRC_COLL_DETECTED_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR peer_addr;
+ UINT8 handle;
+} tBTA_AV_RC_COLLISSION_DETECTED;
+
/* data type for BTA_AV_CONN_CHG_EVT */
typedef struct
{
@@ -397,6 +431,8 @@
tBTA_AV_CODEC codec_type; /* codec type */
UINT8 tsep; /* SEP type of local SEP */
tBTA_AV_DATA_CBACK *p_app_data_cback; /* Application callback for media packets */
+ UINT32 vendorId; /* vendorId type */
+ UINT16 codecId; /* codecId type */
} tBTA_AV_SEP;
@@ -434,6 +470,8 @@
tBTA_AV_SDP_RES sdp_res;
tBTA_AV_API_META_RSP api_meta_rsp;
tBTA_AV_API_STATUS_RSP api_status_rsp;
+ tBTA_AV_ENABLE_MULTICAST multicast_state;
+ tBTA_AV_MAX_CLIENT max_av_clients;
} tBTA_AV_DATA;
typedef void (tBTA_AV_VDP_DATA_ACT)(void *p_scb);
@@ -473,6 +511,7 @@
/* Bitmap for collision, coll_mask */
#define BTA_AV_COLL_INC_TMR 0x01 /* Timer is running for incoming L2C connection */
#define BTA_AV_COLL_API_CALLED 0x02 /* API open was called while incoming timer is running */
+#define BTA_AV_COLL_SETCONFIG_IND 0x04 /* SetConfig indication has been called by remote */
/* type for AV stream control block */
typedef struct
@@ -519,6 +558,7 @@
UINT8 co_started; /* non-zero, if stream started from call-out perspective */
BOOLEAN recfg_sup; /* TRUE if the first attempt to reconfigure the stream was successfull, else False if command fails */
BOOLEAN suspend_sup; /* TRUE if Suspend stream is supported, else FALSE if suspend command fails */
+ BOOLEAN suspend_local_sent; /* TRUE if outgoing Suspend is sent, else FALSE if confirmation is received */
BOOLEAN deregistring; /* TRUE if deregistering */
BOOLEAN sco_suspend; /* TRUE if SUSPEND is issued automatically for SCO */
UINT8 coll_mask; /* Mask to check incoming and outgoing collision */
@@ -601,6 +641,7 @@
BOOLEAN sco_occupied; /* TRUE if SCO is being used or call is in progress */
UINT8 audio_streams; /* handle mask of streaming audio channels */
UINT8 video_streams; /* handle mask of streaming video channels */
+ UINT8 codec_type; /* p_scb->codec_type */
} tBTA_AV_CB;
@@ -649,7 +690,7 @@
extern BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb);
extern void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb);
extern tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op);
-
+extern BOOLEAN bta_av_is_multicast_enabled();
/* main functions */
extern void bta_av_api_deregister(tBTA_AV_DATA *p_data);
@@ -673,6 +714,7 @@
extern void bta_av_rc_disc(UINT8 disc);
extern void bta_av_conn_chg(tBTA_AV_DATA *p_data);
extern void bta_av_dereg_comp(tBTA_AV_DATA *p_data);
+extern void bta_av_rc_collission_detected(tBTA_AV_DATA *p_data);
/* sm action functions */
extern void bta_av_disable (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data);
diff --git a/bta/av/bta_av_main.c b/bta/av/bta_av_main.c
index 735ee2c..50b116d 100644
--- a/bta/av/bta_av_main.c
+++ b/bta/av/bta_av_main.c
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2004-2012 Broadcom Corporation
*
@@ -29,6 +34,7 @@
#include "bt_target.h"
#include "osi/include/log.h"
+#include <cutils/properties.h>
#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
#include "bta_av_co.h"
@@ -36,11 +42,15 @@
#include "l2c_api.h"
#include "l2cdefs.h"
#include "utl.h"
+#include "btm_int.h"
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
+#include "a2d_aptx.h"
+#include "a2d_aptx_hd.h"
+
/*****************************************************************************
** Constants and types
*****************************************************************************/
@@ -65,6 +75,14 @@
#define BTA_AV_RS_TIME_VAL 1000
#endif
+/* offload codecs support */
+enum
+{
+ APTX = 1,
+ AAC,
+ APTXHD
+};
+
/* state machine states */
enum
{
@@ -123,7 +141,7 @@
/* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
/* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
/* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST },
-/* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
+/* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_INIT_ST },
/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST },
/* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_MSG, BTA_AV_INIT_ST },
/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST },
@@ -170,6 +188,9 @@
app_id, BD_ADDR peer_addr);
static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+static void bta_av_api_enable_multicast(tBTA_AV_DATA *p_data);
+static void bta_av_api_update_max_av_clients(tBTA_AV_DATA * p_data);
+
/* action functions */
const tBTA_AV_NSM_ACT bta_av_nsm_act[] =
{
@@ -185,13 +206,16 @@
bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */
bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */
#if (BTA_AV_SINK_INCLUDED == TRUE)
- bta_av_api_sink_enable, /* BTA_AV_API_SINK_ENABLE_EVT */
+ bta_av_api_sink_enable, /* BTA_AV_API_SINK_ENABLE_EVT */
#endif
#if (AVDT_REPORTING == TRUE)
- bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
+ bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
#endif
- bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
- bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+ bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
+ bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+ bta_av_api_update_max_av_clients,
+ bta_av_api_enable_multicast, /* BTA_AV_ENABLE_MULTICAST_EVT */
+ bta_av_rc_collission_detected, /* BTA_AV_RC_COLLISSION_DETECTED_EVT */
};
/*****************************************************************************
@@ -207,6 +231,7 @@
static char *bta_av_st_code(UINT8 state);
#endif
+static BOOLEAN is_multicast_enabled = FALSE;
/*******************************************************************************
**
** Function bta_av_api_enable
@@ -358,6 +383,7 @@
p_ret->a2d_list = list_new(NULL);
p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");
bta_av_cb.p_scb[xx] = p_ret;
+ APPL_TRACE_EVENT("AV: Alloc success, handle is =%d", p_ret->hndl);
break;
}
}
@@ -492,7 +518,10 @@
char *p_service_name;
tBTA_AV_CODEC codec_type;
tBTA_UTL_COD cod;
- UINT8 index = 0;
+ UINT8 startIndex = 0;
+ UINT8 endIndex = 0;
+ UINT8 index;
+ UINT16 profile_initialized;
memset(&cs,0,sizeof(tAVDT_CS));
@@ -500,8 +529,10 @@
registr.app_id = p_data->api_reg.app_id;
registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
- UINT16 profile_initialized = p_data->api_reg.service_uuid;
- if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ APPL_TRACE_DEBUG("bta_av_api_register : channel %d", registr.chnl);
+
+ profile_initialized = p_data->api_reg.service_uuid;
+ if(profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
{
p_bta_av_cfg = (tBTA_AV_CFG *) &bta_avk_cfg;
}
@@ -513,6 +544,7 @@
do
{
p_scb = bta_av_alloc_scb(registr.chnl);
+ cs.registration_id = p_scb->hdi;
if(p_scb == NULL)
{
APPL_TRACE_ERROR("failed to alloc SCB");
@@ -552,9 +584,21 @@
#endif
if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
{
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",
+ NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_6);
+#else
+#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",
+ NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_5);
+#else
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",
NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
(bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_3);
+#endif
+#endif
}
else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
{
@@ -605,6 +649,7 @@
if(registr.chnl == BTA_AV_CHNL_AUDIO)
{
/* set up the audio stream control block */
+ APPL_TRACE_EVENT("AV: set up the audio stream control block ");
p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
p_scb->p_cos = &bta_av_a2d_cos;
p_scb->media_type= AVDT_MEDIA_AUDIO;
@@ -628,36 +673,128 @@
if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
{
cs.tsep = AVDT_TSEP_SRC;
- index = 0;
+ startIndex = BTIF_SV_AV_AA_SBC_INDEX;
+ endIndex = BTIF_SV_AV_AA_SRC_SEP_INDEX;
}
else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
{
cs.tsep = AVDT_TSEP_SNK;
cs.p_data_cback = bta_av_stream_data_cback;
- index = 1;
+ startIndex = BTIF_SV_AV_AA_SBC_SINK_INDEX;
+ endIndex = BTIF_SV_AV_AA_SNK_SEP_INDEX;
}
/* Initialize Handles to zero */
- for (int xx=0; xx < BTA_AV_MAX_SEPS; xx++)
+ for(index = 0; index < (endIndex - startIndex); index++)
{
- p_scb->seps[xx].av_handle = 0;
+ p_scb->seps[index].av_handle = 0;
}
/* keep the configuration in the stream control block */
memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
- if ((*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
- &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
+ index = startIndex;
+ while (index < endIndex &&
+ (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
+ &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
{
- if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)
- {
- p_scb->seps[index].codec_type = codec_type;
- p_scb->seps[index].tsep = cs.tsep;
- if(cs.tsep == AVDT_TSEP_SNK)
- p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback;
- else
- p_scb->seps[index].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */
+ UINT8* ptr = cs.cfg.codec_info;
+ tA2D_APTX_CIE* codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ UINT32 vendorId = codecInfo->vendorId;
+ UINT16 codecId = codecInfo->codecId;
+ if ((*bta_av_a2d_cos.offload)() == TRUE)
+ {
+ if(codec_type == A2D_NON_A2DP_MEDIA_CT)
+ {
+ if (vendorId == A2D_APTX_VENDOR_ID &&
+ codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ {
+ if((*bta_av_a2d_cos.cap)(APTX) != TRUE)
+ {
+ APPL_TRACE_DEBUG("%s: aptx-Classic offload codec not supported",__func__);
+ index++;
+ continue;
+ }
+ else
+ APPL_TRACE_DEBUG("%s:aptx-Classic offload codec supported",__func__)
+ } else {
+ if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH &&
+ vendorId == A2D_APTX_HD_VENDOR_ID ) {
+ if((*bta_av_a2d_cos.cap)(APTXHD) != TRUE)
+ {
+ APPL_TRACE_DEBUG("%s: aptx-HD offload codec not supported",__func__)
+ index++;
+ continue;
+ }
+ else
+ APPL_TRACE_DEBUG("%s: aptx-HD offload codec supported",__func__)
+
+ }
+ }
+ }
+ else if (codec_type == AAC)
+ {
+ if ((*bta_av_a2d_cos.cap)(AAC) != TRUE)
+ {
+ APPL_TRACE_DEBUG("%s: AAC offload codec not supported",__func__);
+ index++;
+ continue;
+ } else {
+ APPL_TRACE_DEBUG("%s: AAC offload codec supported",__func__);
+ }
+ }
+ } else if (codec_type == A2D_NON_A2DP_MEDIA_CT) {
+ if ((codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID)
+ && (A2D_check_and_init_aptX() == false)) {
+ APPL_TRACE_WARNING("%s aptX not available ", __func__);
+ index++;
+ continue;
+
+ } else {
+ char value[PROPERTY_VALUE_MAX];
+ bool enableAptXHD = false;
+ if (property_get("persist.bt.enableAptXHD", value, "false") && strcmp(value, "true") == 0)
+ enableAptXHD = true;
+ else
+ APPL_TRACE_WARNING("%s enableAptXHD property is not set", __func__);
+
+ if ((codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) &&
+ ((enableAptXHD == false) || (A2D_check_and_init_aptX_HD() == false))) {
+ APPL_TRACE_WARNING("%s aptX-HD not available", __func__);
+ index++;
+ continue;
+ }
+ }
+ } else if (codec_type == AAC) {
+ //Don't add AAC in Non split mode
+ index++;
+ continue;
}
+
+ /* Fix for below klockwork Issues
+ * Array 'seps' of size 4 may use index value(s) 4 */
+ if (((index - startIndex) < BTA_AV_MAX_SEPS) &&
+ (AVDT_CreateStream(&p_scb->seps[index - startIndex].av_handle, &cs) ==
+ AVDT_SUCCESS))
+ {
+ if ((profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) &&
+ ((index == BTIF_SV_AV_AA_APTX_INDEX) || (index == BTIF_SV_AV_AA_APTX_HD_INDEX)))
+ {
+ p_scb->seps[index - startIndex].vendorId = vendorId;
+ p_scb->seps[index - startIndex].codecId = codecId;
+ APPL_TRACE_DEBUG("%s audio[%x] vendorId: %x codecId: %x", __func__,
+ index, p_scb->seps[index - startIndex].vendorId,
+ p_scb->seps[index - startIndex].codecId);
+ }
+ p_scb->seps[index - startIndex].codec_type = codec_type;
+ p_scb->seps[index - startIndex].tsep = cs.tsep;
+ if(cs.tsep == AVDT_TSEP_SNK)
+ p_scb->seps[index - startIndex].p_app_data_cback = p_data->api_reg.p_app_data_cback;
+ else
+ p_scb->seps[index - startIndex].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */
+ index++;
+ } else
+ break;
}
if(!bta_av_cb.reg_audio)
@@ -683,9 +820,10 @@
bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
#endif
}
+
/* start listening when A2DP is registered */
if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
- bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, p_scb->hdi, BTA_AV_NUM_LINKS + 1);
/* if the AV and AVK are both supported, it cannot support the CT role */
if (bta_av_cb.features & (BTA_AV_FEAT_RCCT))
@@ -709,8 +847,13 @@
* because we rely on feature bits being scanned by external
* devices more than the profile version itself.
*/
- if ((profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) ||
- (profile_initialized == UUID_SERVCLASS_AUDIO_SINK))
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+ {
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+ p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_4);
+ }
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
{
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
@@ -720,7 +863,7 @@
}
}
bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
- APPL_TRACE_DEBUG("reg_audio: 0x%x",bta_av_cb.reg_audio);
+ APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
}
else
{
@@ -750,6 +893,8 @@
{
tBTA_AV_SCB *p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+ A2D_close_aptX();
+
if(p_scb)
{
p_scb->deregistring = TRUE;
@@ -776,12 +921,12 @@
tBTA_AV_SCB *p_scb;
int i;
UINT8 chnl = (UINT8)p_data->hdr.layer_specific;
-
for( i=0; i < BTA_AV_NUM_STRS; i++ )
{
p_scb = bta_av_cb.p_scb[i];
-
- if(p_scb && p_scb->chnl == chnl)
+ //Check if the Stream is in Started state before sending data
+ //in Dual Handoff mode, get SCB where START is done.
+ if(p_scb && (p_scb->chnl == chnl) && (p_scb->started))
{
bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data);
}
@@ -804,6 +949,20 @@
}
#endif
+BOOLEAN bta_av_multiple_streams_started(void)
+{
+ int xx, stream_count = 0;
+
+ for(xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if((bta_av_cb.p_scb[xx] != NULL) && bta_av_cb.p_scb[xx]->started == TRUE)
+ {
+ stream_count++;
+ }
+ }
+ return (stream_count > 1);
+}
+
/*******************************************************************************
**
** Function bta_av_api_to_ssm
@@ -819,10 +978,57 @@
int xx;
UINT16 event = p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT;
- for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ /* Multicast: Corner case handling for multicast state getting
+ * updated for ACL connected during the stream start where both
+ * streams are not yet started. We need to take care of this
+ * during suspend to ensure we suspend both streams.
+ */
+ if (is_multicast_enabled == TRUE)
{
- bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+ /* Send START request to all Open Stream connections.*/
+ for(xx=0; xx<BTA_AV_NUM_STRS; xx++)
+ {
+ bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+ }
}
+ else
+ {
+ /*In Dual A2dp Handoff, process this fucntion on specific handles.*/
+ APPL_TRACE_DEBUG("bta_av_api_to_ssm: on Handle 0x%x",p_data->hdr.layer_specific);
+ bta_av_ssm_execute(bta_av_hndl_to_scb(p_data->hdr.layer_specific), event, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_av_api_enable_multicast
+**
+** Description Enable/Disable Avdtp multicast
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_api_enable_multicast(tBTA_AV_DATA *p_data)
+{
+ is_multicast_enabled = p_data->multicast_state.is_multicast_enabled;
+ APPL_TRACE_DEBUG("is_multicast_enabled :%d", is_multicast_enabled);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_api_update_max_av_client
+**
+** Description Update max simultaneous AV connections supported
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_av_api_update_max_av_clients(tBTA_AV_DATA *p_data)
+{
+ int bta_av_max_clients = p_data->max_av_clients.max_clients;
+ APPL_TRACE_DEBUG("bta_av_max_clients:%d",bta_av_max_clients);
+ AVDT_UpdateMaxAvClients(bta_av_max_clients);
}
/*******************************************************************************
@@ -840,7 +1046,7 @@
BOOLEAN start = FALSE;
tBTA_AV_SCB *p_scbi;
int i;
-
+ APPL_TRACE_DEBUG("bta_av_chk_start: Audio open count: 0x%x",bta_av_cb.audio_open_cnt);
if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
{
if ((bta_av_cb.audio_open_cnt >= 2) &&
@@ -854,7 +1060,16 @@
p_scbi = bta_av_cb.p_scb[i];
if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
{
- start = TRUE;
+ if (is_multicast_enabled == TRUE)
+ {
+ start = TRUE;
+ }
+ else
+ {
+ start = FALSE;
+ APPL_TRACE_DEBUG("bta_av_chk_start: Already playing");
+ break;
+ }
/* may need to update the flush timeout of this already started stream */
if(p_scbi->co_started != bta_av_cb.audio_open_cnt)
{
@@ -962,11 +1177,17 @@
{
APPL_TRACE_DEBUG ("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);
-
+ /* Multicast:
+ * As per Multicast feature implementation, fallback
+ * happens to soft hand-off when DUT is in scatternet
+ * scenario. Hence, don't fail the connection if
+ * role switch fails because of remote disallowing.
+ * Set switch_res to BTA_AV_RS_DONE on failure.
+ */
if(HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id)
p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
else
- p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
+ p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
/* Continue av open process */
bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
@@ -1050,6 +1271,7 @@
UINT8 role;
BOOLEAN needed = FALSE;
tBTA_AV_SCB *p_scbi;
+ tBTM_STATUS ret;
int i;
UINT8 mask;
@@ -1067,7 +1289,12 @@
{
if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scbi->peer_addr);
- if (BTM_CMD_STARTED != BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL))
+ ret = BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL);
+ if ((ret == BTM_REPEATED_ATTEMPTS) ||
+ ((ret == BTM_NO_RESOURCES) && btm_is_sco_active_by_bdaddr(p_scbi->peer_addr)))
+ return FALSE;
+
+ if (BTM_CMD_STARTED != ret)
{
/* can not switch role on SCBI
* start the timer on SCB - because this function is ONLY called when SCB gets API_OPEN */
@@ -1099,18 +1326,27 @@
{
UINT8 role;
BOOLEAN is_ok = TRUE;
+ tBTM_STATUS ret;
if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS)
{
- LOG_INFO(LOG_TAG, "%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
+ LOG_INFO("%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
__func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits,
bta_av_cb.features);
if (BTM_ROLE_MASTER != role && (A2D_BitsSet(bta_av_cb.conn_audio) > bits || (bta_av_cb.features & BTA_AV_FEAT_MASTER)))
{
if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scb->peer_addr);
+ ret = BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL);
+ /* We have already reached maximum attempts,
+ * If we try again it will anyways fail
+ * return from here
+ * */
+ if ((ret == BTM_REPEATED_ATTEMPTS) ||
+ ((ret == BTM_NO_RESOURCES) && btm_is_sco_active_by_bdaddr(p_scb->peer_addr)))
+ return TRUE;
- if (BTM_CMD_STARTED != BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL))
+ if (BTM_CMD_STARTED != ret)
{
/* can not switch role on SCB - start the timer on SCB */
}
@@ -1276,6 +1512,7 @@
APPL_TRACE_VERBOSE("AV nsm event=0x%x", event);
#endif
/* non state machine events */
+
(*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg);
}
else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT)
@@ -1298,6 +1535,20 @@
return TRUE;
}
+/*******************************************************************************
+**
+** Function bta_av_is_multicast_enabled
+**
+** Description return status of Avdtp multicast
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_av_is_multicast_enabled()
+{
+ return is_multicast_enabled;
+}
/*****************************************************************************
** Debug Functions
*****************************************************************************/
@@ -1397,6 +1648,7 @@
#endif
case BTA_AV_API_START_EVT: return "API_START";
case BTA_AV_API_STOP_EVT: return "API_STOP";
+ case BTA_AV_ENABLE_MULTICAST_EVT: return "MULTICAST_ENABLE";
default: return "unknown";
}
}
diff --git a/bta/av/bta_av_ssm.c b/bta/av/bta_av_ssm.c
index 6ad8bcd..71f508c 100644
--- a/bta/av/bta_av_ssm.c
+++ b/bta/av/bta_av_ssm.c
@@ -172,7 +172,7 @@
/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP,BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
-/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
/* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
@@ -186,7 +186,7 @@
/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
-/* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ, BTA_AV_CLOSING_SST },
+/* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST},
/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
@@ -210,7 +210,7 @@
/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
/* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
-/* SDP_DISC_FAIL_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
/* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
/* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
@@ -449,18 +449,58 @@
}
}
-#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
- APPL_TRACE_VERBOSE("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)",
- p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state));
-#else
- APPL_TRACE_VERBOSE("AV Sevent=0x%x state=%d", event, p_scb->state);
-#endif
+ if ((event != BTA_AV_STR_WRITE_CFM_EVT) && (event != BTA_AV_SRC_DATA_READY_EVT))
+ {
+ #if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE)
+ APPL_TRACE_IMP("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)",
+ p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state));
+ #else
+ APPL_TRACE_IMP("AV Sevent=0x%x state=%d", event, p_scb->state);
+ #endif
+ }
/* look up the state table for the current state */
state_table = bta_av_sst_tbl[p_scb->state];
event -= BTA_AV_FIRST_SSM_EVT;
+ if((p_scb->state != BTA_AV_OPENING_SST) &&
+ (state_table[event][BTA_AV_SNEXT_STATE] == BTA_AV_OPENING_SST))
+ {
+ AVDT_UpdateServiceBusyState(TRUE);
+ }
+ else if(AVDT_GetServiceBusyState() == TRUE)
+ {
+ BOOLEAN keep_busy = TRUE;
+
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if (bta_av_cb.p_scb[xx])
+ {
+ if ((bta_av_cb.p_scb[xx]->state == BTA_AV_OPENING_SST) &&
+ (bta_av_cb.p_scb[xx] != p_scb))
+ {
+ /* There is other SCB in opening state
+ * keep the service state in progress
+ */
+ APPL_TRACE_VERBOSE("SCB in opening state. Keep Busy");
+ keep_busy = TRUE;
+ break;
+ }
+ else if ((bta_av_cb.p_scb[xx]->state == BTA_AV_OPENING_SST) &&
+ (bta_av_cb.p_scb[xx] == p_scb) &&
+ (state_table[event][BTA_AV_SNEXT_STATE] != BTA_AV_OPENING_SST))
+ {
+ keep_busy = FALSE;
+ }
+ }
+ }
+ if (keep_busy == FALSE)
+ {
+ AVDT_UpdateServiceBusyState(FALSE);
+ }
+ }
+
/* set next state */
p_scb->state = state_table[event][BTA_AV_SNEXT_STATE];
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
index e361970..0b71da2 100644
--- a/bta/dm/bta_dm_act.c
+++ b/bta/dm/bta_dm_act.c
@@ -45,6 +45,7 @@
#include "osi/include/osi.h"
#include "sdp_api.h"
#include "utl.h"
+#include "device/include/interop_config.h"
#if (GAP_INCLUDED == TRUE)
#include "gap_api.h"
@@ -106,6 +107,8 @@
static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
#endif
+static void bta_dm_ext_adv_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
+
#ifndef BTA_DM_BLE_ADV_CHNL_MAP
#define BTA_DM_BLE_ADV_CHNL_MAP (BTM_BLE_ADV_CHNL_37|BTM_BLE_ADV_CHNL_38|BTM_BLE_ADV_CHNL_39)
#endif
@@ -306,17 +309,6 @@
*******************************************************************************/
void bta_dm_init_cb(void)
{
- /*
- * TODO: Should alarm_free() the bta_dm_cb timers during graceful
- * shutdown.
- */
- alarm_free(bta_dm_cb.disable_timer);
- alarm_free(bta_dm_cb.switch_delay_timer);
- for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
- for (size_t j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
- alarm_free(bta_dm_cb.pm_timer[i].timer[j]);
- }
- }
memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
bta_dm_cb.disable_timer = alarm_new("bta_dm.disable_timer");
bta_dm_cb.switch_delay_timer = alarm_new("bta_dm.switch_delay_timer");
@@ -329,6 +321,32 @@
/*******************************************************************************
**
+** Function bta_dm_deinit_cb
+**
+** Description De-initializes the bta_dm_cb control block
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_deinit_cb(void)
+{
+ /*
+ * TODO: Should alarm_free() the bta_dm_cb timers during graceful
+ * shutdown.
+ */
+ alarm_free(bta_dm_cb.disable_timer);
+ alarm_free(bta_dm_cb.switch_delay_timer);
+ for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ for (size_t j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ alarm_free(bta_dm_cb.pm_timer[i].timer[j]);
+ }
+ }
+ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+}
+
+/*******************************************************************************
+**
** Function bta_dm_sys_hw_cback
**
** Description callback register to SYS to get HW status updates
@@ -362,7 +380,12 @@
bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
/* reinitialize the control block */
- bta_dm_init_cb();
+ bta_dm_deinit_cb();
+
+ /* hw is ready, go on with BTA DM initialization */
+ alarm_free(bta_dm_search_cb.search_timer);
+ alarm_free(bta_dm_search_cb.gatt_close_timer);
+ memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
/* unregister from SYS */
bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH );
@@ -385,8 +408,6 @@
bta_dm_cb.is_bta_dm_active = TRUE;
/* hw is ready, go on with BTA DM initialization */
- alarm_free(bta_dm_search_cb.search_timer);
- alarm_free(bta_dm_search_cb.gatt_close_timer);
memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
/*
* TODO: Should alarm_free() the bta_dm_search_cb timers during
@@ -431,6 +452,9 @@
BTM_BleReadControllerFeatures (bta_dm_ctrl_features_rd_cmpl_cback);
#endif
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ BTM_BleReadExtAdvControllerFeatures (bta_dm_ext_adv_ctrl_features_rd_cmpl_cback);
+#endif
/* Earlier, we used to invoke BTM_ReadLocalAddr which was just copying the bd_addr
from the control block and invoking the callback which was sending the DM_ENABLE_EVT.
But then we have a few HCI commands being invoked above which were still in progress
@@ -469,6 +493,7 @@
void bta_dm_disable (tBTA_DM_MSG *p_data)
{
UNUSED(p_data);
+ int soc_type = get_soc_type();
/* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after last channel is closed) */
L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0, BT_TRANSPORT_BR_EDR);
@@ -488,6 +513,18 @@
BTM_BleClearBgConnDev();
#endif
+ /* Disable SOC Logging */
+ if (soc_type == BT_SOC_SMD)
+ {
+ UINT8 param[5] = {0x10, 0x02, 0x00, 0x00, 0x01};
+ BTM_VendorSpecificCommand(HCI_VS_HOST_LOG_OPCODE, 5, param, NULL);
+ }
+ else if (soc_type == BT_SOC_CHEROKEE)
+ {
+ UINT8 param_cherokee[2] = {0x14, 0x00};
+ BTM_VendorSpecificCommand(HCI_VS_HOST_LOG_OPCODE, 2, param_cherokee, NULL);
+ }
+
if(BTM_GetNumAclLinks()==0)
{
#if (defined(BTA_DISABLE_DELAY) && BTA_DISABLE_DELAY > 0)
@@ -558,7 +595,7 @@
bta_dm_cb.disabling = FALSE;
bta_sys_remove_uuid(UUID_SERVCLASS_PNP_INFORMATION);
- bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+ bta_dm_disable_conn_down_timer_cback(NULL);
}
}
@@ -665,7 +702,47 @@
/*******************************************************************************
**
-** Function bta_dm_process_remove_device
+** Function bta_dm_hci_raw_command
+**
+** Description Send a HCI RAW command to the controller
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_hci_raw_command (tBTA_DM_MSG *p_data)
+{
+ tBTM_STATUS status;
+ APPL_TRACE_API("bta_dm_hci_raw_command");
+ status = BTM_Hci_Raw_Command(p_data->btc_command.opcode,p_data->btc_command.param_len,p_data->btc_command.p_param_buf, p_data->btc_command.p_cback);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_vendor_spec_command
+**
+** Description Send a vendor specific command to the controller
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_vendor_spec_command (tBTA_DM_MSG *p_data)
+{
+ APPL_TRACE_API("bta_dm_vendor_spec_command");
+ BTM_VendorSpecificCommand(p_data->vendor_command.opcode,
+ p_data->vendor_command.param_len,
+ p_data->vendor_command.p_param_buf,
+ p_data->vendor_command.p_cback);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_process_remove_deviced
+**
+**
+** Returns void
**
** Description Removes device, Disconnects ACL link if required.
****
@@ -712,8 +789,11 @@
bdcpy(other_address, p_dev->bd_addr);
/* If ACL exists for the device in the remove_bond message*/
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, p_dev->bd_addr);
BOOLEAN continue_delete_dev = FALSE;
UINT8 other_transport = BT_TRANSPORT_INVALID;
+ interop_database_remove_addr(INTEROP_DYNAMIC_ROLE_SWITCH, (bt_bdaddr_t *)&remote_bdaddr);
if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR))
@@ -763,9 +843,13 @@
/* Take the link down first, and mark the device for removal when disconnected */
for(int i=0; i < bta_dm_cb.device_list.count; i++)
{
- if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, other_address))
+ if ((!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, other_address))&&
+ ((other_transport && (other_transport == bta_dm_cb.device_list.peer_device[i].transport)) ||
+ !other_transport))
{
bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
+ APPL_TRACE_DEBUG("%s:transport = %d ,other_transport = %d", __func__,
+ bta_dm_cb.device_list.peer_device[i].transport, other_transport);
btm_remove_acl(other_address,bta_dm_cb.device_list.peer_device[i].transport);
break;
}
@@ -2185,6 +2269,8 @@
/* no more services to be discovered */
if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) {
tBTA_DM_MSG *p_msg = (tBTA_DM_MSG *)osi_malloc(sizeof(tBTA_DM_MSG));
+ /* initialize the data structure - includes p_raw_data and raw_data_size */
+ memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
bdcpy(p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
@@ -2323,10 +2409,12 @@
/* check whether connection already exists to the device
if connection exists, we don't have to wait for ACL
link to go down to start search on next device */
- if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR))
- bta_dm_search_cb.wait_disc = FALSE;
- else
- bta_dm_search_cb.wait_disc = TRUE;
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR))
+ bta_dm_search_cb.wait_disc = FALSE;
+ else
+ bta_dm_search_cb.wait_disc = TRUE;
+ }
#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
if ( bta_dm_search_cb.p_btm_inq_info )
@@ -2427,6 +2515,7 @@
result.inq_res.device_type = p_inq->device_type;
result.inq_res.flag = p_inq->flag;
#endif
+ result.inq_res.adv_data_len = p_inq->adv_data_len;
/* application will parse EIR to find out remote device name */
result.inq_res.p_eir = p_eir;
@@ -2670,6 +2759,12 @@
/* 1 additional event data fields for this event */
sec_event.cfm_req.just_works = bta_dm_cb.just_works;
+ /* retrieve the loc and rmt caps */
+ sec_event.cfm_req.loc_io_caps = bta_dm_cb.loc_io_caps;
+ sec_event.cfm_req.rmt_io_caps = bta_dm_cb.rmt_io_caps;
+ sec_event.cfm_req.loc_auth_req = bta_dm_cb.loc_auth_req;
+ sec_event.cfm_req.rmt_auth_req = bta_dm_cb.rmt_auth_req;
+
}
else
{
@@ -2881,16 +2976,21 @@
/*case BTM_SP_KEY_REQ_EVT: */
case BTM_SP_KEY_NOTIF_EVT:
#endif
- bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey;
if(BTM_SP_CFM_REQ_EVT == event)
{
+ bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->cfm_req.num_val;
/* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT,
call remote name request using values from cfm_req */
if(p_data->cfm_req.bd_name[0] == 0)
{
bta_dm_cb.pin_evt = pin_evt;
bdcpy(bta_dm_cb.pin_bd_addr, p_data->cfm_req.bd_addr);
+ bta_dm_cb.rmt_io_caps = sec_event.cfm_req.rmt_io_caps;
+ bta_dm_cb.loc_io_caps = sec_event.cfm_req.loc_io_caps;
+ bta_dm_cb.rmt_auth_req = sec_event.cfm_req.rmt_auth_req;
+ bta_dm_cb.loc_auth_req = sec_event.cfm_req.loc_auth_req;
+
BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->cfm_req.dev_class);
if ((BTM_ReadRemoteDeviceName(p_data->cfm_req.bd_addr, bta_dm_pinname_cback,
BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
@@ -2910,11 +3010,16 @@
if (BTM_SP_KEY_NOTIF_EVT == event)
{
+
+ bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey;
/* If the device name is not known, save bdaddr and devclass
and initiate a name request with values from key_notif */
if(p_data->key_notif.bd_name[0] == 0)
{
bta_dm_cb.pin_evt = pin_evt;
+ /* Store the local and remote io caps */
+ bta_dm_cb.loc_io_caps = sec_event.cfm_req.loc_io_caps;
+ bta_dm_cb.rmt_io_caps = sec_event.cfm_req.rmt_io_caps;
bdcpy(bta_dm_cb.pin_bd_addr, p_data->key_notif.bd_addr);
BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->key_notif.dev_class);
if ((BTM_ReadRemoteDeviceName(p_data->key_notif.bd_addr, bta_dm_pinname_cback,
@@ -3236,9 +3341,12 @@
{
if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE)
{
+ /* new acl connection,reset new peer device */
+ memset(&bta_dm_cb.device_list.peer_device[i], 0, sizeof(bta_dm_cb.device_list.peer_device[i]));
bdcpy(bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].peer_bdaddr, p_bda);
bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].link_policy = bta_dm_cb.cur_policy;
bta_dm_cb.device_list.count++;
+ APPL_TRACE_ERROR("%s new acl connetion:count = %d", __func__, bta_dm_cb.device_list.count);
#if BLE_INCLUDED == TRUE
bta_dm_cb.device_list.peer_device[i].conn_handle = p_data->acl_change.handle;
if (p_data->acl_change.transport == BT_TRANSPORT_LE)
@@ -3289,10 +3397,12 @@
conn.link_down.is_removed = bta_dm_cb.device_list.peer_device[i].remove_dev_pending;
- for(; i<bta_dm_cb.device_list.count ; i++)
+ /* acl disconnection,remove peer device entry and reset last entry */
+ for(; i < (bta_dm_cb.device_list.count - 1); i++)
{
memcpy(&bta_dm_cb.device_list.peer_device[i], &bta_dm_cb.device_list.peer_device[i+1], sizeof(bta_dm_cb.device_list.peer_device[i]));
}
+ memset(&bta_dm_cb.device_list.peer_device[i], 0, sizeof(bta_dm_cb.device_list.peer_device[i]));
break;
}
if(bta_dm_cb.device_list.count)
@@ -3304,7 +3414,8 @@
conn.link_down.link_type = p_data->acl_change.transport;
#endif
- if(bta_dm_search_cb.wait_disc && !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda))
+ if ((p_data->acl_change.transport == BT_TRANSPORT_BR_EDR) &&
+ bta_dm_search_cb.wait_disc && !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda))
{
bta_dm_search_cb.wait_disc = FALSE;
@@ -4269,7 +4380,6 @@
;
tBTA_DM_SEARCH result;
tBTM_INQ_INFO *p_inq_info;
- APPL_TRACE_DEBUG("bta_dm_observe_results_cb")
bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
result.inq_res.rssi = p_inq->rssi;
@@ -4277,6 +4387,7 @@
result.inq_res.inq_result_type = p_inq->inq_result_type;
result.inq_res.device_type = p_inq->device_type;
result.inq_res.flag = p_inq->flag;
+ result.inq_res.adv_data_len = p_inq->adv_data_len;
/* application will parse EIR to find out remote device name */
result.inq_res.p_eir = p_eir;
@@ -4393,7 +4504,11 @@
case BTM_LE_NC_REQ_EVT:
bdcpy(sec_event.key_notif.bd_addr, bda);
- strlcpy((char*)sec_event.key_notif.bd_name, bta_dm_get_remname(), (BD_NAME_LEN));
+ char* bd_name = BTM_SecReadDevName(bda);
+ if (bd_name)
+ strlcpy((char*)sec_event.key_notif.bd_name, bd_name, (BD_NAME_LEN));
+ else
+ strlcpy((char*)sec_event.key_notif.bd_name, bta_dm_get_remname(), (BD_NAME_LEN));
sec_event.key_notif.passkey = p_data->key_notif;
bta_dm_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event);
break;
@@ -4430,8 +4545,7 @@
else
{
sec_event.auth_cmpl.success = TRUE;
- if (!p_data->complt.smp_over_br)
- GATT_ConfigServiceChangeCCC(bda, TRUE, BT_TRANSPORT_LE);
+ sec_event.auth_cmpl.smp_over_br = p_data->complt.smp_over_br;
}
if (bta_dm_cb.p_sec_cback)
@@ -4640,8 +4754,11 @@
void bta_dm_ble_set_scan_params(tBTA_DM_MSG *p_data)
{
BTM_BleSetScanParams(p_data->ble_set_scan_params.client_if,
+ p_data->ble_set_scan_params.scan_phys,
p_data->ble_set_scan_params.scan_int,
p_data->ble_set_scan_params.scan_window,
+ p_data->ble_set_scan_params.scan_int_coded,
+ p_data->ble_set_scan_params.scan_window_coded,
p_data->ble_set_scan_params.scan_mode,
p_data->ble_set_scan_params.scan_param_setup_cback);
}
@@ -4714,6 +4831,7 @@
/*Save the callback to be called when a scan results are available */
bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback;
if ((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration,
+ p_data->ble_observe.period,
bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb))!= BTM_CMD_STARTED)
{
tBTA_DM_SEARCH data;
@@ -4728,7 +4846,7 @@
else
{
bta_dm_search_cb.p_scan_cback = NULL;
- BTM_BleObserve(FALSE, 0, NULL,NULL );
+ BTM_BleObserve(FALSE, 0, p_data->ble_observe.period, NULL, NULL );
}
}
/*******************************************************************************
@@ -4814,6 +4932,43 @@
/*******************************************************************************
**
+** Function bta_dm_ble_set_phy
+**
+** Description This function sets the tx and rx phy for a connection
+**
+** Parameters
+**
+*******************************************************************************/
+void bta_dm_ble_set_phy(tBTA_DM_MSG *p_data)
+{
+ if (BTM_SetBlePhy(p_data->ble_set_phy.remote_bda, p_data->ble_set_phy.all_phy,
+ p_data->ble_set_phy.tx_phy, p_data->ble_set_phy.rx_phy,
+ p_data->ble_set_phy.phy_options) != BTM_SUCCESS)
+ {
+ APPL_TRACE_ERROR("%s failed", __func__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_ble_set_default_phy
+**
+** Description This function sets the default tx and rx phy
+**
+** Parameters
+**
+*******************************************************************************/
+void bta_dm_ble_set_default_phy(tBTA_DM_MSG *p_data)
+{
+ if (BTM_SetDefaultBlePhy(p_data->ble_set_default_phy.all_phy,
+ p_data->ble_set_default_phy.tx_phy, p_data->ble_set_default_phy.rx_phy) != BTM_SUCCESS)
+ {
+ APPL_TRACE_ERROR("%s failed", __func__);
+ }
+}
+
+/*******************************************************************************
+**
** Function bta_dm_ble_broadcast
**
** Description Starts or stops LE broadcasts
@@ -4903,6 +5058,7 @@
btm_status = BTM_BleCfgAdvInstData(p_data->ble_multi_adv_data.inst_id,
p_data->ble_multi_adv_data.is_scan_rsp,
p_data->ble_multi_adv_data.data_mask,
+ p_data->ble_multi_adv_data.frag_pref,
(tBTM_BLE_ADV_DATA*)&p_data->ble_multi_adv_data.data);
}
@@ -5316,7 +5472,7 @@
#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT
-#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000
+#define BTA_DM_GATT_CLOSE_DELAY_TOUT 5000
#endif
/*******************************************************************************
@@ -5667,5 +5823,28 @@
}
#endif /* BLE_VND_INCLUDED */
+/*******************************************************************************
+**
+** Function bta_dm_ext_adv_ctrl_features_rd_cmpl_cback
+**
+** Description callback to handle controller feature read complete
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_dm_ext_adv_ctrl_features_rd_cmpl_cback(tBTM_STATUS result)
+{
+ APPL_TRACE_DEBUG("%s status = %d ", __FUNCTION__, result);
+ if (result == BTM_SUCCESS)
+ {
+ if(bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_LE_ADV_EXT_FEATURES_READ, NULL);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("%s Ctrl BLE ADV EXT feature read failed: status :%d",__FUNCTION__, result);
+ }
+
+}
#endif /* BLE_INCLUDED */
diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c
index 82dd8b2..42167ae 100644
--- a/bta/dm/bta_dm_api.c
+++ b/bta/dm/bta_dm_api.c
@@ -65,8 +65,6 @@
if (bta_dm_cb.disabling)
return BTA_FAILURE;
- bta_dm_init_cb();
-
bta_sys_register(BTA_ID_DM, &bta_dm_reg );
bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg );
@@ -194,6 +192,95 @@
/*******************************************************************************
**
+** Function BTA_DmHciRawCommand
+**
+** Description This function sends the HCI Raw command
+** to the controller
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmHciRawCommand (UINT16 opcode, UINT8 param_len,
+ UINT8 *p_param_buf,
+ tBTA_RAW_CMPL_CBACK *p_cback)
+{
+
+ tBTA_DM_API_RAW_COMMAND *p_msg;
+ UINT16 size;
+
+ size = sizeof (tBTA_DM_API_RAW_COMMAND) + param_len;
+ p_msg = (tBTA_DM_API_RAW_COMMAND *) osi_malloc(size);
+ if (p_msg != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_HCI_RAW_COMMAND_EVT;
+ p_msg->opcode = opcode;
+ p_msg->param_len = param_len;
+ p_msg->p_param_buf = (UINT8 *)(p_msg + 1);
+ p_msg->p_cback = p_cback;
+
+ memcpy (p_msg->p_param_buf, p_param_buf, param_len);
+
+ bta_sys_sendmsg(p_msg);
+ }
+ return BTA_SUCCESS;
+
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmVendorSpecificCommand
+**
+** Description This function sends the vendor specific command
+** to the controller
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, UINT8 param_len,
+ UINT8 *p_param_buf,
+ tBTA_VENDOR_CMPL_CBACK *p_cback)
+{
+
+ tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *p_msg;
+ UINT16 size;
+
+ /* If p_cback is NULL, Notify application */
+ if (p_cback == NULL)
+ {
+ return (BTA_FAILURE);
+ }
+ else
+ {
+ size = sizeof (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND) + param_len;
+ if ((p_msg = (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *) osi_malloc(size)) != NULL)
+ {
+ p_msg->hdr.event = BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT;
+ p_msg->opcode = opcode;
+ p_msg->p_param_buf = (UINT8 *)(p_msg + 1);
+ p_msg->p_cback = p_cback;
+
+ if (p_param_buf && param_len)
+ {
+ memcpy (p_msg->p_param_buf, p_param_buf, param_len);
+ p_msg->param_len = param_len;
+ }
+ else
+ {
+ p_msg->param_len = 0;
+ p_msg->p_param_buf = NULL;
+
+ }
+
+ bta_sys_sendmsg(p_msg);
+ }
+ return (BTA_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
** Function BTA_DmSearch
**
** Description This function searches for peer Bluetooth devices. It performs
@@ -847,10 +934,10 @@
** Returns void
**
*******************************************************************************/
-
#if BLE_INCLUDED == TRUE
-void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
- UINT32 scan_window, tBLE_SCAN_MODE scan_mode,
+void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT8 scan_phys, UINT32 scan_interval,
+ UINT32 scan_window, UINT16 scan_interval_coded,
+ UINT16 scan_window_coded, tBLE_SCAN_MODE scan_mode,
tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback)
{
tBTA_DM_API_BLE_SCAN_PARAMS *p_msg =
@@ -858,11 +945,14 @@
p_msg->hdr.event = BTA_DM_API_BLE_SCAN_PARAM_EVT;
p_msg->client_if = client_if;
+ p_msg->scan_phys = scan_phys;
p_msg->scan_int = scan_interval;
p_msg->scan_window = scan_window;
+ p_msg->scan_int_coded = scan_interval_coded;
+ p_msg->scan_window_coded = scan_window_coded;
+
p_msg->scan_mode = scan_mode;
p_msg->scan_param_setup_cback = scan_param_setup_cback;
-
bta_sys_sendmsg(p_msg);
}
#endif // BLE_INCLUDED == TRUE
@@ -1456,18 +1546,19 @@
**
*******************************************************************************/
void BTA_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp,
- tBTA_BLE_AD_MASK data_mask,
+ tBTA_BLE_AD_MASK data_mask, UINT8 frag_pref,
tBTA_BLE_ADV_DATA *p_data)
{
- tBTA_DM_API_BLE_MULTI_ADV_DATA *p_msg = osi_calloc(sizeof(*p_msg));
+ tBTA_DM_API_BLE_MULTI_ADV_DATA *p_msg = osi_calloc(sizeof(*p_msg));
- p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_DATA_EVT;
- p_msg->inst_id = inst_id;
- p_msg->is_scan_rsp = is_scan_rsp;
- p_msg->data_mask = data_mask;
- memcpy(&p_msg->data, p_data, sizeof(p_msg->data));
+ p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_DATA_EVT;
+ p_msg->inst_id = inst_id;
+ p_msg->is_scan_rsp = is_scan_rsp;
+ p_msg->data_mask = data_mask;
+ memcpy(&p_msg->data, p_data, sizeof(p_msg->data));
+ p_msg->frag_pref = frag_pref;
- bta_sys_sendmsg(p_msg);
+ bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
@@ -1793,6 +1884,59 @@
bta_sys_sendmsg(p_msg);
}
+/*******************************************************************************
+**
+** Function BTA_DmBleSetPhy
+**
+** Description This function is to set Tx and Rx Phy for a connection
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBleSetPhy(BD_ADDR remote_device, UINT8 all_phy, UINT8 tx_phy,
+ UINT8 rx_phy, UINT16 phy_options)
+{
+ tBTA_DM_API_BLE_SET_PHY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BLE_SET_PHY *)osi_malloc(sizeof(tBTA_DM_API_BLE_SET_PHY)))
+ != NULL)
+ {
+ bdcpy(p_msg->remote_bda, remote_device);
+ p_msg->all_phy = all_phy;
+ p_msg->tx_phy = tx_phy;
+ p_msg->rx_phy = rx_phy;
+ p_msg->phy_options = phy_options;
+ p_msg->hdr.event = BTA_DM_API_SET_BLE_PHY_EVT;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_DmBleSetDefaultPhy
+**
+** Description This function is to set default Tx and Rx Phy
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_DmBleSetDefaultPhy(UINT8 all_phy, UINT8 tx_phy, UINT8 rx_phy)
+{
+ tBTA_DM_API_BLE_SET_DEFAULT_PHY *p_msg;
+
+ if ((p_msg = (tBTA_DM_API_BLE_SET_DEFAULT_PHY *)osi_malloc(sizeof(tBTA_DM_API_BLE_SET_DEFAULT_PHY)))
+ != NULL)
+ {
+ p_msg->all_phy = all_phy;
+ p_msg->tx_phy = tx_phy;
+ p_msg->rx_phy = rx_phy;
+ p_msg->hdr.event = BTA_DM_API_SET_DEFAULT_BLE_PHY_EVT;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
#endif
/*******************************************************************************
@@ -1877,7 +2021,7 @@
** Returns void.
**
*******************************************************************************/
-extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration,
+extern void BTA_DmBleObserve(BOOLEAN start, UINT16 duration, UINT16 period,
tBTA_DM_SEARCH_CBACK *p_results_cb)
{
tBTA_DM_API_BLE_OBSERVE *p_msg =
@@ -1888,6 +2032,7 @@
p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT;
p_msg->start = start;
p_msg->duration = duration;
+ p_msg->period = period;
p_msg->p_cback = p_results_cb;
bta_sys_sendmsg(p_msg);
diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c
index 744a6fc..b5a6d41 100644
--- a/bta/dm/bta_dm_cfg.c
+++ b/bta/dm/bta_dm_cfg.c
@@ -56,6 +56,15 @@
#define tBTA_DM_PM_TYPE_QUALIFIER
#endif
+/* Reduce Idle timeout value due to intermediate timer */
+#ifndef BTA_JVS_IDLE_TO_SNIFF_DELAY_MS
+#define BTA_JVS_IDLE_TO_SNIFF_DELAY_MS (BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS - BTA_JV_IDLE_TIMEOUT_MS)
+#endif
+
+#ifndef BTA_JVC_IDLE_TO_SNIFF_DELAY_MS
+#define BTA_JVC_IDLE_TO_SNIFF_DELAY_MS (5000 - BTA_JV_IDLE_TIMEOUT_MS)
+#endif
+
const tBTA_DM_CFG bta_dm_cfg =
{
@@ -170,7 +179,7 @@
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
{{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
- {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_RETRY, 7000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
@@ -284,7 +293,7 @@
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
- {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_JVC_IDLE_TO_SNIFF_DELAY_MS}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
@@ -303,7 +312,7 @@
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
- {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_JVS_IDLE_TO_SNIFF_DELAY_MS}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
@@ -495,6 +504,7 @@
{BTA_DM_PM_SNIFF3_MAX, BTA_DM_PM_SNIFF3_MIN, BTA_DM_PM_SNIFF3_ATTEMPT, BTA_DM_PM_SNIFF3_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF3- SCO open */
{BTA_DM_PM_SNIFF4_MAX, BTA_DM_PM_SNIFF4_MIN, BTA_DM_PM_SNIFF4_ATTEMPT, BTA_DM_PM_SNIFF4_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF4- HD active */
{BTA_DM_PM_SNIFF5_MAX, BTA_DM_PM_SNIFF5_MIN, BTA_DM_PM_SNIFF5_ATTEMPT, BTA_DM_PM_SNIFF5_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF5- HD active */
+ {BTA_DM_PM_SNIFF6_MAX, BTA_DM_PM_SNIFF6_MIN, BTA_DM_PM_SNIFF6_ATTEMPT, BTA_DM_PM_SNIFF6_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF6- HH active */
{BTA_DM_PM_PARK_MAX, BTA_DM_PM_PARK_MIN, BTA_DM_PM_PARK_ATTEMPT, BTA_DM_PM_PARK_TIMEOUT, BTM_PM_MD_PARK}
#ifdef BTE_SIM_APP /* For Insight builds only */
diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h
index a5fe0ad..3e8a2422 100644
--- a/bta/dm/bta_dm_int.h
+++ b/bta/dm/bta_dm_int.h
@@ -98,6 +98,8 @@
BTA_DM_API_BLE_SET_SCAN_RSP_EVT,
BTA_DM_API_BLE_BROADCAST_EVT,
BTA_DM_API_SET_DATA_LENGTH_EVT,
+ BTA_DM_API_SET_BLE_PHY_EVT,
+ BTA_DM_API_SET_DEFAULT_BLE_PHY_EVT,
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
BTA_DM_API_CFG_FILTER_COND_EVT,
@@ -122,6 +124,8 @@
BTA_DM_API_EXECUTE_CBACK_EVT,
BTA_DM_API_REMOVE_ALL_ACL_EVT,
BTA_DM_API_REMOVE_DEVICE_EVT,
+ BTA_DM_API_HCI_RAW_COMMAND_EVT,
+ BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT,
BTA_DM_MAX_EVT
};
@@ -167,6 +171,26 @@
UINT8 conn_paired_only;
} tBTA_DM_API_SET_VISIBILITY;
+/* data type for BTA_DM_API_HCI_RAW_COMMAND_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 opcode;
+ UINT8 param_len;
+ UINT8 *p_param_buf;
+ tBTA_RAW_CMPL_CBACK *p_cback;
+} tBTA_DM_API_RAW_COMMAND;
+
+/* data type for BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 opcode;
+ UINT8 param_len;
+ UINT8 *p_param_buf;
+ tBTA_VENDOR_CMPL_CBACK *p_cback;
+} tBTA_DM_API_VENDOR_SPECIFIC_COMMAND;
+
enum
{
BTA_DM_RS_NONE, /* straight API call */
@@ -458,8 +482,11 @@
{
BT_HDR hdr;
tBTA_GATTC_IF client_if;
+ UINT8 scan_phys;
UINT32 scan_int;
UINT32 scan_window;
+ UINT16 scan_int_coded;
+ UINT16 scan_window_coded;
tBLE_SCAN_MODE scan_mode;
tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback;
}tBTA_DM_API_BLE_SCAN_PARAMS;
@@ -478,6 +505,7 @@
BT_HDR hdr;
BOOLEAN start;
UINT16 duration;
+ UINT16 period;
tBTA_DM_SEARCH_CBACK * p_cback;
}tBTA_DM_API_BLE_OBSERVE;
@@ -488,6 +516,24 @@
UINT16 tx_data_length;
}tBTA_DM_API_BLE_SET_DATA_LENGTH;
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ UINT8 all_phy;
+ UINT8 tx_phy;
+ UINT8 rx_phy;
+ UINT16 phy_options;
+}tBTA_DM_API_BLE_SET_PHY;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 all_phy;
+ UINT8 tx_phy;
+ UINT8 rx_phy;
+}tBTA_DM_API_BLE_SET_DEFAULT_PHY;
+
/* set adv parameter for BLE advertising */
typedef struct
{
@@ -527,6 +573,7 @@
BOOLEAN is_scan_rsp;
tBTA_BLE_AD_MASK data_mask;
tBTA_BLE_ADV_DATA data;
+ UINT8 frag_pref;
}tBTA_DM_API_BLE_MULTI_ADV_DATA;
typedef struct
@@ -724,6 +771,8 @@
#endif
tBTA_DM_API_UPDATE_CONN_PARAM ble_update_conn_params;
tBTA_DM_API_BLE_SET_DATA_LENGTH ble_set_data_length;
+ tBTA_DM_API_BLE_SET_PHY ble_set_phy;
+ tBTA_DM_API_BLE_SET_DEFAULT_PHY ble_set_default_phy;
tBTA_DM_API_BLE_MULTI_ADV_ENB ble_multi_adv_enb;
tBTA_DM_API_BLE_MULTI_ADV_PARAM ble_multi_adv_param;
@@ -740,11 +789,16 @@
tBTA_DM_API_REMOVE_ACL remove_acl;
tBTA_DM_API_REMOVE_ALL_ACL remove_all_acl;
-
+ tBTA_DM_API_RAW_COMMAND btc_command;
+ tBTA_DM_API_VENDOR_SPECIFIC_COMMAND vendor_command;
} tBTA_DM_MSG;
-
+#ifndef MAX_ACL_CONNECTIONS
#define BTA_DM_NUM_PEER_DEVICE 7
+#else
+#define BTA_DM_NUM_PEER_DEVICE MAX_ACL_CONNECTIONS
+#endif
+
#define BTA_DM_NOT_CONNECTED 0
#define BTA_DM_CONNECTED 1
@@ -885,6 +939,10 @@
BD_ADDR pin_bd_addr;
DEV_CLASS pin_dev_class;
tBTA_DM_SEC_EVT pin_evt;
+ tBTA_IO_CAP loc_io_caps; /* IO Capabilities of local device */
+ tBTA_IO_CAP rmt_io_caps; /* IO Capabilities of remote device */
+ tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+ tBTA_AUTH_REQ rmt_auth_req;
UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */
BOOLEAN just_works; /* TRUE, if "Just Works" association model */
#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )
@@ -1115,6 +1173,8 @@
extern void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data);
extern void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data);
extern void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_set_phy(tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_set_default_phy(tBTA_DM_MSG *p_data);
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
extern void bta_dm_cfg_filter_cond (tBTA_DM_MSG *p_data);
@@ -1175,4 +1235,5 @@
extern void bta_dm_remove_all_acl(tBTA_DM_MSG *p_data);
+extern void bta_dm_hci_raw_command(tBTA_DM_MSG *p_data);
#endif /* BTA_DM_INT_H */
diff --git a/bta/dm/bta_dm_main.c b/bta/dm/bta_dm_main.c
index e6d791a..4e51183 100644
--- a/bta/dm/bta_dm_main.c
+++ b/bta/dm/bta_dm_main.c
@@ -96,6 +96,8 @@
bta_dm_ble_set_scan_rsp, /* BTA_DM_API_BLE_SET_SCAN_RSPT */
bta_dm_ble_broadcast, /* BTA_DM_API_BLE_BROADCAST_EVT */
bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */
+ bta_dm_ble_set_phy, /* BTA_DM_API_SET_BLE_PHY_EVT */
+ bta_dm_ble_set_default_phy, /* BTA_DM_API_SET_BLE_DEFAULT_PHY_EVT */
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
bta_dm_cfg_filter_cond, /* BTA_DM_API_CFG_FILTER_COND_EVT */
bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */
@@ -119,6 +121,8 @@
bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */
bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */
+ bta_dm_hci_raw_command, /* BTA_DM_API_HCI_RAW_COMMAND_EVT */
+ bta_dm_vendor_spec_command,/* BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */
};
@@ -358,7 +362,7 @@
/* execute action functions */
for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++)
{
- if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE)
+ if ((action = state_table[p_msg->event & 0x00ff][i]) < BTA_DM_SEARCH_IGNORE)
{
(*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg);
}
diff --git a/bta/dm/bta_dm_pm.c b/bta/dm/bta_dm_pm.c
index bbd4fed..0602022 100644
--- a/bta/dm/bta_dm_pm.c
+++ b/bta/dm/bta_dm_pm.c
@@ -32,6 +32,7 @@
#include "bta_dm_int.h"
#include "btm_api.h"
+#include "device/include/interop.h"
extern fixed_queue_t *btu_bta_alarm_queue;
@@ -46,6 +47,7 @@
static int bta_dm_get_sco_index();
static void bta_dm_pm_hid_check(BOOLEAN bScoActive);
static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable);
+void bta_dm_pm_set_sniff_policy_toggle(BD_ADDR peer_addr, BOOLEAN bDisable);
static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER *p_timer,
UINT8 timer_idx);
@@ -410,6 +412,9 @@
{
bta_dm_conn_srvcs.count--;
+ APPL_TRACE_DEBUG("%s: Removed power mode entry for service id = %d, count = %d",
+ __func__, p_bta_dm_pm_cfg[i].id, bta_dm_conn_srvcs.count);
+
for(; j<bta_dm_conn_srvcs.count ; j++)
{
@@ -442,6 +447,9 @@
bta_dm_conn_srvcs.count++;
bta_dm_conn_srvcs.conn_srvc[j].state = status;
+
+ APPL_TRACE_WARNING("%s: new conn_srvc id:%d, app_id:%d count:%d", __func__,
+ id, app_id, bta_dm_conn_srvcs.count);
}
else
{
@@ -470,7 +478,21 @@
#endif
)
{
- bta_dm_pm_ssr(peer_addr);
+ if( ((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+ ((NULL != (p = BTM_ReadRemoteFeatures (peer_addr))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)))
+ {
+ /* If HID connection open is received and SCO is already active.
+ This will handle the case where HID connects when SCO already active */
+ if ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active())
+ {
+ APPL_TRACE_DEBUG("%s: SCO is Active, disabling SSR on HID link", __func__)
+ BTM_SetSsrParams(peer_addr, 0, 0, 0);
+ }
+ else
+ {
+ bta_dm_pm_ssr(peer_addr);
+ }
+ }
}
else
{
@@ -490,28 +512,53 @@
}
}
}
+
+ /* If HID connection open is received and SCO is already active.
+ disable snii link policy for some devices */
+ if ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active())
+ {
+ /* Check if DUT is slave on SCO Link to decide if sniff needs to be disabled or not */
+ UINT8 role_on_sco_link;
+ BTM_GetRole(bta_dm_conn_srvcs.conn_srvc[bta_dm_get_sco_index()].peer_bdaddr,
+ &role_on_sco_link);
+ APPL_TRACE_DEBUG("%s: Role on SCO Link = %d", __func__, role_on_sco_link);
+ if (role_on_sco_link == BTM_ROLE_SLAVE)
+ {
+ UINT16 manufacturer = 0;
+ UINT16 lmp_sub_version = 0;
+ UINT8 lmp_version = 0;
+ tBTA_DM_PEER_DEVICE *p_rem_dev = NULL;
+ if (BTM_ReadRemoteVersion(peer_addr, &lmp_version,
+ &manufacturer, &lmp_sub_version) == BTM_SUCCESS) {
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, peer_addr);
+ p_rem_dev = bta_dm_find_peer_device(peer_addr);
+ /* Disable sniff policy on the HID link since SCO is Up on Slave Link */
+ if ((p_rem_dev) && (interop_match_addr(
+ INTEROP_DISABLE_SNIFF_DURING_SCO, (const bt_bdaddr_t *)&remote_bdaddr) ||
+ interop_match_manufacturer(INTEROP_DISABLE_SNIFF_DURING_SCO, manufacturer)))
+ {
+ char buf[18];
+ APPL_TRACE_DEBUG("%s: disable sniff for manufacturer:%d addr = %s",
+ __func__, manufacturer, bdaddr_to_string((const bt_bdaddr_t *)peer_addr,
+ buf, sizeof(buf)));
+ bta_dm_pm_set_sniff_policy(p_rem_dev, true);
+ }
+ }
+ }
+ }
+
+ /* If SCO up/down event is received, then enable/disable SSR on active HID link */
+ if (status == BTA_SYS_SCO_OPEN || status == BTA_SYS_SCO_CLOSE)
+ {
+ const bool bScoActive = (status == BTA_SYS_SCO_OPEN);
+
+ APPL_TRACE_DEBUG("%s: bta_dm_pm_hid_check with bScoActive = %d", __func__, bScoActive);
+ bta_dm_pm_hid_check(bScoActive);
+ }
#endif
bta_dm_pm_set_mode(peer_addr, BTA_DM_PM_NO_ACTION, pm_req);
-
- /* perform the HID link workaround if needed
- ** 1. If SCO up/down event is received OR
- ** 2. If HID connection open is received and SCO is already active.
- ** This will handle the case where HID connects when SCO already active
- */
- if ( BTM_IsDeviceUp() &&
- ( ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ||
- ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) ) )
- {
- BOOLEAN bScoActive;
- if (status == BTA_SYS_CONN_OPEN)
- bScoActive = TRUE;
- else
- bScoActive = (status == BTA_SYS_SCO_OPEN);
-
- bta_dm_pm_hid_check(bScoActive);
- }
-
}
@@ -860,6 +907,24 @@
{
if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat, &p_spec_cur->min_rmt_to) == BTA_HH_ERR)
continue;
+ if (p_spec_cur->max_lat == BTA_HH_SSR_MAX_LATENCY_ZERO)
+ {
+ APPL_TRACE_WARNING("%s: Max latency is 0, not sending"
+ "SSR command as device is blacklisted", __func__);
+ return;
+ }
+ else if (p_spec_cur->max_lat == BTA_HH_SSR_DISABLE_SSR)
+ {
+ APPL_TRACE_WARNING("%s: Need to disable SSR"
+ "as device is blacklisted", __func__);
+ BTM_SetSsrParams (peer_addr, 0, 0, 0);
+ return;
+ }
+ else if (p_spec_cur->max_lat < BTA_HH_SSR_MAX_LATENCY_MIN_OPTIMAL)
+ {
+ p_spec_cur->max_lat = BTA_HH_SSR_MAX_LATENCY_MIN_OPTIMAL;
+ }
+ APPL_TRACE_DEBUG("%s: New Max Latency = %d", __func__, p_spec_cur->max_lat);
}
#endif
if (p_spec_cur->max_lat < p_spec->max_lat ||
@@ -880,7 +945,7 @@
if (bta_dm_pm_is_sco_active())
{
int idx = bta_dm_get_sco_index();
- if (idx != -1)
+ if (idx != -1 && idx < bta_dm_conn_srvcs.count)
{
if (bdcmp(bta_dm_conn_srvcs.conn_srvc[idx].peer_bdaddr, peer_addr) == 0)
{
@@ -1195,34 +1260,87 @@
**
** Function bta_dm_pm_hid_check
**
-** Description Disables/Enables sniff in link policy based on SCO Up/Down
+** Description Disables/Enables SSR based on SCO Up/Down
**
** Returns None
**
*******************************************************************************/
static void bta_dm_pm_hid_check(BOOLEAN bScoActive)
{
- int j;
+ BD_ADDR peer_bdaddr;
+ UINT8 role_on_sco_link;
- /* if HID is active, disable the link policy */
- for(j=0; j<bta_dm_conn_srvcs.count ; j++)
+ if (bScoActive)
{
- /* check if an entry already present */
- if(bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH )
+ /* Check if DUT is slave on SCO Link */
+ BTM_GetRole(bta_dm_conn_srvcs.conn_srvc[bta_dm_get_sco_index()].peer_bdaddr,
+ &role_on_sco_link);
+ APPL_TRACE_DEBUG("%s: Role on SCO Link = %d", __func__, role_on_sco_link);
+ }
+ for (int j = 0; j < bta_dm_conn_srvcs.count ; j ++)
+ {
+ /* check if HID entry already present */
+ if (((bScoActive && (role_on_sco_link == BTM_ROLE_SLAVE)) || !bScoActive) &&
+ bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH)
{
- APPL_TRACE_DEBUG ("SCO status change(Active: %d), modify HID link policy. state: %d",
- bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state);
- bta_dm_pm_set_sniff_policy( bta_dm_find_peer_device(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr), bScoActive);
+ UINT16 manufacturer = 0;
+ UINT16 lmp_sub_version = 0;
+ UINT8 lmp_version = 0;
+ tBTA_DM_PEER_DEVICE *p_rem_dev = NULL;
+ UINT8 *p = BTM_ReadLocalFeatures();
+ bt_bdaddr_t remote_address;
+ bdcpy(peer_bdaddr, bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr);
+ bdcpy(remote_address.address, bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr);
- /* if we had disabled link policy, seems like the hid device stop retrying SNIFF after a few tries. force sniff if needed */
- if (!bScoActive)
- bta_dm_pm_set_mode(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, BTA_DM_PM_NO_ACTION,
- BTA_DM_PM_RESTART);
+ if (BTM_ReadRemoteVersion(peer_bdaddr, &lmp_version,
+ &manufacturer, &lmp_sub_version) == BTM_SUCCESS) {
+ p_rem_dev = bta_dm_find_peer_device(peer_bdaddr);
+ /* Disable/Enable sniff policy on the HID link if SCO Up/Down*/
+ if ((p_rem_dev) && (interop_match_addr(
+ INTEROP_DISABLE_SNIFF_DURING_SCO, (const bt_bdaddr_t *)&remote_address) ||
+ interop_match_manufacturer(INTEROP_DISABLE_SNIFF_DURING_SCO, manufacturer)))
+ {
+ char buf[18];
+ APPL_TRACE_DEBUG("%s: %s sniff for manufacturer:%d",
+ __func__, bScoActive ? "disable" : "enable", manufacturer,
+ bdaddr_to_string((const bt_bdaddr_t *)peer_bdaddr, buf, sizeof(buf)));
+ bta_dm_pm_set_sniff_policy(p_rem_dev, bScoActive);
+ /* Put link in sniff with specific parameters since SCO is disconnected */
+ if (!bScoActive)
+ /*
+ * Put HID link in sniff also with specific HID Sniff parameters as remote
+ * device might not attempt sniff in case SCO is connected for longer time.
+ */
+ bta_dm_pm_sniff(p_rem_dev, (BTA_DM_PM_SNIFF6 & 0x0F));
+ }
+ }
+
+ if((p != NULL && HCI_SNIFF_SUB_RATE_SUPPORTED(p))
+ &&((NULL != (p = BTM_ReadRemoteFeatures (peer_bdaddr)))
+ && HCI_SNIFF_SUB_RATE_SUPPORTED(p)))
+ {
+ if (bScoActive)
+ {
+ APPL_TRACE_DEBUG("%s: SCO_OPEN, disabling SSR", __func__);
+ BTM_SetSsrParams(peer_bdaddr, 0, 0, 0);
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("%s: SCO_CLOSE, enabling SSR", __func__);
+ bta_dm_pm_ssr(peer_bdaddr);
+ }
+ }
}
}
}
-
+void bta_dm_pm_set_sniff_policy_toggle(BD_ADDR peer_addr, BOOLEAN bDisable)
+{
+ APPL_TRACE_DEBUG("%s: bDisable:%d", __func__, bDisable);
+ tBTA_DM_PEER_DEVICE *p_dev = NULL;
+ p_dev = bta_dm_find_peer_device(peer_addr);
+ bta_dm_pm_set_sniff_policy(p_dev, bDisable);
+}
/*******************************************************************************
**
** Function bta_dm_pm_set_sniff_policy
diff --git a/bta/gatt/bta_gattc_act.c b/bta/gatt/bta_gattc_act.c
index 3390b94..302f2bd 100644
--- a/bta/gatt/bta_gattc_act.c
+++ b/bta/gatt/bta_gattc_act.c
@@ -36,6 +36,7 @@
#include "osi/include/log.h"
#include "stack/l2cap/l2c_int.h"
#include "utl.h"
+#include "btm_int.h"
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
#include "bta_hh_int.h"
@@ -803,6 +804,9 @@
if (p_clcb->transport == BTA_TRANSPORT_BR_EDR)
bta_sys_conn_close( BTA_ID_GATTC ,BTA_ALL_APP_ID, p_clcb->bda);
+ if (!btm_sec_is_a_bonded_dev(p_clcb->bda))
+ BTA_GATTC_Refresh(p_clcb->bda);
+
bta_gattc_clcb_dealloc(p_clcb);
if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT)
@@ -822,6 +826,7 @@
{
bta_gattc_deregister_cmpl(p_clreg);
}
+ bta_gattc_clear_notif_reg_on_disc(p_clreg, p_clcb->bda);
}
/*******************************************************************************
**
@@ -1820,6 +1825,12 @@
/* if non-service change indication/notification, forward to application */
if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, ¬ify, &p_data->att_value))
{
+ /* Not a service change indication, check for an unallocated HID conn */
+ if (bta_hh_le_is_hh_gatt_if(gatt_if) && !p_clcb)
+ {
+ APPL_TRACE_ERROR("%s, ignore HID ind/notificiation", __func__);
+ return;
+ }
/* if app registered for the notification */
if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, ¬ify))
{
diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c
index 45d2588..8ac3a88 100644
--- a/bta/gatt/bta_gattc_cache.c
+++ b/bta/gatt/bta_gattc_cache.c
@@ -82,11 +82,23 @@
};
/* utility functions */
-bool display_cache_attribute(void *data, void *context) {
- tBTA_GATTC_CACHE_ATTR *p_attr = data;
- APPL_TRACE_ERROR("\t Attr handle[%d] uuid[0x%04x] type[%s] prop[0x%1x]",
- p_attr->handle, p_attr->uuid.uu.uuid16,
- bta_gattc_attr_type[p_attr->attr_type], p_attr->property);
+bool display_cache_descriptor(void *data, void *context) {
+ tBTA_GATTC_DESCRIPTOR *p_desc = data;
+ APPL_TRACE_ERROR("Descriptor handle[%d] uuid[0x%04x]",
+ p_desc->handle, p_desc->uuid.uu.uuid16);
+
+ return true;
+}
+
+bool display_cache_characteristic(void *data, void *context) {
+ tBTA_GATTC_CHARACTERISTIC *p_char = data;
+ APPL_TRACE_ERROR("Characteristic handle[%d] uuid[0x%04x] prop[0x%1x]",
+ p_char->handle, p_char->uuid.uu.uuid16, p_char->properties);
+
+ if (p_char->descriptors != NULL) {
+ list_foreach(p_char->descriptors, display_cache_descriptor, NULL);
+ }
+
return true;
}
@@ -99,7 +111,7 @@
p_cur_srvc->handle);
if (p_cur_srvc->characteristics != NULL) {
- list_foreach(p_cur_srvc->characteristics, display_cache_attribute, NULL);
+ list_foreach(p_cur_srvc->characteristics, display_cache_characteristic, NULL);
}
return true;
@@ -509,7 +521,8 @@
LOG_WARN(LOG_TAG, "%s no more services found", __func__);
#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
- bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+ if(p_srvc_cb->p_srvc_cache)
+ bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
#endif
/* save cache to NV */
p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
@@ -582,7 +595,7 @@
{
tBTA_GATTC_ATTR_REC *p_rec = NULL;
- if (-- p_srvc_cb->total_char > 0)
+ if((p_srvc_cb->total_char != 0) && (-- p_srvc_cb->total_char > 0))
{
p_rec = p_srvc_cb->p_srvc_list + (++ p_srvc_cb->cur_char_idx);
/* add the next characteristic into cache */
@@ -592,8 +605,8 @@
&p_rec->uuid,
p_rec->property);
- /* start discoverying next characteristic for char descriptor */
- bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+ /* start discoverying next characteristic for char descriptor */
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
}
else
/* all characteristic has been explored, start with next service if any */
@@ -1328,6 +1341,7 @@
if (!p_clcb->p_srcb || p_clcb->p_srcb->p_srvc_list || /* no active discovery */
!p_clcb->p_srcb->p_srvc_cache) {
APPL_TRACE_ERROR("No server cache available");
+ return;
}
bta_gattc_get_gatt_db_impl(p_clcb->p_srcb, start_handle, end_handle, db, count);
@@ -1630,6 +1644,10 @@
BTIF_TRACE_DEBUG("%s", __func__);
char fname[255] = {0};
bta_gattc_generate_cache_file_name(fname, server_bda);
+
+ if(!remove(fname))
+ BTIF_TRACE_DEBUG("%s GATT cache deleted successfully", __func__);
+
unlink(fname);
}
#endif /* BTA_GATT_INCLUDED */
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index d895864..88c39a9 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -79,7 +79,11 @@
/* max known devices GATTC can support */
#ifndef BTA_GATTC_KNOWN_SR_MAX
+#ifndef MAX_ACL_CONNECTIONS
#define BTA_GATTC_KNOWN_SR_MAX 10
+#else
+#define BTA_GATTC_KNOWN_SR_MAX MAX_ACL_CONNECTIONS
+#endif
#endif
#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL
@@ -296,7 +300,11 @@
} tBTA_GATTC_SERV;
#ifndef BTA_GATTC_NOTIF_REG_MAX
+#ifndef MAX_ACL_CONNECTIONS
#define BTA_GATTC_NOTIF_REG_MAX 15
+#else
+#define BTA_GATTC_NOTIF_REG_MAX MAX_ACL_CONNECTIONS*3
+#endif
#endif
typedef struct
@@ -471,6 +479,7 @@
extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, UINT8 role);
extern UINT8 bta_gattc_num_reg_app(void);
extern void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV *p_srcb, UINT16 conn_id, UINT16 start_handle, UINT16 end_handle);
+extern void bta_gattc_clear_notif_reg_on_disc(tBTA_GATTC_RCB *p_clreg, BD_ADDR bda);
extern tBTA_GATTC_SERV * bta_gattc_find_srvr_cache(BD_ADDR bda);
/* discovery functions */
diff --git a/bta/gatt/bta_gattc_utils.c b/bta/gatt/bta_gattc_utils.c
index 8910bd3..f87ea49 100644
--- a/bta/gatt/bta_gattc_utils.c
+++ b/bta/gatt/bta_gattc_utils.c
@@ -476,6 +476,31 @@
return FALSE;
}
+
+/*******************************************************************************
+**
+** Function bta_gattc_clear_notif_reg_on_disc
+**
+** Description clear up the notification registration at disconnection.
+**
+** Returns None.
+**
+*******************************************************************************/
+void bta_gattc_clear_notif_reg_on_disc(tBTA_GATTC_RCB *p_clreg, BD_ADDR bda) {
+ if (!p_clreg) {
+ APPL_TRACE_ERROR("%s, Invalid regiseration block", __func__);
+ return;
+ }
+
+ UINT8 i;
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+ if (p_clreg->notif_reg[i].in_use &&
+ !bdcmp(p_clreg->notif_reg[i].remote_bda, bda)) {
+ memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+ }
+ }
+}
+
/*******************************************************************************
**
** Function bta_gattc_clear_notif_registration
diff --git a/bta/hf_client/bta_hf_client_act.c b/bta/hf_client/bta_hf_client_act.c
index d41f298..1126bc7 100644
--- a/bta/hf_client/bta_hf_client_act.c
+++ b/bta/hf_client/bta_hf_client_act.c
@@ -42,6 +42,8 @@
/* maximum length of data to read from RFCOMM */
#define BTA_HF_CLIENT_RFC_READ_MAX 512
+BOOLEAN is_sniff_disabled = false;
+
/*******************************************************************************
**
** Function bta_hf_client_register
@@ -107,6 +109,9 @@
/* disable */
bta_hf_client_scb_disable();
+
+ if (is_sniff_disabled == true)
+ is_sniff_disabled = false;
}
/*******************************************************************************
@@ -427,6 +432,9 @@
bta_hf_client_close_server();
bta_hf_client_scb_disable();
}
+
+ if (is_sniff_disabled == true)
+ is_sniff_disabled = false;
}
/*******************************************************************************
@@ -457,7 +465,7 @@
}
/* free discovery db */
- bta_hf_client_free_db(p_data);
+ bta_hf_client_free_db_int(p_data);
/* send ourselves sdp ok/fail event */
bta_hf_client_sm_execute(event, p_data);
@@ -475,6 +483,7 @@
*******************************************************************************/
void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA *p_data)
{
+ APPL_TRACE_DEBUG ("%s: Status: %d", __func__, p_data->disc_result.status);
/* if found service */
if (p_data->disc_result.status == SDP_SUCCESS ||
p_data->disc_result.status == SDP_DB_FULL)
@@ -484,7 +493,7 @@
}
/* free discovery db */
- bta_hf_client_free_db(p_data);
+ bta_hf_client_free_db_acp(p_data);
}
/*******************************************************************************
@@ -761,3 +770,56 @@
(*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_BINP_EVT, &evt);
}
+
+/*******************************************************************************
+**
+** Function bta_hf_client_cgmi
+**
+** Description Send CGMI event to application.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hf_client_cgmi(char *str)
+{
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ strlcpy(evt.cgmi.name, str, BTA_HF_CLIENT_MANUFACTURER_ID + 1);
+
+ (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CGMI_EVT, &evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_hf_client_cgmm
+**
+** Description Send CGMM event to application.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hf_client_cgmm(char *str)
+{
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ strlcpy(evt.cgmm.model, str, BTA_HF_CLIENT_MANUFACTURER_MODEL + 1);
+
+ APPL_TRACE_DEBUG("%s: phone model is %s", __func__, evt.cgmm.model);
+
+#ifdef SNIFF_DISABLE
+ if (strncmp(evt.cgmm.model, "+CGMM: iPhone", 13) == 0)
+ {
+ APPL_TRACE_WARNING("%s: Changing policy to disable sniff", __func__);
+ bta_sys_clear_policy(BTA_ID_HS, HCI_ENABLE_SNIFF_MODE, bta_hf_client_cb.scb.peer_addr);
+ is_sniff_disabled = true;
+ }
+#endif
+
+ (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CGMM_EVT, &evt);
+}
diff --git a/bta/hf_client/bta_hf_client_at.c b/bta/hf_client/bta_hf_client_at.c
index b273f2f..745d147 100644
--- a/bta/hf_client/bta_hf_client_at.c
+++ b/bta/hf_client/bta_hf_client_at.c
@@ -148,6 +148,7 @@
bta_hf_client_handle_ok();
} else {
APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting");
+ GENERATE_VND_LOGS();
bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
}
}
@@ -260,17 +261,25 @@
{
case BTA_HF_CLIENT_AT_BIA:
case BTA_HF_CLIENT_AT_BCC:
+ case BTA_HF_CLIENT_AT_CGMI:
+ case BTA_HF_CLIENT_AT_CGMM:
break;
case BTA_HF_CLIENT_AT_BCS:
bta_hf_client_start_at_hold_timer();
bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
return;
- case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
+ case BTA_HF_CLIENT_AT_CLIP:
if (bta_hf_client_cb.scb.send_at_reply == FALSE)
{
bta_hf_client_cb.scb.send_at_reply = TRUE;
}
break;
+ case BTA_HF_CLIENT_AT_CGMI_QUERY:
+ bta_hf_client_send_at_cgmi(FALSE);
+ break;
+ case BTA_HF_CLIENT_AT_CGMM_QUERY: //last cmd in post slc seq
+ bta_hf_client_send_at_cgmm(FALSE);
+ break;
case BTA_HF_CLIENT_AT_NONE:
bta_hf_client_stop_at_hold_timer();
break;
@@ -302,12 +311,13 @@
switch(bta_hf_client_cb.scb.at_cb.current_cmd)
{
case BTA_HF_CLIENT_AT_BIA:
+ case BTA_HF_CLIENT_AT_CGMI_QUERY:
break;
case BTA_HF_CLIENT_AT_BCC:
case BTA_HF_CLIENT_AT_BCS:
bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
break;
- case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
+ case BTA_HF_CLIENT_AT_CGMM_QUERY: //last cmd in post slc seq
if (bta_hf_client_cb.scb.send_at_reply == FALSE)
{
bta_hf_client_cb.scb.send_at_reply = TRUE;
@@ -575,6 +585,20 @@
bta_hf_client_evt_val(BTA_HF_CLIENT_BTRH_EVT, code);
}
+static void bta_hf_client_handle_cgmi(char *manf_id)
+{
+ APPL_TRACE_DEBUG("%s %s", __FUNCTION__, manf_id);
+
+ bta_hf_client_cgmi(manf_id);
+}
+
+static void bta_hf_client_handle_cgmm(char *manf_model)
+{
+ APPL_TRACE_DEBUG("%s %s", __FUNCTION__, manf_model);
+
+ bta_hf_client_cgmm(manf_model);
+}
+
/******************************************************************************
**
** COMMON AT EVENTS PARSING FUNCTIONS
@@ -1045,8 +1069,8 @@
{
UINT16 idx, dir, status, mode, mpty;
char numstr[33]; /* spec forces 32 chars, plus one for \0*/
- UINT16 type;
int res;
+ UINT16 type = 0;
int offset = 0;
AT_CHECK_EVENT(buffer, "+CLCC:");
@@ -1289,6 +1313,65 @@
return buffer;
}
+static char *bta_hf_client_parse_cgmi(char *buffer)
+{
+ /* 2048 chars max, plus \0 here */
+ char manf_id[2049];
+ int i = 0;
+
+ // if current cmd is not CGMI, return from here
+ if(bta_hf_client_cb.scb.at_cb.current_cmd != BTA_HF_CLIENT_AT_CGMI)
+ return buffer;
+
+ // no prefix in the response from AG
+ AT_CHECK_EVENT(buffer, "");
+
+ for(; *buffer != '\r'; i++, buffer++)
+ manf_id[i] = *buffer;
+
+ manf_id[i] = '\0';
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_cgmi(manf_id);
+ // check for OK Response in end
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok();
+
+ return buffer;
+}
+
+static char *bta_hf_client_parse_cgmm(char *buffer)
+{
+ /* 2048 chars max, plus \0 here */
+ char manf_model[2049];
+ int i = 0;
+
+ // if current cmd is not CGMM, return from here
+ if(bta_hf_client_cb.scb.at_cb.current_cmd != BTA_HF_CLIENT_AT_CGMM)
+ return buffer;
+
+ // no prefix in the response from AG
+ AT_CHECK_EVENT(buffer, "");
+
+ for(; *buffer != '\r'; i++, buffer++)
+ manf_model[i] = *buffer;
+
+ manf_model[i] = '\0';
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_cgmm(manf_model);
+ // check for OK Response in end
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok();
+
+ return buffer;
+}
/******************************************************************************
** SUPPORTED EVENT MESSAGES
@@ -1325,6 +1408,8 @@
bta_hf_client_parse_clcc,
bta_hf_client_parse_cnum,
bta_hf_client_parse_btrh,
+ bta_hf_client_parse_cgmi,
+ bta_hf_client_parse_cgmm,
bta_hf_client_parse_busy,
bta_hf_client_parse_delayed,
bta_hf_client_parse_no_carrier,
@@ -1924,6 +2009,60 @@
bta_hf_client_send_at(BTA_HF_CLIENT_AT_BIA, buf, at_len);
}
+void bta_hf_client_send_at_cgmi(BOOLEAN query)
+{
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+ tBTA_HF_CLIENT_AT_CMD cmd;
+
+ APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+ if (query == TRUE)
+ {
+ at_len = snprintf(buf, sizeof(buf), "AT+CGMI=?\r");
+ cmd = BTA_HF_CLIENT_AT_CGMI_QUERY;
+ }
+ else
+ {
+ at_len = snprintf(buf, sizeof(buf), "AT+CGMI\r");
+ cmd = BTA_HF_CLIENT_AT_CGMI;
+ }
+
+ if (at_len < 0)
+ {
+ APPL_TRACE_ERROR("HFPClient: AT command Framing error");
+ return;
+ }
+ bta_hf_client_send_at(cmd, buf, at_len);
+}
+
+void bta_hf_client_send_at_cgmm(BOOLEAN query)
+{
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+ tBTA_HF_CLIENT_AT_CMD cmd;
+
+ APPL_TRACE_DEBUG("%s", __FUNCTION__);
+
+ if (query == TRUE)
+ {
+ at_len = snprintf(buf, sizeof(buf), "AT+CGMM=?\r");
+ cmd = BTA_HF_CLIENT_AT_CGMM_QUERY;
+ }
+ else
+ {
+ at_len = snprintf(buf, sizeof(buf), "AT+CGMM\r");
+ cmd = BTA_HF_CLIENT_AT_CGMM;
+ }
+
+ if (at_len < 0)
+ {
+ APPL_TRACE_ERROR("HFPClient: AT command Framing error");
+ return;
+ }
+ bta_hf_client_send_at(cmd, buf, at_len);
+}
+
void bta_hf_client_at_init(void)
{
alarm_free(bta_hf_client_cb.scb.at_cb.resp_timer);
diff --git a/bta/hf_client/bta_hf_client_at.h b/bta/hf_client/bta_hf_client_at.h
index 78b5d63..71ba703 100644
--- a/bta/hf_client/bta_hf_client_at.h
+++ b/bta/hf_client/bta_hf_client_at.h
@@ -70,6 +70,10 @@
BTA_HF_CLIENT_AT_CNUM,
BTA_HF_CLIENT_AT_NREC,
BTA_HF_CLIENT_AT_BINP,
+ BTA_HF_CLIENT_AT_CGMI_QUERY,
+ BTA_HF_CLIENT_AT_CGMI,
+ BTA_HF_CLIENT_AT_CGMM_QUERY,
+ BTA_HF_CLIENT_AT_CGMM,
};
typedef UINT8 tBTA_HF_CLIENT_AT_CMD;
diff --git a/bta/hf_client/bta_hf_client_int.h b/bta/hf_client/bta_hf_client_int.h
index a2dbde2..521dc94 100644
--- a/bta/hf_client/bta_hf_client_int.h
+++ b/bta/hf_client/bta_hf_client_int.h
@@ -140,7 +140,8 @@
{
UINT16 serv_handle; /* RFCOMM server handle */
BD_ADDR peer_addr; /* peer bd address */
- tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */
+ tSDP_DISCOVERY_DB *p_disc_db_int; /* pointer to discovery database for initiator */
+ tSDP_DISCOVERY_DB *p_disc_db_acp; /* pointer to discovery database for acceptor*/
UINT16 conn_handle; /* RFCOMM handle of connected service */
tBTA_SEC serv_sec_mask; /* server security mask */
tBTA_SEC cli_sec_mask; /* client security mask */
@@ -216,7 +217,8 @@
extern void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA *p_data);
extern BOOLEAN bta_hf_client_sdp_find_attr(void);
extern void bta_hf_client_do_disc(void);
-extern void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_free_db_int(tBTA_HF_CLIENT_DATA *p_data);
+extern void bta_hf_client_free_db_acp(tBTA_HF_CLIENT_DATA *p_data);
/* RFCOMM functions */
extern void bta_hf_client_setup_port(UINT16 handle);
@@ -261,6 +263,8 @@
extern void bta_hf_client_send_at_nrec(void);
extern void bta_hf_client_send_at_binp(UINT32 action);
extern void bta_hf_client_send_at_bia(void);
+extern void bta_hf_client_send_at_cgmi(BOOLEAN query);
+extern void bta_hf_client_send_at_cgmm(BOOLEAN query);
/* Action functions */
extern void bta_hf_client_register(tBTA_HF_CLIENT_DATA *p_data);
@@ -287,6 +291,8 @@
extern void bta_hf_client_clcc(UINT32 idx, BOOLEAN incoming, UINT8 status, BOOLEAN mpty, char *number);
extern void bta_hf_client_cnum(char *number, UINT16 service);
extern void bta_hf_client_binp(char *number);
+extern void bta_hf_client_cgmi(char *str);
+extern void bta_hf_client_cgmm(char *str);
/* Commands handling functions */
extern void bta_hf_client_dial(tBTA_HF_CLIENT_DATA *p_data);
diff --git a/bta/hf_client/bta_hf_client_main.c b/bta/hf_client/bta_hf_client_main.c
index 5df418b..871ac91 100644
--- a/bta/hf_client/bta_hf_client_main.c
+++ b/bta/hf_client/bta_hf_client_main.c
@@ -67,7 +67,8 @@
BTA_HF_CLIENT_SCO_OPEN,
BTA_HF_CLIENT_SCO_CLOSE,
BTA_HF_CLIENT_SCO_SHUTDOWN,
- BTA_HF_CLIENT_FREE_DB,
+ BTA_HF_CLIENT_FREE_DB_INT,
+ BTA_HF_CLIENT_FREE_DB_ACP,
BTA_HF_CLIENT_OPEN_FAIL,
BTA_HF_CLIENT_RFC_OPEN,
BTA_HF_CLIENT_RFC_FAIL,
@@ -103,7 +104,8 @@
/* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open,
/* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close,
/* BTA_HF_CLIENT_SCO_SHUTDOWN */ bta_hf_client_sco_shutdown,
-/* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db,
+/* BTA_HF_CLIENT_FREE_DB_INT */ bta_hf_client_free_db_int,
+/* BTA_HF_CLIENT_FREE_DB_ACP */ bta_hf_client_free_db_acp,
/* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail,
/* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open,
/* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail,
@@ -136,7 +138,7 @@
/* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
-/* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
+/* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB_ACP, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
@@ -205,8 +207,8 @@
/* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
-/* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
-/* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
+/* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB_ACP, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
+/* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB_INT, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST},
/* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
@@ -346,11 +348,22 @@
bta_hf_client_cb.scb.state = BTA_HF_CLIENT_INIT_ST;
- /* Cancel SDP if it had been started. */
- if(bta_hf_client_cb.scb.p_disc_db)
+ APPL_TRACE_WARNING ("%s:bta_hf_client_cb.scb.role = %d", __func__,
+ bta_hf_client_cb.scb.role);
+ /* Cancel SDP if it had been started for initiator. */
+ if (bta_hf_client_cb.scb.p_disc_db_int)
{
- (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
- bta_hf_client_free_db(NULL);
+ APPL_TRACE_WARNING ("%s:cancel SDP serach for the HFP client initiator:", __func__);
+ (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db_int);
+ bta_hf_client_free_db_int(NULL);
+ }
+
+ /* Cancel SDP if it had been started for acceptor. */
+ if (bta_hf_client_cb.scb.p_disc_db_acp)
+ {
+ APPL_TRACE_WARNING ("%s:cancel SDP serach for the HFP client acceptor:", __func__);
+ (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db_acp);
+ bta_hf_client_free_db_acp(NULL);
}
/* reopen registered server */
@@ -388,7 +401,7 @@
/* check if mSBC support enabled */
osi_property_get("ro.bluetooth.hfp.ver", value, "0");
- if (strcmp(value,"1.6") == 0)
+ if (strtof(value, NULL) >= 1.6)
{
bta_hf_client_cb.msbc_enabled = TRUE;
}
@@ -511,7 +524,7 @@
/* execute action functions */
for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != BTA_HF_CLIENT_IGNORE)
+ if ((action = state_table[event][i]) < BTA_HF_CLIENT_IGNORE)
{
(*bta_hf_client_action[action])(p_data);
}
@@ -542,6 +555,8 @@
bta_hf_client_send_at_cops(FALSE);
bta_hf_client_send_at_btrh(TRUE, 0);
bta_hf_client_send_at_clip(TRUE);
+ bta_hf_client_send_at_cgmi(TRUE);
+ bta_hf_client_send_at_cgmm(TRUE);
}
/*******************************************************************************
diff --git a/bta/hf_client/bta_hf_client_rfc.c b/bta/hf_client/bta_hf_client_rfc.c
index dc422ae..532b852 100644
--- a/bta/hf_client/bta_hf_client_rfc.c
+++ b/bta/hf_client/bta_hf_client_rfc.c
@@ -248,11 +248,21 @@
p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
bta_sys_sendmsg(p_buf);
- /* Cancel SDP if it had been started. */
- if(bta_hf_client_cb.scb.p_disc_db)
+ APPL_TRACE_DEBUG("%s: bta_hf_client_cb.scb.role = %d",__func__, bta_hf_client_cb.scb.role);
+ /* Cancel SDP if it had been started for initiator. */
+ if (bta_hf_client_cb.scb.p_disc_db_int)
{
- (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
- bta_hf_client_free_db(NULL);
+ APPL_TRACE_DEBUG("%s: Cancel SDP service search for the HF client initiator", __func__);
+ (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db_int);
+ bta_hf_client_free_db_int(NULL);
+ }
+
+ /* Cancel SDP if it had been started for acceptor. */
+ if (bta_hf_client_cb.scb.p_disc_db_acp)
+ {
+ APPL_TRACE_DEBUG("%s: Cancel SDP service search for the HF client acceptor", __func__);
+ (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db_acp);
+ bta_hf_client_free_db_acp(NULL);
}
}
}
diff --git a/bta/hf_client/bta_hf_client_sdp.c b/bta/hf_client/bta_hf_client_sdp.c
index 822fe97..952cf7d 100644
--- a/bta/hf_client/bta_hf_client_sdp.c
+++ b/bta/hf_client/bta_hf_client_sdp.c
@@ -222,19 +222,22 @@
BOOLEAN result = FALSE;
bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1; /* Default version */
-
+ APPL_TRACE_DEBUG("%s: bta_hf_client_cb.scb.role = %d",__func__, bta_hf_client_cb.scb.role);
/* loop through all records we found */
while (TRUE)
{
/* get next record; if none found, we're done */
- if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL)
- {
- break;
- }
-
- /* get scn from proto desc list if initiator */
if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT)
{
+ APPL_TRACE_DEBUG("%s: find SDP services for HFP client initiator", __func__);
+ if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db_int,
+ UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL)
+ {
+ APPL_TRACE_DEBUG("%s:initiator p_rec is null", __func__);
+ break;
+ }
+
+ /* get scn from proto desc list if initiator */
if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
{
bta_hf_client_cb.scb.peer_scn = (UINT8) pe.params[0];
@@ -244,6 +247,17 @@
continue;
}
}
+ /* get next record; if none found, we're done */
+ if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_ACP)
+ {
+ APPL_TRACE_DEBUG("%s: find SDP services for HFP client acceptor", __func__);
+ if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db_acp,
+ UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL)
+ {
+ APPL_TRACE_DEBUG("%s:acceptor p_rec is null", __func__);
+ break;
+ }
+ }
/* get profile version (if failure, version parameter is not updated) */
SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, &bta_hf_client_cb.scb.peer_version);
@@ -304,8 +318,10 @@
UINT16 num_uuid = 1;
UINT16 attr_list[4];
UINT8 num_attr;
- BOOLEAN db_inited = FALSE;
+ BOOLEAN db_inited_int = FALSE;
+ BOOLEAN db_inited_acp = FALSE;
+ APPL_TRACE_DEBUG("%s: bta_hf_client_cb.scb.role=%d",__func__, bta_hf_client_cb.scb.role);
/* initiator; get proto list and features */
if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT)
{
@@ -315,6 +331,32 @@
attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
num_attr = 4;
uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+
+ /* allocate buffer for sdp database for initiator */
+ bta_hf_client_cb.scb.p_disc_db_int =
+ (tSDP_DISCOVERY_DB *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+
+ /* set up service discovery database; attr happens to be attr_list len */
+ uuid_list[0].len = LEN_UUID_16;
+ uuid_list[1].len = LEN_UUID_16;
+ db_inited_int = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db_int,
+ BT_DEFAULT_BUFFER_SIZE, num_uuid,
+ uuid_list, num_attr, attr_list);
+ APPL_TRACE_DEBUG("%s: db_inited_int=%d",__func__, db_inited_int);
+ if (db_inited_int)
+ {
+ /*Service discovery not initiated */
+ db_inited_int = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr,
+ bta_hf_client_cb.scb.p_disc_db_int, bta_hf_client_sdp_cback);
+ }
+
+ if (!db_inited_int)
+ {
+ /*free discover db */
+ bta_hf_client_free_db_int(NULL);
+ /* sent failed event */
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
+ }
}
/* acceptor; get features */
else
@@ -324,47 +366,64 @@
attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
num_attr = 3;
uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
- }
- /* allocate buffer for sdp database */
- bta_hf_client_cb.scb.p_disc_db = (tSDP_DISCOVERY_DB *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ /* allocate buffer for sdp database for acceptor */
+ bta_hf_client_cb.scb.p_disc_db_acp = (tSDP_DISCOVERY_DB *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
- /* set up service discovery database; attr happens to be attr_list len */
- uuid_list[0].len = LEN_UUID_16;
- uuid_list[1].len = LEN_UUID_16;
- db_inited = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db,
+ /* set up service discovery database; attr happens to be attr_list len */
+ uuid_list[0].len = LEN_UUID_16;
+ uuid_list[1].len = LEN_UUID_16;
+ db_inited_acp = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db_acp,
BT_DEFAULT_BUFFER_SIZE, num_uuid,
uuid_list, num_attr, attr_list);
+ APPL_TRACE_DEBUG("%s: db_inited_acp=%d",__func__, db_inited_acp);
+ if (db_inited_acp)
+ {
+ /*Service discovery not initiated */
+ db_inited_acp = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr,
+ bta_hf_client_cb.scb.p_disc_db_acp, bta_hf_client_sdp_cback);
+ }
- if (db_inited)
- {
- /*Service discovery not initiated */
- db_inited = SDP_ServiceSearchAttributeRequest(bta_hf_client_cb.scb.peer_addr,
- bta_hf_client_cb.scb.p_disc_db, bta_hf_client_sdp_cback);
+ if (!db_inited_acp)
+ {
+ /*free discover db */
+ bta_hf_client_free_db_acp(NULL);
+ /* sent failed event */
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
+ }
}
-
- if (!db_inited)
- {
- /*free discover db */
- bta_hf_client_free_db(NULL);
- /* sent failed event */
- bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
- }
-
}
/*******************************************************************************
**
-** Function bta_hf_client_free_db
+** Function bta_hf_client_free_db_int
**
-** Description Free discovery database.
+** Description Free discovery database of initiator.
**
**
** Returns void
**
*******************************************************************************/
-void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA *p_data)
+void bta_hf_client_free_db_int(tBTA_HF_CLIENT_DATA *p_data)
{
UNUSED(p_data);
- osi_free_and_reset((void **)&bta_hf_client_cb.scb.p_disc_db);
+ APPL_TRACE_DEBUG("%s:",__func__);
+ osi_free_and_reset((void **)&bta_hf_client_cb.scb.p_disc_db_int);
+}
+
+/*******************************************************************************
+**
+** Function bta_hf_client_free_db_acp
+**
+** Description Free discovery database of acceptor.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hf_client_free_db_acp(tBTA_HF_CLIENT_DATA *p_data)
+{
+ UNUSED(p_data);
+ APPL_TRACE_DEBUG("%s:",__func__);
+ osi_free_and_reset((void **)&bta_hf_client_cb.scb.p_disc_db_acp);
}
diff --git a/bta/hh/bta_hh_act.c b/bta/hh/bta_hh_act.c
index 7d0e5bd..44fbbb5 100644
--- a/bta/hh/bta_hh_act.c
+++ b/bta/hh/bta_hh_act.c
@@ -35,6 +35,7 @@
#include "bta_hh_int.h"
#include "bta_hh_co.h"
#include "utl.h"
+#include "btm_ble_api.h"
/*****************************************************************************
** Constants
@@ -105,8 +106,11 @@
}
else
#endif
+ if (bta_hh_cb.p_cback)
+ {
/* signal BTA call back event */
(* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status);
+ }
}
/*******************************************************************************
**
@@ -400,6 +404,13 @@
} else {
status = BTA_HH_OK;
}
+ } else if (bta_hh_cb.p_disc_db) {
+ /* It is possible that there is incoming/outgoing collision case. DUT initiated
+ * HID connection at same time remote has connected l2cap for HID control,
+ * so SDP would be in progress, when this flow reaches here. Just do nothing
+ * when the code reaches here, and ongoing SDP completion or failure will handle this case */
+ APPL_TRACE_DEBUG ("bta_hh_start_sdp: ignoring as SDP already in progress");
+ return;
}
if (status != BTA_HH_OK)
@@ -486,6 +497,7 @@
APPL_TRACE_DEBUG ("bta_hh_sdp_cmpl:SDP failed for incoming conn :hndl %d",
p_cb->incoming_hid_handle);
HID_HostRemoveDev( p_cb->incoming_hid_handle);
+ GENERATE_VENDOR_LOGS();
}
conn_dat.status = status;
(* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
@@ -571,6 +583,8 @@
conn.status = p_cb->status;
conn.le_hid = p_cb->is_le_device;
conn.scps_supported = p_cb->scps_supported;
+ if(p_cb->scps_supported)
+ BTA_HhUpdateLeScanParam(dev_handle,BTM_BLE_SCAN_SLOW_INT_1,BTM_BLE_SCAN_SLOW_WIN_1);
if (!p_cb->is_le_device)
#endif
@@ -593,6 +607,7 @@
/* HID connection is up, while SET_PROTO fail */
conn.status = BTA_HH_ERR_PROTO;
(* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn);
+ GENERATE_VENDOR_LOGS();
}
else
{
@@ -676,7 +691,7 @@
**
** Function bta_hh_handsk_act
**
-** Description HID Host process a handshake acknoledgement.
+** Description HID Host process a handshake acknowledgement.
**
**
** Returns void
@@ -708,7 +723,8 @@
/* if handshake gives an OK code for these transaction, fill in UNSUPT */
if ((hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data)) == BTA_HH_OK)
hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
-
+ if (p_cb->w4_evt == BTA_HH_GET_RPT_EVT)
+ bta_hh_co_get_rpt_rsp(cback_data.handle, hs_data.status, NULL, 0);
(* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data);
p_cb->w4_evt = 0;
break;
@@ -719,6 +735,8 @@
case BTA_HH_SET_IDLE_EVT :
cback_data.handle = p_cb->hid_handle;
cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+ if (p_cb->w4_evt == BTA_HH_SET_RPT_EVT)
+ bta_hh_co_set_rpt_rsp(cback_data.handle, cback_data.status);
(* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data);
p_cb->w4_evt = 0;
break;
@@ -781,6 +799,7 @@
break;
case BTA_HH_GET_RPT_EVT:
hs_data.rsp_data.p_rpt_data = pdata;
+ bta_hh_co_get_rpt_rsp(hs_data.handle, hs_data.status, pdata->data, pdata->len);
break;
case BTA_HH_GET_PROTO_EVT:
/* match up BTE/BTA report/boot mode def*/
@@ -834,14 +853,26 @@
UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
memset(&conn_dat, 0, sizeof(tBTA_HH_CONN));
- conn_dat.handle = p_cb->hid_handle;
- conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
- bdcpy(conn_dat.bda, p_cb->addr);
- HID_HostCloseDev(p_cb->hid_handle);
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseDev(p_cb->hid_handle);
+ GENERATE_VENDOR_LOGS();
- /* Report OPEN fail event */
- (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG("bta_hh_open_failure: hid_handle = %d", p_cb->hid_handle);
+#endif
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+ /* if virtually unplug, remove device */
+ if (p_cb->vp )
+ {
+ HID_HostRemoveDev( p_cb->hid_handle);
+ bta_hh_clean_up_kdev(p_cb);
+ }
#if BTA_HH_DEBUG
bta_hh_trace_dev_db();
@@ -880,6 +911,10 @@
/* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */
UINT16 event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG("bta_hh_close_act: reason = %d", reason);
+#endif
+
disc_dat.handle = p_cb->hid_handle;
disc_dat.status = p_data->hid_cback.data;
@@ -892,10 +927,13 @@
conn_dat.handle = p_cb->hid_handle;
conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
bdcpy(conn_dat.bda, p_cb->addr);
+ /* finalize device driver */
+ bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
HID_HostCloseDev(p_cb->hid_handle);
/* Report OPEN fail event */
(*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+ GENERATE_VENDOR_LOGS();
#if BTA_HH_DEBUG
bta_hh_trace_dev_db();
@@ -905,7 +943,7 @@
/* otherwise report CLOSE/VC_UNPLUG event */
else
{
- /* finaliza device driver */
+ /* finalize device driver */
bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
/* inform role manager */
bta_sys_conn_close( BTA_ID_HH ,p_cb->app_id, p_cb->addr);
@@ -1166,7 +1204,7 @@
}
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND)
{
- bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
{
@@ -1234,6 +1272,20 @@
break;
}
}
+ if (xx == BTA_HH_MAX_DEVICE)
+ {
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++)
+ {
+ /* No device matched entry for VC, check if VC receivied in waitng for conn state */
+ APPL_TRACE_DEBUG("bta_hh_cb.kdev[xx].state = %d", bta_hh_cb.kdev[xx].state);
+ if (bta_hh_cb.kdev[xx].state == BTA_HH_W4_CONN_ST)
+ {
+ bta_hh_cb.kdev[xx].hid_handle = dev_handle;
+ bta_hh_cb.kdev[xx].vp = TRUE;
+ break;
+ }
+ }
+ }
break;
}
diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h
index ba5eb0e..ecfad54 100644
--- a/bta/hh/bta_hh_int.h
+++ b/bta/hh/bta_hh_int.h
@@ -222,6 +222,14 @@
}tBTA_HH_LE_HID_SRVC;
+#ifndef BTA_HH_LE_HID_SRVC_MAX
+#if (defined(BLE_HH_QUALIFICATION_ENABLED) && BLE_HH_QUALIFICATION_ENABLED == TRUE)
+#define BTA_HH_LE_HID_SRVC_MAX 2
+#else
+#define BTA_HH_LE_HID_SRVC_MAX 1
+#endif
+#endif
+
/* convert a HID handle to the LE CB index */
#define BTA_HH_GET_LE_CB_IDX(x) (((x) >> 4) - 1)
/* convert a GATT connection ID to HID device handle, it is the hi 4 bits of a UINT8 */
@@ -262,11 +270,14 @@
tBTA_HH_STATUS status;
tBTA_GATT_REASON reason;
BOOLEAN is_le_device;
- tBTA_HH_LE_HID_SRVC hid_srvc;
+ UINT8 total_srvc;
+ tBTA_HH_LE_HID_SRVC hid_srvc[BTA_HH_LE_HID_SRVC_MAX];
UINT16 conn_id;
BOOLEAN in_bg_conn;
+ UINT8 cur_srvc_index; /* currently discovering service index */
UINT8 clt_cfg_idx;
UINT16 scan_refresh_char_handle;
+ UINT16 scan_int_char_handle;
BOOLEAN scps_supported;
#define BTA_HH_LE_SCPS_NOTIFY_NONE 0
diff --git a/bta/hh/bta_hh_le.c b/bta/hh/bta_hh_le.c
index 75d6bd3..af7b74c 100644
--- a/bta/hh/bta_hh_le.c
+++ b/bta/hh/bta_hh_le.c
@@ -31,9 +31,9 @@
#include "btm_api.h"
#include "btm_ble_api.h"
#include "btm_int.h"
+#include "device/include/interop.h"
#include "osi/include/log.h"
#include "srvc_api.h"
-#include "stack/include/l2c_api.h"
#include "utl.h"
#ifndef BTA_HH_LE_RECONN
@@ -243,37 +243,50 @@
*******************************************************************************/
static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB *p_cb)
{
+ UINT8 i, j;
+ tBTA_HH_LE_RPT *p_rpt;
+ char *rpt_name;
+
APPL_TRACE_DEBUG("%s: HID Report DB", __func__);
- if (!p_cb->hid_srvc.in_use)
- return;
-
- tBTA_HH_LE_RPT *p_rpt = &p_cb->hid_srvc.report[0];
-
- for (int j = 0; j < BTA_HH_LE_RPT_MAX; j ++, p_rpt++)
+ for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++)
{
- char * rpt_name = "Unknown";
+ if (p_cb->hid_srvc[i].in_use)
+ {
+ p_rpt = &p_cb->hid_srvc[i].report[0];
- if (!p_rpt->in_use)
+ APPL_TRACE_DEBUG("\t HID serivce inst: %d", i);
+
+ for (j = 0; j < BTA_HH_LE_RPT_MAX; j ++, p_rpt++)
+ {
+ rpt_name = "Unknown";
+ if (p_rpt->in_use)
+ {
+ if (p_rpt->uuid == GATT_UUID_HID_REPORT)
+ rpt_name = "Report";
+ if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT)
+ rpt_name = "Boot KB Input";
+ if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT)
+ rpt_name = "Boot KB Output";
+ if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
+ rpt_name = "Boot MI Input";
+
+ APPL_TRACE_DEBUG("\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [srvc_inst_id: %d] [char_inst_id: %d] [Clt_cfg: %d]",
+ rpt_name,
+ p_rpt->uuid ,
+ ((p_rpt->rpt_type < 4) ? bta_hh_le_rpt_name[p_rpt->rpt_type]
+ : "UNKNOWN"),
+ p_rpt->rpt_id,
+ p_rpt->srvc_inst_id,
+ p_rpt->char_inst_id,
+ p_rpt->client_cfg_value);
+ }
+ else
+ break;
+ }
+ }
+ else
break;
-
- if (p_rpt->uuid == GATT_UUID_HID_REPORT)
- rpt_name = "Report";
- if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT)
- rpt_name = "Boot KB Input";
- if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT)
- rpt_name = "Boot KB Output";
- if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
- rpt_name = "Boot MI Input";
-
- APPL_TRACE_DEBUG("\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [srvc_inst_id: %d] [char_inst_id: %d] [Clt_cfg: %d]",
- rpt_name,
- p_rpt->uuid ,
- ((p_rpt->rpt_type < 4) ? bta_hh_le_rpt_name[p_rpt->rpt_type] : "UNKNOWN"),
- p_rpt->rpt_id,
- p_rpt->srvc_inst_id,
- p_rpt->char_inst_id,
- p_rpt->client_cfg_value);
}
}
@@ -490,10 +503,15 @@
*******************************************************************************/
UINT8 bta_hh_le_find_service_inst_by_battery_inst_id(tBTA_HH_DEV_CB *p_cb, UINT8 ba_inst_id)
{
- if (p_cb->hid_srvc.in_use &&
- p_cb->hid_srvc.incl_srvc_inst == ba_inst_id)
+ UINT8 srvc_inst_id;
+
+ for (srvc_inst_id = 0; srvc_inst_id < BTA_HH_LE_HID_SRVC_MAX; srvc_inst_id ++)
{
- return p_cb->hid_srvc.srvc_inst_id;
+ if (p_cb->hid_srvc[srvc_inst_id].in_use &&
+ p_cb->hid_srvc[srvc_inst_id].incl_srvc_inst == ba_inst_id)
+ {
+ return srvc_inst_id;
+ }
}
return BTA_HH_IDX_INVALID;
}
@@ -511,7 +529,7 @@
UINT16 rpt_uuid,
UINT8 char_inst_id)
{
- UINT8 i;
+ UINT8 i,j;
UINT8 hid_inst_id = srvc_inst_id;
tBTA_HH_LE_RPT *p_rpt;
@@ -523,16 +541,19 @@
return NULL;
}
- p_rpt = &p_cb->hid_srvc.report[0];
-
- for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++)
+ for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++)
{
- if (p_rpt->uuid == rpt_uuid &&
- p_rpt->srvc_inst_id == srvc_inst_id &&
- p_rpt->char_inst_id == char_inst_id)
- {
+ p_rpt = &p_cb->hid_srvc[i].report[0];
- return p_rpt;
+ for (j = 0; j < BTA_HH_LE_RPT_MAX; j ++, p_rpt ++)
+ {
+ if (p_rpt->uuid == rpt_uuid &&
+ p_rpt->srvc_inst_id == srvc_inst_id &&
+ p_rpt->char_inst_id == char_inst_id)
+ {
+
+ return p_rpt;
+ }
}
}
return NULL;
@@ -599,7 +620,7 @@
if (hid_inst_id == BTA_HH_IDX_INVALID)
return NULL;
}
- p_rpt = &p_cb->hid_srvc.report[0];
+ p_rpt = &p_cb->hid_srvc[p_cb->cur_srvc_index].report[0];
for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++)
{
@@ -752,11 +773,11 @@
if (p_data->status == BTA_GATT_OK &&
p_data->p_value && p_data->p_value->len == 2) {
UINT8 *pp = p_data->p_value->p_value;
- STREAM_TO_UINT16(p_dev_cb->hid_srvc.ext_rpt_ref, pp);
+ STREAM_TO_UINT16(p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].ext_rpt_ref, pp);
#if BTA_HH_DEBUG == TRUE
APPL_TRACE_DEBUG("%s: External Report Reference UUID 0x%04x", __func__,
- p_dev_cb->hid_srvc.ext_rpt_ref);
+ p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].ext_rpt_ref);
#endif
}
}
@@ -771,9 +792,10 @@
** Parameters:
**
*******************************************************************************/
-void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB *p_dev_cb, UINT8 proto_mode, BOOLEAN register_ba)
+void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB *p_dev_cb, UINT8 srvc_inst,
+ UINT8 proto_mode, BOOLEAN register_ba)
{
- tBTA_HH_LE_RPT *p_rpt = &p_dev_cb->hid_srvc.report[0];
+ tBTA_HH_LE_RPT *p_rpt = &p_dev_cb->hid_srvc[srvc_inst].report[0];
#if BTA_HH_DEBUG == TRUE
APPL_TRACE_DEBUG("%s: bta_hh_le_register_input_notif mode: %d", __func__, proto_mode);
@@ -842,7 +864,8 @@
*******************************************************************************/
void bta_hh_le_deregister_input_notif(tBTA_HH_DEV_CB *p_dev_cb)
{
- tBTA_HH_LE_RPT *p_rpt = &p_dev_cb->hid_srvc.report[0];
+ tBTA_HH_LE_RPT *p_rpt = &p_dev_cb->hid_srvc[0].report[0];
+ APPL_TRACE_DEBUG("%s ---> current service instance:%d", __func__, p_dev_cb->cur_srvc_index);
for (UINT8 i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++)
{
@@ -882,7 +905,7 @@
#if BTA_HH_DEBUG
bta_hh_le_hid_report_dbg(p_cb);
#endif
- bta_hh_le_register_input_notif(p_cb, p_cb->mode, TRUE);
+ bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, TRUE);
bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
#if (BTA_HH_LE_RECONN == TRUE)
@@ -930,13 +953,15 @@
BOOLEAN bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst_id)
{
UINT8 i;
- tBTA_HH_LE_RPT *p_rpt = &p_cb->hid_srvc.report[p_cb->clt_cfg_idx];
+ tBTA_HH_LE_RPT *p_rpt = &p_cb->hid_srvc[srvc_inst_id].report[p_cb->clt_cfg_idx];
for (i = p_cb->clt_cfg_idx; i < BTA_HH_LE_RPT_MAX && p_rpt->in_use; i ++, p_rpt ++)
{
/* enable notification for all input report, regardless mode */
if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT)
{
+ p_cb->cur_srvc_index = srvc_inst_id;
+ APPL_TRACE_DEBUG(" %s service instance :%d", __func__, srvc_inst_id);
if (bta_hh_le_write_char_clt_cfg(p_cb,
p_rpt->char_inst_id,
BTA_GATT_CLT_CONFIG_NOTIFICATION))
@@ -947,13 +972,19 @@
}
}
p_cb->clt_cfg_idx = 0;
-
+ p_cb->cur_srvc_index++;
+ if (p_cb->cur_srvc_index < BTA_HH_LE_HID_SRVC_MAX)
+ {
+ bta_hh_le_write_rpt_clt_cfg(p_cb,p_cb->cur_srvc_index);
+ return TRUE;
+ }
/* client configuration is completed, send open callback */
if (p_cb->state == BTA_HH_W4_CONN_ST)
{
p_cb->disc_active &= ~BTA_HH_LE_DISC_HIDS;
bta_hh_le_open_cmpl(p_cb);
+ p_cb->cur_srvc_index = 0;
}
return FALSE;
}
@@ -975,7 +1006,7 @@
cback_data.handle = p_cb->hid_handle;
/* boot mode is not supported in the remote device */
- if (p_cb->hid_srvc.proto_mode_handle == 0)
+ if (p_cb->hid_srvc[p_cb->cur_srvc_index].proto_mode_handle == 0)
{
p_cb->mode = BTA_HH_PROTO_RPT_MODE;
@@ -987,7 +1018,7 @@
else
{
/* if set to report mode, need to de-register all input report notification */
- bta_hh_le_register_input_notif(p_cb, p_cb->mode, FALSE);
+ bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, FALSE);
cback_data.status = BTA_HH_OK;
}
if (p_cb->state == BTA_HH_W4_CONN_ST)
@@ -1000,7 +1031,7 @@
p_cb->mode = mode;
mode = (mode == BTA_HH_PROTO_BOOT_MODE)? BTA_HH_LE_PROTO_BOOT_MODE : BTA_HH_LE_PROTO_REPORT_MODE;
- gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_cb->hid_srvc.proto_mode_handle, 1,
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_cb->hid_srvc[p_cb->cur_srvc_index].proto_mode_handle, 1,
&mode, BTA_GATTC_TYPE_WRITE_NO_RSP);
exec = TRUE;
}
@@ -1018,19 +1049,25 @@
void bta_hh_le_get_protocol_mode(tBTA_HH_DEV_CB *p_cb)
{
tBTA_HH_HSDATA hs_data;
+ int i;
p_cb->w4_evt = BTA_HH_GET_PROTO_EVT;
-
- if (p_cb->hid_srvc.in_use && p_cb->hid_srvc.proto_mode_handle != 0) {
- gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id, p_cb->hid_srvc.proto_mode_handle);
- return;
+ for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++)
+ {
+ if (p_cb->hid_srvc[i].in_use && p_cb->hid_srvc[i].proto_mode_handle != 0) {
+ gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id, p_cb->hid_srvc[i].proto_mode_handle);
+ break;
+ }
}
/* no service support protocol_mode, by default report mode */
- hs_data.status = BTA_HH_OK;
- hs_data.handle = p_cb->hid_handle;
- hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
- p_cb->w4_evt = 0;
- (* bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH *)&hs_data);
+ if (i == BTA_HH_LE_HID_SRVC_MAX)
+ {
+ hs_data.status = BTA_HH_OK;
+ hs_data.handle = p_cb->hid_handle;
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+ p_cb->w4_evt = 0;
+ (* bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH *)&hs_data);
+ }
}
/*******************************************************************************
@@ -1150,7 +1187,7 @@
APPL_TRACE_DEBUG("%s", __func__);
if (p_cb->status == BTA_HH_OK)
{
- if (!p_cb->hid_srvc.in_use)
+ if (!p_cb->hid_srvc[0].in_use)
{
APPL_TRACE_DEBUG("bta_hh_security_cmpl no reports loaded, try to load");
@@ -1164,7 +1201,7 @@
// }
}
/* discovery has been done for HID service */
- if (p_cb->app_id != 0 && p_cb->hid_srvc.in_use)
+ if (p_cb->app_id != 0 && p_cb->hid_srvc[0].in_use)
{
APPL_TRACE_DEBUG("%s: discovery has been done for HID service", __func__);
/* configure protocol mode */
@@ -1221,13 +1258,18 @@
*******************************************************************************/
void bta_hh_clear_service_cache(tBTA_HH_DEV_CB *p_cb)
{
- tBTA_HH_LE_HID_SRVC *p_hid_srvc = &p_cb->hid_srvc;
+ UINT8 i;
+ tBTA_HH_LE_HID_SRVC *p_hid_srvc = &p_cb->hid_srvc[0];
p_cb->app_id = 0;
+ p_cb->total_srvc = 0;
p_cb->dscp_info.descriptor.dsc_list = NULL;
- osi_free_and_reset((void **)&p_hid_srvc->rpt_map);
- memset(p_hid_srvc, 0, sizeof(tBTA_HH_LE_HID_SRVC));
+ for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++, p_hid_srvc ++)
+ {
+ osi_free_and_reset((void **)&p_hid_srvc->rpt_map);
+ memset(p_hid_srvc, 0, sizeof(tBTA_HH_LE_HID_SRVC));
+ }
}
/*******************************************************************************
@@ -1320,6 +1362,7 @@
p_cb->in_use = TRUE;
p_cb->conn_id = p_data->conn_id;
p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+ p_cb->cur_srvc_index = 0;
bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
@@ -1379,7 +1422,7 @@
*******************************************************************************/
void bta_hh_le_gatt_disc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_STATUS status)
{
- APPL_TRACE_DEBUG("bta_hh_le_gatt_disc_cmpl ");
+ APPL_TRACE_DEBUG("%s srvc_index =%d ", __func__, p_cb->cur_srvc_index);
/* if open sucessful or protocol mode not desired, keep the connection open but inform app */
if (status == BTA_HH_OK || status == BTA_HH_ERR_PROTO)
@@ -1389,7 +1432,7 @@
/* set report notification configuration */
p_cb->clt_cfg_idx = 0;
- bta_hh_le_write_rpt_clt_cfg(p_cb, p_cb->hid_srvc.srvc_inst_id);
+ bta_hh_le_write_rpt_clt_cfg(p_cb, 0);
}
else /* error, close the GATT connection */
{
@@ -1398,7 +1441,7 @@
}
}
-void process_included(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_SERVICE *service) {
+void process_included(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_SERVICE *service, int srvc_index) {
if (!service->included_svc || list_is_empty(service->included_svc)) {
APPL_TRACE_ERROR("%s: Remote device does not have battery level", __func__);
return;
@@ -1412,7 +1455,7 @@
incl_svc->uuid.len == LEN_UUID_16) {
/* read include service UUID */
- p_dev_cb->hid_srvc.incl_srvc_inst = incl_svc->handle;
+ p_dev_cb->hid_srvc[srvc_index].incl_srvc_inst = incl_svc->handle;
for (list_node_t *cn = list_begin(incl_svc->characteristics);
cn != list_end(incl_svc->characteristics); cn = list_next(cn)) {
@@ -1463,7 +1506,7 @@
switch (p_char->uuid.uu.uuid16)
{
case GATT_UUID_HID_CONTROL_POINT:
- p_dev_cb->hid_srvc.control_point_handle = p_char->handle;
+ p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].control_point_handle = p_char->handle;
break;
case GATT_UUID_HID_INFORMATION:
case GATT_UUID_HID_REPORT_MAP:
@@ -1476,7 +1519,7 @@
case GATT_UUID_HID_REPORT:
p_rpt = bta_hh_le_find_alloc_report_entry(p_dev_cb,
- p_dev_cb->hid_srvc.srvc_inst_id,
+ p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].srvc_inst_id,
GATT_UUID_HID_REPORT,
p_char->handle);
if (p_rpt == NULL) {
@@ -1516,7 +1559,7 @@
if(p_char->uuid.len != LEN_UUID_16 &&
p_char->uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE) {
- p_dev_cb->hid_srvc.proto_mode_handle = p_char->handle;
+ p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].proto_mode_handle = p_char->handle;
bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
break;
}
@@ -1535,6 +1578,7 @@
void bta_hh_le_srvc_search_cmpl(tBTA_GATTC_SEARCH_CMPL *p_data)
{
tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+ int srvc_index = 0;
/* service search exception or no HID service is supported on remote */
if (p_dev_cb == NULL)
@@ -1556,22 +1600,43 @@
tBTA_GATTC_SERVICE *service = list_node(sn);
if (service->uuid.uu.uuid16 == UUID_SERVCLASS_LE_HID &&
- service->is_primary && !have_hid) {
+ service->is_primary ) {
have_hid = true;
-
/* found HID primamry service */
- p_dev_cb->hid_srvc.in_use = TRUE;
- p_dev_cb->hid_srvc.srvc_inst_id = service->handle;
- p_dev_cb->hid_srvc.proto_mode_handle = 0;
- p_dev_cb->hid_srvc.control_point_handle = 0;
-
- process_included(p_dev_cb, service);
+ srvc_index = p_dev_cb->cur_srvc_index;
+ p_dev_cb->hid_srvc[srvc_index].in_use = TRUE;
+ p_dev_cb->hid_srvc[srvc_index].srvc_inst_id = service->handle;
+ p_dev_cb->hid_srvc[srvc_index].proto_mode_handle = 0;
+ p_dev_cb->hid_srvc[srvc_index].control_point_handle = 0;
+ process_included(p_dev_cb, service,srvc_index);
bta_hh_le_search_hid_chars(p_dev_cb, service);
- APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__, p_dev_cb->hid_srvc.srvc_inst_id);
+ APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__, p_dev_cb->hid_srvc[srvc_index].srvc_inst_id);
+ if (p_dev_cb->cur_srvc_index < BTA_HH_LE_HID_SRVC_MAX-1)
+ p_dev_cb->cur_srvc_index++;
+ } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_BATTERY) {
+ for (list_node_t *cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC *p_char = list_node(cn);
+ if (p_char->uuid.uu.uuid16 == GATT_UUID_BATTERY_LEVEL &&
+ p_char->uuid.len == LEN_UUID_16) {
+
+ if (bta_hh_le_find_alloc_report_entry(p_dev_cb,
+ service->s_handle,
+ GATT_UUID_BATTERY_LEVEL,
+ p_char->handle) == NULL)
+ APPL_TRACE_ERROR("Add battery report entry failed !!!");
+
+ gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle);
+ APPL_TRACE_DEBUG("%s: battery service handle= %d", __func__, p_char->handle);
+ bta_hh_le_read_char_dscrpt(p_dev_cb, p_char->handle,
+ GATT_UUID_CHAR_CLIENT_CONFIG);
+ }
+ }
} else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_SCAN_PARAM) {
p_dev_cb->scan_refresh_char_handle = 0;
-
+ p_dev_cb->scan_int_char_handle = 0;
+ p_dev_cb->scps_supported = TRUE;
for (list_node_t *cn = list_begin(service->characteristics);
cn != list_end(service->characteristics); cn = list_next(cn)) {
tBTA_GATTC_CHARACTERISTIC *p_char = list_node(cn);
@@ -1585,22 +1650,13 @@
else
p_dev_cb->scps_notify = BTA_HH_LE_SCPS_NOTIFY_NONE;
- break;
}
- }
- } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER) {
- //TODO(jpawlowski): this should be done by GAP profile, remove when GAP is fixed.
- for (list_node_t *cn = list_begin(service->characteristics);
- cn != list_end(service->characteristics); cn = list_next(cn)) {
- tBTA_GATTC_CHARACTERISTIC *p_char = list_node(cn);
if (p_char->uuid.len == LEN_UUID_16 &&
- p_char->uuid.uu.uuid16 == GATT_UUID_GAP_PREF_CONN_PARAM) {
-
- /* read the char value */
- gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle);
-
- break;
- }
+ p_char->uuid.uu.uuid16 == GATT_UUID_SCAN_INT_WINDOW) {
+ p_dev_cb->scan_int_char_handle = p_char->handle;
+ }
+ if (p_dev_cb->scan_refresh_char_handle && p_dev_cb->scan_int_char_handle)
+ break;
}
}
}
@@ -1621,7 +1677,7 @@
{
UNUSED(status);
UNUSED(p_data);
- p_dev_cb->hid_srvc.expl_incl_srvc = TRUE;
+ p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc = TRUE;
}
@@ -1636,7 +1692,7 @@
*******************************************************************************/
void bta_hh_le_save_rpt_map(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data)
{
- tBTA_HH_LE_HID_SRVC *p_srvc = &p_dev_cb->hid_srvc;
+ tBTA_HH_LE_HID_SRVC *p_srvc = &p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index];
osi_free_and_reset((void **)&p_srvc->rpt_map);
@@ -1648,7 +1704,7 @@
UINT8 *pp = p_data->p_value->p_value;
STREAM_TO_ARRAY(p_srvc->rpt_map, pp, p_data->p_value->len);
p_srvc->descriptor.dl_len = p_data->p_value->len;
- p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc.rpt_map;
+ p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].rpt_map;
}
}
@@ -1678,6 +1734,12 @@
const tBTA_GATTC_CHARACTERISTIC *p_char = BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id,
p_data->handle);
+ if (p_char == NULL) {
+ APPL_TRACE_ERROR("%s: report cmpl for Unknown Characteristic,handle: 0x%04x",
+ __func__, p_data->handle);
+ return;
+ }
+
memset(&hs_data, 0, sizeof(hs_data));
hs_data.status = BTA_HH_ERR;
hs_data.handle = p_dev_cb->hid_handle;
@@ -1778,35 +1840,6 @@
{
bta_hh_read_battery_level_cmpl(p_data->status, p_dev_cb, p_data);
}
- else if (char_uuid == GATT_UUID_GAP_PREF_CONN_PARAM)
- {
- //TODO(jpawlowski): this should be done by GAP profile, remove when GAP is fixed.
- if (p_data->status != BTA_GATT_OK || p_data->p_value == NULL) {
- APPL_TRACE_ERROR("%s: read pref conn params error: %d",
- __func__, p_data->status);
- return;
- }
-
- UINT8 *pp = p_data->p_value->p_value;
- UINT16 min, max, latency, tout;
- STREAM_TO_UINT16 (min, pp);
- STREAM_TO_UINT16 (max, pp);
- STREAM_TO_UINT16 (latency, pp);
- STREAM_TO_UINT16 (tout, pp);
-
- // Make sure both min, and max are bigger than 11.25ms, lower values can introduce
- // audio issues if A2DP is also active.
- if (min < BTM_BLE_CONN_INT_MIN_LIMIT)
- min = BTM_BLE_CONN_INT_MIN_LIMIT;
- if (max < BTM_BLE_CONN_INT_MIN_LIMIT)
- max = BTM_BLE_CONN_INT_MIN_LIMIT;
-
- if (tout < BTM_BLE_CONN_TIMEOUT_MIN_DEF)
- tout = BTM_BLE_CONN_TIMEOUT_MIN_DEF;
-
- BTM_BleSetPrefConnParams (p_dev_cb->addr, min, max, latency, tout);
- L2CA_UpdateBleConnParams(p_dev_cb->addr, min, max, latency, tout);
- }
else
{
if (p_data->status == BTA_GATT_OK && p_data->p_value)
@@ -2006,6 +2039,11 @@
const tBTA_GATTC_CHARACTERISTIC *p_char = BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id,
p_data->handle);
+ if (p_char == NULL) {
+ APPL_TRACE_ERROR("%s: write cmpl for Unknown Characteristic,handle: 0x%04x",
+ __func__, p_data->handle);
+ return;
+ }
if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE)
{
@@ -2037,6 +2075,12 @@
const tBTA_GATTC_CHARACTERISTIC *p_char = BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id,
p_data->handle);
+ if (p_char == NULL) {
+ APPL_TRACE_ERROR("%s: write cmpl for Unknown Characteristic,handle: 0x%04x",
+ __func__, p_data->handle);
+ return;
+ }
+
#if BTA_HH_DEBUG
APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
#endif
@@ -2047,7 +2091,7 @@
cback_data.handle = p_dev_cb->hid_handle;
if (p_data->status == BTA_GATT_OK)
{
- bta_hh_le_register_input_notif(p_dev_cb, p_dev_cb->mode, FALSE);
+ bta_hh_le_register_input_notif(p_dev_cb, p_dev_cb->cur_srvc_index, p_dev_cb->mode, FALSE);
cback_data.status = BTA_HH_OK;
}
else
@@ -2089,8 +2133,8 @@
void bta_hh_le_write_char_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
{
tBTA_GATTC_WRITE *p_data = (tBTA_GATTC_WRITE *)p_buf;
- UINT8 srvc_inst_id, hid_inst_id;
-
+ UINT8 srvc_inst_id;
+ UINT8 hid_inst_id = 0;
const tBTA_GATTC_DESCRIPTOR *p_desc = BTA_GATTC_GetDescriptor(p_dev_cb->conn_id,
p_data->handle);
@@ -2100,7 +2144,6 @@
if (desc_uuid == GATT_UUID_CHAR_CLIENT_CONFIG)
{
srvc_inst_id = p_desc->characteristic->service->handle;
- hid_inst_id = srvc_inst_id;
switch (char_uuid)
{
case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */
@@ -2110,11 +2153,14 @@
case GATT_UUID_HID_BT_MOUSE_INPUT:
case GATT_UUID_HID_REPORT:
if (p_data->status == BTA_GATT_OK)
- p_dev_cb->hid_srvc.report[p_dev_cb->clt_cfg_idx].client_cfg_value =
+ p_dev_cb->hid_srvc[hid_inst_id].report[p_dev_cb->clt_cfg_idx].client_cfg_value =
BTA_GATT_CLT_CONFIG_NOTIFICATION;
p_dev_cb->clt_cfg_idx ++;
- bta_hh_le_write_rpt_clt_cfg(p_dev_cb, hid_inst_id);
-
+ hid_inst_id = p_dev_cb->cur_srvc_index;
+ if (hid_inst_id < BTA_HH_LE_HID_SRVC_MAX ) {
+ APPL_TRACE_DEBUG("write rpt clt cfg for hid srvc instance: %d", hid_inst_id);
+ bta_hh_le_write_rpt_clt_cfg(p_dev_cb, hid_inst_id);
+ }
break;
case GATT_UUID_SCAN_REFRESH:
@@ -2169,10 +2215,21 @@
return;
}
+ if (p_char == NULL) {
+ APPL_TRACE_ERROR("%s: notification received for Unknown Characteristic,handle: 0x%04x",
+ __func__, p_data->handle);
+ return;
+ }
app_id= p_dev_cb->app_id;
+ if (p_char->uuid.uu.uuid16 == GATT_UUID_SCAN_REFRESH) {
+ APPL_TRACE_DEBUG("Notification received for scan refresh parameters");
+ BTA_HhUpdateLeScanParam(p_dev_cb->hid_handle,BTM_BLE_SCAN_SLOW_INT_1,
+ BTM_BLE_SCAN_SLOW_WIN_1);
+ return;
+ }
p_rpt = bta_hh_le_find_report_entry(p_dev_cb,
- p_dev_cb->hid_srvc.srvc_inst_id,
+ p_dev_cb->hid_srvc[0].srvc_inst_id,
p_char->uuid.uu.uuid16,
p_char->handle);
if (p_rpt == NULL)
@@ -2324,15 +2381,31 @@
** Returns void
**
*******************************************************************************/
-void bta_hh_le_get_rpt(tBTA_HH_DEV_CB *p_cb, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id)
+void bta_hh_le_get_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id)
{
- tBTA_HH_LE_RPT *p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id);
-
+ tBTA_HH_LE_RPT *p_rpt;
+#if (defined BLE_HH_QUALIFICATION_ENABLED && BLE_HH_QUALIFICATION_ENABLED == TRUE)
+ UINT8 char_handle;
+ switch (rpt_id) {
+ case 7:
+ APPL_TRACE_DEBUG("bta_hh_le_get_rpt: read hid input client confg char ");
+ bta_hh_le_hid_read_rpt_clt_cfg(p_cb->addr, srvc_inst);
+ return;
+ default:
+ if (rpt_id > 7) {
+ char_handle = rpt_id;
+ APPL_TRACE_DEBUG("bta_hh_le_get_rpt: read PNP ID char handle = %d\n ",char_handle);
+ BTA_GATTC_ReadCharacteristic(p_cb->conn_id, char_handle, BTA_GATT_AUTH_REQ_NONE);
+ return;
+ }
+ }
+#endif
+ p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id);
if (p_rpt == NULL) {
APPL_TRACE_ERROR("%s: no matching report", __func__);
return;
}
-
+ APPL_TRACE_DEBUG("bta_hh_le_get_rpt UUID:%d", p_rpt->uuid);
p_cb->w4_evt = BTA_HH_GET_RPT_EVT;
gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id, p_rpt->char_inst_id);
}
@@ -2346,7 +2419,7 @@
** Returns void
**
*******************************************************************************/
-void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb,
+void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst,
tBTA_HH_RPT_TYPE r_type,
BT_HDR *p_buf, UINT16 w4_evt )
{
@@ -2362,9 +2435,8 @@
/* strip report ID from the data */
p_value = (UINT8 *)(p_buf + 1) + p_buf->offset;
STREAM_TO_UINT8(rpt_id, p_value);
- p_buf->len -= 1;
- p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id);
+ p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id);
if (p_rpt == NULL) {
APPL_TRACE_ERROR("%s: no matching report", __func__);
@@ -2372,12 +2444,17 @@
return;
}
+ p_buf->len -= 1;
+ APPL_TRACE_DEBUG("bta_hh_le_write_rpt: ReportID: 0x%02x Data Len: %d", rpt_id, p_buf->len);
p_cb->w4_evt = w4_evt;
-
- const tBTA_GATTC_CHARACTERISTIC *p_char = BTA_GATTC_GetCharacteristic(p_cb->conn_id,
- p_rpt->char_inst_id);
-
tBTA_GATTC_WRITE_TYPE write_type = BTA_GATTC_TYPE_WRITE;
+ const tBTA_GATTC_CHARACTERISTIC *p_char = BTA_GATTC_GetCharacteristic(p_cb->conn_id,
+ p_rpt->char_inst_id);
+#if ((defined BLE_HH_QUALIFICATION_ENABLED && BLE_HH_QUALIFICATION_ENABLED == TRUE))
+
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
+ p_buf->len, p_value, write_type);
+#endif
if (p_char && (p_char->properties & BTA_GATT_CHAR_PROP_BIT_WRITE_NR))
write_type = BTA_GATTC_TYPE_WRITE_NO_RSP;
@@ -2398,7 +2475,7 @@
{
ctrl_type -= BTA_HH_CTRL_SUSPEND;
- gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_cb->hid_srvc.control_point_handle, 1,
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_cb->hid_srvc[0].control_point_handle, 1,
&ctrl_type, BTA_GATTC_TYPE_WRITE_NO_RSP);
}
@@ -2413,6 +2490,8 @@
*******************************************************************************/
void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
+ int srvc_inst = 0;
+ APPL_TRACE_DEBUG("current service inst:%d", p_cb->cur_srvc_index);
switch(p_data->api_sndcmd.t_type)
{
case HID_TRANS_SET_PROTOCOL:
@@ -2425,24 +2504,33 @@
break;
case HID_TRANS_GET_REPORT:
- bta_hh_le_get_rpt(p_cb,
+ for (srvc_inst=0; srvc_inst < p_cb->cur_srvc_index; srvc_inst++) {
+ bta_hh_le_get_rpt(p_cb,
+ srvc_inst,
p_data->api_sndcmd.param,
p_data->api_sndcmd.rpt_id);
+ }
break;
case HID_TRANS_SET_REPORT:
- bta_hh_le_write_rpt(p_cb,
+ for (srvc_inst=0; srvc_inst < p_cb->cur_srvc_index; srvc_inst++) {
+ bta_hh_le_write_rpt(p_cb,
+ srvc_inst,
p_data->api_sndcmd.param,
p_data->api_sndcmd.p_data,
BTA_HH_SET_RPT_EVT);
+ }
break;
case HID_TRANS_DATA: /* output report */
- bta_hh_le_write_rpt(p_cb,
+ for (srvc_inst=0; srvc_inst < p_cb->cur_srvc_index; srvc_inst++) {
+ bta_hh_le_write_rpt(p_cb,
+ srvc_inst,
p_data->api_sndcmd.param,
p_data->api_sndcmd.p_data,
BTA_HH_DATA_EVT);
+ }
break;
case HID_TRANS_CONTROL:
@@ -2473,10 +2561,12 @@
*******************************************************************************/
void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB *p_cb)
{
- if (p_cb->hid_srvc.in_use)
+ UINT8 i;
+
+ for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX && p_cb->hid_srvc[i].in_use; i ++)
{
- p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc.descriptor.dl_len;
- p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc.descriptor.dsc_list;
+ p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc[i].descriptor.dl_len;
+ p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc[i].descriptor.dsc_list;
(*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info);
}
@@ -2605,7 +2695,7 @@
UINT16_TO_STREAM(p, p_buf->le_scpp_update.scan_int);
UINT16_TO_STREAM(p, p_buf->le_scpp_update.scan_win);
- gatt_queue_write_op(GATT_WRITE_CHAR, p_dev_cb->conn_id, p_dev_cb->scan_refresh_char_handle, 2,
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_dev_cb->conn_id, p_dev_cb->scan_int_char_handle, 4,
value, BTA_GATTC_TYPE_WRITE_NO_RSP);
}
@@ -2705,7 +2795,7 @@
** Returns void
**
*******************************************************************************/
-void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id)
+void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 srvc_inst)
{
tBTA_HH_DEV_CB *p_cb = NULL;
tBTA_HH_LE_RPT *p_rpt ;
@@ -2719,16 +2809,20 @@
}
p_cb = &bta_hh_cb.kdev[index];
+ p_rpt = &p_cb->hid_srvc[srvc_inst].report[0];
- p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, BTA_HH_RPTT_INPUT, rpt_id);
-
- if (p_rpt == NULL)
- {
- APPL_TRACE_ERROR("bta_hh_le_write_rpt: no matching report");
- return;
+ while(p_rpt != NULL ) {
+ if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+ if(p_rpt->uuid == GATT_UUID_HID_REPORT) {
+ bta_hh_le_read_char_dscrpt(p_cb, p_rpt->char_inst_id,
+ GATT_UUID_CHAR_CLIENT_CONFIG);
+ break;
+ }
+ }
+ if (p_rpt->index == BTA_HH_LE_RPT_MAX - 1)
+ break;
+ p_rpt++;
}
-
- bta_hh_le_read_char_dscrpt(p_cb, p_rpt->char_inst_id, GATT_UUID_CHAR_CLIENT_CONFIG);
return;
}
diff --git a/bta/hh/bta_hh_main.c b/bta/hh/bta_hh_main.c
index a4455ef..45e7754 100644
--- a/bta/hh/bta_hh_main.c
+++ b/bta/hh/bta_hh_main.c
@@ -289,8 +289,10 @@
if (!p_cb)
{
/* BTA HH enabled already? otherwise ignore the event although it's bad*/
- if (bta_hh_cb.p_cback != NULL)
+ if (bta_hh_cb.p_cback != NULL && p_data != NULL)
{
+ APPL_TRACE_ERROR("bta_hh_sm_execute: event = %0x, BTA_HH_API_OPEN_EVT = %x",
+ event, BTA_HH_API_OPEN_EVT);
switch (event)
{
/* no control block available for new connection */
@@ -352,6 +354,13 @@
cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
break;
+ case BTA_HH_API_GET_DSCP_EVT:
+ cback_event = BTA_HH_CLOSE_EVT;
+
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->hdr.layer_specific;
+ break;
+
default:
/* invalid handle, call bad API event */
APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
@@ -386,7 +395,7 @@
p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;
- if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
+ if ((action = state_table[event][BTA_HH_ACTION]) < BTA_HH_IGNORE)
{
(*bta_hh_action[action])(p_cb, p_data);
}
@@ -456,7 +465,7 @@
* So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
* force the index to be IDX_INVALID
*/
- if ((index != BTA_HH_IDX_INVALID) &&
+ if ((index != BTA_HH_IDX_INVALID) && (index < BTA_HH_MAX_DEVICE) &&
(bta_hh_cb.kdev[index].in_use == FALSE)) {
index = BTA_HH_IDX_INVALID;
}
@@ -469,7 +478,13 @@
else
index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
- if (index != BTA_HH_IDX_INVALID)
+ if (p_msg->event == BTA_HH_INT_CLOSE_EVT && index == BTA_HH_IDX_INVALID)
+ {
+ /* Special handling for vc unplug event before device is opened */
+ index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
+ }
+
+ if ((index != BTA_HH_IDX_INVALID) && (index < BTA_HH_MAX_DEVICE))
p_cb = &bta_hh_cb.kdev[index];
#if BTA_HH_DEBUG
diff --git a/bta/hh/bta_hh_utils.c b/bta/hh/bta_hh_utils.c
index c8ea864..695ddad 100644
--- a/bta/hh/bta_hh_utils.c
+++ b/bta/hh/bta_hh_utils.c
@@ -22,6 +22,8 @@
#include "bta_hh_int.h"
+#include "device/include/interop.h"
+#include "device/include/interop_config.h"
/* if SSR max latency is not defined by remote device, set the default value
as half of the link supervision timeout */
@@ -51,6 +53,27 @@
/*******************************************************************************
+** Function blacklist_adjust_sniff_subrate
+**
+** Description It's used to update SSR parameter such as max latency,
+** if device is found in HID blacklist.
+**
+** Returns None
+*******************************************************************************/
+static void blacklist_adjust_sniff_subrate(BD_ADDR peer_dev, UINT16 *ssr_max_lat)
+{
+ UINT16 old_ssr_max_lat = *ssr_max_lat;
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, peer_dev);
+ if (interop_match_addr_get_max_lat(INTEROP_UPDATE_HID_SSR_MAX_LAT, &remote_bdaddr,
+ ssr_max_lat)) {
+ APPL_TRACE_WARNING("%s: Device in blacklist for ssr, max latency changed "
+ "from %d to %d", __func__, old_ssr_max_lat, *ssr_max_lat);
+ }
+}
+
+
+/*******************************************************************************
**
** Function bta_hh_find_cb
**
@@ -187,7 +210,8 @@
UINT8 app_id)
{
#if BTA_HH_DEBUG
- APPL_TRACE_DEBUG("subclass = 0x%2x", sub_class);
+ APPL_TRACE_DEBUG("subclass = 0x%2x, maxlat = 0x%2x, minto = 0x%2x",
+ sub_class, ssr_max_latency, ssr_min_tout);
#endif
p_cb->hid_handle = handle;
@@ -198,6 +222,8 @@
p_cb->app_id = app_id;
p_cb->dscp_info.ssr_max_latency = ssr_max_latency;
+ blacklist_adjust_sniff_subrate(p_cb->addr, &(p_cb->dscp_info.ssr_max_latency));
+
p_cb->dscp_info.ssr_min_tout = ssr_min_tout;
/* store report descriptor info */
@@ -240,7 +266,7 @@
}
}
#if BTA_HH_DEBUG
- APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
+ APPL_TRACE_ERROR("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
#endif
return FALSE;
}
@@ -423,11 +449,15 @@
BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency) ;
ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency);
+ APPL_TRACE_DEBUG("ssr_max_latency: 0x%2x", ssr_max_latency);
/* per 1.1 spec, if the newly calculated max latency is greater than
BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use BTA_HH_SSR_MAX_LATENCY_DEF */
- if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF)
+ if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF) {
ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
+ APPL_TRACE_DEBUG("Updating ssr_max_latency to: 0x%2x",
+ BTA_HH_SSR_MAX_LATENCY_DEF);
+ }
* p_max_ssr_lat = ssr_max_latency;
}
@@ -439,6 +469,8 @@
else
* p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout;
+ APPL_TRACE_DEBUG("max_lat: 0x%2x, min to: 0x%2x", * p_max_ssr_lat,
+ * p_min_ssr_tout);
status = BTA_HH_OK;
break;
@@ -465,7 +497,12 @@
for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) {
osi_free_and_reset((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list);
}
- osi_free_and_reset((void **)&bta_hh_cb.p_disc_db);
+
+ if (bta_hh_cb.p_disc_db) {
+ /* Cancel SDP if it had been started. */
+ (void)SDP_CancelServiceSearch (bta_hh_cb.p_disc_db);
+ osi_free_and_reset((void **)&bta_hh_cb.p_disc_db);
+ }
(* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status);
/* all connections are down, no waiting for diconnect */
diff --git a/bta/hl/bta_hl_act.c b/bta/hl/bta_hl_act.c
index fe7fc2c..bb15cf4 100644
--- a/bta/hl/bta_hl_act.c
+++ b/bta/hl/bta_hl_act.c
@@ -414,7 +414,7 @@
tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
tMCA_RESULT result;
- tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ tBTA_HL_STATUS status;
BOOLEAN free_buf = FALSE;
BOOLEAN close_dch = FALSE;
tBTA_HL evt_data;
@@ -423,7 +423,11 @@
#if (BTA_HL_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_hl_dch_ci_get_tx_data");
#endif
-
+ if (p_data != NULL)
+ {
+ status = p_data->ci_get_put_data.status;
+ APPL_TRACE_WARNING("bta_hl_dch_ci_put_rx_data:status=%d", status);
+ }
p_dcb->cout_oper &= ~BTA_HL_CO_GET_TX_DATA_MASK;
if (p_dcb->close_pending)
@@ -436,6 +440,10 @@
close_dch = TRUE;
}
}
+ else if (status == BTA_HL_STATUS_FAIL)
+ {
+ free_buf = TRUE;
+ }
else
{
if ((result = MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_dcb->p_tx_pkt)) != MCA_SUCCESS)
diff --git a/bta/hl/bta_hl_main.c b/bta/hl/bta_hl_main.c
index 8bf2bc6..6a2e499 100644
--- a/bta/hl/bta_hl_main.c
+++ b/bta/hl/bta_hl_main.c
@@ -440,7 +440,7 @@
for (i = 0; i < BTA_HL_CCH_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != BTA_HL_CCH_IGNORE)
+ if ((action = state_table[event][i]) < BTA_HL_CCH_IGNORE)
{
(*bta_hl_cch_action[action])(app_idx, mcl_idx, p_data);
}
@@ -497,7 +497,7 @@
for (i = 0; i < BTA_HL_DCH_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != BTA_HL_DCH_IGNORE)
+ if ((action = state_table[event][i]) < BTA_HL_DCH_IGNORE)
{
(*bta_hl_dch_action[action])(app_idx, mcl_idx, mdl_idx, p_data);
}
diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h
index e281fb1..64a6e0b 100644
--- a/bta/include/bta_ag_api.h
+++ b/bta/include/bta_ag_api.h
@@ -30,20 +30,6 @@
/*****************************************************************************
** Constants and data types
*****************************************************************************/
-#define HFP_VERSION_1_1 0x0101
-#define HFP_VERSION_1_5 0x0105
-#define HFP_VERSION_1_6 0x0106
-#define HFP_VERSION_1_7 0x0107
-
-#define HSP_VERSION_1_0 0x0100
-#define HSP_VERSION_1_2 0x0102
-
-/* Note, if you change the default version here, please also change the one in
- * bta_hs_api.h, they are meant to be the same.
- */
-#ifndef BTA_HFP_VERSION
-#define BTA_HFP_VERSION HFP_VERSION_1_7
-#endif
/* AG feature masks */
#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */
@@ -56,20 +42,15 @@
#define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */
#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */
-
-#define HFP_1_6_FEAT_MASK 0x000003FF /* Valid feature bit mask for HFP 1.6 (and below) */
-
-/* HFP 1.7+ */
-#define BTA_AG_FEAT_HF_IND 0x00000400 /* HF Indicators */
-#define BTA_AG_FEAT_ESCO 0x00000800 /* eSCO S4 (and T2) setting supported */
-
+#define BTA_AG_FEAT_HFIND 0x00000400 /* HF indicators */
+#define BTA_AG_FEAT_S4 0x00000800 /* ESCO S4 link setting */
+#define BTA_AG_FEAT_VOIP 0x00001000 /* VoIP call */
/* Proprietary features: using 31 ~ 16 bits */
#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */
#define BTA_AG_FEAT_UNAT 0x00020000 /* Pass unknown AT commands to application */
#define BTA_AG_FEAT_NOSCO 0x00040000 /* No SCO control performed by BTA AG */
#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */
-#define BTA_AG_FEAT_VOIP 0x00100000 /* VoIP call */
typedef UINT32 tBTA_AG_FEAT;
@@ -85,9 +66,6 @@
#define BTA_AG_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */
#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure */
-/*Status to disallow passing AT Events after BTIF */
-
-#define BTA_AG_DISALLOW_AT 5
typedef UINT8 tBTA_AG_STATUS;
/* handle values used with BTA_AgResult */
@@ -99,17 +77,6 @@
* They donot interfere with each other
*/
-/* Number of supported HF indicators, there is one HF indicator so far i.e.
- enhanced driver status. */
-/* Number of supported HF indicators,
- 1 for Enhanced Safety Status
- 2 for Battery Level Status */
-#ifndef BTA_AG_NUM_LOCAL_HF_IND
-#define BTA_AG_NUM_LOCAL_HF_IND 2
-#endif
-
-
-
#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
/* AG result codes used with BTA_AgResult */
@@ -135,7 +102,8 @@
#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held */
#define BTA_AG_UNAT_RES 20 /* Response to unknown AT command event */
#define BTA_AG_MULTI_CALL_RES 21 /* SLC at three way call */
-#define BTA_AG_BIND_RES 22 /* Activate/Deactivate HF indicator */
+#define BTA_AG_BIND_RES 22 /* Send indicator response for AT+BIND */
+
typedef UINT8 tBTA_AG_RES;
@@ -148,14 +116,11 @@
#define BTA_AG_PEER_FEAT_ECS 0x0020 /* Enhanced Call Status */
#define BTA_AG_PEER_FEAT_ECC 0x0040 /* Enhanced Call Control */
#define BTA_AG_PEER_FEAT_CODEC 0x0080 /* Codec Negotiation */
-#define BTA_AG_PEER_FEAT_HF_IND 0x0100 /* HF Indicators */
-#define BTA_AG_PEER_FEAT_ESCO 0x0200 /* eSCO S4 (and T2) setting supported */
+#define BTA_AG_PEER_FEAT_HFIND 0x0100 /* HF indicators */
+#define BTA_AG_PEER_FEAT_S4 0x0200 /* ESCO S4 link settings */
+#define BTA_AG_PEER_FEAT_VOIP 0x0400 /* VoIP call */
-/* Proprietary features: using bits after 12 */
-#define BTA_AG_PEER_FEAT_UNAT 0x1000 /* Pass unknown AT command responses to application */
-#define BTA_AG_PEER_FEAT_VOIP 0x2000 /* VoIP call */
-
-typedef uint16_t tBTA_AG_PEER_FEAT;
+typedef UINT16 tBTA_AG_PEER_FEAT;
/* HFP peer supported codec masks */
// TODO(google) This should use common definitions
@@ -165,6 +130,10 @@
#define BTA_AG_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */
typedef UINT16 tBTA_AG_PEER_CODEC;
+/* HFP peer supported HF indicator assigned numbers */
+#define BTM_AG_HFIND_NONE 0
+#define BTA_AG_HFIND_ENHANCED_SAFETY 1 /* Enhanced Safety HF indicator */
+
/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */
#define BTA_AG_ERR_PHONE_FAILURE 0 /* Phone Failure */
#define BTA_AG_ERR_NO_CONN_PHONE 1 /* No connection to phone */
@@ -244,12 +213,18 @@
#define BTA_AG_AT_MAX_LEN 256
#endif
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE 0x01 /* no argument */
+#define BTA_AG_AT_SET 0x02 /* set value */
+#define BTA_AG_AT_READ 0x04 /* read value */
+#define BTA_AG_AT_TEST 0x08 /* test value range */
+#define BTA_AG_AT_FREE 0x10 /* freeform argument */
+
/* data associated with BTA_AG_IND_RES */
typedef struct
{
- uint16_t id;
- uint16_t value;
- bool on_demand;
+ UINT16 id;
+ UINT16 value;
} tBTA_AG_IND;
/* data type for BTA_AgResult() */
@@ -298,8 +273,10 @@
#define BTA_AG_AT_CBC_EVT 25 /* Battery Level report from HF */
#define BTA_AG_AT_BAC_EVT 26 /* avablable codec */
#define BTA_AG_AT_BCS_EVT 27 /* Codec select */
-#define BTA_AG_AT_BIND_EVT 28 /* HF indicator */
-#define BTA_AG_AT_BIEV_EVT 29 /* HF indicator updates from peer */
+#define BTA_AG_AT_BIND_EVT 28 /* Read HF indicators supported values */
+#define BTA_AG_AT_BIEV_EVT 29 /* HF indicator value update from HF*/
+
+
typedef UINT8 tBTA_AG_EVT;
@@ -351,7 +328,6 @@
char str[BTA_AG_AT_MAX_LEN+1];
UINT16 num;
UINT8 idx; /* call number used by CLCC and CHLD */
- UINT16 lidx; /* long index, ex, HF indicator */
} tBTA_AG_VAL;
/* union of data associated with AG callback */
@@ -415,24 +391,13 @@
#define BTA_AG_BEARER_RES2 6 /* Reserved */
#define BTA_AG_BEARER_RES3 7 /* Reserved */
-/* type for HF indicator */
-typedef struct
-{
- UINT16 ind_id;
- BOOLEAN is_supported;
- BOOLEAN is_enable;
- UINT32 ind_min_val;
- UINT32 ind_max_val;
-} tBTA_AG_HF_IND;
/* AG configuration structure */
typedef struct
{
char *cind_info;
- char *bind_info;
- uint8_t num_local_hf_ind;
- int32_t conn_tout;
- uint16_t sco_pkt_types;
+ INT32 conn_tout;
+ UINT16 sco_pkt_types;
char *chld_val_ecc;
char *chld_val;
} tBTA_AG_CFG;
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 4a8cd5f..0984f2c 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -392,12 +392,22 @@
/* advertising instance parameters */
typedef struct
{
- UINT16 adv_int_min; /* minimum adv interval */
- UINT16 adv_int_max; /* maximum adv interval */
- tBTA_BLE_ADV_EVT adv_type; /* adv event type */
+ UINT32 adv_int_min; /* minimum adv interval */
+ UINT32 adv_int_max; /* maximum adv interval */
+ UINT16 adv_type; /* adv event type */
tBTA_BLE_ADV_CHNL_MAP channel_map; /* adv channel map */
tBTA_BLE_AFP adv_filter_policy; /* advertising filter policy */
tBTA_BLE_ADV_TX_POWER tx_power; /* adv tx power */
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ UINT8 pri_phy;
+ UINT8 sec_adv_max_skip; /* max adv events skipped before AUX_ADV_IND is sent */
+ UINT8 sec_adv_phy; /* PHY for secondary channel */
+ UINT8 adv_sid;
+ UINT8 scan_req_notf_enb; /* send scan req notifications from controller */
+ UINT16 duration; /* duration of adv */
+ UINT8 max_ext_adv_evts;
+ UINT8 frag_pref;
+#endif
}tBTA_BLE_ADV_PARAMS;
/* These are the fields returned in each device adv packet. It
@@ -593,7 +603,8 @@
#define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */
#define BTA_DM_LE_FEATURES_READ 27 /* Cotroller specific LE features are read */
#define BTA_DM_ENER_INFO_READ 28 /* Energy info read */
-#define BTA_DM_BLE_SC_OOB_REQ_EVT 29 /* SMP SC OOB request event */
+#define BTA_DM_LE_ADV_EXT_FEATURES_READ 29
+#define BTA_DM_BLE_SC_OOB_REQ_EVT 30 /* SMP SC OOB request event */
typedef uint8_t tBTA_DM_SEC_EVT;
/* Structure associated with BTA_DM_ENABLE_EVT */
@@ -726,6 +737,7 @@
UINT8 fail_reason; /* The HCI reason/error code for when success=FALSE */
tBLE_ADDR_TYPE addr_type; /* Peer device address type */
tBT_DEVICE_TYPE dev_type;
+ BOOLEAN smp_over_br; /* SMP pairing done over BR/EDR link CID 7 */
} tBTA_DM_AUTH_CMPL;
@@ -905,6 +917,10 @@
#define BTA_BLE_MULTI_ADV_DISABLE_EVT 2
#define BTA_BLE_MULTI_ADV_PARAM_EVT 3
#define BTA_BLE_MULTI_ADV_DATA_EVT 4
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+#define BTA_BLE_EXTENDED_ADV_ENB_EVT 5
+#define BTA_BLE_EXTENDED_ADV_PARAM_EVT 6
+#endif
typedef UINT8 tBTA_BLE_MULTI_ADV_EVT;
@@ -972,6 +988,12 @@
tBTA_DM_BLE_PF_ADV_TRACK_ENTRIES num_of_tracking_entries;
} tBTA_DM_BLE_PF_FILT_PARAMS;
+/* HCI RAW Command Callback */
+typedef tBTM_RAW_CMPL_CB tBTA_RAW_CMPL_CBACK;
+
+/* Vendor Specific Command Callback */
+typedef tBTM_VSC_CMPL_CB tBTA_VENDOR_CMPL_CBACK;
+
/* Search callback events */
#define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */
#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */
@@ -995,6 +1017,7 @@
BOOLEAN is_limited; /* TRUE, if the limited inquiry bit is set in the CoD */
INT8 rssi; /* The rssi value */
UINT8 *p_eir; /* received EIR */
+ UINT16 adv_data_len;
#if (BLE_INCLUDED == TRUE)
UINT8 inq_result_type;
UINT8 ble_addr_type;
@@ -1226,8 +1249,8 @@
#endif
#ifndef BTA_DM_PM_SNIFF2_MAX
-#define BTA_DM_PM_SNIFF2_MAX 180
-#define BTA_DM_PM_SNIFF2_MIN 150
+#define BTA_DM_PM_SNIFF2_MAX 54
+#define BTA_DM_PM_SNIFF2_MIN 30
#define BTA_DM_PM_SNIFF2_ATTEMPT 4
#define BTA_DM_PM_SNIFF2_TIMEOUT 1
#endif
@@ -1253,6 +1276,13 @@
#define BTA_DM_PM_SNIFF5_TIMEOUT 0
#endif
+#ifndef BTA_DM_PM_SNIFF6_MAX
+#define BTA_DM_PM_SNIFF6_MAX 30
+#define BTA_DM_PM_SNIFF6_MIN 10
+#define BTA_DM_PM_SNIFF6_ATTEMPT 4
+#define BTA_DM_PM_SNIFF6_TIMEOUT 1
+#endif
+
#ifndef BTA_DM_PM_PARK_MAX
#define BTA_DM_PM_PARK_MAX 800
#define BTA_DM_PM_PARK_MIN 400
@@ -1402,6 +1432,34 @@
/*******************************************************************************
**
+** Function BTA_DmHciRawCommand
+**
+** Description This function sends the HCI RAW command
+** to the controller
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+extern tBTA_STATUS BTA_DmHciRawCommand (UINT16 opcode, UINT8 param_len,UINT8 *p_param_buf, tBTA_RAW_CMPL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_DmVendorSpecificCommand
+**
+** Description This function sends the vendor specific command
+** to the controller
+**
+**
+** Returns tBTA_STATUS
+**
+*******************************************************************************/
+extern tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode,
+ UINT8 param_len,UINT8 *p_param_buf, tBTA_VENDOR_CMPL_CBACK *p_cback);
+
+
+/*******************************************************************************
+**
** Function BTA_DmSearch
**
** Description This function searches for peer Bluetooth devices. It
@@ -1844,8 +1902,9 @@
** Returns void
**
*******************************************************************************/
-extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
- UINT32 scan_window, tBLE_SCAN_MODE scan_mode,
+extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT8 scan_phys, UINT32 scan_interval,
+ UINT32 scan_window, UINT16 scan_interval_coded,
+ UINT16 scan_window_coded, tBLE_SCAN_MODE scan_mode,
tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_status_cback);
/*******************************************************************************
@@ -1967,7 +2026,7 @@
** Returns void
**
*******************************************************************************/
-extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration,
+extern void BTA_DmBleObserve(BOOLEAN start, UINT16 duration, UINT16 period,
tBTA_DM_SEARCH_CBACK *p_results_cb);
@@ -2090,7 +2149,7 @@
**
*******************************************************************************/
extern void BTA_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp,
- tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_data);
+ tBTA_BLE_AD_MASK data_mask, UINT8 frag_pref, tBTA_BLE_ADV_DATA *p_data);
/*******************************************************************************
**
@@ -2136,6 +2195,30 @@
/*******************************************************************************
**
+** Function BTA_DmBleSetPhy
+**
+** Description This function is to set Tx and Rx Phy for a connection
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTA_DmBleSetPhy(BD_ADDR remote_device, UINT8 all_phy,
+ UINT8 tx_phy, UINT8 rx_phy, UINT16 phy_options);
+
+/*******************************************************************************
+**
+** Function BTA_DmBleSetDefaultPhy
+**
+** Description This function is to set default Tx and Rx Phy
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTA_DmBleSetDefaultPhy(UINT8 all_phy,
+ UINT8 tx_phy, UINT8 rx_phy);
+
+/*******************************************************************************
+**
** Function BTA_DmBleSetStorageParams
**
** Description This function is called to set the storage parameters
diff --git a/bta/include/bta_av_aac.h b/bta/include/bta_av_aac.h
new file mode 100644
index 0000000..310cbfa
--- /dev/null
+++ b/bta/include/bta_av_aac.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Interface to utility functions for AAC codec
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_AAC_H
+#define BTA_AV_AAC_H
+
+
+/* AAC packet header size */
+#define BTA_AV_AAC_HDR_SIZE A2D_AAC_MPL_HDR_LEN
+
+/*******************************************************************************
+**
+** Function bta_av_aac_cfg_in_cap
+**
+** Description Checks if AAC codec config is allowed for given caps.
+** codec config bits are also checked for sanity
+**
+** Returns 0 if ok, nonzero if error.
+**
+*******************************************************************************/
+extern UINT8 bta_av_aac_cfg_in_cap(UINT8 *p_cfg, tA2D_AAC_CIE *p_cap);
+
+#endif /* BTA_AV_AAC_H */
+
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
index 701d90c..7dd1e6f 100644
--- a/bta/include/bta_av_api.h
+++ b/bta/include/bta_av_api.h
@@ -1,4 +1,10 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
+/******************************************************************************
*
* Copyright (C) 2004-2012 Broadcom Corporation
*
@@ -60,6 +66,7 @@
#define BTA_AV_FEAT_METADATA 0x0040 /* remote control Metadata Transfer command/response */
#define BTA_AV_FEAT_MULTI_AV 0x0080 /* use multi-av, if controller supports it */
#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */
+#define BTA_AV_FEAT_CA 0x0020 /* use cover art */
#define BTA_AV_FEAT_MASTER 0x0100 /* stream only as master role */
#define BTA_AV_FEAT_ADV_CTRL 0x0200 /* remote control Advanced Control command/response */
#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */
@@ -67,6 +74,7 @@
#define BTA_AV_FEAT_APP_SETTING 0x2000 /* Player app setting support */
/* Internal features */
+#define BTA_AV_FEAT_AVRC_UI_UPDATE 0x4000 /* Update UI to show notification for browsing capable remote*/
#define BTA_AV_FEAT_NO_SCO_SSPD 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */
typedef UINT16 tBTA_AV_FEAT;
@@ -89,15 +97,17 @@
/* offset of codec type in codec info byte array */
#define BTA_AV_CODEC_TYPE_IDX AVDT_CODEC_TYPE_INDEX /* 2 */
-
-
/* maximum number of streams created: 1 for audio, 1 for video */
#ifndef BTA_AV_NUM_STRS
#define BTA_AV_NUM_STRS 2
#endif
#ifndef BTA_AV_MAX_SEPS
-#define BTA_AV_MAX_SEPS 2
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+#define BTA_AV_MAX_SEPS 4
+#else
+#define BTA_AV_MAX_SEPS 3
+#endif
#endif
#ifndef BTA_AV_MAX_A2DP_MTU
@@ -126,6 +136,9 @@
/* Company ID in BT assigned numbers */
#define BTA_AV_BT_VENDOR_ID VDP_BT_VENDOR_ID /* Broadcom Corporation */
+/* Offset for codec configuration in codec info */
+#define BTA_AV_CFG_START_IDX 3
+
/* vendor specific codec ID */
#define BTA_AV_CODEC_ID_H264 VDP_CODEC_ID_H264 /* Non-VDP codec ID - H.264 */
#define BTA_AV_CODEC_ID_IMG VDP_CODEC_ID_IMG /* Non-VDP codec ID - images/slideshow */
@@ -254,9 +267,12 @@
#define BTA_AV_MEDIA_SINK_CFG_EVT 20 /* command to configure codec */
#define BTA_AV_MEDIA_DATA_EVT 21 /* sending data to Media Task */
#define BTA_AV_OFFLOAD_START_RSP_EVT 22 /* a2dp offload start response */
-/* Max BTA event */
-#define BTA_AV_MAX_EVT 23
+#define BTA_AV_BROWSE_MSG_EVT 23 /* Browse MSG EVT */
+#define BTA_AV_ROLE_CHANGED_EVT 24
+#define BTA_AV_RC_COLL_DETECTED_EVT 25 /* RC channel collosion detected */
+/* Max BTA event */
+#define BTA_AV_MAX_EVT 26
typedef UINT8 tBTA_AV_EVT;
@@ -289,6 +305,10 @@
BOOLEAN starting;
tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */
UINT8 sep; /* sep type of peer device */
+ UINT8 role; /* 0x00 master, 0x01 slave , 0xFF unkown*/
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ UINT16 stream_chnl_id;
+#endif
} tBTA_AV_OPEN;
/* data associated with BTA_AV_CLOSE_EVT */
@@ -306,6 +326,7 @@
tBTA_AV_STATUS status;
BOOLEAN initiator; /* TRUE, if local device initiates the START */
BOOLEAN suspending;
+ UINT8 role; /* 0x00 master, 0x01 slave , 0xFF unkown*/
} tBTA_AV_START;
/* data associated with BTA_AV_SUSPEND_EVT */
@@ -360,6 +381,13 @@
BD_ADDR peer_addr;
} tBTA_AV_RC_CLOSE;
+/* data associated with BTA_AV_RC_COLL_DETECTED */
+typedef struct
+{
+ UINT8 rc_handle;
+ BD_ADDR peer_addr;
+} tBTA_AV_RC_COLL_DETECTED;
+
/* data associated with BTA_AV_RC_FEAT_EVT */
typedef struct
{
@@ -415,10 +443,19 @@
tAVRC_MSG *p_msg;
} tBTA_AV_META_MSG;
+/*data associated with BTA_AV_BROWSE_MSG_EVT */
+typedef struct
+{
+ UINT8 rc_handle;
+ UINT8 label;
+ tAVRC_MSG *p_msg;
+}tBTA_AV_BROWSE_MSG;
+
/* data associated with BTA_AV_PENDING_EVT */
typedef struct
{
BD_ADDR bd_addr;
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream. */
} tBTA_AV_PEND;
/* data associated with BTA_AV_REJECT_EVT */
@@ -428,6 +465,13 @@
tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */
} tBTA_AV_REJECT;
+/* data associated with BTA_AV_ROLE_CHANGED */
+typedef struct
+{
+ BD_ADDR bd_addr;
+ UINT8 new_role;
+ tBTA_AV_HNDL hndl; /* Handle associated with role change event */
+} tBTA_AV_ROLE_CHANGED;
/* union of data associated with AV callback */
typedef union
@@ -442,6 +486,7 @@
tBTA_AV_PROTECT_RSP protect_rsp;
tBTA_AV_RC_OPEN rc_open;
tBTA_AV_RC_CLOSE rc_close;
+ tBTA_AV_RC_COLL_DETECTED rc_col_detected;
tBTA_AV_REMOTE_CMD remote_cmd;
tBTA_AV_REMOTE_RSP remote_rsp;
tBTA_AV_VENDOR vendor_cmd;
@@ -450,9 +495,11 @@
tBTA_AV_SUSPEND suspend;
tBTA_AV_PEND pend;
tBTA_AV_META_MSG meta_msg;
+ tBTA_AV_BROWSE_MSG browse_msg;
tBTA_AV_REJECT reject;
tBTA_AV_RC_FEAT rc_feat;
tBTA_AV_STATUS status;
+ tBTA_AV_ROLE_CHANGED role_changed;
} tBTA_AV;
typedef struct
@@ -635,25 +682,47 @@
**
** Function BTA_AvStart
**
-** Description Start audio/video stream data transfer.
+** Description Start audio/video stream data transfer on the AV handle.
**
** Returns void
**
*******************************************************************************/
-void BTA_AvStart(void);
+void BTA_AvStart(tBTA_AV_HNDL hndl);
/*******************************************************************************
**
** Function BTA_AvStop
**
-** Description Stop audio/video stream data transfer.
+** Description Stop audio/video stream data transfer on the AV handle.
** If suspend is TRUE, this function sends AVDT suspend signal
** to the connected peer(s).
**
** Returns void
**
*******************************************************************************/
-void BTA_AvStop(BOOLEAN suspend);
+void BTA_AvStop(BOOLEAN suspend, tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+**
+** Function BTA_AvEnableMultiCast
+**
+** Description Enable/disable Avdtp MultiCast
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvEnableMultiCast(BOOLEAN state, tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+**
+** Function BTA_AvUpdateMaxAVClient
+**
+** Description Update max simultaneous AV connections supported
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvUpdateMaxAVClient(UINT8 max_clients);
/*******************************************************************************
**
@@ -834,6 +903,16 @@
*******************************************************************************/
void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status);
+/*******************************************************************************
+**
+** Function bta_av_get_codec_type
+**
+** Description Returns the codec_type from the most recently used scb
+**
+** Returns Codec type corresponding to AV handle
+**
+*******************************************************************************/
+UINT8 bta_av_get_codec_type(tBTA_AV_HNDL hndl);
#ifdef __cplusplus
}
diff --git a/bta/include/bta_av_co.h b/bta/include/bta_av_co.h
index ad8e697..661cb7b 100644
--- a/bta/include/bta_av_co.h
+++ b/bta/include/bta_av_co.h
@@ -59,6 +59,23 @@
BTA_AV_CO_ST_STREAM
};
+enum
+{
+ BTIF_SV_AV_AA_SBC_INDEX = 0,
+ BTIF_SV_AV_AA_APTX_INDEX,
+ BTIF_SV_AV_AA_APTX_HD_INDEX,
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ BTIF_SV_AV_AA_AAC_INDEX,
+#endif
+ BTIF_SV_AV_AA_SRC_SEP_INDEX /* Last index */
+};
+
+enum
+{
+ BTIF_SV_AV_AA_SBC_SINK_INDEX = BTIF_SV_AV_AA_SRC_SEP_INDEX,
+ BTIF_SV_AV_AA_SNK_SEP_INDEX /* Last index */
+};
+
/* data type for the Audio Codec Information*/
typedef struct
@@ -388,4 +405,28 @@
*******************************************************************************/
extern void bta_av_co_video_delay(tBTA_AV_HNDL hndl, UINT16 delay);
+/*******************************************************************************
+**
+** Function bta_av_co_audio_is_offload_supported
+**
+** Description This function is called by AV to check if DUT is in offload
+** mode.
+**
+** Returns TRUE if offload is enabled, FALSE otherwise
+**
+*******************************************************************************/
+extern BOOLEAN bta_av_co_audio_is_offload_supported(void);
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_is_codec_supported
+**
+** Description This function is called by AV to check if corresponding
+** codec is supported in offload mode.
+**
+** Returns TRUE if codec is supported in offload, FALSE otherwise
+**
+*******************************************************************************/
+extern BOOLEAN bta_av_co_audio_is_codec_supported(int codec);
+
#endif /* BTA_AV_CO_H */
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 4c9f76c..b55dfc7 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -146,6 +146,10 @@
#define BTA_GATTC_SCAN_FLT_PARAM_EVT 32 /* Param filter event */
#define BTA_GATTC_SCAN_FLT_STATUS_EVT 33 /* Filter status event */
#define BTA_GATTC_ADV_VSC_EVT 34 /* ADV VSC event */
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+#define BTA_GATTC_EXTENDED_ADV_ENB_EVT 35 /* Extended Enable ADV event */
+#define BTA_GATTC_EXTENDED_ADV_UPD_EVT 36 /* Extended Update parameter event */
+#endif
typedef UINT8 tBTA_GATTC_EVT;
diff --git a/bta/include/bta_hf_client_api.h b/bta/include/bta_hf_client_api.h
index 82235fa..784d9ac 100644
--- a/bta/include/bta_hf_client_api.h
+++ b/bta/include/bta_hf_client_api.h
@@ -26,6 +26,7 @@
#define BTA_HF_CLIENT_API_H
#include "bta_api.h"
+#define SNIFF_DISABLE 0
/*****************************************************************************
** Constants and data types
@@ -101,6 +102,8 @@
#define BTA_HF_CLIENT_BSIR_EVT 19 /* in-band ring tone setting changed event */
#define BTA_HF_CLIENT_BINP_EVT 20 /* binp number event */
#define BTA_HF_CLIENT_RING_INDICATION 21 /* HF Client ring indication */
+#define BTA_HF_CLIENT_CGMI_EVT 22 /* AG manufacturer identification */
+#define BTA_HF_CLIENT_CGMM_EVT 23 /* AG manufacturer model */
#define BTA_HF_CLIENT_DISABLE_EVT 30 /* HF Client disabled */
typedef UINT8 tBTA_HF_CLIENT_EVT;
@@ -227,6 +230,20 @@
UINT16 value;
} tBTA_HF_CLIENT_VAL;
+#define BTA_HF_CLIENT_MANUFACTURER_ID 2048
+/* data associated with BTA_HF_CLIENT_CGMI_EVT event */
+typedef struct
+{
+ char name[BTA_HF_CLIENT_MANUFACTURER_ID + 1];
+} tBTA_HF_CLIENT_CGMI;
+
+#define BTA_HF_CLIENT_MANUFACTURER_MODEL 2048
+/* data associated with BTA_HF_CLIENT_CGMI_EVT event */
+typedef struct
+{
+ char model[BTA_HF_CLIENT_MANUFACTURER_MODEL + 1];
+} tBTA_HF_CLIENT_CGMM;
+
/* union of data associated with AG callback */
typedef union
{
@@ -241,10 +258,14 @@
tBTA_HF_CLIENT_AT_RESULT result;
tBTA_HF_CLIENT_CLCC clcc;
tBTA_HF_CLIENT_CNUM cnum;
+ tBTA_HF_CLIENT_CGMI cgmi;
+ tBTA_HF_CLIENT_CGMM cgmm;
} tBTA_HF_CLIENT;
typedef UINT32 tBTA_HF_CLIENT_FEAT;
+extern BOOLEAN is_sniff_disabled;
+
/* HF Client callback */
typedef void (tBTA_HF_CLIENT_CBACK)(tBTA_HF_CLIENT_EVT event, tBTA_HF_CLIENT *p_data);
diff --git a/bta/include/bta_hh_api.h b/bta/include/bta_hh_api.h
index d43e492..f55664d 100644
--- a/bta/include/bta_hh_api.h
+++ b/bta/include/bta_hh_api.h
@@ -40,6 +40,22 @@
#define BTA_HH_SSR_MIN_TOUT_DEF 2
#endif
+#ifndef BTA_HH_SSR_MAX_LATENCY_OPTIMAL
+#define BTA_HH_SSR_MAX_LATENCY_OPTIMAL 360 /* 225 ms*/
+#endif
+
+#ifndef BTA_HH_SSR_MAX_LATENCY_MIN_OPTIMAL
+#define BTA_HH_SSR_MAX_LATENCY_MIN_OPTIMAL 256 /* 160 ms*/
+#endif
+
+#ifndef BTA_HH_SSR_MAX_LATENCY_ZERO
+#define BTA_HH_SSR_MAX_LATENCY_ZERO 0
+#endif
+
+#ifndef BTA_HH_SSR_DISABLE_SSR
+#define BTA_HH_SSR_DISABLE_SSR 1
+#endif
+
/* BTA HID Host callback events */
#define BTA_HH_ENABLE_EVT 0 /* HH enabled */
#define BTA_HH_DISABLE_EVT 1 /* HH disabled */
diff --git a/bta/include/bta_hh_co.h b/bta/include/bta_hh_co.h
old mode 100755
new mode 100644
index 940b3cc..3b72478
--- a/bta/include/bta_hh_co.h
+++ b/bta/include/bta_hh_co.h
@@ -76,6 +76,30 @@
*******************************************************************************/
extern void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id);
+/*******************************************************************************
+**
+** Function bta_hh_co_set_rpt_rsp
+**
+** Description This callout function is executed by HH when Set Report Response is received
+** on Control Channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+extern void bta_hh_co_set_rpt_rsp(UINT8 dev_handle, UINT8 status);
+
+/*******************************************************************************
+**
+** Function bta_hh_co_get_rpt_rsp
+**
+** Description This callout function is executed by HH when Get Report Response is received
+** on Control Channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+extern void bta_hh_co_get_rpt_rsp(UINT8 dev_handle, UINT8 status, UINT8 *p_rpt, UINT16 len);
+
#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
/*******************************************************************************
**
diff --git a/bta/include/bta_jv_api.h b/bta/include/bta_jv_api.h
index f4999c5..9042f28 100644
--- a/bta/include/bta_jv_api.h
+++ b/bta/include/bta_jv_api.h
@@ -68,6 +68,9 @@
#define BTA_JV_LAST_SERVICE_ID BTA_LAST_JV_SERVICE_ID
#define BTA_JV_NUM_SERVICE_ID (BTA_LAST_JV_SERVICE_ID - BTA_FIRST_JV_SERVICE_ID + 1)
+/* Intermediate Idle timeout(s) for TX/RX*/
+#define BTA_JV_IDLE_TIMEOUT_MS 1000
+
/* Discoverable modes */
enum
{
@@ -269,6 +272,7 @@
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
UINT32 handle; /* The connection handle */
BD_ADDR rem_bda; /* The peer address */
+ UINT16 mtu; /* peer mtu */
} tBTA_JV_RFCOMM_OPEN;
/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */
typedef struct
@@ -277,6 +281,7 @@
UINT32 handle; /* The connection handle */
UINT32 new_listen_handle; /* The new listen handle */
BD_ADDR rem_bda; /* The peer address */
+ UINT16 mtu; /* peer mtu */
} tBTA_JV_RFCOMM_SRV_OPEN;
diff --git a/bta/include/utl.h b/bta/include/utl.h
index c309ec9..cc7fa0c 100644
--- a/bta/include/utl.h
+++ b/bta/include/utl.h
@@ -75,6 +75,20 @@
/*******************************************************************************
**
+** Function utl_str2int32
+**
+** Description This utility function converts a character string to an
+** int32. Acceptable values in string are 0-9. If
+** invalid string or string value too large, -1 is returned.
+**
+**
+** Returns int32_t value or -1 on error.
+**
+*******************************************************************************/
+extern INT32 utl_str2int32(const char *p_s);
+
+/*******************************************************************************
+**
** Function utl_strucmp
**
** Description This utility function compares two strings in uppercase.
diff --git a/bta/jv/bta_jv_act.c b/bta/jv/bta_jv_act.c
index 3918fdf..68dd4f9 100644
--- a/bta/jv/bta_jv_act.c
+++ b/bta/jv/bta_jv_act.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "osi/include/allocator.h"
+#include "btu.h"
#include "bt_types.h"
#include "bt_common.h"
#include "utl.h"
@@ -49,7 +50,7 @@
#include "osi/include/osi.h"
-
+extern fixed_queue_t *btu_general_alarm_queue;
/* one of these exists for each client */
struct fc_client {
struct fc_client *next_all_list;
@@ -413,9 +414,15 @@
*******************************************************************************/
static void bta_jv_clear_pm_cb(tBTA_JV_PM_CB *p_pm_cb, BOOLEAN close_conn)
{
+ /* Ensure that timer is stopped */
+ alarm_cancel(p_pm_cb->idle_timer);
+
/* needs to be called if registered with bta pm, otherwise we may run out of dm pm slots! */
if (close_conn)
bta_sys_conn_close(BTA_ID_JV, p_pm_cb->app_id, p_pm_cb->peer_bd_addr);
+ else
+ bta_jv_pm_state_change(p_pm_cb, BTA_JV_CONN_IDLE);
+
p_pm_cb->state = BTA_JV_PM_FREE_ST;
p_pm_cb->app_id = BTA_JV_PM_ALL;
p_pm_cb->handle = BTA_JV_PM_HANDLE_CLEAR;
@@ -456,10 +463,6 @@
"app_id: 0x%x",__func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
APPL_TRACE_API("%s, bd_counter = %d, "
"appid_counter = %d", __func__, bd_counter, appid_counter);
- if (bd_counter > 1)
- {
- bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
- }
if (bd_counter <= 1 || (appid_counter <= 1))
{
@@ -576,6 +579,9 @@
bta_jv_cb.pm_cb[i].app_id = app_id;
bdcpy(bta_jv_cb.pm_cb[i].peer_bd_addr, peer_bd_addr);
bta_jv_cb.pm_cb[i].state = BTA_JV_PM_IDLE_ST;
+
+ bta_jv_cb.pm_cb[i].idle_timer = alarm_new("bta.jv_idle_timer");
+ APPL_TRACE_DEBUG("bta_jv_alloc_set_pm_profile_cb: %d, PM_cb: %p", i, &bta_jv_cb.pm_cb[i]);
return &bta_jv_cb.pm_cb[i];
}
APPL_TRACE_WARNING("bta_jv_alloc_set_pm_profile_cb(jv_handle: 0x%x, app_id: %d) "
@@ -1026,6 +1032,10 @@
bta_jv_pm_conn_idle(p_cb->p_pm_cb);
break;
+ case GAP_EVT_TX_DONE:
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
case GAP_EVT_CONN_CONGESTED:
case GAP_EVT_CONN_UNCONGESTED:
p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
@@ -1115,7 +1125,8 @@
}
evt_data.handle = handle;
- cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
+ if(cc->p_cback)
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
}
@@ -1196,6 +1207,10 @@
bta_jv_pm_conn_idle(p_cb->p_pm_cb);
break;
+ case GAP_EVT_TX_DONE:
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
case GAP_EVT_CONN_CONGESTED:
case GAP_EVT_CONN_UNCONGESTED:
p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
@@ -1280,7 +1295,8 @@
p_cb->psm = ls->local_psm;
}
- ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+ if(ls->p_cback)
+ ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ls->user_data);
}
/*******************************************************************************
@@ -1309,7 +1325,8 @@
evt_data.handle = p_cb->handle;
evt_data.status = bta_jv_free_l2c_cb(p_cb);
evt_data.async = FALSE;
- p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+ if(p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, ls->user_data);
break;
}
}
@@ -1438,13 +1455,17 @@
{
tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+ int ret = 0;
APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb, p_pcb, len, type);
if (p_pcb != NULL)
{
switch(type)
{
case DATA_CO_CALLBACK_TYPE_INCOMING:
- return bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR*)buf);
+ bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
+ ret = bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR*)buf);
+ bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+ return ret;
case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE:
return bta_co_rfc_data_outgoing_size(p_pcb->user_data, (int*)buf);
case DATA_CO_CALLBACK_TYPE_OUTGOING:
@@ -1477,7 +1498,10 @@
tBTA_JV_RFCOMM_CBACK *p_cback; /* the callback function */
APPL_TRACE_DEBUG( "bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code, port_handle);
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ /* Fix for below Klockwork issue
+ * Pointer 'p_pcb' returned from call to function 'bta_jv_rfc_port_to_pcb' at line 1490
+ * may be NULL and may be dereferenced at line 1500*/
+ if(NULL == p_cb || NULL == p_cb->p_cback || NULL == p_pcb)
return;
APPL_TRACE_DEBUG( "bta_jv_port_mgmt_cl_cback code=%d port_handle:%d handle:%d",
@@ -1490,6 +1514,7 @@
evt_data.rfc_open.handle = p_cb->handle;
evt_data.rfc_open.status = BTA_JV_SUCCESS;
bdcpy(evt_data.rfc_open.rem_bda, rem_bda);
+ evt_data.rfc_open.mtu = PORT_GetRemoteMtu(port_handle);
p_pcb->state = BTA_JV_ST_CL_OPEN;
p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->user_data);
}
@@ -1528,8 +1553,11 @@
tBTA_JV evt_data;
APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback:%d", port_handle);
- if (NULL == p_cb || NULL == p_cb->p_cback)
- return;
+ /* Fix for below Klockwork issue
+ * Pointer 'p_pcb' returned from call to function 'bta_jv_rfc_port_to_pcb' at line 1547
+ * may be NULL and may be dereferenced at line 1554*/
+ if (NULL == p_cb || NULL == p_cb->p_cback || NULL == p_pcb)
+ return;
APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d",
code, port_handle, p_cb->handle);
@@ -1709,12 +1737,12 @@
BD_ADDR rem_bda;
UINT16 lcid;
APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:%d, port_handle:%d", code, port_handle);
- if (NULL == p_cb || NULL == p_cb->p_cback)
- {
- APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
- p_cb, p_cb ? p_cb->p_cback : NULL);
+ /* Fix for below Klockwork issue
+ * Pointer 'p_pcb' returned from call to function 'bta_jv_rfc_port_to_pcb' at line 1729
+ * may be NULL and may be dereferenced at line 1738*/
+ if (NULL == p_cb || NULL == p_cb->p_cback || NULL == p_pcb)
return;
- }
+
void *user_data = p_pcb->user_data;
APPL_TRACE_DEBUG( "bta_jv_port_mgmt_sr_cback code=%d port_handle:0x%x handle:0x%x, p_pcb:%p, user:%d",
code, port_handle, p_cb->handle, p_pcb, p_pcb->user_data);
@@ -1726,6 +1754,7 @@
evt_data.rfc_srv_open.handle = p_pcb->handle;
evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda);
+ evt_data.rfc_srv_open.mtu = PORT_GetRemoteMtu(port_handle);
tBTA_JV_PCB *p_pcb_new_listen = bta_jv_add_rfc_port(p_cb, p_pcb);
if (p_pcb_new_listen)
{
@@ -1777,7 +1806,7 @@
tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- if (NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback || NULL == p_pcb)
return;
APPL_TRACE_DEBUG( "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d",
@@ -2028,6 +2057,13 @@
tBTA_JV_PCB *p_pcb = wc->p_pcb;
tBTA_JV_RFCOMM_WRITE evt_data;
+
+ if (p_pcb->state == BTA_JV_ST_NONE) {
+ APPL_TRACE_ERROR("bta_jv_rfcomm_write : Incorect state (%d) to write data, returning",
+ p_pcb->state);
+ return;
+ }
+
evt_data.status = BTA_JV_FAILURE;
evt_data.handle = p_cb->handle;
evt_data.req_id = wc->req_id;
@@ -2157,7 +2193,19 @@
static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB *p_cb)
{
if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST == p_cb->state))
- bta_jv_pm_state_change(p_cb, BTA_JV_CONN_BUSY);
+ {
+ tBTM_PM_MODE mode = BTM_PM_MD_ACTIVE;
+ if (BTM_ReadPowerMode(p_cb->peer_bd_addr, &mode) == BTM_SUCCESS) {
+ if (mode == BTM_PM_MD_SNIFF) {
+ bta_jv_pm_state_change(p_cb, BTA_JV_CONN_BUSY);
+ } else {
+ p_cb->state = BTA_JV_PM_BUSY_ST;
+ APPL_TRACE_DEBUG("bta_jv_pm_conn_busy:power mode: %d", mode);
+ }
+ } else {
+ bta_jv_pm_state_change(p_cb, BTA_JV_CONN_BUSY);
+ }
+ }
}
/*******************************************************************************
@@ -2173,8 +2221,15 @@
*******************************************************************************/
static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB *p_cb)
{
- if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST != p_cb->state))
- bta_jv_pm_state_change(p_cb, BTA_JV_CONN_IDLE);
+ if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST != p_cb->state)) {
+ APPL_TRACE_DEBUG("bta_jv_pm_conn_idle, p_cb: %p", p_cb);
+ p_cb->state = BTA_JV_PM_IDLE_ST;
+ // start intermediate idle timer for 1s
+ if (!alarm_is_scheduled(p_cb->idle_timer)) {
+ alarm_set_on_queue(p_cb->idle_timer, BTA_JV_IDLE_TIMEOUT_MS,
+ bta_jv_idle_timeout_handler, p_cb, btu_general_alarm_queue);
+ }
+ }
}
/*******************************************************************************
@@ -2461,7 +2516,7 @@
}
}
- if (call_init)
+ if (call_init && p_cback)
p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, user_data);
//call this with lock taken so socket does not disappear from under us */
@@ -2488,10 +2543,15 @@
return;
}
}
-
- sock_cback = t->p_cback;
- sock_user_data = t->user_data;
- evt_data.le_data_ind.handle = t->id;
+ /* Fix for below klockwork issue
+ * Null pointer 't' that comes from line 2508
+ * may be dereferenced at line 2525*/
+ if (t)
+ {
+ sock_cback = t->p_cback;
+ sock_user_data = t->user_data;
+ evt_data.le_data_ind.handle = t->id;
+ }
evt_data.le_data_ind.p_buf = p_buf;
if (sock_cback)
@@ -2547,7 +2607,8 @@
}
if (call_init_f)
cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
- t->init_called = TRUE;
+ if (t)
+ t->init_called = TRUE;
}
@@ -2644,3 +2705,33 @@
if (t)
fcclient_free(t);
}
+
+/*******************************************************************************
+**
+** Function bta_jv_idle_timeout_handler
+**
+** Description Bta JV specific idle timeout handler
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_idle_timeout_handler(void *tle) {
+ tBTA_JV_PM_CB *p_cb = (tBTA_JV_PM_CB *)tle;;
+ APPL_TRACE_DEBUG("%s p_cb: %p", __func__, p_cb);
+
+ if (NULL != p_cb) {
+
+ tBTM_PM_MODE mode = BTM_PM_MD_ACTIVE;
+ if (BTM_ReadPowerMode(p_cb->peer_bd_addr, &mode) == BTM_SUCCESS) {
+ if (mode == BTM_PM_MD_SNIFF) {
+ APPL_TRACE_WARNING("%s: %d", __func__, mode)
+ return;
+ }
+ } else {
+ APPL_TRACE_DEBUG("%s: Read power mode failed %d", __func__, mode);
+ }
+ bta_jv_pm_state_change(p_cb, BTA_JV_CONN_IDLE);
+ }
+}
+
diff --git a/bta/jv/bta_jv_int.h b/bta/jv/bta_jv_int.h
index 84580fa..5181196 100644
--- a/bta/jv/bta_jv_int.h
+++ b/bta/jv/bta_jv_int.h
@@ -29,6 +29,7 @@
#include "bta_jv_api.h"
#include "rfcdefs.h"
#include "port_api.h"
+#include "osi/include/alarm.h"
/*****************************************************************************
** Constants
@@ -102,6 +103,7 @@
UINT8 state; /* state: see above enum */
tBTA_JV_PM_ID app_id; /* JV app specific id indicating power table to use */
BD_ADDR peer_bd_addr; /* Peer BD address */
+ alarm_t *idle_timer; /* intermediate idle timer for paricular scb */
} tBTA_JV_PM_CB;
enum
@@ -435,5 +437,6 @@
extern void bta_jv_l2cap_stop_server_le (tBTA_JV_MSG *p_data);
extern void bta_jv_l2cap_write_fixed (tBTA_JV_MSG *p_data);
extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data);
+extern void bta_jv_idle_timeout_handler(void *tle);
#endif /* BTA_JV_INT_H */
diff --git a/bta/pan/bta_pan_ci.c b/bta/pan/bta_pan_ci.c
index ec77e60..64c6776 100644
--- a/bta/pan/bta_pan_ci.c
+++ b/bta/pan/bta_pan_ci.c
@@ -194,6 +194,9 @@
p_scb = bta_pan_scb_by_handle(handle);
+ if (p_scb == NULL)
+ return NULL;
+
p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_scb->data_queue);
if (p_buf != NULL)
{
diff --git a/bta/pan/bta_pan_main.c b/bta/pan/bta_pan_main.c
index a766f2e..36fdbc9 100644
--- a/bta/pan/bta_pan_main.c
+++ b/bta/pan/bta_pan_main.c
@@ -214,12 +214,13 @@
/* execute action functions */
for (i = 0; i < BTA_PAN_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != BTA_PAN_IGNORE)
+ if ((action = state_table[event][i]) < BTA_PAN_IGNORE)
{
(*bta_pan_action[action])(p_scb, p_data);
}
else
{
+ APPL_TRACE_EVENT("action: %d", action);
break;
}
}
diff --git a/bta/sys/bta_sys_main.c b/bta/sys/bta_sys_main.c
index af32cc9..6bb64c6 100644
--- a/bta/sys/bta_sys_main.c
+++ b/bta/sys/bta_sys_main.c
@@ -58,6 +58,7 @@
/* TODO Hard-coded trace levels - Needs to be configurable */
UINT8 appl_trace_level = BT_TRACE_LEVEL_WARNING; //APPL_INITIAL_TRACE_LEVEL;
UINT8 btif_trace_level = BT_TRACE_LEVEL_WARNING;
+UINT8 audio_latency_trace_level = BT_TRACE_LEVEL_WARNING;
// Communication queue between btu_task and bta.
extern fixed_queue_t *btu_bta_msg_queue;
@@ -225,7 +226,7 @@
/* execute action functions */
for (i = 0; i < BTA_SYS_ACTIONS; i++)
{
- if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE)
+ if ((action = state_table[p_msg->event & 0x00ff][i]) < BTA_SYS_IGNORE)
{
(*bta_sys_action[action])( (tBTA_SYS_HW_MSG*) p_msg);
}
diff --git a/bta/sys/utl.c b/bta/sys/utl.c
index fc3d7eb..e75e973 100644
--- a/bta/sys/utl.c
+++ b/bta/sys/utl.c
@@ -68,6 +68,46 @@
/*******************************************************************************
**
+** Function utl_str2int32
+**
+** Description This utility function converts a character string to an
+** int32. Acceptable values in string are 0-9. If invalid
+** string or string value too large, -1 is returned. Leading
+** spaces are skipped.
+**
+**
+** Returns int32_t value or -1 on error.
+**
+*******************************************************************************/
+INT32 utl_str2int32(const char *p_s)
+{
+ INT32 val = 0;
+
+ for (;*p_s == ' ' && *p_s != 0; p_s++);
+
+ if (*p_s == 0) return -1;
+
+ for (;;)
+ {
+ if ((*p_s < '0') || (*p_s > '9')) return -1;
+
+ val += (INT32) (*p_s++ - '0');
+
+ if (val > 65535) return -1;
+
+ if (*p_s == 0)
+ {
+ return val;
+ }
+ else
+ {
+ val *= 10;
+ }
+ }
+}
+
+/*******************************************************************************
+**
** Function utl_strucmp
**
** Description This utility function compares two strings in uppercase.
@@ -265,6 +305,7 @@
{
if(!(((p_s[i] >= '0') && (p_s[i] <= '9'))
|| (p_s[i] == '*') || (p_s[i] == '+') || (p_s[i] == '#') || (p_s[i] == ';')
+ || (p_s[i] == '-')
|| ((p_s[i] >= 'A') && (p_s[i] <= 'C'))
|| ((p_s[i] == 'p') || (p_s[i] == 'P')
|| (p_s[i] == 'w') || (p_s[i] == 'W'))))
diff --git a/btcore/src/module.c b/btcore/src/module.c
index 07b3dd0..ab7710a 100644
--- a/btcore/src/module.c
+++ b/btcore/src/module.c
@@ -33,7 +33,8 @@
typedef enum {
MODULE_STATE_NONE = 0,
MODULE_STATE_INITIALIZED = 1,
- MODULE_STATE_STARTED = 2
+ MODULE_STATE_STARTED = 2,
+ MODULE_STATE_STARTUP_ERROR = 3
} module_state_t;
static const size_t number_of_metadata_buckets = 42;
@@ -100,8 +101,8 @@
LOG_INFO(LOG_TAG, "%s Starting module \"%s\"", __func__, module->name);
if (!call_lifecycle_function(module->start_up)) {
- LOG_ERROR(LOG_TAG, "%s Failed to start up module \"%s\"",
- __func__, module->name);
+ LOG_ERROR(LOG_TAG, "%s failed to start up \"%s\"", __func__, module->name);
+ set_module_state(module, MODULE_STATE_STARTUP_ERROR);
return false;
}
LOG_INFO(LOG_TAG, "%s Started module \"%s\"", __func__, module->name);
@@ -114,7 +115,6 @@
assert(metadata != NULL);
assert(module != NULL);
module_state_t state = get_module_state(module);
- assert(state <= MODULE_STATE_STARTED);
// Only something to do if the module was actually started
if (state < MODULE_STATE_STARTED)
diff --git a/btif/Android.mk b/btif/Android.mk
index d6b934d..cea6e80 100644
--- a/btif/Android.mk
+++ b/btif/Android.mk
@@ -65,7 +65,15 @@
src/btif_storage.c \
src/btif_uid.c \
src/btif_util.c \
- src/stack_manager.c
+ src/stack_manager.c \
+ src/btif_stack_log.c \
+ src/btif_rfcomm.c \
+ src/btif_mcap.c \
+ src/btif_l2cap.c \
+ src/btif_vendor.c \
+ src/btif_gatt_qual.c \
+ src/btif_gap.c \
+ src/btif_smp.c
# Callouts
btifCommonSrc += \
@@ -109,7 +117,18 @@
$(LOCAL_PATH)/../utils/include \
$(bluetooth_C_INCLUDES) \
external/tinyxml2 \
- external/zlib
+ external/zlib \
+ $(call include-path-for, audio-utils)
+
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+btifCommonIncludes += \
+ vendor/qcom/opensource/bluetooth/hal/include \
+ vendor/qcom/opensource/bluetooth/system_bt_ext
+else
+btifCommonIncludes += \
+ device/qcom/msm8909w/opensource/bluetooth/hal/include \
+ device/qcom/msm8909w/opensource/bluetooth/system_bt_ext
+endif
# libbtif static library for target
# ========================================================
@@ -126,6 +145,7 @@
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
include $(BUILD_STATIC_LIBRARY)
# btif unit tests for target
@@ -134,7 +154,7 @@
LOCAL_C_INCLUDES := $(btifCommonIncludes)
LOCAL_SRC_FILES := $(btifTestSrc)
LOCAL_SHARED_LIBRARIES += liblog libhardware libhardware_legacy libcutils
-LOCAL_STATIC_LIBRARIES += libbtcore libbtif libosi
+LOCAL_STATIC_LIBRARIES += libbtcore libbtif libosi libbtdevice
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := net_test_btif
diff --git a/btif/co/bta_ag_co.c b/btif/co/bta_ag_co.c
old mode 100755
new mode 100644
index e18cc9d..c50c128
--- a/btif/co/bta_ag_co.c
+++ b/btif/co/bta_ag_co.c
@@ -66,7 +66,9 @@
void bta_ag_co_audio_state(UINT16 handle, UINT8 app_id, UINT8 state)
#endif
{
+#if (BLUETOOTH_QTI_SW == TRUE)
BTIF_TRACE_DEBUG("bta_ag_co_audio_state: handle %d, state %d", handle, state);
+#else
switch (state)
{
case SCO_STATE_OFF:
@@ -99,6 +101,7 @@
APPL_TRACE_DEBUG("bta_ag_co_audio_state(handle %d, app_id: %d, state %d)", \
handle, app_id, state);
#endif
+#endif
}
diff --git a/btif/co/bta_av_co.c b/btif/co/bta_av_co.c
index 76c8836..e6f480f 100644
--- a/btif/co/bta_av_co.c
+++ b/btif/co/bta_av_co.c
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2004-2012 Broadcom Corporation
*
@@ -22,7 +27,7 @@
* BTIF.
*
******************************************************************************/
-
+#include <cutils/properties.h>
#include "string.h"
#include "a2d_api.h"
#include "a2d_sbc.h"
@@ -34,10 +39,19 @@
#include "btif_media.h"
#include "sbc_encoder.h"
+#include "btif_av.h"
#include "btif_av_co.h"
#include "btif_util.h"
#include "osi/include/mutex.h"
+#include "device/include/interop.h"
+#include "bt_utils.h"
+#include "a2d_aptx.h"
+#include "a2d_aptx_hd.h"
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+#include "a2d_aac.h"
+#include "bta_av_aac.h"
+#endif
/*****************************************************************************
** Constants
@@ -63,7 +77,11 @@
#define BTA_AV_CO_SBC_MIN_BITPOOL_OFF 5
#define BTA_AV_CO_SBC_MAX_BITPOOL_OFF 6
+#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+#define BTA_AV_CO_SBC_MAX_BITPOOL 51
+#else
#define BTA_AV_CO_SBC_MAX_BITPOOL 53
+#endif
/* SCMS-T protect info */
const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00";
@@ -71,11 +89,15 @@
/* SBC SRC codec capabilities */
const tA2D_SBC_CIE bta_av_co_sbc_caps =
{
+#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ (A2D_SBC_IE_SAMP_FREQ_48), /* samp_freq */
+#else
(A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */
- (A2D_SBC_IE_CH_MD_JOINT), /* ch_mode */
- (A2D_SBC_IE_BLOCKS_16), /* block_len */
- (A2D_SBC_IE_SUBBAND_8), /* num_subbands */
- (A2D_SBC_IE_ALLOC_MD_L), /* alloc_mthd */
+#endif
+ (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */
+ (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */
+ (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */
+ (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */
BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */
A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */
};
@@ -93,9 +115,18 @@
};
#if !defined(BTIF_AV_SBC_DEFAULT_SAMP_FREQ)
+#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+#define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_48
+#else
#define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44
#endif
+#endif
+/* A2dp offload capabilities */
+#define SBC 0
+#define APTX 1
+#define AAC 2
+#define APTXHD 3
/* Default SBC codec configuration */
const tA2D_SBC_CIE btif_av_sbc_default_config =
{
@@ -108,6 +139,96 @@
A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */
};
+const tA2D_APTX_CIE bta_av_co_aptx_caps =
+{
+ A2D_APTX_VENDOR_ID,
+ A2D_APTX_CODEC_ID_BLUETOOTH,
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ A2D_APTX_SAMPLERATE_44100,
+#else
+ A2D_APTX_SAMPLERATE_48000,
+#endif
+ A2D_APTX_CHANNELS_STEREO,
+ A2D_APTX_FUTURE_1,
+ A2D_APTX_FUTURE_2
+};
+
+/* Default aptX codec configuration */
+const tA2D_APTX_CIE btif_av_aptx_default_config =
+{
+ A2D_APTX_VENDOR_ID,
+ A2D_APTX_CODEC_ID_BLUETOOTH,
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ A2D_APTX_SAMPLERATE_44100,
+#else
+ A2D_APTX_SAMPLERATE_48000,
+#endif
+ A2D_APTX_CHANNELS_STEREO,
+ A2D_APTX_FUTURE_1,
+ A2D_APTX_FUTURE_2
+};
+
+const tA2D_APTX_HD_CIE bta_av_co_aptx_hd_caps =
+{
+ A2D_APTX_HD_VENDOR_ID,
+ A2D_APTX_HD_CODEC_ID_BLUETOOTH,
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ A2D_APTX_HD_SAMPLERATE_44100,
+#else
+ A2D_APTX_HD_SAMPLERATE_48000,
+#endif
+ A2D_APTX_HD_CHANNELS_STEREO,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED0,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED1,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED2,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED3
+};
+
+/* Default aptX_hd codec configuration */
+const tA2D_APTX_HD_CIE btif_av_aptx_hd_default_config =
+{
+ A2D_APTX_HD_VENDOR_ID,
+ A2D_APTX_HD_CODEC_ID_BLUETOOTH,
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ A2D_APTX_HD_SAMPLERATE_44100,
+#else
+ A2D_APTX_HD_SAMPLERATE_48000,
+#endif
+ A2D_APTX_HD_CHANNELS_STEREO,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED0,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED1,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED2,
+ A2D_APTX_HD_ACL_SPRINT_RESERVED3
+};
+
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+const tA2D_AAC_CIE bta_av_co_aac_caps =
+{
+ (A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC), /* obj type */
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ (A2D_AAC_IE_SAMP_FREQ_44100),
+#else
+ (A2D_AAC_IE_SAMP_FREQ_48000),
+#endif
+ (A2D_AAC_IE_CHANNELS_1 | A2D_AAC_IE_CHANNELS_2 ), /* channels */
+ BTIF_AAC_DEFAULT_BIT_RATE, /* bit rate */
+ A2D_AAC_IE_VBR_NOT_SUPP /* variable bit rate */
+};
+
+/* Default AAC codec configuration */
+const tA2D_AAC_CIE btif_av_aac_default_config =
+{
+ A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC, /* obj type */
+#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ A2D_AAC_IE_SAMP_FREQ_44100, /* samp_freq */
+#else
+ A2D_AAC_IE_SAMP_FREQ_48000, /* samp_freq */
+#endif
+ A2D_AAC_IE_CHANNELS_2, /* channels */
+ BTIF_AAC_DEFAULT_BIT_RATE, /* bit rate */
+ A2D_AAC_IE_VBR_NOT_SUPP
+};
+#endif
/*****************************************************************************
** Local data
@@ -125,8 +246,10 @@
typedef struct
{
BD_ADDR addr; /* address of audio/video peer */
- tBTA_AV_CO_SINK snks[BTIF_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */
- tBTA_AV_CO_SINK srcs[BTIF_SV_AV_AA_SEP_INDEX]; /* array of supported srcs */
+ /* array of supported sinks */
+ tBTA_AV_CO_SINK snks[BTIF_SV_AV_AA_SRC_SEP_INDEX - BTIF_SV_AV_AA_SBC_INDEX];
+ /* array of supported srcs */
+ tBTA_AV_CO_SINK srcs[BTIF_SV_AV_AA_SNK_SEP_INDEX - BTIF_SV_AV_AA_SBC_SINK_INDEX];
UINT8 num_snks; /* total number of sinks at peer */
UINT8 num_srcs; /* total number of srcs at peer */
UINT8 num_seps; /* total number of seids at peer */
@@ -156,9 +279,19 @@
/* Connected peer information */
tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
/* Current codec configuration - access to this variable must be protected */
- tBTIF_AV_CODEC_INFO codec_cfg;
- tBTIF_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */
-
+ tBTIF_AV_CODEC_INFO* codec_cfg;
+ tBTIF_AV_CODEC_INFO* codec_cfg_setconfig; /* remote peer setconfig preference */
+ UINT8 current_codec_id;
+ tBTIF_AV_CODEC_INFO codec_cfg_sbc;
+ tBTIF_AV_CODEC_INFO codec_cfg_sbc_setconfig; /* remote peer setconfig preference (SBC) */
+ tBTIF_AV_CODEC_INFO codec_cfg_aptx;
+ tBTIF_AV_CODEC_INFO codec_cfg_aptx_setconfig; /* remote peer setconfig preference (aptX)*/
+ tBTIF_AV_CODEC_INFO codec_cfg_aptx_hd;
+ tBTIF_AV_CODEC_INFO codec_cfg_aptx_hd_setconfig; /* remote peer setconfig preference (aptX HD) */
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ tBTIF_AV_CODEC_INFO codec_cfg_aac;
+ tBTIF_AV_CODEC_INFO codec_cfg_aac_setconfig; /* remote peer setconfig preference (AAC)*/
+#endif
tBTA_AV_CO_CP cp;
} tBTA_AV_CO_CB;
@@ -169,13 +302,17 @@
static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer);
static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo);
static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink);
-static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index);
+static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index, UINT8 *p_codec_type);
static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg);
static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg);
static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index);
-
-
-
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+extern BOOLEAN btif_av_is_codec_offload_supported(int codec);
+#else
+#define btif_av_is_codec_offload_supported(codec) (0)
+#endif
+extern BOOLEAN btif_av_is_offload_supported();
+extern BOOLEAN bt_split_a2dp_enabled;
/*******************************************************************************
**
** Function bta_av_co_cp_is_active
@@ -287,7 +424,7 @@
*p_protect_info = 0;
/* reset remote preference through setconfig */
- bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE;
+ bta_av_co_cb.codec_cfg_setconfig = NULL;
switch (index)
{
@@ -311,6 +448,28 @@
/* Codec is valid */
return TRUE;
+
+ case BTIF_SV_AV_AA_APTX_INDEX:
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ /* Set up for aptX codec */
+ *p_codec_type = A2D_NON_A2DP_MEDIA_CT;
+ A2D_BldAptxInfo(AVDT_MEDIA_AUDIO, (tA2D_APTX_CIE *) &bta_av_co_aptx_caps, p_codec_info);
+ return TRUE;
+
+ case BTIF_SV_AV_AA_APTX_HD_INDEX:
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ /* Set up for aptX HD codec */
+ *p_codec_type = A2D_NON_A2DP_MEDIA_CT;
+ A2D_BldAptx_hdInfo(AVDT_MEDIA_AUDIO, (tA2D_APTX_HD_CIE *) &bta_av_co_aptx_hd_caps, p_codec_info);
+ return TRUE;
+
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ case BTIF_SV_AV_AA_AAC_INDEX:
+ APPL_TRACE_DEBUG("%s AAC", __func__);
+ *p_codec_type = BTA_AV_CODEC_M24;
+ A2D_BldAacInfo(AVDT_MEDIA_AUDIO, (tA2D_AAC_CIE *) &bta_av_co_aac_caps ,p_codec_info);
+ return TRUE;
+#endif
#if (BTA_AV_SINK_INCLUDED == TRUE)
case BTIF_SV_AV_AA_SBC_SINK_INDEX:
*p_codec_type = BTA_AV_CODEC_SBC;
@@ -623,7 +782,28 @@
case BTA_AV_CODEC_SBC:
supported = TRUE;
break;
+ case A2D_NON_A2DP_MEDIA_CT:
+ {
+ UINT16 codecId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->codecId;
+ UINT32 vendorId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->vendorId;
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId );
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId );
+ if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) {
+ /* aptX */
+ supported = TRUE;
+ } else if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) {
+ /* aptX HD */
+ supported = TRUE;
+ }
+ break;
+ }
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ case BTA_AV_CODEC_M24:
+ APPL_TRACE_DEBUG("%s: AAC is supported", __func__);
+ supported = TRUE;
+ break;
+#endif
default:
break;
}
@@ -633,13 +813,21 @@
/* If there is room for a new one */
if (p_peer->num_sup_snks < BTA_AV_CO_NUM_ELEMENTS(p_peer->snks))
{
+ int i = 0;
p_sink = &p_peer->snks[p_peer->num_sup_snks++];
APPL_TRACE_DEBUG("bta_av_co_audio_getconfig saved caps[%x:%x:%x:%x:%x:%x]",
p_codec_info[1], p_codec_info[2], p_codec_info[3],
p_codec_info[4], p_codec_info[5], p_codec_info[6]);
- memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+ for (i = 0 ; i < AVDT_CODEC_SIZE; i++)
+ APPL_TRACE_DEBUG("%s p_codec_info[%d]: %x", __func__, i, p_codec_info[i]);
+
+ if (codec_type == A2D_NON_A2DP_MEDIA_CT)
+ memcpy(p_sink->codec_caps, &p_codec_info[BTA_AV_CFG_START_IDX], AVDT_CODEC_SIZE);
+ else
+ memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+
p_sink->codec_type = codec_type;
p_sink->sep_info_idx = *p_sep_info_idx;
p_sink->seid = seid;
@@ -662,7 +850,7 @@
mutex_global_lock();
/* Find a sink that matches the codec config */
- if (bta_av_co_audio_peer_supports_codec(p_peer, &index))
+ if (bta_av_co_audio_peer_supports_codec(p_peer, &index, NULL))
{
/* stop fetching caps once we retrieved a supported codec */
if (p_peer->acp)
@@ -676,10 +864,14 @@
/* Build the codec configuration for this sink */
if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg))
{
+ int i = 0;
APPL_TRACE_DEBUG("bta_av_co_audio_getconfig reconfig p_codec_info[%x:%x:%x:%x:%x:%x]",
codec_cfg[1], codec_cfg[2], codec_cfg[3],
codec_cfg[4], codec_cfg[5], codec_cfg[6]);
+ for (i = 0 ; i < AVDT_CODEC_SIZE; i++)
+ APPL_TRACE_DEBUG("%s p_codec_info[%d]: %x", __func__, i, p_codec_info[i]);
+
/* Save the new configuration */
p_peer->p_snk = p_sink;
memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE);
@@ -751,7 +943,7 @@
FUNC_TRACE();
- APPL_TRACE_DEBUG("bta_av_co_audio_setconfig p_codec_info[%x:%x:%x:%x:%x:%x]",
+ APPL_TRACE_IMP("bta_av_co_audio_setconfig p_codec_info[%x:%x:%x:%x:%x:%x]",
p_codec_info[1], p_codec_info[2], p_codec_info[3],
p_codec_info[4], p_codec_info[5], p_codec_info[6]);
APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x",
@@ -817,10 +1009,10 @@
mutex_global_lock();
/* Check if the configuration matches the current codec config */
- switch (bta_av_co_cb.codec_cfg.id)
+ switch (codec_type)
{
case BTIF_AV_CODEC_SBC:
- if ((codec_type != BTA_AV_CODEC_SBC) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg.info, 5))
+ if ((codec_type != BTA_AV_CODEC_SBC) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg_sbc.info, 5))
{
recfg_needed = TRUE;
}
@@ -831,24 +1023,93 @@
/* if remote side requests a restricted notify sinks preferred bitpool range as all other params are
already checked for validify */
+ APPL_TRACE_DEBUG("%s SBC", __func__);
APPL_TRACE_EVENT("remote peer setconfig bitpool range [%d:%d]",
p_codec_info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
p_codec_info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] );
- bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_SBC;
- memcpy(bta_av_co_cb.codec_cfg_setconfig.info, p_codec_info, AVDT_CODEC_SIZE);
+ bta_av_co_cb.codec_cfg_sbc_setconfig.id = BTIF_AV_CODEC_SBC;
+ memcpy(bta_av_co_cb.codec_cfg_sbc_setconfig.info, p_codec_info, AVDT_CODEC_SIZE);
+ bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_sbc_setconfig;
+ memcpy(bta_av_co_cb.codec_cfg_sbc.info, p_codec_info, AVDT_CODEC_SIZE);
+ memcpy(bta_av_co_cb.codec_cfg->info, p_codec_info, AVDT_CODEC_SIZE);
if(AVDT_TSEP_SNK == t_local_sep)
{
/* If Peer is SRC, and our cfg subset matches with what is requested by peer, then
just accept what peer wants */
- memcpy(bta_av_co_cb.codec_cfg.info, p_codec_info, AVDT_CODEC_SIZE);
recfg_needed = FALSE;
}
break;
+ case A2D_NON_A2DP_MEDIA_CT:
+ {
+ UINT16 codecId;
+ UINT32 vendorId;
+ codecId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->codecId;
+ vendorId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->vendorId;
+ APPL_TRACE_DEBUG("%s codec_type = %x", __func__, codec_type);
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId);
+ if ( (codec_type != A2D_NON_A2DP_MEDIA_CT) ||
+ ( (codecId != A2D_APTX_CODEC_ID_BLUETOOTH) &&
+ (codecId != A2D_APTX_HD_CODEC_ID_BLUETOOTH) )
+ || ((vendorId != A2D_APTX_VENDOR_ID) && (vendorId != A2D_APTX_HD_VENDOR_ID)) ||
+ (memcmp(p_codec_info, bta_av_co_cb.codec_cfg_aptx.info, 5) &&
+ memcmp(p_codec_info, bta_av_co_cb.codec_cfg_aptx_hd.info, 5)) )
+ {
+ APPL_TRACE_DEBUG("%s recfg_needed", __func__);
+ recfg_needed = TRUE;
+ }
+ else if ((num_protect == 1) && (!bta_av_co_cb.cp.active))
+ {
+ APPL_TRACE_DEBUG("%s recfg_needed", __func__);
+ recfg_needed = TRUE;
+ }
+
+ if ((codecId == A2D_APTX_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_VENDOR_ID)) {
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ bta_av_co_cb.codec_cfg_aptx_setconfig.id = A2D_NON_A2DP_MEDIA_CT;
+ memcpy(bta_av_co_cb.codec_cfg_aptx_setconfig.info, p_codec_info, AVDT_CODEC_SIZE);
+ bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_aptx_setconfig;
+ } else if ((codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_HD_VENDOR_ID)) {
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ bta_av_co_cb.codec_cfg_aptx_hd_setconfig.id = A2D_NON_A2DP_MEDIA_CT;
+ memcpy(bta_av_co_cb.codec_cfg_aptx_hd_setconfig.info, p_codec_info, AVDT_CODEC_SIZE);
+ bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_aptx_hd_setconfig;
+ }
+ break;
+ }
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ case BTA_AV_CODEC_M24:
+ {
+ tA2D_AAC_CIE p_aac_cie;
+ A2D_ParsAacInfo(&p_aac_cie, p_codec_info, FALSE);
+ APPL_TRACE_ERROR("%s p_aac_cie->bitrate = %x",__func__, p_aac_cie.bit_rate);
+ if ((codec_type != BTA_AV_CODEC_M24) ||
+ memcmp(p_codec_info, bta_av_co_cb.codec_cfg_aac.info, 5))
+ {
+ recfg_needed = TRUE;
+ }
+ else if (p_aac_cie.bit_rate == 0 || p_aac_cie.bit_rate < BTIF_AAC_MIN_BITRATE)
+ {
+ recfg_needed = TRUE;
+ }
+ else if ((num_protect == 1) && (!bta_av_co_cb.cp.active))
+ {
+ recfg_needed = TRUE;
+ }
+
+ APPL_TRACE_DEBUG("%s AAC", __func__);
+ bta_av_co_cb.codec_cfg_aac_setconfig.id = BTIF_AV_CODEC_M24;
+ memcpy(bta_av_co_cb.codec_cfg_aac_setconfig.info, p_codec_info, AVDT_CODEC_SIZE);
+ bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_aac_setconfig;
+
+ APPL_TRACE_DEBUG("%s codec_type = %x", __func__, codec_type);
+ } break;
+#endif
default:
- APPL_TRACE_ERROR("bta_av_co_audio_setconfig unsupported cid %d", bta_av_co_cb.codec_cfg.id);
+ APPL_TRACE_ERROR("bta_av_co_audio_setconfig unsupported cid %d", bta_av_co_cb.codec_cfg->id);
recfg_needed = TRUE;
break;
}
@@ -864,7 +1125,7 @@
if (status != A2D_SUCCESS)
{
- APPL_TRACE_DEBUG("bta_av_co_audio_setconfig reject s=%d c=%d", status, category);
+ APPL_TRACE_ERROR("bta_av_co_audio_setconfig reject s=%d c=%d", status, category);
/* Call call-in rejecting the configuration */
bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE, avdt_handle);
@@ -951,7 +1212,7 @@
}
/* reset remote preference through setconfig */
- bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE;
+ bta_av_co_cb.codec_cfg_setconfig = NULL;
}
/*******************************************************************************
@@ -969,14 +1230,21 @@
UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr)
{
UNUSED(hndl);
- UNUSED(codec_type);
- UNUSED(p_codec_info);
- UNUSED(p_no_rtp_hdr);
FUNC_TRACE();
APPL_TRACE_DEBUG("bta_av_co_audio_start");
+ if (codec_type == A2D_NON_A2DP_MEDIA_CT) {
+ UINT16 codecId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->codecId;
+ UINT32 vendorId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->vendorId;
+
+ // for aptX, we only add RTP hdr along with CP
+ if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) {
+ if (!bta_av_co_cb.cp.active)
+ *p_no_rtp_hdr = TRUE;
+ }
+ }
}
/*******************************************************************************
@@ -1034,8 +1302,10 @@
/* Set up packet header */
bta_av_sbc_bld_hdr(p_buf, p_buf->layer_specific);
break;
-
-
+ case A2D_NON_A2DP_MEDIA_CT:
+ /* Retrieve the timestamp information from the media packet */
+ *p_timestamp = *((UINT32 *) (p_buf + 1));
+ break;
default:
APPL_TRACE_ERROR("bta_av_co_audio_src_data_path Unsupported codec type (%d)", codec_type);
break;
@@ -1107,26 +1377,69 @@
static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg)
{
FUNC_TRACE();
+ tA2D_AAC_CIE peer_aac_cfg;
+ tA2D_AAC_CIE aac_cfg_selected;
memset(p_codec_cfg, 0, AVDT_CODEC_SIZE);
- switch (bta_av_co_cb.codec_cfg.id)
+ switch (bta_av_co_cb.codec_cfg->id)
{
case BTIF_AV_CODEC_SBC:
/* only copy the relevant portions for this codec to avoid issues when
comparing codec configs covering larger codec sets than SBC (7 bytes) */
- memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg.info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF+1);
+ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF+1);
/* Update the bit pool boundaries with the codec capabilities */
p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF];
p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF];
+ APPL_TRACE_DEBUG("%s SBC", __func__);
APPL_TRACE_EVENT("bta_av_co_audio_codec_build_config : bitpool min %d, max %d",
p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]);
break;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ case BTIF_AV_CODEC_M24:
+ /* only copy the relevant portions for this codec to avoid issues when
+ comparing codec configs covering larger codec sets than SBC (7 bytes) */
+ A2D_ParsAacInfo (&peer_aac_cfg ,(UINT8*)p_codec_caps, FALSE);
+ A2D_ParsAacInfo (&aac_cfg_selected ,bta_av_co_cb.codec_cfg->info, FALSE);
+
+ if (peer_aac_cfg.bit_rate != 0 && peer_aac_cfg.bit_rate >= BTIF_AAC_MIN_BITRATE)
+ {
+ aac_cfg_selected.bit_rate =
+ BTA_AV_CO_MIN(peer_aac_cfg.bit_rate,
+ aac_cfg_selected.bit_rate);
+ //update with new value
+ A2D_BldAacInfo (AVDT_MEDIA_AUDIO, &aac_cfg_selected, bta_av_co_cb.codec_cfg->info);
+ }
+ APPL_TRACE_EVENT("%s AAC bitrate selected %d", __func__,
+ aac_cfg_selected.bit_rate);
+ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, A2D_AAC_INFO_LEN+1);
+ APPL_TRACE_DEBUG("%s AAC", __func__);
+ break;
+#endif
+ case A2D_NON_A2DP_MEDIA_CT:
+ {
+ UINT16 codecId;
+ UINT16 vendorId;
+ codecId = ((tA2D_APTX_CIE*)p_codec_caps)->codecId;
+ vendorId = ((tA2D_APTX_CIE*)p_codec_caps)->vendorId;
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId);
+
+ if ((codecId == A2D_APTX_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_VENDOR_ID)) {
+ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, A2D_APTX_CODEC_LEN+1);
+ APPL_TRACE_DEBUG("%s aptX",__func__);
+ } else if ((codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_HD_VENDOR_ID)) {
+ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, A2D_APTX_HD_CODEC_LEN+1);
+ APPL_TRACE_DEBUG("%s aptX HD",__func__);
+ }
+ break;
+ }
+
default:
- APPL_TRACE_ERROR("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg.id);
+ APPL_TRACE_ERROR("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg->id);
return FALSE;
break;
}
@@ -1168,8 +1481,71 @@
return FALSE;
}
break;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ /* in case of Sink we have to match if Src Cap is a subset of ours */
+ case BTA_AV_CODEC_M24:
+ {
+ tBTIF_AV_CODEC_INFO *p_local_aac_cfg = (tBTIF_AV_CODEC_INFO*)p_codec_cfg;
+ tA2D_AAC_CIE p_local_aac_caps;
+ tA2D_AAC_CIE p_snk_aac_caps;
+ if (A2D_ParsAacInfo(&p_local_aac_caps, (UINT8*)p_local_aac_cfg, FALSE) != A2D_SUCCESS) {
+ APPL_TRACE_ERROR("%s: A2D_BldAacInfo: LOCAL failed", __func__);
+ }
+ if (A2D_ParsAacInfo(&p_snk_aac_caps, (UINT8*)p_codec_cfg, FALSE) != A2D_SUCCESS) {
+ APPL_TRACE_ERROR("%s: A2D_BldAacInfo: SNK failed", __func__);
+ }
+ APPL_TRACE_EVENT("AAC obj_type: snk %x local %x",
+ p_snk_aac_caps.object_type, p_local_aac_caps.object_type);
+ APPL_TRACE_EVENT("AAC samp_freq: snk %x local %x",
+ p_snk_aac_caps.samp_freq, p_local_aac_caps.samp_freq);
+ APPL_TRACE_EVENT("AAC channels: snk %x local %x",
+ p_snk_aac_caps.channels, p_local_aac_caps.channels);
+ APPL_TRACE_EVENT("AAC bit_rate: snk %x local %x",
+ p_snk_aac_caps.bit_rate, p_local_aac_caps.bit_rate);
+ APPL_TRACE_EVENT("AAC vbr: snk %x local %x",
+ p_snk_aac_caps.vbr, p_local_aac_caps.vbr);
+ return (((p_snk_aac_caps.object_type)&(p_local_aac_caps.object_type))&&
+ ((p_snk_aac_caps.samp_freq)&(p_local_aac_caps.samp_freq))&&
+ ((p_snk_aac_caps.channels)&(p_local_aac_caps.channels)));
+ }
+ break;
+#endif
+ case A2D_NON_A2DP_MEDIA_CT:
+ {
+ UINT16 codecId;
+ UINT32 vendorId;
+ UINT8* aptx_capabilities;
+
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ aptx_capabilities = &(((tBTA_AV_CO_SINK*)p_codec_cfg)->codec_caps[0]);
+ codecId = ((tA2D_APTX_CIE*)p_codec_caps)->codecId;
+ vendorId = ((tA2D_APTX_CIE*)p_codec_caps)->vendorId;
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId);
+
+ int i = 0;
+ for (i = 0 ; i < AVDT_CODEC_SIZE; i++)
+ APPL_TRACE_DEBUG("%s p_codec_cfg[%d]: %x", __func__, i, p_codec_cfg[i]);
+
+ APPL_TRACE_EVENT("%s Caps -> sample rate/channel mode: %x configured %x", __func__, p_codec_caps[6], p_codec_cfg[9]);
+
+ if (((vendorId != ((tA2D_APTX_CIE*)(aptx_capabilities))->vendorId) || /*vendor id*/
+ (codecId != ((tA2D_APTX_CIE*)(aptx_capabilities))->codecId) || /*codec id*/
+ ((p_codec_caps[6] & p_codec_cfg[9]) == 0 ) /*sampling rate & channel mode*/
+ ))
+ {
+ APPL_TRACE_DEBUG("%s aptX config don't match", __func__);
+ APPL_TRACE_EVENT("%s Caps -> vendor id: %x %x %x %x", __func__, p_codec_caps[0], p_codec_caps[1], p_codec_caps[2], p_codec_caps[3]);
+ APPL_TRACE_EVENT("%s Configured: %x %x %x %x", __func__, p_codec_cfg[3], p_codec_cfg[4], p_codec_cfg[5], p_codec_cfg[6]);
+ APPL_TRACE_EVENT("%s Caps -> codec id: %x", __func__, p_codec_caps[4]);
+ APPL_TRACE_EVENT("%s Configured: %x ", __func__, p_codec_cfg[7]);
+ APPL_TRACE_EVENT("%s Caps -> Sample Rate/Channel Mode: %x Configured: %x", __func__, p_codec_caps[6], p_codec_cfg[9]);
+ return FALSE;
+ }
+ break;
+ }
default:
APPL_TRACE_ERROR("bta_av_co_audio_codec_cfg_matches_caps: unsupported codec id %d", codec_id);
return FALSE;
@@ -1189,11 +1565,54 @@
** Returns TRUE if the connection supports this codec, FALSE otherwise
**
*******************************************************************************/
-static BOOLEAN bta_av_co_audio_codec_match(const UINT8 *p_codec_caps)
+static BOOLEAN bta_av_co_audio_codec_match(const UINT8 *p_codec_caps, UINT8 codec_id)
{
FUNC_TRACE();
- return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg.id, p_codec_caps, bta_av_co_cb.codec_cfg.info);
+ switch(codec_id)
+ {
+ case BTIF_AV_CODEC_SBC:
+ return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_sbc.id, p_codec_caps, bta_av_co_cb.codec_cfg_sbc.info);
+ break;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ case BTIF_AV_CODEC_M24:
+ return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_aac.id, p_codec_caps, bta_av_co_cb.codec_cfg_aac.info);
+ break;
+#endif
+ case A2D_NON_A2DP_MEDIA_CT:
+ {
+ UINT16 codecId;
+ UINT32 vendorId;
+ int i = 0;
+ for (i = 0 ; i < AVDT_CODEC_SIZE; i++)
+ APPL_TRACE_DEBUG("%s p_codec_caps[%d]: %x", __func__, i, p_codec_caps[i]);
+
+ codecId = ((tA2D_APTX_CIE*)p_codec_caps)->codecId;
+ vendorId = ((tA2D_APTX_CIE*)p_codec_caps)->vendorId;
+ APPL_TRACE_DEBUG("%s codecId = %d ", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x ", __func__, vendorId);
+
+ if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) {
+ /* aptX Classic */
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_aptx.id, p_codec_caps, bta_av_co_cb.codec_cfg_aptx.info);
+ break;
+ } else if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) {
+ /* aptX HD */
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_aptx_hd.id, p_codec_caps, bta_av_co_cb.codec_cfg_aptx_hd.info);
+ break;
+ } else {
+ APPL_TRACE_ERROR("%s incorrect codecId (%d)", __func__, codecId);
+ APPL_TRACE_ERROR("%s incorrect vendorId (%x)", __func__, vendorId);
+ break;
+ }
+ }
+ default:
+ return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_sbc.id, p_codec_caps, bta_av_co_cb.codec_cfg_sbc.info);
+ break;
+ }
+ return TRUE;
}
/*******************************************************************************
@@ -1300,6 +1719,26 @@
}
}
+BOOLEAN bta_av_co_audio_is_aac_enabled(bt_bdaddr_t *remote_bdaddr)
+{
+ int retval;
+ BOOLEAN res = FALSE;
+ char is_whitelist_by_default[255] = "false";
+ retval = property_get("persist.bt.a2dp.aac_whitelist", is_whitelist_by_default, "false");
+ BTIF_TRACE_DEBUG("%s: property_get: bt.a2dp.aac_whitelist: %s, retval: %d",
+ __func__, is_whitelist_by_default, retval);
+
+ if (!strncmp(is_whitelist_by_default, "true", 4)) {
+ if (interop_match_addr(INTEROP_ENABLE_AAC_CODEC, remote_bdaddr))
+ res = TRUE;
+ } else if (!interop_match_addr(INTEROP_DISABLE_AAC_CODEC, remote_bdaddr)) {
+ res = TRUE;
+ }
+
+ return res;
+}
+
+
/*******************************************************************************
**
** Function bta_av_co_audio_peer_supports_codec
@@ -1309,30 +1748,183 @@
** Returns TRUE if the connection supports this codec, FALSE otherwise
**
*******************************************************************************/
-static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index)
+static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index, UINT8 *p_codec_type)
{
int index;
UINT8 codec_type;
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, p_peer->addr);
+
FUNC_TRACE();
+ codec_type = bta_av_co_cb.codec_cfg->id;
+
/* Configure the codec type to look for */
- codec_type = bta_av_co_cb.codec_cfg.id;
+ if (p_codec_type != NULL)
+ {
+ APPL_TRACE_DEBUG("%s Incoming codec_type = %d", __func__, *p_codec_type);
+ APPL_TRACE_DEBUG("%s SEP codec_type = %d", __func__, codec_type);
+ }
+
+/* Check for aptX HD before aptX Classic as
+ * this is order of priority, if supported return true.
+ * multicast is not supported for aptX
+ */
+ if ((!bt_split_a2dp_enabled && isA2dAptXEnabled && (btif_av_is_multicast_supported() == FALSE)) ||
+ (bt_split_a2dp_enabled && (btif_av_is_codec_offload_supported(APTX)|| btif_av_is_codec_offload_supported(APTXHD))))
+ {
+ UINT16 codecId;
+ UINT32 vendorId;
+ UINT8* aptx_capabilities;
+
+ if ((bt_split_a2dp_enabled && btif_av_is_codec_offload_supported(APTXHD)) || isA2dAptXHdEnabled) {
+ for (index = 0; index < p_peer->num_sup_snks; index++)
+ {
+ if (((p_codec_type != NULL) && (p_peer->snks[index].codec_type == *p_codec_type)) ||
+ ((p_codec_type == NULL) && (p_peer->snks[index].codec_type == A2D_NON_A2DP_MEDIA_CT)))
+ {
+ aptx_capabilities = &(p_peer->snks[index].codec_caps[0]);
+ codecId = ((tA2D_APTX_HD_CIE*)aptx_capabilities)->codecId;
+ vendorId = ((tA2D_APTX_HD_CIE*)aptx_capabilities)->vendorId;
+ int i = 0;
+ for ( i = 0 ; i < AVDT_CODEC_SIZE; i++) {
+ APPL_TRACE_DEBUG("%s codec_caps[%d]: %x", __func__, i, p_peer->snks[index].codec_caps[i]);
+ }
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId);
+ APPL_TRACE_DEBUG("%s p_peer->snks[index].codec_type = %x", __func__, p_peer->snks[index].codec_type );
+
+ if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID )
+ {
+ if (p_snk_index)
+ *p_snk_index = index;
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+
+ if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, A2D_NON_A2DP_MEDIA_CT))
+ {
+ #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index]))
+ #endif
+ {
+ bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_aptx_hd.id;
+ bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_aptx_hd;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ if ((bt_split_a2dp_enabled && btif_av_is_codec_offload_supported(APTX)) || isA2dAptXEnabled) {
+ for (index = 0; index < p_peer->num_sup_snks; index++)
+ {
+ if (((p_codec_type != NULL) && (p_peer->snks[index].codec_type == *p_codec_type)) ||
+ ((p_codec_type == NULL) && (p_peer->snks[index].codec_type == A2D_NON_A2DP_MEDIA_CT)))
+ {
+ aptx_capabilities = &(p_peer->snks[index].codec_caps[0]);
+ codecId = ((tA2D_APTX_CIE*)aptx_capabilities)->codecId;
+ vendorId = ((tA2D_APTX_CIE*)aptx_capabilities)->vendorId;
+ int i = 0;
+ for ( i = 0 ; i < AVDT_CODEC_SIZE; i++) {
+ APPL_TRACE_DEBUG("%s codec_caps[%d]: %x", __func__, i, p_peer->snks[index].codec_caps[i]);
+ }
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId);
+ APPL_TRACE_DEBUG("%s p_peer->snks[index].codec_type = %x", __func__, p_peer->snks[index].codec_type );
+
+ if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID)
+ {
+ if (p_snk_index)
+ *p_snk_index = index;
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+
+ if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, A2D_NON_A2DP_MEDIA_CT))
+ {
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index]))
+#endif
+ {
+ bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_aptx.id;
+ bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_aptx;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ } else
+ APPL_TRACE_DEBUG("%s aptX is disabled", __func__);
+
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ if (bt_split_a2dp_enabled && btif_av_is_codec_offload_supported(AAC) &&
+ bta_av_co_audio_is_aac_enabled(&remote_bdaddr)) {
+ for (index = 0; index < p_peer->num_sup_snks; index++)
+ {
+ APPL_TRACE_DEBUG("%s AAC: index: %d, codec_type: %d", __func__, index, p_peer->snks[index].codec_type);
+
+ if (((p_codec_type != NULL) && (p_peer->snks[index].codec_type == *p_codec_type)) ||
+ ((p_codec_type == NULL) && (p_peer->snks[index].codec_type == bta_av_co_cb.codec_cfg_aac.id)))
+ {
+ switch (p_peer->snks[index].codec_type)
+ {
+ case BTIF_AV_CODEC_M24:
+ if (p_snk_index) *p_snk_index = index;
+ APPL_TRACE_DEBUG("%s AAC", __func__);
+ if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, BTIF_AV_CODEC_M24))
+ {
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index]))
+#endif
+ {
+ bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_aac.id;
+ bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_aac;
+
+ APPL_TRACE_DEBUG("%s AAC matched", __func__);
+ return TRUE;
+ }
+ }
+ break;
+
+ default:
+ APPL_TRACE_ERROR("AAC: bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg->id);
+ //Fall thru for further SBC check
+ break;
+ }
+ }
+ }
+ } else
+ APPL_TRACE_DEBUG("%s AAC is disabled", __func__);
+#endif
for (index = 0; index < p_peer->num_sup_snks; index++)
{
- if (p_peer->snks[index].codec_type == codec_type)
+ if (((p_codec_type != NULL) && (p_peer->snks[index].codec_type == *p_codec_type)) ||
+ ((p_codec_type == NULL) && (p_peer->snks[index].codec_type == codec_type ||
+ p_peer->snks[index].codec_type == bta_av_co_cb.codec_cfg_sbc.id)))
{
- switch (bta_av_co_cb.codec_cfg.id)
+ switch (p_peer->snks[index].codec_type)
{
case BTIF_AV_CODEC_SBC:
if (p_snk_index) *p_snk_index = index;
- return bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps);
+ APPL_TRACE_DEBUG("%s SBC", __func__);
+ if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, BTIF_AV_CODEC_SBC))
+ {
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index]))
+#endif
+ {
+ bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_sbc.id;
+ bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_sbc;
+ return TRUE;
+ }
+ }
break;
default:
- APPL_TRACE_ERROR("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg.id);
+ APPL_TRACE_ERROR("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg->id);
return FALSE;
break;
}
@@ -1357,14 +1949,14 @@
FUNC_TRACE();
/* Configure the codec type to look for */
- codec_type = bta_av_co_cb.codec_cfg.id;
+ codec_type = bta_av_co_cb.codec_cfg->id;
for (index = 0; index < p_peer->num_sup_srcs; index++)
{
if (p_peer->srcs[index].codec_type == codec_type)
{
- switch (bta_av_co_cb.codec_cfg.id)
+ switch (bta_av_co_cb.codec_cfg->id)
{
case BTIF_AV_CODEC_SBC:
if (p_src_index) *p_src_index = index;
@@ -1377,7 +1969,7 @@
default:
APPL_TRACE_ERROR("peer_src_supports_codec: unsupported codec id %d",
- bta_av_co_cb.codec_cfg.id);
+ bta_av_co_cb.codec_cfg->id);
return FALSE;
break;
}
@@ -1430,16 +2022,52 @@
{
FUNC_TRACE();
+ APPL_TRACE_DEBUG("%s codec_type = %x", __func__, codec_type);
+
+ UINT16 codecId;
+ UINT32 vendorId;
+ UINT8* aptx_capabilities;
+
switch (codec_type)
{
case BTA_AV_CODEC_SBC:
if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps))
{
+ APPL_TRACE_DEBUG("%s SBC ",__func__);
return FALSE;
}
break;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ case BTA_AV_CODEC_M24:
+ if (bta_av_aac_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_AAC_CIE *)&bta_av_co_aac_caps))
+ {
+ APPL_TRACE_DEBUG("%s AAC ",__func__);
+ return FALSE;
+ }
+ break;
+#endif
+ case A2D_NON_A2DP_MEDIA_CT:
+ aptx_capabilities = &(((tBTA_AV_CO_SINK*)p_codec_cfg)->codec_caps[0]);
+ codecId = ((tA2D_APTX_CIE*)(aptx_capabilities))->codecId;
+ vendorId = ((tA2D_APTX_CIE*)(aptx_capabilities))->vendorId;
+ APPL_TRACE_DEBUG("%s codecId = %d ", __func__, codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x ", __func__, vendorId);
-
+ if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) {
+ APPL_TRACE_DEBUG("%s tA2D_APTX_CIE aptX HD", __func__);
+ if (a2d_av_aptx_hd_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_APTX_HD_CIE *)&bta_av_co_aptx_hd_caps)) {
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ return FALSE;
+ }
+ break;
+ } else if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) {
+ APPL_TRACE_DEBUG("%s tA2D_APTX_CIE aptX", __func__);
+ if (a2d_av_aptx_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_APTX_CIE *)&bta_av_co_aptx_caps)) {
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ return FALSE;
+ }
+ break;
+ }
default:
APPL_TRACE_ERROR("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type);
return FALSE;
@@ -1469,7 +2097,9 @@
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
BOOLEAN cp_active;
#endif
-
+ UINT16 current_codec_id;
+ current_codec_id = bta_av_co_cb.current_codec_id;
+ UINT8 p_scb_codec_type = 0;
FUNC_TRACE();
APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported");
@@ -1482,8 +2112,22 @@
p_peer = &bta_av_co_cb.peers[index];
if (p_peer->opened)
{
- if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index))
+ if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index, NULL))
{
+ APPL_TRACE_DEBUG("%s current_codec_id: %x", __func__, bta_av_co_cb.current_codec_id);
+ p_scb_codec_type = bta_av_get_codec_type(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index));
+ APPL_TRACE_DEBUG("%s p_scb_codec_type: %x", __func__, p_scb_codec_type);
+ APPL_TRACE_DEBUG("%s current_sink_index: %x", __func__, snk_index);
+ if (bta_av_co_cb.current_codec_id != p_scb_codec_type)
+ {
+ APPL_TRACE_WARNING("%s Mismatch found in selected codec and configured codec type", __func__);
+ if (!bta_av_co_audio_peer_supports_codec(p_peer, &snk_index, &p_scb_codec_type))
+ {
+ APPL_TRACE_ERROR("bta_av_co_audio_codec_supported index %d doesn't support codec", index);
+ return FALSE;
+ }
+ APPL_TRACE_WARNING("%s current_sink_index changed to: %x", __func__, snk_index);
+ }
p_sink = &p_peer->snks[snk_index];
/* Check that this sink is compatible with the CP */
@@ -1492,7 +2136,16 @@
APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported sink %d of peer %d doesn't support cp",
snk_index, index);
*p_status = BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED;
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (!bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg))
+ {
+ APPL_TRACE_DEBUG("%s index %d doesn't support codec", __func__, index);
+ return FALSE;
+ }
+ return TRUE;
+#else
return FALSE;
+#endif
}
/* Build the codec configuration for this sink */
@@ -1502,6 +2155,10 @@
/* Check if this sink supports SCMS */
cp_active = bta_av_co_audio_sink_has_scmst(p_sink);
#endif
+ APPL_TRACE_DEBUG("%s current_codec_id: %x", __func__, bta_av_co_cb.current_codec_id);
+ APPL_TRACE_DEBUG("%s p_scb_codec_type: %x", __func__, p_scb_codec_type);
+ p_scb_codec_type = bta_av_get_codec_type(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index));
+ APPL_TRACE_DEBUG("%s p_scb_codec_type: %x", __func__, p_scb_codec_type);
/* Check if this is a new configuration (new sink or new config) */
if ((p_sink != p_peer->p_snk) ||
(memcmp(codec_cfg, p_peer->codec_cfg, AVDT_CODEC_SIZE))
@@ -1558,12 +2215,30 @@
FUNC_TRACE();
/* Reset the current configuration to SBC */
- bta_av_co_cb.codec_cfg.id = BTIF_AV_CODEC_SBC;
-
- if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btif_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS)
+ bta_av_co_cb.codec_cfg_sbc.id = BTIF_AV_CODEC_SBC;
+ if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btif_av_sbc_default_config, bta_av_co_cb.codec_cfg_sbc.info) != A2D_SUCCESS)
{
APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed");
- }
+ } else
+ bta_av_co_cb.codec_cfg = &(bta_av_co_cb.codec_cfg_sbc);
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ /* Reset the current configuration to AAC */
+ bta_av_co_cb.codec_cfg_aac.id = BTIF_AV_CODEC_M24;
+ if (A2D_BldAacInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_AAC_CIE *)&btif_av_aac_default_config, bta_av_co_cb.codec_cfg_aac.info) != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldAacInfo failed");
+ } else
+ bta_av_co_cb.codec_cfg = &(bta_av_co_cb.codec_cfg_sbc);
+#endif
+ /* Reset the Current configuration to aptX */
+ bta_av_co_cb.codec_cfg_aptx.id = A2D_NON_A2DP_MEDIA_CT;
+ if (A2D_BldAptxInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_APTX_CIE *)&btif_av_aptx_default_config, bta_av_co_cb.codec_cfg_aptx.info) != A2D_SUCCESS)
+ APPL_TRACE_ERROR("%s A2D_BldAptxInfo failed", __func__);
+
+ /* Reset the Current configuration to aptX HD */
+ bta_av_co_cb.codec_cfg_aptx_hd.id = A2D_NON_A2DP_MEDIA_CT;
+ if (A2D_BldAptx_hdInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_APTX_HD_CIE *)&btif_av_aptx_hd_default_config, bta_av_co_cb.codec_cfg_aptx_hd.info) != A2D_SUCCESS)
+ APPL_TRACE_ERROR("%s A2D_BldAptx_hdInfo failed", __func__);
mutex_global_unlock();
}
@@ -1582,8 +2257,15 @@
BOOLEAN bta_av_co_audio_set_codec(const tBTIF_AV_MEDIA_FEEDINGS *p_feeding, tBTIF_STATUS *p_status)
{
tA2D_SBC_CIE sbc_config;
- tBTIF_AV_CODEC_INFO new_cfg;
-
+ tBTIF_AV_CODEC_INFO new_cfg_sbc;
+ tA2D_APTX_CIE aptx_config;
+ tBTIF_AV_CODEC_INFO new_cfg_aptx;
+ tA2D_APTX_HD_CIE aptx_hd_config;
+ tBTIF_AV_CODEC_INFO new_cfg_aptx_hd;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ tA2D_AAC_CIE aac_config;
+ tBTIF_AV_CODEC_INFO new_cfg_aac;
+#endif
FUNC_TRACE();
/* Check AV feeding is supported */
@@ -1595,7 +2277,7 @@
switch (p_feeding->format)
{
case BTIF_AV_CODEC_PCM:
- new_cfg.id = BTIF_AV_CODEC_SBC;
+ new_cfg_sbc.id = BTIF_AV_CODEC_SBC;
sbc_config = btif_av_sbc_default_config;
if ((p_feeding->cfg.pcm.num_channel != 1) &&
@@ -1605,11 +2287,20 @@
return FALSE;
}
if ((p_feeding->cfg.pcm.bit_per_sample != 8) &&
- (p_feeding->cfg.pcm.bit_per_sample != 16))
+ (p_feeding->cfg.pcm.bit_per_sample != 16) &&
+ (p_feeding->cfg.pcm.bit_per_sample != 32))
{
APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM sample size unsupported");
return FALSE;
}
+ new_cfg_aptx.id = A2D_NON_A2DP_MEDIA_CT;
+ aptx_config = btif_av_aptx_default_config;
+ new_cfg_aptx_hd.id = A2D_NON_A2DP_MEDIA_CT;
+ aptx_hd_config = btif_av_aptx_hd_default_config;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ new_cfg_aac.id = BTIF_AV_CODEC_M24;
+ aac_config = btif_av_aac_default_config;
+#endif
switch (p_feeding->cfg.pcm.sampling_freq)
{
case 8000:
@@ -1619,12 +2310,22 @@
case 32000:
case 48000:
sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_48;
+ aptx_config.sampleRate = A2D_APTX_SAMPLERATE_48000;
+ aptx_hd_config.sampleRate = A2D_APTX_HD_SAMPLERATE_48000;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ aac_config.samp_freq = A2D_AAC_IE_SAMP_FREQ_48000;
+#endif
break;
case 11025:
case 22050:
case 44100:
sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_44;
+ aptx_config.sampleRate = A2D_APTX_SAMPLERATE_44100;
+ aptx_hd_config.sampleRate = A2D_APTX_HD_SAMPLERATE_44100;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ aac_config.samp_freq = A2D_AAC_IE_SAMP_FREQ_44100;
+#endif
break;
default:
APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM sampling frequency unsupported");
@@ -1632,11 +2333,28 @@
break;
}
/* Build the codec config */
- if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &sbc_config, new_cfg.info) != A2D_SUCCESS)
+ if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &sbc_config, new_cfg_sbc.info) != A2D_SUCCESS)
{
APPL_TRACE_ERROR("bta_av_co_audio_set_codec A2D_BldSbcInfo failed");
return FALSE;
}
+ if (A2D_BldAptxInfo(A2D_MEDIA_TYPE_AUDIO, &aptx_config, new_cfg_aptx.info) != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR("%s A2D_BldAptxInfo failed", __func__);
+ return FALSE;
+ }
+ if (A2D_BldAptx_hdInfo(A2D_MEDIA_TYPE_AUDIO, &aptx_hd_config, new_cfg_aptx_hd.info) != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR("%s A2D_BldAptx_hdInfo failed", __func__);
+ return FALSE;
+ }
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ if (A2D_BldAacInfo(A2D_MEDIA_TYPE_AUDIO, &aac_config, new_cfg_aac.info) != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR("%s A2D_BldAacInfo failed", __func__);
+ return FALSE;
+ }
+#endif
break;
@@ -1646,15 +2364,164 @@
break;
}
- /* The new config was correctly built */
- bta_av_co_cb.codec_cfg = new_cfg;
-
+ /* The new config was correctly built. The default codec is set to be SBC */
+ bta_av_co_cb.codec_cfg_sbc = new_cfg_sbc;
+ bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_sbc;
+ bta_av_co_cb.codec_cfg_aptx= new_cfg_aptx;
+ bta_av_co_cb.codec_cfg_aptx_hd = new_cfg_aptx_hd;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ bta_av_co_cb.codec_cfg_aac = new_cfg_aac;
+#endif
/* Check all devices support it */
*p_status = BTIF_SUCCESS;
return bta_av_co_audio_codec_supported(p_status);
}
+UINT8 bta_av_select_codec(UINT8 hdl)
+{
+ if (NULL == bta_av_co_cb.codec_cfg)
+ {
+ // Some circumstances - bta_av_co functions are called before
+ // codec clock is initialised
+ APPL_TRACE_ERROR("%s hdl = %d, no codec configured", __func__, hdl);
+ return BTIF_AV_CODEC_NONE;
+ }
+ else
+ {
+ tBTA_AV_CO_PEER *p_peer;
+ UINT8 index;
+ APPL_TRACE_ERROR("%s hdl = %d",__func__,hdl);
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hdl);
+ /* Fix for below KW Issue
+ Pointer 'p_peer' returned from call to function 'bta_av_co_get_peer' at line
+ 1993 may be NULL, will be passed to function and may be dereferenced there
+ by passing argument 1 to function 'bta_av_co_audio_peer_supports_codec' at
+ line 2001.*/
+ if (p_peer != NULL)
+ {
+ bta_av_co_audio_peer_supports_codec(p_peer,&index, NULL);
+ }
+ return bta_av_co_cb.codec_cfg->id;
+ }
+}
+
+UINT8 bta_av_co_get_current_codec()
+{
+ // Some circumstances - bta_av_co functions are called before codec clock is initialised
+ if (NULL == bta_av_co_cb.codec_cfg)
+ return BTIF_AV_CODEC_NONE;
+ else
+ return bta_av_co_cb.codec_cfg->id;
+}
+
+UINT8* bta_av_co_get_current_codecInfo()
+{
+ // We assume that the configuration block is always valid when this is called.
+ return &bta_av_co_cb.codec_cfg->info[0];
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_get_codec_config
+ **
+ ** Description Retrieves the current codec configuration. In case of failure return
+ ** the default SBC codec configuration.
+ **
+ ** Returns TRUE if returned current codec config, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_get_codec_config(UINT8 *p_config, UINT16 *p_minmtu, UINT8 type)
+{
+ BOOLEAN result = FALSE;
+ UINT8 index, jndex;
+ tBTA_AV_CO_PEER *p_peer;
+ tBTA_AV_CO_SINK *p_sink;
+ tA2D_SBC_CIE *sbc_config;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ tA2D_AAC_CIE *aac_config;
+#endif
+
+ APPL_TRACE_EVENT("%s codec 0x%x", __func__, bta_av_co_cb.codec_cfg->id);
+
+ /* Minimum MTU is by default very large */
+ *p_minmtu = 0xFFFF;
+
+ mutex_global_lock();
+ if (type == BTIF_AV_CODEC_SBC)
+ {
+ APPL_TRACE_DEBUG("%s SBC", __func__);
+ sbc_config = (tA2D_SBC_CIE *)p_config;
+ if (A2D_ParsSbcInfo(sbc_config, bta_av_co_cb.codec_cfg_sbc.info, FALSE) == A2D_SUCCESS)
+ result = TRUE;
+ else
+ memcpy((tA2D_SBC_CIE *) p_config, &btif_av_sbc_default_config, sizeof(tA2D_SBC_CIE));
+ } else if (type == A2D_NON_A2DP_MEDIA_CT && ((tA2D_APTX_CIE *)p_config)->vendorId == A2D_APTX_VENDOR_ID && ((tA2D_APTX_CIE *)p_config)->codecId == A2D_APTX_CODEC_ID_BLUETOOTH) {
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ tA2D_APTX_CIE *aptx_config = (tA2D_APTX_CIE *)p_config;
+ if (A2D_ParsAptxInfo(aptx_config, bta_av_co_cb.codec_cfg_aptx.info, FALSE) == A2D_SUCCESS)
+ result = TRUE;
+ else
+ memcpy((tA2D_APTX_CIE *) p_config, &btif_av_aptx_default_config, sizeof(tA2D_APTX_CIE));
+ } else if (type == A2D_NON_A2DP_MEDIA_CT && ((tA2D_APTX_HD_CIE *)p_config)->vendorId == A2D_APTX_HD_VENDOR_ID && ((tA2D_APTX_HD_CIE *)p_config)->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) {
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ tA2D_APTX_HD_CIE *aptx_hd_config = (tA2D_APTX_HD_CIE *)p_config;
+ if (A2D_ParsAptx_hdInfo(aptx_hd_config, bta_av_co_cb.codec_cfg_aptx_hd.info, FALSE) == A2D_SUCCESS)
+ result = TRUE;
+ else
+ memcpy((tA2D_APTX_HD_CIE *) p_config, &btif_av_aptx_hd_default_config, sizeof(tA2D_APTX_HD_CIE));
+ } else {
+ APPL_TRACE_DEBUG("%s vendorId: %d codecId: %d\n", __func__, ((tA2D_APTX_CIE *)p_config)->vendorId, ((tA2D_APTX_CIE *)p_config)->codecId);
+ }
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ if (type == BTIF_AV_CODEC_M24)
+ {
+ APPL_TRACE_DEBUG("%s AAC", __func__);
+ aac_config = (tA2D_AAC_CIE *)p_config;
+ if (A2D_ParsAacInfo(aac_config, bta_av_co_cb.codec_cfg_aac.info, FALSE) == A2D_SUCCESS)
+ result = TRUE;
+ else
+ memcpy((tA2D_AAC_CIE *) p_config, &btif_av_aac_default_config, sizeof(tA2D_AAC_CIE));
+ }
+#endif
+ for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++)
+ {
+ p_peer = &bta_av_co_cb.peers[index];
+ if (p_peer->opened)
+ {
+ if (p_peer->mtu < *p_minmtu)
+ *p_minmtu = p_peer->mtu;
+
+ for (jndex = 0; jndex < p_peer->num_sup_snks; jndex++)
+ {
+ p_sink = &p_peer->snks[jndex];
+ if (type == BTIF_AV_CODEC_SBC && p_sink->codec_type == A2D_MEDIA_CT_SBC)
+ {
+ /* Update the bitpool boundaries of the current config */
+ sbc_config->min_bitpool =
+ BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
+ sbc_config->min_bitpool);
+ sbc_config->max_bitpool =
+ BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF],
+ sbc_config->max_bitpool);
+ APPL_TRACE_EVENT("%s actual sink bitpool min %d, max %d", __func__,
+ sbc_config->min_bitpool, sbc_config->max_bitpool);
+ if(sbc_config->min_bitpool > sbc_config->max_bitpool) {
+ sbc_config->max_bitpool = sbc_config->min_bitpool;
+ APPL_TRACE_EVENT("%s changed sink bitpool min %d, max %d", __func__,
+ sbc_config->min_bitpool, sbc_config->max_bitpool);
+ }
+ break;
+ }
+ }
+ }
+ }
+ mutex_global_unlock();
+
+ return result;
+}
+
/*******************************************************************************
**
** Function bta_av_co_audio_get_sbc_config
@@ -1672,21 +2539,22 @@
tBTA_AV_CO_PEER *p_peer;
tBTA_AV_CO_SINK *p_sink;
- APPL_TRACE_EVENT("bta_av_co_cb.codec_cfg.id : codec 0x%x", bta_av_co_cb.codec_cfg.id);
+ APPL_TRACE_EVENT("bta_av_co_cb.codec_cfg->id : codec 0x%x", bta_av_co_cb.codec_cfg->id);
/* Minimum MTU is by default very large */
*p_minmtu = 0xFFFF;
mutex_global_lock();
- if (bta_av_co_cb.codec_cfg.id == BTIF_AV_CODEC_SBC)
+ if (bta_av_co_cb.codec_cfg->id == BTIF_AV_CODEC_SBC)
{
- if (A2D_ParsSbcInfo(p_sbc_config, bta_av_co_cb.codec_cfg.info, FALSE) == A2D_SUCCESS)
+ if (A2D_ParsSbcInfo(p_sbc_config, bta_av_co_cb.codec_cfg->info, FALSE) == A2D_SUCCESS)
{
for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++)
{
p_peer = &bta_av_co_cb.peers[index];
if (p_peer->opened)
{
+ APPL_TRACE_EVENT("%s on index= %d", __func__, index);
if (p_peer->mtu < *p_minmtu)
{
*p_minmtu = p_peer->mtu;
@@ -1697,14 +2565,20 @@
if (p_sink->codec_type == A2D_MEDIA_CT_SBC)
{
/* Update the bitpool boundaries of the current config */
+ APPL_TRACE_EVENT("%s Update the bitpool boundaries on index= %d", __func__, jndex);
p_sbc_config->min_bitpool =
BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
p_sbc_config->min_bitpool);
p_sbc_config->max_bitpool =
BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF],
p_sbc_config->max_bitpool);
- APPL_TRACE_EVENT("bta_av_co_audio_get_sbc_config : sink bitpool min %d, max %d",
- p_sbc_config->min_bitpool, p_sbc_config->max_bitpool);
+ APPL_TRACE_EVENT("%s: actual sink bitpool min %d, max %d", __func__,
+ p_sbc_config->min_bitpool, p_sbc_config->max_bitpool);
+ if(p_sbc_config->min_bitpool > p_sbc_config->max_bitpool) {
+ p_sbc_config->max_bitpool = p_sbc_config->min_bitpool;
+ APPL_TRACE_EVENT("%s: updated sink bitpool min %d, max %d", __func__,
+ p_sbc_config->min_bitpool, p_sbc_config->max_bitpool);
+ }
break;
}
}
@@ -1717,12 +2591,67 @@
if (!result)
{
/* Not SBC, still return the default values */
+ APPL_TRACE_EVENT("%s Not SBC, still return the default values", __func__);
*p_sbc_config = btif_av_sbc_default_config;
}
mutex_global_unlock();
return result;
}
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_get_aac_config
+ **
+ ** Description Retrieves the AAC codec configuration. If the codec in use
+ ** is not AAC, return the default AAC codec configuration.
+ **
+ ** Returns TRUE if codec is AAC, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_get_aac_config(tA2D_AAC_CIE *p_aac_config, UINT16 *p_minmtu)
+{
+ BOOLEAN result = FALSE;
+ UINT8 index;
+ tBTA_AV_CO_PEER *p_peer;
+
+ APPL_TRACE_EVENT("bta_av_co_cb.codec_cfg->id : codec 0x%x", bta_av_co_cb.codec_cfg->id);
+
+ /* Minimum MTU is by default very large */
+ *p_minmtu = 0xFFFF;
+
+ mutex_global_lock();
+ if (bta_av_co_cb.codec_cfg->id == BTIF_AV_CODEC_M24)
+ {
+ if (A2D_ParsAacInfo(p_aac_config, bta_av_co_cb.codec_cfg->info, FALSE) == A2D_SUCCESS)
+ {
+ for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++)
+ {
+ p_peer = &bta_av_co_cb.peers[index];
+ if (p_peer->opened)
+ {
+ APPL_TRACE_EVENT("%s on index= %d", __func__, index);
+ if (p_peer->mtu < *p_minmtu)
+ {
+ *p_minmtu = p_peer->mtu;
+ }
+ }
+ }
+ result = TRUE;
+ }
+ }
+
+ if (!result)
+ {
+ /* Not AAC, still return the default values */
+ APPL_TRACE_EVENT("%s Not SBC, still return the default values", __func__);
+ *p_aac_config = btif_av_aac_default_config;
+ }
+ mutex_global_unlock();
+
+ return result;
+}
+#endif
/*******************************************************************************
**
@@ -1767,7 +2696,7 @@
/* Reset the control block */
memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb));
- bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE;
+ bta_av_co_cb.codec_cfg_setconfig = NULL;
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_NEVER);
@@ -1833,11 +2762,41 @@
BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max)
{
/* check if remote peer did a set config */
- if (bta_av_co_cb.codec_cfg_setconfig.id == BTIF_AV_CODEC_NONE)
+ if (bta_av_co_cb.codec_cfg_setconfig == NULL)
return FALSE;
- *min = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF];
- *max = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF];
+ *min = bta_av_co_cb.codec_cfg_setconfig->info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF];
+ *max = bta_av_co_cb.codec_cfg_setconfig->info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF];
return TRUE;
}
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_is_offload_supported
+**
+** Description This function is called by AV to check if DUT is in offload
+** mode.
+**
+** Returns TRUE if offload is enabled, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_av_co_audio_is_offload_supported(void)
+{
+ return btif_av_is_offload_supported();
+}
+
+/*******************************************************************************
+**
+** Function bta_av_co_audio_is_codec_supported
+**
+** Description This function is called by AV to check if corresponding
+** codec is supported in offload mode.
+**
+** Returns TRUE if codec is supported in offload, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_av_co_audio_is_codec_supported(int codec)
+{
+ return btif_av_is_codec_offload_supported(codec);
+}
diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c
index 55b2f86..5c3b0a3 100644
--- a/btif/co/bta_dm_co.c
+++ b/btif/co/bta_dm_co.c
@@ -30,6 +30,11 @@
#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
#include "bte_appl.h"
+#if (defined BTM_NO_MITM_NO_BONDING_INCLUDED && BTM_NO_MITM_NO_BONDING_INCLUDED == TRUE)
+tBTE_APPL_CFG bte_appl_cfg = { 0x0, 0x4, 0x0, 0x0, 0x10 };
+#elif (defined BTM_NO_MITM_INCLUDED && BTM_NO_MITM_INCLUDED == TRUE)
+tBTE_APPL_CFG bte_appl_cfg = { 0x1, 0x4, 0x7, 0x7, 0x10 };
+#else
tBTE_APPL_CFG bte_appl_cfg =
{
#if SMP_INCLUDED == TRUE
@@ -43,6 +48,7 @@
BTM_BLE_MAX_KEY_SIZE
};
#endif
+#endif
/*******************************************************************************
**
diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c
index c95a19d..344f4ac 100644
--- a/btif/co/bta_hh_co.c
+++ b/btif/co/bta_hh_co.c
@@ -35,6 +35,8 @@
#include "bta_hh_co.h"
#include "btif_hh.h"
#include "btif_util.h"
+#include "btcore/include/bdaddr.h"
+#include "device/include/interop.h"
const char *dev_path = "/dev/uhid";
@@ -44,6 +46,94 @@
static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
#endif
+#define REPORT_DESC_REPORT_ID 0x05
+#define REPORT_DESC_DIGITIZER_PAGE 0x0D
+#define REPORT_DESC_START_COLLECTION 0xA1
+#define REPORT_DESC_END_COLLECTION 0xC0
+
+static void remove_digitizer_descriptor(UINT8 **data, UINT16 *length)
+{
+ UINT8 *startDescPtr = *data;
+ UINT8 *desc = *data;
+
+ /* Parse until complete report descriptor is parsed */
+ while (startDescPtr < *data + *length)
+ {
+ UINT8 item = *startDescPtr++;
+ UINT8 usage_page;
+
+ switch (item) {
+ case REPORT_DESC_REPORT_ID: // Report ID
+ usage_page = *startDescPtr;
+ if (usage_page == REPORT_DESC_DIGITIZER_PAGE)
+ {
+ // digitizer usage page
+ UINT8 *traversePtr = startDescPtr;
+ UINT8 num_of_collections = 0;
+ UINT8 num_of_end_collections = 0;
+ UINT16 remainingBytesToBeCopied = 0;
+ /* increment pointer until digitizer descriptor is parsed
+ * completely or start collection matches end collection */
+ while ((num_of_collections == 0 || (num_of_collections !=
+ num_of_end_collections)) && (traversePtr <
+ *data + *length))
+ {
+ if (*traversePtr == REPORT_DESC_START_COLLECTION) {
+ /* Increment number of collections for
+ * digitizer descriptor */
+ num_of_collections++;
+ }
+ if (*traversePtr == REPORT_DESC_END_COLLECTION) {
+ /* Increment number of end collections for
+ * digitizer descriptor */
+ num_of_end_collections++;
+ }
+ /* increment the pointer to continue parsing
+ * the digitizer descriptor */
+ UNUSED(*traversePtr++);
+ }
+ remainingBytesToBeCopied = *length - (traversePtr - *data);
+ BTIF_TRACE_DEBUG("starting point of digitizer desc = %d\n",
+ (startDescPtr - *data) - 1);
+ BTIF_TRACE_DEBUG("start collection = %d, end collection = "
+ " %d\n", num_of_collections, num_of_end_collections);
+ BTIF_TRACE_DEBUG("end point of digitizer desc = %d\n",
+ (traversePtr - *data));
+ BTIF_TRACE_DEBUG("length of digitizer desc = %d\n",
+ traversePtr - startDescPtr + 2);
+ BTIF_TRACE_DEBUG("bytes remaining to be copied = %d\n",
+ remainingBytesToBeCopied);
+ if (remainingBytesToBeCopied)
+ {
+ UINT32 i;
+ UINT8 *newDescPtr = traversePtr;
+ UINT32 digDescStartPoint = (startDescPtr - *data) - 1;
+ UINT32 digDescEndPoint = *length -
+ (traversePtr - startDescPtr) - 1;
+ /* copy the remaining bytes in descriptor to the
+ * existing place of digitizer descriptor */
+ for (i = digDescStartPoint; i < digDescEndPoint; i ++) {
+ desc[i] = *newDescPtr++;
+ }
+ }
+ /* update the length as digitizer descriptor is removed */
+ *length = *length - (traversePtr - startDescPtr) - 1;
+ BTIF_TRACE_DEBUG("new length of report desc = %d\n",
+ *length);
+ /* Update the start descriptor again to continue parsing
+ * for digitizer records assuming more than 1 digitizer
+ * record exists in report descriptor */
+ startDescPtr --;
+ }
+ break;
+
+ default:
+ startDescPtr += (item & 0x03);
+ break;
+ }
+ }
+}
+
void uhid_set_non_blocking(int fd)
{
int opts = fcntl(fd, F_GETFL);
@@ -56,6 +146,19 @@
APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__, strerror(errno));
}
+static void lst_free_cb (void * rpt_id)
+{
+ UINT32 *p_rpt_id = (UINT32 *)rpt_id;
+
+ if (rpt_id == NULL)
+ return;
+
+ APPL_TRACE_DEBUG("%s: freeing report id %d",
+ __func__, (int)*p_rpt_id);
+ free(rpt_id);
+ rpt_id = NULL;
+}
+
/*Internal function to perform UHID write and error checking*/
static int uhid_write(int fd, const struct uhid_event *ev)
{
@@ -84,15 +187,24 @@
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
+ if(!p_dev)
+ {
+ APPL_TRACE_ERROR("%s: Device not found", __func__)
+ return -1;
+ }
+
ssize_t ret;
+
+ APPL_TRACE_DEBUG("%s: reading", __func__);
OSI_NO_INTR(ret = read(p_dev->fd, &ev, sizeof(ev)));
+ APPL_TRACE_DEBUG("%s: read %d bytes", __func__, ret);
if (ret == 0) {
- APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
+ APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __func__,
strerror(errno));
return -EFAULT;
} else if (ret < 0) {
- APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __FUNCTION__,
+ APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __func__,
strerror(errno));
return -errno;
} else if ((ev.type == UHID_OUTPUT) || (ev.type==UHID_OUTPUT_EV)) {
@@ -100,11 +212,12 @@
// ensure we read full event descriptor
if (ret < (ssize_t)sizeof(ev)) {
APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %ld != %lu",
- __FUNCTION__, ret, sizeof(ev.type));
+ __func__, ret, sizeof(ev.type));
return -EFAULT;
}
}
+ APPL_TRACE_DEBUG("%s: received event = %d", __func__, ev.type);
switch (ev.type) {
case UHID_START:
APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
@@ -125,7 +238,7 @@
case UHID_OUTPUT:
if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
- __FUNCTION__, ret,
+ __func__, ret,
sizeof(ev.type) + sizeof(ev.u.output));
return -EFAULT;
}
@@ -137,20 +250,81 @@
btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
ev.u.output.size, ev.u.output.data);
else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
+ {
+ if (ev.u.output.size == BTIF_HH_OUTPUT_REPORT_SIZE &&
+ !memcmp(&p_dev->last_output_rpt_data, &ev.u.output.data,
+ BTIF_HH_OUTPUT_REPORT_SIZE)) {
+ /* Last output report same as current output report, don't inform to remote
+ * device as this could be the case when reports are being sent due to
+ * device suspend/resume. If same output report is sent to remote device
+ * device which uses UART as transport might not be able to suspend at all
+ * leading to higher battery drain.
+ */
+ APPL_TRACE_VERBOSE("UHID_OUTPUT: data same returning");
+ return 0;
+ }
+ /* Copy new output report data for future tracking */
+ memcpy(&p_dev->last_output_rpt_data, &ev.u.output.data, ev.u.output.size);
btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
ev.u.output.size, ev.u.output.data);
+ }
else
btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
ev.u.output.size, ev.u.output.data);
- break;
+ break;
case UHID_OUTPUT_EV:
APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
break;
- case UHID_FEATURE:
- APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
+ case UHID_SET_REPORT:
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.set_report))) {
+ APPL_TRACE_ERROR("%s: UHID_SET_REPORT: Invalid size read from "
+ "uhid-dev: %zd < %zu", __func__, ret,
+ sizeof(ev.type) + sizeof(ev.u.set_report));
+ return -EFAULT;
+ }
+ APPL_TRACE_DEBUG("UHID_SET_REPORT: Report type = %d, report_size = %d"
+ ,ev.u.set_report.rtype, ev.u.set_report.size);
+ UINT32 *p_set_rpt_id = (UINT32 *)malloc(sizeof(UINT32));
+ if (!p_set_rpt_id) {
+ APPL_TRACE_ERROR("%s unable to allocate p_set_rpt_id", __func__);
+ return -ENOMEM;
+ }
+ *p_set_rpt_id = ev.u.set_report.id;
+ if (p_dev->set_rpt_id_list) {
+ if (!list_append(p_dev->set_rpt_id_list, (void *)p_set_rpt_id)) {
+ APPL_TRACE_ERROR("%s: list_append failed", __func__)
+ return -EFAULT;
+ }
+ }
+ if (ev.u.set_report.rtype == UHID_FEATURE_REPORT)
+ btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else if (ev.u.set_report.rtype == UHID_OUTPUT_REPORT)
+ btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else
+ btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
break;
- case UHID_FEATURE_ANSWER:
- APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
+ case UHID_GET_REPORT:
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.get_report))) {
+ APPL_TRACE_ERROR("%s: UHID_GET_REPORT: Invalid size read from "
+ "uhid-dev: %zd < %zu", __func__, ret,
+ sizeof(ev.type) + sizeof(ev.u.get_report));
+ return -EFAULT;
+ }
+ APPL_TRACE_DEBUG("UHID_GET_REPORT: Report type = %d",
+ ev.u.get_report.rtype);
+ p_dev->get_rpt_snt++;
+ if (ev.u.get_report.rtype == UHID_FEATURE_REPORT)
+ btif_hh_getreport(p_dev, BTHH_FEATURE_REPORT,
+ ev.u.get_report.rnum, 0);
+ else if (ev.u.get_report.rtype == UHID_OUTPUT_REPORT)
+ btif_hh_getreport(p_dev, BTHH_OUTPUT_REPORT,
+ ev.u.get_report.rnum, 0);
+ else
+ btif_hh_getreport(p_dev, BTHH_INPUT_REPORT,
+ ev.u.get_report.rnum, 0);
break;
default:
@@ -282,7 +456,7 @@
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...",
- __FUNCTION__, dev_handle);
+ __func__, dev_handle);
return;
}
@@ -292,22 +466,22 @@
p_dev->dev_handle == dev_handle) {
// We found a device with the same handle. Must be a device reconnected.
APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
- "dev_status = %d",__FUNCTION__,
+ "dev_status = %d",__func__,
p_dev->dev_status);
- APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
+ APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __func__,
p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
APPL_TRACE_WARNING("%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
- __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
+ __func__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
if(p_dev->fd<0) {
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
- __FUNCTION__,strerror(errno));
+ __func__,strerror(errno));
return;
}else
- APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
}
p_dev->hh_keep_polling = 1;
@@ -333,10 +507,10 @@
p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
- __FUNCTION__,strerror(errno));
+ __func__,strerror(errno));
return;
}else{
- APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
p_dev->hh_keep_polling = 1;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
}
@@ -348,12 +522,18 @@
}
if (p_dev == NULL) {
- APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __FUNCTION__);
+ APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
return;
}
p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
- APPL_TRACE_DEBUG("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
+ APPL_TRACE_DEBUG("%s: allocating the set_rpt_id_list", __func__);
+ memset(&p_dev->last_output_rpt_data, 0, BTIF_HH_OUTPUT_REPORT_SIZE);
+ p_dev->set_rpt_id_list = list_new(lst_free_cb);
+ if (!p_dev->set_rpt_id_list) {
+ APPL_TRACE_ERROR("%s: unable to create list", __func__);
+ }
+ APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
}
@@ -374,19 +554,25 @@
UINT32 i;
btif_hh_device_t *p_dev = NULL;
- APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __FUNCTION__, dev_handle, app_id);
+ APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle, app_id);
if (dev_handle == BTA_HH_INVALID_HANDLE) {
- APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
+ APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTIF_HH_MAX_HID; i++) {
p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->set_rpt_id_list && list_length(p_dev->set_rpt_id_list)) {
+ APPL_TRACE_DEBUG("%s: freeing the set_rpt_id_list", __func__);
+ list_free(p_dev->set_rpt_id_list);
+ p_dev->set_rpt_id_list = NULL;
+ }
if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
"dev_status = %d, dev_handle =%d"
- ,__FUNCTION__,p_dev->dev_status
+ ,__func__,p_dev->dev_status
,p_dev->dev_handle);
+ memset(&p_dev->last_output_rpt_data, 0, BTIF_HH_OUTPUT_REPORT_SIZE);
btif_hh_close_poll_thread(p_dev);
break;
}
@@ -435,7 +621,6 @@
}
}
-
/*******************************************************************************
**
** Function bta_hh_co_send_hid_info
@@ -467,6 +652,11 @@
vendor_id, product_id,
version, ctry_code);
+ if (interop_match_vendor_product_ids(INTEROP_REMOVE_HID_DIG_DESCRIPTOR,
+ vendor_id, product_id) ||
+ interop_match_name(INTEROP_REMOVE_HID_DIG_DESCRIPTOR, dev_name))
+ remove_digitizer_descriptor(&p_dscp, (UINT16 *)&dscp_len);
+
//Create and send hid descriptor to kernel
memset(&ev, 0, sizeof(ev));
ev.type = UHID_CREATE;
@@ -483,7 +673,11 @@
ev.u.create.product = product_id;
ev.u.create.version = version;
ev.u.create.country = ctry_code;
+ // block write to uhid driver until create completes
+ p_dev->ready_for_data = FALSE;
result = uhid_write(p_dev->fd, &ev);
+ // unblock write to uhid driver now
+ p_dev->ready_for_data = TRUE;
APPL_TRACE_WARNING("%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
p_dev->fd, dscp_len, result);
@@ -497,6 +691,90 @@
}
}
+/*******************************************************************************
+**
+** Function bta_hh_co_set_rpt_rsp
+**
+** Description This callout function is executed by HH when Set Report Response is received
+** on Control Channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_hh_co_set_rpt_rsp(UINT8 dev_handle, UINT8 status)
+{
+ struct uhid_event ev;
+ btif_hh_device_t *p_dev;
+
+ APPL_TRACE_VERBOSE("%s: dev_handle = %d", __func__, dev_handle);
+
+ p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
+ if (p_dev == NULL) {
+ APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__, dev_handle);
+ return;
+ }
+ // Send the HID report to the kernel.
+ if (p_dev->fd >= 0 && p_dev->set_rpt_id_list &&
+ list_length(p_dev->set_rpt_id_list)) {
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_SET_REPORT_REPLY;
+ /* get the report id from start of list */
+ UINT32 *set_report_reply_id = list_front(p_dev->set_rpt_id_list);
+ if (set_report_reply_id) {
+ ev.u.set_report_reply.id = *set_report_reply_id;
+ APPL_TRACE_VERBOSE("%s: set_report_reply_id = %d",
+ __func__, *(set_report_reply_id));
+ /* remove the entry from list now */
+ if (!list_remove(p_dev->set_rpt_id_list, set_report_reply_id)) {
+ APPL_TRACE_ERROR("%s: unable to remove set_report_reply_id = %d",
+ __func__, *(set_report_reply_id));
+ }
+ }
+ ev.u.set_report_reply.err = status;
+ uhid_write(p_dev->fd, &ev);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_co_get_rpt_rsp
+**
+** Description This callout function is executed by HH when Get Report Response is received
+** on Control Channel.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_hh_co_get_rpt_rsp(UINT8 dev_handle, UINT8 status, UINT8 *p_rpt, UINT16 len)
+{
+ struct uhid_event ev;
+ btif_hh_device_t *p_dev;
+
+ APPL_TRACE_VERBOSE("%s: dev_handle = %d", __func__, dev_handle);
+
+ p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
+ if (p_dev == NULL) {
+ APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__, dev_handle);
+ return;
+ }
+ // Send the HID report to the kernel.
+ if (p_dev->fd >= 0 && p_dev->get_rpt_snt--) {
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_GET_REPORT_REPLY;
+ ev.u.get_report_reply.err = status;
+ ev.u.get_report_reply.size = len;
+ if (len > 0) {
+ if (len > UHID_DATA_MAX) {
+ APPL_TRACE_WARNING("%s: Report size greater than allowed size",
+ __func__);
+ return;
+ }
+ memcpy(ev.u.get_report_reply.data, p_rpt, len);
+ }
+ uhid_write(p_dev->fd, &ev);
+ }
+}
+
#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
/*******************************************************************************
**
@@ -568,7 +846,7 @@
remote_bda[3], remote_bda[4], remote_bda[5]);
size_t len = btif_config_get_bin_length(bdstr, "HidReport");
- if (!p_num_rpt && len < sizeof(tBTA_HH_RPT_CACHE_ENTRY))
+ if (!p_num_rpt || len < sizeof(tBTA_HH_RPT_CACHE_ENTRY))
return NULL;
if (len > sizeof(sReportCache))
diff --git a/btif/co/bta_hl_co.c b/btif/co/bta_hl_co.c
index e76d078..fbfb7df 100644
--- a/btif/co/bta_hl_co.c
+++ b/btif/co/bta_hl_co.c
@@ -332,7 +332,7 @@
{
p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
- if (p_dcb->tx_size <= buf_size )
+ if ((p_dcb->tx_size <= buf_size) && p_dcb->p_tx_pkt)
{
memcpy(p_buf, p_dcb->p_tx_pkt, p_dcb->tx_size);
osi_free_and_reset((void **)&p_dcb->p_tx_pkt);
@@ -341,7 +341,7 @@
}
}
-
+ BTIF_TRACE_WARNING("%s status = %d ", __FUNCTION__, status);
bta_hl_ci_get_tx_data(mdl_handle, status, evt);
}
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
index 355f188..14e16cb 100644
--- a/btif/include/btif_api.h
+++ b/btif/include/btif_api.h
@@ -379,6 +379,17 @@
/*******************************************************************************
**
+** Function btif_hci_cmd_send
+**
+** Description Sends a HCI Raw command to the controller
+**
+** Returns BT_STATUS_SUCCESS on success
+**
+*******************************************************************************/
+bt_status_t btif_hci_cmd_send(uint16_t opcode, uint8_t *buf, uint8_t len);
+
+/*******************************************************************************
+**
** Function btif_le_test_mode
**
** Description Sends a HCI BLE Test command to the Controller
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
index 1fc7cfe..8e2de02 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -32,6 +32,7 @@
#include "btif_sm.h"
#include "bta_av_api.h"
+#define BTIF_RC_HANDLE_NONE 0xFF
/*******************************************************************************
** Type definitions for callback functions
@@ -48,6 +49,11 @@
BTIF_AV_OFFLOAD_START_REQ_EVT,
BTIF_AV_SINK_FOCUS_REQ_EVT,
BTIF_AV_CLEANUP_REQ_EVT,
+ BTIF_AV_UPDATE_ENCODER_REQ_EVT,
+ BTIF_AV_REMOTE_SUSPEND_STREAM_REQ_EVT,
+ BTIF_AV_RESET_REMOTE_STARTED_FLAG_EVT,
+ BTIF_AV_RESET_REMOTE_STARTED_FLAG_UPDATE_AUDIO_STATE_EVT,
+ BTIF_AV_INIT_REQ_EVT,
} btif_av_sm_event_t;
@@ -77,7 +83,7 @@
**
*******************************************************************************/
-bt_bdaddr_t btif_av_get_addr(void);
+bt_bdaddr_t btif_av_get_addr(BD_ADDR address);
/*******************************************************************************
** Function btif_av_is_sink_enabled
@@ -204,6 +210,18 @@
/*******************************************************************************
**
+** Function btif_av_any_br_peer
+**
+** Description Check if the any of connected devices is BR device.
+**
+** Returns TRUE if connected to any BR device, FALSE otherwise.
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_any_br_peer(void);
+
+/*******************************************************************************
+**
** Function btif_av_peer_supports_3mbps
**
** Description Check if the connected A2DP device supports
@@ -215,4 +233,74 @@
*******************************************************************************/
BOOLEAN btif_av_peer_supports_3mbps(void);
+/*******************************************************************************
+**
+** Function btif_av_check_flag_remote_suspend
+**
+** Description Check whether remote suspend flag is set or not
+**
+** Returns TRUE if remote suspen flag set
+**
+*******************************************************************************/
+BOOLEAN btif_av_check_flag_remote_suspend(int index);
+
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/******************************************************************************
+**
+** Function btif_av_get_streaming_channel_id
+**
+** Description Returns streaming channel id
+**
+** Returns channel id
+********************************************************************************/
+UINT16 btif_av_get_streaming_channel_id(void);
+
+/******************************************************************************
+**
+** Function btif_av_get_peer_addr
+**
+** Description Returns peer device address
+**
+** Returns peer address
+********************************************************************************/
+void btif_av_get_peer_addr(bt_bdaddr_t *peer_bda);
+
+/*******************************************************************************
+**
+** Function btif_av_get_current_playing_dev_idx
+**
+** Description Returns the current playing device index.
+**
+** Returns index.
+**
+*******************************************************************************/
+int btif_av_get_current_playing_dev_idx();
+#else
+#define btif_av_get_streaming_channel_id() (0)
+#define btif_av_get_peer_addr(peer_bda) (0)
+#define btif_av_get_current_playing_dev_idx() (0)
+#endif
+
+/*******************************************************************************
+**
+** Function btif_av_get_multicast_state
+**
+** Description Check if A2DP multicast is enabled
+**
+** Returns TRUE if a2dp multicast is enabled
+**
+*******************************************************************************/
+BOOLEAN btif_av_get_multicast_state();
+
+/*******************************************************************************
+**
+** Function btif_av_is_multicast_supported
+**
+** Description Check if A2DP multicast is supported
+**
+** Returns TRUE if a2dp multicast is supported
+**
+*******************************************************************************/
+BOOLEAN btif_av_is_multicast_supported();
+
#endif /* BTIF_AV_H */
diff --git a/btif/include/btif_av_api.h b/btif/include/btif_av_api.h
index 86cd40b..857fed2 100644
--- a/btif/include/btif_av_api.h
+++ b/btif/include/btif_av_api.h
@@ -1,4 +1,10 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
+/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
@@ -43,9 +49,9 @@
*****************************************************************************/
/* Codec type */
-#define BTIF_AV_CODEC_NONE 0xFF
+#define BTIF_AV_CODEC_NONE 0xF1
#define BTIF_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */
-
+#define BTIF_AV_CODEC_M24 A2D_MEDIA_CT_M24 /* AAC media codec type */
#define BTIF_AV_CODEC_PCM 0x5 /* Raw PCM */
typedef UINT8 tBTIF_AV_CODEC_ID;
diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h
index a6a5bfa..a60749a 100644
--- a/btif/include/btif_av_co.h
+++ b/btif/include/btif_av_co.h
@@ -1,4 +1,10 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
+/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
@@ -24,15 +30,6 @@
/*******************************************************************************
** Constants & Macros
********************************************************************************/
-
-enum
-{
- BTIF_SV_AV_AA_SBC_INDEX = 0,
- BTIF_SV_AV_AA_SBC_SINK_INDEX,
- BTIF_SV_AV_AA_SEP_INDEX /* Last index */
-};
-
-
/*******************************************************************************
** Functions
********************************************************************************/
@@ -114,6 +111,39 @@
/*******************************************************************************
**
+ ** Function bta_av_co_get_current_codec
+ **
+ ** Description Get the current codec type.
+ **
+ ** Returns Codec Type Value
+ **
+ *******************************************************************************/
+UINT8 bta_av_co_get_current_codec();
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_get_current_codecInfo
+ **
+ ** Description Get the current codec Info.
+ **
+ ** Returns Returns pointer to Info
+ **
+ *******************************************************************************/
+UINT8* bta_av_co_get_current_codecInfo();
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_get_codec_config
+ **
+ ** Description Retrieves the current codec configuration. On Failure return the default
+ ** codec configuration.
+ **
+ ** Returns TRUE if codec is SBC, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_get_codec_config(UINT8 *p_sbc_config, UINT16 *p_minmtu, UINT8 type);
+/*******************************************************************************
+ **
** Function bta_av_co_audio_get_sbc_config
**
** Description Retrieves the SBC codec configuration. If the codec in use
@@ -123,6 +153,20 @@
**
*******************************************************************************/
BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu);
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_get_aac_config
+ **
+ ** Description Retrieves the AAC codec configuration. If the codec in use
+ ** is not AAC, return the default SBC codec configuration.
+ **
+ ** Returns TRUE if codec is AAC, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_get_aac_config(tA2D_AAC_CIE *p_aac_config, UINT16 *p_minmtu);
+#endif
+
/*******************************************************************************
**
@@ -171,4 +215,28 @@
*******************************************************************************/
BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max);
+/*******************************************************************************
+ **
+ ** Function bta_av_select_codec
+ **
+ ** Description Select the current codec for the remote device selected
+ ** for streaming.
+ **
+ ** Returns Return current codec id
+ **
+ *******************************************************************************/
+UINT8 bta_av_select_codec(tBTA_AV_HNDL hdl);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_is_aac_enabled
+ **
+ ** Description Compares the given BD address family against the interop databse
+ ** and return if AAC can be selected as a codec for streaming or not
+ **
+ ** Returns TRUE if AAC is allowed , FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_is_aac_enabled(bt_bdaddr_t *remote_bdaddr);
+
#endif
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
index b48631b..83ab28e 100644
--- a/btif/include/btif_common.h
+++ b/btif/include/btif_common.h
@@ -34,7 +34,7 @@
********************************************************************************/
#define ASSERTC(cond, msg, val) if (!(cond)) { LOG_ERROR(LOG_TAG, \
- "### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+ "### ASSERT : %s %s line %d %s (%d) ###", __FILE__, __func__, __LINE__, msg, val);}
/* Calculate start of event enumeration; id is top 8 bits of event */
#define BTIF_SIG_START(id) ((id) << 8)
@@ -125,7 +125,9 @@
BTIF_DM_CB_HID_REMOTE_NAME, /* Remote name callback for HID device */
BTIF_DM_CB_BOND_STATE_BONDING,
BTIF_DM_CB_LE_TX_TEST, /* BLE Tx Test command complete callback */
+ BTIF_DM_CB_LE_ENH_TX_TEST, /* BLE Enh Tx Test command complete callback */
BTIF_DM_CB_LE_RX_TEST, /* BLE Rx Test command complete callback */
+ BTIF_DM_CB_LE_ENH_RX_TEST, /* BLE Enh Rx Test command complete callback */
BTIF_DM_CB_LE_TEST_END, /* BLE Test mode end callback */
BTIF_HFP_CB_START = BTIF_SIG_CB_START(BTIF_HFP),
@@ -138,6 +140,19 @@
BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, /* AUDIO connect has been sent to BTA successfully */
};
+/*
+ * Logger preference, based on which the Bluetooth logging is
+ * enabled.
+ */
+#ifdef BLUEDROID_DEBUG
+typedef enum {
+ CONFIG_PREFERENCE_FALSE = 0,
+ CONFIG_PREFERENCE_TRUE,
+ DEV_OPT_PREFERENCE,
+ NO_PREFERENCE,
+} logging_preference_t;
+#endif
+
/* Macro definitions for BD ADDR persistence */
/**
@@ -216,4 +231,6 @@
void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param);
+void btif_ssr_cleanup(void);
+
#endif /* BTIF_COMMON_H */
diff --git a/btif/include/btif_gatt_multi_adv_util.h b/btif/include/btif_gatt_multi_adv_util.h
index ac8351c..b009875 100644
--- a/btif/include/btif_gatt_multi_adv_util.h
+++ b/btif/include/btif_gatt_multi_adv_util.h
@@ -47,6 +47,7 @@
uint8_t* p_service_data;
uint16_t service_uuid_len;
uint8_t* p_service_uuid;
+ uint8_t frag_preference;
} btif_adv_data_t;
@@ -58,7 +59,8 @@
tBTA_BLE_ADV_PARAMS param;
alarm_t *multi_adv_timer;
int timeout_s;
-} btgatt_multi_adv_inst_cb;
+ UINT8 frag_preference;
+}btgatt_multi_adv_inst_cb;
typedef struct
{
diff --git a/btif/include/btif_gatt_util.h b/btif/include/btif_gatt_util.h
index 715e0c5..1dff7cf 100644
--- a/btif/include/btif_gatt_util.h
+++ b/btif/include/btif_gatt_util.h
@@ -26,7 +26,7 @@
void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src);
void btif_to_bta_response(tBTA_GATTS_RSP *p_dest, btgatt_response_t* p_src);
-void btif_to_bta_uuid_mask(tBTA_DM_BLE_PF_COND_MASK *p_mask, bt_uuid_t *p_src);
+void btif_to_bta_uuid_mask(tBTA_DM_BLE_PF_COND_MASK *p_mask, bt_uuid_t *p_src, bt_uuid_t *svc_uuid);
void bta_to_btif_uuid(bt_uuid_t *p_dest, tBT_UUID *p_src);
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index cf9731f..b58be36 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -25,20 +25,25 @@
#include <stdint.h>
#include "bta_hh_api.h"
#include "btu.h"
-
+#include "osi/include/list.h"
/*******************************************************************************
** Constants & Macros
********************************************************************************/
+#ifndef MAX_ACL_CONNECTIONS
#define BTIF_HH_MAX_HID 8
+#else
+#define BTIF_HH_MAX_HID MAX_ACL_CONNECTIONS
+#endif
+
#define BTIF_HH_MAX_ADDED_DEV 32
#define BTIF_HH_MAX_KEYSTATES 3
#define BTIF_HH_KEYSTATE_MASK_NUMLOCK 0x01
#define BTIF_HH_KEYSTATE_MASK_CAPSLOCK 0x02
#define BTIF_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
-
+#define BTIF_HH_OUTPUT_REPORT_SIZE 2
/*******************************************************************************
** Type definitions and return values
@@ -68,7 +73,10 @@
pthread_t hh_poll_thread_id;
UINT8 hh_keep_polling;
alarm_t *vup_timer;
+ list_t *set_rpt_id_list; // Owns a collection of set_rpt_id objects.
+ UINT8 get_rpt_snt;
BOOLEAN local_vup; // Indicated locally initiated VUP
+ UINT8 last_output_rpt_data[BTIF_HH_OUTPUT_REPORT_SIZE];
} btif_hh_device_t;
/* Control block to maintain properties of devices */
@@ -106,6 +114,8 @@
extern void btif_hh_disconnect(bt_bdaddr_t *bd_addr);
extern void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type,
UINT16 size, UINT8* report);
+extern void btif_hh_getreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type,
+ UINT8 reportId, UINT16 bufferSize);
BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
diff --git a/btif/include/btif_media.h b/btif/include/btif_media.h
index d432260..3046f60 100644
--- a/btif/include/btif_media.h
+++ b/btif/include/btif_media.h
@@ -1,4 +1,10 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
+/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
@@ -32,7 +38,7 @@
#include "bta_api.h"
#include "bt_common.h"
#include "btif_av_api.h"
-#include "audio_a2dp_hw.h"
+#include "a2d_aac.h"
/*******************************************************************************
** Constants
@@ -54,7 +60,8 @@
/* Transcoding definition for TxTranscoding and RxTranscoding */
#define BTIF_MEDIA_TRSCD_OFF 0
#define BTIF_MEDIA_TRSCD_PCM_2_SBC 1 /* Tx */
-
+#define BTIF_MEDIA_TRSCD_PCM_2_APTX 2
+#define BTIF_MEDIA_TRSCD_PCM_2_APTX_HD 3
/*******************************************************************************
** Data types
@@ -72,6 +79,14 @@
UINT8 NumOfBlocks; /* 4, 8, 12 or 16*/
UINT8 AllocationMethod; /* loudness or SNR*/
UINT16 MtuSize; /* peer mtu size */
+ UINT8 CodecType; /* SBC or Non-A2DP */
+ UINT32 BluetoothVendorID; /* Bluetooth Vendor ID */
+ UINT16 BluetoothCodecID; /* Bluetooth Codec ID */
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ UINT8 ObjectType;
+ UINT32 bit_rate;
+ UINT8 vbr;
+#endif
} tBTIF_MEDIA_INIT_AUDIO;
#if (BTA_AV_INCLUDED == TRUE)
@@ -82,6 +97,9 @@
UINT16 MinMtuSize; /* Minimum peer mtu size */
UINT8 MaxBitPool; /* Maximum peer bitpool */
UINT8 MinBitPool; /* Minimum peer bitpool */
+ UINT8 CodecType; /* SBC or Non-A2DP */
+ UINT32 BluetoothVendorID; /* Bluetooth Vendor ID */
+ UINT16 BluetoothCodecID; /* Bluetooth Codec ID */
} tBTIF_MEDIA_UPDATE_AUDIO;
/* tBTIF_MEDIA_INIT_AUDIO_FEEDING msg structure */
@@ -272,24 +290,37 @@
bool btif_a2dp_start_media_task(void);
void btif_a2dp_stop_media_task(void);
-
+bool btif_a2dp_is_media_task_stopped(void);
void btif_a2dp_on_init(void);
-void btif_a2dp_setup_codec(void);
+tBTIF_STATUS btif_a2dp_setup_codec(tBTA_AV_HNDL hdl);
+void btif_a2dp_update_codec(void);
void btif_a2dp_on_idle(void);
void btif_a2dp_on_open(void);
-BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start);
+BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start, tBTA_AV_HNDL hdl);
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+void btif_media_on_stop_vendor_command();
+void btif_media_send_reset_vendor_state();
+BOOLEAN btif_media_send_vendor_start();
+void btif_media_start_vendor_command();
+#else
+#define btif_media_on_stop_vendor_command() (0)
+#define btif_media_send_reset_vendor_state() (0)
+#define btif_media_send_vendor_start() (0)
+#define btif_media_start_vendor_command() (0)
+#endif
+void btif_a2dp_on_remote_started();
void btif_a2dp_ack_fail(void);
void btif_a2dp_on_stop_req(void);
void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av);
void btif_a2dp_on_suspend(void);
void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av);
+UINT8 btif_a2dp_get_pending_hal_command();
void btif_a2dp_set_tx_flush(BOOLEAN enable);
void btif_a2dp_set_rx_flush(BOOLEAN enable);
void btif_media_check_iop_exceptions(UINT8 *peer_bda);
void btif_reset_decoder(UINT8 *p_av);
void btif_a2dp_on_offload_started(tBTA_AV_STATUS status);
-
int btif_a2dp_get_track_frequency(UINT8 frequency);
int btif_a2dp_get_track_channel_count(UINT8 channeltype);
void btif_a2dp_set_peer_sep(UINT8 sep);
diff --git a/btif/include/btif_sm.h b/btif/include/btif_sm.h
index b4caf9e..b98936b 100644
--- a/btif/include/btif_sm.h
+++ b/btif/include/btif_sm.h
@@ -45,7 +45,7 @@
typedef UINT32 btif_sm_state_t;
typedef UINT32 btif_sm_event_t;
typedef void* btif_sm_handle_t;
-typedef BOOLEAN(*btif_sm_handler_t)(btif_sm_event_t event, void *data);
+typedef BOOLEAN(*btif_sm_handler_t)(btif_sm_event_t event, void *data, int index);
/*****************************************************************************
** Functions
@@ -67,7 +67,7 @@
**
******************************************************************************/
btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers,
- btif_sm_state_t initial_state);
+ btif_sm_state_t initial_state, int index);
/*****************************************************************************
**
diff --git a/btif/include/btif_sock_rfc.h b/btif/include/btif_sock_rfc.h
index 7d93856..f80df3c 100644
--- a/btif/include/btif_sock_rfc.h
+++ b/btif/include/btif_sock_rfc.h
@@ -35,6 +35,10 @@
int* sock_fd, int flags, int app_uid);
bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* uuid,
int channel, int* sock_fd, int flags, int app_uid);
+bt_status_t btsock_rfc_get_sockopt(int channel, btsock_option_type_t option_name,
+ void *option_value, int *option_len);
+bt_status_t btsock_rfc_set_sockopt(int channel, btsock_option_type_t option_name,
+ void *option_value, int option_len);
void btsock_rfc_signaled(int fd, int flags, uint32_t user_id);
#endif
diff --git a/btif/include/btif_sock_sdp.h b/btif/include/btif_sock_sdp.h
index 7353cc9..674c4cd 100644
--- a/btif/include/btif_sock_sdp.h
+++ b/btif/include/btif_sock_sdp.h
@@ -33,6 +33,10 @@
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static const uint8_t UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_FTP[] = {0x00, 0x00, 0x11, 0x06, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_DUN[] = {0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
static inline bool is_uuid_empty(const uint8_t* uuid)
{
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index 5309ce0..a0d04c0 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -138,6 +138,18 @@
/*******************************************************************************
**
+** Function btif_storage_is_device_bonded
+**
+* Description BTIF storage API - checks if device present in bonded list
+**
+** Returns TRUE if the device is bonded,
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_device_bonded(bt_bdaddr_t *remote_bd_addr);
+
+/*******************************************************************************
+**
** Function btif_storage_remove_bonded_device
**
** Description BTIF storage API - Deletes the bonded device from NVRAM
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
index 81964db..a264f32 100644
--- a/btif/src/bluetooth.c
+++ b/btif/src/bluetooth.c
@@ -31,7 +31,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
+#include <cutils/properties.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_av.h>
#include <hardware/bt_gatt.h>
@@ -44,9 +44,15 @@
#include <hardware/bt_rc.h>
#include <hardware/bt_sdp.h>
#include <hardware/bt_sock.h>
+#include <hardware/vendor.h>
+#ifdef WIPOWER_SUPPORTED
+#include <hardware/wipower.h>
+#endif
#include "bt_utils.h"
#include "btif_api.h"
+#include "btif_common.h"
+#include "device/include/controller.h"
#include "btif_debug.h"
#include "btsnoop.h"
#include "btsnoop_mem.h"
@@ -64,6 +70,17 @@
#include "btif/include/btif_debug_conn.h"
#include "btif/include/btif_debug_l2c.h"
#include "btif/include/btif_media.h"
+#include "l2cdefs.h"
+#include "l2c_api.h"
+#include "stack_config.h"
+
+#if TEST_APP_INTERFACE == TRUE
+#include <bt_testapp.h>
+#endif
+
+
+#include <logging.h>
+
/************************************************************************************
** Static variables
@@ -102,9 +119,31 @@
/* avrc target */
extern btrc_interface_t *btif_rc_get_interface();
/* avrc controller */
+#ifdef WIPOWER_SUPPORTED
+extern wipower_interface_t *get_wipower_interface();
+#endif
extern btrc_interface_t *btif_rc_ctrl_get_interface();
/*SDP search client*/
extern btsdp_interface_t *btif_sdp_get_interface();
+/* vendor */
+extern btvendor_interface_t *btif_vendor_get_interface();
+
+extern const btstacklog_interface_t *btif_stack_log_interface(void);
+#if TEST_APP_INTERFACE == TRUE
+extern const btl2cap_interface_t *btif_l2cap_get_interface(void);
+extern const btrfcomm_interface_t *btif_rfcomm_get_interface(void);
+extern const btmcap_interface_t *btif_mcap_get_interface(void);
+extern const btgatt_test_interface_t *btif_gatt_test_get_interface(void);
+extern const btsmp_interface_t *btif_smp_get_interface(void);
+extern const btgap_interface_t *btif_gap_get_interface(void);
+#endif
+
+extern void set_logging_pref(uint16_t pref_val);
+#ifdef BLUEDROID_DEBUG
+extern void enable_bt_logger_debug(bool);
+#else
+extern void enable_bt_logger(bool);
+#endif
/************************************************************************************
** Functions
@@ -164,6 +203,9 @@
static void cleanup(void) {
stack_manager_get_interface()->clean_up_stack();
+
+ if(bt_logger_enabled)
+ property_set("bluetooth.startbtlogger", "false");
}
bool is_restricted_mode() {
@@ -377,6 +419,9 @@
if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
return btif_sock_get_interface();
+ if (is_profile(profile_id, "LOG_ID"))
+ return btif_stack_log_interface();
+
if (is_profile(profile_id, BT_PROFILE_PAN_ID))
return btif_pan_get_interface();
@@ -403,12 +448,49 @@
if (is_profile(profile_id, BT_PROFILE_AV_RC_ID))
return btif_rc_get_interface();
+#ifdef WIPOWER_SUPPORTED
+ if (is_profile(profile_id, BT_PROFILE_WIPOWER_VENDOR_ID))
+ return get_wipower_interface();
+#endif
+
if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
return btif_rc_ctrl_get_interface();
+ if (is_profile(profile_id, BT_PROFILE_VENDOR_ID))
+ return btif_vendor_get_interface();
+
return NULL;
}
+#if TEST_APP_INTERFACE == TRUE
+static const void* get_testapp_interface(int test_app_profile)
+{
+ ALOGI("get_testapp_interface %d", test_app_profile);
+
+ if (interface_ready() == FALSE) {
+ return NULL;
+ }
+ switch(test_app_profile) {
+ case TEST_APP_L2CAP:
+ return btif_l2cap_get_interface();
+ case TEST_APP_RFCOMM:
+ return btif_rfcomm_get_interface();
+ case TEST_APP_MCAP:
+ return btif_mcap_get_interface();
+ case TEST_APP_GATT:
+ return btif_gatt_test_get_interface();
+ case TEST_APP_SMP:
+ return btif_smp_get_interface();
+ case TEST_APP_GAP:
+ return btif_gap_get_interface();
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+#endif //TEST_APP_INTERFACE
+
int dut_mode_configure(uint8_t enable)
{
LOG_INFO(LOG_TAG, "dut_mode_configure");
@@ -431,6 +513,19 @@
return btif_dut_mode_send(opcode, buf, len);
}
+#if HCI_RAW_CMD_INCLUDED == TRUE
+int hci_cmd_send(uint16_t opcode, uint8_t* buf, uint8_t len)
+{
+ ALOGI("hci_cmd_send");
+
+ /* sanity check */
+ if (interface_ready() == FALSE || stack_manager_get_interface()->get_stack_is_running() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_hci_cmd_send(opcode, buf, len);
+}
+#endif
+
#if BLE_INCLUDED == TRUE
int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len)
{
@@ -451,7 +546,15 @@
if (!interface_ready())
return BT_STATUS_NOT_READY;
+#ifdef BLUEDROID_DEBUG
+ enable_bt_logger_debug(enable);
+#else
+ enable_bt_logger(enable);
+#endif
+
btsnoop_get_interface()->set_api_wants_to_log(enable);
+ controller_get_static_interface()->enable_soc_logging(enable);
+
return BT_STATUS_SUCCESS;
}
@@ -491,6 +594,11 @@
get_profile_interface,
dut_mode_configure,
dut_mode_send,
+#if HCI_RAW_CMD_INCLUDED == TRUE
+ hci_cmd_send,
+#else
+ NULL,
+#endif
#if BLE_INCLUDED == TRUE
le_test_mode,
#else
@@ -503,6 +611,11 @@
config_clear,
interop_database_clear,
interop_database_add,
+#if TEST_APP_INTERFACE == TRUE
+ get_testapp_interface,
+#else
+ NULL,
+#endif
};
const bt_interface_t* bluetooth__get_bluetooth_interface ()
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c
old mode 100644
new mode 100755
index f852d48..ee05fa0
--- a/btif/src/btif_av.c
+++ b/btif/src/btif_av.c
@@ -1,4 +1,6 @@
/******************************************************************************
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
@@ -35,6 +37,10 @@
#include "btu.h"
#include "bt_common.h"
#include "osi/include/allocator.h"
+#include <cutils/properties.h>
+#include "device/include/interop.h"
+#include "btif_storage.h"
+#include "audio_a2dp_hw.h"
/*****************************************************************************
** Constants & Macros
@@ -43,6 +49,13 @@
#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink"
#define BTIF_TIMEOUT_AV_OPEN_ON_RC_MS (2 * 1000)
+#define BTIF_TIMEOUT_AV_COLL_DETECTED_MS (2 * 1000)
+
+/* Number of BTIF-AV control blocks */
+/* Now supports Two AV connections. */
+#define BTIF_AV_NUM_CB 2
+#define HANDLE_TO_INDEX(x) ((x & BTA_AV_HNDL_MSK) - 1)
+#define INVALID_INDEX -1
typedef enum {
BTIF_AV_STATE_IDLE = 0x0,
@@ -61,6 +74,11 @@
#define BTIF_AV_FLAG_REMOTE_SUSPEND 0x2
#define BTIF_AV_FLAG_PENDING_START 0x4
#define BTIF_AV_FLAG_PENDING_STOP 0x8
+#define BTIF_AV_FLAG_PENDING_DISCONNECT 0x10
+/* Host role defenitions */
+#define HOST_ROLE_MASTER 0x00
+#define HOST_ROLE_SLAVE 0x01
+#define HOST_ROLE_UNKNOWN 0xff
/*****************************************************************************
** Local type definitions
@@ -74,6 +92,18 @@
UINT8 flags;
tBTA_AV_EDR edr;
UINT8 peer_sep; /* sep type of peer device */
+ UINT8 edr_3mbps;
+ BOOLEAN dual_handoff;
+ BOOLEAN current_playing;
+ btif_sm_state_t state;
+ int service;
+ BOOLEAN is_slave;
+ BOOLEAN is_device_playing;
+ BOOLEAN is_remote_start_received;
+ BOOLEAN is_suspend_for_remote_start;
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ UINT16 channel_id;
+#endif
} btif_av_cb_t;
typedef struct
@@ -89,17 +119,43 @@
bt_bdaddr_t peer_bd;
} btif_av_sink_config_req_t;
+typedef struct
+{
+ BOOLEAN sbc_offload;
+ BOOLEAN aptx_offload;
+ BOOLEAN aac_offload;
+ BOOLEAN aptxhd_offload;
+} btif_av_a2dp_offloaded_codec_cap_t;
+
+typedef enum {
+ SBC,
+ APTX,
+ AAC,
+ APTXHD,
+}btif_av_codec_list;
+
/*****************************************************************************
** Static variables
******************************************************************************/
static btav_callbacks_t *bt_av_src_callbacks = NULL;
static btav_callbacks_t *bt_av_sink_callbacks = NULL;
-static btif_av_cb_t btif_av_cb = {0, {{0}}, 0, 0, 0, 0};
static alarm_t *av_open_on_rc_timer = NULL;
-
+static alarm_t *av_coll_detected_timer = NULL;
+static bt_bdaddr_t retry_bda;
+static int conn_retry_count = 1;
+static btif_av_cb_t btif_av_cb[BTIF_AV_NUM_CB];
+static btif_sm_event_t idle_rc_event;
+static tBTA_AV idle_rc_data;
+int btif_max_av_clients = 1;
+static BOOLEAN enable_multicast = FALSE;
+static BOOLEAN is_multicast_supported = FALSE;
+static BOOLEAN multicast_disabled = FALSE;
+BOOLEAN bt_split_a2dp_enabled = FALSE;
+BOOLEAN reconfig_a2dp = FALSE;
+btif_av_a2dp_offloaded_codec_cap_t btif_av_codec_offload;
/* both interface and media task needs to be ready to alloc incoming request */
#define CHECK_BTAV_INIT() if (((bt_av_src_callbacks == NULL) &&(bt_av_sink_callbacks == NULL)) \
- || (btif_av_cb.sm_handle == NULL))\
+ || (btif_av_cb[0].sm_handle == NULL))\
{\
BTIF_TRACE_WARNING("%s: BTAV not initialized", __FUNCTION__);\
return BT_STATUS_NOT_READY;\
@@ -111,23 +167,40 @@
/* Helper macro to avoid code duplication in the state machine handlers */
#define CHECK_RC_EVENT(e, d) \
- case BTA_AV_RC_OPEN_EVT: \
case BTA_AV_RC_CLOSE_EVT: \
case BTA_AV_REMOTE_CMD_EVT: \
case BTA_AV_VENDOR_CMD_EVT: \
case BTA_AV_META_MSG_EVT: \
+ case BTA_AV_BROWSE_MSG_EVT: \
case BTA_AV_RC_FEAT_EVT: \
case BTA_AV_REMOTE_RSP_EVT: \
{ \
btif_rc_handler(e, d);\
}break; \
-static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data);
-static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *data);
+static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data, int index);
+static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data, int index);
+static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data, int index);
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data,int index);
+
+static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *data,int index);
+
+static BOOLEAN btif_av_get_valid_idx(int idx);
+UINT8 btif_av_idx_by_bdaddr( BD_ADDR bd_addr);
+int btif_get_latest_playing_device_idx();
+static int btif_get_latest_device_idx_to_start();
+static int btif_av_get_valid_idx_for_rc_events(BD_ADDR bd_addr, int rc_handle);
+static int btif_get_conn_state_of_device(BD_ADDR address);
+static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid);
+static void btif_av_update_current_playing_device(int index);
+static void btif_av_check_rc_connection_priority(void *p_data);
+static int btif_get_is_remote_started_idx();
+static void btif_av_reset_remote_started_flag();
+
+#ifdef AVK_BACKPORT
+void btif_av_request_audio_focus( BOOLEAN enable);
+#endif
static const btif_sm_handler_t btif_av_state_handlers[] =
{
btif_av_state_idle_handler,
@@ -144,14 +217,46 @@
*************************************************************************/
extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
-extern UINT8 btif_rc_get_connected_peer_handle(void);
+extern UINT8 btif_rc_get_connected_peer_handle(BD_ADDR peer_addr);
extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp);
+extern void btif_rc_get_playing_device(BD_ADDR address);
+extern void btif_rc_clear_playing_state(BOOLEAN play);
+extern void btif_rc_clear_priority(BD_ADDR address);
+extern void btif_rc_send_pause_command();
+extern UINT16 btif_dm_get_br_edr_links();
+extern UINT16 btif_dm_get_le_links();
+extern UINT16 btif_hf_is_call_vr_idle();
+extern void btif_media_on_cancel_remote_start_alarm();
extern fixed_queue_t *btu_general_alarm_queue;
/*****************************************************************************
** Local helper functions
******************************************************************************/
+void btif_av_trigger_dual_handoff(BOOLEAN handoff, BD_ADDR address);
+BOOLEAN btif_av_is_device_connected(BD_ADDR address);
+
+BOOLEAN btif_av_is_connected_on_other_idx(int current_index);
+BOOLEAN btif_av_is_playing_on_other_idx(int current_index);
+BOOLEAN btif_av_is_playing();
+void btif_av_update_multicast_state(int index);
+BOOLEAN btif_av_get_ongoing_multicast();
+tBTA_AV_HNDL btif_av_get_playing_device_hdl();
+tBTA_AV_HNDL btif_av_get_av_hdl_from_idx(UINT8 idx);
+int btif_av_get_other_connected_idx(int current_index);
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+BOOLEAN btif_av_is_codec_offload_supported(int codec);
+BOOLEAN btif_av_is_under_handoff();
+void btif_av_reset_reconfig_flag();
+BOOLEAN btif_av_is_device_disconnecting();
+BOOLEAN btif_av_is_suspend_stop_pending_ack();
+#else
+#define btif_av_is_codec_offload_supported(codec) (0)
+#define btif_av_is_under_handoff() (0)
+#define btif_av_reset_reconfig_flag() (0)
+#define btif_av_is_device_disconnecting() (0)
+#define btif_av_is_suspend_stop_pending_ack() (0)
+#endif
const char *dump_av_sm_state_name(btif_av_state_t state)
{
@@ -198,15 +303,31 @@
CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT)
CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT)
CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_REMOTE_SUSPEND_STREAM_REQ_EVT)
CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT)
CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
#ifdef USE_AUDIO_TRACK
CASE_RETURN_STR(BTIF_AV_SINK_FOCUS_REQ_EVT)
#endif
+ CASE_RETURN_STR(BTIF_AV_UPDATE_ENCODER_REQ_EVT)
default: return "UNKNOWN_EVENT";
}
}
+const char *dump_av_codec_name(btif_av_codec_list codec)
+{
+ switch((int)codec)
+ {
+ CASE_RETURN_STR(SBC)
+ CASE_RETURN_STR(APTX)
+ CASE_RETURN_STR(AAC)
+ CASE_RETURN_STR(APTXHD)
+ default: return "UNKNOWN_CODEC";
+ }
+}
+//TODO.. We will remove this data structure
+static BD_ADDR bd_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
/****************************************************************************
** Local helper functions
*****************************************************************************/
@@ -224,25 +345,49 @@
static void btif_initiate_av_open_timer_timeout(UNUSED_ATTR void *data)
{
BD_ADDR peer_addr;
- btif_av_connect_req_t connect_req;
/* is there at least one RC connection - There should be */
- if (btif_rc_get_connected_peer(peer_addr)) {
- BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
- /* In case of AVRCP connection request, we will initiate SRC connection */
- connect_req.target_bda = (bt_bdaddr_t*)&peer_addr;
- if(bt_av_sink_callbacks != NULL)
- connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
- else if(bt_av_src_callbacks != NULL)
- connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
- btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
+ /*We have Two Connections.*/
+ if (btif_rc_get_connected_peer(peer_addr))
+ {
+ /*Check if this peer_addr is same as currently connected AV*/
+ if (btif_get_conn_state_of_device(peer_addr) == BTIF_AV_STATE_OPENED)
+ {
+ BTIF_TRACE_DEBUG("AV is already connected");
+ }
+ else
+ {
+ UINT8 rc_handle;
+ int index;
+ /* Multicast: Check if AV slot is available for connection
+ * If not available, AV got connected to different devices.
+ * Disconnect this RC connection without AV connection.
+ */
+ rc_handle = btif_rc_get_connected_peer_handle(peer_addr);
+ index = btif_av_get_valid_idx_for_rc_events(peer_addr, rc_handle);
+ if(index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("%s No slot free for AV connection, back off",
+ __FUNCTION__);
+ return;
+ }
+ BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
+ if(bt_av_sink_callbacks != NULL)
+ btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, (bt_bdaddr_t*)&peer_addr,
+ connect_int);
+ if(bt_av_src_callbacks != NULL)
+ btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, (bt_bdaddr_t*)&peer_addr,
+ connect_int);
+ }
}
else
{
BTIF_TRACE_ERROR("%s No connected RC peers", __FUNCTION__);
}
+
}
+
/*****************************************************************************
** Static functions
******************************************************************************/
@@ -261,7 +406,7 @@
{
if (bt_av_sink_callbacks != NULL) {
HAL_CBACK(bt_av_sink_callbacks, connection_state_cb, state, bd_addr);
- } else if (bt_av_src_callbacks != NULL) {
+ } else if ( bt_av_src_callbacks != NULL) {
HAL_CBACK(bt_av_src_callbacks, connection_state_cb, state, bd_addr);
}
}
@@ -288,6 +433,90 @@
}
}
+static void btif_av_collission_timer_timeout(UNUSED_ATTR void *data)
+{
+ bt_bdaddr_t *target_bda = &retry_bda;
+ btif_sm_state_t av_state;
+ BD_ADDR av_address;
+
+ bdcpy(av_address, target_bda->address);
+ av_state = btif_get_conn_state_of_device(av_address);
+ BTIF_TRACE_IMP("btif_av_collission_timer_timeout: AV state: %d", av_state);
+ BTIF_TRACE_IMP("TARGET BD ADDRESS %x:%x:%x:%x:%x:%x", av_address[0],
+ av_address[1], av_address[2], av_address[3], av_address[4], av_address[5]);
+
+ if (av_state == BTIF_AV_STATE_IDLE && conn_retry_count <= 1)
+ {
+ if (bt_av_src_callbacks != NULL)
+ {
+ BTIF_TRACE_IMP("%s Starting A2dp connection", __FUNCTION__);
+ conn_retry_count++;
+ btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, target_bda, connect_int);
+ }
+ else
+ {
+ BTIF_TRACE_IMP("%s Aborting A2dp connection retry", __FUNCTION__);
+ }
+ }
+ else if (btif_rc_get_connected_peer_handle(av_address) == BTIF_RC_HANDLE_NONE
+ && conn_retry_count <= 1)
+ {
+ tBTA_AV_HNDL handle;
+ UINT8 idx = btif_av_idx_by_bdaddr(av_address);
+ if (idx == btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid handle",__func__);
+ handle = (tBTA_AV_HNDL)INVALID_INDEX;
+ }
+ else
+ {
+ handle = btif_av_cb[idx].bta_handle;
+ }
+ BTIF_TRACE_IMP("%s Starting Avrcp connection for handle: %d", __FUNCTION__, handle);
+ if ((handle != (tBTA_AV_HNDL)INVALID_INDEX) && (bt_av_src_callbacks != NULL))
+ {
+ BTA_AvOpenRc(handle);
+ conn_retry_count++;
+ }
+ else
+ {
+ BTIF_TRACE_IMP("%s Aborting Avrcp connection retry", __FUNCTION__);
+ }
+ }
+ else
+ {
+ if (conn_retry_count > 1)
+ {
+ conn_retry_count = 1;
+ BTIF_TRACE_IMP("%s Connection Retry count exceeded", __FUNCTION__);
+ return;
+ }
+ BTIF_TRACE_IMP("%s A2dp already connected", __FUNCTION__);
+ BTIF_TRACE_IMP("%s Avrcp already connected on handle: %d", __FUNCTION__,
+ btif_rc_get_connected_peer_handle(av_address));
+ }
+}
+
+
+void btif_av_check_and_start_collission_timer(int index)
+{
+ memcpy(&retry_bda, &btif_av_cb[index].peer_bda, sizeof(bt_bdaddr_t));
+
+ BTIF_TRACE_IMP("btif_av_check_and_start_collission_timer, index: %d ", index);
+
+ if (alarm_is_scheduled(av_coll_detected_timer))
+ {
+ alarm_cancel(av_coll_detected_timer);
+ BTIF_TRACE_IMP("btif_av_check_and_start_collission_timer:Deleting previously queued timer");
+ }
+ alarm_set_on_queue(av_coll_detected_timer,
+ BTIF_TIMEOUT_AV_COLL_DETECTED_MS,
+ btif_av_collission_timer_timeout,
+ NULL,
+ btu_general_alarm_queue);
+}
+
+
/*****************************************************************************
**
** Function btif_av_state_idle_handler
@@ -298,75 +527,76 @@
**
*******************************************************************************/
-static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data, int index)
{
- BTIF_TRACE_DEBUG("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ char a2dp_role[255] = "false";
+
+ BTIF_TRACE_IMP("%s event:%s flags %x on Index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
/* clear the peer_bda */
- memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
- btif_av_cb.flags = 0;
- btif_av_cb.edr = 0;
- btif_a2dp_on_idle();
+ BTIF_TRACE_EVENT("IDLE state for index: %d", index);
+ memset(&btif_av_cb[index].peer_bda, 0, sizeof(bt_bdaddr_t));
+ btif_av_cb[index].flags = 0;
+ btif_av_cb[index].edr_3mbps = 0;
+ btif_av_cb[index].edr = 0;
+ btif_av_cb[index].current_playing = FALSE;
+ btif_av_cb[index].is_slave = FALSE;
+ btif_av_cb[index].is_remote_start_received = FALSE;
+ btif_av_cb[index].is_suspend_for_remote_start = FALSE;
+ btif_av_cb[index].is_device_playing = FALSE;
+ for (int i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].dual_handoff = FALSE;
+ }
+ property_get("persist.service.bt.a2dp.sink", a2dp_role, "false");
+ if (!strncmp("false", a2dp_role, 5)) {
+ btif_av_cb[index].peer_sep = AVDT_TSEP_SNK;
+ btif_a2dp_set_peer_sep(AVDT_TSEP_SNK);
+ } else {
+ btif_av_cb[index].peer_sep = AVDT_TSEP_SRC;
+ btif_a2dp_set_peer_sep(AVDT_TSEP_SRC);
+ }
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ btif_av_cb[index].channel_id = 0;
+#endif
+ /* This API will be called twice at initialization
+ ** Idle can be moved when device is disconnected too.
+ ** Take care of other connected device here.*/
+ if (!btif_av_is_connected())
+ {
+ BTIF_TRACE_EVENT("reset A2dp states in IDLE ");
+ btif_a2dp_on_idle();
+ }
+ else
+ {
+ //There is another AV connection, update current playin
+ BTIF_TRACE_EVENT("reset A2dp states in IDLE ");
+ //btif_media_send_reset_vendor_state();
+ btif_av_update_current_playing_device(index);
+ }
+ if (!btif_av_is_playing_on_other_idx(index) &&
+ bt_split_a2dp_enabled)
+ {
+ BTIF_TRACE_EVENT("reset Vendor flag A2DP state is IDLE");
+ reconfig_a2dp = FALSE;
+ btif_media_send_reset_vendor_state();
+ }
break;
case BTIF_SM_EXIT_EVT:
break;
case BTA_AV_ENABLE_EVT:
+ BTIF_TRACE_EVENT("AV is enabled now for index: %d", index);
break;
case BTA_AV_REGISTER_EVT:
- btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
- break;
-
- case BTA_AV_PENDING_EVT:
- case BTIF_AV_CONNECT_REQ_EVT:
- {
- if (event == BTIF_AV_CONNECT_REQ_EVT)
- {
- memcpy(&btif_av_cb.peer_bda, ((btif_av_connect_req_t*)p_data)->target_bda,
- sizeof(bt_bdaddr_t));
- BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
- TRUE, BTA_SEC_AUTHENTICATE, ((btif_av_connect_req_t*)p_data)->uuid);
- }
- else if (event == BTA_AV_PENDING_EVT)
- {
- bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
- if (bt_av_src_callbacks != NULL)
- {
- BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
- TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
- }
- if (bt_av_sink_callbacks != NULL)
- {
- BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
- TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
- }
- }
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
- } break;
-
- case BTA_AV_RC_OPEN_EVT:
- /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
- * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
- * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
- * We initiate the AV connection after a small 3s timeout to avoid any collisions from the
- * headsets, as some headsets initiate the AVRC connection first and then
- * immediately initiate the AV connection
- *
- * TODO: We may need to do this only on an AVRCP Play. FixMe
- */
-
- BTIF_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
- alarm_set_on_queue(av_open_on_rc_timer,
- BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
- btif_initiate_av_open_timer_timeout, NULL,
- btu_general_alarm_queue);
- btif_rc_handler(event, p_data);
+ BTIF_TRACE_EVENT("The AV Handle:%d", ((tBTA_AV*)p_data)->registr.hndl);
+ btif_av_cb[index].bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
break;
/*
@@ -390,47 +620,157 @@
}
} break;
+ case BTIF_AV_CONNECT_REQ_EVT:
+ /* For outgoing connect stack and app are in sync.
+ */
+ memcpy(&btif_av_cb[index].peer_bda, ((btif_av_connect_req_t*)p_data)->target_bda,
+ sizeof(bt_bdaddr_t));
+ BTA_AvOpen(btif_av_cb[index].peer_bda.address, btif_av_cb[index].bta_handle,
+ TRUE, BTA_SEC_AUTHENTICATE, ((btif_av_connect_req_t*)p_data)->uuid);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENING);
+ break;
+
+ case BTA_AV_PENDING_EVT:
+ case BTA_AV_RC_OPEN_EVT:
+ /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
+ * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
+ * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
+ * We initiate the AV connection after a small 3s timeout to avoid any collisions from the
+ * headsets, as some headsets initiate the AVRC connection first and then
+ * immediately initiate the AV connection
+ *
+ * TODO: We may need to do this only on an AVRCP Play. FixMe
+ */
+ /* Check if connection allowed with this device */
+ /* In Dual A2dp case, this event can come for both the headsets.
+ * Reject second connection request as we are already checking
+ * for device priority for first device and we cannot queue
+ * incoming connections requests.
+ */
+
+ if (idle_rc_event != 0)
+ {
+ BTIF_TRACE_DEBUG("Processing another RC Event ");
+ return FALSE;
+ }
+ memcpy(&idle_rc_data, ((tBTA_AV*)p_data), sizeof(tBTA_AV));
+ if (event == BTA_AV_RC_OPEN_EVT)
+ {
+ if (((tBTA_AV*)p_data)->rc_open.status == BTA_AV_SUCCESS)
+ {
+ bdcpy(btif_av_cb[index].peer_bda.address,
+ ((tBTA_AV*)p_data)->rc_open.peer_addr);
+ }
+ else
+ {
+ idle_rc_event = 0;
+ return TRUE;
+ }
+ }
+ else
+ {
+ bdcpy(btif_av_cb[index].peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
+ }
+
+ // Only for AVDTP connection request move to opening state
+ if (event == BTA_AV_PENDING_EVT)
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENING);
+
+ if (bt_av_src_callbacks != NULL)
+ {
+ BTIF_TRACE_DEBUG("Calling connection priority callback ");
+ idle_rc_event = event;
+ HAL_CBACK(bt_av_src_callbacks, connection_priority_cb,
+ &(btif_av_cb[index].peer_bda));
+ }
+ if (bt_av_sink_callbacks != NULL)
+ {
+ if(event == BTA_AV_PENDING_EVT)
+ {
+ BTA_AvOpen(btif_av_cb[index].peer_bda.address, btif_av_cb[index].bta_handle,
+ TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
+ }
+ else if(event == BTA_AV_RC_OPEN_EVT)
+ {
+ alarm_set_on_queue(av_open_on_rc_timer,
+ BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
+ btif_initiate_av_open_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ btif_rc_handler(event, p_data);
+ }
+ }
+ break;
+
case BTA_AV_OPEN_EVT:
{
+ /* We get this event in Idle State if Signaling
+ * channel is not closed, only Streaming channel was
+ * closed earlier, and now only stream setup process is
+ * initiated.
+ */
tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
btav_connection_state_t state;
- btif_sm_state_t av_state;
BTIF_TRACE_DEBUG("status:%d, edr 0x%x",p_bta_data->open.status,
p_bta_data->open.edr);
if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
state = BTAV_CONNECTION_STATE_CONNECTED;
- av_state = BTIF_AV_STATE_OPENED;
- btif_av_cb.edr = p_bta_data->open.edr;
-
- btif_av_cb.peer_sep = p_bta_data->open.sep;
+ btif_av_cb[index].edr = p_bta_data->open.edr;
+ if (p_bta_data->open.role == HOST_ROLE_SLAVE)
+ {
+ btif_av_cb[index].is_slave = TRUE;
+ }
+ btif_av_cb[index].peer_sep = p_bta_data->open.sep;
btif_a2dp_set_peer_sep(p_bta_data->open.sep);
+
+ if ((p_bta_data->open.edr & BTA_AV_EDR_3MBPS) &&
+ (!(interop_match_addr(INTEROP_2MBPS_LINK_ONLY,
+ (const bt_bdaddr_t *)&btif_av_cb[index].peer_bda.address))))
+ {
+ BTIF_TRACE_DEBUG("remote supports 3 mbps");
+ btif_av_cb[index].edr_3mbps = TRUE;
+ }
+
+ bdcpy(btif_av_cb[index].peer_bda.address, ((tBTA_AV*)p_data)->open.bd_addr);
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ btif_av_cb[index].channel_id = p_bta_data->open.stream_chnl_id;
+ BTIF_TRACE_DEBUG("streaming channel id updated as : 0x%x",
+ btif_av_cb[index].channel_id);
+#endif
}
else
{
BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
p_bta_data->open.status );
state = BTAV_CONNECTION_STATE_DISCONNECTED;
- av_state = BTIF_AV_STATE_IDLE;
}
- /* inform the application of the event */
- btif_report_connection_state(state, &(btif_av_cb.peer_bda));
- /* change state to open/idle based on the status */
- btif_sm_change_state(btif_av_cb.sm_handle, av_state);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ /* change state to open based on the status */
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
+ {
+ /* inform the application of the event */
+ btif_report_connection_state(state, &(btif_av_cb[index].peer_bda));
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENED);
+ /* BTIF AV State updated, now check
+ * and update multicast state
+ */
+ btif_av_update_multicast_state(index);
+ }
+
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
/* if queued PLAY command, send it now */
btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
(p_bta_data->open.status == BTA_AV_SUCCESS));
}
- else if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ else if ((btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) &&
+ (p_bta_data->open.status == BTA_AV_SUCCESS))
{
/* if queued PLAY command, send it now */
btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
/* Bring up AVRCP connection too */
- BTA_AvOpenRc(btif_av_cb.bta_handle);
+ BTA_AvOpenRc(btif_av_cb[index].bta_handle);
}
btif_queue_advance();
} break;
@@ -440,6 +780,7 @@
case BTA_AV_META_MSG_EVT:
case BTA_AV_RC_FEAT_EVT:
case BTA_AV_REMOTE_RSP_EVT:
+ case BTA_AV_BROWSE_MSG_EVT:
btif_rc_handler(event, (tBTA_AV*)p_data);
break;
@@ -454,6 +795,10 @@
btif_a2dp_on_offload_started(BTA_AV_FAIL);
break;
+ case BTA_AV_RC_COLL_DETECTED_EVT:
+ BTIF_TRACE_WARNING("BTA_AV_RC_COLL_DETECTED_EVT: Not Starting conn retry timer");
+ break;
+
default:
BTIF_TRACE_WARNING("%s : unhandled event:%s", __FUNCTION__,
dump_av_sm_event_name(event));
@@ -474,16 +819,25 @@
**
*******************************************************************************/
-static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data, int index)
{
- BTIF_TRACE_DEBUG("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
-
+ int i;
+ BTIF_TRACE_IMP("%s event:%s flags %x on index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
/* inform the application that we are entering connecting state */
- btif_report_connection_state(BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda));
+ if (bt_av_sink_callbacks != NULL)
+ {
+ HAL_CBACK(bt_av_sink_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb[index].peer_bda));
+ }
+ else if (bt_av_src_callbacks != NULL)
+ {
+ HAL_CBACK(bt_av_src_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb[index].peer_bda));
+ }
break;
case BTIF_SM_EXIT_EVT:
@@ -491,8 +845,9 @@
case BTA_AV_REJECT_EVT:
BTIF_TRACE_DEBUG(" Received BTA_AV_REJECT_EVT ");
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
case BTA_AV_OPEN_EVT:
@@ -500,53 +855,114 @@
tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
btav_connection_state_t state;
btif_sm_state_t av_state;
- BTIF_TRACE_DEBUG("status:%d, edr 0x%x",p_bta_data->open.status,
- p_bta_data->open.edr);
+ BTIF_TRACE_DEBUG("status:%d, edr 0x%x, role: 0x%x",p_bta_data->open.status,
+ p_bta_data->open.edr, p_bta_data->open.role);
if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
state = BTAV_CONNECTION_STATE_CONNECTED;
av_state = BTIF_AV_STATE_OPENED;
- btif_av_cb.edr = p_bta_data->open.edr;
-
- btif_av_cb.peer_sep = p_bta_data->open.sep;
+ btif_av_cb[index].edr = p_bta_data->open.edr;
+ if (p_bta_data->open.role == HOST_ROLE_SLAVE)
+ {
+ btif_av_cb[index].is_slave = TRUE;
+ }
+ btif_av_cb[index].peer_sep = p_bta_data->open.sep;
btif_a2dp_set_peer_sep(p_bta_data->open.sep);
+ if ((p_bta_data->open.edr & BTA_AV_EDR_3MBPS) &&
+ (!(interop_match_addr(INTEROP_2MBPS_LINK_ONLY,
+ (const bt_bdaddr_t *)&btif_av_cb[index].peer_bda.address))))
+ {
+ BTIF_TRACE_DEBUG("remote supports 3 mbps");
+ btif_av_cb[index].edr_3mbps = TRUE;
+ }
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ btif_av_cb[index].channel_id = p_bta_data->open.stream_chnl_id;
+ BTIF_TRACE_DEBUG("streaming channel id updated as : 0x%x",
+ btif_av_cb[index].channel_id);
+#endif
}
else
{
BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
p_bta_data->open.status );
+ /* Multicast: Check if connected to AVRC only device
+ * disconnect when Dual A2DP/Multicast is supported.
+ */
BD_ADDR peer_addr;
if ((btif_rc_get_connected_peer(peer_addr))
- &&(!bdcmp(btif_av_cb.peer_bda.address, peer_addr)))
+ &&(!bdcmp(btif_av_cb[index].peer_bda.address, peer_addr)))
{
- /*
- * Disconnect AVRCP connection, if
- * A2DP conneciton failed, for any reason
+ /* Do not disconnect AVRCP connection if A2DP
+ * connection failed due to SDP failure since remote
+ * may not support A2DP. In such case we will keep
+ * AVRCP only connection.
*/
- BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
- BTA_AvCloseRc(btif_rc_get_connected_peer_handle());
+ if (p_bta_data->open.status != BTA_AV_FAIL_SDP)
+ {
+ BTIF_TRACE_WARNING("Disconnecting AVRCP ");
+ BTA_AvCloseRc(btif_rc_get_connected_peer_handle(peer_addr));
+ }
+ else
+ {
+ BTIF_TRACE_WARNING("Keep AVRCP only connection");
+ }
}
state = BTAV_CONNECTION_STATE_DISCONNECTED;
av_state = BTIF_AV_STATE_IDLE;
}
- /* inform the application of the event */
- btif_report_connection_state(state, &(btif_av_cb.peer_bda));
- /* change state to open/idle based on the status */
- btif_sm_change_state(btif_av_cb.sm_handle, av_state);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (p_bta_data->open.status != BTA_AV_SUCCESS &&
+ p_bta_data->open.status != BTA_AV_FAIL_SDP)
{
- /* if queued PLAY command, send it now */
- btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
- (p_bta_data->open.status == BTA_AV_SUCCESS));
+ btif_av_check_and_start_collission_timer(index);
}
- else if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+
+ /* inform the application of the event */
+ btif_report_connection_state(state, &(btif_av_cb[index].peer_bda));
+ /* change state to open/idle based on the status */
+ btif_sm_change_state(btif_av_cb[index].sm_handle, av_state);
+ /* Check if the other connected AV is playing,
+ * If YES, trigger DUAL Handoff. */
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
- /* if queued PLAY command, send it now */
- btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
- /* Bring up AVRCP connection too */
- BTA_AvOpenRc(btif_av_cb.bta_handle);
+ /* BTIF AV State updated, now check
+ * and update multicast state
+ */
+ btif_av_update_multicast_state(index);
+
+ /*This device should be now ready for all next playbacks*/
+ btif_av_cb[index].current_playing = TRUE;
+ if (enable_multicast == FALSE)
+ {
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ //Other device is not current playing
+ if (i != index)
+ btif_av_cb[i].current_playing = FALSE;
+ }
+ /* In A2dp Multicast, stack will take care of starting
+ * the stream on newly connected A2dp device. If Handoff
+ * is supported, trigger Handoff here. */
+ if (btif_av_is_playing())
+ {
+ BTIF_TRACE_DEBUG("Trigger Dual A2dp Handoff on %d", index);
+ btif_av_trigger_dual_handoff(TRUE, btif_av_cb[index].peer_bda.address);
+ }
+ }
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
+ (p_bta_data->open.status == BTA_AV_SUCCESS));
+ }
+ else if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
+ {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
+ /* Bring up AVRCP connection too */
+ BTA_AvOpenRc(btif_av_cb[index].bta_handle);
+ }
}
btif_queue_advance();
} break;
@@ -559,16 +975,16 @@
BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
req.channel_count);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) {
- HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb.peer_bda),
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC && bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb[index].peer_bda),
req.sample_rate, req.channel_count);
}
} break;
case BTIF_AV_CONNECT_REQ_EVT:
// Check for device, if same device which moved to opening then ignore callback
- if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb.peer_bda),
- sizeof(btif_av_cb.peer_bda)) == 0)
+ if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb[index].peer_bda),
+ sizeof(btif_av_cb[index].peer_bda)) == 0)
{
BTIF_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Connect Req", __func__);
btif_queue_advance();
@@ -584,8 +1000,8 @@
case BTA_AV_PENDING_EVT:
// Check for device, if same device which moved to opening then ignore callback
- if (memcmp (((tBTA_AV*)p_data)->pend.bd_addr, &(btif_av_cb.peer_bda),
- sizeof(btif_av_cb.peer_bda)) == 0)
+ if (memcmp (((tBTA_AV*)p_data)->pend.bd_addr, &(btif_av_cb[index].peer_bda),
+ sizeof(btif_av_cb[index].peer_bda)) == 0)
{
BTIF_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Pending Req", __func__);
break;
@@ -603,10 +1019,35 @@
break;
case BTA_AV_CLOSE_EVT:
- btif_a2dp_on_stopped(NULL);
+ /* avdtp link is closed */
+ /* Check if any other device is playing
+ * and this is not the one.*/
+ if (!btif_av_is_playing())
+ {
+ btif_a2dp_on_stopped(NULL);
+ }
+ /* inform the application that we are disconnected */
btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
- &(btif_av_cb.peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ &(btif_av_cb[index].peer_bda));
+ btif_queue_advance();
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ btif_av_check_and_start_collission_timer(index);
+ break;
+
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
+ BTA_AvClose(btif_av_cb[index].bta_handle);
+ btif_queue_advance();
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ case BTA_AV_RC_OPEN_EVT:
+ btif_rc_handler(event, p_data);;
+ break;
+
+ case BTA_AV_RC_COLL_DETECTED_EVT:
+ BTIF_TRACE_WARNING("BTA_AV_RC_COLL_DETECTED_EVT: Not Starting conn retry timer");
break;
CHECK_RC_EVENT(event, p_data);
@@ -631,21 +1072,42 @@
**
*******************************************************************************/
-static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data, int index)
{
- BTIF_TRACE_DEBUG("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ BTIF_TRACE_IMP("%s event:%s flags %x and index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
- /* immediately stop transmission of frames */
- btif_a2dp_set_tx_flush(TRUE);
- /* wait for audioflinger to stop a2dp */
+ /* Multicast/Soft Hand-off:
+ * If MC/SHO is enabled we need to keep/start playing on
+ * other device.
+ */
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ if (btif_av_is_playing())
+ {
+ APPL_TRACE_DEBUG("Keep playing on other device");
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("Not playing on other devie: Set Flush");
+ btif_a2dp_set_tx_flush(TRUE);
+ }
+ }
+ else
+ {
+ /* Single connections scenario:
+ * Immediately stop transmission of frames
+ * wait for audioflinger to stop a2dp
+ */
+ btif_a2dp_set_tx_flush(TRUE);
+ }
}
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(TRUE);
}
@@ -653,17 +1115,35 @@
case BTA_AV_STOP_EVT:
case BTIF_AV_STOP_STREAM_REQ_EVT:
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
- /* immediately flush any pending tx frames while suspend is pending */
- btif_a2dp_set_tx_flush(TRUE);
+ /* Dont stop in DUAL A2dp connections, as
+ * UIPC will keep waiting for Audio CTRL channel
+ * to get closed which is not required in Dual A2dp.
+ * We will stop only when only single A2dp conn is present.*/
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ if (!btif_av_is_playing())
+ {
+ APPL_TRACE_WARNING("Suspend the AV Data channel");
+ //Flush and close media channel
+ btif_a2dp_set_tx_flush(TRUE);
+ btif_media_task_stop_aa_req();
+ }
+ }
+ else
+ {
+ /* immediately flush any pending tx frames while suspend is pending */
+ APPL_TRACE_WARNING("Stop the AV Data channel");
+ btif_a2dp_set_tx_flush(TRUE);
+ btif_a2dp_on_stopped(NULL);
+ }
}
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(TRUE);
+ btif_a2dp_on_stopped(NULL);
}
-
- btif_a2dp_on_stopped(NULL);
break;
case BTIF_SM_EXIT_EVT:
@@ -672,9 +1152,9 @@
case BTA_AV_CLOSE_EVT:
/* inform the application that we are disconnecting */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb[index].peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
/* Handle the RC_CLOSE event for the cleanup */
@@ -682,6 +1162,10 @@
btif_rc_handler(event, (tBTA_AV*)p_data);
break;
+ case BTA_AV_RC_COLL_DETECTED_EVT:
+ BTIF_TRACE_WARNING("BTA_AV_RC_COLL_DETECTED_EVT: Not Starting conn retry timer");
+ break;
+
case BTIF_AV_OFFLOAD_START_REQ_EVT:
btif_a2dp_on_offload_started(BTA_AV_FAIL);
BTIF_TRACE_ERROR("BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Closing");
@@ -695,6 +1179,19 @@
return TRUE;
}
+/******************************************************************************
+**
+** Function btif_av_is_offload_supported
+**
+** Description Returns split mode status
+**
+** Returns TRUE if split mode is enabled, FALSE otherwise
+********************************************************************************/
+BOOLEAN btif_av_is_offload_supported()
+{
+ return bt_split_a2dp_enabled;
+}
+
/*****************************************************************************
**
** Function btif_av_state_opened_handler
@@ -705,131 +1202,279 @@
**
*******************************************************************************/
-static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data, int index)
{
tBTA_AV *p_av = (tBTA_AV*)p_data;
- BTIF_TRACE_DEBUG("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ BTIF_TRACE_IMP("%s event:%s flags %x and index = %d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
- if ( (event == BTA_AV_REMOTE_CMD_EVT) && (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
+ if ((event == BTA_AV_REMOTE_CMD_EVT) &&
(p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY) )
{
- BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY", __FUNCTION__);
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ if (btif_av_check_flag_remote_suspend(index))
+ {
+ BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY",
+ __FUNCTION__);
+ btif_av_clear_remote_suspend_flag();
+ if (btif_av_is_offload_supported())
+ {
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ }
+ }
}
switch (event)
{
case BTIF_SM_ENTER_EVT:
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_STOP;
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
break;
case BTIF_SM_EXIT_EVT:
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
break;
case BTIF_AV_START_STREAM_REQ_EVT:
- if (btif_av_cb.peer_sep != AVDT_TSEP_SRC)
- btif_a2dp_setup_codec();
- BTA_AvStart();
- btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START;
+ /* update multicast state here if new device is connected
+ * after A2dp connection. New A2dp device is connected
+ * whlie playing */
+ btif_av_update_multicast_state(index);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
+ {
+ BTA_AvStart(btif_av_cb[index].bta_handle);
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_START;
+ break;
+ }
+ tBTIF_STATUS status = btif_a2dp_setup_codec(btif_av_cb[index].bta_handle);
+ if (status == BTIF_SUCCESS)
+ {
+ int idx = 0;
+ BTA_AvStart(btif_av_cb[index].bta_handle);
+ if (enable_multicast == TRUE)
+ {
+ /* In A2dp Multicast, DUT initiated stream request
+ * should be true for all connected A2dp devices. */
+ for (; idx < btif_max_av_clients; idx++)
+ {
+ btif_av_cb[idx].flags |= BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+ else
+ {
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+ else if (status == BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED)
+ {
+#if defined(BTA_AV_DISCONNECT_IF_NO_SCMS_T) && (BTA_AV_DISCONNECT_IF_NO_SCMS_T == TRUE)
+ BTIF_TRACE_ERROR0("SCMST enabled, disconnect as remote does not support SCMST");
+ BTA_AvDisconnect(btif_av_cb[index].peer_bda.address);
+#else
+ BTIF_TRACE_WARNING("SCMST enabled, connecting to non SCMST SEP");
+ BTA_AvStart(btif_av_cb[index].bta_handle);
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_START;
+#endif
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("## AV Disconnect## status : %x",status);
+ BTA_AvDisconnect(btif_av_cb[index].peer_bda.address);
+ }
+ break;
+
+ case BTIF_AV_UPDATE_ENCODER_REQ_EVT:
+ btif_a2dp_update_codec();
break;
case BTA_AV_START_EVT:
{
- BTIF_TRACE_EVENT("BTA_AV_START_EVT status %d, suspending %d, init %d",
+ BTIF_TRACE_DEBUG("BTA_AV_START_EVT status %d, suspending %d, init %d",
p_av->start.status, p_av->start.suspending, p_av->start.initiator);
+ BTIF_TRACE_DEBUG("BTA_AV_START_EVT role: %d", p_av->start.role);
+ if (p_av->start.role == HOST_ROLE_SLAVE)
+ {
+ btif_av_cb[index].is_slave = TRUE;
+ }
+ else
+ {
+ // update if we are master after role switch before start
+ btif_av_cb[index].is_slave = FALSE;
+ }
+ /* There can be role switch after device is connected,
+ * hence check for role before starting multicast, and
+ * disable if we are in slave role for any connection
+ */
+ btif_av_update_multicast_state(index);
if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE))
return TRUE;
+ /* if remote tries to start a2dp when call is in progress, suspend it right away */
+ if ((!(btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)) && (!btif_hf_is_call_vr_idle())) {
+ BTIF_TRACE_EVENT("%s: trigger suspend as call is in progress!!", __FUNCTION__);
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].is_remote_start_received = TRUE;
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_STARTED);
+ btif_dispatch_sm_event(BTIF_AV_REMOTE_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ break;
+ }
+
/* if remote tries to start a2dp when DUT is a2dp source
* then suspend. In case a2dp is sink and call is active
* then disconnect the AVDTP channel
*/
- if (!(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START))
+ if (!(btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START))
{
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
- BTIF_TRACE_EVENT("%s: trigger suspend as remote initiated!!", __FUNCTION__);
- btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
- }
- }
+ if (enable_multicast)
+ {
+ /* Stack will start the playback on newly connected
+ * A2dp device, if the playback is already happening on
+ * other connected device.*/
+ if (btif_av_is_playing())
+ {
+ /* when HS2 is connected during HS1 playing, stack directly
+ * sends start event hence update encoder so that least L2CAP
+ * MTU is selected.*/
+ //btif_a2dp_update_codec();
+ BTIF_TRACE_DEBUG("%s: A2dp Multicast playback",
+ __FUNCTION__);
+ }
+ /* initiate suspend if start is initiate by remote and multicast
+ * is enabled.
+ * Avoid suspend if stream is started as quick suspend-start
+ * creates IOT issue, seen with SBH50.
+ */
- /* In case peer is A2DP SRC we do not want to ack commands on UIPC*/
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
- {
- if (btif_a2dp_on_started(&p_av->start,
- ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0)))
- {
- /* only clear pending flag after acknowledgement */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ if (!p_av->start.initiator && !btif_av_is_playing())
+ {
+ BTIF_TRACE_DEBUG("initiate suspend for remote start");
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
+ }
+ else
+ {
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_REMOTE_SUSPEND))
+ {
+ BTIF_TRACE_DEBUG("%s: clear remote suspend flag on remote start",
+ __FUNCTION__);
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ if (btif_av_is_offload_supported())
+ {
+ btif_media_start_vendor_command();
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s: honor remote started for BL device",__FUNCTION__);
+ btif_a2dp_on_remote_started();
+ btif_av_cb[index].is_remote_start_received = TRUE;
+ }
+ }
}
}
/* remain in open state if status failed */
+ /* Multicast-soft Handoff:
+ * START failed, cleanup Handoff flag.
+ */
if (p_av->start.status != BTA_AV_SUCCESS)
- return FALSE;
+ {
+ int i;
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ /* In case peer is A2DP SRC we do not want to ack commands on UIPC */
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ {
+ if (btif_a2dp_on_started(&p_av->start,
+ ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) != 0),
+ btif_av_cb[index].bta_handle))
+ {
+ /* only clear pending flag after acknowledgement */
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+ /* Clear dual handoff flag */
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].dual_handoff = FALSE;
+ }
+ return FALSE;
+ }
+
+#ifndef AVK_BACKPORT
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/
}
+#endif
- /* change state to started, send acknowledgement if start is pending */
- if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
- btif_a2dp_on_started(NULL, TRUE);
- /* pending start flag will be cleared when exit current state */
- }
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_STARTED);
} break;
case BTIF_AV_DISCONNECT_REQ_EVT:
- BTA_AvClose(btif_av_cb.bta_handle);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
- BTA_AvCloseRc(btif_av_cb.bta_handle);
+ BTA_AvClose(btif_av_cb[index].bta_handle);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) {
+ BTA_AvCloseRc(btif_av_cb[index].bta_handle);
}
/* inform the application that we are disconnecting */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb[index].peer_bda));
break;
case BTA_AV_CLOSE_EVT:
/* avdtp link is closed */
- btif_a2dp_on_stopped(NULL);
+ /*Dont close the A2dp when Dual playback is happening*/
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ APPL_TRACE_WARNING("Conn is closing,close AV data channel");
+ if (!btif_av_is_playing())
+ {
+ APPL_TRACE_WARNING("Suspend the AV Data channel");
+ /* ensure tx frames are immediately suspended */
+ btif_a2dp_set_tx_flush(TRUE);
+ btif_media_task_stop_aa_req();
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("Stop the AV Data channel");
+ btif_a2dp_on_stopped(NULL);
+ }
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_DISCONNECT;
/* inform the application that we are disconnected */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_DISCONNECT;
/* change state to idle, send acknowledgement if start is pending */
- if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+ if (btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) {
btif_a2dp_ack_fail();
- /* pending start flag will be cleared when exit current state */
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
}
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
break;
case BTA_AV_RECONFIG_EVT:
- if((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) &&
+ if((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) &&
(p_av->reconfig.status == BTA_AV_SUCCESS))
{
APPL_TRACE_WARNING("reconfig done BTA_AVstart()");
- BTA_AvStart();
+ BTA_AvStart(btif_av_cb[index].bta_handle);
}
- else if(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START)
+ else if(btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)
{
- btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
btif_a2dp_ack_fail();
}
break;
case BTIF_AV_CONNECT_REQ_EVT:
- if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb.peer_bda),
- sizeof(btif_av_cb.peer_bda)) == 0)
+ if (memcmp ((bt_bdaddr_t*)p_data, &(btif_av_cb[index].peer_bda),
+ sizeof(btif_av_cb[index].peer_bda)) == 0)
{
BTIF_TRACE_DEBUG("%s: Ignore BTIF_AV_CONNECT_REQ_EVT for same device", __func__);
}
@@ -847,6 +1492,15 @@
BTIF_TRACE_ERROR("BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Opened");
break;
+ case BTA_AV_RC_OPEN_EVT:
+ btif_av_check_rc_connection_priority(p_data);
+ break;
+
+ case BTA_AV_RC_COLL_DETECTED_EVT:
+ BTIF_TRACE_ERROR("BTA_AV_RC_COLL_DETECTED_EVT: Start conn retry timer");
+ btif_av_check_and_start_collission_timer(index);
+ break;
+
CHECK_RC_EVENT(event, p_data);
default:
@@ -868,31 +1522,84 @@
**
*******************************************************************************/
-static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data)
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data, int index)
{
tBTA_AV *p_av = (tBTA_AV*)p_data;
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ BOOLEAN hal_suspend_pending = FALSE;
- BTIF_TRACE_DEBUG("%s event:%s flags %x", __FUNCTION__,
- dump_av_sm_event_name(event), btif_av_cb.flags);
+ BTIF_TRACE_IMP("%s event:%s flags %x index =%d", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb[index].flags, index);
switch (event)
{
case BTIF_SM_ENTER_EVT:
+ /*Ack from entry point of started handler instead of open state to avoid race condition*/
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ {
+ if (!((!enable_multicast)&&((btif_av_cb[index].is_remote_start_received)
+ && ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) == 0))))
+ {
+ BTIF_TRACE_IMP("%s update media task on DUT initiated start for index =%d",
+ __FUNCTION__, index);
+ if (btif_a2dp_on_started(&p_av->start,
+ ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) != 0),
+ btif_av_cb[index].bta_handle))
+ {
+ /* only clear pending flag after acknowledgement */
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_IMP("%s Do not update media task on remote start for index =%d",
+ __FUNCTION__, index);
+ }
+ }
+
+ /* Already changed state to started, send acknowledgement if start is pending */
+ if (btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START) {
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ btif_a2dp_on_started(NULL, TRUE, btif_av_cb[index].bta_handle);
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_PENDING_START;
+ }
/* we are again in started state, clear any remote suspend flags */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
- /**
- * Report to components above that we have entered the streaming
- * stage, this should usually be followed by focus grant.
- * see update_audio_focus_state()
- */
- btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
+ if ((!enable_multicast)&&((btif_av_cb[index].is_remote_start_received)
+ && (btif_av_is_playing_on_other_idx(index))))
+ {
+ BTIF_TRACE_IMP("%s Do not update audio state change to app for index =%d",
+ __FUNCTION__, index);
+ }
+ else
+ {
+ btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb[index].peer_bda));
+ }
+ btif_av_cb[index].is_device_playing = TRUE;
/* increase the a2dp consumer task priority temporarily when start
** audio playing, to avoid overflow the audio packet queue. */
adjust_priority_a2dp(TRUE);
-
+#ifdef AVK_BACKPORT
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC)
+ {
+ btif_av_request_audio_focus(TRUE);
+ }
+#endif
+ //Clear Dual Handoff for all SCBs
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].dual_handoff = FALSE;
+ //Other device is not current playing
+ if (i != index)
+ btif_av_cb[i].current_playing = FALSE;
+ }
+ //This is latest device to play now
+ btif_av_cb[index].current_playing = TRUE;
+ //reconfig_a2dp = FALSE;
break;
case BTIF_SM_EXIT_EVT:
@@ -903,8 +1610,25 @@
case BTIF_AV_START_STREAM_REQ_EVT:
/* we were remotely started, just ack back the local request */
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
- btif_a2dp_on_started(NULL, TRUE);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ {
+ btif_a2dp_on_started(NULL, TRUE, btif_av_cb[index].bta_handle);
+ btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb[index].peer_bda));
+ btif_av_cb[index].is_device_playing = TRUE;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ //Other device is not current playing
+ if (i != index)
+ btif_av_cb[i].current_playing = FALSE;
+ }
+ //This is latest device to play now
+ btif_av_cb[index].current_playing = TRUE;
+ btif_av_reset_reconfig_flag();
+ }
+ break;
+
+ case BTIF_AV_UPDATE_ENCODER_REQ_EVT:
+ btif_a2dp_update_codec();
break;
/* fixme -- use suspend = true always to work around issue with BTA AV */
@@ -912,56 +1636,150 @@
case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
/* set pending flag to ensure btif task is not trying to restart
- stream while suspend is in progress */
- btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ * stream while suspend is in progress.
+ * Multicast: If streaming is happening on both devices, we need
+ * to update flag for both connections as SUSPEND request will
+ * be sent to only one stream as internally BTA takes care of
+ * suspending both streams.
+ */
+ if (enable_multicast)
+ {
+ for(i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ {
+ btif_av_cb[i].flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ }
+ }
+ }
+ else
+ {
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ }
/* if we were remotely suspended but suspend locally, local suspend
always overrides */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
/* immediately stop transmission of frames while suspend is pending */
btif_a2dp_set_tx_flush(TRUE);
}
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) {
btif_a2dp_set_rx_flush(TRUE);
btif_a2dp_on_stopped(NULL);
}
- BTA_AvStop(TRUE);
+ BTA_AvStop(TRUE, btif_av_cb[index].bta_handle);
break;
case BTIF_AV_DISCONNECT_REQ_EVT:
+ //Now it is not the current playing
+ btif_av_cb[index].current_playing = FALSE;
+ btif_av_update_current_playing_device(index);
+ btif_rc_clear_priority(btif_av_cb[index].peer_bda.address);
+ if (bt_split_a2dp_enabled && btif_av_is_connected_on_other_idx(index))
+ {
+ /*Fake handoff state to switch streaming to other coddeced
+ device */
+ btif_av_cb[index].dual_handoff = TRUE;
+ }
/* request avdtp to close */
- BTA_AvClose(btif_av_cb.bta_handle);
- if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
- BTA_AvCloseRc(btif_av_cb.bta_handle);
+ BTA_AvClose(btif_av_cb[index].bta_handle);
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SRC) {
+ BTA_AvCloseRc(btif_av_cb[index].bta_handle);
}
/* inform the application that we are disconnecting */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb[index].peer_bda));
/* wait in closing state until fully closed */
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_CLOSING);
+ if (bt_split_a2dp_enabled &&
+ btif_av_is_connected_on_other_idx(index))
+ {
+ BTIF_TRACE_DEBUG("%s: Notify framework to reconfig",__func__);
+ int idx = btif_av_get_other_connected_idx(index);
+ /* Fix for below Klockwork Issue
+ * Array 'btif_av_cb' of size 2 may use index value(s) -1 */
+ if (idx != INVALID_INDEX)
+ {
+ reconfig_a2dp = TRUE;
+ HAL_CBACK(bt_av_src_callbacks, reconfig_a2dp_trigger_cb, 1,
+ &(btif_av_cb[idx].peer_bda));
+ }
+ }
break;
case BTA_AV_SUSPEND_EVT:
-
BTIF_TRACE_EVENT("BTA_AV_SUSPEND_EVT status %d, init %d",
p_av->suspend.status, p_av->suspend.initiator);
+ //Check if this suspend is due to DUAL_Handoff
+ if ((btif_av_cb[index].dual_handoff) &&
+ (p_av->suspend.status == BTA_AV_SUCCESS))
+ {
+ BTIF_TRACE_EVENT("BTA_AV_SUSPEND_EVT: Dual handoff");
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ }
+ if (p_av->suspend.initiator != TRUE)
+ {
+ /* remote suspend, notify HAL and await audioflinger to
+ * suspend/stop stream
+ * set remote suspend flag to block media task from restarting
+ * stream only if we did not already initiate a local suspend
+ * set remote suspend flag before suspending stream as in race conditions
+ * when stream is suspended, but flag is things ge tossed up
+ */
+ BTIF_TRACE_EVENT("Clear before suspending");
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
+ for (int i = 0; i < btif_max_av_clients; i++)
+ {
+ if ((i != index) && btif_av_get_ongoing_multicast())
+ {
+ multicast_disabled = TRUE;
+ btif_av_update_multicast_state(index);
+ BTIF_TRACE_EVENT("Initiate suspend for other HS also");
+ btif_sm_dispatch(btif_av_cb[i].sm_handle,
+ BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL);
+ }
+ }
+ }
/* a2dp suspended, stop media task until resumed */
- btif_a2dp_on_suspended(&p_av->suspend);
+ /* Multicast: If streaming on other device, don't call onsuspended
+ * as it unblocks the audio process and audio process may send
+ * subsequent commands and create problem during the time where we
+ * still did not receive response for SUSPEND sent to other device.
+ * Keep the suspend failure handling untouched and handle
+ * only success case to check and avoid calling onsuspended.
+ */
+ if (btif_a2dp_get_pending_hal_command() == A2DP_CTRL_CMD_SUSPEND ||
+ btif_a2dp_get_pending_hal_command() == A2DP_CTRL_CMD_STOP)
+ {
+ BTIF_TRACE_DEBUG("HAL suspend/stop pending ack the suspend");
+ hal_suspend_pending = TRUE;
+ }
+ if ((p_av->suspend.status != BTA_AV_SUCCESS) ||
+ hal_suspend_pending || !btif_av_is_playing_on_other_idx(index))
+ {
+ btif_a2dp_on_suspended(&p_av->suspend);
+ }
+ else if(btif_av_is_playing_on_other_idx(index))
+ {
+ BTIF_TRACE_DEBUG("Other device not suspended, don't ack the suspend");
+ }
/* if not successful, remain in current state */
if (p_av->suspend.status != BTA_AV_SUCCESS)
{
- btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
- if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
{
/* suspend failed, reset back tx flush state */
btif_a2dp_set_tx_flush(FALSE);
@@ -969,64 +1787,114 @@
return FALSE;
}
- if (p_av->suspend.initiator != TRUE)
+ if ((!enable_multicast)&& btif_av_cb[index].is_suspend_for_remote_start
+ && (btif_av_is_playing_on_other_idx(index)))
{
- /* remote suspend, notify HAL and await audioflinger to
- suspend/stop stream */
-
- /* set remote suspend flag to block media task from restarting
- stream only if we did not already initiate a local suspend */
- if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
- btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
-
- btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda));
+ BTIF_TRACE_IMP("%s Do not update audio state change to app for index =%d",
+ __FUNCTION__, index);
}
else
{
- btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+ btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb[index].peer_bda));
}
+ btif_av_cb[index].is_suspend_for_remote_start = FALSE;
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+ btif_av_cb[index].is_device_playing = FALSE;
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENED);
/* suspend completed and state changed, clear pending status */
- btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ btif_av_cb[index].flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
break;
case BTA_AV_STOP_EVT:
- btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
- btif_a2dp_on_stopped(&p_av->suspend);
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb[index].current_playing = FALSE;
+ if (btif_av_is_connected_on_other_idx(index))
+ {
+ if (enable_multicast == FALSE)
+ {
+ APPL_TRACE_WARNING("other Idx is connected, move to SUSPENDED");
+ if (!bt_split_a2dp_enabled) {
+ btif_rc_send_pause_command();
+ }
+ btif_a2dp_on_stopped(&p_av->suspend);
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("Stop the AV Data channel as no connection is present");
+ btif_a2dp_on_stopped(&p_av->suspend);
+ }
+ btif_av_cb[index].is_device_playing = FALSE;
- btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
-
+ if ((!enable_multicast)&& btif_av_cb[index].is_suspend_for_remote_start
+ && (btif_av_is_playing_on_other_idx(index)))
+ {
+ BTIF_TRACE_IMP("%s Do not update audio state change to app for index =%d",
+ __FUNCTION__, index);
+ }
+ else
+ {
+ btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb[index].peer_bda));
+ }
+ btif_av_cb[index].is_suspend_for_remote_start = FALSE;
/* if stop was successful, change state to open */
if (p_av->suspend.status == BTA_AV_SUCCESS)
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_OPENED);
+
+ if (bt_split_a2dp_enabled &&
+ btif_av_is_connected_on_other_idx(index))
+ {
+ /*Fake handoff state to switch streaming to other coddeced
+ device */
+ btif_av_cb[index].dual_handoff = TRUE;
+ BTIF_TRACE_DEBUG("%s: Notify framework to reconfig",__func__);
+ int idx = btif_av_get_other_connected_idx(index);
+ /* Fix for below Klockwork Issue
+ * Array 'btif_av_cb' of size 2 may use index value(s) -1 */
+ if (idx != INVALID_INDEX)
+ {
+ reconfig_a2dp = TRUE;
+ HAL_CBACK(bt_av_src_callbacks, reconfig_a2dp_trigger_cb, 1,
+ &(btif_av_cb[idx].peer_bda));
+ }
+ }
break;
case BTA_AV_CLOSE_EVT:
- btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb[index].flags |= BTIF_AV_FLAG_PENDING_STOP;
/* avdtp link is closed */
+ APPL_TRACE_WARNING("Stop the AV Data channel");
btif_a2dp_on_stopped(NULL);
/* inform the application that we are disconnected */
- btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb[index].peer_bda));
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ case BTA_AV_RC_OPEN_EVT:
+ btif_av_check_rc_connection_priority(p_data);
break;
case BTIF_AV_OFFLOAD_START_REQ_EVT:
- BTA_AvOffloadStart(btif_av_cb.bta_handle);
+ BTA_AvOffloadStart(btif_av_cb[index].bta_handle);
break;
case BTA_AV_OFFLOAD_START_RSP_EVT:
-
btif_a2dp_on_offload_started(p_av->status);
break;
+ case BTA_AV_RC_COLL_DETECTED_EVT:
+ BTIF_TRACE_ERROR("BTA_AV_RC_COLL_DETECTED_EVT: Start conn retry timer");
+ btif_av_check_and_start_collission_timer(index);
+ break;
+
CHECK_RC_EVENT(event, p_data);
default:
@@ -1038,33 +1906,6 @@
return TRUE;
}
-/*****************************************************************************
-** Local event handlers
-******************************************************************************/
-
-static void btif_av_handle_event(UINT16 event, char* p_param)
-{
- BTIF_TRACE_EVENT("%s event:%s", __func__,
- dump_av_sm_event_name((btif_av_sm_event_t)event));
- switch(event)
- {
- case BTIF_AV_CLEANUP_REQ_EVT:
- btif_a2dp_stop_media_task();
- break;
-
- case BTA_AV_REGISTER_EVT:
- if (btif_av_cb.sm_handle == NULL)
- {
- btif_av_cb.bta_handle = ((tBTA_AV*)p_param)->registr.hndl;
- BTIF_TRACE_DEBUG("%s: BTA AV Handle updated", __func__);
- }
- /* FALLTHROUGH */
- default:
- btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
- btif_av_event_free_data(event, p_param);
- }
-}
-
void btif_av_event_deep_copy(UINT16 event, char *p_dest, char *p_src)
{
tBTA_AV *av_src = (tBTA_AV *)p_src;
@@ -1100,6 +1941,25 @@
}
}
break;
+ case BTA_AV_BROWSE_MSG_EVT:
+ if (av_src->browse_msg.p_msg)
+ {
+ av_dest->browse_msg.p_msg = osi_calloc(sizeof(tAVRC_MSG));
+ assert(av_dest->browse_msg.p_msg);
+ memcpy(av_dest->browse_msg.p_msg, av_src->browse_msg.p_msg, sizeof(tAVRC_MSG));
+
+ if (av_src->browse_msg.p_msg->browse.p_browse_data &&
+ av_src->browse_msg.p_msg->browse.browse_len)
+ {
+ av_dest->browse_msg.p_msg->browse.p_browse_data = osi_calloc(
+ av_src->browse_msg.p_msg->browse.browse_len);
+ assert(av_dest->browse_msg.p_msg->browse.p_browse_data);
+ memcpy(av_dest->browse_msg.p_msg->browse.p_browse_data,
+ av_src->browse_msg.p_msg->browse.p_browse_data,
+ av_src->browse_msg.p_msg->browse.browse_len);
+ }
+ }
+ break;
default:
break;
@@ -1121,18 +1981,547 @@
}
}
break;
+ case BTA_AV_BROWSE_MSG_EVT:
+ {
+ tBTA_AV *av = (tBTA_AV*)p_data;
+
+ if (av->browse_msg.p_msg)
+ {
+ if (av->browse_msg.p_msg->browse.p_browse_data)
+ osi_free(av->browse_msg.p_msg->browse.p_browse_data);
+ osi_free(av->browse_msg.p_msg);
+ }
+ }
+ break;
default:
break;
}
}
+/*****************************************************************************
+** Local event handlers
+******************************************************************************/
+
+static void btif_av_handle_event(UINT16 event, char* p_param)
+{
+ int index = 0;
+ tBTA_AV *p_bta_data = (tBTA_AV*)p_param;
+ bt_bdaddr_t * bt_addr;
+ UINT8 role;
+ int uuid;
+
+ switch (event)
+ {
+ case BTIF_AV_INIT_REQ_EVT:
+ BTIF_TRACE_IMP("%s: BTIF_AV_INIT_REQ_EVT", __FUNCTION__);
+ if(btif_a2dp_start_media_task())
+ btif_a2dp_on_init();
+ break;
+ /*events from Upper layer and Media Task*/
+ case BTIF_AV_CLEANUP_REQ_EVT: /*Clean up to be called on default index*/
+ BTIF_TRACE_IMP("%s: BTIF_AV_CLEANUP_REQ_EVT", __FUNCTION__);
+ uuid = (int)*p_param;
+ if (uuid == BTA_A2DP_SOURCE_SERVICE_ID)
+ {
+ if (bt_av_src_callbacks)
+ {
+ bt_av_src_callbacks = NULL;
+ if (bt_av_sink_callbacks != NULL)
+ break;
+ }
+ }
+ else
+ {
+ if (bt_av_sink_callbacks)
+ {
+ bt_av_sink_callbacks = NULL;
+ if (bt_av_src_callbacks != NULL)
+ break;
+ }
+ }
+
+ btif_a2dp_stop_media_task();
+ return;
+ case BTIF_AV_CONNECT_REQ_EVT:
+ break;
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+ /*Bd address passed should help us in getting the handle*/
+ bt_addr = (bt_bdaddr_t *)p_param;
+ index = btif_av_idx_by_bdaddr(bt_addr->address);
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ if (bt_split_a2dp_enabled && (btif_av_get_current_playing_dev_idx() == index))
+ {
+ BTIF_TRACE_DEBUG("%s:Disconnecting playing device,send VS STOP",__func__);
+ btif_media_on_stop_vendor_command();
+ }
+#endif
+ break;
+ case BTIF_AV_UPDATE_ENCODER_REQ_EVT:
+ case BTIF_AV_START_STREAM_REQ_EVT:
+ /* Get the last connected device on which START can be issued
+ * Get the Dual A2dp Handoff Device first, if none is present,
+ * go for lastest connected.
+ * In A2dp Multicast, the index selected can be any of the
+ * connected device. Stack will ensure to START the steaming
+ * on both the devices. */
+ index = btif_get_latest_device_idx_to_start();
+ break;
+ case BTIF_AV_STOP_STREAM_REQ_EVT:
+ case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+ /*Should be handled by current STARTED*/
+ index = btif_get_latest_playing_device_idx();
+ if ((index < btif_max_av_clients) && (index == btif_get_is_remote_started_idx()))
+ {
+ BTIF_TRACE_IMP("%s: Postpone handling suspend/stop req @ index = %d",
+ __FUNCTION__, index);
+ return;
+ }
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ if (bt_split_a2dp_enabled)
+ btif_media_on_stop_vendor_command();
+#endif
+ break;
+ case BTIF_AV_REMOTE_SUSPEND_STREAM_REQ_EVT:
+ index = btif_get_is_remote_started_idx();
+ if (index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid index for connection", __FUNCTION__);
+ return;
+ }
+ BTIF_TRACE_IMP("%s: Remote Started set @ index = %d", __FUNCTION__, index);
+ btif_av_cb[index].is_remote_start_received = FALSE;
+ btif_av_cb[index].is_suspend_for_remote_start = TRUE;
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ if ((bt_split_a2dp_enabled) && (!btif_av_is_playing_on_other_idx(index)))
+ {
+ BTIF_TRACE_IMP("%s: Other index is not playing", __FUNCTION__);
+ btif_media_on_stop_vendor_command();
+ }
+#endif
+ event = BTIF_AV_SUSPEND_STREAM_REQ_EVT;
+ break;
+ case BTIF_AV_RESET_REMOTE_STARTED_FLAG_UPDATE_AUDIO_STATE_EVT:
+ index = btif_get_is_remote_started_idx();
+ if (btif_av_cb[index].peer_sep == AVDT_TSEP_SNK)
+ {
+ BTIF_TRACE_IMP("%s: on remote start clean up update audio started state for index %d",
+ __FUNCTION__, index);
+ btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb[index].peer_bda));
+ }
+ case BTIF_AV_RESET_REMOTE_STARTED_FLAG_EVT:
+ btif_av_reset_remote_started_flag();
+ return;
+ /*Events from the stack, BTA*/
+ case BTA_AV_ENABLE_EVT:
+ index = 0;
+ break;
+ case BTA_AV_REGISTER_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->registr.hndl);
+ break;
+ case BTA_AV_OPEN_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->open.hndl);
+ break;
+ case BTA_AV_ROLE_CHANGED_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->role_changed.hndl);
+ role = p_bta_data->role_changed.new_role;
+ BTIF_TRACE_EVENT("Role change: 0x%x: new role: %s",
+ p_bta_data->role_changed.hndl, (role == HOST_ROLE_SLAVE) ? "Slave" : "Master");
+ if (index >= 0 && index < btif_max_av_clients)
+ {
+ btif_av_cb[index].is_slave = (role == HOST_ROLE_SLAVE) ? TRUE : FALSE;
+ btif_av_update_multicast_state(index);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: Invalid index for connection", __FUNCTION__);
+ }
+ return;
+ case BTA_AV_PENDING_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->pend.hndl);
+ break;
+ case BTA_AV_REJECT_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->reject.hndl);
+ break;
+ case BTA_AV_STOP_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->suspend.hndl);
+ break;
+ case BTA_AV_CLOSE_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->close.hndl);
+ break;
+ case BTA_AV_START_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->start.hndl);
+ break;
+ case BTA_AV_RECONFIG_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->reconfig.hndl);
+ break;
+ case BTA_AV_SUSPEND_EVT:
+ index = HANDLE_TO_INDEX(p_bta_data->suspend.hndl);
+ break;
+
+ /* Handle all RC events on default index. RC handling should take
+ * care of the events. All events come with BD Address
+ * Handled well in AV Opening, opened and started state
+ * AV Idle handler needs to take care of this event properly.
+ */
+ case BTA_AV_RC_OPEN_EVT:
+ index = btif_av_get_valid_idx_for_rc_events(p_bta_data->rc_open.peer_addr,
+ p_bta_data->rc_open.rc_handle);
+ break;
+ case BTA_AV_RC_CLOSE_EVT:
+ /* If there is no entry in the connection table
+ * RC handler has to be called for cleanup.
+ * Directly call the RC handler as we cannot
+ * associate any AV handle to it.
+ */
+ index = btif_av_idx_by_bdaddr(p_bta_data->rc_open.peer_addr);
+ if (index == btif_max_av_clients)
+ {
+ btif_rc_handler(event, p_bta_data);
+ }
+ break;
+ case BTA_AV_RC_COLL_DETECTED_EVT:
+ index = btif_av_idx_by_bdaddr(p_bta_data->rc_col_detected.peer_addr);
+ break;
+ /* Let the RC handler decide on these passthrough cmds
+ * Use rc_handle to get the active AV device and use that mapping.
+ */
+ case BTA_AV_REMOTE_CMD_EVT:
+ case BTA_AV_VENDOR_CMD_EVT:
+ case BTA_AV_META_MSG_EVT:
+ case BTA_AV_RC_FEAT_EVT:
+ case BTA_AV_BROWSE_MSG_EVT:
+ index = 0;
+ BTIF_TRACE_EVENT("RC events: on index = %d", index);
+ break;
+ default:
+ BTIF_TRACE_ERROR("Unhandled event = %d", event);
+ break;
+ }
+ BTIF_TRACE_DEBUG("Handle the AV event = %x on index = %d", event, index);
+ if (index >= 0 && index < btif_max_av_clients)
+ btif_sm_dispatch(btif_av_cb[index].sm_handle, event, (void*)p_param);
+ else
+ BTIF_TRACE_ERROR("Unhandled Index = %d", index);
+ btif_av_event_free_data(event, p_param);
+
+}
+
+void btif_av_reset_remote_started_flag()
+{
+ int i;
+ BTIF_TRACE_DEBUG("btif_av_reset_remote_started_flag");
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].is_remote_start_received)
+ btif_av_cb[i].is_remote_start_received = FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_valid_idx
+**
+** Description Check the validity of the current index for the connection
+**
+** Returns Boolean
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_get_valid_idx(int idx)
+{
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb[idx].sm_handle);
+ return ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED) ||
+ (state == BTIF_AV_STATE_OPENING));
+}
+
+/*******************************************************************************
+**
+** Function btif_av_idx_by_bdaddr
+**
+** Description Get the index corresponding to BD addr
+**
+** Returns UNIT8
+**
+*******************************************************************************/
+
+UINT8 btif_av_idx_by_bdaddr(BD_ADDR bd_addr)
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if ((bdcmp(bd_addr,
+ btif_av_cb[i].peer_bda.address) == 0))
+ return i;
+ }
+ return i;
+}
+
+BOOLEAN btif_av_is_current_device(BD_ADDR address)
+{
+ UINT8 index;
+
+ index = btif_av_idx_by_bdaddr(address);
+ if ((index < btif_max_av_clients) && (btif_av_cb[index].current_playing)
+ && (!btif_av_cb[index].is_remote_start_received))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_latest_device_idx_to_start
+**
+** Description Get the index of the AV where streaming is to be started
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_get_latest_device_idx_to_start()
+{
+ int i, j;
+ BD_ADDR playing_address;
+
+ /* Get the device which sent PLAY command
+ * If found, START on that index.
+ */
+ memset(playing_address, 0, sizeof(BD_ADDR));
+ btif_rc_get_playing_device(playing_address);
+ if (bdcmp(playing_address, bd_addr_null) != 0)
+ {
+ /* Got some valid Playing device.
+ * Get the AV index for this device.
+ */
+ i = btif_av_idx_by_bdaddr(playing_address);
+ if (i == btif_max_av_clients)
+ return btif_max_av_clients;
+ BTIF_TRACE_EVENT("Got some valid Playing device; %d", i);
+ /*Clear the Current playing device*/
+ for (j = 0; j < btif_max_av_clients; j++)
+ {
+ if (j != i)
+ btif_av_cb[j].current_playing = FALSE;
+ }
+ /*Clear the Play command in RC*/
+ btif_rc_clear_playing_state(FALSE);
+ return i;
+ }
+
+ /*No playing device, get the latest*/
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].current_playing)
+ break;
+ }
+ if (i == btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("Play on default");
+ i = 0; /*play on default*/
+ }
+ return i;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_latest_playing_device_idx
+**
+** Description Get the index of AV where streaming is happening
+**
+** Returns int
+**
+*******************************************************************************/
+
+int btif_get_latest_playing_device_idx()
+{
+ int i;
+ btif_sm_state_t state;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ {
+ BTIF_TRACE_IMP("Latest playing device index %d", i);
+ break;
+ }
+ }
+ return i;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_is_remote_started_idx
+**
+** Description Get the index of AV where remote Start is received
+**
+** Returns int
+**
+*******************************************************************************/
+
+int btif_get_is_remote_started_idx()
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].is_remote_start_received == TRUE)
+ {
+ BTIF_TRACE_IMP("remote started set for device index %d", i);
+ break;
+ }
+ }
+ return i;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_playing
+**
+** Description Is AV in streaming state
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_playing()
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].state == BTIF_AV_STATE_STARTED)
+ {
+ BTIF_TRACE_EVENT("btif_av_is_playing on index= %d", i);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_get_conn_state_of_device
+**
+** Description Returns the state of AV scb
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_get_conn_state_of_device(BD_ADDR address)
+{
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if ((bdcmp(address,
+ btif_av_cb[i].peer_bda.address) == 0))
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ BTIF_TRACE_EVENT("BD Found: %02X %02X %02X %02X %02X %02X :state: %s",
+ address[5], address[4], address[3],
+ address[2], address[1], address[0],
+ dump_av_sm_state_name(state));
+ }
+ }
+ return state;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_valid_idx_for_rc_events
+**
+** Description gets th valid index for the RC event address
+**
+** Returns int
+**
+*******************************************************************************/
+
+static int btif_av_get_valid_idx_for_rc_events(BD_ADDR bd_addr, int rc_handle)
+{
+ int index = 0;
+ /* First try to find if it is first event in AV IF
+ * both the handles would be in IDLE state, pick the first
+ * If we get second RC event while processing the priority
+ * for the first, reject the second connection. */
+
+ /*Get the index from connected SCBs*/
+ index = btif_av_idx_by_bdaddr(bd_addr);
+ if (index == btif_max_av_clients)
+ {
+ /* None of the SCBS matched
+ * Allocate free SCB, null address SCB*/
+ index = btif_av_idx_by_bdaddr(bd_null);
+ BTIF_TRACE_EVENT("btif_av_get_valid_idx_for_rc_events is %d", index);
+ if (index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_EVENT("disconnect only AVRCP device rc_handle %d", rc_handle);
+ BTA_AvCloseRc(rc_handle);
+ }
+ }
+ return index;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_check_rc_connection_priority
+**
+** Description Handles Priority callback for RC connections
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_av_check_rc_connection_priority(void *p_data)
+{
+ bt_bdaddr_t peer_bda;
+
+ /*Check if it is for same AV device*/
+ if (btif_av_is_device_connected(((tBTA_AV*)p_data)->rc_open.peer_addr))
+ {
+ /*AV is connected */
+ BTIF_TRACE_DEBUG("AV is connected, process RC connect event");
+ btif_rc_handler(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)p_data);
+ return;
+ }
+ BTIF_TRACE_DEBUG("btif_av_check_rc_connection_priority");
+ bdcpy(peer_bda.address, ((tBTA_AV*)p_data)->rc_open.peer_addr);
+
+ if (idle_rc_event != 0)
+ {
+ BTIF_TRACE_DEBUG("Processing another RC Event ");
+ return;
+ }
+ idle_rc_event = BTA_AV_RC_OPEN_EVT;
+ memcpy(&idle_rc_data, ((tBTA_AV*)p_data), sizeof(tBTA_AV));
+ if (((tBTA_AV*)p_data)->rc_open.status == BTA_AV_SUCCESS)
+ {
+ BTIF_TRACE_DEBUG("RC conn is success ");
+ if (bt_av_src_callbacks != NULL)
+ {
+ BTIF_TRACE_DEBUG(" Check Device priority");
+ HAL_CBACK(bt_av_src_callbacks, connection_priority_cb,
+ &peer_bda);
+ }
+ }
+ else
+ {
+ idle_rc_event = 0;
+ memset(&idle_rc_data, 0, sizeof(tBTA_AV));
+ }
+ return;
+}
+
+
static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data)
{
btif_transfer_context(btif_av_handle_event, event,
(char*)p_data, sizeof(tBTA_AV), btif_av_event_deep_copy);
}
+/*Called only in case of A2dp SInk, which runs on index 0*/
static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
{
btif_sm_state_t state;
@@ -1140,10 +2529,11 @@
tA2D_STATUS a2d_status;
tA2D_SBC_CIE sbc_cie;
btif_av_sink_config_req_t config_req;
+ int index =0;
if (event == BTA_AV_MEDIA_DATA_EVT)/* Switch to BTIF_MEDIA context */
{
- state= btif_sm_get_state(btif_av_cb.sm_handle);
+ state= btif_sm_get_state(btif_av_cb[index].sm_handle);
if ( (state == BTIF_AV_STATE_STARTED) || /* send SBC packets only in Started State */
(state == BTIF_AV_STATE_OPENED) )
{
@@ -1171,6 +2561,79 @@
}
}
}
+
+/******************************************************************************
+** Function a2dp_offload_codec_cap_parser
+**
+** Description Parse the offload supported codec capability during init
+**
+** Returns
+*****************************************************************************/
+static void a2dp_offload_codec_cap_parser(const char *value)
+{
+ char *tok = NULL;
+ char *tmp_token = NULL;
+ int size = 0;
+ char *tmp_copy_buf = NULL;
+ if (value == NULL)
+ {
+ BTIF_TRACE_ERROR("%s: Offload String is NULL",__func__);
+ return;
+ }
+ size = strlen(value) + 1;
+ tmp_copy_buf = (char *) osi_malloc (size);
+ if (tmp_copy_buf == NULL)
+ {
+ BTIF_TRACE_ERROR("%s: Memorey allocation failed",__func__);
+ return;
+ }
+ memset(tmp_copy_buf, 0, size);
+ memcpy(tmp_copy_buf, value, size - 1);
+ /* Fix for below Klockwork Issue
+ * 'strtok' has been deprecated; replace it with a safe function. */
+ tok = strtok_r((char*)tmp_copy_buf, "-", &tmp_token);
+ while (tok != NULL)
+ {
+ if (strcmp(tok,"sbc") == 0)
+ {
+ BTIF_TRACE_ERROR("%s: SBC offload supported",__func__);
+ btif_av_codec_offload.sbc_offload = TRUE;
+ }
+ else if (strcmp(tok,"aptx") == 0)
+ {
+ BTIF_TRACE_ERROR("%s: aptX offload supported",__func__);
+ btif_av_codec_offload.aptx_offload = TRUE;
+ }
+ else if (strcmp(tok,"aac") == 0)
+ {
+ BTIF_TRACE_ERROR("%s: AAC offload supported",__func__);
+ btif_av_codec_offload.aac_offload = TRUE;
+ }
+ else if (strcmp(tok,"aptxhd") == 0)
+ {
+ BTIF_TRACE_ERROR("%s: APTXHD offload supported",__func__);
+ btif_av_codec_offload.aptxhd_offload = TRUE;
+ }
+ tok = strtok_r(NULL, "-", &tmp_token);
+ };
+ osi_free_and_reset((void **) &tmp_copy_buf);
+}
+
+/******************************************************************************
+** Function get_offload_codec_capabilities
+**
+** Description Read offload supported codecs
+** To set offload capabilities:
+** adb shell setprop persist.bt.a2dp_offload_cap "sbc-aptx"
+**
+** Returns
+*****************************************************************************/
+static void get_offload_codec_capabilities(const char* codec_cap)
+{
+ BTIF_TRACE_DEBUG("%s",__func__);
+ a2dp_offload_codec_cap_parser(codec_cap);
+ return;
+}
/*******************************************************************************
**
** Function btif_av_init
@@ -1183,20 +2646,29 @@
bt_status_t btif_av_init(int service_id)
{
- if (btif_av_cb.sm_handle == NULL)
+ int i;
+ if (btif_av_cb[0].sm_handle == NULL)
{
alarm_free(av_open_on_rc_timer);
av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");
- if (!btif_a2dp_start_media_task())
+ alarm_free(av_coll_detected_timer);
+ av_coll_detected_timer = alarm_new("btif_av.av_coll_detected_timer");
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ if(!btif_a2dp_is_media_task_stopped())
return BT_STATUS_FAIL;
-
- btif_enable_service(service_id);
+ btif_av_cb[0].service = service_id;
/* Also initialize the AV state machine */
- btif_av_cb.sm_handle =
- btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers,
+ BTIF_AV_STATE_IDLE, i);
+ }
- btif_a2dp_on_init();
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_INIT_REQ_EVT,
+ (char*)&service_id, sizeof(int), NULL);
+
+ btif_enable_service(service_id);
}
return BT_STATUS_SUCCESS;
@@ -1212,13 +2684,36 @@
**
*******************************************************************************/
-static bt_status_t init_src(btav_callbacks_t* callbacks)
+static bt_status_t init_src(btav_callbacks_t* callbacks, int max_a2dp_connections,
+ int a2dp_multicast_state, const char* offload_cap)
{
- BTIF_TRACE_EVENT("%s()", __func__);
+ bt_status_t status;
- bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
- if (status == BT_STATUS_SUCCESS)
+ BTIF_TRACE_EVENT("%s with max conn = %d", __FUNCTION__, max_a2dp_connections);
+
+ if (bt_av_sink_callbacks != NULL) {
+ // already did btif_av_init()
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ if (a2dp_multicast_state)
+ {
+ is_multicast_supported = TRUE;
+ }
+ if (offload_cap)
+ {
+ bt_split_a2dp_enabled = TRUE;
+ get_offload_codec_capabilities(offload_cap);
+ is_multicast_supported = FALSE; //Disable multicast in Split A2dp mode
+ }
+ btif_max_av_clients = max_a2dp_connections;
+ status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
+ }
+
+ if (status == BT_STATUS_SUCCESS) {
bt_av_src_callbacks = callbacks;
+ }
return status;
}
@@ -1233,13 +2728,34 @@
**
*******************************************************************************/
-static bt_status_t init_sink(btav_callbacks_t* callbacks)
+static bt_status_t init_sink(btav_callbacks_t* callbacks, int max,
+ int a2dp_multicast_state, const char *offload_cap)
{
- BTIF_TRACE_EVENT("%s()", __func__);
+ bt_status_t status;
- bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
- if (status == BT_STATUS_SUCCESS)
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+
+ if (bt_av_src_callbacks != NULL) {
+ // already did btif_av_init()
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ enable_multicast = FALSE; // Clear multicast flag for sink
+ bt_split_a2dp_enabled = FALSE; //Clear split a2dp for sink
+ if (max > 1)
+ {
+ BTIF_TRACE_ERROR("Only one Sink can be initialized");
+ max = 1;
+ }
+ btif_max_av_clients = max; //Should be 1
+ status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
+ }
+
+ if (status == BT_STATUS_SUCCESS) {
bt_av_sink_callbacks = callbacks;
+ //BTA_AvEnable_Sink(TRUE);
+ }
return status;
}
@@ -1277,6 +2793,119 @@
}
#endif
+
+void btif_get_latest_playing_device(BD_ADDR address)
+{
+ int index;
+ index = btif_get_latest_playing_device_idx();
+ if (index < btif_max_av_clients)
+ {
+ //copy bdaddrsss
+ bdcpy(address, btif_av_cb[index].peer_bda.address);
+ }
+ else
+ {
+ bdcpy(address, bd_null);
+ }
+}
+
+BOOLEAN btif_av_is_device_connected(BD_ADDR address)
+{
+ btif_sm_state_t state = btif_get_conn_state_of_device(address);
+
+ if ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*This function will trigger remote suspend for currently
+* playing device and then initiate START on Handoff device
+* whose address is passed as an argument. */
+/*******************************************************************************
+**
+** Function btif_av_trigger_dual_handoff
+**
+** Description Trigger the DUAL HANDOFF
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_av_trigger_dual_handoff(BOOLEAN handoff, BD_ADDR address)
+{
+ int index,next_idx;
+ /*Get the current playing device*/
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ index = btif_get_latest_playing_device_idx();
+ if (index != btif_max_av_clients)
+ {
+ btif_av_cb[index].dual_handoff = handoff; /*Initiate Handoff*/
+ if (bt_split_a2dp_enabled)
+ btif_media_on_stop_vendor_command();
+ /*Initiate SUSPEND for this device*/
+
+ next_idx = btif_av_get_other_connected_idx(index);
+ if (next_idx != INVALID_INDEX && next_idx != btif_max_av_clients)
+ {
+ if (btif_av_cb[next_idx].is_remote_start_received)
+ {
+ btif_media_on_cancel_remote_start_alarm();
+ BTIF_TRACE_DEBUG("Reset remote start alarm on index = %d", next_idx);
+ btif_av_cb[next_idx].is_remote_start_received = FALSE;
+ }
+ }
+ BTIF_TRACE_DEBUG("Initiate SUSPEND for this device on index = %d", index);
+ btif_sm_dispatch(btif_av_cb[index].sm_handle, BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("Handoff on invalid index");
+ }
+ if (bt_split_a2dp_enabled)
+ {
+ next_idx = btif_av_get_other_connected_idx(index);
+ /* Fix for below Klockwork Issue
+ Array 'btif_av_cb' of size 2 may use index value(s) -1 */
+ if (next_idx != INVALID_INDEX && next_idx != btif_max_av_clients)
+ {
+ reconfig_a2dp = TRUE;
+ HAL_CBACK(bt_av_src_callbacks, reconfig_a2dp_trigger_cb, 1,
+ &(btif_av_cb[next_idx].peer_bda));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_av_trigger_suspend
+**
+** Description Trigger suspend when multicast is ongoing for tuch tones
+** and new ACL is created.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_av_trigger_suspend()
+{
+ int index;
+ /*Get the current playing device*/
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ index = btif_get_latest_playing_device_idx();
+ if (index <= btif_max_av_clients)
+ {
+ /*Initiate SUSPEND for this device*/
+ BTIF_TRACE_DEBUG("Initiate SUSPEND for this device on index = %d", index);
+ btif_sm_dispatch(btif_av_cb[index].sm_handle, BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("suspend on invalid index");
+ }
+}
+
/*******************************************************************************
**
** Function connect
@@ -1290,11 +2919,49 @@
static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid)
{
btif_av_connect_req_t connect_req;
+ int i;
connect_req.target_bda = bd_addr;
connect_req.uuid = uuid;
BTIF_TRACE_EVENT("%s", __FUNCTION__);
- btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
+ for (i = 0; i < btif_max_av_clients;)
+ {
+ if(btif_av_get_valid_idx(i))
+ {
+ if (bdcmp(bd_addr->address, btif_av_cb[i].peer_bda.address) == 0)
+ {
+ BTIF_TRACE_ERROR("Attempting connection for non idle device.. back off ");
+ btif_queue_advance();
+ return BT_STATUS_SUCCESS;
+ }
+ i++;
+ }
+ else
+ break;
+ }
+ if (i == btif_max_av_clients)
+ {
+ UINT8 rc_handle;
+
+ BTIF_TRACE_ERROR("%s: All indexes are full", __FUNCTION__);
+
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, bd_addr);
+
+ /* Multicast: Check if AV slot is available for connection
+ * If not available, AV got connected to different devices.
+ * Disconnect this RC connection without AV connection.
+ */
+ rc_handle = btif_rc_get_connected_peer_handle(bd_addr->address);
+ if (rc_handle != BTIF_RC_HANDLE_NONE)
+ {
+ BTA_AvCloseRc(rc_handle);
+ }
+ btif_queue_advance();
+ return BT_STATUS_FAIL;
+ }
+
+ btif_sm_dispatch(btif_av_cb[i].sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
+
return BT_STATUS_SUCCESS;
}
@@ -1346,37 +3013,73 @@
*******************************************************************************/
static void cleanup(int service_uuid)
{
- BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ BTIF_TRACE_IMP("AV %s", __FUNCTION__);
- btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0, NULL);
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT,
+ (char*)&service_uuid, sizeof(int), NULL);
btif_disable_service(service_uuid);
-
- /* Also shut down the AV state machine */
- btif_sm_shutdown(btif_av_cb.sm_handle);
- btif_av_cb.sm_handle = NULL;
}
static void cleanup_src(void) {
BTIF_TRACE_EVENT("%s", __FUNCTION__);
-
- if (bt_av_src_callbacks)
- {
- bt_av_src_callbacks = NULL;
- if (bt_av_sink_callbacks == NULL)
- cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
- }
+ cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
+ BTIF_TRACE_EVENT("%s completed", __FUNCTION__);
}
static void cleanup_sink(void) {
BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ cleanup(BTA_A2DP_SINK_SERVICE_ID);
+}
- if (bt_av_sink_callbacks)
+static void allow_connection(int is_valid, bt_bdaddr_t *bd_addr)
+{
+ int index = 0;
+ BTIF_TRACE_DEBUG(" %s isValid is %d event %d", __FUNCTION__,is_valid,idle_rc_event);
+ switch (idle_rc_event)
{
- bt_av_sink_callbacks = NULL;
- if (bt_av_src_callbacks == NULL)
- cleanup(BTA_A2DP_SINK_SERVICE_ID);
+ case BTA_AV_RC_OPEN_EVT:
+ if (is_valid)
+ {
+ BTIF_TRACE_DEBUG("allowconn for RC connection");
+ alarm_set_on_queue(av_open_on_rc_timer,
+ BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
+ btif_initiate_av_open_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ btif_rc_handler(idle_rc_event, &idle_rc_data);
+ }
+ else
+ {
+ UINT8 rc_handle = idle_rc_data.rc_open.rc_handle;
+ BTA_AvCloseRc(rc_handle);
+ }
+ break;
+
+ case BTA_AV_PENDING_EVT:
+ if (is_valid)
+ {
+ index = btif_av_idx_by_bdaddr(bd_addr->address);
+ if (index >= btif_max_av_clients)
+ {
+ BTIF_TRACE_DEBUG("Invalid index for device");
+ break;
+ }
+ BTIF_TRACE_DEBUG("The connection is allowed for the device at index = %d", index);
+ BTA_AvOpen(btif_av_cb[index].peer_bda.address, btif_av_cb[index].bta_handle,
+ TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ else
+ {
+ BTA_AvDisconnect(idle_rc_data.pend.bd_addr);
+ }
+ break;
+
+ default:
+ BTIF_TRACE_DEBUG("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(idle_rc_event));
}
+ idle_rc_event = 0;
+ memset(&idle_rc_data, 0, sizeof(tBTA_AV));
}
static const btav_interface_t bt_av_src_interface = {
@@ -1387,6 +3090,7 @@
cleanup_src,
NULL,
NULL,
+ allow_connection,
};
static const btav_interface_t bt_av_sink_interface = {
@@ -1402,6 +3106,7 @@
NULL,
NULL,
#endif
+ NULL,
};
/*******************************************************************************
@@ -1413,10 +3118,11 @@
** Returns None
**
*******************************************************************************/
-
+/* Media task uses this info
+* But dont use it. */
btif_sm_handle_t btif_av_get_sm_handle(void)
{
- return btif_av_cb.sm_handle;
+ return btif_av_cb[0].sm_handle;
}
/*******************************************************************************
@@ -1429,9 +3135,17 @@
**
*******************************************************************************/
-bt_bdaddr_t btif_av_get_addr(void)
+bt_bdaddr_t btif_av_get_addr(BD_ADDR address)
{
- return btif_av_cb.peer_bda;
+ int i;
+ bt_bdaddr_t not_found ;
+ memset (¬_found, 0, sizeof(bt_bdaddr_t));
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (bdcmp(btif_av_cb[i].peer_bda.address, address) == 0)
+ return btif_av_cb[i].peer_bda;
+ }
+ return not_found;
}
/*******************************************************************************
@@ -1460,11 +3174,8 @@
BOOLEAN btif_av_stream_ready(void)
{
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
-
- BTIF_TRACE_DEBUG("btif_av_stream_ready : sm hdl %d, state %d, flags %x",
- btif_av_cb.sm_handle, state, btif_av_cb.flags);
-
+ int i;
+ BOOLEAN status = FALSE;
/* also make sure main adapter is enabled */
if (btif_is_enabled() == 0)
{
@@ -1472,11 +3183,35 @@
return FALSE;
}
- /* check if we are remotely suspended or stop is pending */
- if (btif_av_cb.flags & (BTIF_AV_FLAG_REMOTE_SUSPEND|BTIF_AV_FLAG_PENDING_STOP))
- return FALSE;
-
- return (state == BTIF_AV_STATE_OPENED);
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ /* Multicast:
+ * If any of the stream is in pending suspend state when
+ * we initiate start, it will result in inconsistent behavior
+ * Check the pending SUSPEND flag and return failure
+ * if suspend is in progress.
+ */
+ BTIF_TRACE_DEBUG("btif_av_stream_ready flags: %d", btif_av_cb[i].flags);
+ if (btif_av_cb[i].dual_handoff ||
+ (btif_av_cb[i].flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING))
+ {
+ status = FALSE;
+ break;
+ }
+ else if (btif_av_cb[i].flags &
+ (BTIF_AV_FLAG_REMOTE_SUSPEND|BTIF_AV_FLAG_PENDING_STOP|BTIF_AV_FLAG_PENDING_DISCONNECT))
+ {
+ status = FALSE;
+ break;
+ }
+ else if (btif_av_cb[i].state == BTIF_AV_STATE_OPENED)
+ {
+ status = TRUE;
+ }
+ }
+ BTIF_TRACE_DEBUG("btif_av_stream_ready: %d", status);
+ return status;
}
/*******************************************************************************
@@ -1491,19 +3226,68 @@
BOOLEAN btif_av_stream_started_ready(void)
{
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ int i;
+ BOOLEAN status = FALSE;
- BTIF_TRACE_DEBUG("btif_av_stream_started : sm hdl %d, state %d, flags %x",
- btif_av_cb.sm_handle, state, btif_av_cb.flags);
-
- /* disallow media task to start if we have pending actions */
- if (btif_av_cb.flags & (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND
- | BTIF_AV_FLAG_PENDING_STOP))
- return FALSE;
-
- return (state == BTIF_AV_STATE_STARTED);
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].dual_handoff)
+ {
+ BTIF_TRACE_ERROR("%s: Under Dual handoff ",__FUNCTION__ );
+ status = FALSE;
+ break;
+ } else if (btif_av_cb[i].flags &
+ (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING |
+ BTIF_AV_FLAG_REMOTE_SUSPEND |
+ BTIF_AV_FLAG_PENDING_STOP))
+ {
+ status = FALSE;
+ break;
+ } else if (btif_av_cb[i].state == BTIF_AV_STATE_STARTED)
+ {
+ status = TRUE;
+ }
+ }
+ BTIF_TRACE_DEBUG("btif_av_stream_started_ready: %d", status);
+ return status;
}
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/*******************************************************************************
+**
+** Function btif_av_stream_started_ready
+**
+** Description Checks whether AV ready for media start in streaming state
+**
+** Returns None
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_suspend_stop_pending_ack(void)
+{
+ int i;
+ BOOLEAN status = FALSE;
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ BTIF_TRACE_DEBUG("btif_av_stream_ready flags: %d, state: %d",
+ btif_av_cb[i].flags, btif_av_cb[i].state);
+ if ((btif_av_cb[i].flags &
+ (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING |
+ BTIF_AV_FLAG_PENDING_STOP)) &&
+ (btif_av_cb[i].state == BTIF_AV_STATE_STARTED))
+ {
+ status = TRUE;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG("btif_av_is_stream_suspend_pending_ack: %d", status);
+ return status;
+}
+#endif
+
/*******************************************************************************
**
** Function btif_dispatch_sm_event
@@ -1518,8 +3302,10 @@
void btif_dispatch_sm_event(btif_av_sm_event_t event, void *p_data, int len)
{
/* Switch to BTIF context */
+ BTIF_TRACE_IMP("%s: event: %d, len: %d", __FUNCTION__, event, len);
btif_transfer_context(btif_av_handle_event, event,
(char*)p_data, len, NULL);
+ BTIF_TRACE_IMP("%s: event %d sent", __FUNCTION__, event);
}
/*******************************************************************************
@@ -1533,37 +3319,66 @@
*******************************************************************************/
bt_status_t btif_av_execute_service(BOOLEAN b_enable)
{
- if (b_enable)
- {
- /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
- * handle this request in order to allow incoming connections to succeed.
- * We need to put this back once support for this is added */
+ int i;
+ btif_sm_state_t state;
+ BTIF_TRACE_IMP("%s: enable: %d", __FUNCTION__, b_enable);
+ if (b_enable)
+ {
+ /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+ * handle this request in order to allow incoming connections to succeed.
+ * We need to put this back once support for this is added */
- /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
- * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
- * be initiated by the app/audioflinger layers */
- /* Support for browsing for SDP record should work only if we enable BROWSE
- * while registering. */
+ /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
#if (AVRC_METADATA_INCLUDED == TRUE)
- BTA_AvEnable(BTA_SEC_AUTHENTICATE,
- BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+ BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
+ |BTA_AV_FEAT_ACP_START
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- |BTA_AV_FEAT_RCCT
- |BTA_AV_FEAT_ADV_CTRL
+ |BTA_AV_FEAT_RCCT
+ |BTA_AV_FEAT_ADV_CTRL
+ |BTA_AV_FEAT_BROWSE
#endif
- ,bte_av_callback);
+ ,bte_av_callback);
#else
- BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD),
- bte_av_callback);
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD
+ |BTA_AV_FEAT_ACP_START), bte_av_callback);
#endif
- BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
- UUID_SERVCLASS_AUDIO_SOURCE);
- }
- else {
- BTA_AvDeregister(btif_av_cb.bta_handle);
- BTA_AvDisable();
- }
- return BT_STATUS_SUCCESS;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ BTIF_TRACE_DEBUG("%s: BTA_AvRegister : %d", __FUNCTION__, i);
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
+ UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ BTA_AvUpdateMaxAVClient(btif_max_av_clients);
+ }
+ else
+ {
+ /* Also shut down the AV state machine */
+ for (i = 0; i < btif_max_av_clients; i++ )
+ {
+ if (btif_av_cb[i].sm_handle != NULL)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if(state==BTIF_AV_STATE_OPENING)
+ {
+ BTIF_TRACE_DEBUG("Moving State from Opening to Idle due to BT ShutDown");
+ btif_sm_change_state(btif_av_cb[i].sm_handle, BTIF_AV_STATE_IDLE);
+ btif_queue_advance();
+ }
+ btif_sm_shutdown(btif_av_cb[i].sm_handle);
+ btif_av_cb[i].sm_handle = NULL;
+ }
+ }
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ BTA_AvDeregister(btif_av_cb[i].bta_handle);
+ }
+ BTA_AvDisable();
+ }
+ BTIF_TRACE_IMP("%s: enable: %d completed", __FUNCTION__, b_enable);
+ return BT_STATUS_SUCCESS;
}
/*******************************************************************************
@@ -1577,6 +3392,9 @@
*******************************************************************************/
bt_status_t btif_av_sink_execute_service(BOOLEAN b_enable)
{
+ int i;
+ BTIF_TRACE_IMP("%s: enable: %d", __FUNCTION__, b_enable);
+
if (b_enable)
{
/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
@@ -1590,9 +3408,20 @@
UUID_SERVCLASS_AUDIO_SINK);
}
else {
- BTA_AvDeregister(btif_av_cb.bta_handle);
- BTA_AvDisable();
+ /* Also shut down the AV state machine */
+ for (i = 0; i < btif_max_av_clients; i++ )
+ {
+ if (btif_av_cb[i].sm_handle != NULL)
+ {
+ BTIF_TRACE_IMP("%s: shutting down AV SM", __FUNCTION__);
+ btif_sm_shutdown(btif_av_cb[i].sm_handle);
+ btif_av_cb[i].sm_handle = NULL;
+ }
+ }
+ BTA_AvDeregister(btif_av_cb[0].bta_handle);
+ BTA_AvDisable();
}
+ BTIF_TRACE_IMP("%s: enable: %d completed", __FUNCTION__, b_enable);
return BT_STATUS_SUCCESS;
}
@@ -1637,8 +3466,119 @@
*******************************************************************************/
BOOLEAN btif_av_is_connected(void)
{
- btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
- return ((state == BTIF_AV_STATE_OPENED) || (state == BTIF_AV_STATE_STARTED));
+ int i;
+ BOOLEAN status = FALSE;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((btif_av_cb[i].state == BTIF_AV_STATE_OPENED) ||
+ (btif_av_cb[i].state == BTIF_AV_STATE_STARTED))
+ status = TRUE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_connected_on_other_idx
+**
+** Description Checks if any other AV SCB is connected
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_connected_on_other_idx(int current_index)
+{
+ //return true if other IDx is connected
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != current_index)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_other_connected_idx
+**
+** Description Checks if any AV SCB is connected other than the current
+** index
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+int btif_av_get_other_connected_idx(int current_index)
+{
+ //return true if other IDx is connected
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != current_index)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED))
+ return i;
+ }
+ }
+ return INVALID_INDEX;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_playing_on_other_idx
+**
+** Description Checks if any other AV SCB is connected
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_is_playing_on_other_idx(int current_index)
+{
+ //return true if other IDx is playing
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != current_index)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_update_current_playing_device
+**
+** Description Update the next connected device as playing
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_av_update_current_playing_device(int index)
+{
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (i != index)
+ btif_av_cb[i].current_playing = TRUE;
+ }
}
/*******************************************************************************
@@ -1655,12 +3595,91 @@
*******************************************************************************/
BOOLEAN btif_av_is_peer_edr(void)
{
+ btif_sm_state_t state;
+ BOOLEAN peer_edr = FALSE;
+
ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
- if (btif_av_cb.edr)
- return TRUE;
- else
- return FALSE;
+ /* If any of the remote in streaming state is BR
+ * return FALSE to ensure proper configuration
+ * is used. Ideally, since multicast is not supported
+ * if any of the connected device is BR device,
+ * we should not see both devices in START state.
+ */
+ for (int index = 0; index < btif_max_av_clients; index ++)
+ {
+ state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)
+ || (state == BTIF_AV_STATE_STARTED))
+ {
+ if (btif_av_cb[index].edr)
+ {
+ peer_edr = TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ }
+ return peer_edr;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_any_br_peer
+**
+** Description Check if the any of connected devices is BR device.
+**
+** Returns TRUE if connected to any BR device, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btif_av_any_br_peer(void)
+{
+ btif_sm_state_t state;
+ for (int index = 0; index < btif_max_av_clients; index ++)
+ {
+ state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ if (state >= BTIF_AV_STATE_OPENED)
+ {
+ if (!btif_av_cb[index].edr)
+ {
+ BTIF_TRACE_WARNING("%s : Connected to BR device :", __FUNCTION__);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_peer_supports_3mbps
+**
+** Description check if the connected a2dp device supports
+** 3mbps edr. Only when connected this function
+** will accurately provide a true capability of
+** remote peer. If not connected it will always be false.
+**
+** Returns TRUE if remote device is EDR and supports 3mbps
+**
+*******************************************************************************/
+BOOLEAN btif_av_peer_supports_3mbps(void)
+{
+ btif_sm_state_t state;
+ ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
+
+ for (int index = 0; index < btif_max_av_clients; index ++)
+ {
+ state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ if ((btif_av_cb[index].flags & BTIF_AV_FLAG_PENDING_START)
+ || (state == BTIF_AV_STATE_STARTED))
+ {
+ if(btif_av_cb[index].edr_3mbps)
+ return TRUE;
+ }
+ }
+ return FALSE;
}
/******************************************************************************
@@ -1669,29 +3688,472 @@
**
** Description Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
**
-** Returns void
+** Returns void
******************************************************************************/
void btif_av_clear_remote_suspend_flag(void)
{
- BTIF_TRACE_DEBUG("%s: flag :%x",__func__, btif_av_cb.flags);
- btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ int i;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ BTIF_TRACE_DEBUG(" flag :%x",btif_av_cb[i].flags);
+ btif_av_cb[i].flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ }
}
/*******************************************************************************
**
-** Function btif_av_peer_supports_3mbps
+** Function btif_av_move_idle
**
-** Description Check if the connected A2DP device supports
-** 3 Mbps EDR. This function only works if connected.
-** If not connected it will always be false.
+** Description Opening state is intermediate state. It cannot handle
+** incoming/outgoing connect/disconnect requests.When ACL
+** is disconnected and we are in opening state then move back
+** to idle state which is proper to handle connections.
**
-** Returns TRUE if remote device is EDR and supports 3 Mbps
+** Returns Void
**
*******************************************************************************/
-BOOLEAN btif_av_peer_supports_3mbps(void)
+void btif_av_move_idle(bt_bdaddr_t bd_addr)
{
- BOOLEAN is3mbps = ((btif_av_cb.edr & BTA_AV_EDR_3MBPS) != 0);
- BTIF_TRACE_DEBUG("%s: connected %d, edr_3mbps %d", __func__,
- btif_av_is_connected(), is3mbps);
- return (btif_av_is_connected() && is3mbps);
+ int index =0;
+ /* inform the application that ACL is disconnected and move to idle state */
+ index = btif_av_idx_by_bdaddr(bd_addr.address);
+ if (index == btif_max_av_clients)
+ {
+ BTIF_TRACE_DEBUG("btif_av_move_idle: Already in IDLE");
+ return;
+ }
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb[index].sm_handle);
+ BTIF_TRACE_DEBUG("ACL Disconnected state %d is same device %d",state,
+ memcmp (&bd_addr, &(btif_av_cb[index].peer_bda), sizeof(bd_addr)));
+ if (state == BTIF_AV_STATE_OPENING &&
+ (memcmp (&bd_addr, &(btif_av_cb[index].peer_bda), sizeof(bd_addr)) == 0))
+ {
+ BTIF_TRACE_DEBUG("Moving BTIF State from Opening to Idle due to ACL disconnect");
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb[index].peer_bda));
+ BTA_AvClose(btif_av_cb[index].bta_handle);
+ btif_sm_change_state(btif_av_cb[index].sm_handle, BTIF_AV_STATE_IDLE);
+ btif_queue_advance();
+ btif_av_check_and_start_collission_timer(index);
+ }
}
+/******************************************************************************
+**
+** Function btif_av_get_num_playing_devices
+**
+** Description Return number of A2dp playing devices
+**
+** Returns int
+******************************************************************************/
+UINT16 btif_av_get_num_playing_devices(void)
+{
+ UINT16 i;
+ UINT16 playing_devices = 0;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].state == BTIF_AV_STATE_STARTED)
+ {
+ playing_devices++;
+ }
+ }
+ BTIF_TRACE_DEBUG("AV devices playing: %d", playing_devices);
+
+ return playing_devices;
+}
+/*******************************************************************************
+**
+** Function btif_av_get_num_connected_devices
+**
+** Description Return number of A2dp connected devices
+**
+** Returns int
+******************************************************************************/
+UINT16 btif_av_get_num_connected_devices(void)
+{
+ UINT16 i;
+ UINT16 connected_devies = 0;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ btif_av_cb[i].state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((btif_av_cb[i].state == BTIF_AV_STATE_OPENED) ||
+ (btif_av_cb[i].state == BTIF_AV_STATE_STARTED))
+ {
+ connected_devies++;
+ }
+ }
+ BTIF_TRACE_DEBUG("AV Connection count: %d", connected_devies);
+
+ return connected_devies;
+}
+
+/******************************************************************************
+**
+** Function btif_av_update_multicast_state
+**
+** Description Enable Multicast only if below conditions are satisfied
+** 1. Connected to only 2 EDR HS.
+** 2. Connected to both HS as master.
+** 3. Connected to 2 EDR HS and one BLE device
+** Multicast will fall back to soft handsoff in below conditions
+** 1. Number of ACL links is more than 2,like connected to HID
+** initiating connection for HS1 and HS2.
+** 2. Connected to BR and EDR HS.
+** 3. Connected to more then 1 BLE device
+**
+** Returns void
+******************************************************************************/
+void btif_av_update_multicast_state(int index)
+{
+ UINT16 num_connected_br_edr_devices = 0;
+ UINT16 num_connected_le_devices = 0;
+ UINT16 num_av_connected = 0;
+ UINT16 i = 0;
+ BOOLEAN is_slave = FALSE;
+ BOOLEAN is_br_hs_connected = FALSE;
+ BOOLEAN prev_multicast_state = enable_multicast;
+
+ if (!is_multicast_supported)
+ {
+ BTIF_TRACE_DEBUG("%s Multicast is Disabled", __FUNCTION__);
+ return;
+ }
+
+ if (multicast_disabled == TRUE)
+ {
+ multicast_disabled = FALSE;
+ enable_multicast = FALSE;
+ BTA_AvEnableMultiCast(FALSE, btif_av_cb[index].bta_handle);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG("%s Multicast previous state : %s", __FUNCTION__,
+ enable_multicast ? "Enabled" : "Disabled" );
+
+ num_connected_br_edr_devices = btif_dm_get_br_edr_links();
+ num_connected_le_devices = btif_dm_get_le_links();
+ num_av_connected = btif_av_get_num_connected_devices();
+ is_br_hs_connected = btif_av_any_br_peer();
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].is_slave == TRUE)
+ {
+ BTIF_TRACE_WARNING("Conected as slave");
+ is_slave = TRUE;
+ break;
+ }
+ }
+
+ if ((num_av_connected <= 2) && (is_br_hs_connected != TRUE) &&
+ (is_slave == FALSE) && ((num_connected_br_edr_devices <= 2) &&
+ (num_connected_le_devices <= 1)))
+ {
+ enable_multicast = TRUE;
+ }
+ else
+ {
+ enable_multicast = FALSE;
+ }
+
+ BTIF_TRACE_DEBUG("%s Multicast current state : %s", __FUNCTION__,
+ enable_multicast ? "Enabled" : "Disabled" );
+
+ if (prev_multicast_state != enable_multicast)
+ {
+ BTA_AvEnableMultiCast(enable_multicast,
+ btif_av_cb[index].bta_handle);
+ HAL_CBACK(bt_av_src_callbacks, multicast_state_cb,
+ enable_multicast);
+ }
+}
+/******************************************************************************
+**
+** Function btif_av_get_multicast_state
+**
+** Description Returns TRUE if multicast is enabled else false
+**
+** Returns BOOLEAN
+******************************************************************************/
+BOOLEAN btif_av_get_multicast_state()
+{
+ return enable_multicast;
+}
+/******************************************************************************
+**
+** Function btif_av_get_ongoing_multicast
+**
+** Description Returns TRUE if multicast is ongoing
+**
+** Returns BOOLEAN
+******************************************************************************/
+BOOLEAN btif_av_get_ongoing_multicast()
+{
+ int i = 0, j = 0;
+ if (!is_multicast_supported)
+ {
+ BTIF_TRACE_DEBUG("Multicast is Disabled");
+ return FALSE;
+ }
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].is_device_playing)
+ {
+ j++;
+ }
+ }
+ if (j == btif_max_av_clients)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/******************************************************************************
+**
+** Function btif_av_is_multicast_supported
+**
+** Description Returns TRUE if multicast is supported
+**
+** Returns BOOLEAN
+******************************************************************************/
+BOOLEAN btif_av_is_multicast_supported()
+{
+ return is_multicast_supported;
+}
+
+BOOLEAN btif_av_check_flag_remote_suspend(int index)
+{
+ BTIF_TRACE_ERROR("%s: index = %d",__FUNCTION__,index);
+ if (btif_av_cb[index].flags & BTIF_AV_FLAG_REMOTE_SUSPEND)
+ {
+ BTIF_TRACE_DEBUG("remote suspend flag set on index = %d",index);
+ return TRUE;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("remote suspend flag not set on index = %d",index);
+ return FALSE;
+ }
+}
+
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+int btif_av_get_current_playing_dev_idx(void)
+{
+ int i;
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].current_playing == TRUE)
+ {
+ BTIF_TRACE_DEBUG("current playing on index = %d",i);
+ return i;
+ }
+ }
+ return -1;
+}
+/******************************************************************************
+**
+** Function btif_av_get_streaming_channel_id
+**
+** Description Returns streaming channel id
+**
+** Returns channel id
+********************************************************************************/
+UINT16 btif_av_get_streaming_channel_id(void)
+{
+ int index;
+
+ index = btif_av_get_current_playing_dev_idx();
+ if (index != -1)
+ {
+ BTIF_TRACE_DEBUG("btif_av_get_streaming_channel_id: %u",
+ btif_av_cb[index].channel_id);
+ return btif_av_cb[index].channel_id;
+ }
+ return 0;
+}
+
+/******************************************************************************
+**
+** Function btif_av_get_peer_addr
+**
+** Description Returns peer device address.
+**
+** Returns peer address
+********************************************************************************/
+void btif_av_get_peer_addr(bt_bdaddr_t *peer_bda)
+{
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ int i;
+ memset(peer_bda, 0, sizeof(bt_bdaddr_t));
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if ((state == BTIF_AV_STATE_OPENED) ||
+ (state == BTIF_AV_STATE_STARTED))
+ {
+ BTIF_TRACE_DEBUG("btif_av_get_peer_addr: %u state: %d ",
+ btif_av_cb[i].peer_bda, state);
+ memset(peer_bda, 0, sizeof(bt_bdaddr_t));
+ memcpy(peer_bda, &btif_av_cb[i].peer_bda,
+ sizeof(bt_bdaddr_t));
+ if (state == BTIF_AV_STATE_STARTED)
+ break;
+ }
+ }
+}
+
+/******************************************************************************
+**
+** Function btif_av_get_playing_device_hdl
+**
+** Description Returns current playing device's bta handle
+**
+** Returns BTA HANDLE
+********************************************************************************/
+tBTA_AV_HNDL btif_av_get_playing_device_hdl()
+{
+ int i;
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (state == BTIF_AV_STATE_STARTED)
+ {
+ return btif_av_cb[i].bta_handle;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************
+**
+** Function btif_av_get_av_hdl_from_idx
+**
+** Description Returns bta handle from the device index
+**
+** Returns BTA HANDLE
+********************************************************************************/
+tBTA_AV_HNDL btif_av_get_av_hdl_from_idx(UINT8 idx)
+{
+ if (idx == btif_max_av_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid handle",__func__);
+ return -1;
+ }
+ return btif_av_cb[idx].bta_handle;
+}
+
+/******************************************************************************
+**
+** Function btif_av_is_codec_offload_supported
+**
+** Description check if the correpsonding codec is supported in offload
+**
+** Returns TRUE if supported, FALSE otherwise
+********************************************************************************/
+BOOLEAN btif_av_is_codec_offload_supported(int codec)
+{
+ BOOLEAN ret = FALSE;
+ int retval;
+ char value[255] = "false";
+
+ BTIF_TRACE_DEBUG("btif_av_is_codec_offload_supported = %s",dump_av_codec_name(codec));
+ switch(codec)
+ {
+ case SBC:
+ ret = btif_av_codec_offload.sbc_offload;
+ break;
+ case APTX:
+ ret = btif_av_codec_offload.aptx_offload;
+ break;
+ case AAC:
+ ret = btif_av_codec_offload.aac_offload;
+ retval = property_get("persist.bt.a2dp.aac_disable", value, "false");
+ BTIF_TRACE_DEBUG("%s: property_get: bt.a2dp.aac_disable: %s, retval: %d", __func__, value, retval);
+ if (strncmp(value, "true", 5) == 0) {
+ ret = FALSE;
+ }
+ break;
+ case APTXHD:
+ ret = btif_av_codec_offload.aptxhd_offload;
+ break;
+ default:
+ ret = FALSE;
+ }
+ BTIF_TRACE_DEBUG("btif_av_is_codec_offload_supported %s codec supported = %d",dump_av_codec_name(codec),ret);
+ return ret;
+}
+
+/******************************************************************************
+**
+** Function btif_av_is_under_handoff
+**
+** Description check if AV state is under handoff
+**
+** Returns TRUE if handoff is triggered, FALSE otherwise
+********************************************************************************/
+BOOLEAN btif_av_is_under_handoff()
+{
+ int i;
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+
+ BTIF_TRACE_DEBUG("btif_av_is_under_handoff");
+
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ if (btif_av_cb[i].dual_handoff &&
+ (state == BTIF_AV_STATE_STARTED || state == BTIF_AV_STATE_OPENED))
+ {
+ /* If a2dp reconfigure is triggered when playing device disconnect is
+ * initiated locally then return false, otherwise wait till the suspend cfm
+ * is received from the remote.
+ */
+ BTIF_TRACE_DEBUG("AV is under handoff");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOLEAN btif_av_is_device_disconnecting()
+{
+ int i;
+ btif_sm_state_t state = BTIF_AV_STATE_IDLE;
+ BTIF_TRACE_DEBUG("btif_av_is_device_disconnecting");
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ state = btif_sm_get_state(btif_av_cb[i].sm_handle);
+ BTIF_TRACE_DEBUG("%s: state = %d",__func__,state);
+ if ((btif_av_cb[i].dual_handoff &&
+ state == BTIF_AV_STATE_CLOSING))
+ {
+ BTIF_TRACE_DEBUG("Device disconnecting");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void btif_av_reset_reconfig_flag()
+{
+ int i;
+ BTIF_TRACE_DEBUG("%s",__func__);
+ reconfig_a2dp = FALSE;
+ for (i = 0; i < btif_max_av_clients; i++)
+ {
+ if (btif_av_cb[i].dual_handoff)
+ {
+ BTIF_TRACE_DEBUG("%s resetting dual handoff flag for index %d",
+ __func__, i);
+ btif_av_cb[i].dual_handoff = FALSE;
+ }
+ }
+}
+#endif
+
diff --git a/btif/src/btif_avrcp_audio_track.cpp b/btif/src/btif_avrcp_audio_track.cpp
index cd9cf9a..89d2a5f 100644
--- a/btif/src/btif_avrcp_audio_track.cpp
+++ b/btif/src/btif_avrcp_audio_track.cpp
@@ -15,6 +15,8 @@
*/
//#define LOG_NDEBUG 0
+#define LOG_TAG "bt_btif_avrcp_audio_track"
+
#include "btif_avrcp_audio_track.h"
#include <media/AudioTrack.h>
diff --git a/btif/src/btif_config.c b/btif/src/btif_config.c
index d5fb323..b2b4b68 100644
--- a/btif/src/btif_config.c
+++ b/btif/src/btif_config.c
@@ -188,8 +188,10 @@
} else {
time_t current_time = time(NULL);
struct tm* time_created = localtime(¤t_time);
- strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT, time_created);
- config_set_string(config, INFO_SECTION, FILE_TIMESTAMP, btif_config_time_created);
+ if (time_created) {
+ strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT, time_created);
+ config_set_string(config, INFO_SECTION, FILE_TIMESTAMP, btif_config_time_created);
+ }
}
// TODO(sharvil): use a non-wake alarm for this once we have
diff --git a/btif/src/btif_config_transcode.cpp b/btif/src/btif_config_transcode.cpp
index e9d859e..e8bd1a2 100644
--- a/btif/src/btif_config_transcode.cpp
+++ b/btif/src/btif_config_transcode.cpp
@@ -31,19 +31,19 @@
XMLDocument document;
int error = document.LoadFile(xml_filename);
if (error != XML_SUCCESS) {
- LOG_ERROR("%s unable to load XML file '%s': %d", __func__, xml_filename, error);
+ LOG_ERROR(LOG_TAG, "%s unable to load XML file '%s': %d", __func__, xml_filename, error);
return NULL;
}
XMLElement *rootElement = document.RootElement();
if (!rootElement) {
- LOG_ERROR("%s unable to find root element; assuming corrupted config file.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to find root element; assuming corrupted config file.", __func__);
return NULL;
}
config_t *config = config_new_empty();
if (!config) {
- LOG_ERROR("%s unable to allocate config object.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate config object.", __func__);
return NULL;
}
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
index c74c6dd..ef73e89 100644
--- a/btif/src/btif_core.c
+++ b/btif/src/btif_core.c
@@ -45,7 +45,6 @@
#include "btif_api.h"
#include "btif_av.h"
#include "btif_config.h"
-#include "btif_config.h"
#include "btif_pan.h"
#include "btif_profile_queue.h"
#include "btif_sock.h"
@@ -76,6 +75,12 @@
#endif // defined(OS_GENERIC)
#endif // BTE_DID_CONF_FILE
+#define VENDOR_PERSISTENCE_PATH "/persist/bluetooth"
+#define VENDOR_BT_NV_FILE_NAME ".bt_nv.bin"
+#define VENDOR_PAYLOAD_MAXLENGTH (260)
+#define VENDOR_MAX_CMD_HDR_SIZE (3)
+#define VENDOR_BD_ADDR_TYPE (1)
+
/************************************************************************************
** Local type definitions
************************************************************************************/
@@ -125,6 +130,8 @@
static const char *BT_JNI_WORKQUEUE_NAME = "bt_jni_workqueue";
static uid_set_t* uid_set = NULL;
+static BOOLEAN ssr_triggered = FALSE;
+
/************************************************************************************
** Static functions
************************************************************************************/
@@ -170,17 +177,20 @@
static void btif_context_switched(void *p_msg)
{
-
- BTIF_TRACE_VERBOSE("btif_context_switched");
-
tBTIF_CONTEXT_SWITCH_CBACK *p = (tBTIF_CONTEXT_SWITCH_CBACK *) p_msg;
/* each callback knows how to parse the data */
if (p->p_cb)
+ {
+ BTIF_TRACE_VERBOSE("btif_context_switched for event: %u", p->event);
p->p_cb(p->event, p->p_param);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("btif_context_switched with null callback");
+ }
}
-
/*******************************************************************************
**
** Function btif_transfer_context
@@ -328,6 +338,60 @@
}
return FALSE;
}
+static bool fetch_vendor_addr (bt_bdaddr_t *local_addr)
+{
+ int addr_fd, i;
+ int bytes_read = 0;
+ bool status = false;
+ unsigned char payload[VENDOR_PAYLOAD_MAXLENGTH];
+ unsigned char header[VENDOR_MAX_CMD_HDR_SIZE];
+ char filename[NAME_MAX];
+
+ snprintf(filename, NAME_MAX, "%s/%s",VENDOR_PERSISTENCE_PATH,VENDOR_BT_NV_FILE_NAME);
+ BTIF_TRACE_VERBOSE("Opening file '%s' for reading\n",filename);
+
+ /* Open the Vendor BD Addr file */
+ addr_fd = open(filename, O_RDONLY);
+ if(addr_fd < 0)
+ {
+ BTIF_TRACE_ERROR("Open of Vendor BD addr file failed\n");
+ return false;
+ }
+
+ while((bytes_read = read(addr_fd, header, VENDOR_MAX_CMD_HDR_SIZE)) &&
+ (bytes_read == 0 || bytes_read == VENDOR_MAX_CMD_HDR_SIZE))
+ {
+ if( VENDOR_BD_ADDR_TYPE == header[0])
+ {
+ if(read(addr_fd, local_addr, header[2]) == header[2])
+ {
+ BTIF_TRACE_WARNING("Read the Vendor BD addr from '%s'\n",filename);
+ status = true;
+ }
+ }
+ else
+ {
+ if(read(addr_fd, payload, header[2]) == header[2])
+ {
+ continue;
+ }
+ }
+ }
+
+ if (status) // swap bd address
+ {
+ char swap;
+
+ for (i = 0 ; i < 3; i++) {
+ swap = local_addr->address[i];
+ local_addr->address[i] = local_addr->address[5-i];
+ local_addr->address[5-i] = swap;
+ }
+ }
+
+ close(addr_fd);
+ return status;
+}
static void btif_fetch_local_bdaddr(bt_bdaddr_t *local_addr)
{
@@ -380,6 +444,26 @@
valid_bda = btif_fetch_property(FACTORY_BT_ADDR_PROPERTY, local_addr);
}
+ /* No factory BDADDR found. Look for BDA in ro.boot.btmacaddr */
+ if ((!valid_bda) && \
+ (property_get("ro.boot.btmacaddr", val, NULL)))
+ {
+ valid_bda = string_to_bdaddr(val, local_addr);
+ if (valid_bda) {
+ BTIF_TRACE_DEBUG("Got vendor BDA %02X:%02X:%02X:%02X:%02X:%02X",
+ local_addr->address[0], local_addr->address[1], local_addr->address[2],
+ local_addr->address[3], local_addr->address[4], local_addr->address[5]);
+ }
+ }
+
+ if (!valid_bda && fetch_vendor_addr(local_addr))
+ {
+ valid_bda = TRUE;
+ BTIF_TRACE_DEBUG("Got Vendor BDA %02X:%02X:%02X:%02X:%02X:%02X",
+ local_addr->address[0], local_addr->address[1], local_addr->address[2],
+ local_addr->address[3], local_addr->address[4], local_addr->address[5]);
+ }
+
/* Generate new BDA if necessary */
if (!valid_bda)
{
@@ -472,6 +556,8 @@
BTIF_TRACE_DEBUG("%s: status %d, local bd [%s]", __FUNCTION__, status, bdstr);
+ ssr_triggered = FALSE;
+
if (bdcmp(btif_local_bd_addr.address, controller->get_address()->address))
{
// TODO(zachoverflow): this whole code path seems like a bad time waiting to happen
@@ -521,12 +607,12 @@
/* init rfcomm & l2cap api */
btif_sock_init(uid_set);
- /* init pan */
- btif_pan_init();
-
/* load did configuration */
bte_load_did_conf(BTE_DID_CONF_FILE);
+ /* init pan */
+ btif_pan_init();
+
#ifdef BTIF_DM_OOB_TEST
btif_dm_load_local_oob();
#endif
@@ -583,7 +669,11 @@
void btif_disable_bluetooth_evt(void)
{
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
-
+ if (ssr_triggered == TRUE)
+ {
+ BTIF_TRACE_DEBUG("%s SSR triggered,Ignore EVT",__FUNCTION__);
+ return;
+ }
#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
bte_main_enable_lpm(FALSE);
#endif
@@ -629,6 +719,62 @@
}
/*******************************************************************************
+Function btif_ssrcleanup
+Description Trigger SSR when Disable timeout occured
+
+*******************************************************************************/
+void btif_ssr_cleanup(void)
+{
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ ssr_triggered = TRUE;
+ bte_ssr_cleanup(0x11);//SSR reason 0x11 - ENABLE_TIMEOUT
+}
+
+/*******************************************************************************
+**
+** BTIF Test Mode APIs
+**
+*****************************************************************************/
+#if HCI_RAW_CMD_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btif_hci_event_cback
+**
+** Description Callback invoked on receiving HCI event
+**
+** Returns None
+**
+*******************************************************************************/
+static void btif_hci_event_cback ( tBTM_RAW_CMPL *p )
+{
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ if((p != NULL) && (bt_hal_cbacks != NULL)
+ && (bt_hal_cbacks->hci_event_recv_cb != NULL))
+ {
+ HAL_CBACK(bt_hal_cbacks, hci_event_recv_cb, p->event_code, p->p_param_buf,
+ p->param_len);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hci_cmd_send
+**
+** Description Sends a HCI raw command to the controller
+**
+** Returns BT_STATUS_SUCCESS on success
+**
+*******************************************************************************/
+bt_status_t btif_hci_cmd_send(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+
+ BTM_Hci_Raw_Command(opcode, len, buf, btif_hci_event_cback);
+ return BT_STATUS_SUCCESS;
+}
+#endif
+
+/*******************************************************************************
**
** Function btif_dut_mode_cback
**
diff --git a/btif/src/btif_debug_conn.c b/btif/src/btif_debug_conn.c
index 9c9a9f3..cf9ac6d 100644
--- a/btif/src/btif_debug_conn.c
+++ b/btif/src/btif_debug_conn.c
@@ -42,9 +42,11 @@
const time_t secs = ms / 1000;
struct tm *ptm = localtime(&secs);
- char tempbuff[20];
- strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm);
- snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000));
+ char tempbuff[20] = {0};
+ if (ptm) {
+ strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm);
+ snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000));
+ }
return buffer;
}
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
index f54b642..75cccde 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -64,6 +64,8 @@
/******************************************************************************
** Constants & Macros
******************************************************************************/
+#define BTIF_DM_GET_REMOTE_PROP(b,t,v,l,p) \
+ {p.type=t;p.val=v;p.len=l;btif_storage_get_remote_device_property(b,&p);}
#define COD_MASK 0x07FF
@@ -167,11 +169,6 @@
uint64_t energy_used;
} btif_activity_energy_info_cb_t;
-typedef struct
-{
- unsigned int manufact_id;
-}skip_sdp_entry_t;
-
typedef enum
{
BTIF_DM_FUNC_CREATE_BOND,
@@ -194,8 +191,6 @@
#define MAX_BTIF_BOND_EVENT_ENTRIES 15
-static skip_sdp_entry_t sdp_blacklist[] = {{76}}; //Apple Mouse and Keyboard
-
/* This flag will be true if HCI_Inquiry is in progress */
static BOOLEAN btif_dm_inquiry_in_progress = FALSE;
@@ -221,6 +216,8 @@
******************************************************************************/
static btif_dm_pairing_cb_t pairing_cb;
static btif_dm_oob_cb_t oob_cb;
+static UINT16 num_active_br_edr_links;
+static UINT16 num_active_le_links;
static void btif_dm_generic_evt(UINT16 event, char* p_param);
static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr, tBTA_TRANSPORT transport);
static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME *p_remote_name);
@@ -259,6 +256,9 @@
extern bt_status_t btif_sdp_execute_service(BOOLEAN b_enable);
extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16);
+extern void btif_av_move_idle(bt_bdaddr_t bd_addr);
+extern void btif_av_trigger_suspend();
+extern BOOLEAN btif_av_get_ongoing_multicast();
/******************************************************************************
** Functions
@@ -351,6 +351,36 @@
return BT_STATUS_SUCCESS;
}
+
+/*******************************************************************************
+**
+** Function check_eir_is_remote_name_short
+**
+** Description Check if remote name is shortened
+**
+** Returns TRUE if remote name found
+** else FALSE
+**
+*******************************************************************************/
+static BOOLEAN check_eir_is_remote_name_short(tBTA_DM_SEARCH *p_search_data)
+{
+ UINT8 *p_eir_remote_name = NULL;
+ UINT8 remote_name_len = 0;
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir)
+ {
+ p_eir_remote_name = BTM_CheckEirData(p_search_data->inq_res.p_eir,
+ BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len, p_search_data->inq_res.adv_data_len);
+
+ if (p_eir_remote_name)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/*******************************************************************************
**
** Function check_eir_remote_name
@@ -371,11 +401,11 @@
if (p_search_data->inq_res.p_eir)
{
p_eir_remote_name = BTM_CheckEirData(p_search_data->inq_res.p_eir,
- BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+ BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len, p_search_data->inq_res.adv_data_len);
if (!p_eir_remote_name)
{
p_eir_remote_name = BTM_CheckEirData(p_search_data->inq_res.p_eir,
- BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len, p_search_data->inq_res.adv_data_len);
}
if (p_eir_remote_name)
@@ -483,31 +513,97 @@
/*****************************************************************************
**
-** Function check_sdp_bl
+** Function interop_skip_authentication
**
-** Description Checks if a given device is blacklisted to skip sdp
+** Description Checks if a given device is blacklisted to skip authentication
**
-** Parameters skip_sdp_entry
+** Parameters remote_bdaddr
**
** Returns TRUE if the device is present in blacklist, else FALSE
**
*******************************************************************************/
-BOOLEAN check_sdp_bl(const bt_bdaddr_t *remote_bdaddr)
+static bool interop_skip_authentication(bt_bdaddr_t * remote_bdaddr)
{
- UINT16 manufacturer = 0;
- UINT8 lmp_ver = 0;
- UINT16 lmp_subver = 0;
+ if (remote_bdaddr == NULL)
+ {
+ LOG_WARN(LOG_TAG, "%s: remote_bdaddr = NULL, returning false", __func__);
+ return FALSE;
+ }
+
+ if (interop_match_addr(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, remote_bdaddr))
+ return TRUE;
+
bt_property_t prop_name;
- bt_remote_version_t info;
+ bt_bdname_t bdname;
+
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr,
+ &prop_name) != BT_STATUS_SUCCESS)
+ {
+ LOG_WARN(LOG_TAG, "%s: BT_PROPERTY_BDNAME failed, returning false", __func__);
+ return FALSE;
+ }
+
+ if (strlen((const char *)bdname.name) != 0 &&
+ interop_match_name(INTEROP_DISABLE_SDP_AFTER_PAIRING, (const char *)bdname.name))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*****************************************************************************
+**
+** Function interop_skip_sdp
+**
+** Description Checks if a given device is blacklisted to skip sdp
+**
+** Parameters remote_bdaddr
+**
+** Returns TRUE if the device is present in blacklist, else FALSE
+**
+*******************************************************************************/
+BOOLEAN interop_skip_sdp(const bt_bdaddr_t *remote_bdaddr)
+{
+ if (remote_bdaddr == NULL) {
+ LOG_WARN(LOG_TAG, "%s: remote_bdaddr = NULL, returning false", __func__);
+ return FALSE;
+ }
+
+ if (interop_match_addr(INTEROP_DISABLE_SDP_AFTER_PAIRING, remote_bdaddr)) {
+ LOG_WARN(LOG_TAG, "%s: device is in blacklist for skipping sdp", __func__);
+ return TRUE;
+ }
+
+ bt_property_t prop_name;
+ bt_bdname_t bdname;
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr,
+ &prop_name) != BT_STATUS_SUCCESS)
+ {
+ LOG_WARN(LOG_TAG, "%s: BT_PROPERTY_BDNAME failed, returning false", __func__);
+ return FALSE;
+ }
+
+ if (strlen((const char *)bdname.name) != 0 &&
+ interop_match_name(INTEROP_DISABLE_SDP_AFTER_PAIRING, (const char *)bdname.name))
+ return TRUE;
if (remote_bdaddr == NULL)
return FALSE;
-/* fetch additional info about remote device used in iop query */
+ UINT16 manufacturer = 0;
+ UINT8 lmp_ver = 0;
+ UINT16 lmp_subver = 0;
+
+ /* fetch additional info about remote device used in iop query */
BTM_ReadRemoteVersion(*(BD_ADDR*)remote_bdaddr, &lmp_ver,
&manufacturer, &lmp_subver);
- /* if not available yet, try fetching from config database */
+ bt_remote_version_t info;
+
+ /* if not available yet, try fetching from config database */
BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_VERSION_INFO,
sizeof(bt_remote_version_t), &info);
@@ -515,15 +611,15 @@
&prop_name) != BT_STATUS_SUCCESS)
{
+ APPL_TRACE_WARNING("%s: BT_PROPERTY_REMOTE_VERSION_INFO failed, returning false", __func__);
return FALSE;
}
manufacturer = info.manufacturer;
- for (unsigned int i = 0; i < ARRAY_SIZE(sdp_blacklist); i++)
- {
- if (manufacturer == sdp_blacklist[i].manufact_id)
- return TRUE;
- }
+ if (manufacturer != 0 &&
+ interop_match_manufacturer(INTEROP_DISABLE_SDP_AFTER_PAIRING, manufacturer))
+ return TRUE;
+
return FALSE;
}
@@ -550,13 +646,19 @@
state, pairing_cb.state, pairing_cb.sdp_attempts);
HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);
-
if (state == BT_BOND_STATE_BONDING)
{
pairing_cb.state = state;
bdcpy(pairing_cb.bd_addr, bd_addr->address);
- } else {
- if (!pairing_cb.sdp_attempts)
+ } else if ((state == BT_BOND_STATE_NONE)&&
+ ((bdcmp(bd_addr->address, pairing_cb.bd_addr) == 0) ||
+ (bdcmp(bd_addr->address, pairing_cb.static_bdaddr.address) == 0)))
+ {
+ memset(&pairing_cb, 0, sizeof(pairing_cb));
+ }else{
+ if ((!pairing_cb.sdp_attempts)&&
+ ((bdcmp(bd_addr->address, pairing_cb.bd_addr) == 0) ||
+ (bdcmp(bd_addr->address, pairing_cb.static_bdaddr.address) == 0)))
memset(&pairing_cb, 0, sizeof(pairing_cb));
else
BTIF_TRACE_DEBUG("%s: BR-EDR service discovery active", __func__);
@@ -768,6 +870,21 @@
*******************************************************************************/
void btif_dm_cb_remove_bond(bt_bdaddr_t *bd_addr)
{
+ bt_bdname_t alias;
+ bt_property_t properties[1];
+ uint32_t num_properties = 0;
+ memset(&alias, 0, sizeof(alias));
+ BTIF_DM_GET_REMOTE_PROP(bd_addr, BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+ &alias, sizeof(alias), properties[num_properties]);
+
+ if(alias.name[0] != '\0') {
+ properties[0].type = BT_PROPERTY_REMOTE_FRIENDLY_NAME;
+ properties[0].val = (void *) "";
+ properties[0].len = 1;
+
+ btif_storage_set_remote_device_property(bd_addr, &properties[0]);
+ }
+
/*special handling for HID devices */
/* VUP needs to be sent if its a HID Device. The HID HOST module will check if there
is a valid hid connection with this bd_addr. If yes VUP will be issued.*/
@@ -840,7 +957,7 @@
if (p_src_data->inq_res.p_eir)
{
p_dest_data->inq_res.p_eir = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
- memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir, HCI_EXT_INQ_RESPONSE_LEN);
+ memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir, p_src_data->inq_res.adv_data_len);
}
}
break;
@@ -919,6 +1036,14 @@
bdcpy(bd_addr.address, p_pin_req->bd_addr);
memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+ if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+ bdcmp(bd_addr.address, pairing_cb.bd_addr) != 0)
+ {
+ BTIF_TRACE_WARNING("%s(): already in bonding state, reject request", __FUNCTION__);
+ btif_dm_pin_reply(&bd_addr, 0, 0, NULL);
+ return;
+ }
+
bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
cod = devclass2uint(p_pin_req->dev_class);
@@ -931,14 +1056,22 @@
/* check for auto pair possiblity only if bond was initiated by local device */
if (pairing_cb.is_local_initiated && (p_pin_req->min_16_digit == FALSE))
{
+ if (bdcmp(pairing_cb.bd_addr, bd_addr.address))
+ {
+ /* Pin code from different device reject it as we dont support more than 1 pairing */
+ BTIF_TRACE_DEBUG("%s()rejecting pairing request", __FUNCTION__);
+ BTA_DmPinReply( (UINT8*)bd_addr.address, FALSE, 0, NULL);
+ return;
+ }
if (check_cod(&bd_addr, COD_AV_HEADSETS) ||
check_cod(&bd_addr, COD_AV_HEADPHONES) ||
+ check_cod(&bd_addr, COD_AV_HANDSFREE) ||
check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) ||
check_cod(&bd_addr, COD_AV_HIFI_AUDIO) ||
check_cod(&bd_addr, COD_HID_POINTING))
{
/* Check if this device can be auto paired */
- if (!interop_match_addr(INTEROP_DISABLE_AUTO_PAIRING, &bd_addr) &&
+ if (!interop_match_addr(INTEROP_DISABLE_AUTO_PAIRING, (bt_bdaddr_t *)&bd_addr) &&
!interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, (const char *)bd_name.name) &&
(pairing_cb.autopair_attempts == 0))
{
@@ -956,7 +1089,7 @@
else if (check_cod(&bd_addr, COD_HID_KEYBOARD) ||
check_cod(&bd_addr, COD_HID_COMBO))
{
- if ((interop_match_addr(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN, &bd_addr) == TRUE) &&
+ if ((interop_match_addr(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN, (bt_bdaddr_t *)&bd_addr) == TRUE) &&
(pairing_cb.autopair_attempts == 0))
{
BTIF_TRACE_DEBUG("%s() Attempting auto pair", __FUNCTION__);
@@ -1005,9 +1138,21 @@
bdcpy(bd_addr.address, p_ssp_cfm_req->bd_addr);
memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
+ if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+ bdcmp(bd_addr.address, pairing_cb.bd_addr) != 0)
+ {
+ BTIF_TRACE_WARNING("%s(): already in bonding state, reject request", __FUNCTION__);
+ btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 0, 0);
+ return;
+ }
+
/* Set the pairing_cb based on the local & remote authentication requirements */
bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ BTIF_TRACE_EVENT("%s: just_works :%d, loc_auth_req =%d, rmt_auth_req =%d ",
+ __FUNCTION__,p_ssp_cfm_req->just_works,p_ssp_cfm_req->loc_auth_req,
+ p_ssp_cfm_req->rmt_auth_req);
+
/* if just_works and bonding bit is not set treat this as temporary */
if (p_ssp_cfm_req->just_works && !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) &&
!(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS) &&
@@ -1036,6 +1181,19 @@
BTIF_TRACE_EVENT("%s: User consent needed for incoming pairing request. loc_io_caps: %d, rmt_io_caps: %d",
__FUNCTION__, p_ssp_cfm_req->loc_io_caps, p_ssp_cfm_req->rmt_io_caps);
}
+ /* Errata:4348
+ * Pairing confirmation for JustWorks needed if:
+ * 1. Outgoing (non-temporary) pairing is detected AND
+ * 2. local IO capabilities are DisplayYesNo AND
+ * 3. remote IO capbiltiies are NoInputNoOutput
+ */
+ else if (!is_incoming && pairing_cb.bond_type != BOND_TYPE_TEMPORARY &&
+ (p_ssp_cfm_req->loc_io_caps == HCI_IO_CAP_DISPLAY_YESNO) &&
+ (p_ssp_cfm_req->rmt_io_caps == HCI_IO_CAP_NO_IO))
+ {
+ BTIF_TRACE_EVENT("%s: Show pairing pop up for outgoing pairing when loc_io_caps: %d, rmt_io_caps: %d",
+ __FUNCTION__, p_ssp_cfm_req->loc_io_caps, p_ssp_cfm_req->rmt_io_caps);
+ }
else
{
BTIF_TRACE_EVENT("%s: Auto-accept JustWorks pairing", __FUNCTION__);
@@ -1105,7 +1263,6 @@
bt_bdaddr_t bd_addr;
bt_status_t status = BT_STATUS_FAIL;
bt_bond_state_t state = BT_BOND_STATE_NONE;
- BOOLEAN skip_sdp = FALSE;
BTIF_TRACE_DEBUG("%s: bond state=%d", __func__, pairing_cb.state);
@@ -1141,45 +1298,40 @@
}
}
- // We could have received a new link key without going through the pairing flow.
- // If so, we don't want to perform SDP or any other operations on the authenticated
- // device.
- if (bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0) {
- char address[32];
- bt_bdaddr_t bt_bdaddr;
-
- memcpy(bt_bdaddr.address, p_auth_cmpl->bd_addr,
- sizeof(bt_bdaddr.address));
- bdaddr_to_string(&bt_bdaddr, address, sizeof(address));
- LOG_INFO(LOG_TAG, "%s skipping SDP since we did not initiate pairing to %s.", __func__, address);
- return;
- }
-
// Skip SDP for certain HID Devices
if (p_auth_cmpl->success)
{
+ // We could have received a new link key without going through the pairing flow.
+ // If so, we don't want to perform SDP or any other operations on the authenticated
+ // device. Also, make sure that the link key is not derived from secure LTK, because
+ // we will need to perform SDP in case of link key derivation to allow bond state change
+ // notification for the BR/EDR transport so that the subsequent BR/EDR connections
+ // to the remote can use the derived link key.
+ if ((bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0) &&
+ (!pairing_cb.ble.is_penc_key_rcvd)) {
+ char address[32];
+ bt_bdaddr_t bt_bdaddr;
+
+ memcpy(bt_bdaddr.address, p_auth_cmpl->bd_addr,
+ sizeof(bt_bdaddr.address));
+ bdaddr_to_string(&bt_bdaddr, address, sizeof(address));
+ LOG_INFO(LOG_TAG, "%s skipping SDP since we did not initiate pairing to %s.", __func__, address);
+ return;
+ }
#if BLE_INCLUDED == TRUE
btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);
#endif
btif_update_remote_properties(p_auth_cmpl->bd_addr,
p_auth_cmpl->bd_name, NULL, p_auth_cmpl->dev_type);
pairing_cb.timeout_retries = 0;
- status = BT_STATUS_SUCCESS;
- state = BT_BOND_STATE_BONDED;
- bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
- if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr))
+ if (interop_skip_sdp(&bd_addr) && check_cod_hid(&bd_addr))
{
- LOG_WARN(LOG_TAG, "%s:skip SDP", __FUNCTION__);
- skip_sdp = TRUE;
- }
- if(!pairing_cb.is_local_initiated && skip_sdp)
- {
- bond_state_changed(status, &bd_addr, state);
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
- LOG_WARN(LOG_TAG, "%s: Incoming HID Connection",__FUNCTION__);
+ BTIF_TRACE_DEBUG("%s: HID Connection from "
+ "blacklisted device, skipping sdp",__FUNCTION__);
bt_property_t prop;
- bt_bdaddr_t bd_addr;
bt_uuid_t uuid;
char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
@@ -1189,12 +1341,18 @@
prop.val = uuid.uu;
prop.len = MAX_UUID_SIZE;
+ /* Also write this to the NVRAM */
+ status = btif_storage_set_remote_device_property(&bd_addr, &prop);
/* Send the event to the BTIF */
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
}
else
{
+ status = BT_STATUS_SUCCESS;
+ state = BT_BOND_STATE_BONDED;
+
+
#if BLE_INCLUDED == TRUE
BOOLEAN is_crosskey = FALSE;
/* If bonded due to cross-key, save the static address too*/
@@ -1228,8 +1386,9 @@
switch(p_auth_cmpl->fail_reason)
{
case HCI_ERR_PAGE_TIMEOUT:
- if (interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &bd_addr)
- && pairing_cb.timeout_retries)
+ if ((pairing_cb.timeout_retries == NUM_TIMEOUT_RETRIES) ||
+ (interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, (bt_bdaddr_t *)&bd_addr)
+ && pairing_cb.timeout_retries))
{
BTIF_TRACE_WARNING("%s() - Pairing timeout; retrying (%d) ...", __FUNCTION__, pairing_cb.timeout_retries);
--pairing_cb.timeout_retries;
@@ -1242,6 +1401,7 @@
break;
case HCI_ERR_PAIRING_NOT_ALLOWED:
+ btif_storage_remove_bonded_device(&bd_addr);
status = BT_STATUS_AUTH_REJECTED;
break;
@@ -1249,9 +1409,12 @@
status = BT_STATUS_AUTH_FAILURE;
break;
+ /* Dont fail the bonding for key missing error as stack retry security */
+ case HCI_ERR_KEY_MISSING:
+ btif_storage_remove_bonded_device(&bd_addr);
+ return;
/* map the auth failure codes, so we can retry pairing if necessary */
case HCI_ERR_AUTH_FAILURE:
- case HCI_ERR_KEY_MISSING:
btif_storage_remove_bonded_device(&bd_addr);
case HCI_ERR_HOST_REJECT_SECURITY:
case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
@@ -1260,6 +1423,7 @@
case HCI_ERR_INSUFFCIENT_SECURITY:
case HCI_ERR_PEER_USER:
case HCI_ERR_UNSPECIFIED:
+ case HCI_ERR_REPEATED_ATTEMPTS:
BTIF_TRACE_DEBUG(" %s() Authentication fail reason %d",
__FUNCTION__, p_auth_cmpl->fail_reason);
if (pairing_cb.autopair_attempts == 1)
@@ -1279,6 +1443,13 @@
default:
status = BT_STATUS_FAIL;
}
+ if(p_auth_cmpl->fail_reason == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE
+ || p_auth_cmpl->fail_reason == HCI_ERR_UNIT_KEY_USED
+ || p_auth_cmpl->fail_reason == HCI_ERR_INSUFFCIENT_SECURITY
+ || p_auth_cmpl->fail_reason == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED
+ || p_auth_cmpl->fail_reason == HCI_ERR_HOST_REJECT_SECURITY
+ || p_auth_cmpl->fail_reason == HCI_ERR_UNSPECIFIED)
+ GENERATE_VND_LOGS();
/* Special Handling for HID Devices */
if (check_cod(&bd_addr, COD_HID_POINTING)) {
/* Remove Device as bonded in nvram as authentication failed */
@@ -1374,6 +1545,10 @@
uint32_t num_properties = 0;
bt_status_t status;
int addr_type = 0;
+ bt_bdname_t alias;
+ memset(&alias, 0, sizeof(alias));
+ BTIF_DM_GET_REMOTE_PROP(&bdaddr, BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+ &alias, sizeof(alias), properties[num_properties]);
memset(properties, 0, sizeof(properties));
/* BD_ADDR */
@@ -1382,13 +1557,28 @@
num_properties++;
/* BD_NAME */
/* Don't send BDNAME if it is empty */
- if (bdname.name[0])
- {
+ /* send alias name as the name if alias name present */
+ if(alias.name[0] != '\0') {
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
BT_PROPERTY_BDNAME,
- strlen((char *)bdname.name), &bdname);
+ strlen((char *)alias.name), &alias);
num_properties++;
}
+ else if (bdname.name[0])
+ {
+ if((check_eir_is_remote_name_short(p_search_data) == TRUE) &&
+ (btif_storage_is_device_bonded(&bdaddr) == TRUE))
+ {
+ BTIF_TRACE_DEBUG("%s Don't update about the device name ", __FUNCTION__);
+ }
+ else
+ {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDNAME,
+ strlen((char *)bdname.name), &bdname);
+ num_properties++;
+ }
+ }
/* DEV_CLASS */
BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
@@ -1495,8 +1685,9 @@
{
case BTA_DM_DISC_RES_EVT:
{
- bt_property_t prop;
uint32_t i = 0;
+ bt_property_t prop[2];
+ int num_properties = 0;
bt_bdaddr_t bd_addr;
bt_status_t ret;
@@ -1513,12 +1704,12 @@
btif_dm_get_remote_services(&bd_addr);
return;
}
- prop.type = BT_PROPERTY_UUIDS;
- prop.len = 0;
+ prop[0].type = BT_PROPERTY_UUIDS;
+ prop[0].len = 0;
if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0))
{
- prop.val = p_data->disc_res.p_uuid_list;
- prop.len = p_data->disc_res.num_uuids * MAX_UUID_SIZE;
+ prop[0].val = p_data->disc_res.p_uuid_list;
+ prop[0].len = p_data->disc_res.num_uuids * MAX_UUID_SIZE;
for (i=0; i < p_data->disc_res.num_uuids; i++)
{
char temp[256];
@@ -1535,26 +1726,45 @@
(bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) == 0)) &&
pairing_cb.sdp_attempts > 0)
{
- BTIF_TRACE_DEBUG("%s Remote Service SDP done. Call bond_state_changed_cb BONDED",
- __FUNCTION__);
- pairing_cb.sdp_attempts = 0;
+ BTIF_TRACE_DEBUG("%s Remote Service SDP done. Call bond_state_changed_cb BONDED",
+ __FUNCTION__);
+ if(p_data->disc_res.result != BTA_SUCCESS)
+ GENERATE_VND_LOGS();
+ pairing_cb.sdp_attempts = 0;
- // If bonding occured due to cross-key pairing, send bonding callback
- // for static address now
- if (bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) == 0)
+ // If bonding occured due to cross-key pairing, send bonding callback
+ // for static address now
+ if (bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) == 0)
bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
- bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
}
if (p_data->disc_res.num_uuids != 0)
{
/* Also write this to the NVRAM */
- ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+ num_properties++;
+ }
+
+ /* Remote name update */
+ if (strlen((const char *) p_data->disc_res.bd_name))
+ {
+ prop[1].type = BT_PROPERTY_BDNAME;
+ prop[1].val = p_data->disc_res.bd_name;
+ prop[1].len = strlen((char *)p_data->disc_res.bd_name);
+
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop[1]);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "failed to save remote device property", ret);
+ num_properties++;
+ }
+
+ if(num_properties > 0)
+ {
/* Send the event to the BTIF */
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
- BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+ BT_STATUS_SUCCESS, &bd_addr, num_properties, prop);
}
}
break;
@@ -1574,10 +1784,11 @@
bt_uuid_t uuid;
int i = 0;
int j = 15;
+ int num_properties = 0;
if (p_data->disc_ble_res.service.uu.uuid16 == UUID_SERVCLASS_LE_HID)
{
BTIF_TRACE_DEBUG("%s: Found HOGP UUID",__FUNCTION__);
- bt_property_t prop;
+ bt_property_t prop[2];
bt_bdaddr_t bd_addr;
char temp[256];
bt_status_t ret;
@@ -1597,17 +1808,30 @@
LOG_INFO(LOG_TAG, "%s uuid:%s", __func__, temp);
bdcpy(bd_addr.address, p_data->disc_ble_res.bd_addr);
- prop.type = BT_PROPERTY_UUIDS;
- prop.val = uuid.uu;
- prop.len = MAX_UUID_SIZE;
+ prop[0].type = BT_PROPERTY_UUIDS;
+ prop[0].val = uuid.uu;
+ prop[0].len = MAX_UUID_SIZE;
/* Also write this to the NVRAM */
- ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+ num_properties++;
+
+ /* Remote name update */
+ if (strnlen((const char *) p_data->disc_ble_res.bd_name, BD_NAME_LEN))
+ {
+ prop[1].type = BT_PROPERTY_BDNAME;
+ prop[1].val = p_data->disc_ble_res.bd_name;
+ prop[1].len = strnlen((char *)p_data->disc_ble_res.bd_name, BD_NAME_LEN);
+
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop[1]);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "failed to save remote device property", ret);
+ num_properties++;
+ }
/* Send the event to the BTIF */
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
- BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+ BT_STATUS_SUCCESS, &bd_addr, num_properties, prop);
}
break;
@@ -1698,7 +1922,7 @@
bt_status_t status;
bt_property_t prop;
prop.type = BT_PROPERTY_BDNAME;
- prop.len = BD_NAME_LEN;
+ prop.len = BD_NAME_LEN + 1;
prop.val = (void*)bdname;
status = btif_storage_get_adapter_property(&prop);
@@ -1740,6 +1964,8 @@
*/
btif_storage_load_bonded_devices();
+ load_iot_devlist(IOT_DEV_CONF_FILE);
+
btif_enable_bluetooth_evt(p_data->enable.status);
}
break;
@@ -1748,14 +1974,12 @@
/* for each of the enabled services in the mask, trigger the profile
* disable */
service_mask = btif_get_enabled_services_mask();
- for (i=0; i <= BTA_MAX_SERVICE_ID; i++)
+ if (service_mask &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(BTA_BLE_SERVICE_ID)))
{
- if (service_mask &
- (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i)))
- {
- btif_in_execute_service_request(i, FALSE);
- }
+ btif_in_execute_service_request(BTA_BLE_SERVICE_ID, FALSE);
}
+ unload_iot_devlist();
btif_disable_bluetooth_evt();
break;
@@ -1773,6 +1997,7 @@
bdcpy(bd_addr.address, pairing_cb.bd_addr);
btm_set_bond_type_dev(pairing_cb.bd_addr, BOND_TYPE_UNKNOWN);
bond_state_changed(p_data->bond_cancel_cmpl.result, &bd_addr, BT_BOND_STATE_NONE);
+ btif_dm_remove_bond(&bd_addr);
}
break;
@@ -1823,6 +2048,33 @@
bdcpy(bd_addr.address, p_data->link_up.bd_addr);
BTIF_TRACE_DEBUG("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED");
+ if(p_data->link_up.link_type == BT_TRANSPORT_LE)
+ {
+ num_active_le_links++;
+ BTIF_TRACE_DEBUG("num_active_le_links is %d ",
+ num_active_le_links);
+ }
+
+ if(p_data->link_up.link_type == BT_TRANSPORT_BR_EDR)
+ {
+ num_active_br_edr_links++;
+ BTIF_TRACE_DEBUG("num_active_br_edr_links is %d ",
+ num_active_br_edr_links);
+ }
+ /* When tuchtones are enabled and 2 EDR HS are connected, if new
+ * connection is initated, then tuch tones are send to both connected HS
+ * over A2dp.Stream will be suspended after 3 secs and if remote has
+ * initiated play in this duartion, multicast must not be enabled with
+ * 3 ACL's, hence trigger a2dp suspend.
+ * During active muisc streaming no new connection can happen, hence
+ * We will get this only when multistreaming is happening due to tuchtones
+ */
+ if (btif_av_get_ongoing_multicast())
+ {
+ // trigger a2dp suspend
+ btif_av_trigger_suspend();
+ }
+
btif_update_remote_version_property(&bd_addr);
HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
@@ -1831,7 +2083,24 @@
case BTA_DM_LINK_DOWN_EVT:
bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+
btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
+
+ BTIF_TRACE_DEBUG("BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
+ if (num_active_le_links > 0 &&
+ p_data->link_down.link_type == BT_TRANSPORT_LE)
+ {
+ num_active_le_links--;
+ BTIF_TRACE_DEBUG("num_active_le_links is %d ",num_active_le_links);
+ }
+
+ if (num_active_br_edr_links > 0 &&
+ p_data->link_down.link_type == BT_TRANSPORT_BR_EDR)
+ {
+ num_active_br_edr_links--;
+ BTIF_TRACE_DEBUG("num_active_br_edr_links is %d ",num_active_br_edr_links);
+ }
+ btif_av_move_idle(bd_addr);
BTIF_TRACE_DEBUG("BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
&bd_addr, BT_ACL_STATE_DISCONNECTED);
@@ -2078,7 +2347,9 @@
}
break;
case BTIF_DM_CB_LE_TX_TEST:
+ case BTIF_DM_CB_LE_ENH_TX_TEST:
case BTIF_DM_CB_LE_RX_TEST:
+ case BTIF_DM_CB_LE_ENH_RX_TEST:
{
uint8_t status;
STREAM_TO_UINT8(status, p_param);
@@ -2145,14 +2416,14 @@
{
case BTA_DM_INQ_RES_EVT:
{
- if (p_data->inq_res.p_eir)
- param_len += HCI_EXT_INQ_RESPONSE_LEN;
+ if (p_data && p_data->inq_res.p_eir)
+ param_len += p_data->inq_res.adv_data_len;
}
break;
case BTA_DM_DISC_RES_EVT:
{
- if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
+ if (p_data && p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
param_len += p_data->disc_res.raw_data_size;
}
break;
@@ -2160,7 +2431,7 @@
BTIF_TRACE_DEBUG("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
/* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
- if (event == BTA_DM_INQ_RES_EVT)
+ if (p_data && event == BTA_DM_INQ_RES_EVT)
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
@@ -2186,7 +2457,7 @@
{
case BTA_DM_DISC_RES_EVT:
{
- if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) {
+ if ((p_data && p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) {
param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE);
}
} break;
@@ -2290,7 +2561,11 @@
tBTA_SERVICE_MASK services = 0;
tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;
- BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ BTIF_TRACE_EVENT("%s : pairing_cb.state: 0x%x", __FUNCTION__, pairing_cb.state);
+
+ /* We should not go for inquiry in BONDING STATE. */
+ if (pairing_cb.state == BT_BOND_STATE_BONDING)
+ return BT_STATUS_BUSY;
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
memset(&adv_filt_param, 0, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
@@ -2487,6 +2762,47 @@
/*******************************************************************************
**
+** Function btif_dm_hh_open_success
+**
+** Description informs the upper layers if the HH conneciton is successfully opened.
+**
+** Returns none
+**
+*******************************************************************************/
+
+void btif_dm_hh_open_success(bt_bdaddr_t *bdaddr)
+{
+ if (pairing_cb.state != BT_BOND_STATE_BONDING ||
+ bdcmp(bdaddr->address, pairing_cb.bd_addr))
+ return;
+
+ if (interop_skip_authentication(bdaddr) && check_cod_hid(bdaddr))
+ {
+ bt_status_t status;
+ LINK_KEY link_key = {0};
+ bond_state_changed(BT_STATUS_SUCCESS, bdaddr, BT_BOND_STATE_BONDED);
+ BTIF_TRACE_DEBUG("%s: Device is blacklisted for authentication", __func__);
+ bt_property_t prop;
+ bt_uuid_t uuid;
+ char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
+ string_to_uuid(uuid_str, &uuid);
+ prop.type = BT_PROPERTY_UUIDS;
+ prop.val = uuid.uu;
+ prop.len = MAX_UUID_SIZE;
+ // Also write this to the NVRAM
+ status = btif_storage_set_remote_device_property(bdaddr, &prop);
+ ASSERTC(status == BT_STATUS_SUCCESS, "storing remote services failed", status);
+ // Store fake link for device as bonded in nvram,
+ // otherwise on device reboot/bt off-on device will not be shown in paired list.
+ btif_storage_add_bonded_device(bdaddr, link_key, HCI_LKEY_TYPE_UNAUTH_COMB, 0);
+ // Send the event to the BTIF
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, bdaddr, 1, &prop);
+ }
+}
+
+/*******************************************************************************
+**
** Function btif_dm_hh_open_failed
**
** Description informs the upper layers if the HH have failed during bonding
@@ -2497,7 +2813,7 @@
void btif_dm_hh_open_failed(bt_bdaddr_t *bdaddr)
{
- if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+ if (check_cod_hid(bdaddr) && (pairing_cb.state == BT_BOND_STATE_BONDING) &&
bdcmp(bdaddr->address, pairing_cb.bd_addr) == 0)
{
bond_state_changed(BT_STATUS_FAIL, bdaddr, BT_BOND_STATE_NONE);
@@ -2681,10 +2997,15 @@
*******************************************************************************/
bt_status_t btif_dm_get_remote_services(bt_bdaddr_t *remote_addr)
{
- bdstr_t bdstr;
+ bdstr_t bdstr = {'\0'};
BTIF_TRACE_EVENT("%s: remote_addr=%s", __FUNCTION__, bdaddr_to_string(remote_addr, bdstr, sizeof(bdstr)));
+ if (bdaddr_is_empty(remote_addr))
+ {
+ BTIF_TRACE_WARNING("%s: remote_addr =%s not valid.", __FUNCTION__, bdaddr_to_string(remote_addr, bdstr, sizeof(bdstr)));
+ return BT_STATUS_FAIL;
+ }
BTA_DmDiscover(remote_addr->address, BTA_ALL_SERVICE_MASK,
bte_dm_search_services_evt, TRUE);
@@ -3113,7 +3434,10 @@
} else {
btif_dm_save_ble_bonding_keys();
BTA_GATTC_Refresh(bd_addr.address);
- btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
+ if(!p_auth_cmpl->smp_over_br)
+ btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
+ else
+ btif_dm_get_remote_services(&bd_addr);
}
}
else
@@ -3442,12 +3766,24 @@
(char *)p, 1, NULL);
}
+static void btif_dm_ble_enh_tx_test_cback(void *p)
+{
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_ENH_TX_TEST,
+ (char *)p, 1, NULL);
+}
+
static void btif_dm_ble_rx_test_cback(void *p)
{
btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_RX_TEST,
(char *)p, 1, NULL);
}
+static void btif_dm_ble_enh_rx_test_cback(void *p)
+{
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_ENH_RX_TEST,
+ (char *)p, 1, NULL);
+}
+
static void btif_dm_ble_test_end_cback(void *p)
{
btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TEST_END,
@@ -3469,10 +3805,18 @@
if (len != 3) return BT_STATUS_PARM_INVALID;
BTM_BleTransmitterTest(buf[0],buf[1],buf[2], btif_dm_ble_tx_test_cback);
break;
+ case HCI_BLE_ENH_TRANSMITTER_TEST:
+ if (len != 4) return BT_STATUS_PARM_INVALID;
+ BTM_BleEnhTransmitterTest(buf[0],buf[1],buf[2],buf[3], btif_dm_ble_enh_tx_test_cback);
+ break;
case HCI_BLE_RECEIVER_TEST:
if (len != 1) return BT_STATUS_PARM_INVALID;
BTM_BleReceiverTest(buf[0], btif_dm_ble_rx_test_cback);
break;
+ case HCI_BLE_ENH_RECEIVER_TEST:
+ if (len != 3) return BT_STATUS_PARM_INVALID;
+ BTM_BleEnhReceiverTest(buf[0],buf[1],buf[2], btif_dm_ble_enh_rx_test_cback);
+ break;
case HCI_BLE_TEST_END:
BTM_BleTestEnd((tBTM_CMPL_CB*) btif_dm_ble_test_end_cback);
break;
@@ -3486,6 +3830,10 @@
void btif_dm_on_disable()
{
+ /* Cleanup static variables.*/
+ num_active_br_edr_links = 0;
+ num_active_le_links = 0;
+
/* cancel any pending pairing requests */
if (pairing_cb.state == BT_BOND_STATE_BONDING)
{
@@ -3588,11 +3936,13 @@
btif_bond_event_t* event = &btif_dm_bond_events[i];
char eventtime[20];
- char temptime[20];
+ char temptime[20] = {0};
struct tm *tstamp = localtime(&event->timestamp.tv_sec);
- strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
- snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
- event->timestamp.tv_nsec / 1000000);
+ if (tstamp) {
+ strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
+ snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
+ event->timestamp.tv_nsec / 1000000);
+ }
char bdaddr[18];
bdaddr_to_string(&event->bd_addr, bdaddr, sizeof(bdaddr));
@@ -3632,3 +3982,34 @@
}
pthread_mutex_unlock(&bond_event_lock);
}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_br_edr_links.
+**
+** Description Returns number of active BR/EDR links.
+**
+** Returns UINT16
+**
+*******************************************************************************/
+UINT16 btif_dm_get_br_edr_links()
+{
+ BTIF_TRACE_DEBUG("BR/EDR Link count: %d", num_active_br_edr_links);
+ return num_active_br_edr_links;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_le_links.
+**
+** Description Returns number of active LE links.
+**
+** Returns UINT16
+**
+*******************************************************************************/
+UINT16 btif_dm_get_le_links()
+{
+ BTIF_TRACE_DEBUG("LE Link count: %d", num_active_le_links);
+ return num_active_le_links;
+}
+
diff --git a/btif/src/btif_gap.c b/btif/src/btif_gap.c
new file mode 100644
index 0000000..c90cc2d
--- /dev/null
+++ b/btif/src/btif_gap.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+#include "bt_utils.h"
+#include "gap_api.h"
+#include "l2c_api.h"
+
+#ifdef TEST_APP_INTERFACE
+#include <bt_testapp.h>
+
+
+
+static void GapAttrInit(void)
+{
+ GAP_Init();
+}
+static void Gap_BleAttrDBUpdate(BD_ADDR p_bda, UINT16 int_min, UINT16 int_max, UINT16 latency, UINT16 sp_tout)
+{
+ printf("%s:: remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, int_min=%d, int_max=%d, latency=%d sp_tout=%d\n", __FUNCTION__,
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5],
+ int_min, int_max, latency, sp_tout);
+ L2CA_UpdateBleConnParams(p_bda, 50, 70, 0, 1000);
+
+}
+
+static const btgap_interface_t btgapInterface = {
+ sizeof(btgap_interface_t),
+ GapAttrInit,
+ Gap_BleAttrDBUpdate,
+};
+
+const btgap_interface_t *btif_gap_get_interface(void)
+{
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ return &btgapInterface;
+}
+
+#endif //TEST_APP_INTERFACE
diff --git a/btif/src/btif_gatt_client.c b/btif/src/btif_gatt_client.c
index 7ad4f08..bac5772 100644
--- a/btif/src/btif_gatt_client.c
+++ b/btif/src/btif_gatt_client.c
@@ -117,6 +117,10 @@
#define ENABLE_BATCH_SCAN 1
#define DISABLE_BATCH_SCAN 0
+#define SCAN_PHY_LE_1M 1
+#define SCAN_PHY_LE_CODED 4
+#define SCAN_PHY_LE_1M_CODED 5
+
/*******************************************************************************
** Local type definitions
********************************************************************************/
@@ -199,9 +203,17 @@
uint8_t start;
uint8_t has_mask;
int8_t rssi;
+ uint8_t scan_phys;
+ uint16_t scan_interval_coded;
+ uint16_t scan_window_coded;
+
+ uint16_t duration;
+ uint16_t period;
+
uint8_t flag;
tBT_DEVICE_TYPE device_type;
btgatt_transport_t transport;
+ UINT16 adv_data_len;
} __attribute__((packed)) btif_gattc_cb_t;
typedef struct
@@ -422,12 +434,12 @@
bt_bdname_t bdname;
p_eir_remote_name = BTM_CheckEirData(p_btif_cb->value,
- BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+ BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len, p_btif_cb->adv_data_len);
if (p_eir_remote_name == NULL)
{
p_eir_remote_name = BTM_CheckEirData(p_btif_cb->value,
- BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len, p_btif_cb->adv_data_len);
}
if (p_eir_remote_name)
@@ -554,7 +566,9 @@
}
if (p_data->open.status == BTA_GATT_OK)
- btif_gatt_check_encrypted_link(p_data->open.remote_bda, p_data->open.transport);
+#if (!defined(BTA_SKIP_BLE_START_ENCRYPTION) || BTA_SKIP_BLE_START_ENCRYPTION == FALSE)
+ btif_gatt_check_encrypted_link(p_data->open.remote_bda,p_data->open.transport);
+#endif
break;
}
@@ -584,12 +598,12 @@
bt_property_t properties;
p_eir_remote_name = BTM_CheckEirData(p_btif_cb->value,
- BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+ BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len, p_btif_cb->adv_data_len);
if (p_eir_remote_name == NULL)
{
p_eir_remote_name = BTM_CheckEirData(p_btif_cb->value,
- BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len, p_btif_cb->adv_data_len);
}
if ((p_btif_cb->addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name))
@@ -665,6 +679,31 @@
break;
}
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ case BTA_GATTC_EXTENDED_ADV_ENB_EVT:
+ {
+ btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*) p_param;
+ if (0xFF != p_btif_cb->inst_id)
+ btif_multi_adv_add_instid_map(p_btif_cb->client_if, p_btif_cb->inst_id, false);
+ HAL_CBACK(bt_gatt_callbacks, client->multi_adv_enable_cb
+ , p_btif_cb->client_if
+ , p_btif_cb->status
+ );
+ break;
+ }
+
+ case BTA_GATTC_EXTENDED_ADV_UPD_EVT:
+ {
+ btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*) p_param;
+ HAL_CBACK(bt_gatt_callbacks, client->multi_adv_update_cb
+ , p_btif_cb->client_if
+ , p_btif_cb->status
+ );
+ break;
+ }
+
+#endif
+
case BTA_GATTC_MULT_ADV_DATA_EVT:
{
btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*) p_param;
@@ -862,6 +901,16 @@
upevt = BTA_GATTC_MULT_ADV_DATA_EVT;
break;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ case BTA_BLE_EXTENDED_ADV_ENB_EVT:
+ upevt = BTA_GATTC_EXTENDED_ADV_ENB_EVT;
+ break;
+
+ case BTA_BLE_EXTENDED_ADV_PARAM_EVT:
+ upevt = BTA_GATTC_EXTENDED_ADV_UPD_EVT;
+ break;
+#endif
+
default:
return;
}
@@ -989,11 +1038,14 @@
btif_cb.rssi = p_data->inq_res.rssi;
btif_cb.addr_type = p_data->inq_res.ble_addr_type;
btif_cb.flag = p_data->inq_res.flag;
+ btif_cb.adv_data_len = p_data->inq_res.adv_data_len;
+
+ memset(&btif_cb.value[0], 0, BTGATT_MAX_ATTR_LEN);
if (p_data->inq_res.p_eir)
{
- memcpy(btif_cb.value, p_data->inq_res.p_eir, 62);
+ memcpy(btif_cb.value, p_data->inq_res.p_eir, p_data->inq_res.adv_data_len);
if (BTM_CheckEirData(p_data->inq_res.p_eir, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE,
- &len))
+ &len, p_data->inq_res.adv_data_len))
{
p_data->inq_res.remt_name_not_required = TRUE;
}
@@ -1115,6 +1167,10 @@
tBT_UUID uuid;
tBTA_GATT_UNFMT descr_val;
+ if (!btif_is_enabled()) {
+ LOG_ERROR(LOG_TAG,"%s: bluetooth adapter not enabled",__FUNCTION__);
+ return;
+ }
btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*) p_param;
if (!p_cb) return;
@@ -1136,11 +1192,11 @@
case BTIF_GATTC_SCAN_START:
btif_gattc_init_dev_cb();
- BTA_DmBleObserve(TRUE, 0, bta_scan_results_cb);
+ BTA_DmBleObserve(TRUE, 0, 0, bta_scan_results_cb);
break;
case BTIF_GATTC_SCAN_STOP:
- BTA_DmBleObserve(FALSE, 0, 0);
+ BTA_DmBleObserve(FALSE, 0, 0, 0);
break;
case BTIF_GATTC_OPEN:
@@ -1341,7 +1397,7 @@
cond.srvc_uuid.p_uuid_mask = NULL;
if (p_adv_filt_cb->has_mask)
{
- btif_to_bta_uuid_mask(&uuid_mask, &p_adv_filt_cb->uuid_mask);
+ btif_to_bta_uuid_mask(&uuid_mask, &p_adv_filt_cb->uuid_mask, &p_adv_filt_cb->uuid);
cond.srvc_uuid.p_uuid_mask = &uuid_mask;
}
BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
@@ -1516,10 +1572,12 @@
{
btgatt_multi_adv_common_data *p_multi_adv_data_cb =
btif_obtain_multi_adv_data_cb();
+ p_multi_adv_data_cb->inst_cb[cbindex].frag_preference = p_adv_data->frag_preference;
BTA_BleCfgAdvInstData(
(UINT8)inst_id,
p_adv_data->set_scan_rsp,
p_multi_adv_data_cb->inst_cb[cbindex].mask,
+ p_multi_adv_data_cb->inst_cb[cbindex].frag_preference,
&p_multi_adv_data_cb->inst_cb[cbindex].data);
}
else
@@ -1565,7 +1623,8 @@
case BTIF_GATTC_SET_SCAN_PARAMS:
{
- BTA_DmSetBleScanParams(p_cb->client_if, p_cb->scan_interval, p_cb->scan_window,
+ BTA_DmSetBleScanParams(p_cb->client_if, p_cb->scan_phys, p_cb->scan_interval, p_cb->scan_window,
+ p_cb->scan_interval_coded, p_cb->scan_window_coded,
BTM_BLE_SCAN_MODE_ACTI, bta_scan_param_setup_cb);
break;
}
@@ -1637,6 +1696,12 @@
{
CHECK_BTGATT_INIT();
btif_gattc_cb_t btif_cb;
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ btif_cb.duration = 0;
+ btif_cb.period = 0;
+#endif
+
return btif_transfer_context(btgattc_handle_event, start ? BTIF_GATTC_SCAN_START : BTIF_GATTC_SCAN_STOP,
(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}
@@ -1989,9 +2054,23 @@
{
CHECK_BTGATT_INIT();
btif_gattc_cb_t btif_cb;
+
+ memset(&btif_cb, 0, sizeof(btif_gattc_cb_t));
+
btif_cb.client_if = client_if;
btif_cb.scan_interval = scan_interval;
btif_cb.scan_window = scan_window;
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ btif_cb.scan_phys = 0x01;/*LE 1M*/
+ btif_cb.scan_interval_coded = 0;
+ btif_cb.scan_window_coded = 0;
+
+ BTIF_TRACE_DEBUG("btif_gattc_set_scan_parameters ::scan_phys=%d scan_interval=%d scan_window= %d "
+ "scan_interval_coded= %d scan_window_coded=%d",btif_cb.scan_phys,btif_cb.scan_interval,
+ btif_cb.scan_window, btif_cb.scan_interval_coded, btif_cb.scan_window_coded);
+#endif
+
return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_SET_SCAN_PARAMS,
(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}
@@ -2021,6 +2100,9 @@
adv_cb.param.channel_map = chnl_map;
adv_cb.param.adv_filter_policy = 0;
adv_cb.param.tx_power = tx_power;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ adv_cb.param.duration = timeout_s;
+#endif
adv_cb.timeout_s = timeout_s;
return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_ADV_INSTANCE_ENABLE,
(char*) &adv_cb, sizeof(btgatt_multi_adv_inst_cb), NULL);
@@ -2040,6 +2122,9 @@
adv_cb.param.channel_map = chnl_map;
adv_cb.param.adv_filter_policy = 0;
adv_cb.param.tx_power = tx_power;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ adv_cb.param.duration = timeout_s;
+#endif
adv_cb.timeout_s = timeout_s;
return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_ADV_INSTANCE_UPDATE,
(char*) &adv_cb, sizeof(btgatt_multi_adv_inst_cb), NULL);
@@ -2063,6 +2148,10 @@
min_interval, max_interval, appearance, manufacturer_len, manufacturer_data,
service_data_len, service_data, service_uuid_len, service_uuid, &multi_adv_data_inst);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ multi_adv_data_inst.frag_preference = 0;
+#endif
+
bt_status_t status = btif_transfer_context(
btgattc_handle_event, BTIF_GATTC_ADV_INSTANCE_SET_DATA,
(char *)&multi_adv_data_inst, sizeof(multi_adv_data_inst),
diff --git a/btif/src/btif_gatt_multi_adv_util.c b/btif/src/btif_gatt_multi_adv_util.c
index ddca7d2..8430475 100644
--- a/btif/src/btif_gatt_multi_adv_util.c
+++ b/btif/src/btif_gatt_multi_adv_util.c
@@ -43,6 +43,7 @@
#include "btif_common.h"
#include "btif_gatt_multi_adv_util.h"
#include "btif_gatt_util.h"
+#include "device/include/controller.h"
extern fixed_queue_t *btu_general_alarm_queue;
@@ -54,6 +55,11 @@
btgatt_multi_adv_common_data *btif_obtain_multi_adv_data_cb()
{
+ if (!controller_get_interface()->get_is_ready())
+ {
+ BTIF_TRACE_ERROR("btif_obtain_multi_adv_data_cb controller not ready!");
+ return NULL;
+ }
int max_adv_inst = BTM_BleMaxMultiAdvInstanceCount();
if (0 == max_adv_inst)
max_adv_inst = 1;
diff --git a/btif/src/btif_gatt_qual.c b/btif/src/btif_gatt_qual.c
new file mode 100644
index 0000000..f973d67
--- /dev/null
+++ b/btif/src/btif_gatt_qual.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+#include "bt_utils.h"
+#include "gatt_api.h"
+#include "bta_api.h"
+
+#ifdef TEST_APP_INTERFACE
+#include <bt_testapp.h>
+
+UINT16 g_conn_id = 0;
+
+tGATT_IF Gatt_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
+{
+ tGATT_IF Gatt_if = 0;
+ Gatt_if = GATT_Register (p_app_uuid128, p_cb_info);
+ printf("%s:: Gatt_if=%d\n", __FUNCTION__, Gatt_if);
+ if (!BTM_SetSecurityLevel (TRUE, "gatt_tool", /*BTM_SEC_SERVICE_SDP_SERVER*/ BTM_SEC_PROTO_L2CAP,
+ 0, 0x1f, 0, 0))
+ {
+ BTIF_TRACE_DEBUG("Error:: BTM_SetSecurityLevel failed");
+ return FALSE;
+ }
+ return Gatt_if;
+
+}
+void Gatt_Deregister (tGATT_IF gatt_if)
+{
+ GATT_Deregister (gatt_if);
+ printf("%s:: \n", __FUNCTION__);
+}
+
+void Gatt_StartIf(tGATT_IF gatt_if)
+{
+ GATT_StartIf (gatt_if);
+ printf("%s::\n", __FUNCTION__);
+}
+
+BOOLEAN Gatt_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct,tBT_TRANSPORT transport)
+{
+ BOOLEAN Ret = 0;
+ Ret = GATT_Connect(gatt_if, bd_addr, is_direct,BT_TRANSPORT_LE, false);
+ printf("%s::Ret=%d,gatt_if=%d, is_direct=%d \n", __FUNCTION__, Ret, gatt_if, is_direct);
+ return Ret;
+}
+tGATT_STATUS Gatt_Disconnect (UINT16 conn_id)
+{
+ tGATT_STATUS Ret = 0;
+ Ret = GATT_Disconnect(conn_id);
+ printf("%s::Ret=%d,conn_id=%d\n", __FUNCTION__, Ret, conn_id);
+ return Ret;
+}
+
+BOOLEAN Gatt_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr)
+{
+ BOOLEAN Ret = 0;
+ Ret = GATT_Listen(gatt_if, start, bd_addr);
+ printf("%s::Ret=%d, gatt_if=%d, start=%d \n", __FUNCTION__, Ret, gatt_if, start);
+ return Ret;
+}
+ //GATT Client APIs
+ tGATT_STATUS Gatt_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
+ {
+ tGATT_STATUS Ret =0;
+ Ret = GATTC_ConfigureMTU(conn_id, mtu);
+ printf("%s::Ret=%d, conn_id=%d, mtu=%d \n", __FUNCTION__, Ret, conn_id, mtu);
+ return Ret;
+ }
+
+ tGATT_STATUS Gatt_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_PARAM *p_param )
+ {
+ tGATT_STATUS Ret = 0;
+ Ret = GATTC_Discover(conn_id, disc_type, p_param);
+ printf("%s::Ret=%d, conn_id=%d, disc_type=%d \n", __FUNCTION__, Ret, conn_id, disc_type);
+ return Ret;
+ }
+
+ tGATT_STATUS Gatt_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
+ {
+ tGATT_STATUS Ret = 0;
+ Ret = GATTC_Read(conn_id, type, p_read);
+ printf("%s::Ret=%d, conn_id=%d, type=%d \n", __FUNCTION__, Ret, conn_id, type);
+ return Ret;
+ }
+
+ tGATT_STATUS Gatt_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
+ {
+ tGATT_STATUS Ret = 0;
+ Ret = GATTC_Write(conn_id, type, p_write);
+ printf("%s::Ret=%d, conn_id=%d, type=%d \n", __FUNCTION__, Ret, conn_id, type);
+ return Ret;
+ }
+ tGATT_STATUS Gatt_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
+ {
+ tGATT_STATUS Ret = 0;
+ Ret = GATTC_ExecuteWrite(conn_id, is_execute);
+ printf("%s::Ret=%d, conn_id=%d, is_execute=%d \n", __FUNCTION__, Ret, conn_id, is_execute);
+ return Ret;
+ }
+ tGATT_STATUS Gatt_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
+ {
+ tGATT_STATUS Ret = 0;
+ Ret = GATTC_SendHandleValueConfirm(conn_id, handle);
+ printf("%s::Ret=%d, conn_id=%d, handle=%d \n", __FUNCTION__, Ret, conn_id, handle);
+ return Ret;
+ }
+
+ void Gatt_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout)
+ {
+ GATT_SetIdleTimeout (bd_addr, idle_tout,BT_TRANSPORT_LE);
+ printf("%s::\n", __FUNCTION__);
+ }
+
+ void Gatt_SetLeAdvMode (tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode)
+ {
+ printf("%s::call set Visibility\n", __FUNCTION__);
+ BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE);
+ }
+
+static const btgatt_test_interface_t btgatt_testInterface =
+{
+ sizeof(btgatt_test_interface_t),
+ Gatt_Register,
+ Gatt_Deregister,
+ Gatt_StartIf,
+ Gatt_Connect,
+ Gatt_Disconnect,
+ Gatt_Listen,
+ Gatt_ConfigureMTU,
+ Gatt_Discover,
+ Gatt_Read,
+ Gatt_Write,
+ Gatt_ExecuteWrite,
+ Gatt_SendHandleValueConfirm,
+ Gatt_SetIdleTimeout,
+ Gatt_SetLeAdvMode
+
+};
+
+
+const btgatt_test_interface_t *btif_gatt_test_get_interface(void)
+{
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ printf("\n%s\n", __FUNCTION__);
+ return &btgatt_testInterface;
+}
+
+#endif //TEST_APP_INTERFACE
diff --git a/btif/src/btif_gatt_server.c b/btif/src/btif_gatt_server.c
index 4a4cc5b..039db8d 100644
--- a/btif/src/btif_gatt_server.c
+++ b/btif/src/btif_gatt_server.c
@@ -187,8 +187,9 @@
bt_bdaddr_t bda;
bdcpy(bda.address, p_data->conn.remote_bda);
- btif_gatt_check_encrypted_link(p_data->conn.remote_bda, p_data->conn.transport);
-
+#if (!defined(BTA_SKIP_BLE_START_ENCRYPTION) || BTA_SKIP_BLE_START_ENCRYPTION == FALSE)
+ btif_gatt_check_encrypted_link(p_data->conn.remote_bda,p_data->conn.transport);
+#endif
HAL_CBACK(bt_gatt_callbacks, server->connection_cb,
p_data->conn.conn_id, p_data->conn.server_if, TRUE, &bda);
break;
@@ -358,6 +359,11 @@
static void btgatts_handle_event(uint16_t event, char* p_param)
{
+ if (!btif_is_enabled()) {
+ LOG_ERROR(LOG_TAG,"%s: bluetooth adapter not enabled",__FUNCTION__);
+ return;
+ }
+
btif_gatts_cb_t* p_cb = (btif_gatts_cb_t*)p_param;
if (!p_cb) return;
@@ -430,13 +436,15 @@
}
case BTIF_GATTS_CLOSE:
- // Cancel pending foreground/background connections
- BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, TRUE);
- BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, FALSE);
// Close active connection
if (p_cb->conn_id != 0)
BTA_GATTS_Close(p_cb->conn_id);
+ else
+ BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, TRUE);
+
+ // Cancel pending background connections
+ BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, FALSE);
break;
case BTIF_GATTS_CREATE_SERVICE:
diff --git a/btif/src/btif_gatt_util.c b/btif/src/btif_gatt_util.c
index c93d866..17661ea 100644
--- a/btif/src/btif_gatt_util.c
+++ b/btif/src/btif_gatt_util.c
@@ -118,20 +118,21 @@
memcpy(p_dest->attr_value.value, p_src->attr_value.value, GATT_MAX_ATTR_LEN);
}
-void btif_to_bta_uuid_mask(tBTA_DM_BLE_PF_COND_MASK *p_mask, bt_uuid_t *p_src)
+void btif_to_bta_uuid_mask(tBTA_DM_BLE_PF_COND_MASK *p_mask, bt_uuid_t *uuid_mask, bt_uuid_t *svc_uuid)
{
- char *p_byte = (char*)p_src;
+ char *p_byte = (char*)uuid_mask;
+ int uuid_len = uuidType(svc_uuid->uu);
int i = 0;
- switch (uuidType(p_src->uu))
+ switch (uuid_len)
{
case LEN_UUID_16:
- p_mask->uuid16_mask = (p_src->uu[13] << 8) + p_src->uu[12];
+ p_mask->uuid16_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
break;
case LEN_UUID_32:
- p_mask->uuid32_mask = (p_src->uu[13] << 8) + p_src->uu[12];
- p_mask->uuid32_mask += (p_src->uu[15] << 24) + (p_src->uu[14] << 16);
+ p_mask->uuid32_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
+ p_mask->uuid32_mask += (uuid_mask->uu[15] << 24) + (uuid_mask->uu[14] << 16);
break;
case LEN_UUID_128:
diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
index 9d963d1..9883f42 100644
--- a/btif/src/btif_hf.c
+++ b/btif/src/btif_hf.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <cutils/properties.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_hf.h>
@@ -40,6 +41,7 @@
#include "btif_common.h"
#include "btif_profile_queue.h"
#include "btif_util.h"
+#include "device/include/controller.h"
/************************************************************************************
** Constants & Macros
@@ -64,7 +66,6 @@
#define BTIF_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
#endif
-#if (BTM_WBS_INCLUDED == TRUE )
#ifndef BTIF_HF_FEATURES
#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
BTA_AG_FEAT_ECNR | \
@@ -73,25 +74,10 @@
BTA_AG_FEAT_EXTERR | \
BTA_AG_FEAT_BTRH | \
BTA_AG_FEAT_VREC | \
- BTA_AG_FEAT_CODEC |\
- BTA_AG_FEAT_HF_IND | \
- BTA_AG_FEAT_ESCO | \
+ BTA_AG_FEAT_HFIND | \
+ BTA_AG_FEAT_S4 | \
BTA_AG_FEAT_UNAT)
#endif
-#else
-#ifndef BTIF_HF_FEATURES
-#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
- BTA_AG_FEAT_ECNR | \
- BTA_AG_FEAT_REJECT | \
- BTA_AG_FEAT_ECS | \
- BTA_AG_FEAT_EXTERR | \
- BTA_AG_FEAT_BTRH | \
- BTA_AG_FEAT_VREC | \
- BTA_AG_FEAT_HF_IND | \
- BTA_AG_FEAT_ESCO | \
- BTA_AG_FEAT_UNAT)
-#endif
-#endif
#define BTIF_HF_CALL_END_TIMEOUT 6
@@ -100,6 +86,9 @@
/* Number of BTIF-HF control blocks */
#define BTIF_HF_NUM_CB 2
+/* Assigned number for mSBC codec */
+#define BTA_AG_MSBC_CODEC 5
+
/* Max HF clients supported from App */
UINT16 btif_max_hf_clients = 1;
@@ -127,6 +116,7 @@
************************************************************************************/
static bthf_callbacks_t *bt_hf_callbacks = NULL;
static int hf_idx = BTIF_HF_INVALID_IDX;
+static UINT32 btif_features = BTIF_HF_FEATURES;
#define CHECK_BTHF_INIT() if (bt_hf_callbacks == NULL)\
{\
@@ -135,7 +125,7 @@
}\
else\
{\
- BTIF_TRACE_EVENT("BTHF: %s", __FUNCTION__);\
+ BTIF_TRACE_IMP("BTHF: %s", __FUNCTION__);\
}
#define CHECK_BTHF_SLC_CONNECTED() if (bt_hf_callbacks == NULL)\
@@ -166,6 +156,7 @@
struct timespec call_end_timestamp;
struct timespec connected_timestamp;
bthf_call_state_t call_setup_state;
+ bthf_audio_state_t audio_state;
} btif_hf_cb_t;
static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
@@ -181,10 +172,12 @@
* codec unless this variable is set to TRUE.
*/
#ifndef BTIF_HF_WBS_PREFERRED
-#define BTIF_HF_WBS_PREFERRED FALSE
+#define BTIF_HF_WBS_PREFERRED TRUE
#endif
BOOLEAN btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
+BOOLEAN send_bvra_other_index = FALSE;
+int bvra_other_index_state = 0;
/************************************************************************************
** Functions
@@ -215,6 +208,88 @@
/*******************************************************************************
**
+** Function btif_hf_is_connected_on_other_idx
+**
+** Description Checks if any other AV SCB is connected
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+BOOLEAN btif_hf_is_connected_on_other_idx(int current_index)
+{
+ int i;
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ if (i != current_index)
+ {
+ if ((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_hf_get_other_connected_index
+**
+** Description Checks for other connected index
+**
+** Returns Other connected index
+**
+*******************************************************************************/
+
+int btif_hf_get_other_connected_index(int current_index)
+{
+ int i;
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ if (i != current_index)
+ {
+ if ((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED))
+ return i;
+ }
+ }
+ return btif_max_hf_clients;
+}
+/*******************************************************************************
+**
+** Function send_bvra_update
+**
+** Description Internal function to updated other connected HS for BVRA state
+**
+** Returns void
+**
+*******************************************************************************/
+static void send_bvra_update(int index)
+{
+ BTIF_TRACE_EVENT("connected %d",btif_hf_is_connected_on_other_idx(index));
+ if (btif_hf_is_connected_on_other_idx(index))
+ {
+ int other_idx = btif_hf_get_other_connected_index(index);
+ BTIF_TRACE_EVENT("other_idx %d",other_idx);
+ if (other_idx < btif_max_hf_clients &&
+ (btif_hf_cb[other_idx].peer_feat & BTA_AG_PEER_FEAT_VREC))
+ {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = bvra_other_index_state;
+ BTIF_TRACE_EVENT("sending on idex %d",other_idx);
+ BTA_AgResult (btif_hf_cb[other_idx].handle,
+ BTA_AG_BVRA_RES, &ag_res);
+ }
+ else
+ {
+ BTIF_TRACE_EVENT("Invalid connected index");
+ }
+ }
+
+}
+/*******************************************************************************
+**
** Function btif_hf_idx_by_bdaddr
**
** Description Internal function to get idx by bdaddr
@@ -227,7 +302,7 @@
int i;
for (i = 0; i < btif_max_hf_clients; ++i)
{
- if ((bdcmp(bd_addr->address,
+ if (is_connected(bd_addr) && (bdcmp(bd_addr->address,
btif_hf_cb[i].connected_bda.address) == 0))
return i;
}
@@ -371,6 +446,40 @@
}
}
+/*******************************************************************************
+**
+** Function btif_hf_check_if_sco_connected
+**
+** Description Returns BT_STATUS_SUCCESS if SCO is up for any HF
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t btif_hf_check_if_sco_connected()
+{
+ if (bt_hf_callbacks == NULL)
+ {
+ BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized. ", __FUNCTION__);
+ return BT_STATUS_NOT_READY;
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ if ((btif_hf_cb[i].audio_state == BTHF_AUDIO_STATE_CONNECTED) ||
+ (btif_hf_cb[i].audio_state == BTHF_AUDIO_STATE_CONNECTING))
+ {
+ BTIF_TRACE_EVENT("BTHF: %s: sco connected/connecting for idx = %d",
+ __FUNCTION__, i);
+ return BT_STATUS_SUCCESS;
+ }
+ }
+ BTIF_TRACE_WARNING("BTHF: %s: No SCO connection up", __FUNCTION__);
+ return BT_STATUS_NOT_READY;
+ }
+}
+
/*****************************************************************************
** Section name (Group of functions)
*****************************************************************************/
@@ -394,10 +503,23 @@
{
tBTA_AG *p_data = (tBTA_AG *)p_param;
bdstr_t bdstr;
- int idx = p_data->hdr.handle - 1;
+ int idx;
+ BOOLEAN ignore_rfc_fail = false;
- BTIF_TRACE_DEBUG("%s: event=%s", __FUNCTION__, dump_hf_event(event));
+ BTIF_TRACE_IMP("%s: event=%s", __FUNCTION__, dump_hf_event(event));
+ // for BTA_AG_ENABLE_EVT/BTA_AG_DISABLE_EVT, p_data is NULL
+ if (event == BTA_AG_ENABLE_EVT || event == BTA_AG_DISABLE_EVT)
+ return;
+
+ // p_data is NULL for any other event, return
+ if (p_data == NULL)
+ {
+ BTIF_TRACE_ERROR("%s: data is NULL", __FUNCTION__);
+ return;
+ }
+
+ idx = p_data->hdr.handle - 1;
if ((idx < 0) || (idx >= BTIF_HF_NUM_CB))
{
BTIF_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
@@ -406,10 +528,6 @@
switch (event)
{
- case BTA_AG_ENABLE_EVT:
- case BTA_AG_DISABLE_EVT:
- break;
-
case BTA_AG_REGISTER_EVT:
btif_hf_cb[idx].handle = p_data->reg.hdr.handle;
BTIF_TRACE_DEBUG("%s: BTA_AG_REGISTER_EVT,"
@@ -427,6 +545,18 @@
}
else if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_CONNECTING)
{
+ /* In Multi-hf, if outgoing RFCOMM connection fails due to collision,
+ * ignore the failure if HF is already connected.
+ */
+ if ( (btif_max_hf_clients > 1) &&
+ (p_data->open.status == BTA_AG_FAIL_RFCOMM) &&
+ (is_connected(&btif_hf_cb[idx].connected_bda)) )
+ {
+ BTIF_TRACE_WARNING("%s: Ignoring RFCOMM failure due to collision for dev %s",
+ __FUNCTION__, bdaddr_to_string(&btif_hf_cb[idx].connected_bda, bdstr, sizeof(bdstr)));
+ ignore_rfc_fail = true;
+ }
+
btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
}
else
@@ -437,19 +567,25 @@
break;
}
- HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ if (ignore_rfc_fail != true)
+ {
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
&btif_hf_cb[idx].connected_bda);
+ }
if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_DISCONNECTED)
bdsetany(btif_hf_cb[idx].connected_bda.address);
- if (p_data->open.status != BTA_AG_SUCCESS)
- btif_queue_advance();
+ btif_queue_advance();
+
break;
case BTA_AG_CLOSE_EVT:
btif_hf_cb[idx].connected_timestamp.tv_sec = 0;
btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+
+ BTIF_TRACE_IMP("%s: Moving the audio_state to DISCONNECTED", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_DISCONNECTED;
BTIF_TRACE_DEBUG("%s: BTA_AG_CLOSE_EVT,"
"idx = %d, btif_hf_cb.handle = %d", __FUNCTION__, idx,
btif_hf_cb[idx].handle);
@@ -476,16 +612,19 @@
HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
&btif_hf_cb[idx].connected_bda);
- btif_queue_advance();
break;
case BTA_AG_AUDIO_OPEN_EVT:
hf_idx = idx;
+ BTIF_TRACE_IMP("%s: Moving the audio_state to CONNECTED", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_CONNECTED;
HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED,
&btif_hf_cb[idx].connected_bda);
break;
case BTA_AG_AUDIO_CLOSE_EVT:
+ BTIF_TRACE_IMP("%s: Moving the audio_state to DISCONNECTED", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_DISCONNECTED;
HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED,
&btif_hf_cb[idx].connected_bda);
break;
@@ -541,6 +680,9 @@
HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
(p_data->val.num == 1) ? BTHF_VR_STATE_STARTED :
BTHF_VR_STATE_STOPPED, &btif_hf_cb[idx].connected_bda);
+ send_bvra_other_index = TRUE;
+ bvra_other_index_state = p_data->val.num;
+
break;
case BTA_AG_AT_NREC_EVT:
@@ -627,19 +769,26 @@
break;
case BTA_AG_AT_BIND_EVT:
- if (p_data->val.hdr.status == BTA_AG_SUCCESS)
+ switch(p_data->val.num)
{
- HAL_CBACK(bt_hf_callbacks, bind_cb,p_data->val.str,
- &btif_hf_cb[idx].connected_bda);
+ case BTA_AG_AT_SET:
+ HAL_CBACK(bt_hf_callbacks, bind_cmd_cb, p_data->val.str, BTHF_BIND_SET,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+ case BTA_AG_AT_READ:
+ HAL_CBACK(bt_hf_callbacks, bind_cmd_cb, p_data->val.str, BTHF_BIND_READ,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+ case BTA_AG_AT_TEST:
+ HAL_CBACK(bt_hf_callbacks, bind_cmd_cb, p_data->val.str, BTHF_BIND_TEST,
+ &btif_hf_cb[idx].connected_bda);
+ break;
}
break;
-
case BTA_AG_AT_BIEV_EVT:
- if (p_data->val.hdr.status == BTA_AG_SUCCESS)
- {
- HAL_CBACK(bt_hf_callbacks, biev_cb, (bthf_hf_ind_type_t)p_data->val.lidx, (int)p_data->val.num,
- &btif_hf_cb[idx].connected_bda);
- }
+ HAL_CBACK(bt_hf_callbacks, biev_cmd_cb, p_data->val.str,
+ &btif_hf_cb[idx].connected_bda);
+
break;
default:
BTIF_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
@@ -706,6 +855,8 @@
switch (event) {
case BTIF_HFP_CB_AUDIO_CONNECTING:
{
+ BTIF_TRACE_IMP("%s: Moving the audio_state to CONNECTING", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_CONNECTING;
HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
&btif_hf_cb[idx].connected_bda);
} break;
@@ -815,7 +966,7 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
BTA_AgClose(btif_hf_cb[idx].handle);
return BT_STATUS_SUCCESS;
@@ -849,7 +1000,7 @@
if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
return BT_STATUS_NOT_READY;
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
BTA_AgAudioOpen(btif_hf_cb[idx].handle);
@@ -883,7 +1034,7 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
BTA_AgAudioClose(btif_hf_cb[idx].handle);
return BT_STATUS_SUCCESS;
@@ -904,33 +1055,29 @@
static bt_status_t start_voice_recognition(bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
-
- int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
- if ((idx < 0) || (idx >= BTIF_HF_NUM_CB))
+ BOOLEAN is_success = FALSE;
+ for (int i = 0; i < btif_max_hf_clients; i++)
{
- BTIF_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
- return BT_STATUS_FAIL;
- }
-
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
- {
- if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)
+ if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
+ btif_hf_cb[i].peer_feat & BTA_AG_PEER_FEAT_VREC)
{
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof(ag_res));
ag_res.state = 1;
- BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
-
- return BT_STATUS_SUCCESS;
- }
- else
- {
- return BT_STATUS_UNSUPPORTED;
+ BTA_AgResult (btif_hf_cb[i].handle, BTA_AG_BVRA_RES, &ag_res);
+ is_success = TRUE;
}
}
- return BT_STATUS_NOT_READY;
+ if (is_success)
+ {
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ return BT_STATUS_NOT_READY;
+ }
}
/*******************************************************************************
@@ -945,33 +1092,29 @@
static bt_status_t stop_voice_recognition(bt_bdaddr_t *bd_addr)
{
CHECK_BTHF_INIT();
-
- int idx = btif_hf_idx_by_bdaddr(bd_addr);
-
- if ((idx < 0) || (idx >= BTIF_HF_NUM_CB))
+ BOOLEAN is_success = FALSE;
+ for (int i = 0; i < btif_max_hf_clients; i++)
{
- BTIF_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
- return BT_STATUS_FAIL;
- }
-
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
- {
- if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)
+ if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
+ btif_hf_cb[i].peer_feat & BTA_AG_PEER_FEAT_VREC)
{
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof(ag_res));
ag_res.state = 0;
- BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
-
- return BT_STATUS_SUCCESS;
- }
- else
- {
- return BT_STATUS_UNSUPPORTED;
+ BTA_AgResult (btif_hf_cb[i].handle, BTA_AG_BVRA_RES, &ag_res);
+ is_success = TRUE;
}
}
- return BT_STATUS_NOT_READY;
+ if (is_success)
+ {
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ return BT_STATUS_NOT_READY;
+ }
}
/*******************************************************************************
@@ -998,7 +1141,7 @@
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
ag_res.num = volume;
BTA_AgResult(btif_hf_cb[idx].handle,
@@ -1062,7 +1205,7 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
tBTA_AG_RES_DATA ag_res;
@@ -1100,7 +1243,7 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
tBTA_AG_RES_DATA ag_res;
@@ -1127,33 +1270,6 @@
/*******************************************************************************
**
-** Function bind_response
-**
-** Description Send +BIND response
-**
-** Returns bt_status_t
-**
-*******************************************************************************/
-static bt_status_t bind_response(bthf_hf_ind_type_t ind_id, bthf_hf_ind_status_t ind_status,
- bt_bdaddr_t * bd_addr)
-{
- CHECK_BTHF_INIT();
-
- int index = btif_hf_idx_by_bdaddr(bd_addr);
- if (!is_connected(bd_addr) || index == BTIF_HF_INVALID_IDX)
- return BT_STATUS_FAIL;
-
- tBTA_AG_RES_DATA ag_res;
- memset(&ag_res, 0, sizeof(ag_res));
- ag_res.ind.id = ind_id;
- ag_res.ind.on_demand = (ind_status == BTHF_HF_IND_ENABLED);
-
- BTA_AgResult(btif_hf_cb[index].handle, BTA_AG_BIND_RES, &ag_res);
- return BT_STATUS_SUCCESS;
-}
-
-/*******************************************************************************
-**
** Function formatted_at_response
**
** Description Pre-formatted AT response, typically in response to unknown AT cmd
@@ -1173,7 +1289,7 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
/* Format the response and send */
memset (&ag_res, 0, sizeof (ag_res));
@@ -1208,10 +1324,15 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
: BTA_AG_OK_ERROR, error_code, idx);
+ if (response_code == BTHF_AT_RESPONSE_OK && send_bvra_other_index)
+ {
+ send_bvra_update(idx);
+ send_bvra_other_index = FALSE;
+ }
return BT_STATUS_SUCCESS;
}
@@ -1244,7 +1365,7 @@
return BT_STATUS_FAIL;
}
- if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
+ if (idx != BTIF_HF_INVALID_IDX)
{
tBTA_AG_RES_DATA ag_res;
int xx;
@@ -1306,6 +1427,8 @@
BOOLEAN activeCallUpdated = FALSE;
int idx, i;
+ memset(&ag_res, 0, sizeof(ag_res));
+
/* hf_idx is index of connected HS that sent ATA/BLDN,
otherwise index of latest connected HS */
if (hf_idx != BTIF_HF_INVALID_IDX)
@@ -1313,13 +1436,13 @@
else
idx = btif_hf_latest_connected_idx();
- BTIF_TRACE_DEBUG("phone_state_change: idx = %d", idx);
+ BTIF_TRACE_IMP("phone_state_change: idx = %d", idx);
/* Check if SLC is connected */
if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
return BT_STATUS_NOT_READY;
- BTIF_TRACE_DEBUG("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"
+ BTIF_TRACE_IMP("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"
" call_setup=%s [prev: %s]", num_active, btif_hf_cb[idx].num_active,
num_held, btif_hf_cb[idx].num_held, dump_hf_call_state(call_setup_state),
dump_hf_call_state(btif_hf_cb[idx].call_setup_state));
@@ -1361,11 +1484,14 @@
if ( ((num_active + num_held) > 0) && (btif_hf_cb[idx].num_active == 0) && (btif_hf_cb[idx].num_held == 0) &&
(btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) )
{
- BTIF_TRACE_DEBUG("%s: Active/Held call notification received without call setup update",
+ BTIF_TRACE_IMP("%s: Active/Held call notification received without call setup update",
__FUNCTION__);
memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
ag_res.audio_handle = btif_hf_cb[idx].handle;
+
+ BTIF_TRACE_IMP("%s: Moving the audio_state to CONNECTING", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_CONNECTING;
/* Addition call setup with the Active call
** CIND response should have been updated.
** just open SCO conenction.
@@ -1381,7 +1507,7 @@
/* Ringing call changed? */
if (call_setup_state != btif_hf_cb[idx].call_setup_state)
{
- BTIF_TRACE_DEBUG("%s: Call setup states changed. old: %s new: %s",
+ BTIF_TRACE_IMP("%s: Call setup states changed. old: %s new: %s",
__FUNCTION__, dump_hf_call_state(btif_hf_cb[idx].call_setup_state),
dump_hf_call_state(call_setup_state));
memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
@@ -1397,6 +1523,10 @@
{
res = BTA_AG_IN_CALL_CONN_RES;
ag_res.audio_handle = btif_hf_cb[idx].handle;
+
+ BTIF_TRACE_IMP("%s: Moving the audio_state to CONNECTING",
+ __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_CONNECTING;
}
else if (num_held > btif_hf_cb[idx].num_held)
res = BTA_AG_IN_CALL_HELD_RES;
@@ -1447,14 +1577,33 @@
break;
case BTHF_CALL_STATE_DIALING:
if (!(num_active + num_held))
+ {
ag_res.audio_handle = btif_hf_cb[idx].handle;
+
+ BTIF_TRACE_IMP("%s: Moving the audio_state to CONNECTING", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_CONNECTING;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s: Already in a call, don't set audio handle", __FUNCTION__);
+ }
res = BTA_AG_OUT_CALL_ORIG_RES;
break;
case BTHF_CALL_STATE_ALERTING:
/* if we went from idle->alert, force SCO setup here. dialing usually triggers it */
if ((btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) &&
!(num_active + num_held))
+ {
ag_res.audio_handle = btif_hf_cb[idx].handle;
+
+ BTIF_TRACE_IMP("%s: Moving the audio_state to CONNECTING", __FUNCTION__);
+ btif_hf_cb[idx].audio_state = BTHF_AUDIO_STATE_CONNECTING;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s: Already in a call or prev call state was dialing,"
+ " don't set audio handle", __FUNCTION__);
+ }
res = BTA_AG_OUT_CALL_ALERT_RES;
break;
default:
@@ -1462,7 +1611,7 @@
status = BT_STATUS_PARM_INVALID;
break;
}
- BTIF_TRACE_DEBUG("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
+ BTIF_TRACE_IMP("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
if (res)
BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
@@ -1486,7 +1635,7 @@
if (!activeCallUpdated && ((num_active + num_held) !=
(btif_hf_cb[idx].num_active + btif_hf_cb[idx].num_held)) )
{
- BTIF_TRACE_DEBUG("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb[idx].num_active, num_active);
+ BTIF_TRACE_IMP("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb[idx].num_active, num_active);
send_indicator_update(BTA_AG_IND_CALL, ((num_active + num_held) > 0) ? 1 : 0);
}
@@ -1494,7 +1643,7 @@
if (num_held != btif_hf_cb[idx].num_held ||
((num_active == 0) && ((num_held + btif_hf_cb[idx].num_held) > 1)))
{
- BTIF_TRACE_DEBUG("%s: Held call states changed. old: %d new: %d",
+ BTIF_TRACE_IMP("%s: Held call states changed. old: %d new: %d",
__FUNCTION__, btif_hf_cb[idx].num_held, num_held);
send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
}
@@ -1505,39 +1654,57 @@
(num_active == btif_hf_cb[idx].num_active) &&
(num_held == btif_hf_cb[idx].num_held) )
{
- BTIF_TRACE_DEBUG("%s: Calls swapped", __FUNCTION__);
+ BTIF_TRACE_IMP("%s: Calls swapped", __FUNCTION__);
send_indicator_update(BTA_AG_IND_CALLHELD, 1);
}
update_call_states:
for (i = 0; i < btif_max_hf_clients; i++)
{
- btif_hf_cb[i].num_active = num_active;
- btif_hf_cb[i].num_held = num_held;
- btif_hf_cb[i].call_setup_state = call_setup_state;
+ if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+ btif_hf_cb[i].num_active = num_active;
+ btif_hf_cb[i].num_held = num_held;
+ btif_hf_cb[i].call_setup_state = call_setup_state;
+ }
}
return status;
}
/*******************************************************************************
**
-** Function btif_hf_is_call_idle
+** Function btif_hf_is_call_vr_idle
**
** Description returns true if no call is in progress
**
** Returns bt_status_t
**
*******************************************************************************/
-BOOLEAN btif_hf_is_call_idle()
+BOOLEAN btif_hf_is_call_vr_idle()
{
- if (bt_hf_callbacks == NULL)
- return TRUE;
+ int i, j = 1;
- for (int i = 0; i < btif_max_hf_clients; ++i)
+ if (bt_hf_callbacks == NULL)
{
- if ((btif_hf_cb[i].call_setup_state != BTHF_CALL_STATE_IDLE)
- || ((btif_hf_cb[i].num_held + btif_hf_cb[i].num_active) > 0))
- return FALSE;
+ return TRUE;
+ }
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ BTIF_TRACE_EVENT("%s: call_setup_state: %d for handle: %d",
+ __FUNCTION__, btif_hf_cb[i].call_setup_state, btif_hf_cb[i].handle);
+ BTIF_TRACE_EVENT("num_held: %d, num_active: %d for handle: %d",
+ btif_hf_cb[i].num_held, btif_hf_cb[i].num_active, btif_hf_cb[i].handle);
+ j &= ((btif_hf_cb[i].call_setup_state == BTHF_CALL_STATE_IDLE) &&
+ ((btif_hf_cb[i].num_held + btif_hf_cb[i].num_active) == 0));
+ }
+
+ if (j && (btif_hf_check_if_sco_connected() != BT_STATUS_SUCCESS))
+ {
+ BTIF_TRACE_EVENT("%s: call state idle and no sco connected.", __FUNCTION__);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
}
return TRUE;
@@ -1580,13 +1747,13 @@
*******************************************************************************/
static void cleanup( void )
{
- BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ BTIF_TRACE_IMP("%s", __FUNCTION__);
- if (bt_hf_callbacks)
- {
- btif_disable_service(BTA_HFP_SERVICE_ID);
- bt_hf_callbacks = NULL;
- }
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+ btif_disable_service(BTA_HFP_SERVICE_ID);
+#else
+ btif_disable_service(BTA_HSP_SERVICE_ID);
+#endif
}
/*******************************************************************************
@@ -1623,6 +1790,151 @@
return BT_STATUS_SUCCESS;
}
+/*******************************************************************************
+**
+** Function bind_response
+**
+** Description response for BIND READ command
+** Can be iteratively called for each Hf indicator.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t bind_response(int anum, bthf_hf_indicator_status_t status,
+ bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB))
+ {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (idx != BTIF_HF_INVALID_IDX)
+ {
+ tBTA_AG_RES_DATA ag_res;
+ int xx;
+
+ memset (&ag_res, 0, sizeof (ag_res));
+
+ /* Format the response */
+ BTIF_TRACE_EVENT("bind_response: anum : [%d] status %d ", anum, status);
+ xx = snprintf (ag_res.str, sizeof(ag_res.str), "%d,%d", anum, status);
+
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BIND_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function bind_string_response
+**
+** Description response for BIND TEST command
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t bind_string_response(const char* res,
+ bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB))
+ {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (idx != BTIF_HF_INVALID_IDX)
+ {
+ tBTA_AG_RES_DATA ag_res;
+ int xx;
+
+ memset (&ag_res, 0, sizeof (ag_res));
+
+ /* Format the response */
+ xx = snprintf (ag_res.str, sizeof(ag_res.str), "%s", res);
+
+ BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BIND_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+static void set_voip_network_type_wifi_hci_cmd_complete(tBTM_VSC_CMPL* p_data)
+{
+ UINT8 *stream, status, subcmd;
+ UINT16 opcode, length;
+
+ if (p_data && (stream = (UINT8*)p_data->p_param_buf))
+ {
+ opcode = p_data->opcode;
+ length = p_data->param_len;
+ STREAM_TO_UINT8(status, stream);
+ STREAM_TO_UINT8(subcmd, stream);
+ BTIF_TRACE_DEBUG("%s opcode = 0x%04X, length = %d, status = %d, subcmd = %d",
+ __FUNCTION__, opcode, length, status, subcmd);
+ if (status == HCI_SUCCESS)
+ {
+ BTIF_TRACE_DEBUG("btm_SetVoipNetworkTypeWifi status success");
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function voip_network_type_wifi
+**
+** Description BT app updates the connectivity network used for VOIP as Wifi
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t voip_network_type_wifi(bthf_voip_state_t isVoipStarted,
+ bthf_voip_call_network_type_t isNetworkWifi)
+{
+ UINT8 cmd[3], *p_cursor;
+ UINT8 sub_cmd = HCI_VSC_SUBCODE_VOIP_NETWORK_WIFI;
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ int idx = btif_hf_latest_connected_idx();
+
+ CHECK_BTHF_INIT();
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB))
+ {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ p_cursor = cmd;
+ memset(cmd, 0, 3);
+
+ *p_cursor++ = sub_cmd;
+ *p_cursor++ = isVoipStarted;
+ *p_cursor++ = isNetworkWifi;
+
+ if ((status = BTM_VendorSpecificCommand(HCI_VSC_VOIP_NETWORK_WIFI_OCF, sizeof(cmd),
+ cmd, set_voip_network_type_wifi_hci_cmd_complete)) != BTM_CMD_STARTED)
+ {
+ BTIF_TRACE_ERROR("%s: status %d", __FUNCTION__, status);
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+
+}
+
static const bthf_interface_t bthfInterface = {
sizeof(bthfInterface),
init,
@@ -1643,6 +1955,8 @@
cleanup,
configure_wbs,
bind_response,
+ bind_string_response,
+ voip_network_type_wifi,
};
/*******************************************************************************
@@ -1656,28 +1970,60 @@
*******************************************************************************/
bt_status_t btif_hf_execute_service(BOOLEAN b_enable)
{
- char * p_service_names[] = BTIF_HF_SERVICE_NAMES;
- int i;
- if (b_enable)
- {
- /* Enable and register with BTA-AG */
- BTA_AgEnable (BTA_AG_PARSE, bte_hf_evt);
- for (i = 0; i < btif_max_hf_clients; i++)
- {
- BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY,
- BTIF_HF_FEATURES, p_service_names, bthf_hf_id[i]);
- }
- }
- else {
- /* De-register AG */
- for (i = 0; i < btif_max_hf_clients; i++)
- {
- BTA_AgDeregister(btif_hf_cb[i].handle);
- }
- /* Disable AG */
- BTA_AgDisable();
- }
- return BT_STATUS_SUCCESS;
+ char * p_service_names[] = BTIF_HF_SERVICE_NAMES;
+ int i;
+ uint8_t no_of_codecs = 0;
+ uint8_t* codecs;
+ char value[PROPERTY_VALUE_MAX];
+
+ BTIF_TRACE_IMP("%s: enable: %d", __FUNCTION__, b_enable);
+
+ if (b_enable)
+ {
+ /* Enable and register with BTA-AG */
+ BTA_AgEnable (BTA_AG_PARSE, bte_hf_evt);
+ codecs = controller_get_interface()->get_local_supported_codecs(&no_of_codecs);
+ if (codecs != NULL)
+ {
+ for (i = 0; i < no_of_codecs; i++)
+ {
+ if (codecs[i] == BTA_AG_MSBC_CODEC)
+ {
+ btif_features |= BTA_AG_FEAT_CODEC;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Read the property if local supported codecs commands is not supported */
+ if (property_get("ro.bluetooth.hfp.ver", value, "1.5") &&
+ (!strcmp(value, "1.6") || !strcmp(value, "1.7")) )
+ btif_features |= BTA_AG_FEAT_CODEC;
+ }
+
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY,
+ btif_features, p_service_names, bthf_hf_id[i]);
+ }
+ }
+ else {
+ if (bt_hf_callbacks)
+ {
+ BTIF_TRACE_IMP("%s: setting call backs to NULL", __FUNCTION__);
+ bt_hf_callbacks = NULL;
+ }
+ /* De-register AG */
+ for (i = 0; i < btif_max_hf_clients; i++)
+ {
+ BTA_AgDeregister(btif_hf_cb[i].handle);
+ }
+ /* Disable AG */
+ BTA_AgDisable();
+ }
+ BTIF_TRACE_IMP("%s: enable: %d completed", __FUNCTION__, b_enable);
+ return BT_STATUS_SUCCESS;
}
/*******************************************************************************
diff --git a/btif/src/btif_hf_client.c b/btif/src/btif_hf_client.c
index bdf0874..5ebb965 100644
--- a/btif/src/btif_hf_client.c
+++ b/btif/src/btif_hf_client.c
@@ -400,7 +400,7 @@
{
CHECK_BTHF_CLIENT_SLC_CONNECTED();
- if (number)
+ if (strcmp(number,"") != 0)
{
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0, number);
}
@@ -640,11 +640,7 @@
{
BTIF_TRACE_EVENT("%s", __FUNCTION__);
- if (bt_hf_client_callbacks)
- {
- btif_disable_service(BTA_HFP_HS_SERVICE_ID);
- bt_hf_client_callbacks = NULL;
- }
+ btif_disable_service(BTA_HFP_HS_SERVICE_ID);
}
/*******************************************************************************
@@ -738,7 +734,7 @@
tBTA_HF_CLIENT *p_data = (tBTA_HF_CLIENT *)p_param;
bdstr_t bdstr;
- BTIF_TRACE_DEBUG("%s: event=%s (%u)", __FUNCTION__, dump_hf_client_event(event), event);
+ BTIF_TRACE_IMP("%s: event=%s (%u)", __FUNCTION__, dump_hf_client_event(event), event);
switch (event)
{
@@ -899,6 +895,12 @@
case BTA_HF_CLIENT_RING_INDICATION:
HAL_CBACK(bt_hf_client_callbacks, ring_indication_cb);
break;
+ case BTA_HF_CLIENT_CGMI_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, cgmi_cb, p_data->cgmi.name);
+ break;
+ case BTA_HF_CLIENT_CGMM_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, cgmm_cb, p_data->cgmm.model);
+ break;
default:
BTIF_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
break;
@@ -945,7 +947,7 @@
{
/* Enable and register with BTA-HFClient */
BTA_HfClientEnable(bte_hf_client_evt);
- if (strcmp(btif_hf_client_version, "1.6") == 0)
+ if (strtof(btif_hf_client_version, NULL) >= 1.6)
{
BTIF_TRACE_EVENT("Support Codec Nego. %d ", BTIF_HF_CLIENT_FEATURES);
BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, BTIF_HF_CLIENT_FEATURES,
@@ -964,9 +966,15 @@
}
else
{
+ if (bt_hf_client_callbacks)
+ {
+ BTIF_TRACE_IMP("%s: setting call backs to NULL", __FUNCTION__);
+ bt_hf_client_callbacks = NULL;
+ }
BTA_HfClientDeregister(btif_hf_client_cb.handle);
BTA_HfClientDisable();
}
+ BTIF_TRACE_IMP("%s: enable: %d completed", __FUNCTION__, b_enable);
return BT_STATUS_SUCCESS;
}
diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c
index 9d883bb..a4057cc 100644
--- a/btif/src/btif_hh.c
+++ b/btif/src/btif_hh.c
@@ -150,6 +150,7 @@
extern void btif_dm_cb_remove_bond(bt_bdaddr_t *bd_addr);
extern BOOLEAN check_cod_hid(const bt_bdaddr_t *remote_bdaddr);
extern int scru_ascii_2_hex(char *p_ascii, int len, UINT8 *p_hex);
+extern void btif_dm_hh_open_success(bt_bdaddr_t *bdaddr);
extern void btif_dm_hh_open_failed(bt_bdaddr_t *bdaddr);
/*****************************************************************************
@@ -482,6 +483,13 @@
LOG_INFO(LOG_TAG, "%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __FUNCTION__,
bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+ /* Check if this is not received while hid host service is disabled */
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_WARNING("%s: HH service not enabled", __FUNCTION__);
+ return;
+ }
+
for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
p_added_dev = &btif_hh_cb.added_devices[i];
if (memcmp(&(p_added_dev->bd_addr),&bd_addr, 6) == 0) {
@@ -556,6 +564,12 @@
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
btif_hh_device_t *p_dev;
char bd_str[18];
+ /* Check if this is not received while hid host service is disabled */
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_WARNING("%s: HH service not enabled", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
sprintf(bd_str, "%02X:%02X:%02X:%02X:%02X:%02X",
bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3],
bd_addr->address[4], bd_addr->address[5]);
@@ -595,6 +609,12 @@
int i;
BD_ADDR *bda = (BD_ADDR*)bd_addr;
CHECK_BTHH_INIT();
+ /* Check if this is not received while hid host service is disabled */
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_WARNING("%s: HH service not enabled", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
dev = btif_hh_find_dev_by_bda(bd_addr);
BTIF_TRACE_DEBUG("Connect _hh");
sprintf(bda_str, "%02X:%02X:%02X:%02X:%02X:%02X",
@@ -677,6 +697,22 @@
BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
}
+/*******************************************************************************
+**
+** Function btif_hh_getreport
+**
+** Description getreport initiated from the BTIF thread context
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hh_getreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type,
+ UINT8 reportId, UINT16 bufferSize)
+
+{
+ BTA_HhGetReport(p_dev->dev_handle, r_type, reportId, bufferSize);
+}
+
/*****************************************************************************
** Section name (Group of functions)
*****************************************************************************/
@@ -758,6 +794,7 @@
BTA_HhClose(p_data->conn.handle);
}
else {
+ btif_dm_hh_open_success((bt_bdaddr_t*)p_data->conn.bda);
BTIF_TRACE_WARNING("BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle ... %d",p_data->conn.handle);
memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
btif_hh_cb.status = BTIF_HH_DEV_CONNECTED;
@@ -857,7 +894,7 @@
break;
case BTA_HH_GET_PROTO_EVT:
- p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
BTIF_TRACE_WARNING("BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s",
p_data->hs_data.status, p_data->hs_data.handle,
p_data->hs_data.rsp_data.proto_mode,
@@ -890,6 +927,9 @@
BTIF_TRACE_DEBUG("BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d",
p_data->hs_data.handle, p_data->hs_data.status,
p_data->hs_data.rsp_data.idle_rate);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
+ HAL_CBACK(bt_hh_callbacks, idle_time_cb,(bt_bdaddr_t*) &(p_dev->bd_addr),
+ (bthh_status_t) p_data->hs_data.status, p_data->hs_data.rsp_data.idle_rate);
break;
case BTA_HH_SET_IDLE_EVT:
@@ -935,6 +975,7 @@
bdcpy(bda, p_dev->bd_addr.address);
tBTA_HH_DEV_DSCP_INFO dscp_info;
bt_status_t ret;
+ memset(&dscp_info, 0, sizeof(dscp_info));
bdcpy(bda, p_dev->bd_addr.address);
btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info);
BTIF_TRACE_DEBUG("BTA_HH_GET_DSCP_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
@@ -1207,6 +1248,11 @@
*******************************************************************************/
static bt_status_t connect( bt_bdaddr_t *bd_addr)
{
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_WARNING("%s: HH service not enabled", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
if(btif_hh_cb.status != BTIF_HH_DEV_CONNECTING)
{
btif_transfer_context(btif_hh_handle_evt, BTIF_HH_CONNECT_REQ_EVT,
@@ -1311,6 +1357,8 @@
return BT_STATUS_FAIL;
}
+ memset(&dscp_info, 0, sizeof(dscp_info));
+
dscp_info.vendor_id = hid_info.vendor_id;
dscp_info.product_id = hid_info.product_id;
dscp_info.version = hid_info.version;
@@ -1333,6 +1381,74 @@
/*******************************************************************************
**
+** Function get_idle_time
+**
+** Description Get the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_idle_time(bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG(" addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ BTA_HhGetIdle(p_dev->dev_handle);
+ }
+ else {
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_idle_time
+**
+** Description Set the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_idle_time (bt_bdaddr_t *bd_addr, uint8_t idle_time)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ BTA_HhSetIdle(p_dev->dev_handle, idle_time);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
** Function get_protocol
**
** Description Get the HID proto mode.
@@ -1624,8 +1740,8 @@
set_info,
get_protocol,
set_protocol,
-// get_idle_time,
-// set_idle_time,
+ get_idle_time,
+ set_idle_time,
get_report,
set_report,
send_data,
diff --git a/btif/src/btif_hl.c b/btif/src/btif_hl.c
index 97ca1c2..dcd8db4 100644
--- a/btif/src/btif_hl.c
+++ b/btif/src/btif_hl.c
@@ -3190,6 +3190,7 @@
break;
case BTIF_HL_REG_APP:
+ reg_counter++;
p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->reg.app_idx);
BTIF_TRACE_DEBUG("Rcv BTIF_HL_REG_APP app_idx=%d reg_pending=%d", p_data->reg.app_idx, p_acb->reg_pending);
if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED && p_acb->reg_pending)
@@ -3211,6 +3212,7 @@
break;
case BTIF_HL_UNREG_APP:
+ reg_counter--;
BTIF_TRACE_DEBUG("Rcv BTIF_HL_UNREG_APP app_idx=%d", p_data->unreg.app_idx );
p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->unreg.app_idx);
if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED)
@@ -4038,7 +4040,6 @@
if (btif_hl_find_app_idx(((UINT8)app_id), &app_idx))
{
evt_param.unreg.app_idx = app_idx;
- reg_counter --;
len = sizeof(btif_hl_unreg_t);
status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_UNREG_APP,
(char*) &evt_param, len, NULL);
@@ -4164,7 +4165,6 @@
evt_param.reg.app_idx = app_idx;
len = sizeof(btif_hl_reg_t);
p_acb->reg_pending = TRUE;
- reg_counter++;
BTIF_TRACE_DEBUG("calling btif_transfer_context status=%d app_id=%d", status, *app_id);
status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_REG_APP,
(char*) &evt_param, len, NULL);
diff --git a/btif/src/btif_l2cap.c b/btif/src/btif_l2cap.c
new file mode 100644
index 0000000..c44fe57
--- /dev/null
+++ b/btif/src/btif_l2cap.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <hardware/bluetooth.h>
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+#include "bt_utils.h"
+#include "l2cdefs.h"
+#include "l2c_api.h"
+#include <l2c_int.h>
+#if TEST_APP_INTERFACE == TRUE
+#include <bt_testapp.h>
+
+static tL2CAP_APPL_INFO *pl2test_l2c_appl = NULL;
+static bt_status_t L2cap_Init (tL2CAP_APPL_INFO *p);
+static bt_status_t L2cap_Register (UINT16 psm, BOOLEAN ConnType, UINT16 SecLevel);
+static bt_status_t L2cap_DeRegister (UINT16 psm);
+static UINT16 L2cap_AllocatePSM(void);
+static UINT16 L2cap_Connect(UINT16 psm, bt_bdaddr_t *bd_addr);
+static BOOLEAN L2cap_ConnectRsp(BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status);
+static UINT16 L2cap_ErtmConnect(UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info);
+static BOOLEAN L2cap_ErtmConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status,
+ tL2CAP_ERTM_INFO *p_ertm_info);
+static BOOLEAN L2cap_ConfigReq(UINT16 cid, tL2CAP_CFG_INFO *p_cfg);
+static BOOLEAN L2cap_ConfigRsp(UINT16 cid, tL2CAP_CFG_INFO *p_cfg);
+static BOOLEAN L2cap_DisconnectReq (UINT16 cid);
+static BOOLEAN L2cap_DisconnectRsp (UINT16 cid);
+static UINT8 L2cap_DataWrite (UINT16 cid, char *p_data, UINT32 len);
+static BOOLEAN L2cap_Ping (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_cb);
+static BOOLEAN L2cap_Echo (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback);
+static BOOLEAN L2cap_SetIdleTimeout (UINT16 cid, UINT16 timeout, BOOLEAN is_global);
+static BOOLEAN L2cap_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, UINT16 timeout);
+static void L2cap_SetSecConnOnlyMode (BOOLEAN secvalue);
+static UINT8 L2cap_SetDesireRole (UINT8 new_role);
+static UINT16 L2cap_LocalLoopbackReq (UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr);
+static UINT16 L2cap_FlushChannel (UINT16 lcid, UINT16 num_to_flush);
+static BOOLEAN L2cap_SetAclPriority (BD_ADDR bd_addr, UINT8 priority);
+static BOOLEAN L2cap_FlowControl (UINT16 cid, BOOLEAN data_enabled);
+static BOOLEAN L2cap_SendTestSFrame (UINT16 cid, BOOLEAN rr_or_rej, UINT8 back_track);
+static BOOLEAN L2cap_SetTxPriority (UINT16 cid, tL2CAP_CHNL_PRIORITY priority);
+static BOOLEAN L2cap_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda);
+static BOOLEAN L2cap_SetChnlDataRate (UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx);
+static BOOLEAN L2cap_SetFlushTimeout (BD_ADDR bd_addr, UINT16 flush_tout);
+static UINT8 L2cap_DataWriteEx (UINT16 cid, BT_HDR *p_data, UINT16 flags);
+static BOOLEAN L2cap_SetChnlFlushability (UINT16 cid, BOOLEAN is_flushable);
+static BOOLEAN L2cap_GetPeerFeatures (BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask);
+static BOOLEAN L2cap_GetBDAddrbyHandle (UINT16 handle, BD_ADDR bd_addr);
+static UINT8 L2cap_GetChnlFcrMode (UINT16 lcid);
+static UINT16 L2cap_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf);
+static bt_status_t L2cap_LE_Register (UINT16 le_psm, BOOLEAN ConnType, UINT16 SecLevel, UINT8 enc_key_size);
+static bt_status_t L2cap_LE_DeRegister (UINT16 psm);
+static UINT16 L2cap_LE_Connect(UINT16 le_psm , BD_ADDR address, tL2CAP_LE_CFG_INFO *p_cfg);
+static BOOLEAN L2cap_LE_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result,
+ UINT16 status, tL2CAP_LE_CFG_INFO *p_cfg);
+//static BOOLEAN L2cap_LE_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, tL2CAP_LE_CFG_INFO *p_cfg);
+static BOOLEAN L2cap_LE_FlowControl (UINT16 lcid, UINT16 credits);
+static void L2cap_LE_freebuf(BT_HDR *p_buf);
+
+static const btl2cap_interface_t btl2capInterface = {
+ sizeof(btl2cap_interface_t),
+ L2cap_Init,
+ L2cap_Register,
+ L2cap_DeRegister,
+ L2cap_AllocatePSM,
+ L2cap_Connect,
+ L2cap_ConnectRsp,
+ L2cap_ErtmConnect,
+ L2cap_ErtmConnectRsp,
+ L2cap_ConfigReq,
+ L2cap_ConfigRsp,
+ L2cap_DisconnectReq,
+ L2cap_DisconnectRsp,
+ L2cap_DataWrite,
+ L2cap_Ping,
+ L2cap_Echo,
+ L2cap_SetIdleTimeout,
+ L2cap_SetIdleTimeoutByBdAddr,
+ L2cap_SetDesireRole,
+ L2cap_SetSecConnOnlyMode,
+ L2cap_LocalLoopbackReq,
+ L2cap_FlushChannel,
+ L2cap_SetAclPriority,
+ L2cap_FlowControl,
+ L2cap_SendTestSFrame,
+ L2cap_SetTxPriority,
+ L2cap_RegForNoCPEvt,
+ L2cap_SetChnlDataRate,
+ L2cap_SetFlushTimeout,
+ L2cap_DataWriteEx,
+ L2cap_SetChnlFlushability,
+ L2cap_GetPeerFeatures,
+ L2cap_GetBDAddrbyHandle,
+ L2cap_GetChnlFcrMode,
+ L2cap_SendFixedChnlData,
+ NULL, // cleanup,
+ L2cap_LE_Register,
+ L2cap_LE_DeRegister,
+ L2cap_LE_Connect,
+ L2cap_LE_ConnectRsp,
+ L2cap_LE_FlowControl,
+ L2cap_LE_freebuf,
+};
+
+const btl2cap_interface_t *btif_l2cap_get_interface(void)
+{
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ return &btl2capInterface;
+}
+
+
+/*
+- Take PSM only once during the Register func call.
+- Rest of the functions (connect, dereg) uses the same PSM. This way user need not pass it again.
+ This will also avoid additional error checks like unregistered psm is passed etc.
+ */
+
+static UINT16 g_Psm = 0;
+static UINT16 g_lcid = 0;
+
+static bt_status_t L2cap_Init (tL2CAP_APPL_INFO *p)
+{
+ pl2test_l2c_appl = p;
+ return BT_STATUS_SUCCESS;
+}
+/*******************************************************************************
+**
+** Function L2cap_Register
+**
+** Description This function is called during the task startup
+** to register interface functions with L2CAP.
+**
+*******************************************************************************/
+static bt_status_t L2cap_Register (UINT16 psm, BOOLEAN ConnType, UINT16 SecLevel)
+{
+
+ BTIF_TRACE_DEBUG("L2cap_Register :: psm=%d", psm);
+ if (!BTM_SetSecurityLevel (ConnType, "l2test", /*BTM_SEC_SERVICE_SDP_SERVER*/ BTM_SEC_PROTO_L2CAP,
+ SecLevel, psm, 0, 0))
+ {
+ BTIF_TRACE_DEBUG("Error:: BTM_SetSecurityLevel failed");
+ return BT_STATUS_FAIL;
+}
+#if 1
+ if(4113 == psm) {
+ if (!BTM_SetSecurityLevel (ConnType, "l2test 4113", /*BTM_SEC_SERVICE_SDP_SERVER*/ BTM_SEC_PROTO_L2CAP,
+ SecLevel, psm, 0, 0)) {
+ BTIF_TRACE_DEBUG("Error:: BTM_SetSecurityLevel failed");
+ return BT_STATUS_FAIL;
+ }
+ }
+#endif
+ g_Psm = L2CA_Register (psm, pl2test_l2c_appl);
+ if(0 == g_Psm) {
+ BTIF_TRACE_DEBUG("Error:: L2CA_Register failed");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function L2cap_LE_Register
+**
+** Description This function is called during the task startup
+** to register interface functions with L2CAP.
+**
+*******************************************************************************/
+static bt_status_t L2cap_LE_Register (UINT16 le_psm, BOOLEAN ConnType, UINT16 SecLevel,
+ UINT8 enc_key_size)
+{
+
+ BTIF_TRACE_DEBUG("LE-L2CAP: %s le_psm=%d, SecLevel=%d ", __FUNCTION__, le_psm, SecLevel);
+#if 0
+ if (!BTM_SetSecurityLevel (ConnType, "l2c_le_test", BTM_SEC_SERVICE_ATT,
+ SecLevel, le_psm))
+ {
+ BTIF_TRACE_ERROR("LE-L2CAP: BTM_SetSecurityLevel failed");
+ return BT_STATUS_FAIL;
+ }
+ if (!BTM_SetBleEncKeySize ("l2c_le_test", enc_key_size, le_psm))
+ {
+ BTIF_TRACE_ERROR("LE-L2CAP: BTM_SetBleEncKeySize failed");
+ return BT_STATUS_FAIL;
+ }
+#endif
+
+ g_Psm = L2CA_REGISTER_COC (le_psm, pl2test_l2c_appl,
+ AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE);
+
+ if(0 == g_Psm) {
+ BTIF_TRACE_ERROR("LE-L2CAP: L2cap_LE_Register failed");
+ return BT_STATUS_FAIL;
+ }
+
+ if (!BTM_SetSecurityLevel (ConnType, "l2c_le_test", BTM_SEC_SERVICE_ATT,
+ SecLevel, le_psm, 0, 0))
+ {
+ BTIF_TRACE_ERROR("LE-L2CAP: BTM_SetSecurityLevel failed");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+static UINT16 L2cap_LE_Connect (UINT16 le_psm , BD_ADDR address, tL2CAP_LE_CFG_INFO *p_cfg)
+{
+ BTIF_TRACE_DEBUG("LE-L2CAP: %s:: %0x %0x %0x %0x %0x %0x", __FUNCTION__,
+ address[0], address[1], address[2],address[3],address[4],address[5]);
+
+ if (0 == (g_lcid = L2CA_CONNECT_COC_REQ (le_psm, address, p_cfg))) {
+ BTIF_TRACE_ERROR("LE-L2CAP: L2CA_LE_CreditBasedConn_Req failed for le_psm ");
+ }
+ return g_lcid;
+}
+
+static BOOLEAN L2cap_LE_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result,
+ UINT16 status, tL2CAP_LE_CFG_INFO *p_cfg)
+{
+ p_cfg->credits = L2CAP_LE_DEFAULT_CREDIT;
+ p_cfg->mtu = L2CAP_LE_DEFAULT_MTU;
+ p_cfg->mps = L2CAP_LE_DEFAULT_MPS;
+
+ L2CA_CONNECT_COC_RSP (p_bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, p_cfg);
+#if 0
+ if (!L2CA_LE_CreditBasedConn_Rsp (p_bd_addr, id, lcid, conn_info)) {
+ BTIF_TRACE_ERROR("LE-L2CAP: L2CA_LE_CreditBasedConn_Rsp failed");
+ return BT_STATUS_FAIL;
+ }
+#endif
+ return BT_STATUS_SUCCESS;
+}
+
+static BOOLEAN L2cap_LE_FlowControl (UINT16 lcid, UINT16 credits)
+{
+ if (!L2CA_LE_SetFlowControlCredits (lcid, credits)) {
+ BTIF_TRACE_ERROR("LE-L2CAP: L2CA_LE_SetFlowControlCredits failed");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+static void L2cap_LE_freebuf (BT_HDR *p_buf)
+{
+ osi_free(p_buf);
+}
+
+static bt_status_t L2cap_LE_DeRegister (UINT16 psm)
+{
+ L2CA_DeregisterLECoc(psm);
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t L2cap_DeRegister (UINT16 psm)
+{
+ L2CA_Deregister(psm);
+ return BT_STATUS_SUCCESS;
+}
+
+static UINT16 L2cap_AllocatePSM(void)
+{
+ BTIF_TRACE_DEBUG("L2cap_AllocatePSM");
+ return L2CA_AllocatePSM();
+}
+
+static UINT16 L2cap_Connect(UINT16 psm, bt_bdaddr_t *bd_addr)
+{
+
+ BTIF_TRACE_DEBUG("L2cap_Connect:: %0x %0x %0x %0x %0x %0x", bd_addr->address[0],bd_addr->address[1],
+ bd_addr->address[2],bd_addr->address[3],bd_addr->address[4],bd_addr->address[5]);
+
+ if (0 == (g_lcid = L2CA_ConnectReq (psm, bd_addr->address)))
+ {
+ BTIF_TRACE_DEBUG("Error:: L2CA_ConnectReq failed for psm %d", psm);
+ }
+ return g_lcid;
+}
+
+static BOOLEAN L2cap_ConnectRsp(BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status)
+{
+ if (!L2CA_ConnectRsp (p_bd_addr, id, lcid, result, status)) {
+ BTIF_TRACE_DEBUG("L2CA_ConnectRsp:: error ");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+static UINT16 L2cap_ErtmConnect(UINT16 psm, BD_ADDR address, tL2CAP_ERTM_INFO *p_ertm_info)
+{
+ BTIF_TRACE_DEBUG("L2cap_ErtmConnect:: %0x %0x %0x %0x %0x %0x", address[0],address[1],address[2],address[3],address[4],address[5]);
+ if (0 == (g_lcid = L2CA_ErtmConnectReq (psm, address, p_ertm_info))) {
+ BTIF_TRACE_DEBUG("Error:: L2CA_ErtmConnectReq failed for psm %d", psm);
+ }
+ return g_lcid;
+}
+
+static BOOLEAN L2cap_ErtmConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status,
+ tL2CAP_ERTM_INFO *p_ertm_info)
+{
+ if (!L2CA_ErtmConnectRsp (p_bd_addr, id, lcid, result, status, p_ertm_info)) {
+ BTIF_TRACE_DEBUG("L2CA_ErtmConnectRsp:: error ");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+static BOOLEAN L2cap_ConfigReq(UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ BTIF_TRACE_DEBUG("L2cap_ConfigReq:: Invoked\n");
+ if (p_cfg->fcr_present)
+ {
+ BTIF_TRACE_DEBUG("L2cap_ConfigReq:: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u\n",
+ p_cfg->fcr.mode, p_cfg->fcr.tx_win_sz, p_cfg->fcr.max_transmit,
+ p_cfg->fcr.rtrans_tout,p_cfg->fcr.mon_tout, p_cfg->fcr.mps);
+ }
+ return L2CA_ConfigReq (cid, p_cfg);
+}
+
+static BOOLEAN L2cap_ConfigRsp(UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ BTIF_TRACE_DEBUG("L2cap_ConfigRsp:: Invoked");
+ return L2CA_ConfigRsp (cid, p_cfg);
+}
+
+static BOOLEAN L2cap_DisconnectReq (UINT16 cid)
+{
+ BTIF_TRACE_DEBUG("L2cap_DisconnectReq:: cid=%d", cid);
+ return L2CA_DisconnectReq(cid);
+}
+static BOOLEAN L2cap_DisconnectRsp (UINT16 cid)
+{
+ BTIF_TRACE_DEBUG("L2cap_DisconnectRsp:: Invoked");
+ return L2CA_DisconnectRsp (cid);
+}
+
+static UINT8 L2cap_DataWrite (UINT16 cid, char *p_data, UINT32 len)
+{
+ BTIF_TRACE_DEBUG("L2cap_DataWrite:: Invoked");
+ BT_HDR *p_msg = NULL;
+ UINT8 *ptr, *p_start;
+
+ p_msg = (BT_HDR *) osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ BTIF_TRACE_DEBUG("osi_malloc");
+ if (!p_msg)
+ {
+ BTIF_TRACE_DEBUG("No resource to allocate");
+ return BT_STATUS_FAIL;
+ }
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ ptr = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+ p_msg->len = len; //Sends len bytes, irrespective of what you copy to the buffer
+ memcpy(ptr, p_data, len);
+ return L2CA_DataWrite(cid, p_msg);
+}
+
+
+static BOOLEAN L2cap_Ping (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_cb)
+{
+ BTIF_TRACE_DEBUG("L2cap_Ping:: Invoked");
+ return L2CA_Ping (p_bd_addr, p_cb);
+}
+
+static BOOLEAN L2cap_Echo (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback)
+{
+ BTIF_TRACE_DEBUG("L2cap_Echo:: Invoked");
+ return L2CA_Echo (p_bd_addr, p_data, p_callback);
+}
+
+static BOOLEAN L2cap_SetIdleTimeout (UINT16 cid, UINT16 timeout, BOOLEAN is_global)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetIdleTimeout:: Invoked");
+ return L2CA_SetIdleTimeout (cid, timeout, is_global);
+}
+
+
+static BOOLEAN L2cap_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, UINT16 timeout)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetIdleTimeoutByBdAddr:: Invoked");
+ return L2CA_SetIdleTimeoutByBdAddr(bd_addr, timeout,BT_TRANSPORT_BR_EDR);
+}
+
+static void L2cap_SetSecConnOnlyMode(BOOLEAN secvalue)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetSecConnOnlyMode:: Invoked");
+ BTM_SetSecureConnectionsOnly(secvalue);
+}
+
+static UINT8 L2cap_SetDesireRole (UINT8 new_role)
+{
+ BTIF_TRACE_DEBUG("L2CA_SetDesireRole:: Invoked");
+ return L2CA_SetDesireRole (new_role);
+}
+
+
+static UINT16 L2cap_LocalLoopbackReq (UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr)
+{
+ BTIF_TRACE_DEBUG("L2cap_LocalLoopbackReq:: Invoked");
+ return L2CA_LocalLoopbackReq (psm, handle, p_bd_addr);
+}
+
+static UINT16 L2cap_FlushChannel (UINT16 lcid, UINT16 num_to_flush)
+{
+ BTIF_TRACE_DEBUG("L2cap_FlushChannel:: Invoked");
+ return L2CA_FlushChannel (lcid, num_to_flush);
+}
+
+static BOOLEAN L2cap_SetAclPriority (BD_ADDR bd_addr, UINT8 priority)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetAclPriority:: Invoked");
+ return L2CA_SetAclPriority (bd_addr, priority);
+}
+
+static BOOLEAN L2cap_FlowControl (UINT16 cid, BOOLEAN data_enabled)
+{
+ BTIF_TRACE_DEBUG("L2cap_FlowControl:: Invoked with LocalBusy=%s\n", (data_enabled)? "FALSE" :"TRUE");
+ return L2CA_FlowControl (cid, data_enabled);
+}
+
+static BOOLEAN L2cap_SendTestSFrame (UINT16 cid, BOOLEAN rr_or_rej, UINT8 back_track)
+{
+ BTIF_TRACE_DEBUG("L2cap_SendTestSFrame:: Invoked");
+ return L2CA_SendTestSFrame (cid, rr_or_rej, back_track);
+}
+
+static BOOLEAN L2cap_SetTxPriority (UINT16 cid, tL2CAP_CHNL_PRIORITY priority)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetTxPriority:: Invoked");
+ return L2CA_SetTxPriority (cid, priority);
+}
+
+static BOOLEAN L2cap_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda)
+{
+ BTIF_TRACE_DEBUG("L2cap_RegForNoCPEvt:: Invoked");
+ return L2CA_RegForNoCPEvt(p_cb, p_bda);
+}
+
+static BOOLEAN L2cap_SetChnlDataRate (UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetChnlDataRate:: Invoked");
+ return L2CA_SetChnlDataRate (cid, tx, rx);
+}
+
+static BOOLEAN L2cap_SetFlushTimeout (BD_ADDR bd_addr, UINT16 flush_tout)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetFlushTimeout:: Invoked");
+ return L2CA_SetFlushTimeout (bd_addr, flush_tout);
+}
+
+static UINT8 L2cap_DataWriteEx (UINT16 cid, BT_HDR *p_data, UINT16 flags)
+{
+ BTIF_TRACE_DEBUG("L2cap_DataWriteEx:: Invoked");
+ return L2CA_DataWriteEx (cid, p_data, flags);
+}
+static BOOLEAN L2cap_SetChnlFlushability (UINT16 cid, BOOLEAN is_flushable)
+{
+ BTIF_TRACE_DEBUG("L2cap_SetChnlFlushability:: Invoked");
+ return L2CA_SetChnlFlushability (cid, is_flushable);
+}
+static BOOLEAN L2cap_GetPeerFeatures (BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask)
+{
+ BTIF_TRACE_DEBUG("L2cap_GetPeerFeatures:: Invoked");
+ return L2CA_GetPeerFeatures (bd_addr, p_ext_feat, p_chnl_mask);
+}
+static BOOLEAN L2cap_GetBDAddrbyHandle (UINT16 handle, BD_ADDR bd_addr)
+{
+ BTIF_TRACE_DEBUG("L2cap_GetBDAddrbyHandle:: Invoked");
+ return L2CA_GetBDAddrbyHandle (handle, bd_addr);
+}
+static UINT8 L2cap_GetChnlFcrMode (UINT16 lcid)
+{
+ BTIF_TRACE_DEBUG("L2cap_GetChnlFcrMode:: Invoked");
+ return L2CA_GetChnlFcrMode (lcid);
+}
+
+//---------------------FIXED CHANNEL API ---------------------
+static UINT16 L2cap_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf)
+{
+ BTIF_TRACE_DEBUG("L2cap_SendFixedChnlData:: Invoked");
+ p_buf->event = 20;
+ return L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_buf);
+}
+#endif //TEST_APP_INTERFACE
diff --git a/btif/src/btif_mcap.c b/btif/src/btif_mcap.c
new file mode 100644
index 0000000..f0b84b3
--- /dev/null
+++ b/btif/src/btif_mcap.c
@@ -0,0 +1,220 @@
+/*
+ *Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the followin conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the followin disclaimer.
+ * * Redistributions in binary form must reproduce the above copyriht
+ * notice, this list of conditions and the followin disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+#include "bt_utils.h"
+#include "bt_testapp.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "mca_api.h"
+
+#ifdef TEST_APP_INTERFACE
+
+static void McaInit(void)
+{
+ MCA_Init();
+}
+
+static tMCA_HANDLE McaRegister(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback)
+{
+ tMCA_HANDLE Ret = 0;
+ BTM_SetConnectability (1, 0, 0);
+ Ret = MCA_Register(p_reg, p_cback);
+ ALOGI("McaRegister");
+ return Ret;
+}
+
+static void Mca_Deregister(tMCA_HANDLE handle)
+{
+ MCA_Deregister(handle);
+ ALOGI("McaRegister");
+}
+
+static tMCA_RESULT Mca_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs)
+{
+ tMCA_RESULT Ret = 0;
+ ALOGI("Mca_CreateDep Enter");
+ Ret = MCA_CreateDep(handle, p_dep, p_cs);
+ ALOGI("Mca_CreateDep Exit");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_DeleteDep(handle, dep);
+ ALOGI("MCA_DeleteDep Exit");
+ return Ret;
+}
+
+
+static tMCA_RESULT Mca_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr, UINT16 ctrl_psm, UINT16 sec_mask)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_ConnectReq(handle, bd_addr, ctrl_psm, sec_mask);
+ ALOGI("MCA_ConnectReq");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_DisconnectReq(tMCA_CL mcl)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_DisconnectReq(mcl);
+ ALOGI("Mca_DisconnectReq");
+ return Ret;
+}
+
+
+static tMCA_RESULT Mca_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, UINT8 peer_dep_id,
+ UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_CreateMdl(mcl, dep, data_psm, mdl_id, peer_dep_id, cfg, p_chnl_cfg);
+ ALOGI("MCA_CreateMdl");
+ return Ret;
+}
+
+
+static tMCA_RESULT Mca_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_CreateMdlRsp(mcl, dep, mdl_id, cfg, rsp_code, p_chnl_cfg);
+ ALOGI("Mca_CreateMdlRsp");
+ return Ret;
+}
+
+
+static tMCA_RESULT Mca_CloseReq(tMCA_DL mdl)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_CloseReq(mdl);
+ ALOGI("Mca_CloseReq");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm, UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_ReconnectMdl(mcl, dep, data_psm, mdl_id, p_chnl_cfg);
+ ALOGI("Mca_ReconnectMdl");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, UINT16 mdl_id, UINT8 rsp_code, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_ReconnectMdlRsp(mcl, dep, mdl_id, rsp_code, p_chnl_cfg);
+ ALOGI("Mca_ReconnectMdl");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_DataChnlCfg(mcl, p_chnl_cfg);
+ ALOGI("Mca_DataChnlCfg");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_Abort(tMCA_CL mcl)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_Abort(mcl);
+ ALOGI("MCA_Abort");
+ return Ret;
+}
+
+
+static tMCA_RESULT Mca_Delete(tMCA_CL mcl, UINT16 mdl_id)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_Delete(mcl, mdl_id);
+ ALOGI("Mca_Delete");
+ return Ret;
+}
+
+static tMCA_RESULT Mca_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = MCA_WriteReq(mdl, p_pkt);
+ ALOGI("Mca_Delete");
+ return Ret;
+}
+
+static UINT16 Mca_GetL2CapChannel (tMCA_DL mdl)
+{
+ UINT16 Ret = 0;
+ Ret = MCA_GetL2CapChannel(mdl);
+ ALOGI("Mca_GetL2CapChannel");
+ return Ret;
+}
+
+static const btmcap_interface_t btmcaInterface = {
+ sizeof(btmcap_interface_t),
+ McaInit,
+ McaRegister,
+ Mca_Deregister,
+ Mca_CreateDep,
+ Mca_DeleteDep,
+ Mca_ConnectReq,
+ Mca_DisconnectReq,
+ Mca_CreateMdl,
+ Mca_CreateMdlRsp,
+ Mca_CloseReq,
+ Mca_ReconnectMdl,
+ Mca_ReconnectMdlRsp,
+ Mca_DataChnlCfg,
+ Mca_Abort,
+ Mca_Delete,
+ Mca_WriteReq,
+ Mca_GetL2CapChannel
+};
+
+
+const btmcap_interface_t *btif_mcap_get_interface(void)
+{
+ //BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ //printf("\n%s\n", __FUNCTION__);
+ return &btmcaInterface;
+}
+
+
+#endif
diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c
index cf464e1..fb5a27b 100644
--- a/btif/src/btif_media_task.c
+++ b/btif/src/btif_media_task.c
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
@@ -25,6 +30,9 @@
** audio & video processing
**
******************************************************************************/
+#ifdef BT_AUDIO_SYSTRACE_LOG
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
+#endif
#define LOG_TAG "bt_btif_media"
@@ -34,23 +42,37 @@
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
+#include <dlfcn.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
#include <hardware/bluetooth.h>
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/mutex.h"
+#include "osi/include/thread.h"
+#include "bt_utils.h"
#include "a2d_api.h"
#include "a2d_int.h"
#include "a2d_sbc.h"
+#include "a2d_aptx.h"
+#include "a2d_aptx_hd.h"
+#include "a2d_aac.h"
#include "audio_a2dp_hw.h"
#include "bt_target.h"
#include "bta_api.h"
#include "bta_av_api.h"
#include "bta_av_ci.h"
#include "bta_av_sbc.h"
+#include "bta_av_aac.h"
#include "bta_sys.h"
#include "bta_sys_int.h"
#include "btif_av.h"
@@ -62,12 +84,6 @@
#include "bt_common.h"
#include "device/include/controller.h"
#include "l2c_api.h"
-#include "osi/include/alarm.h"
-#include "osi/include/fixed_queue.h"
-#include "osi/include/log.h"
-#include "osi/include/metrics.h"
-#include "osi/include/mutex.h"
-#include "osi/include/thread.h"
#if (BTA_AV_INCLUDED == TRUE)
#include "sbc_encoder.h"
@@ -82,12 +98,23 @@
#include "btif_avrcp_audio_track.h"
#endif
+#include "bthost_ipc.h"
#if (BTA_AV_SINK_INCLUDED == TRUE)
OI_CODEC_SBC_DECODER_CONTEXT context;
OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
OI_INT16 pcmData[15*SBC_MAX_SAMPLES_PER_FRAME*SBC_MAX_CHANNELS];
#endif
+#ifdef BT_AUDIO_SYSTRACE_LOG
+#include <cutils/trace.h>
+#define PERF_SYSTRACE 1
+#endif
+
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+#include "bta_api.h"
+#endif
+
+
/*****************************************************************************
** Constants
*****************************************************************************/
@@ -117,6 +144,21 @@
BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE,
BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK,
BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ ,BTIF_MEDIA_START_VS_CMD,
+ BTIF_MEDIA_STOP_VS_CMD,
+ BTIF_MEDIA_RESET_VS_STATE,
+ BTIF_MEDIA_VS_A2DP_START_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_STOP_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_MEDIA_CHNL_CFG_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_WRITE_SBC_CFG_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_PREF_BIT_RATE_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_SET_SCMST_HDR_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_STOP_FAILURE,
+ BTIF_MEDIA_VS_A2DP_START_FAILURE,
+ BTIF_MEDIA_VS_A2DP_SELECTED_CODEC_SUCCESS,
+ BTIF_MEDIA_VS_A2DP_TRANSPORT_CFG_SUCCESS
+#endif
};
enum {
@@ -124,7 +166,6 @@
MEDIA_TASK_STATE_ON = 1,
MEDIA_TASK_STATE_SHUTTING_DOWN = 2
};
-
/* Macro to multiply the media task tick */
#ifndef BTIF_MEDIA_NUM_TICK
#define BTIF_MEDIA_NUM_TICK 1
@@ -136,7 +177,7 @@
#define BTIF_MEDIA_TIME_TICK (20 * BTIF_MEDIA_NUM_TICK)
#define A2DP_DATA_READ_POLL_MS (BTIF_MEDIA_TIME_TICK / 2)
#define BTIF_SINK_MEDIA_TIME_TICK_MS (20 * BTIF_MEDIA_NUM_TICK)
-
+#define BTIF_REMOTE_START_TOUT 3000
/* buffer pool */
#define BTIF_MEDIA_AA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
@@ -148,19 +189,39 @@
#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE)
#endif
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define BTIF_MEDIA_AA_AAC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_AAC_HDR_SIZE + 1)
+#else
+#define BTIF_MEDIA_AA_AAC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_AAC_HDR_SIZE)
+#endif
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define BTIF_MEDIA_AA_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1)
+#define BTIF_MEDIA_AA_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1)
+#else
+#define BTIF_MEDIA_AA_APTX_OFFSET (AVDT_MEDIA_OFFSET - AVDT_MEDIA_HDR_SIZE) //no RTP header for aptX classic
+#define BTIF_MEDIA_AA_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET) //there is an RTP header for aptX HD, but no CP byte
+#endif
/* Define the bitrate step when trying to match bitpool value */
#ifndef BTIF_MEDIA_BITRATE_STEP
#define BTIF_MEDIA_BITRATE_STEP 5
#endif
-#ifndef BTIF_A2DP_DEFAULT_BITRATE
-/* High quality quality setting @ 44.1 khz */
-#define BTIF_A2DP_DEFAULT_BITRATE 328
+#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+#define BTIF_A2DP_DEFAULT_BITRATE 345
+
+#ifndef BTIF_A2DP_NON_EDR_MAX_RATE
+#define BTIF_A2DP_NON_EDR_MAX_RATE 237
#endif
+#else
+#define BTIF_A2DP_DEFAULT_BITRATE 328
#ifndef BTIF_A2DP_NON_EDR_MAX_RATE
#define BTIF_A2DP_NON_EDR_MAX_RATE 229
#endif
+#endif
+
+#define BTIF_A2DP_MAX_BITPOOL_MQ 35
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
/* A2DP header will contain a CP header of size 1 */
@@ -206,6 +267,7 @@
#define PACKET_PLAYED_PER_TICK_44 7
#define PACKET_PLAYED_PER_TICK_32 5
#define PACKET_PLAYED_PER_TICK_16 3
+#define MAX_MEDIA_WORKQUEUE_SEM_COUNT 1024
/* Readability constants */
#define SBC_FRAME_HEADER_SIZE_BYTES 4 // A2DP Spec v1.3, 12.4, Table 12.12
@@ -318,6 +380,11 @@
tBTIF_AV_MEDIA_FEEDINGS media_feeding;
tBTIF_AV_MEDIA_FEEDINGS_STATE media_feeding_state;
SBC_ENC_PARAMS encoder;
+ UINT16 offset;
+ A2D_APTX_ENC_PARAMS aptxEncoderParams;
+ A2D_APTX_HD_ENC_PARAMS aptxhdEncoderParams;
+ UINT16 as16PcmBuffer[1024];
+ UINT32 as32PcmBuffer[1024];
UINT8 busy_level;
void* av_sm_hdl;
UINT8 a2dp_cmd_pending; /* we can have max one command pending */
@@ -336,7 +403,18 @@
#endif
alarm_t *media_alarm;
alarm_t *decode_alarm;
+ alarm_t *remote_start_alarm;
btif_media_stats_t stats;
+//#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ UINT8 max_bitpool;
+ UINT8 min_bitpool;
+ BOOLEAN vs_configs_exchanged;
+ BOOLEAN tx_started;
+ BOOLEAN tx_stop_initiated;
+ BOOLEAN tx_start_initiated;
+ BOOLEAN tx_enc_update_initiated;
+//#endif
+
btif_media_stats_t accumulated_stats;
#endif
} tBTIF_MEDIA_CB;
@@ -382,6 +460,8 @@
static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg);
#endif
+BOOLEAN bta_av_co_audio_get_codec_config(UINT8 *p_config, UINT16 *p_minmtu, UINT8 type);
+
#if (BTA_AV_INCLUDED == TRUE)
static void btif_media_send_aa_frame(uint64_t timestamp_us);
static void btif_media_task_feeding_state_reset(void);
@@ -402,14 +482,62 @@
static void btif_media_task_aa_handle_timer(UNUSED_ATTR void *context);
static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context);
-extern BOOLEAN btif_hf_is_call_idle();
+extern BOOLEAN btif_hf_is_call_vr_idle();
+extern int btif_get_latest_playing_device_idx();
+extern tBTA_AV_HNDL btif_av_get_playing_device_hdl();
+extern int btif_get_num_playing_devices();
+extern UINT16 btif_av_get_num_playing_devices(void);
+extern BOOLEAN btif_av_get_multicast_state();
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+extern tBTA_AV_HNDL btif_av_get_av_hdl_from_idx(UINT8 idx);
+extern BOOLEAN btif_av_is_under_handoff();
+extern BOOLEAN btif_av_is_device_disconnecting();
+extern void btif_av_reset_reconfig_flag();
+void btif_media_send_reset_vendor_state();
+void btif_media_on_start_vendor_command();
+void btif_media_on_stop_vendor_command();
+BOOLEAN btif_media_send_vendor_pref_bit_rate();
+BOOLEAN btif_media_send_vendor_write_sbc_cfg();
+BOOLEAN btif_media_send_vendor_media_chn_cfg();
+BOOLEAN btif_media_send_vendor_stop();
+void disconnect_a2dp_on_vendor_start_failure();
+BOOLEAN btif_media_send_vendor_selected_codec();
+BOOLEAN btif_media_send_vendor_transport_cfg();
+BOOLEAN btif_media_send_vendor_scmst_hdr();
+BOOLEAN btif_av_is_suspend_stop_pending_ack();
+#else
+#define btif_av_get_av_hdl_from_idx(idx) (0)
+#define btif_av_is_under_handoff() (0)
+#define btif_av_is_device_disconnecting() (0)
+#define btif_av_reset_reconfig_flag() (0)
+#define btif_media_send_reset_vendor_state() (0)
+#define btif_media_on_start_vendor_command() (0)
+#define btif_media_on_stop_vendor_command() (0)
+#define btif_media_send_vendor_pref_bit_rate() (0)
+#define btif_media_send_vendor_write_sbc_cfg() (0)
+#define btif_media_send_vendor_media_chn_cfg() (0)
+#define btif_media_send_vendor_stop() (0)
+#define disconnect_a2dp_on_vendor_start_failure() (0)
+#define btif_media_send_vendor_selected_codec() (0)
+#define btif_media_send_vendor_transport_cfg() (0)
+#define btif_media_send_vendor_scmst_hdr() (0)
+#define btif_av_is_suspend_stop_pending_ack() (0)
+#endif
+void btif_a2dp_remote_start_timer();
static tBTIF_MEDIA_CB btif_media_cb;
static int media_task_running = MEDIA_TASK_STATE_OFF;
+static BOOLEAN enc_update_in_progress = FALSE;
static fixed_queue_t *btif_media_cmd_msg_queue;
static thread_t *worker_thread;
+BOOLEAN bta_av_co_audio_get_codec_config(UINT8 *p_config, UINT16 *p_minmtu, UINT8 type);
+
+extern BOOLEAN bt_split_a2dp_enabled;
+extern int btif_max_av_clients;
+static uint8_t multicast_query = FALSE;
+extern BOOLEAN reconfig_a2dp;
/*****************************************************************************
** Misc helper functions
*****************************************************************************/
@@ -526,9 +654,22 @@
static void log_tstamps_us(char *comment, uint64_t now_us)
{
+ #define USEC_PER_MSEC 1000L
static uint64_t prev_us = 0;
- APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment, now_us, now_us - prev_us,
+ static uint64_t diff_us = 0;
+
+ diff_us = now_us - prev_us;
+ if ((diff_us / USEC_PER_MSEC) > (BTIF_MEDIA_TIME_TICK + 10))
+ {
+ APPL_TRACE_ERROR("[%s] ts %08llu, diff : %08llu, queue sz %d", comment, now_us, diff_us,
fixed_queue_length(btif_media_cb.TxAaQ));
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment, now_us, diff_us,
+ fixed_queue_length(btif_media_cb.TxAaQ));
+ }
+
prev_us = now_us;
}
@@ -594,7 +735,11 @@
CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_START)
-
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_GET_CODEC_CONFIG)
+ CASE_RETURN_STR(A2DP_CTRL_GET_MULTICAST_STATUS)
+ CASE_RETURN_STR(A2DP_CTRL_GET_CONNECTION_STATUS)
default:
return "UNKNOWN MSG ID";
}
@@ -602,7 +747,7 @@
static void btif_audiopath_detached(void)
{
- APPL_TRACE_EVENT("## AUDIO PATH DETACHED ##");
+ APPL_TRACE_IMP("## AUDIO PATH DETACHED ##");
/* send stop request only if we are actively streaming and haven't received
a stop request. Potentially audioflinger detached abnormally */
@@ -616,7 +761,7 @@
{
UINT8 ack = status;
- APPL_TRACE_EVENT("## a2dp ack : %s, status %d ##",
+ APPL_TRACE_IMP("## a2dp ack : %s, status %d ##",
dump_a2dp_ctrl_event(btif_media_cb.a2dp_cmd_pending), status);
/* sanity check */
@@ -643,7 +788,7 @@
/* detach on ctrl channel means audioflinger process was terminated */
if (n == 0)
{
- APPL_TRACE_EVENT("CTRL CH DETACHED");
+ APPL_TRACE_IMP("CTRL CH DETACHED");
UIPC_Close(UIPC_CH_ID_AV_CTRL);
/* we can operate only on datachannel, if af client wants to
do send additional commands the ctrl channel would be reestablished */
@@ -651,7 +796,7 @@
return;
}
- APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s", dump_a2dp_ctrl_event(cmd));
+ APPL_TRACE_IMP("a2dp-ctrl-cmd : %s", dump_a2dp_ctrl_event(cmd));
btif_media_cb.a2dp_cmd_pending = cmd;
@@ -659,14 +804,31 @@
{
case A2DP_CTRL_CMD_CHECK_READY:
- if (media_task_running == MEDIA_TASK_STATE_SHUTTING_DOWN)
+ if (!bt_split_a2dp_enabled && media_task_running == MEDIA_TASK_STATE_SHUTTING_DOWN)
{
APPL_TRACE_WARNING("%s: A2DP command %s while media task shutting down",
__func__, dump_a2dp_ctrl_event(cmd));
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
return;
}
-
+ if (bt_split_a2dp_enabled && !btif_hf_is_call_vr_idle())
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_INCALL_FAILURE);
+ return;
+ }
+ /*There can be instances where because of remote start received early, reconfig
+ flag may get reset, for such case check for tx_started flag set as well,
+ this would help returning proper status to MM*/
+ if (bt_split_a2dp_enabled)
+ APPL_TRACE_IMP("%s: A2DP command %s, reconfig: %d, tx_started: %d",
+ __func__, dump_a2dp_ctrl_event(cmd), reconfig_a2dp,
+ btif_media_cb.tx_started);
+ if (bt_split_a2dp_enabled && (btif_av_is_under_handoff() || reconfig_a2dp
+ || btif_media_cb.tx_started))
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ return;
+ }
/* check whether av is ready to setup a2dp datapath */
if ((btif_av_stream_ready() == TRUE) || (btif_av_stream_started_ready() == TRUE))
{
@@ -680,15 +842,27 @@
}
break;
+ case A2DP_CTRL_CMD_CHECK_STREAM_STARTED:
+
+ if((btif_av_stream_started_ready() == TRUE))
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
+
case A2DP_CTRL_CMD_START:
/* Don't sent START request to stack while we are in call.
Some headsets like the Sony MW600, don't allow AVDTP START
in call and respond BAD_STATE. */
- if (!btif_hf_is_call_idle())
+ if (!btif_hf_is_call_vr_idle())
{
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_INCALL_FAILURE);
break;
}
+ APPL_TRACE_DEBUG("%s:A2DP command %s AV stream_started_ready %d",
+ __func__, dump_a2dp_ctrl_event(cmd),btif_av_stream_started_ready());
+ APPL_TRACE_DEBUG("%s:A2DP command %s AV stream_ready %d",
+ __func__, dump_a2dp_ctrl_event(cmd),btif_av_stream_ready());
if (alarm_is_scheduled(btif_media_cb.media_alarm))
{
@@ -698,11 +872,59 @@
break;
}
- if (btif_av_stream_ready() == TRUE)
+ if (alarm_is_scheduled(btif_media_cb.remote_start_alarm))
+ {
+ APPL_TRACE_WARNING("%s: remote a2dp started, cancle remote start timer",
+ __func__);
+ alarm_free(btif_media_cb.remote_start_alarm);
+ btif_media_cb.remote_start_alarm = NULL;
+ btif_dispatch_sm_event(BTIF_AV_RESET_REMOTE_STARTED_FLAG_UPDATE_AUDIO_STATE_EVT, NULL, 0);
+ }
+ /* In Dual A2dp, first check for started state of stream
+ * as we dont want to START again as while doing Handoff
+ * the stack state will be started, so it is not needed
+ * to send START again, just open the media socket
+ * and ACK the audio HAL.*/
+ if (btif_av_stream_started_ready())
+ {
+ if (!bt_split_a2dp_enabled)
+ {
+ /* already started, setup audio data channel listener
+ * and ack back immediately */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+ }
+ else
+ {
+ //UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);//Test Remove later
+ APPL_TRACE_DEBUG("Av stream already started");
+ if (btif_media_cb.peer_sep == AVDT_TSEP_SNK)
+ btif_a2dp_encoder_update();
+ if (btif_media_cb.tx_start_initiated == TRUE) {
+ APPL_TRACE_DEBUG("VSC exchange alreday started on Handoff Start, wait");
+ break;
+ }
+ else if (btif_media_cb.tx_started == FALSE) {
+ APPL_TRACE_DEBUG("Start VSC exchange on MM Start when state is remote started");
+ btif_media_on_start_vendor_command();
+ break;
+ }
+ }
+ btif_av_reset_reconfig_flag();
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else if (btif_av_stream_ready() == TRUE)
{
/* setup audio data channel listener */
- UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
-
+ if (!bt_split_a2dp_enabled)
+ {
+ /* already started, setup audio data channel listener
+ * and ack back immediately */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("Av stream ready");
+ }
/* post start event and wait for audio path to open */
btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
@@ -711,14 +933,6 @@
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
#endif
}
- else if (btif_av_stream_started_ready())
- {
- /* already started, setup audio data channel listener
- and ack back immediately */
- UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
-
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
- }
else
{
APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
@@ -729,22 +943,35 @@
break;
case A2DP_CTRL_CMD_STOP:
- if (btif_media_cb.peer_sep == AVDT_TSEP_SNK &&
- (!alarm_is_scheduled(btif_media_cb.media_alarm)))
+ if ((!bt_split_a2dp_enabled && btif_media_cb.peer_sep == AVDT_TSEP_SNK &&
+ (!alarm_is_scheduled(btif_media_cb.media_alarm))) ||
+ (bt_split_a2dp_enabled && btif_media_cb.peer_sep == AVDT_TSEP_SNK &&
+ btif_media_cb.tx_started == FALSE))
{
/* we are already stopped, just ack back */
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
break;
}
+ APPL_TRACE_DEBUG("Stop stream request to Av");
btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
break;
case A2DP_CTRL_CMD_SUSPEND:
/* local suspend */
- if (btif_av_stream_started_ready())
+ APPL_TRACE_DEBUG("%s:A2DP command %s AV stream_started_ready %d",
+ __func__, dump_a2dp_ctrl_event(cmd),btif_av_stream_started_ready());
+ if (bt_split_a2dp_enabled && reconfig_a2dp)
{
+ APPL_TRACE_DEBUG("Suspend called due to reconfig");
+ APPL_TRACE_DEBUG("VS exchange started: ACK suspend, cmd_start will block");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else if (btif_av_stream_started_ready())
+ {
+ APPL_TRACE_DEBUG("Suspend stream request to Av");
btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
}
else
@@ -752,6 +979,8 @@
/* if we are not in started state, just ack back ok and let
audioflinger close the channel. This can happen if we are
remotely suspended, clear REMOTE SUSPEND Flag */
+ APPL_TRACE_DEBUG("%s:A2DP command %s AV stream_started_ready clear flag",
+ __func__, dump_a2dp_ctrl_event(cmd));
btif_av_clear_remote_suspend_flag();
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
}
@@ -767,24 +996,198 @@
UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &channel_count, 1);
break;
}
-
case A2DP_CTRL_CMD_OFFLOAD_START:
btif_dispatch_sm_event(BTIF_AV_OFFLOAD_START_REQ_EVT, NULL, 0);
break;
+ case A2DP_CTRL_GET_CODEC_CONFIG:
+ {
+ UINT16 min_mtu;
+ uint8_t param[MAX_CODEC_CFG_SIZE],idx,bta_hdl,codec_id = 0;
+ uint32_t bitrate = 0;
+ uint8_t i = 0;
+ UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &idx, 1);
+ memset(param,0,MAX_CODEC_CFG_SIZE);
+ if ((btif_av_stream_started_ready() == FALSE) ||
+ (enc_update_in_progress == TRUE))
+ {
+ BTIF_TRACE_ERROR("A2DP_CTRL_GET_CODEC_CONFIG: stream not started");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
+ }
+ /*
+ If multicast is supported, codec config will be queried
+ successively for num of playing devices
+ */
+ if (multicast_query)
+ {
+ if (idx == (btif_max_av_clients-1))
+ {
+ multicast_query = FALSE;
+ //Get AV handle of index 1
+ }
+ BTIF_TRACE_DEBUG("Mulitcast Enabled, querying index =%d",idx);
+
+ bta_hdl = btif_av_get_av_hdl_from_idx(idx);
+ if (bta_hdl < 0)
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
+ }
+ //TODO Maintain selected codec info for Multicast with different codecs
+ }
+ else //get playing device hdl
+ {
+ codec_id = bta_av_co_get_current_codec();
+ }
+
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ BTIF_TRACE_DEBUG("codec_id = %x",codec_id);
+
+ if (get_soc_type() == BT_SOC_SMD)
+ {
+ //For Pronto PLs Audio pumps raw PCM data for others its encoded data to SOC
+ param[1] = 4; //RAW PCM
+ param[2] = AVDT_MEDIA_AUDIO;
+ param[3] = BTIF_AV_CODEC_PCM;
+ param[4] = btif_media_cb.media_feeding.cfg.pcm.sampling_freq;
+ param[5] = btif_media_cb.media_feeding.cfg.pcm.num_channel;
+ }
+ else if (codec_id == BTIF_AV_CODEC_SBC)
+ {
+ tA2D_SBC_CIE codec_cfg;
+ bta_av_co_audio_get_sbc_config(&codec_cfg, &min_mtu);
+ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO,&codec_cfg,¶m[1]);
+ bitrate = btif_media_cb.encoder.u16BitRate * 1000;
+ }
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ else if (codec_id == BTIF_AV_CODEC_M24) {
+ tA2D_AAC_CIE aac_cfg;
+ bta_av_co_audio_get_aac_config(&aac_cfg, &min_mtu);
+ A2D_BldAacInfo(AVDT_MEDIA_AUDIO,&aac_cfg,¶m[1]);
+ bitrate = btif_media_cb.encoder.u16BitRate * 1000;
+ }
+#endif
+ else if (codec_id == A2D_NON_A2DP_MEDIA_CT) //this is changed to non-a2dp VS codec
+ {
+ //ADD APTX support
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ int j;
+ UINT8 *p_ptr = ptr;
+ for(j=0; j< (int)sizeof(tA2D_APTX_CIE);j++)
+ {
+ BTIF_TRACE_DEBUG("codec[%d] = %x",j,*p_ptr++);
+ }
+ if (ptr)
+ {
+ tA2D_APTX_CIE* codecInfo = 0;
+ codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID
+ && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ {
+ tA2D_APTX_CIE aptx_config;
+ memset(&aptx_config,0,sizeof(tA2D_APTX_CIE));
+ aptx_config.vendorId = codecInfo->vendorId;
+ aptx_config.codecId = codecInfo->codecId;
+ //SampleRate & Chmode are bitmasked
+ aptx_config.sampleRate = (codecInfo->sampleRate & 0xF0);
+ aptx_config.channelMode = (codecInfo->sampleRate & 0x0F);
+ BTIF_TRACE_DEBUG("vendor id = %x",aptx_config.vendorId);
+ BTIF_TRACE_DEBUG("codec id = %x",aptx_config.codecId);
+ BTIF_TRACE_DEBUG("sample rate = %x",aptx_config.sampleRate);
+ BTIF_TRACE_DEBUG("ch mode = %x",aptx_config.channelMode);
+ A2D_BldAptxInfo(AVDT_MEDIA_AUDIO,&aptx_config,¶m[1]);
+
+ /* For aptxClassic BR = (Sampl_Rate * PCM_DEPTH * CHNL)/Compression_Ratio */
+ bitrate = ((btif_media_cb.media_feeding.cfg.pcm.sampling_freq * 16 * 2)/4);
+ } else {
+ tA2D_APTX_HD_CIE* cI = 0;
+ cI = (tA2D_APTX_HD_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (cI && cI->vendorId == A2D_APTX_HD_VENDOR_ID
+ && cI->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ {
+ tA2D_APTX_HD_CIE aptxhd_config;
+ memset(&aptxhd_config,0,sizeof(tA2D_APTX_HD_CIE));
+ aptxhd_config.vendorId = codecInfo->vendorId;
+ aptxhd_config.codecId = codecInfo->codecId;
+ //SampleRate & Chmode are bitmasked
+ aptxhd_config.sampleRate = (codecInfo->sampleRate & 0xF0);
+ aptxhd_config.channelMode = (codecInfo->sampleRate & 0x0F);
+ BTIF_TRACE_DEBUG("vendor id = %x",aptxhd_config.vendorId);
+ BTIF_TRACE_DEBUG("codec id = %x",aptxhd_config.codecId);
+ BTIF_TRACE_DEBUG("sample rate = %x",aptxhd_config.sampleRate);
+ BTIF_TRACE_DEBUG("ch mode = %x",aptxhd_config.channelMode);
+ A2D_BldAptx_hdInfo(AVDT_MEDIA_AUDIO,&aptxhd_config,¶m[1]);
+
+ /* For aptxHD BR = (Sampl_Rate * PCM_DEPTH * CHNL)/Compression_Ratio,
+ derived from classic */
+ bitrate = ((btif_media_cb.media_feeding.cfg.pcm.sampling_freq * 24 * 2)/4);
+ }
+ }
+ }
+ }
+ param[0] = btif_get_latest_playing_device_idx();
+ i = param[1] + 2; //LOSC
+ param[i++] = (UINT8)(btif_media_cb.TxAaMtuSize & 0x00FF);
+ param[i++] = (UINT8)(((btif_media_cb.TxAaMtuSize & 0xFF00) >> 8) & 0x00FF);
+ param[i++] = (UINT8)(bitrate & 0x00FF);
+ param[i++] = (UINT8)(((bitrate & 0xFF00) >> 8) & 0x00FF);
+ param[i++] = (UINT8)(((bitrate & 0xFF0000) >> 16) & 0x00FF);
+ param[i++] = (UINT8)(((bitrate & 0xFF000000) >> 24) & 0x00FF);
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &i, 1);
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, (UINT8 *)¶m, i);
+ break;
+ }
+
+ case A2DP_CTRL_GET_MULTICAST_STATUS:
+ {
+ uint8_t playing_devices = (uint8_t)btif_av_get_num_playing_devices();
+ BOOLEAN multicast_state = btif_av_get_multicast_state();
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ multicast_query = FALSE;
+ if ((btif_max_av_clients > 1 && playing_devices == btif_max_av_clients) &&
+ multicast_state)
+ {
+ multicast_query = TRUE;
+ }
+ BTIF_TRACE_ERROR("multicast status = %d",multicast_query);
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &multicast_query, 1);
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &playing_devices, 1);
+
+ break;
+ }
+ case A2DP_CTRL_CMD_OFFLOAD_SUPPORTED:
+ BTIF_TRACE_ERROR("Split A2DP supported");
+ bt_split_a2dp_enabled = TRUE;
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ break;
+ case A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED:
+ BTIF_TRACE_ERROR("Split A2DP not supported");
+ bt_split_a2dp_enabled = FALSE; //Change to FALSE later
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ break;
+ case A2DP_CTRL_GET_CONNECTION_STATUS:
+ if (btif_av_is_connected() && media_task_running != MEDIA_TASK_STATE_SHUTTING_DOWN)
+ {
+ BTIF_TRACE_DEBUG("got valid connection");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
default:
APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
break;
}
- APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s DONE", dump_a2dp_ctrl_event(cmd));
+ APPL_TRACE_IMP("a2dp-ctrl-cmd : %s DONE", dump_a2dp_ctrl_event(cmd));
}
static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event)
{
UNUSED(ch_id);
- APPL_TRACE_DEBUG("A2DP-CTRL-CHANNEL EVENT %s", dump_uipc_event(event));
+ APPL_TRACE_IMP("A2DP-CTRL-CHANNEL EVENT %s", dump_uipc_event(event));
switch (event)
{
@@ -826,11 +1229,9 @@
(void *)A2DP_DATA_READ_POLL_MS);
if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) {
- /* Start the media task to encode SBC */
- btif_media_task_start_aa_req();
-
/* make sure we update any changed sbc encoder params */
- btif_a2dp_encoder_update();
+ /*post a message to btif_av to serialize encode update and encode init*/
+ btif_dispatch_sm_event(BTIF_AV_UPDATE_ENCODER_REQ_EVT, NULL, 0);
}
btif_media_cb.data_channel_open = TRUE;
@@ -849,6 +1250,45 @@
}
}
+static BOOLEAN btif_media_task_is_aptx_configured()
+{
+ BOOLEAN result = FALSE;
+ UINT8 codectype = bta_av_co_get_current_codec();
+
+ if (codectype == A2D_NON_A2DP_MEDIA_CT) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ tA2D_APTX_CIE* codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ /* Fix for below Klockwork Issue.
+ * Pointer 'codecInfo' checked for NULL at line 1089 may be dereferenced at line 1092.*/
+ if ((codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ || (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)) {
+ APPL_TRACE_DEBUG("%s codecId %d", __func__, codecInfo->codecId);
+ APPL_TRACE_DEBUG("%s vendorId %x", __func__, codecInfo->vendorId);
+ result = TRUE;
+ }
+ }
+ }
+ return result;
+}
+
+A2D_AptXCodecType btif_media_task_get_aptX_codec_type()
+{
+ A2D_AptXCodecType codec = APTX_CODEC_NONE;
+ UINT8 a2dp_codectype = bta_av_co_get_current_codec();
+
+ if (a2dp_codectype == A2D_NON_A2DP_MEDIA_CT) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ tA2D_APTX_CIE* codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ codec = APTX_CODEC;
+ else if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ codec = APTX_HD_CODEC;
+ }
+ }
+ return codec;
+}
/*****************************************************************************
** BTIF ADAPTATION
@@ -868,12 +1308,15 @@
return rate;
}
-static void btif_a2dp_encoder_init(void)
+static void btif_a2dp_encoder_init(tBTA_AV_HNDL hdl)
{
UINT16 minmtu;
tBTIF_MEDIA_INIT_AUDIO msg;
tA2D_SBC_CIE sbc_config;
-
+ tA2D_APTX_CIE* codecInfo = 0;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ tA2D_AAC_CIE aac_config;
+#endif
/* lookup table for converting channel mode */
UINT16 codec_mode_tbl[5] = { SBC_JOINT_STEREO, SBC_STEREO, SBC_DUAL, 0, SBC_MONO };
@@ -885,14 +1328,92 @@
APPL_TRACE_DEBUG("btif_a2dp_encoder_init");
+ btif_media_cb.aptxEncoderParams.encoder = 0;
+
+ memset(&msg, 0, sizeof(msg));
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ ALOGI("%s SCMS_T ENABLED", __func__);
+#else
+ ALOGI("%s SCMS_T DISABLED", __func__);
+#endif
+
+ UINT8 codectype;
+ codectype = bta_av_select_codec(hdl);
+ if (A2D_NON_A2DP_MEDIA_CT == codectype) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ //tA2D_APTX_CIE starts on 4th byte
+ codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecInfo->codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x", __func__, codecInfo->vendorId);
+
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID
+ && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ {
+ btif_media_cb.offset = BTIF_MEDIA_AA_APTX_OFFSET;
+ tA2D_APTX_CIE aptx_config;
+ ALOGI("%s Selected Codec aptX", __func__);
+ aptx_config.vendorId = codecInfo->vendorId;
+ aptx_config.codecId = codecInfo->codecId;
+ bta_av_co_audio_get_codec_config((UINT8*)&aptx_config, &minmtu, A2D_NON_A2DP_MEDIA_CT);
+ msg.CodecType = A2D_NON_A2DP_MEDIA_CT;
+ msg.SamplingFreq = aptx_config.sampleRate;
+ msg.MtuSize = minmtu;
+ msg.ChannelMode = aptx_config.channelMode;
+ msg.BluetoothVendorID = aptx_config.vendorId;
+ msg.BluetoothCodecID = aptx_config.codecId;
+ btif_media_task_enc_init_req(&msg);
+ return;
+ }
+
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID
+ && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ {
+ btif_media_cb.offset = BTIF_MEDIA_AA_APTX_HD_OFFSET;
+ tA2D_APTX_HD_CIE aptx_hd_config;
+ ALOGI("%s Selected Codec aptX HD", __func__);
+ aptx_hd_config.vendorId = codecInfo->vendorId;
+ aptx_hd_config.codecId = codecInfo->codecId;
+ bta_av_co_audio_get_codec_config((UINT8*)&aptx_hd_config, &minmtu, A2D_NON_A2DP_MEDIA_CT);
+ msg.CodecType = A2D_NON_A2DP_MEDIA_CT;
+ msg.SamplingFreq = aptx_hd_config.sampleRate;
+ msg.MtuSize = minmtu;
+ msg.ChannelMode = aptx_hd_config.channelMode;
+ msg.BluetoothVendorID = aptx_hd_config.vendorId;
+ msg.BluetoothCodecID = aptx_hd_config.codecId;
+ btif_media_task_enc_init_req(&msg);
+ return;
+ }
+ }
+ }/* if ( A2D_NON_A2DP_MEDIA_CT == codectype) */
+
+
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ if (BTIF_AV_CODEC_M24 == codectype) {
+ ALOGI("%s Selected Codec AAC", __func__);
+ bta_av_co_audio_get_codec_config ((UINT8*)&aac_config, &minmtu, BTIF_AV_CODEC_M24);
+ msg.ObjectType = aac_config.object_type;
+ msg.ChannelMode = (aac_config.channels == A2D_AAC_IE_CHANNELS_2) ? SBC_STEREO : SBC_MONO;
+ msg.SamplingFreq = freq_block_tbl[aac_config.samp_freq >> 5];
+ msg.MtuSize = minmtu;
+ msg.CodecType = BTIF_AV_CODEC_M24;
+ msg.bit_rate = aac_config.bit_rate;
+ btif_media_task_enc_init_req(&msg);
+ return;
+ }
+#endif
+
+ ALOGI("%s Selected Codec SBC", __func__);
+
/* Retrieve the current SBC configuration (default if currently not used) */
- bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
+ bta_av_co_audio_get_codec_config((UINT8*)&sbc_config, &minmtu, BTIF_AV_CODEC_SBC);
msg.NumOfSubBands = (sbc_config.num_subbands == A2D_SBC_IE_SUBBAND_4) ? 4 : 8;
msg.NumOfBlocks = codec_block_tbl[sbc_config.block_len >> 5];
msg.AllocationMethod = (sbc_config.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) ? SBC_LOUDNESS : SBC_SNR;
msg.ChannelMode = codec_mode_tbl[sbc_config.ch_mode >> 1];
msg.SamplingFreq = freq_block_tbl[sbc_config.samp_freq >> 5];
msg.MtuSize = minmtu;
+ msg.CodecType = BTIF_AV_CODEC_SBC;
APPL_TRACE_EVENT("msg.ChannelMode %x", msg.ChannelMode);
@@ -902,51 +1423,112 @@
static void btif_a2dp_encoder_update(void)
{
- UINT16 minmtu;
+ UINT16 minmtu = 0;
tA2D_SBC_CIE sbc_config;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ tA2D_AAC_CIE aac_config;
+#endif
tBTIF_MEDIA_UPDATE_AUDIO msg;
UINT8 pref_min;
UINT8 pref_max;
+ tA2D_APTX_CIE* codecInfo = 0;
APPL_TRACE_DEBUG("btif_a2dp_encoder_update");
+ btif_media_cb.tx_enc_update_initiated = TRUE;
- /* Retrieve the current SBC configuration (default if currently not used) */
- bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
-
- APPL_TRACE_DEBUG("btif_a2dp_encoder_update: Common min_bitpool:%d(0x%x) max_bitpool:%d(0x%x)",
- sbc_config.min_bitpool, sbc_config.min_bitpool,
- sbc_config.max_bitpool, sbc_config.max_bitpool);
-
- if (sbc_config.min_bitpool > sbc_config.max_bitpool)
+ UINT8 codectype = 0;
+ codectype = bta_av_co_get_current_codec();
+ enc_update_in_progress = TRUE;
+ if (codectype == A2D_NON_A2DP_MEDIA_CT)
{
- APPL_TRACE_ERROR("btif_a2dp_encoder_update: ERROR btif_a2dp_encoder_update min_bitpool > max_bitpool");
- }
-
- /* check if remote sink has a preferred bitpool range */
- if (bta_av_co_get_remote_bitpool_pref(&pref_min, &pref_max) == TRUE)
- {
- /* adjust our preferred bitpool with the remote preference if within
- our capable range */
-
- if (pref_min < sbc_config.min_bitpool)
- pref_min = sbc_config.min_bitpool;
-
- if (pref_max > sbc_config.max_bitpool)
- pref_max = sbc_config.max_bitpool;
-
- msg.MinBitPool = pref_min;
- msg.MaxBitPool = pref_max;
-
- if ((pref_min != sbc_config.min_bitpool) || (pref_max != sbc_config.max_bitpool))
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr)
{
- APPL_TRACE_EVENT("## adjusted our bitpool range to peer pref [%d:%d] ##",
- pref_min, pref_max);
- }
+ codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ {
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ tA2D_APTX_CIE aptx_config;
+ aptx_config.vendorId = codecInfo->vendorId;
+ aptx_config.codecId = codecInfo->codecId;
+ bta_av_co_audio_get_codec_config((UINT8*)&aptx_config, &minmtu, A2D_NON_A2DP_MEDIA_CT );
+ msg.CodecType = A2D_NON_A2DP_MEDIA_CT;
+ msg.BluetoothVendorID = aptx_config.vendorId;
+ msg.BluetoothCodecID = aptx_config.codecId;
+ }
+
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ {
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ tA2D_APTX_HD_CIE aptx_hd_config;
+ aptx_hd_config.vendorId = codecInfo->vendorId;
+ aptx_hd_config.codecId = codecInfo->codecId;
+ bta_av_co_audio_get_codec_config((UINT8*)&aptx_hd_config, &minmtu, A2D_NON_A2DP_MEDIA_CT );
+ msg.CodecType = A2D_NON_A2DP_MEDIA_CT;
+ msg.BluetoothVendorID = aptx_hd_config.vendorId;
+ msg.BluetoothCodecID = aptx_hd_config.codecId;
+ }
+ } /* if (ptr) */
}
- else
- {
- msg.MinBitPool = sbc_config.min_bitpool;
- msg.MaxBitPool = sbc_config.max_bitpool;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ else if (codectype == BTIF_AV_CODEC_M24) {
+ bta_av_co_audio_get_aac_config(&aac_config, &minmtu);
+
+ APPL_TRACE_DEBUG("btif_a2dp_encoder_update: AAC object_type :%d channels :%d",
+ aac_config.object_type, aac_config.channels);
+ msg.CodecType = BTIF_AV_CODEC_M24;
+ }
+#endif
+ else {
+
+ /* Retrieve the current SBC configuration (default if currently not used) */
+ bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
+
+ APPL_TRACE_DEBUG("btif_a2dp_encoder_update: Common min_bitpool:%d(0x%x) max_bitpool:%d(0x%x)",
+ sbc_config.min_bitpool, sbc_config.min_bitpool,
+ sbc_config.max_bitpool, sbc_config.max_bitpool);
+
+ if (sbc_config.min_bitpool > sbc_config.max_bitpool)
+ {
+ APPL_TRACE_ERROR("btif_a2dp_encoder_update: ERROR btif_a2dp_encoder_update min_bitpool > max_bitpool");
+ }
+
+ /* check if remote sink has a preferred bitpool range */
+ if (bta_av_co_get_remote_bitpool_pref(&pref_min, &pref_max) == TRUE)
+ {
+ /* adjust our preferred bitpool with the remote preference if within
+ our capable range */
+
+ if (pref_min < sbc_config.min_bitpool)
+ pref_min = sbc_config.min_bitpool;
+
+ if ((pref_max > sbc_config.max_bitpool) || (pref_max == 0))
+ pref_max = sbc_config.max_bitpool;
+
+ msg.MinBitPool = pref_min;
+ msg.MaxBitPool = pref_max;
+
+ if ((pref_min != sbc_config.min_bitpool) || (pref_max != sbc_config.max_bitpool))
+ {
+ APPL_TRACE_EVENT("## adjusted our bitpool range to peer pref [%d:%d] ##",
+ pref_min, pref_max);
+ }
+ }
+ else
+ {
+ msg.MinBitPool = sbc_config.min_bitpool;
+ msg.MaxBitPool = sbc_config.max_bitpool;
+ }
+
+ msg.CodecType = BTIF_AV_CODEC_SBC;
+
+ if (bt_split_a2dp_enabled)
+ {
+ btif_media_cb.max_bitpool = msg.MaxBitPool;
+ btif_media_cb.min_bitpool = msg.MinBitPool;
+ APPL_TRACE_DEBUG("Updated min_bitpool: 0x%x max_bitpool: 0x%x",
+ btif_media_cb.min_bitpool, btif_media_cb.max_bitpool);
+ }
}
msg.MinMtuSize = minmtu;
@@ -955,6 +1537,17 @@
btif_media_task_enc_update_req(&msg);
}
+bool btif_a2dp_is_media_task_stopped(void)
+{
+ if (media_task_running != MEDIA_TASK_STATE_OFF)
+ {
+ APPL_TRACE_ERROR("btif_a2dp_is_media_task_stopped: %d",
+ media_task_running);
+ return false;
+ }
+ return true;
+}
+
bool btif_a2dp_start_media_task(void)
{
if (media_task_running != MEDIA_TASK_STATE_OFF)
@@ -963,12 +1556,14 @@
return false;
}
- APPL_TRACE_EVENT("## A2DP START MEDIA THREAD ##");
+ APPL_TRACE_IMP("## A2DP START MEDIA THREAD ##");
btif_media_cmd_msg_queue = fixed_queue_new(SIZE_MAX);
+ if (btif_media_cmd_msg_queue == NULL)
+ goto error_exit;
/* start a2dp media task */
- worker_thread = thread_new("media_worker");
+ worker_thread = thread_new_sized("media_worker", MAX_MEDIA_WORKQUEUE_SEM_COUNT);
if (worker_thread == NULL)
goto error_exit;
@@ -978,7 +1573,7 @@
NULL);
thread_post(worker_thread, btif_media_thread_init, NULL);
- APPL_TRACE_EVENT("## A2DP MEDIA THREAD STARTED ##");
+ APPL_TRACE_IMP("## A2DP MEDIA THREAD STARTED ##");
return true;
@@ -989,18 +1584,37 @@
void btif_a2dp_stop_media_task(void)
{
- APPL_TRACE_EVENT("## A2DP STOP MEDIA THREAD ##");
+ APPL_TRACE_DEBUG("## A2DP STOP MEDIA THREAD ##");
+ if (media_task_running != MEDIA_TASK_STATE_ON)
+ {
+ APPL_TRACE_ERROR("warning: media task cleanup state: %d",
+ media_task_running);
+ return;
+ }
+ /* make sure no channels are restarted while shutting down */
+ media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN;
+
+ // remove aptX thread
+ A2D_stop_aptX();
// Stop timer
alarm_free(btif_media_cb.media_alarm);
btif_media_cb.media_alarm = NULL;
+ if (btif_media_cb.remote_start_alarm != NULL)
+ {
+ alarm_free(btif_media_cb.remote_start_alarm);
+ btif_media_cb.remote_start_alarm = NULL;
+ btif_dispatch_sm_event(BTIF_AV_RESET_REMOTE_STARTED_FLAG_EVT, NULL, 0);
+ }
// Exit thread
fixed_queue_free(btif_media_cmd_msg_queue, NULL);
- btif_media_cmd_msg_queue = NULL;
thread_post(worker_thread, btif_media_thread_cleanup, NULL);
thread_free(worker_thread);
+
worker_thread = NULL;
+ btif_media_cmd_msg_queue = NULL;
+ APPL_TRACE_DEBUG("## A2DP MEDIA THREAD STOPPED ##");
}
/*****************************************************************************
@@ -1032,7 +1646,7 @@
**
*******************************************************************************/
-void btif_a2dp_setup_codec(void)
+tBTIF_STATUS btif_a2dp_setup_codec(tBTA_AV_HNDL hdl)
{
tBTIF_AV_MEDIA_FEEDINGS media_feeding;
tBTIF_STATUS status;
@@ -1041,18 +1655,28 @@
mutex_global_lock();
- /* for now hardcode 44.1 khz 16 bit stereo PCM format */
+
+#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ
+ /* for now hardcode 48 khz 16 bit stereo PCM format */
+ media_feeding.cfg.pcm.sampling_freq = 48000;
+#else
+ /* for now hardcode 44.1 khz 32 bit stereo PCM format */
media_feeding.cfg.pcm.sampling_freq = BTIF_A2DP_SRC_SAMPLING_RATE;
+#endif
media_feeding.cfg.pcm.bit_per_sample = BTIF_A2DP_SRC_BIT_DEPTH;
media_feeding.cfg.pcm.num_channel = BTIF_A2DP_SRC_NUM_CHANNELS;
media_feeding.format = BTIF_AV_CODEC_PCM;
+ /* 32 bits for AUDIO_FORMAT_PCM_8_24_BIT, all codecs affected. */
+ APPL_TRACE_EVENT("%s bit_per_sample %d", __func__, media_feeding.cfg.pcm.bit_per_sample);
+ APPL_TRACE_EVENT("%s sampling_freq %d", __func__, media_feeding.cfg.pcm.sampling_freq);
+
if (bta_av_co_audio_set_codec(&media_feeding, &status))
{
tBTIF_MEDIA_INIT_AUDIO_FEEDING mfeed;
/* Init the encoding task */
- btif_a2dp_encoder_init();
+ btif_a2dp_encoder_init(hdl);
/* Build the media task configuration */
mfeed.feeding = media_feeding;
@@ -1060,8 +1684,33 @@
/* Send message to Media task to configure transcoding */
btif_media_task_audio_feeding_init_req(&mfeed);
}
+ else
+ {
+ status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED;
+ }
mutex_global_unlock();
+ return status;
+}
+
+
+/*****************************************************************************
+**
+** Function btif_a2dp_update_codec
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_update_codec(void)
+{
+ APPL_TRACE_DEBUG("## A2DP UPDATE CODEC ##");
+ mutex_global_lock();
+ btif_media_task_start_aa_req();
+ btif_a2dp_encoder_update();
+ mutex_global_unlock();
}
@@ -1077,12 +1726,14 @@
void btif_a2dp_on_idle(void)
{
- APPL_TRACE_EVENT("## ON A2DP IDLE ## peer_sep = %d", btif_media_cb.peer_sep);
+ APPL_TRACE_IMP("## ON A2DP IDLE ## peer_sep = %d", btif_media_cb.peer_sep);
if (btif_media_cb.peer_sep == AVDT_TSEP_SNK)
{
/* Make sure media task is stopped */
btif_media_task_stop_aa_req();
}
+ if (bt_split_a2dp_enabled)
+ btif_media_send_reset_vendor_state();
bta_av_co_init();
#if (BTA_AV_SINK_INCLUDED == TRUE)
@@ -1109,10 +1760,11 @@
void btif_a2dp_on_open(void)
{
- APPL_TRACE_EVENT("## ON A2DP OPEN ##");
+ APPL_TRACE_IMP("## ON A2DP OPEN ##");
/* always use callback to notify socket events */
- UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+ if (!bt_split_a2dp_enabled)
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
}
/*******************************************************************************
@@ -1126,10 +1778,11 @@
*******************************************************************************/
BOOLEAN btif_media_task_clear_track(void)
{
- BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
@@ -1156,8 +1809,8 @@
memcpy(p_buf->codec_info,p_av, AVDT_CODEC_SIZE);
p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE;
-
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
}
/*****************************************************************************
@@ -1170,16 +1823,28 @@
**
*******************************************************************************/
-BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start)
+BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start, tBTA_AV_HNDL hdl)
{
BOOLEAN ack = FALSE;
- APPL_TRACE_EVENT("## ON A2DP STARTED ##");
+ APPL_TRACE_IMP("## ON A2DP STARTED ##");
if (p_av == NULL)
{
- /* ack back a local start request */
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ if (bt_split_a2dp_enabled)
+ {
+ APPL_TRACE_EVENT("## ON A2DP STARTED split a2dp enabled##");
+ if (btif_media_cb.peer_sep == AVDT_TSEP_SNK)
+ {
+ btif_media_on_start_vendor_command();
+ }
+ }
+ else
+ {
+ /* ack back a local start request */
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_START)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
return TRUE;
}
@@ -1190,7 +1855,18 @@
if (p_av->initiator)
{
if (pending_start) {
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ if (bt_split_a2dp_enabled)
+ {
+ if (btif_media_cb.peer_sep == AVDT_TSEP_SNK)
+ {
+ btif_media_on_start_vendor_command();
+ }
+ }
+ else
+ {
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_START)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
ack = TRUE;
}
}
@@ -1198,7 +1874,16 @@
{
/* we were remotely started, make sure codec
is setup before datapath is started */
- btif_a2dp_setup_codec();
+ if (bt_split_a2dp_enabled)
+ {
+ if (btif_media_cb.peer_sep == AVDT_TSEP_SNK)
+ {
+ APPL_TRACE_IMP("Do not Initiate VSC exchange on remote start");
+ //btif_media_on_start_vendor_command();
+ }
+ }
+ else
+ btif_a2dp_setup_codec(hdl);
}
/* media task is autostarted upon a2dp audiopath connection */
@@ -1208,13 +1893,13 @@
{
APPL_TRACE_WARNING("%s: A2DP start request failed: status = %d",
__func__, p_av->status);
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_START)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
ack = TRUE;
}
return ack;
}
-
/*****************************************************************************
**
** Function btif_a2dp_ack_fail
@@ -1227,7 +1912,7 @@
void btif_a2dp_ack_fail(void)
{
- APPL_TRACE_EVENT("## A2DP_CTRL_ACK_FAILURE ##");
+ APPL_TRACE_IMP("## A2DP_CTRL_ACK_FAILURE ##");
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
}
@@ -1243,7 +1928,7 @@
void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av)
{
- APPL_TRACE_EVENT("## ON A2DP STOPPED ##");
+ APPL_TRACE_IMP("## ON A2DP STOPPED ##");
if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) /* Handling for A2DP SINK cases*/
{
btif_media_cb.rx_flush = TRUE;
@@ -1265,7 +1950,9 @@
if (p_av->initiator) {
APPL_TRACE_WARNING("%s: A2DP stop request failed: status = %d",
__func__, p_av->status);
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ if ((btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_STOP) ||
+ (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND))
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
}
return;
}
@@ -1275,7 +1962,8 @@
btif_media_cb.tx_flush = 1;
/* request to stop media task */
- btif_media_task_aa_tx_flush_req();
+ if (!bt_split_a2dp_enabled)
+ btif_media_task_aa_tx_flush_req();
btif_media_task_stop_aa_req();
/* once stream is fully stopped we will ack back */
@@ -1294,7 +1982,7 @@
void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av)
{
- APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##");
+ APPL_TRACE_IMP("## ON A2DP SUSPENDED ##");
if (btif_media_cb.peer_sep == AVDT_TSEP_SRC)
{
btif_media_cb.rx_flush = TRUE;
@@ -1312,7 +2000,9 @@
if (p_av->initiator == TRUE) {
APPL_TRACE_WARNING("%s: A2DP suspend request failed: status = %d",
__func__, p_av->status);
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ if ((btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_STOP) ||
+ (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND))
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
}
}
@@ -1325,9 +2015,83 @@
btif_media_task_stop_aa_req();
}
+UINT8 btif_a2dp_get_pending_hal_command()
+{
+ return btif_media_cb.a2dp_cmd_pending;
+}
/*****************************************************************************
**
+** Function btif_media_remote_start_alarm_cb
+**
+** Description Remote start honor timer, if media is not started then
+** suspend AV
+** Returns
+**
+*******************************************************************************/
+static void btif_media_remote_start_alarm_cb(UNUSED_ATTR void *context) {
+ thread_post(worker_thread, btif_a2dp_remote_start_timer, NULL);
+}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_remote_start_timer
+**
+** Description Suspend stream if media is not started for remote stream
+** start is honored
+** Returns
+**
+*******************************************************************************/
+void btif_a2dp_remote_start_timer()
+{
+ alarm_free(btif_media_cb.remote_start_alarm);
+ btif_media_cb.remote_start_alarm = NULL;
+ APPL_TRACE_DEBUG("Suspend stream request to Av");
+ btif_dispatch_sm_event(BTIF_AV_REMOTE_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+}
+
+void btif_a2dp_cancel_remote_start_timer()
+{
+ if (alarm_is_scheduled(btif_media_cb.remote_start_alarm))
+ {
+ APPL_TRACE_DEBUG("Cancel remote start timer");
+ alarm_free(btif_media_cb.remote_start_alarm);
+ btif_media_cb.remote_start_alarm = NULL;
+ }
+}
+
+void btif_media_on_cancel_remote_start_alarm() {
+ thread_post(worker_thread, btif_a2dp_cancel_remote_start_timer, NULL);
+}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_remote_started
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+void btif_a2dp_on_remote_started()
+{
+ btif_media_cb.remote_start_alarm = alarm_new("btif.remote_start_task");
+
+ if (!btif_media_cb.remote_start_alarm)
+ {
+ APPL_TRACE_WARNING("%s:unable to allocate media alarm",__func__);
+ return;
+ }
+ alarm_set(btif_media_cb.remote_start_alarm, BTIF_REMOTE_START_TOUT,
+ btif_media_remote_start_alarm_cb, NULL);
+}
+
+BOOLEAN btif_is_remote_start_timer_scheduled()
+{
+ return (alarm_is_scheduled(btif_media_cb.remote_start_alarm))? TRUE:FALSE;
+}
+/*****************************************************************************
+**
** Function btif_a2dp_on_offload_started
**
** Description
@@ -1381,7 +2145,8 @@
p_buf->focus_state = state;
p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
}
void btif_a2dp_set_audio_track_gain(float gain)
@@ -1499,6 +2264,7 @@
// we're using that in frame size calculations now.
assert(CHAR_BIT == 8);
+ APPL_TRACE_IMP(" btif_media_thread_init");
memset(&btif_media_cb, 0, sizeof(btif_media_cb));
UIPC_Init(NULL);
@@ -1511,13 +2277,16 @@
raise_priority_a2dp(TASK_HIGH_MEDIA);
media_task_running = MEDIA_TASK_STATE_ON;
+ enc_update_in_progress = FALSE;
+ APPL_TRACE_DEBUG(" btif_media_thread_init complete");
metrics_log_bluetooth_session_start(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
}
static void btif_media_thread_cleanup(UNUSED_ATTR void *context) {
- /* make sure no channels are restarted while shutting down */
- media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN;
+ APPL_TRACE_IMP(" btif_media_thread_cleanup");
+ APPL_TRACE_IMP(" before close the UIPC channnel, ack the pending cmd");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
/* this calls blocks until uipc is fully closed */
UIPC_Close(UIPC_CH_ID_ALL);
@@ -1530,6 +2299,8 @@
/* Clear media task flag */
media_task_running = MEDIA_TASK_STATE_OFF;
+ enc_update_in_progress = FALSE;
+ APPL_TRACE_DEBUG(" btif_media_thread_cleanup complete");
metrics_log_bluetooth_session_end(DISCONNECT_REASON_UNKNOWN, 0);
}
@@ -1544,11 +2315,12 @@
*******************************************************************************/
BOOLEAN btif_media_task_send_cmd_evt(UINT16 Evt)
{
- BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
p_buf->event = Evt;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
@@ -1572,7 +2344,7 @@
static void btif_media_thread_handle_cmd(fixed_queue_t *queue, UNUSED_ATTR void *context)
{
BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
- LOG_VERBOSE(LOG_TAG, "btif_media_thread_handle_cmd : %d %s", p_msg->event,
+ APPL_TRACE_IMP("btif_media_thread_handle_cmd : %d %s", p_msg->event,
dump_media_event(p_msg->event));
switch (p_msg->event)
@@ -1620,12 +2392,189 @@
case BTIF_MEDIA_FLUSH_AA_RX:
btif_media_task_aa_rx_flush();
break;
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+ case BTIF_MEDIA_RESET_VS_STATE:
+ btif_media_cb.tx_started = FALSE;
+ btif_media_cb.tx_stop_initiated = FALSE;
+ btif_media_cb.vs_configs_exchanged = FALSE;
+ btif_media_cb.tx_start_initiated = FALSE;
+ btif_media_cb.tx_enc_update_initiated = FALSE;
+ break;
+ case BTIF_MEDIA_START_VS_CMD:
+ if (!btif_hf_is_call_vr_idle())
+ {
+ APPL_TRACE_IMP("ignore VS start request as Call is not idle");
+ }
+ else if (!btif_media_cb.tx_started
+ && (!btif_media_cb.tx_start_initiated || btif_media_cb.tx_enc_update_initiated))
+ {
+ btif_a2dp_encoder_update();
+ btif_media_start_vendor_command();
+ }
+ else
+ {
+ APPL_TRACE_IMP("ignore VS start request");
+ }
+ break;
+ case BTIF_MEDIA_STOP_VS_CMD:
+ if (btif_media_cb.tx_started && !btif_media_cb.tx_stop_initiated)
+ btif_media_send_vendor_stop();
+ else if((btif_media_cb.tx_start_initiated || btif_media_cb.tx_enc_update_initiated)
+ && !btif_media_cb.tx_started)
+ {
+ APPL_TRACE_IMP("Suspend Req when VSC exchange in progress,reset VSC");
+ btif_media_send_reset_vendor_state();
+ }
+ else
+ APPL_TRACE_IMP("ignore VS stop request");
+ break;
+ case BTIF_MEDIA_VS_A2DP_START_SUCCESS:
+ if (get_soc_type() == BT_SOC_SMD)
+ {
+ btif_media_cb.vs_configs_exchanged = false;
+ }
+ btif_media_cb.tx_start_initiated = FALSE;
+ btif_media_cb.tx_started = TRUE;
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_START)
+ {
+ btif_av_reset_reconfig_flag();
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("wrong cmd %d pending, ignore ACK",
+ btif_media_cb.a2dp_cmd_pending);
+ }
+ break;
+ case BTIF_MEDIA_VS_A2DP_START_FAILURE:
+ if (get_soc_type() == BT_SOC_SMD)
+ {
+ btif_media_cb.vs_configs_exchanged = false;
+ }
+ btif_media_cb.tx_start_initiated = FALSE;
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_START)
+ {
+ btif_av_reset_reconfig_flag();
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("wrong cmd %d pending, ignore ACK",
+ btif_media_cb.a2dp_cmd_pending);
+ }
+ disconnect_a2dp_on_vendor_start_failure();
+ break;
+ case BTIF_MEDIA_VS_A2DP_STOP_SUCCESS:
+ btif_media_cb.tx_started = FALSE;
+ btif_media_cb.tx_stop_initiated = FALSE;
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND ||
+ btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_STOP)
+ {
+ /*Reset vendor state after stop success
+ to handle stream started for touch tone
+ to connect to second other device
+ */
+ btif_media_send_reset_vendor_state();
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("wrong cmd %d pending, ignore ACK",
+ btif_media_cb.a2dp_cmd_pending);
+ }
+ break;
+ case BTIF_MEDIA_VS_A2DP_STOP_FAILURE:
+ btif_media_cb.tx_stop_initiated = FALSE;
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND ||
+ btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_STOP)
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("wrong cmd %d pending, ignore ACK",
+ btif_media_cb.a2dp_cmd_pending);
+ }
+ break;
+ case BTIF_MEDIA_VS_A2DP_MEDIA_CHNL_CFG_SUCCESS:
+ //btif_media_send_vendor_pref_bit_rate();
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ btif_media_send_vendor_scmst_hdr();
+#else
+ if (get_soc_type() == BT_SOC_SMD)
+ {
+ if (!btif_media_cb.vs_configs_exchanged &&
+ btif_media_cb.tx_start_initiated)
+ btif_media_cb.vs_configs_exchanged = TRUE;
+ else
+ {
+ APPL_TRACE_ERROR("Dont send start,stream suspended")
+ break;
+ }
+ }
+ else
+ {
+ if (!btif_media_cb.tx_start_initiated)
+ {
+ APPL_TRACE_ERROR("Dont send start,stream suspended")
+ break;
+ }
+ }
+ btif_media_send_vendor_start();
+#endif
+ break;
+ case BTIF_MEDIA_VS_A2DP_WRITE_SBC_CFG_SUCCESS:
+ btif_media_send_vendor_media_chn_cfg();
+ break;
+ case BTIF_MEDIA_VS_A2DP_SELECTED_CODEC_SUCCESS:
+ btif_media_send_vendor_transport_cfg();
+ break;
+ case BTIF_MEDIA_VS_A2DP_TRANSPORT_CFG_SUCCESS:
+ btif_media_send_vendor_media_chn_cfg();
+ break;
+ case BTIF_MEDIA_VS_A2DP_PREF_BIT_RATE_SUCCESS:
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ btif_media_send_vendor_scmst_hdr();
+#else
+ if ((get_soc_type() == BT_SOC_SMD) &&
+ (!btif_media_cb.vs_configs_exchanged))
+ {
+ btif_media_cb.vs_configs_exchanged = TRUE;
+ }
+ btif_media_send_vendor_start();
+#endif
+ break;
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ case BTIF_MEDIA_VS_A2DP_SET_SCMST_HDR_SUCCESS:
+ if (get_soc_type() == BT_SOC_SMD)
+ {
+ if (!btif_media_cb.vs_configs_exchanged &&
+ btif_media_cb.tx_start_initiated)
+ btif_media_cb.vs_configs_exchanged = TRUE;
+ else
+ {
+ APPL_TRACE_ERROR("Dont send start,stream suspended")
+ break;
+ }
+ }
+ else
+ {
+ if (!btif_media_cb.tx_start_initiated)
+ {
+ APPL_TRACE_ERROR("Dont send start,stream suspended")
+ break;
+ }
+ }
+ btif_media_send_vendor_start();
+ break;
+#endif
+#endif
#endif
default:
APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
}
osi_free(p_msg);
- LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+ APPL_TRACE_IMP("%s: %s DONE", __func__, dump_media_event(p_msg->event));
}
#if (BTA_AV_SINK_INCLUDED == TRUE)
@@ -1707,8 +2656,9 @@
memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO));
p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_INIT;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
@@ -1728,8 +2678,9 @@
memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_UPDATE_AUDIO));
p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_UPDATE;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
@@ -1749,8 +2700,9 @@
memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO_FEEDING));
p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_INIT;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
@@ -1765,11 +2717,12 @@
*******************************************************************************/
BOOLEAN btif_media_task_start_aa_req(void)
{
- BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_START_AA_TX;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
memset(&btif_media_cb.stats, 0, sizeof(btif_media_stats_t));
// Assign session_start_us to 1 when time_now_us() is 0 to indicate
// btif_media_task_start_aa_req() has been called
@@ -1792,7 +2745,7 @@
*******************************************************************************/
BOOLEAN btif_media_task_stop_aa_req(void)
{
- BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_STOP_AA_TX;
@@ -1831,10 +2784,11 @@
if (fixed_queue_is_empty(btif_media_cb.RxSbcQ)) /* Que is already empty */
return TRUE;
- BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_FLUSH_AA_RX;
- fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
return TRUE;
}
@@ -1849,7 +2803,7 @@
*******************************************************************************/
BOOLEAN btif_media_task_aa_tx_flush_req(void)
{
- BT_HDR *p_buf = osi_malloc(sizeof(BT_HDR));
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTIF_MEDIA_FLUSH_AA_TX;
@@ -1930,6 +2884,44 @@
btif_media_cb.timestamp = 0;
+ if (pInitAudio->CodecType == A2D_NON_A2DP_MEDIA_CT)
+ {
+ APPL_TRACE_EVENT("%s BluetoothVendorID %x, BluetoothCodecID %d", __func__,
+ pInitAudio->BluetoothVendorID, pInitAudio->BluetoothCodecID);
+ if ((pInitAudio->BluetoothVendorID == A2D_APTX_VENDOR_ID)
+ && (pInitAudio->BluetoothCodecID == A2D_APTX_CODEC_ID_BLUETOOTH)) {
+ btif_media_cb.aptxEncoderParams.s16SamplingFreq= pInitAudio->SamplingFreq;
+ btif_media_cb.aptxEncoderParams.s16ChannelMode = pInitAudio->ChannelMode;
+ btif_media_cb.aptxEncoderParams.u16PacketLength = 4; // 32-bit word encoded by aptX encoder
+ btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_APTX;
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_OFFSET-sizeof(BT_HDR))
+ < pInitAudio->MtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_OFFSET
+ - sizeof(BT_HDR)) : pInitAudio->MtuSize;
+ return;
+ } else if ((pInitAudio->BluetoothVendorID == A2D_APTX_HD_VENDOR_ID)
+ && (pInitAudio->BluetoothCodecID == A2D_APTX_HD_CODEC_ID_BLUETOOTH)) {
+ btif_media_cb.aptxhdEncoderParams.s16SamplingFreq= pInitAudio->SamplingFreq;
+ btif_media_cb.aptxhdEncoderParams.s16ChannelMode = pInitAudio->ChannelMode;
+ btif_media_cb.aptxhdEncoderParams.u16PacketLength = 6; // 48-bit word encoded by aptX encoder
+ btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_APTX_HD;
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_HD_OFFSET-sizeof(BT_HDR))
+ < pInitAudio->MtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_HD_OFFSET
+ - sizeof(BT_HDR)) : pInitAudio->MtuSize;
+ return;
+ } else {
+ /* do nothing, fall through to SBC */
+ }
+ }
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ else if (pInitAudio->CodecType == BTIF_AV_CODEC_M24) {
+ /*AAC is supported only in split mode, so only update the
+ required MTU size for AAC to send down to FW via VSC*/
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE-BTIF_MEDIA_AA_AAC_OFFSET-sizeof(BT_HDR))
+ < pInitAudio->MtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_AAC_OFFSET
+ - sizeof(BT_HDR)) : pInitAudio->MtuSize;
+ return;
+ }
+#endif
/* SBC encoder config (enforced even if not used) */
btif_media_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode;
btif_media_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
@@ -1953,12 +2945,15 @@
btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate,
btif_media_cb.encoder.s16SamplingFreq);
- /* Reset entirely the SBC encoder */
- SBC_Encoder_Init(&(btif_media_cb.encoder));
+ if (!bt_split_a2dp_enabled)
+ {
+ /* Reset entirely the SBC encoder */
+ SBC_Encoder_Init(&(btif_media_cb.encoder));
- btif_media_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+ btif_media_cb.tx_sbc_frames = calculate_max_frames_per_packet();
- APPL_TRACE_DEBUG("%s bit pool %d", __func__, btif_media_cb.encoder.s16BitPool);
+ APPL_TRACE_DEBUG("btif_media_task_enc_init bit pool %d", btif_media_cb.encoder.s16BitPool);
+ }
}
/*******************************************************************************
@@ -1985,143 +2980,185 @@
pUpdateAudio->MinMtuSize, pUpdateAudio->MaxBitPool,
pUpdateAudio->MinBitPool);
- if (!pstrEncParams->s16NumOfSubBands)
+ /* Only update the bitrate and MTU size while timer is running to make sure it has been initialized */
+ if (pUpdateAudio->CodecType == A2D_NON_A2DP_MEDIA_CT)
{
- APPL_TRACE_WARNING("%s SubBands are set to 0, resetting to max (%d)",
- __func__, SBC_MAX_NUM_OF_SUBBANDS);
- pstrEncParams->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS;
+ APPL_TRACE_EVENT("%s BluetoothVendorID %x, BluetoothCodecID %d", __func__,
+ pUpdateAudio->BluetoothVendorID, pUpdateAudio->BluetoothCodecID);
+
+ if ((pUpdateAudio->BluetoothVendorID == A2D_APTX_VENDOR_ID)
+ && (pUpdateAudio->BluetoothCodecID == A2D_APTX_CODEC_ID_BLUETOOTH)) {
+ APPL_TRACE_DEBUG("%s aptX ", __func__);
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_OFFSET - sizeof(BT_HDR)) < pUpdateAudio->MinMtuSize) ?
+ (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_OFFSET - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
+ APPL_TRACE_DEBUG("%s : aptX btif_media_cb.TxAaMtuSize %d", __func__, btif_media_cb.TxAaMtuSize);
+ enc_update_in_progress = FALSE;
+ return;
+ } else if ((pUpdateAudio->BluetoothVendorID == A2D_APTX_HD_VENDOR_ID)
+ && (pUpdateAudio->BluetoothCodecID == A2D_APTX_HD_CODEC_ID_BLUETOOTH)) {
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_HD_OFFSET - sizeof(BT_HDR)) < pUpdateAudio->MinMtuSize) ?
+ (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_APTX_HD_OFFSET - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
+ enc_update_in_progress = FALSE;
+ return;
+ } else {
+ /* do nothing, fall through to SBC */
+ }
}
-
- if (!pstrEncParams->s16NumOfBlocks)
- {
- APPL_TRACE_WARNING("%s Blocks are set to 0, resetting to max (%d)",
- __func__, SBC_MAX_NUM_OF_BLOCKS);
- pstrEncParams->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS;
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+ else if (pUpdateAudio->CodecType == BTIF_AV_CODEC_M24) {
+ APPL_TRACE_EVENT("%s AAC" , __func__);
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE -
+ BTIF_MEDIA_AA_AAC_OFFSET - sizeof(BT_HDR))
+ < pUpdateAudio->MinMtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_AAC_OFFSET
+ - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
+ enc_update_in_progress = FALSE;
+ return;
}
-
- if (!pstrEncParams->s16NumOfChannels)
- {
- APPL_TRACE_WARNING("%s Channels are set to 0, resetting to max (%d)",
- __func__, SBC_MAX_NUM_OF_CHANNELS);
- pstrEncParams->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS;
- }
-
- btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE -
- BTIF_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
- < pUpdateAudio->MinMtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET
- - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
-
- /* Set the initial target bit rate */
- pstrEncParams->u16BitRate = btif_media_task_get_sbc_rate();
-
- if (pstrEncParams->s16SamplingFreq == SBC_sf16000)
- s16SamplingFreq = 16000;
- else if (pstrEncParams->s16SamplingFreq == SBC_sf32000)
- s16SamplingFreq = 32000;
- else if (pstrEncParams->s16SamplingFreq == SBC_sf44100)
- s16SamplingFreq = 44100;
+#endif
else
- s16SamplingFreq = 48000;
-
- do {
- if (pstrEncParams->s16NumOfBlocks == 0 ||
- pstrEncParams->s16NumOfSubBands == 0 ||
- pstrEncParams->s16NumOfChannels == 0) {
- APPL_TRACE_ERROR("%s - Avoiding division by zero...", __func__);
- APPL_TRACE_ERROR("%s - block=%d, subBands=%d, channels=%d",
- __func__,
- pstrEncParams->s16NumOfBlocks,
- pstrEncParams->s16NumOfSubBands,
- pstrEncParams->s16NumOfChannels);
- break;
+ {
+ if (!pstrEncParams->s16NumOfSubBands)
+ {
+ APPL_TRACE_WARNING("%s SubBands are set to 0, resetting to max (%d)",
+ __func__, SBC_MAX_NUM_OF_SUBBANDS);
+ pstrEncParams->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS;
}
- if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) ||
- (pstrEncParams->s16ChannelMode == SBC_STEREO)) {
- s16BitPool = (SINT16)((pstrEncParams->u16BitRate *
- pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
- - ((32 + (4 * pstrEncParams->s16NumOfSubBands *
- pstrEncParams->s16NumOfChannels)
- + ((pstrEncParams->s16ChannelMode - 2) *
- pstrEncParams->s16NumOfSubBands))
- / pstrEncParams->s16NumOfBlocks));
-
- s16FrameLen = 4 + (4*pstrEncParams->s16NumOfSubBands *
- pstrEncParams->s16NumOfChannels) / 8
- + (((pstrEncParams->s16ChannelMode - 2) *
- pstrEncParams->s16NumOfSubBands)
- + (pstrEncParams->s16NumOfBlocks * s16BitPool)) / 8;
-
- s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
- / (pstrEncParams->s16NumOfSubBands *
- pstrEncParams->s16NumOfBlocks * 1000);
-
- if (s16BitRate > pstrEncParams->u16BitRate)
- s16BitPool--;
-
- if (pstrEncParams->s16NumOfSubBands == 8)
- s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
- else
- s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
- } else {
- s16BitPool = (SINT16)(((pstrEncParams->s16NumOfSubBands *
- pstrEncParams->u16BitRate * 1000)
- / (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
- - (((32 / pstrEncParams->s16NumOfChannels) +
- (4 * pstrEncParams->s16NumOfSubBands))
- / pstrEncParams->s16NumOfBlocks));
-
- pstrEncParams->s16BitPool =
- (s16BitPool > (16 * pstrEncParams->s16NumOfSubBands)) ?
- (16 * pstrEncParams->s16NumOfSubBands) : s16BitPool;
+ if (!pstrEncParams->s16NumOfBlocks)
+ {
+ APPL_TRACE_WARNING("%s Blocks are set to 0, resetting to max (%d)",
+ __func__, SBC_MAX_NUM_OF_BLOCKS);
+ pstrEncParams->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS;
}
- if (s16BitPool < 0)
- s16BitPool = 0;
-
- APPL_TRACE_EVENT("%s bitpool candidate : %d (%d kbps)", __func__,
- s16BitPool, pstrEncParams->u16BitRate);
-
- if (s16BitPool > pUpdateAudio->MaxBitPool) {
- APPL_TRACE_DEBUG("%s computed bitpool too large (%d)", __func__,
- s16BitPool);
- /* Decrease bitrate */
- btif_media_cb.encoder.u16BitRate -= BTIF_MEDIA_BITRATE_STEP;
- /* Record that we have decreased the bitrate */
- protect |= 1;
- } else if (s16BitPool < pUpdateAudio->MinBitPool) {
- APPL_TRACE_WARNING("%s computed bitpool too small (%d)", __func__,
- s16BitPool);
-
- /* Increase bitrate */
- UINT16 previous_u16BitRate = btif_media_cb.encoder.u16BitRate;
- btif_media_cb.encoder.u16BitRate += BTIF_MEDIA_BITRATE_STEP;
- /* Record that we have increased the bitrate */
- protect |= 2;
- /* Check over-flow */
- if (btif_media_cb.encoder.u16BitRate < previous_u16BitRate)
- protect |= 3;
- } else {
- break;
+ if (!pstrEncParams->s16NumOfChannels)
+ {
+ APPL_TRACE_WARNING("%s Channels are set to 0, resetting to max (%d)",
+ __func__, SBC_MAX_NUM_OF_CHANNELS);
+ pstrEncParams->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS;
}
- /* In case we have already increased and decreased the bitrate, just stop */
- if (protect == 3) {
- APPL_TRACE_ERROR("%s could not find bitpool in range", __func__);
- break;
+
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE -
+ BTIF_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
+ < pUpdateAudio->MinMtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET
+ - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
+
+ /* Set the initial target bit rate */
+ pstrEncParams->u16BitRate = btif_media_task_get_sbc_rate();
+
+ if (pstrEncParams->s16SamplingFreq == SBC_sf16000)
+ s16SamplingFreq = 16000;
+ else if (pstrEncParams->s16SamplingFreq == SBC_sf32000)
+ s16SamplingFreq = 32000;
+ else if (pstrEncParams->s16SamplingFreq == SBC_sf44100)
+ s16SamplingFreq = 44100;
+ else
+ s16SamplingFreq = 48000;
+
+ do {
+ if (pstrEncParams->s16NumOfBlocks == 0 ||
+ pstrEncParams->s16NumOfSubBands == 0 ||
+ pstrEncParams->s16NumOfChannels == 0) {
+ APPL_TRACE_ERROR("%s - Avoiding division by zero...", __func__);
+ APPL_TRACE_ERROR("%s - block=%d, subBands=%d, channels=%d",
+ __func__,
+ pstrEncParams->s16NumOfBlocks,
+ pstrEncParams->s16NumOfSubBands,
+ pstrEncParams->s16NumOfChannels);
+ break;
+ }
+
+ if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) ||
+ (pstrEncParams->s16ChannelMode == SBC_STEREO)) {
+ s16BitPool = (SINT16)((pstrEncParams->u16BitRate *
+ pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
+ - ((32 + (4 * pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfChannels)
+ + ((pstrEncParams->s16ChannelMode - 2) *
+ pstrEncParams->s16NumOfSubBands))
+ / pstrEncParams->s16NumOfBlocks));
+
+ s16FrameLen = 4 + (4*pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfChannels) / 8
+ + (((pstrEncParams->s16ChannelMode - 2) *
+ pstrEncParams->s16NumOfSubBands)
+ + (pstrEncParams->s16NumOfBlocks * s16BitPool)) / 8;
+
+ s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
+ / (pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfBlocks * 1000);
+
+ if (s16BitRate > pstrEncParams->u16BitRate)
+ s16BitPool--;
+
+ if (pstrEncParams->s16NumOfSubBands == 8)
+ s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
+ else
+ s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
+ } else {
+ s16BitPool = (SINT16)(((pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->u16BitRate * 1000)
+ / (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
+ - (((32 / pstrEncParams->s16NumOfChannels) +
+ (4 * pstrEncParams->s16NumOfSubBands))
+ / pstrEncParams->s16NumOfBlocks));
+
+ pstrEncParams->s16BitPool =
+ (s16BitPool > (16 * pstrEncParams->s16NumOfSubBands)) ?
+ (16 * pstrEncParams->s16NumOfSubBands) : s16BitPool;
+ }
+
+ if (s16BitPool < 0)
+ s16BitPool = 0;
+
+ APPL_TRACE_EVENT("%s bitpool candidate : %d (%d kbps)", __func__,
+ s16BitPool, pstrEncParams->u16BitRate);
+
+ if (s16BitPool > pUpdateAudio->MaxBitPool) {
+ APPL_TRACE_DEBUG("%s computed bitpool too large (%d)", __func__,
+ s16BitPool);
+ /* Decrease bitrate */
+ btif_media_cb.encoder.u16BitRate -= BTIF_MEDIA_BITRATE_STEP;
+ /* Record that we have decreased the bitrate */
+ protect |= 1;
+ } else if (s16BitPool < pUpdateAudio->MinBitPool) {
+ APPL_TRACE_WARNING("%s computed bitpool too small (%d)", __func__,
+ s16BitPool);
+
+ /* Increase bitrate */
+ UINT16 previous_u16BitRate = btif_media_cb.encoder.u16BitRate;
+ btif_media_cb.encoder.u16BitRate += BTIF_MEDIA_BITRATE_STEP;
+ /* Record that we have increased the bitrate */
+ protect |= 2;
+ /* Check over-flow */
+ if (btif_media_cb.encoder.u16BitRate < previous_u16BitRate)
+ protect |= 3;
+ } else {
+ break;
+ }
+ /* In case we have already increased and decreased the bitrate, just stop */
+ if (protect == 3) {
+ APPL_TRACE_ERROR("%s could not find bitpool in range", __func__);
+ break;
+ }
+ } while (1);
+
+ /* Finally update the bitpool in the encoder structure */
+ pstrEncParams->s16BitPool = s16BitPool;
+
+ APPL_TRACE_DEBUG("%s final bit rate %d, final bit pool %d", __func__,
+ btif_media_cb.encoder.u16BitRate,
+ btif_media_cb.encoder.s16BitPool);
+
+ if (!bt_split_a2dp_enabled)
+ {
+ /* make sure we reinitialize encoder with new settings */
+ SBC_Encoder_Init(&(btif_media_cb.encoder));
}
- } while (1);
-
- /* Finally update the bitpool in the encoder structure */
- pstrEncParams->s16BitPool = s16BitPool;
-
- APPL_TRACE_DEBUG("%s final bit rate %d, final bit pool %d", __func__,
- btif_media_cb.encoder.u16BitRate,
- btif_media_cb.encoder.s16BitPool);
-
- /* make sure we reinitialize encoder with new settings */
- SBC_Encoder_Init(&(btif_media_cb.encoder));
-
- btif_media_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+ btif_media_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+ }
+ enc_update_in_progress = FALSE;
}
/*******************************************************************************
@@ -2194,8 +3231,8 @@
btif_media_cb.encoder.s16NumOfSubBands, btif_media_cb.encoder.s16NumOfBlocks,
btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate,
btif_media_cb.encoder.s16SamplingFreq);
-
- SBC_Encoder_Init(&(btif_media_cb.encoder));
+ if (!bt_split_a2dp_enabled)
+ SBC_Encoder_Init(&(btif_media_cb.encoder));
}
else
{
@@ -2203,6 +3240,152 @@
}
}
+/*******************************************************************************
+ **
+ ** Function btif_media_task_pcm2aptx_hd_init
+ **
+ ** Description Init encoding task for PCM to aptX according to feeding
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_pcm2aptx_hd_init(tBTIF_MEDIA_INIT_AUDIO_FEEDING * p_feeding)
+{
+ BOOLEAN reconfig_needed = FALSE;
+
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ APPL_TRACE_DEBUG("%s PCM feeding:", __func__);
+ APPL_TRACE_DEBUG("%s sampling_freq:%d", __func__, p_feeding->feeding.cfg.pcm.sampling_freq);
+ APPL_TRACE_DEBUG("%s num_channel:%d", __func__, p_feeding->feeding.cfg.pcm.num_channel);
+ APPL_TRACE_DEBUG("%s bit_per_sample:%d", __func__, p_feeding->feeding.cfg.pcm.bit_per_sample);
+
+ /* Check the PCM feeding sampling_freq */
+ switch (p_feeding->feeding.cfg.pcm.sampling_freq)
+ {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ /* For these sampling_freq the AV connection must be 48000 */
+ if (btif_media_cb.aptxhdEncoderParams.s16SamplingFreq != A2D_APTX_HD_SAMPLERATE_48000)
+ {
+ /* Reconfiguration needed at 48000 */
+ APPL_TRACE_DEBUG("%s Reconfiguration needed at 48000", __func__);
+ btif_media_cb.aptxhdEncoderParams.s16SamplingFreq = A2D_APTX_HD_SAMPLERATE_48000;
+ reconfig_needed = TRUE;
+ }
+ break;
+
+ case 11025:
+ case 22050:
+ case 44100:
+ /* For these sampling_freq the AV connection must be 44100 */
+ if (btif_media_cb.aptxhdEncoderParams.s16SamplingFreq != A2D_APTX_HD_SAMPLERATE_44100)
+ {
+ /* Reconfiguration needed at 44100 */
+ APPL_TRACE_DEBUG("%s Reconfiguration needed at 44100", __func__);
+ btif_media_cb.aptxhdEncoderParams.s16SamplingFreq = A2D_APTX_HD_SAMPLERATE_44100;
+ reconfig_needed = TRUE;
+ }
+ break;
+ default:
+ APPL_TRACE_DEBUG("%s Feeding PCM sampling_freq unsupported", __func__);
+ break;
+ }
+
+ /* Some AV Headsets do not support Mono => always ask for Stereo */
+ if (btif_media_cb.aptxhdEncoderParams.s16ChannelMode == A2D_APTX_HD_CHANNELS_MONO)
+ {
+ APPL_TRACE_DEBUG("%s Reconfiguration needed in Stereo", __func__);
+ btif_media_cb.aptxhdEncoderParams.s16ChannelMode = A2D_APTX_HD_CHANNELS_STEREO;
+ reconfig_needed = TRUE;
+ }
+
+ if (reconfig_needed != FALSE)
+ {
+ APPL_TRACE_DEBUG("%s calls APTX_HD_Encoder_Init", __func__);
+ APPL_TRACE_DEBUG("%s mtu %d", __func__, btif_media_cb.TxAaMtuSize);
+ APPL_TRACE_DEBUG("%s ch mode %d, Smp freq %d", __func__,
+ btif_media_cb.aptxhdEncoderParams.s16ChannelMode, btif_media_cb.aptxhdEncoderParams.s16SamplingFreq);
+ } else {
+ APPL_TRACE_DEBUG("%s No aptX HD reconfig needed", __func__);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_pcm2aptx_init
+ **
+ ** Description Init encoding task for PCM to aptX according to feeding
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_pcm2aptx_init(tBTIF_MEDIA_INIT_AUDIO_FEEDING * p_feeding)
+{
+ BOOLEAN reconfig_needed = FALSE;
+
+ APPL_TRACE_DEBUG("%s PCM feeding:", __func__);
+ APPL_TRACE_DEBUG("%s sampling_freq:%d", __func__, p_feeding->feeding.cfg.pcm.sampling_freq);
+ APPL_TRACE_DEBUG("%s num_channel:%d", __func__, p_feeding->feeding.cfg.pcm.num_channel);
+ APPL_TRACE_DEBUG("%s bit_per_sample:%d", __func__, p_feeding->feeding.cfg.pcm.bit_per_sample);
+
+ /* Check the PCM feeding sampling_freq */
+ switch (p_feeding->feeding.cfg.pcm.sampling_freq)
+ {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ /* For these sampling_freq the AV connection must be 48000 */
+ if (btif_media_cb.aptxEncoderParams.s16SamplingFreq != A2D_APTX_SAMPLERATE_48000)
+ {
+ /* Reconfiguration needed at 48000 */
+ APPL_TRACE_DEBUG("%s Reconfiguration needed at 48000", __func__);
+ btif_media_cb.aptxEncoderParams.s16SamplingFreq = A2D_APTX_SAMPLERATE_48000;
+ reconfig_needed = TRUE;
+ }
+ break;
+
+ case 11025:
+ case 22050:
+ case 44100:
+ /* For these sampling_freq the AV connection must be 44100 */
+ if (btif_media_cb.aptxEncoderParams.s16SamplingFreq != A2D_APTX_SAMPLERATE_44100)
+ {
+ /* Reconfiguration needed at 44100 */
+ APPL_TRACE_DEBUG("%s Reconfiguration needed at 44100", __func__);
+ btif_media_cb.aptxEncoderParams.s16SamplingFreq = A2D_APTX_SAMPLERATE_44100;
+ reconfig_needed = TRUE;
+ }
+ break;
+ default:
+ APPL_TRACE_DEBUG("%s Feeding PCM sampling_freq unsupported", __func__);
+ break;
+ }
+
+ /* Some AV Headsets do not support Mono => always ask for Stereo */
+ if (btif_media_cb.aptxEncoderParams.s16ChannelMode == A2D_APTX_CHANNELS_MONO)
+ {
+ APPL_TRACE_DEBUG("%s Reconfiguration needed in Stereo", __func__);
+ btif_media_cb.aptxEncoderParams.s16ChannelMode = A2D_APTX_CHANNELS_STEREO;
+ reconfig_needed = TRUE;
+ }
+
+ if (reconfig_needed != FALSE)
+ {
+ APPL_TRACE_DEBUG("%s calls APTX_Encoder_Init", __func__);
+ APPL_TRACE_DEBUG("%s mtu %d", __func__, btif_media_cb.TxAaMtuSize);
+ APPL_TRACE_DEBUG("%s ch mode %d, Smp freq %d", __func__,
+ btif_media_cb.aptxEncoderParams.s16ChannelMode, btif_media_cb.aptxEncoderParams.s16SamplingFreq);
+ } else {
+ APPL_TRACE_DEBUG("%s no aptX reconfig needed", __func__);
+ }
+}
/*******************************************************************************
**
@@ -2216,7 +3399,7 @@
static void btif_media_task_audio_feeding_init(BT_HDR *p_msg)
{
tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_feeding = (tBTIF_MEDIA_INIT_AUDIO_FEEDING *) p_msg;
-
+ tA2D_APTX_CIE* codecInfo = 0;
APPL_TRACE_DEBUG("btif_media_task_audio_feeding_init format:%d", p_feeding->feeding.format);
/* Save Media Feeding information */
@@ -2227,10 +3410,40 @@
switch (p_feeding->feeding.format)
{
case BTIF_AV_CODEC_PCM:
+ {
+ UINT8 codectype;
+ codectype = bta_av_co_get_current_codec();
+
+ if (A2D_NON_A2DP_MEDIA_CT == codectype) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ // tA2D_APTX_CIE starts on 4th byte
+ codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo) {
+ APPL_TRACE_DEBUG("%s codecId = %d ", __func__, codecInfo->codecId);
+ APPL_TRACE_DEBUG("%s vendorId = %x ", __func__, codecInfo->vendorId);
+ }
+
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH) {
+ APPL_TRACE_DEBUG("%s aptX", __func__);
+ btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_APTX;
+ btif_media_task_pcm2aptx_init(p_feeding);
+ break;
+ } else if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) {
+ APPL_TRACE_DEBUG("%s aptX HD", __func__);
+ btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_APTX_HD;
+ btif_media_task_pcm2aptx_hd_init(p_feeding);
+ break;
+ } else {
+ /* do nothing, fall through to SBC */
+ }
+ }
+ }
+
btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC;
btif_media_task_pcm2sbc_init(p_feeding);
break;
-
+ }
default :
APPL_TRACE_ERROR("unknown feeding format %d", p_feeding->feeding.format);
break;
@@ -2517,6 +3730,78 @@
thread_post(worker_thread, btif_media_task_aa_handle_timer, NULL);
}
+int btif_media_task_cb_packet_send(uint8_t* packet, int length, int pcm_bytes_encoded)
+{
+ int bytes_per_frame = 2;
+ uint64_t timestamp_us = 0;
+ UINT8 codectype;
+ codectype = bta_av_co_get_current_codec();
+
+ if (btif_media_task_get_aptX_codec_type() == APTX_HD_CODEC) {
+ bytes_per_frame = 3;
+ }
+
+ if (length > 0 ) {
+
+ if (fixed_queue_length(btif_media_cb.TxAaQ) >= (MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ))
+ {
+ APPL_TRACE_WARNING("%s() - TX queue buffer count %d/%d", __func__,
+ fixed_queue_length(btif_media_cb.TxAaQ),
+ MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ);
+ btif_media_cb.stats.tx_queue_dropouts++;
+ timestamp_us = time_now_us();
+ btif_media_cb.stats.tx_queue_last_dropouts_us = timestamp_us;
+ }
+
+ while (fixed_queue_length(btif_media_cb.TxAaQ) >= MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) {
+ btif_media_cb.stats.tx_queue_total_dropped_messages++;
+ osi_free(fixed_queue_try_dequeue(btif_media_cb.TxAaQ));
+ }
+
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(BTIF_MEDIA_AA_BUF_SIZE);
+
+ int rtpTimestamp = (pcm_bytes_encoded / btif_media_cb.media_feeding.cfg.pcm.num_channel / bytes_per_frame);
+
+ *((UINT32 *) (p_buf + 1)) = btif_media_cb.timestamp;
+ btif_media_cb.timestamp += rtpTimestamp;
+
+ p_buf->offset = btif_media_cb.offset;
+ p_buf->layer_specific = 0;
+
+ UINT8* ptr = (UINT8*)(p_buf + 1);
+ ptr += p_buf->offset;
+
+ memcpy(ptr, packet, length);
+ p_buf->len = length;
+
+ if (btif_media_cb.tx_flush)
+ {
+ APPL_TRACE_DEBUG("### tx suspended, discarded frame ###");
+
+ btif_media_cb.stats.tx_queue_total_flushed_messages +=
+ fixed_queue_length(btif_media_cb.TxAaQ);
+ btif_media_cb.stats.tx_queue_last_flushed_us =
+ timestamp_us;
+ btif_media_flush_q(btif_media_cb.TxAaQ);
+
+ osi_free(p_buf);
+ } else {
+ update_scheduling_stats(&btif_media_cb.stats.tx_queue_enqueue_stats,
+ timestamp_us,
+ BTIF_SINK_MEDIA_TIME_TICK_MS * 1000);
+
+ const int BYTES_PER_FRAME = 4;
+ UINT32 frames = pcm_bytes_encoded / BYTES_PER_FRAME;
+ btif_media_cb.stats.tx_queue_total_frames += frames;
+ if (frames > btif_media_cb.stats.tx_queue_max_frames_per_packet)
+ btif_media_cb.stats.tx_queue_max_frames_per_packet = frames;
+ fixed_queue_enqueue(btif_media_cb.TxAaQ, p_buf);
+ }
+
+ bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
+ }
+ return length;
+}
/*******************************************************************************
**
** Function btif_media_task_aa_start_tx
@@ -2528,26 +3813,58 @@
*******************************************************************************/
static void btif_media_task_aa_start_tx(void)
{
- APPL_TRACE_DEBUG("%s media_alarm %srunning, feeding mode %d", __func__,
- alarm_is_scheduled(btif_media_cb.media_alarm)? "" : "not ",
- btif_media_cb.feeding_mode);
+ APPL_TRACE_IMP("%s media_alarm %srunning, feeding mode %d", __func__,
+ alarm_is_scheduled(btif_media_cb.media_alarm)? "" : "not ",
+ btif_media_cb.feeding_mode);
last_frame_us = 0;
/* Reset the media feeding state */
btif_media_task_feeding_state_reset();
- APPL_TRACE_EVENT("starting timer %dms", BTIF_MEDIA_TIME_TICK);
+ if (!bt_split_a2dp_enabled)
+ {
+ if (isA2dAptXEnabled && btif_media_task_is_aptx_configured()) {
- alarm_free(btif_media_cb.media_alarm);
- btif_media_cb.media_alarm = alarm_new_periodic("btif.media_task");
- if (!btif_media_cb.media_alarm) {
- LOG_ERROR(LOG_TAG, "%s unable to allocate media alarm.", __func__);
- return;
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ BOOLEAN use_SCMS_T = true;
+#else
+ BOOLEAN use_SCMS_T = false;
+#endif
+ A2D_AptXCodecType aptX_codec_type = btif_media_task_get_aptX_codec_type();
+ BOOLEAN is_24bit_audio = true;
+
+ BOOLEAN test = false;
+ BOOLEAN trace = false;
+
+ A2D_start_aptX(btif_media_cb.aptxEncoderParams.encoder,
+ aptX_codec_type,
+ use_SCMS_T,
+ is_24bit_audio,
+ btif_media_cb.media_feeding.cfg.pcm.sampling_freq,
+ btif_media_cb.media_feeding.cfg.pcm.bit_per_sample,
+ UIPC_CH_ID_AV_AUDIO,
+ btif_media_cb.TxAaMtuSize,
+ UIPC_Read,
+ btif_media_task_cb_packet_send,
+ raise_priority_a2dp,
+ test,
+ trace);
+
+ } else {
+ APPL_TRACE_EVENT("starting timer %dms", BTIF_MEDIA_TIME_TICK);
+
+ alarm_free(btif_media_cb.media_alarm);
+ btif_media_cb.media_alarm = alarm_new_periodic("btif.media_task");
+ if (!btif_media_cb.media_alarm) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate media alarm.", __func__);
+ return;
+ }
+
+ alarm_set(btif_media_cb.media_alarm, BTIF_MEDIA_TIME_TICK,
+ btif_media_task_alarm_cb, NULL);
+ }
}
-
- alarm_set(btif_media_cb.media_alarm, BTIF_MEDIA_TIME_TICK,
- btif_media_task_alarm_cb, NULL);
}
/*******************************************************************************
@@ -2561,16 +3878,25 @@
*******************************************************************************/
static void btif_media_task_aa_stop_tx(void)
{
- APPL_TRACE_DEBUG("%s media_alarm is %srunning", __func__,
- alarm_is_scheduled(btif_media_cb.media_alarm)? "" : "not ");
+ if (!bt_split_a2dp_enabled)
+ {
+ APPL_TRACE_IMP("%s media_alarm is %srunning", __func__,
+ alarm_is_scheduled(btif_media_cb.media_alarm)? "" : "not ");
+ const bool send_ack = alarm_is_scheduled(btif_media_cb.media_alarm) |
+ btif_is_remote_start_timer_scheduled();
- const bool send_ack = alarm_is_scheduled(btif_media_cb.media_alarm);
+ if (isA2dAptXEnabled && A2d_aptx_thread)
+ {
+ A2D_stop_aptX();
+ }
+ else
+ {
+ /* Stop the timer first */
+ alarm_free(btif_media_cb.media_alarm);
+ btif_media_cb.media_alarm = NULL;
+ }
- /* Stop the timer first */
- alarm_free(btif_media_cb.media_alarm);
- btif_media_cb.media_alarm = NULL;
-
- UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+ UIPC_Close(UIPC_CH_ID_AV_AUDIO);
/* Try to send acknowldegment once the media stream is
stopped. This will make sure that the A2DP HAL layer is
@@ -2583,15 +3909,47 @@
a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
to get the ACK for any pending command in such cases. */
- if (send_ack)
- a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ if (send_ack)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
- /* audio engine stopped, reset tx suspended flag */
- btif_media_cb.tx_flush = 0;
- last_frame_us = 0;
+ /* audio engine stopped, reset tx suspended flag */
+ btif_media_cb.tx_flush = 0;
+ last_frame_us = 0;
- /* Reset the media feeding state */
- btif_media_task_feeding_state_reset();
+ /* Reset the media feeding state */
+ btif_media_task_feeding_state_reset();
+ }
+ else
+ {
+ APPL_TRACE_IMP("%s tx_started: %d, tx_stop_initiated: %d",
+ __func__, btif_media_cb.tx_started, btif_media_cb.tx_stop_initiated);
+ if (btif_media_cb.remote_start_alarm != NULL)
+ {
+ alarm_free(btif_media_cb.remote_start_alarm);
+ btif_media_cb.remote_start_alarm = NULL;
+ btif_dispatch_sm_event(BTIF_AV_RESET_REMOTE_STARTED_FLAG_EVT, NULL, 0);
+ }
+ if (btif_media_cb.tx_started && !btif_media_cb.tx_stop_initiated)
+ btif_media_send_vendor_stop();
+ else
+ {
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_STOP ||
+ btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND)
+ {
+ BTIF_TRACE_DEBUG("Ack Pending Stop/Suspend");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_START)
+ {
+ BTIF_TRACE_ERROR("Ack Pending Start while Disconnect in Progress");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("Invalid cmd pending for ack");
+ }
+ }
+ }
}
static UINT32 get_frame_length()
@@ -2886,7 +4244,7 @@
BT_HDR *btif_media_aa_readbuf(void)
{
uint64_t now_us = time_now_us();
- BT_HDR *p_buf = fixed_queue_try_dequeue(btif_media_cb.TxAaQ);
+ BT_HDR *p_buf = (BT_HDR *)fixed_queue_try_dequeue(btif_media_cb.TxAaQ);
btif_media_cb.stats.tx_queue_total_readbuf_calls++;
btif_media_cb.stats.tx_queue_last_readbuf_us = now_us;
@@ -2920,15 +4278,18 @@
UINT16 bytes_needed = blocm_x_subband * btif_media_cb.encoder.s16NumOfChannels * \
btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
- * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
+ * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 4];
static UINT16 read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
- * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
+ * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
UINT32 src_size_used;
UINT32 dst_size_used;
BOOLEAN fract_needed;
INT32 fract_max;
INT32 fract_threshold;
UINT32 nb_byte_read;
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ char trace_buf[512];
+ #endif
/* Get the SBC sampling rate */
switch (btif_media_cb.encoder.s16SamplingFreq)
@@ -2950,7 +4311,7 @@
if (sbc_sampling == btif_media_cb.media_feeding.cfg.pcm.sampling_freq) {
read_size = bytes_needed - btif_media_cb.media_feeding_state.pcm.aa_feed_residue;
nb_byte_read = UIPC_Read(channel_id, &event,
- ((UINT8 *)btif_media_cb.encoder.as16PcmBuffer) +
+ ((UINT8 *)btif_media_cb.encoder.as32PcmBuffer) +
btif_media_cb.media_feeding_state.pcm.aa_feed_residue,
read_size);
if (nb_byte_read == read_size) {
@@ -3024,6 +4385,19 @@
btif_media_cb.stats.media_read_total_underrun_bytes += (read_size - nb_byte_read);
btif_media_cb.stats.media_read_total_underrun_count++;
btif_media_cb.stats.media_read_last_underrun_us = time_now_us();
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ snprintf(trace_buf, 32, "A2DP UNDERRUN read %ld ", nb_byte_read);
+
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_BEGIN(trace_buf);
+ }
+
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_END();
+ }
+ #endif
if (nb_byte_read == 0)
return FALSE;
@@ -3056,7 +4430,7 @@
if(btif_media_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed)
{
/* Copy the output pcm samples in SBC encoding buffer */
- memcpy((UINT8 *)btif_media_cb.encoder.as16PcmBuffer,
+ memcpy((UINT8 *)btif_media_cb.encoder.as32PcmBuffer,
(UINT8 *)up_sampled_buffer,
bytes_needed);
/* update the residue */
@@ -3091,7 +4465,7 @@
btif_media_cb.encoder.s16NumOfBlocks;
while (nb_frame) {
- BT_HDR *p_buf = osi_malloc(BTIF_MEDIA_AA_BUF_SIZE);
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(BTIF_MEDIA_AA_BUF_SIZE);
/* Init buffer */
p_buf->offset = BTIF_MEDIA_AA_SBC_OFFSET;
@@ -3103,12 +4477,14 @@
/* Write @ of allocated buffer in encoder.pu8Packet */
btif_media_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
/* Fill allocated buffer with 0 */
- memset(btif_media_cb.encoder.as16PcmBuffer, 0, blocm_x_subband
- * btif_media_cb.encoder.s16NumOfChannels);
+ memset(btif_media_cb.encoder.as32PcmBuffer, 0, blocm_x_subband
+ * btif_media_cb.encoder.s16NumOfChannels * 2);
/* Read PCM data and upsample them if needed */
if (btif_media_aa_read_feeding(UIPC_CH_ID_AV_AUDIO))
{
+ size_t frames = blocm_x_subband * btif_media_cb.encoder.s16NumOfChannels;
+ memcpy_by_audio_format(btif_media_cb.encoder.as16PcmBuffer, AUDIO_FORMAT_PCM_16_BIT, btif_media_cb.encoder.as32PcmBuffer, AUDIO_FORMAT_PCM_8_24_BIT, frames);
SBC_Encoder(&(btif_media_cb.encoder));
/* Update SBC frame length */
@@ -3190,7 +4566,7 @@
static void btif_media_aa_prep_2_send(UINT8 nb_frame, uint64_t timestamp_us)
{
// Check for TX queue overflow
-
+ BD_ADDR peer_bda;
if (nb_frame > MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ)
nb_frame = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ;
@@ -3214,8 +4590,8 @@
}
// Request RSSI for log purposes if we had to flush buffers
- bt_bdaddr_t peer_bda = btif_av_get_addr();
- BTM_ReadRSSI(peer_bda.address, btm_read_rssi_cb);
+ btif_av_get_addr(peer_bda);
+ BTM_ReadRSSI(peer_bda, btm_read_rssi_cb);
}
// Transcode frame
@@ -3248,6 +4624,11 @@
btif_get_num_aa_frame_iteration(&nb_iterations, &nb_frame_2_send);
+ /* get the number of frame to send */
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ char trace_buf[1024];
+ #endif
+
if (nb_frame_2_send != 0) {
for (UINT8 counter = 0; counter < nb_iterations; counter++)
{
@@ -3258,9 +4639,595 @@
LOG_VERBOSE(LOG_TAG, "%s Sent %d frames per iteration, %d iterations",
__func__, nb_frame_2_send, nb_iterations);
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ snprintf(trace_buf, 32, "btif_media_send_aa_frame:");
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_BEGIN(trace_buf);
+ }
+ #endif
+
+ /* send it */
+
+ #ifdef BT_AUDIO_SYSTRACE_LOG
+ if (PERF_SYSTRACE)
+ {
+ ATRACE_END();
+ }
+ #endif
bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
}
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/*******************************************************************************
+ **
+ ** Function bta_av_co_send_vendor_start
+ **
+ ** Description Send Vendor Specific A2dp START command to controller
+ **
+ ** Returns TRUE if command succeeds, FALSE otherwize
+ **
+ *******************************************************************************/
+
+#define HCI_VSQC_CONTROLLER_A2DP_OPCODE 0x000A
+
+#define VS_QHCI_READ_A2DP_CFG 0x01
+#define VS_QHCI_WRITE_SBC_CFG 0x02
+#define VS_QHCI_WRITE_A2DP_MEDIA_CHANNEL_CFG 0x03
+#define VS_QHCI_START_A2DP_MEDIA 0x04
+#define VS_QHCI_STOP_A2DP_MEDIA 0x05
+#define VS_QHCI_A2DP_WRITE_SUGGESTED_BITRATE 0x06
+#define VS_QHCI_A2DP_TRANSPORT_CONFIGURATION 0x07
+#define VS_QHCI_A2DP_WRITE_SCMS_T_CP 0x08
+#define VS_QHCI_A2DP_SELECTED_CODEC 0x09
+
+#define A2DP_CODEC_SBC 0
+#define A2DP_CODEC_AAC 2
+/* Below type is not defined in spec, it is for our convenience */
+#define A2DP_CODEC_APTX 8
+
+#define A2DP_CODEC_APTX_HD 9
+/* Need to check if we need a different type for APTX low latency
+ * or just we can handle with reducing the MTU updated in media
+ * channel configuration.
+ */
+
+#define A2DP_TRANSPORT_TYPE_SLIMBUS 0
+
+/* Better to match the codec type, for PCM we can use undefined number */
+#define A2DP_TRANSPORT_STREAM_TYPE_PCM 10
+#define A2DP_TRANSPORT_STREAM_TYPE_SBC 0
+#define A2DP_TRANSPORT_STREAM_TYPE_AAC 2
+#define A2DP_TRANSPORT_STREAM_TYPE_APTX 8
+#define A2DP_TRANSPORT_STREAM_TYPE_APTX_HD 9
+
+void disconnect_a2dp_on_vendor_start_failure()
+{
+ bt_bdaddr_t bd_addr;
+ APPL_TRACE_IMP("disconnect_a2dp_on_vendor_start_failure");
+ btif_av_reset_reconfig_flag();
+ btif_av_get_peer_addr(&bd_addr);
+ btif_dispatch_sm_event(BTIF_AV_DISCONNECT_REQ_EVT,(char*)&bd_addr,
+ sizeof(bt_bdaddr_t));
+}
+
+void btif_media_send_reset_vendor_state()
+{
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTIF_MEDIA_RESET_VS_STATE;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+}
+
+void btif_media_start_vendor_command()
+{
+ APPL_TRACE_IMP("btif_media_start_vendor_command_exchange");
+ btif_media_cb.tx_start_initiated = TRUE;
+ btif_media_cb.tx_enc_update_initiated = FALSE;
+
+ if (get_soc_type() == BT_SOC_SMD)
+ {
+ APPL_TRACE_IMP("vs_configs_exchanged:%u", btif_media_cb.vs_configs_exchanged);
+ if(btif_media_cb.vs_configs_exchanged)
+ {
+ btif_media_send_vendor_start();
+ }
+ else
+ {
+ btif_media_send_vendor_write_sbc_cfg();
+ }
+ }
+ else
+ {
+ btif_media_send_vendor_selected_codec();
+ }
+}
+
+void btif_media_on_start_vendor_command()
+{
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTIF_MEDIA_START_VS_CMD;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+}
+
+void btif_media_on_stop_vendor_command()
+{
+ BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+
+ APPL_TRACE_IMP("btif_media_on_stop_vendor_command");
+ p_buf->event = BTIF_MEDIA_STOP_VS_CMD;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+}
+
+void btif_media_a2dp_start_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_START_A2DP_MEDIA sent with error code: %u", status);
+
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+
+ if (!status)
+ p_buf->event = BTIF_MEDIA_VS_A2DP_START_SUCCESS;
+ else
+ p_buf->event = BTIF_MEDIA_VS_A2DP_START_FAILURE;
+
+ if (btif_media_cmd_msg_queue != NULL)
+ {
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Message queue cleaned up");
+ if (!status)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ btif_av_reset_reconfig_flag();
+ }
+}
+
+BOOLEAN btif_media_send_vendor_start()
+{
+ UINT8 param[2];
+
+ APPL_TRACE_IMP("btif_media_send_vendor_start");
+
+ param[0] = VS_QHCI_START_A2DP_MEDIA;
+ param[1] = 0; /*needs to send index for multi A2dp*/
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 2,
+ param, btif_media_a2dp_start_cb);
+}
+
+void btif_media_a2dp_stop_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_STOP_A2DP_MEDIA sent with error code: %u", status);
+
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+
+ if (!status)
+ p_buf->event = BTIF_MEDIA_VS_A2DP_STOP_SUCCESS;
+ else
+ p_buf->event = BTIF_MEDIA_VS_A2DP_STOP_FAILURE;
+
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ {
+ APPL_TRACE_ERROR("Message queue cleaned up");
+ if (!status)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+}
+
+BOOLEAN btif_media_send_vendor_stop()
+{
+ UINT8 param[2];
+
+ APPL_TRACE_IMP("btif_media_send_vendor_stop");
+
+ btif_media_cb.tx_stop_initiated = TRUE;
+
+ param[0] = VS_QHCI_STOP_A2DP_MEDIA;
+ param[1] = 0; /*needs to send index for multi A2dp*/
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 2,
+ param, btif_media_a2dp_stop_cb);
+}
+
+void btif_media_selected_codec_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_A2DP_SELECTED_CODEC sent with error code: %u",
+ status);
+
+ if (!status)
+ {
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTIF_MEDIA_VS_A2DP_SELECTED_CODEC_SUCCESS;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Error in processing Vendor command response");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ disconnect_a2dp_on_vendor_start_failure();
+ }
+}
+
+BOOLEAN btif_media_send_vendor_selected_codec()
+{
+ UINT8 param[12], codec_type = A2DP_CODEC_SBC;
+ UINT16 index = 0;
+
+ codec_type = bta_av_co_get_current_codec();
+ if (codec_type == A2D_NON_A2DP_MEDIA_CT) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ tA2D_APTX_CIE* codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ codec_type = A2DP_CODEC_APTX;
+ else if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ codec_type = A2DP_CODEC_APTX_HD;
+ }
+ }
+
+ APPL_TRACE_IMP("btif_media_send_selected_codec: codec: %d", codec_type);
+ param[index++] = VS_QHCI_A2DP_SELECTED_CODEC;
+ param[index++] = codec_type;
+ param[index++] = 0; //Max Latency
+ param[index++] = 0; //Delay report
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ param[index++] = bta_av_co_cp_is_active();
+#else
+ param[index++] = 0;
+#endif
+ param[index++] = bta_av_co_cp_get_flag();
+ param[index++] = (UINT8)(btif_media_cb.media_feeding.cfg.pcm.sampling_freq & 0xFF);
+ param[index++] = (UINT8)((btif_media_cb.media_feeding.cfg.pcm.sampling_freq >> 8)& 0xFF);
+ if (codec_type == A2DP_CODEC_SBC)
+ {
+ param[index++] = (UINT8)btif_media_cb.encoder.s16NumOfSubBands;
+ param[index++] = (UINT8)btif_media_cb.encoder.s16NumOfBlocks;
+ }
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, index,
+ param, btif_media_selected_codec_cb);
+}
+
+void btif_media_transport_cfg_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_A2DP_TRANSPORT_CFG sent with error code: %u",
+ status);
+
+ if (!status)
+ {
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTIF_MEDIA_VS_A2DP_TRANSPORT_CFG_SUCCESS;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Error in processing Vendor command response");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ disconnect_a2dp_on_vendor_start_failure();
+ }
+}
+BOOLEAN btif_media_send_vendor_transport_cfg()
+{
+ UINT8 param[3];
+ UINT8 codec_type = bta_av_co_get_current_codec();
+ UINT8 stream_type;
+ APPL_TRACE_IMP("btif_media_send_vendor_transport_cfg: codec: %d", codec_type);
+ stream_type = codec_type;
+
+ if (codec_type == A2D_NON_A2DP_MEDIA_CT) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ tA2D_APTX_CIE* codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ stream_type = A2DP_TRANSPORT_STREAM_TYPE_APTX;
+ else if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ stream_type = A2DP_TRANSPORT_STREAM_TYPE_APTX_HD;
+ }
+ }
+
+ param[0] = VS_QHCI_A2DP_TRANSPORT_CONFIGURATION;
+ param[1] = A2DP_TRANSPORT_TYPE_SLIMBUS;
+ param[2] = stream_type;
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 3,
+ param, btif_media_transport_cfg_cb);
+}
+
+void btif_media_a2dp_media_chn_cfg_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_WRITE_A2DP_MEDIA_CHANNEL_CFG sent with error code: %u",
+ status);
+
+ if (!status)
+ {
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTIF_MEDIA_VS_A2DP_MEDIA_CHNL_CFG_SUCCESS;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Error in processing Vendor command response");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ disconnect_a2dp_on_vendor_start_failure();
+ }
+}
+
+BOOLEAN btif_media_send_vendor_media_chn_cfg()
+{
+ UINT8 param[8];
+ bt_bdaddr_t bd_addr;
+ BD_ADDR addr;
+ UINT8 codec_type = A2DP_CODEC_SBC;
+
+ if (btif_av_is_peer_edr() && (btif_av_peer_supports_3mbps() == FALSE)) {
+ // This condition would be satisfied only if the remote device is
+ // EDR and supports only 2 Mbps, but the effective AVDTP MTU size
+ // exceeds the 2DH5 packet size.
+ APPL_TRACE_DEBUG("%s The remote devce is EDR but does not support 3 Mbps", __func__);
+
+ if (btif_media_cb.TxAaMtuSize > MAX_2MBPS_AVDTP_MTU) {
+ APPL_TRACE_WARNING("%s Restricting AVDTP MTU size to %d",
+ __func__, MAX_2MBPS_AVDTP_MTU);
+ btif_media_cb.TxAaMtuSize = MAX_2MBPS_AVDTP_MTU;
+ }
+ }
+
+ codec_type = bta_av_co_get_current_codec();
+ if (codec_type == A2D_NON_A2DP_MEDIA_CT) {
+ UINT8* ptr = bta_av_co_get_current_codecInfo();
+ if (ptr) {
+ tA2D_APTX_CIE* codecInfo = (tA2D_APTX_CIE*) &ptr[BTA_AV_CFG_START_IDX];
+ if (codecInfo && codecInfo->vendorId == A2D_APTX_VENDOR_ID && codecInfo->codecId == A2D_APTX_CODEC_ID_BLUETOOTH)
+ codec_type = A2DP_CODEC_APTX;
+ else if (codecInfo && codecInfo->vendorId == A2D_APTX_HD_VENDOR_ID && codecInfo->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH)
+ codec_type = A2DP_CODEC_APTX_HD;
+ }
+ }
+
+ if ((codec_type == A2DP_CODEC_APTX) || (codec_type == A2DP_CODEC_APTX_HD))
+ {
+ if (btif_media_cb.TxAaMtuSize > MAX_2MBPS_AVDTP_MTU)
+ {
+ APPL_TRACE_IMP("Restricting AVDTP MTU size to 663 for APTx codecs");
+ btif_media_cb.TxAaMtuSize = MAX_2MBPS_AVDTP_MTU;
+ }
+ }
+
+ btif_av_get_peer_addr(&bd_addr);
+ memcpy(addr, bd_addr.address, sizeof(BD_ADDR));
+ UINT16 acl_hdl = BTM_GetHCIConnHandle(addr, BT_TRANSPORT_BR_EDR);
+ APPL_TRACE_IMP("btif_media_send_vendor_media_chn_cfg");
+ APPL_TRACE_IMP("AVDTP mtu: %u, hdl: %u", btif_media_cb.TxAaMtuSize, acl_hdl);
+
+ if ((codec_type == A2DP_CODEC_SBC) && (btif_media_cb.max_bitpool <= BTIF_A2DP_MAX_BITPOOL_MQ))
+ {
+ APPL_TRACE_IMP("Restricting streaming MTU size for MQ Bitpool");
+ btif_media_cb.TxAaMtuSize = MAX_2MBPS_AVDTP_MTU;
+ }
+
+ param[0] = VS_QHCI_WRITE_A2DP_MEDIA_CHANNEL_CFG;
+ param[1] = 0; /*needs to send index for multi A2dp*/
+ param[2] = (UINT8)(acl_hdl & 0x00ff);
+ param[3] = (UINT8)(((acl_hdl & 0xff00) >> 8) & 0x00ff);
+ param[4] = (UINT8)(btif_av_get_streaming_channel_id()& 0x00ff);
+ param[5] = (UINT8)(((btif_av_get_streaming_channel_id() & 0xff00)
+ >> 8) & 0x00ff);
+ param[6] = (UINT8)(btif_media_cb.TxAaMtuSize & 0x00ff);
+ param[7] = (UINT8)(((btif_media_cb.TxAaMtuSize & 0xff00) >> 8) & 0x00ff);
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 8,
+ param, btif_media_a2dp_media_chn_cfg_cb);
+}
+
+void btif_media_a2dp_write_sbc_cfg_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_WRITE_SBC_CFG sent with error code: %u", status);
+
+ if (!status)
+ {
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTIF_MEDIA_VS_A2DP_WRITE_SBC_CFG_SUCCESS;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Error in processing Vendor command response");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ disconnect_a2dp_on_vendor_start_failure();
+ }
+}
+
+BOOLEAN btif_media_send_vendor_write_sbc_cfg()
+{
+ UINT8 param[12];
+ bt_bdaddr_t bd_addr;
+ BD_ADDR addr;
+ btif_av_get_peer_addr(&bd_addr);
+ memcpy(addr, bd_addr.address, sizeof(BD_ADDR));
+ UINT16 acl_hdl = BTM_GetHCIConnHandle(addr, BT_TRANSPORT_BR_EDR);
+ APPL_TRACE_IMP("btif_media_send_vendor_write_sbc_cfg");
+ APPL_TRACE_IMP("acl hdl: %u", acl_hdl);
+ APPL_TRACE_IMP("channel mode: %u", btif_media_cb.encoder.s16ChannelMode);
+ APPL_TRACE_IMP("sampling frequency: %u", btif_media_cb.encoder.s16SamplingFreq);
+ APPL_TRACE_IMP("allocation method: %u", btif_media_cb.encoder.s16AllocationMethod);
+ APPL_TRACE_IMP("subbands: %u", btif_media_cb.encoder.s16NumOfSubBands);
+ APPL_TRACE_IMP("num of blocks: %u", btif_media_cb.encoder.s16NumOfBlocks);
+ APPL_TRACE_IMP("bitpool: <%u>,<%u>", btif_media_cb.min_bitpool, btif_media_cb.max_bitpool);
+ APPL_TRACE_IMP("Scmst flag: %u", bta_av_co_cp_get_flag());
+
+ param[0] = VS_QHCI_WRITE_SBC_CFG;
+ param[1] = (UINT8)((1 << (3 - btif_media_cb.encoder.s16ChannelMode)) |
+ (1 << (7 - btif_media_cb.encoder.s16SamplingFreq)));
+ param[2] = (UINT8)((1 << btif_media_cb.encoder.s16AllocationMethod) |
+ (1 << (3 - (btif_media_cb.encoder.s16NumOfSubBands >> 3))) |
+ (1 << (7 - ((btif_media_cb.encoder.s16NumOfBlocks - 4) >> 2))));
+ param[3] = btif_media_cb.min_bitpool;
+ param[4] = btif_media_cb.max_bitpool;
+ param[5] = 0; // Not in use as latency calculation will now be taken care of in SOC
+ param[6] = 0; // Not in use as latency calculation will now be taken care of in SOC
+ param[7] = 0; // Not in use as latency calculation will now be taken care of in SOC
+ param[8] = 0; // Not in use as latency calculation will now be taken care of in SOC
+ param[9] = 0; // 0 as delayed report not supported
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ param[10] = 1;
+#else
+ param[10] = 0;
+#endif
+ param[11] = bta_av_co_cp_get_flag();
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 12,
+ param, btif_media_a2dp_write_sbc_cfg_cb);
+}
+
+void btif_media_pref_bit_rate_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_A2DP_WRITE_SUGGESTED_BITRATE sent with error code: %u", status);
+
+ if (!status)
+ {
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTIF_MEDIA_VS_A2DP_PREF_BIT_RATE_SUCCESS;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Error in processing Vendor command response");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ disconnect_a2dp_on_vendor_start_failure();
+ }
+}
+
+BOOLEAN btif_media_send_vendor_pref_bit_rate()
+{
+ UINT8 param[3];
+
+ APPL_TRACE_IMP("btif_media_send_vendor_pref_bit_rate: bitrate: %d", btif_media_cb.encoder.u16BitRate);
+
+ param[0] = VS_QHCI_A2DP_WRITE_SUGGESTED_BITRATE;
+ param[1] = (UINT8)(btif_media_cb.encoder.u16BitRate & 0x00ff);
+ param[2] = (UINT8)((btif_media_cb.encoder.u16BitRate & 0xff00) >> 8);
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 3,
+ param, btif_media_pref_bit_rate_cb);
+}
+
+void btif_media_scmst_cb(tBTM_VSC_CMPL *param)
+{
+ unsigned char status = 0;
+ BT_HDR *p_buf;
+
+ if (param->param_len)
+ {
+ status = param->p_param_buf[0];
+ }
+ APPL_TRACE_IMP("VS_QHCI_A2DP_WRITE_SCMS_T_CP sent with error code: %u", status);
+
+ if (!status)
+ {
+ p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTIF_MEDIA_VS_A2DP_SET_SCMST_HDR_SUCCESS;
+ if (btif_media_cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+ else
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ else
+ {
+ APPL_TRACE_ERROR("Error in processing Vendor command response");
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ disconnect_a2dp_on_vendor_start_failure();
+ }
+}
+
+BOOLEAN btif_media_send_vendor_scmst_hdr()
+{
+ UINT8 param[3];
+
+ APPL_TRACE_IMP("btif_media_send_vendor_scmst_hdr");
+
+ param[0] = VS_QHCI_A2DP_WRITE_SCMS_T_CP;
+ param[1] = bta_av_co_cp_get_flag();
+
+ return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 2,
+ param, btif_media_scmst_cb);
+}
+
+#endif
+
#endif /* BTA_AV_INCLUDED == TRUE */
/*******************************************************************************
diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
index 28a2499..1657b13 100644
--- a/btif/src/btif_rc.c
+++ b/btif/src/btif_rc.c
@@ -38,6 +38,7 @@
#include "bta_api.h"
#include "bta_av_api.h"
#include "btif_av.h"
+#include "btif_media.h"
#include "btif_common.h"
#include "btif_util.h"
#include "bt_common.h"
@@ -47,6 +48,7 @@
#include "osi/include/list.h"
#include "osi/include/properties.h"
#include "btu.h"
+#include "stack/sdp/sdpint.h"
#include "log/log.h"
#define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL)
@@ -54,52 +56,139 @@
** Constants & Macros
******************************************************************************/
+/* Support Two RC Handles simultaneously*/
+#define BTIF_RC_NUM_CB 2
+/* Default index*/
+#define BTIF_RC_DEFAULT_INDEX 0
/* cod value for Headsets */
#define COD_AV_HEADSETS 0x0404
/* for AVRC 1.4 need to change this */
#define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
+//#define TEST_BROWSE_RESPONSE
+#define MAX_FOLDER_RSP_SUPPORT 10
-#define IDX_GET_PLAY_STATUS_RSP 0
-#define IDX_LIST_APP_ATTR_RSP 1
-#define IDX_LIST_APP_VALUE_RSP 2
-#define IDX_GET_CURR_APP_VAL_RSP 3
-#define IDX_SET_APP_VAL_RSP 4
-#define IDX_GET_APP_ATTR_TXT_RSP 5
-#define IDX_GET_APP_VAL_TXT_RSP 6
-#define IDX_GET_ELEMENT_ATTR_RSP 7
+#define IDX_GET_PLAY_STATUS_RSP 0
+#define IDX_LIST_APP_ATTR_RSP 1
+#define IDX_LIST_APP_VALUE_RSP 2
+#define IDX_GET_CURR_APP_VAL_RSP 3
+#define IDX_SET_APP_VAL_RSP 4
+#define IDX_GET_APP_ATTR_TXT_RSP 5
+#define IDX_GET_APP_VAL_TXT_RSP 6
+#define IDX_GET_ELEMENT_ATTR_RSP 7
+#define IDX_GET_FOLDER_ITEMS_RSP 8
+#define IDX_SET_FOLDER_ITEM_RSP 9
+#define IDX_SET_ADDRESS_PLAYER_RSP 10
+#define IDX_SET_BROWSE_PLAYER_RSP 11
+#define IDX_CHANGE_PATH_RSP 12
+#define IDX_PLAY_ITEM_RSP 13
+#define IDX_GET_ITEM_ATTR_RSP 14
+#define IDX_GET_TOTAL_ITEMS_RSP 15
#define MAX_VOLUME 128
#define MAX_LABEL 16
#define MAX_TRANSACTIONS_PER_SESSION 16
-#define MAX_CMD_QUEUE_LEN 8
#define PLAY_STATUS_PLAYING 1
+#define MAX_CMD_QUEUE_LEN 16
+#define ERR_PLAYER_NOT_ADDRESED 0x13
+#define BTRC_FEAT_AVRC_UI_UPDATE 0x08
+
+#if (defined(AVCT_COVER_ART_INCLUDED) && (AVCT_COVER_ART_INCLUDED == TRUE))
+#define MAX_ELEM_ATTR_SIZE 8
+#else
+#define MAX_ELEM_ATTR_SIZE 7
+#endif
#define CHECK_RC_CONNECTED \
BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__); \
- if (btif_rc_cb.rc_connected == FALSE) \
- { \
+ int clients; \
+ int conn_status = BT_STATUS_NOT_READY; \
+ for (clients = 0; clients < btif_max_rc_clients; clients++) \
+ { \
+ if ((btif_rc_cb[clients].rc_connected == TRUE)) \
+ conn_status = BT_STATUS_SUCCESS; \
+ } \
+ if(conn_status == BT_STATUS_NOT_READY) \
+ { \
BTIF_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \
- return BT_STATUS_NOT_READY; \
+ return BT_STATUS_NOT_READY; \
}
-#define FILL_PDU_QUEUE(index, ctype, label, pending) \
-{ \
- btif_rc_cb.rc_pdu_info[index].ctype = ctype; \
- btif_rc_cb.rc_pdu_info[index].label = label; \
- btif_rc_cb.rc_pdu_info[index].is_rsp_pending = pending; \
+#define TXN_LABEL_ENQUEUE(handle, label, front, rear, size, item, cmd) \
+{ \
+ if (size == MAX_TRANSACTIONS_PER_SESSION) \
+ { \
+ send_reject_response(handle, item, cmd, AVRC_STS_INTERNAL_ERR); \
+ break; \
+ } \
+ rear = (rear + 1) % MAX_TRANSACTIONS_PER_SESSION; \
+ label[rear] = item; \
+ size = size + 1; \
}
-#define SEND_METAMSG_RSP(index, avrc_rsp) \
+#define TXN_LABEL_DEQUEUE(label, front, rear, size) \
+{ \
+ if (size == 0) \
+ return BT_STATUS_UNHANDLED; \
+ front = (front + 1) % MAX_TRANSACTIONS_PER_SESSION; \
+ size = size - 1; \
+}
+
+#define FILL_PDU_QUEUE(idx, ctype, label, pending, index, cmd) \
{ \
- if (btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \
+ btif_rc_cb[index].rc_pdu_info[idx].ctype[idx] = ctype; \
+ TXN_LABEL_ENQUEUE(btif_rc_cb[index].rc_handle, btif_rc_cb[index].rc_pdu_info[idx].label, \
+ btif_rc_cb[index].rc_pdu_info[idx].front, btif_rc_cb[index].rc_pdu_info[idx].rear, \
+ btif_rc_cb[index].rc_pdu_info[idx].size, label, cmd); \
+ BTIF_TRACE_DEBUG("%s txn label %d enqueued to txn queue of pdu %s, queue size %d \n", \
+ __FUNCTION__, label, dump_rc_pdu(cmd), btif_rc_cb[index].rc_pdu_info[idx].size); \
+ btif_rc_cb[index].rc_pdu_info[idx].is_rsp_pending = pending; \
+}
+
+#define SEND_METAMSG_RSP(idx, avrc_rsp, index) \
+{ \
+ UINT8 curr_label = btif_rc_cb[index].rc_pdu_info[idx].label[ \
+ btif_rc_cb[index].rc_pdu_info[idx].front]; \
+ if(btif_rc_cb[index].rc_pdu_info[idx].is_rsp_pending == FALSE) \
{ \
- BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \
+ BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \
return BT_STATUS_UNHANDLED; \
} \
- send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_pdu_info[index].label, \
- btif_rc_cb.rc_pdu_info[index].ctype, avrc_rsp); \
- btif_rc_cb.rc_pdu_info[index].ctype = 0; \
- btif_rc_cb.rc_pdu_info[index].label = 0; \
- btif_rc_cb.rc_pdu_info[index].is_rsp_pending = FALSE; \
+ TXN_LABEL_DEQUEUE(btif_rc_cb[index].rc_pdu_info[idx].label, \
+ btif_rc_cb[index].rc_pdu_info[idx].front, \
+ btif_rc_cb[index].rc_pdu_info[idx].rear, \
+ btif_rc_cb[index].rc_pdu_info[idx].size); \
+ send_metamsg_rsp(btif_rc_cb[index].rc_handle, curr_label, \
+ btif_rc_cb[index].rc_pdu_info[idx].ctype[idx], avrc_rsp); \
+ BTIF_TRACE_DEBUG("%s txn label %d dequeued from txn queue, queue sz %d \n", __FUNCTION__, \
+ curr_label, btif_rc_cb[index].rc_pdu_info[idx].size); \
+ if (btif_rc_cb[index].rc_pdu_info[idx].size == 0) \
+ { \
+ btif_rc_cb[index].rc_pdu_info[idx].ctype[idx] = 0; \
+ btif_rc_cb[index].rc_pdu_info[idx].is_rsp_pending = FALSE; \
+ } \
+}
+
+#define SEND_BROWSEMSG_RSP(idx , avrc_rsp, index) \
+{ \
+ UINT8 curr_label = btif_rc_cb[index].rc_pdu_info[idx].label[ \
+ btif_rc_cb[index].rc_pdu_info[idx].front]; \
+ if(btif_rc_cb[index].rc_pdu_info[idx].is_rsp_pending == FALSE) \
+ { \
+ BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \
+ return BT_STATUS_UNHANDLED; \
+ } \
+ TXN_LABEL_DEQUEUE(btif_rc_cb[index].rc_pdu_info[idx].label, \
+ btif_rc_cb[index].rc_pdu_info[idx].front, \
+ btif_rc_cb[index].rc_pdu_info[idx].rear, \
+ btif_rc_cb[index].rc_pdu_info[idx].size); \
+ send_browsemsg_rsp(btif_rc_cb[index].rc_handle, curr_label, \
+ btif_rc_cb[index].rc_pdu_info[idx].ctype[idx], avrc_rsp); \
+ BTIF_TRACE_DEBUG("%s txn label %d dequeued from txn queue, queue sz %d \n", __FUNCTION__, \
+ curr_label, btif_rc_cb[index].rc_pdu_info[idx].size); \
+ if (btif_rc_cb[index].rc_pdu_info[idx].size == 0) \
+ { \
+ btif_rc_cb[index].rc_pdu_info[idx].ctype[idx] = 0; \
+ btif_rc_cb[index].rc_pdu_info[idx].is_rsp_pending = FALSE; \
+ } \
}
/*****************************************************************************
@@ -112,8 +201,11 @@
typedef struct
{
- UINT8 label;
- UINT8 ctype;
+ int front;
+ int rear;
+ int size;
+ UINT8 label[MAX_TRANSACTIONS_PER_SESSION];
+ UINT8 ctype[MAX_TRANSACTIONS_PER_SESSION];
BOOLEAN is_rsp_pending;
} btif_rc_cmd_ctxt_t;
@@ -183,6 +275,7 @@
BOOLEAN rc_features_processed;
UINT64 rc_playing_uid;
BOOLEAN rc_procedure_complete;
+ BOOLEAN rc_play_processed;
} btif_rc_cb_t;
typedef struct {
@@ -197,14 +290,17 @@
{
pthread_mutex_t lbllock;
rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
+ BOOLEAN lbllock_destroyed;
} rc_device_t;
rc_device_t device;
#define MAX_UINPUT_PATHS 3
+static int btif_max_rc_clients = 1;
static const char* uinput_dev_path[] =
{"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput" };
static int uinput_fd = -1;
+static BD_ADDR bd_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static int send_event (int fd, uint16_t type, uint16_t code, int32_t value);
static void send_key (int fd, uint16_t key, int pressed);
@@ -236,7 +332,7 @@
static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label,
tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp);
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void register_volumechange(UINT8 label);
+static void register_volumechange(UINT8 label, int index);
#endif
static void lbl_init();
static void lbl_destroy();
@@ -265,7 +361,6 @@
static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ELEM_ATTRS_RSP *p_rsp);
static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_RSP *p_rsp);
static bt_status_t get_play_status_cmd(void);
-static bt_status_t get_player_app_setting_attr_text_cmd (UINT8 *attrs, UINT8 num_attrs);
static bt_status_t get_player_app_setting_value_text_cmd (UINT8 *vals, UINT8 num_vals);
static bt_status_t register_notification_cmd (UINT8 label, UINT8 event_id, UINT32 event_value);
static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids);
@@ -274,30 +369,51 @@
static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id);
static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids);
#endif
-static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label);
-#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
-static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label);
-#endif
static void rc_start_play_status_timer(void);
static bool absolute_volume_disabled(void);
+static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label,
+ int index);
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label,
+ int index);
+#endif
+static bt_status_t set_addrplayer_rsp(btrc_status_t status_code, bt_bdaddr_t *bd_addr);
+static int btif_rc_get_idx_by_addr(BD_ADDR address);
+
+/*Added for Browsing Message Response */
+static void send_browsemsg_rsp (UINT8 rc_handle, UINT8 label,
+ tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp);
+
static char const* key_id_to_str(uint16_t id);
/*****************************************************************************
** Static variables
******************************************************************************/
-static btif_rc_cb_t btif_rc_cb;
+/* Two RC CBs needed to handle two connections*/
+static btif_rc_cb_t btif_rc_cb[BTIF_RC_NUM_CB];
static btrc_callbacks_t *bt_rc_callbacks = NULL;
static btrc_ctrl_callbacks_t *bt_rc_ctrl_callbacks = NULL;
/*****************************************************************************
** Static functions
******************************************************************************/
+static UINT8 btif_rc_get_idx_by_rc_handle(UINT8 rc_handle);
/*****************************************************************************
** Externs
******************************************************************************/
extern BOOLEAN btif_hf_call_terminated_recently();
extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
+extern void btif_get_latest_playing_device(BD_ADDR address); //get the Playing device address
+extern BOOLEAN btif_av_is_playing();
+extern BOOLEAN btif_av_is_device_connected(BD_ADDR address);
+extern void btif_av_trigger_dual_handoff(BOOLEAN handoff, BD_ADDR address);
+extern BOOLEAN btif_hf_is_call_vr_idle();
+extern BOOLEAN btif_av_is_current_device(BD_ADDR address);
+extern UINT16 btif_av_get_num_connected_devices(void);
+extern UINT16 btif_av_get_num_playing_devices(void);
+extern BOOLEAN btif_av_is_offload_supported();
+extern UINT8 btif_av_idx_by_bdaddr(BD_ADDR bd_addr);
extern fixed_queue_t *btu_general_alarm_queue;
@@ -370,7 +486,7 @@
}
memset(&dev, 0, sizeof(dev));
if (name)
- strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE-1);
+ strlcpy(dev.name, name, UINPUT_MAX_NAME_SIZE-1);
dev.id.bustype = BUS_BLUETOOTH;
dev.id.vendor = 0x0000;
@@ -397,6 +513,8 @@
close(fd);
return -1;
}
+ BTIF_TRACE_IMP("AVRCP: input device opened.. Delay 30 ms");
+ sleep_ms(30);
return fd;
}
@@ -405,19 +523,27 @@
char *name = "AVRCP";
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
- uinput_fd = uinput_create(name);
- if (uinput_fd < 0) {
- BTIF_TRACE_ERROR("%s AVRCP: Failed to initialize uinput for %s (%d)",
- __FUNCTION__, name, uinput_fd);
- } else {
- BTIF_TRACE_DEBUG("%s AVRCP: Initialized uinput for %s (fd=%d)",
- __FUNCTION__, name, uinput_fd);
+ if (uinput_fd < 0)
+ {
+ BTIF_TRACE_DEBUG("Create Uinput device");
+ uinput_fd = uinput_create(name);
+ if (uinput_fd < 0) {
+ BTIF_TRACE_ERROR("%s AVRCP: Failed to initialize uinput for %s (%d)",
+ __FUNCTION__, name, uinput_fd);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s AVRCP: Initialized uinput for %s (fd=%d)",
+ __FUNCTION__, name, uinput_fd);
+ }
}
return uinput_fd;
}
void close_uinput (void)
{
+ //Dont close uinput untill all connections are teared down
+ // Since we support Dual AVRCP conn now.
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
if (uinput_fd > 0) {
ioctl(uinput_fd, UI_DEV_DESTROY);
@@ -427,6 +553,7 @@
}
}
+
#if (AVRC_CTLR_INCLUDED == TRUE)
void rc_cleanup_sent_cmd (void *p_data)
{
@@ -434,119 +561,280 @@
}
-void handle_rc_ctrl_features(BD_ADDR bd_addr)
+void handle_rc_ctrl_features(int index)
{
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
- ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)||
+ ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL)))
{
bt_bdaddr_t rc_addr;
int rc_features = 0;
- bdcpy(rc_addr.address,bd_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT))
{
rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
}
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_VENDOR)&&
- (btif_rc_cb.rc_features_processed != TRUE))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_METADATA)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_VENDOR)&&
+ (btif_rc_cb[index].rc_features_processed != TRUE))
{
rc_features |= BTRC_FEAT_METADATA;
/* Mark rc features processed to avoid repeating
* the AVRCP procedure every time on receiving this
* update.
*/
- btif_rc_cb.rc_features_processed = TRUE;
-
- if (btif_av_is_sink_enabled())
+ if ((btif_rc_cb[index].rc_features_processed == FALSE) &&
+ btif_av_is_sink_enabled())
+ {
+ btif_rc_cb[index].rc_features_processed = TRUE;
getcapabilities_cmd (AVRC_CAP_COMPANY_ID);
+ }
}
BTIF_TRACE_DEBUG("%s Update rc features to CTRL %d", __FUNCTION__, rc_features);
- HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+ if (btif_av_is_sink_enabled()) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+ }
}
}
#endif
-void handle_rc_features(BD_ADDR bd_addr)
+void handle_rc_features(int index)
{
if (bt_rc_callbacks != NULL)
{
- btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
- bt_bdaddr_t rc_addr;
+ btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
+ bt_bdaddr_t rc_addr;
+ bt_bdaddr_t avdtp_addr;
+ bdstr_t addr1, addr2;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- bt_bdaddr_t avdtp_addr = btif_av_get_addr();
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ avdtp_addr = btif_av_get_addr(btif_rc_cb[index].rc_addr);
- bdstr_t addr1, addr2;
- BTIF_TRACE_DEBUG("%s: AVDTP Address: %s AVCTP address: %s", __func__,
- bdaddr_to_string(&avdtp_addr, addr1, sizeof(addr1)),
- bdaddr_to_string(&rc_addr, addr2, sizeof(addr2)));
+ BTIF_TRACE_DEBUG("AVDTP Address : %s AVCTP address: %s",
+ bdaddr_to_string(&avdtp_addr, addr1, sizeof(bdstr_t)),
+ bdaddr_to_string(&rc_addr, addr2, sizeof(bdstr_t)) );
- if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr)
- || absolute_volume_disabled()
- || bdcmp(avdtp_addr.address, rc_addr.address))
- btif_rc_cb.rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+ if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, (bt_bdaddr_t *)&rc_addr)
+ || absolute_volume_disabled()
+ || bdcmp(avdtp_addr.address, rc_addr.address))
+ btif_rc_cb[index].rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_BROWSE)
- {
- rc_features |= BTRC_FEAT_BROWSE;
- }
-
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_BROWSE)
+ {
+ rc_features |= BTRC_FEAT_BROWSE;
+ }
+ if ( (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG))
+ {
+ rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+ }
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_METADATA)
+ {
+ rc_features |= BTRC_FEAT_METADATA;
+ }
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_AVRC_UI_UPDATE)
+ {
+ rc_features |= BTRC_FEAT_AVRC_UI_UPDATE;
+ }
+ BTIF_TRACE_IMP("%s: rc_features=0x%x", __FUNCTION__, rc_features);
+ if (btif_rc_cb[index].rc_connected)
+ {
+ BTIF_TRACE_IMP("%s: update App on supported features", __FUNCTION__);
+ HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
+ }
+ else
+ {
+ BTIF_TRACE_IMP("%s: skipping feature update to App", __FUNCTION__);
+ }
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- if ( (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL) &&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG))
- {
- rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
- }
-#endif
-
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)
- {
- rc_features |= BTRC_FEAT_METADATA;
- }
-
- BTIF_TRACE_DEBUG("%s: rc_features=0x%x", __FUNCTION__, rc_features);
- HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
-
-#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- BTIF_TRACE_DEBUG("%s Checking for feature flags in btif_rc_handler with label %d",
- __FUNCTION__, btif_rc_cb.rc_vol_label);
- // Register for volume change on connect
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL &&
- btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
- {
- rc_transaction_t *p_transaction=NULL;
- bt_status_t status = BT_STATUS_NOT_READY;
- if (MAX_LABEL==btif_rc_cb.rc_vol_label)
- {
- status=get_transaction(&p_transaction);
- }
- else
- {
- p_transaction=get_transaction_by_lbl(btif_rc_cb.rc_vol_label);
- if (NULL!=p_transaction)
+ BTIF_TRACE_DEBUG("Checking for feature flags in btif_rc_handler with label %d",
+ btif_rc_cb[index].rc_vol_label);
+ // Register for volume change on connect
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL &&
+ btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
+ {
+ rc_transaction_t *p_transaction=NULL;
+ bt_status_t status = BT_STATUS_NOT_READY;
+ if (MAX_LABEL == btif_rc_cb[index].rc_vol_label)
{
- BTIF_TRACE_DEBUG("%s register_volumechange already in progress for label %d",
- __FUNCTION__, btif_rc_cb.rc_vol_label);
- return;
+ status=get_transaction(&p_transaction);
}
else
- status=get_transaction(&p_transaction);
- }
+ {
+ p_transaction=get_transaction_by_lbl(btif_rc_cb[index].rc_vol_label);
+ if (NULL != p_transaction)
+ {
+ BTIF_TRACE_DEBUG("register_volumechange already in progress for label %d",
+ btif_rc_cb[index].rc_vol_label);
+ return;
+ }
+ else
+ status = get_transaction(&p_transaction);
+ }
- if (BT_STATUS_SUCCESS == status && NULL!=p_transaction)
- {
- btif_rc_cb.rc_vol_label=p_transaction->lbl;
- register_volumechange(btif_rc_cb.rc_vol_label);
- }
- }
+ if (BT_STATUS_SUCCESS == status && NULL!=p_transaction)
+ {
+ btif_rc_cb[index].rc_vol_label=p_transaction->lbl;
+ register_volumechange(btif_rc_cb[index].rc_vol_label, index);
+ }
+ }
#endif
}
}
/***************************************************************************
+ * Function btif_rc_init_txn_label_queue
+ *
+ * - Argument: index of rc control block
+ *
+ * - Description: initializes the txn label queues for the rc index
+ *
+ ***************************************************************************/
+void btif_rc_init_txn_label_queue(int index)
+{
+ int j;
+ for (j = 0; j < MAX_CMD_QUEUE_LEN; j++)
+ {
+ btif_rc_cb[index].rc_pdu_info[j].front = 0;
+ btif_rc_cb[index].rc_pdu_info[j].size = 0;
+ btif_rc_cb[index].rc_pdu_info[j].rear = MAX_TRANSACTIONS_PER_SESSION - 1;
+ }
+}
+
+/***************************************************************************
+ * Function btif_rc_get_connection_state
+ *
+ * - Argument: none
+ *
+ * - Description: Return true if any RC is in connected state
+ *
+ ***************************************************************************/
+static BOOLEAN btif_rc_get_connection_state()
+{
+ int clients;
+
+ for (clients = 0; clients < btif_max_rc_clients; clients++)
+ {
+ if (btif_rc_cb[clients].rc_connected == TRUE)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/***************************************************************************
+ * Function btif_rc_get_valid_idx
+ *
+ * - Argument: none
+ *
+ * - Description: Gets the index which is ready for new connection
+ *
+ ***************************************************************************/
+static int btif_rc_get_valid_idx()
+{
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (!(btif_rc_cb[i].rc_connected))
+ break;
+ }
+ return i;
+}
+
+/***************************************************************************
+ * Function btif_rc_get_idx_by_rc_handle
+ *
+ * - Argument: rc handle
+ *
+ * - Description: Gets the RC handle index of matching handle
+ *
+ ***************************************************************************/
+static UINT8 btif_rc_get_idx_by_rc_handle(UINT8 rc_handle)
+{
+ UINT8 i;
+
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_handle == rc_handle)
+ break;
+ }
+ return i;
+}
+
+/* Get the address of device on which PLAY command came
+* This address will be used in AV IF layer to determine
+* On which device to START playback. */
+/***************************************************************************
+ * Function btif_rc_get_playing_device
+ *
+ * - Argument: bd_addr
+ *
+ * - Description: Copies the BD address of current playing device
+ *
+ ***************************************************************************/
+void btif_rc_get_playing_device(BD_ADDR address)
+{
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_play_processed)
+ {
+ //copy bd address
+ bdcpy(address, btif_rc_cb[i].rc_addr);
+ }
+ }
+}
+
+/* Reset the Play trigger, once the AVDTP START is
+* sent, called from AV IF layer. */
+/***************************************************************************
+ * Function btif_rc_clear_playing_state
+ *
+ * - Argument: BOOLEAN
+ *
+ * - Description: Clears the PLAY processed.rc_play_processed denotes
+ * play command has been processed for this device.
+ *
+ ***************************************************************************/
+void btif_rc_clear_playing_state(BOOLEAN state)
+{
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_play_processed)
+ {
+ btif_rc_cb[i].rc_play_processed = state;
+ }
+ }
+}
+
+/***************************************************************************
+ * Function btif_rc_clear_priority
+ *
+ * - Argument: Device address
+ *
+ * - Description: Clears the priority information for the device
+ * This can be used while AV disconnection for the device.
+ * Setting of rc_play_processed flag could have been avoided
+ * looking at the stream state, but it might still leave some
+ * corner case of audio suspending just before the play takes
+ * effect.
+ ***************************************************************************/
+void btif_rc_clear_priority(BD_ADDR address)
+{
+ int index;
+
+ index = btif_rc_get_idx_by_addr(address);
+ if(index < btif_max_rc_clients)
+ {
+ btif_rc_cb[index].rc_play_processed = FALSE;
+ }
+}
+
+/***************************************************************************
* Function handle_rc_connect
*
* - Argument: tBTA_AV_RC_OPEN RC open data structure
@@ -556,73 +844,77 @@
***************************************************************************/
void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
{
- BTIF_TRACE_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle);
+ BTIF_TRACE_IMP("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle);
bt_status_t result = BT_STATUS_SUCCESS;
-#if (AVRC_CTLR_INCLUDED == TRUE)
bt_bdaddr_t rc_addr;
-#endif
-
- if (p_rc_open->status == BTA_AV_SUCCESS)
+ int index;
+ if(p_rc_open->status == BTA_AV_SUCCESS)
{
- //check if already some RC is connected
- if (btif_rc_cb.rc_connected)
+ //Check if already some RC is connected
+ /*Now we can have two RC connections
+ * Check should be here about 3rd connection too.
+ * Get the free or MAX index. Max index should be rejected. */
+ index = btif_rc_get_valid_idx();
+ if (index == btif_max_rc_clients)
{
- BTIF_TRACE_ERROR("%s Got RC OPEN in connected state, Connected RC: %d \
- and Current RC: %d", __FUNCTION__, btif_rc_cb.rc_handle,p_rc_open->rc_handle );
- if ((btif_rc_cb.rc_handle != p_rc_open->rc_handle)
- && (bdcmp(btif_rc_cb.rc_addr, p_rc_open->peer_addr)))
- {
- BTIF_TRACE_DEBUG("%s Got RC connected for some other handle", __FUNCTION__);
- BTA_AvCloseRc(p_rc_open->rc_handle);
- return;
- }
+ /*Reached Max, this connection must be rejected*/
+ BTIF_TRACE_ERROR("RC OPEN in MAX connected state");
+ BTA_AvCloseRc(p_rc_open->rc_handle);
+ return;
}
- memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
- btif_rc_cb.rc_features = p_rc_open->peer_features;
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
+ /*Use the index for this RC connection*/
+ BTIF_TRACE_DEBUG("Got RC OPEN on the index= %d", index);
+ memcpy(btif_rc_cb[index].rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+ btif_rc_cb[index].rc_features = p_rc_open->peer_features;
+ btif_rc_cb[index].rc_vol_label = MAX_LABEL;
+ btif_rc_cb[index].rc_volume = MAX_VOLUME;
+ btif_rc_cb[index].rc_connected = TRUE;
+ btif_rc_cb[index].rc_handle = p_rc_open->rc_handle;
+ btif_rc_init_txn_label_queue(index);
- btif_rc_cb.rc_connected = TRUE;
- btif_rc_cb.rc_handle = p_rc_open->rc_handle;
-
- /* on locally initiated connection we will get remote features as part of connect */
- if (btif_rc_cb.rc_features != 0)
- handle_rc_features(btif_rc_cb.rc_addr);
if (bt_rc_callbacks)
{
result = uinput_driver_check();
- if (result == BT_STATUS_SUCCESS)
+ if(result == BT_STATUS_SUCCESS)
{
init_uinput();
}
}
else
{
- BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not initializing UInput",
- __FUNCTION__);
+ BTIF_TRACE_WARNING("Avrcp TG role not enabled, not initializing UInput");
}
- BTIF_TRACE_DEBUG("%s handle_rc_connect features %d ",__FUNCTION__, btif_rc_cb.rc_features);
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT)
+ {
+ HAL_CBACK(bt_rc_callbacks, connection_state_cb, TRUE, &rc_addr);
+ }
+ /* on locally initiated connection we will get remote features as part of connect */
+ if (btif_rc_cb[index].rc_features != 0)
+ handle_rc_features(index);
+ BTIF_TRACE_DEBUG(" handle_rc_connect features %d ",btif_rc_cb[index].rc_features);
#if (AVRC_CTLR_INCLUDED == TRUE)
- btif_rc_cb.rc_playing_uid = RC_INVALID_TRACK_ID;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ btif_rc_cb[index].rc_playing_uid = RC_INVALID_TRACK_ID;
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
if (bt_rc_ctrl_callbacks != NULL)
{
HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &rc_addr);
}
/* report connection state if remote device is AVRCP target */
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
- ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)||
+ ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCCT)&&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL)))
{
- handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+ handle_rc_ctrl_features(index);
}
#endif
+ /* on locally initiated connection we will get remote features as part of connect
+ Delay this update till connection update reaches Apps*/
}
else
{
BTIF_TRACE_ERROR("%s Connect failed with error code: %d",
__FUNCTION__, p_rc_open->status);
- btif_rc_cb.rc_connected = FALSE;
}
}
@@ -636,52 +928,52 @@
***************************************************************************/
void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
{
-#if (AVRC_CTLR_INCLUDED == TRUE)
bt_bdaddr_t rc_addr;
tBTA_AV_FEAT features;
-#endif
- BTIF_TRACE_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle);
- if ((p_rc_close->rc_handle != btif_rc_cb.rc_handle)
- && (bdcmp(btif_rc_cb.rc_addr, p_rc_close->peer_addr)))
+ UINT8 index;
+ BOOLEAN is_connected = 0;
+
+ BTIF_TRACE_IMP("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle);
+
+ index = btif_rc_get_idx_by_rc_handle(p_rc_close->rc_handle);
+ if (index == btif_max_rc_clients)
{
BTIF_TRACE_ERROR("Got disconnect of unknown device");
return;
}
-#if (AVRC_CTLR_INCLUDED == TRUE)
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- features = btif_rc_cb.rc_features;
- /* Clean up AVRCP procedure flags */
- memset(&btif_rc_cb.rc_app_settings, 0,
- sizeof(btif_rc_player_app_settings_t));
- btif_rc_cb.rc_features_processed = FALSE;
- btif_rc_cb.rc_procedure_complete = FALSE;
- rc_stop_play_status_timer();
- /* Check and clear the notification event list */
- if (btif_rc_cb.rc_supported_event_list != NULL)
+ if ((p_rc_close->rc_handle != btif_rc_cb[index].rc_handle)
+ && (bdcmp(btif_rc_cb[index].rc_addr, p_rc_close->peer_addr)))
{
- list_clear(btif_rc_cb.rc_supported_event_list);
- btif_rc_cb.rc_supported_event_list = NULL;
+ BTIF_TRACE_ERROR("Got disconnect of unknown device");
+ return;
}
-#endif
- btif_rc_cb.rc_handle = 0;
- btif_rc_cb.rc_connected = FALSE;
- memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
- memset(btif_rc_cb.rc_notif, 0, sizeof(btif_rc_cb.rc_notif));
+ btif_rc_cb[index].rc_handle = BTIF_RC_HANDLE_NONE;
+ btif_rc_cb[index].rc_connected = FALSE;
+ bdcpy(rc_addr.address, btif_rc_cb[index].rc_addr);
+ memset(btif_rc_cb[index].rc_addr, 0, sizeof(BD_ADDR));
+ memset(btif_rc_cb[index].rc_notif, 0, sizeof(btif_rc_cb[index].rc_notif));
+ features = btif_rc_cb[index].rc_features;
+ btif_rc_cb[index].rc_features = 0;
+ btif_rc_cb[index].rc_vol_label = MAX_LABEL;
+ btif_rc_cb[index].rc_volume = MAX_VOLUME;
+ btif_rc_cb[index].rc_play_processed = FALSE;
+ btif_rc_cb[index].rc_pending_play = FALSE;
+ btif_rc_init_txn_label_queue(index);
- btif_rc_cb.rc_features = 0;
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
- init_all_transactions();
- if (bt_rc_callbacks != NULL)
+ //CLose Uinput only when all RCs are disconnected
+ is_connected = btif_rc_get_connection_state();
+ BTIF_TRACE_DEBUG("RC connected : %d", is_connected);
+ if (is_connected != TRUE && device.lbllock_destroyed != TRUE)
{
+ BTIF_TRACE_DEBUG("Clear UINPUT and transactions when zero RC left");
+ init_all_transactions();
close_uinput();
}
- else
+ if (!bdcmp(bd_null, rc_addr.address))
{
- BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not closing UInput", __FUNCTION__);
+ BTIF_TRACE_DEBUG("Cleanup already done");
+ return;
}
-
- memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
#if (AVRC_CTLR_INCLUDED == TRUE)
/* report connection state if device is AVRCP target */
if (bt_rc_ctrl_callbacks != NULL)
@@ -689,6 +981,10 @@
HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr);
}
#endif
+ if (features & BTA_AV_FEAT_RCCT)
+ {
+ HAL_CBACK(bt_rc_callbacks, connection_state_cb, FALSE, &rc_addr);
+ }
}
/***************************************************************************
@@ -700,11 +996,88 @@
* - Description: Remote control command handler
*
***************************************************************************/
+
+/* Rules: Only currenlty playing device's Passthrough commands
+* will be entertained.
+* While playing on Dev 1, if Dev2 sends Play, just respond it
+* without passing it to APP and in parallel start a protocol
+* suspend/pause the playback on DEV1 and Start on DEV2
+* Making sure that music is not paused and transfer happens seamless. */
void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
{
const char *status;
int pressed, i;
+ UINT8 index;
+ BD_ADDR address;
+ bt_bdaddr_t remote_address;
+ BOOLEAN ignore_play_processed = FALSE;
+ if (p_remote_cmd == NULL)
+ return;
+
+ index = btif_rc_get_idx_by_rc_handle(p_remote_cmd->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("Passthrough on invalid index");
+ return;
+ }
+ /* Multicast: Passthru command on AVRCP only device when connected
+ * to other A2DP devices, ignore it.
+ */
+ if (btif_av_is_connected() && !btif_av_is_device_connected(btif_rc_cb[index].rc_addr))
+ {
+ BTIF_TRACE_ERROR("Passthrough on AVRCP only device: Ignore..");
+ return;
+ }
+
+ /* Trigger DUAL Handoff when support single streaming */
+ if (btif_av_is_playing() &&
+ (btif_av_get_multicast_state() == FALSE))
+ {
+ /*compare the bd addr of current playing dev and this dev*/
+ btif_get_latest_playing_device(address);
+ if (bdcmp(btif_rc_cb[index].rc_addr, address) == 0)
+ {
+ APPL_TRACE_WARNING("Passthrough on the playing device");
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) &&
+ (p_remote_cmd->key_state == AVRC_STATE_PRESS))
+ {
+ APPL_TRACE_WARNING("Play again");
+ ignore_play_processed = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("Passthrough command on other device");
+ if (p_remote_cmd->rc_id == BTA_AV_RC_PLAY)
+ {
+ if (btif_av_is_device_connected(btif_rc_cb[index].rc_addr))
+ {
+ /* Trigger suspend on currently playing device
+ * Allow the Play to be sent to Music player to
+ * address Play during Pause(Local/DUT initiated)
+ * but SUSPEND not triggered by Audio module.
+ */
+ if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
+ {
+ BTIF_TRACE_DEBUG("Trigger dual handoff for this play command");
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ btif_av_trigger_dual_handoff(TRUE, btif_rc_cb[index].rc_addr);
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("%s: Command Invalid on %d", __FUNCTION__, index);
+ return;
+ }
+ }
+ else
+ {
+ APPL_TRACE_WARNING("%s:Ignore all Passthrough on %d", __FUNCTION__, index);
+ return;
+ }
+ }
+ }
BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id=%d", __FUNCTION__, p_remote_cmd->rc_id);
/* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */
@@ -716,15 +1089,15 @@
if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
{
APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command", __FUNCTION__);
- btif_rc_cb.rc_pending_play = TRUE;
+ btif_rc_cb[index].rc_pending_play = TRUE;
}
return;
}
- if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play))
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb[index].rc_pending_play))
{
APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received", __FUNCTION__);
- btif_rc_cb.rc_pending_play = FALSE;
+ btif_rc_cb[index].rc_pending_play = FALSE;
return;
}
if ((p_remote_cmd->rc_id == BTA_AV_RC_VOL_UP)||(p_remote_cmd->rc_id == BTA_AV_RC_VOL_DOWN))
@@ -736,20 +1109,35 @@
APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd",__FUNCTION__);
return;
}
+ if(!btif_av_is_connected())
+ {
+ APPL_TRACE_WARNING("%s: AVDT not open, discarding pass-through command: %d",
+ __FUNCTION__, p_remote_cmd->rc_id);
+ return;
+ }
if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) {
status = "released";
pressed = 0;
- } else {
+ }
+ else
+ {
status = "pressed";
pressed = 1;
}
if (p_remote_cmd->rc_id == BTA_AV_RC_FAST_FOR || p_remote_cmd->rc_id == BTA_AV_RC_REWIND) {
- HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed);
+ bdcpy(remote_address.address, btif_rc_cb[index].rc_addr);
+ HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed, &remote_address);
return;
}
-
+ /*Update the device on which PLAY is issued*/
+ if (p_remote_cmd->rc_id == BTA_AV_RC_PLAY)
+ {
+ BTIF_TRACE_DEBUG("PLAY command on the Index: = %d", index);
+ if (p_remote_cmd->key_state == AVRC_STATE_PRESS && !ignore_play_processed)
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ }
for (i = 0; key_map[i].name != NULL; i++) {
if (p_remote_cmd->rc_id == key_map[i].avrcp) {
BTIF_TRACE_DEBUG("%s: %s %s", __FUNCTION__, key_map[i].name, status);
@@ -780,8 +1168,37 @@
}
if (key_map[i].name == NULL)
+ {
BTIF_TRACE_ERROR("%s AVRCP: unknown button 0x%02X %s", __FUNCTION__,
p_remote_cmd->rc_id, status);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s AVRCP:send passthrough cmd = %s to BT Apps ",
+ __FUNCTION__, key_map[i].name);
+ bdcpy(remote_address.address, btif_rc_cb[index].rc_addr);
+ HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed, &remote_address);
+ }
+}
+
+/***************************************************************************
+ * Function btif_rc_send_pause_command
+ *
+ * - Argument: None
+ *
+ * - Description: Sends PAUSE key event to Upper layer.
+ *
+ ***************************************************************************/
+void btif_rc_send_pause_command()
+{
+ int rc_id;
+
+ rc_id = BTA_AV_RC_PAUSE;
+ BTIF_TRACE_DEBUG("Send Pause to music if playing is remotely disconnected");
+
+ send_key(uinput_fd, KEY_PAUSECD, 1);
+ sleep_ms(30); // 30ms
+ send_key(uinput_fd, KEY_PAUSECD, 0);
}
/***************************************************************************
@@ -796,7 +1213,8 @@
{
#if (AVRC_CTLR_INCLUDED == TRUE)
const char *status;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ int index = BTIF_RC_DEFAULT_INDEX; // 0th index is RC
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
int key_state;
if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
@@ -839,7 +1257,8 @@
#if (AVRC_CTLR_INCLUDED == TRUE)
const char *status;
UINT8 vendor_id = 0;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ int index = BTIF_RC_DEFAULT_INDEX; // 0th index is RC
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
int key_state;
if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
@@ -903,6 +1322,15 @@
UINT8 scratch_buf[512] = {0};
tAVRC_COMMAND avrc_command = {0};
tAVRC_STS status;
+ UINT8 index;
+
+ //Get the index of RC
+ index = btif_rc_get_idx_by_rc_handle(pmeta_msg->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
BTIF_TRACE_EVENT("+ %s", __FUNCTION__);
@@ -964,8 +1392,8 @@
UINT8 event_id = avrc_command.reg_notif.event_id;
BTIF_TRACE_EVENT("%s:New register notification received.event_id:%s,label:0x%x,code:%x",
__FUNCTION__,dump_rc_notification_event_id(event_id), pmeta_msg->label,pmeta_msg->code);
- btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE;
- btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label;
+ btif_rc_cb[index].rc_notif[event_id-1].bNotify = TRUE;
+ btif_rc_cb[index].rc_notif[event_id-1].label = pmeta_msg->label;
if (event_id == AVRC_EVT_UIDS_CHANGE)
{
@@ -982,10 +1410,306 @@
*btif context, no context switching is required. Invoke
* btif_rc_upstreams_evt directly from here. */
btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command, pmeta_msg->code,
- pmeta_msg->label);
+ pmeta_msg->label, index);
}
}
+/************************************************************************************
+* Function handle_get_folder_item_mediaplyerlist_cmd
+*
+* - Argument: tBTA_AV_BROWSE_MSG structure containing the received
+* browse message
+* tAVRC_COMMAND structure containing the commands
+* to be updated
+* UINT8 event, variable having value of event.
+*
+* - Description: Handler for get media player list command
+*
+************************************************************************************/
+UINT8 handle_get_folder_item_mediaplyerlist_cmd (tBTA_AV_BROWSE_MSG *pbrowse_msg,
+ tAVRC_COMMAND *cmd, UINT8 *event)
+{
+ UINT8 *p_length, *start_item, *end_item;
+ UINT8 length, xx;
+ *event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd->get_items.pdu = *event;
+ //Check length
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_length);
+ if (length < 10)
+ {
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d",length);
+ return TRUE;
+ }
+ else
+ {
+ start_item = &pbrowse_msg->p_msg->browse.p_browse_data[4];
+ BE_STREAM_TO_UINT32(cmd->get_items.start_item ,start_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.start_item);
+ end_item = &pbrowse_msg->p_msg->browse.p_browse_data[8];
+ BE_STREAM_TO_UINT32(cmd->get_items.end_item,end_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.end_item);
+ cmd->get_items.attr_count = 0xff; /* in MediaPlayerList we don't have attr_id */
+ //Update OPCODE
+ cmd->get_items.opcode = AVRC_OP_BROWSE;
+ cmd->get_items.scope = pbrowse_msg->p_msg->browse.p_browse_data[3] ;
+ cmd->get_items.status = AVRC_STS_NO_ERROR ;
+ for (xx = 0; xx < MAX_ELEM_ATTR_SIZE ; xx++)
+ {
+ cmd->get_items.attrs[xx] = 0;
+ }
+ return FALSE;
+ }
+}
+
+/************************************************************************************
+* Function handle_get_folder_item_filesystem_cmd
+*
+* - Argument: tBTA_AV_BROWSE_MSG structure containing the received
+* browse message
+* tAVRC_COMMAND structure containing the commands
+* to be updated
+* UINT8 event, variable having value of event.
+*
+* - Description: Handler for get folder item command
+*
+************************************************************************************/
+UINT8 handle_get_folder_item_filesystem_cmd (tBTA_AV_BROWSE_MSG *pbrowse_msg, tAVRC_COMMAND *cmd,
+ UINT8 *event)
+{
+ UINT8 *p_length, *start_item, *end_item, *p_data;
+ UINT8 length, attr_count = 0, xx;
+ *event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd->get_items.pdu = *event;
+ //Check length
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_length);
+ attr_count = pbrowse_msg->p_msg->browse.p_browse_data[12];
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: attr_count: =%d", attr_count);
+ switch (attr_count)
+ {
+ case 0xff:
+ if (length != 10)
+ {
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d", length);
+ return TRUE;
+ }
+ break;
+ default:
+ if (length != ((attr_count * 4) + 10))
+ {
+ BTIF_TRACE_ERROR("GET_FOLDER_ITEMS: length error: =%d", length);
+ return TRUE;
+ }
+ }
+
+ start_item = &pbrowse_msg->p_msg->browse.p_browse_data[4];
+ BE_STREAM_TO_UINT32(cmd->get_items.start_item ,start_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.start_item);
+ end_item = &pbrowse_msg->p_msg->browse.p_browse_data[8];
+ BE_STREAM_TO_UINT32(cmd->get_items.end_item,end_item);
+ BTIF_TRACE_EVENT("pbrowse_msg start_item :%x",cmd->get_items.end_item);
+ cmd->get_items.attr_count = attr_count;
+ if (attr_count == 0)
+ {
+ for (xx = 0; xx < MAX_ELEM_ATTR_SIZE; xx++)
+ {
+ cmd->get_items.attrs[xx] = xx + 1;
+ }
+ }
+ else if (attr_count == 0xff) /* no attribute requested */
+ {
+ BTIF_TRACE_DEBUG("No attribute requested");
+ }
+ else if (attr_count <= AVRC_MAX_ELEM_ATTR_SIZE)
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[13];
+ for (xx = 0; xx < attr_count; xx++)
+ BE_STREAM_TO_UINT32(cmd->get_items.attrs[xx], p_data)
+ }
+ //Update OPCODE
+ cmd->get_items.opcode = AVRC_OP_BROWSE;
+ cmd->get_items.scope = pbrowse_msg->p_msg->browse.p_browse_data[3] ;
+ cmd->get_items.status = AVRC_STS_NO_ERROR ;
+ return FALSE;
+}
+
+/************************************************************************************
+* Function handle_rc_browsemsg_cmd
+*
+* - Argument: tBTA_AV_BROWSE_MSG structure containing the recieved
+* browse message
+*
+* - Description: Remote Control browse message handler
+*
+************************************************************************************/
+void handle_rc_browsemsg_cmd (tBTA_AV_BROWSE_MSG *pbrowse_msg)
+{
+ UINT8 event;
+ UINT16 length;
+ tAVRC_COMMAND cmd;
+ UINT8 *p_length, *p_data;
+ tAVRC_RESPONSE avrc_rsp;
+ UINT8 dropmsg = TRUE;
+ UINT8 index = btif_rc_get_idx_by_rc_handle(pbrowse_msg->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
+
+ BTIF_TRACE_EVENT("+ %s", __FUNCTION__);
+ BTIF_TRACE_EVENT("pbrowse_msg PDU_ID :%x",pbrowse_msg->p_msg->browse.p_browse_data[0]);
+ BTIF_TRACE_EVENT("pbrowse_msg length :%x",pbrowse_msg->p_msg->browse.browse_len);
+ switch(pbrowse_msg->p_msg->browse.p_browse_data[0])
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ {
+ UINT8 scope = pbrowse_msg->p_msg->browse.p_browse_data[3];
+ switch (scope)
+ {
+ case AVRC_SCOPE_PLAYER_LIST:
+ dropmsg = handle_get_folder_item_mediaplyerlist_cmd(pbrowse_msg, &cmd, &event);
+ break;
+ case AVRC_SCOPE_FILE_SYSTEM:
+ case AVRC_SCOPE_NOW_PLAYING:
+ dropmsg = handle_get_folder_item_filesystem_cmd(pbrowse_msg, &cmd, &event);
+ break;
+ }
+ if (dropmsg == FALSE)
+ {
+ btif_rc_upstreams_evt(event,&cmd,0,pbrowse_msg->label, index);
+ }
+ }
+ break;
+
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd.br_player.pdu = event;
+ //Check for length
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_length);
+ if (length != 0x0002)
+ {
+ BTIF_TRACE_ERROR("SET_BROWSED_PLAYERlength error: = %d", length);
+ }
+ else
+ {
+ p_length = &pbrowse_msg->p_msg->browse.p_browse_data[3];
+ BE_STREAM_TO_UINT16(cmd.br_player.player_id, p_length);
+ cmd.br_player.opcode = AVRC_OP_BROWSE;
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
+ dropmsg = FALSE;
+ }
+ break;
+
+ case AVRC_PDU_CHANGE_PATH:
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd.chg_path.pdu = event;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_data);
+ if (length != 11)
+ {
+ BTIF_TRACE_ERROR("CHANGE_PATH length error: = %d",length);
+ }
+ else
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[3];
+ BE_STREAM_TO_UINT16(cmd.chg_path.uid_counter, p_data);
+ cmd.chg_path.direction = pbrowse_msg->p_msg->browse.p_browse_data[5];
+ cmd.chg_path.opcode = AVRC_OP_BROWSE;
+ cmd.chg_path.status = AVRC_STS_NO_ERROR;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[6];
+ BE_STREAM_TO_UINT64(cmd.chg_path.folder_uid, p_data);
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
+ dropmsg = FALSE;
+ }
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ {
+ UINT16 packet_len;
+ UINT8 num_attr, idx;
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0] ;
+ cmd.get_attrs.pdu = event;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(packet_len, p_data);
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[14];
+ BE_STREAM_TO_UINT8(num_attr, p_data);
+ if (packet_len != ((num_attr * 4) + 12))
+ {
+ BTIF_TRACE_ERROR("Get Item Attributes length error: = %d",packet_len);
+ }
+ else
+ {
+ cmd.get_attrs.status = AVRC_STS_NO_ERROR;
+ cmd.get_attrs.opcode = AVRC_OP_BROWSE;
+ cmd.get_attrs.scope = pbrowse_msg->p_msg->browse.p_browse_data[3];
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[4];
+ BE_STREAM_TO_UINT64(cmd.get_attrs.uid, p_data);
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[12];
+ BE_STREAM_TO_UINT16(cmd.get_attrs.uid_counter, p_data);
+ cmd.get_attrs.attr_count = num_attr;
+ if (num_attr == 0)
+ {
+ /* remote requested all Attribute ID*/
+ for (idx = 0; idx < MAX_ELEM_ATTR_SIZE; idx++)
+ {
+ cmd.get_attrs.attrs[idx] = idx + 1;
+ }
+ }
+ else
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[15];
+ BTIF_TRACE_ERROR("GetItemAttr num_attr: = %d", cmd.get_attrs.attr_count);
+ for (idx = 0; idx < num_attr ; idx++)
+ {
+ BE_STREAM_TO_UINT32(cmd.get_attrs.attrs[idx], p_data);
+ BTIF_TRACE_ERROR("GetItemAttr attrid: = %d", cmd.get_attrs.attrs[idx]);
+ }
+ }
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
+ dropmsg = FALSE;
+ }
+ }
+ break;
+
+ case AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS:
+ event = pbrowse_msg->p_msg->browse.p_browse_data[0];
+ cmd.get_tot_item.pdu = event;
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[1];
+ BE_STREAM_TO_UINT16(length, p_data);
+ if (length != 1)
+ {
+ BTIF_TRACE_ERROR("GET_TOTAL_ITEMS length error: = %d", length);
+ }
+ else
+ {
+ p_data = &pbrowse_msg->p_msg->browse.p_browse_data[3];
+ BE_STREAM_TO_UINT8(cmd.get_tot_item.scope, p_data);
+ cmd.get_tot_item.opcode = AVRC_OP_BROWSE;
+ cmd.get_tot_item.status = AVRC_STS_NO_ERROR;
+ btif_rc_upstreams_evt(event, &cmd, 0, pbrowse_msg->label, index);
+ dropmsg = FALSE;
+ }
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("pbrowse_msg ERROR");
+ break;
+ }
+ if (dropmsg == TRUE)
+ {
+ avrc_rsp.rsp.pdu = pbrowse_msg->p_msg->browse.p_browse_data[0];
+ avrc_rsp.rsp.status = AVRC_STS_BAD_CMD;
+ avrc_rsp.rsp.opcode = AVRC_OP_BROWSE;
+ BTIF_TRACE_ERROR("handle_rc_browsemsg_cmd: pbrowse_msg ERROR: %x", avrc_rsp.rsp.pdu);
+ send_browsemsg_rsp(btif_rc_cb[index].rc_handle, pbrowse_msg->label, 0, &avrc_rsp);
+ }
+
+}
+
+
/***************************************************************************
**
** Function btif_rc_handler
@@ -995,9 +1719,24 @@
***************************************************************************/
void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
{
- BTIF_TRACE_DEBUG ("%s event:%s", __FUNCTION__, dump_rc_event(event));
+ UINT8 index;
+
+ BTIF_TRACE_IMP ("%s event:%s", __FUNCTION__, dump_rc_event(event));
switch (event)
{
+ case BTIF_AV_CLEANUP_REQ_EVT:
+ {
+ memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
+ close_uinput();
+
+ if (bt_rc_callbacks)
+ {
+ bt_rc_callbacks = NULL;
+ }
+
+ lbl_destroy();
+ }break;
+
case BTA_AV_RC_OPEN_EVT:
{
BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_open.peer_features);
@@ -1011,28 +1750,13 @@
case BTA_AV_REMOTE_CMD_EVT:
{
- if (bt_rc_callbacks != NULL)
- {
- BTIF_TRACE_DEBUG("%s rc_id:0x%x key_state:%d",
- __FUNCTION__, p_data->remote_cmd.rc_id,
+ BTIF_TRACE_DEBUG("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
p_data->remote_cmd.key_state);
- /** In race conditions just after 2nd AVRCP is connected
- * remote might send pass through commands, so check for
- * Rc handle before processing pass through commands
- **/
- if (btif_rc_cb.rc_handle == p_data->remote_cmd.rc_handle)
- {
- handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
- }
- else
- {
- BTIF_TRACE_DEBUG("%s Pass-through command for Invalid rc handle", __FUNCTION__);
- }
- }
- else
- {
- BTIF_TRACE_ERROR("AVRCP TG role not up, drop passthrough commands");
- }
+ /** In race conditions just after 2nd AVRCP is connected
+ * remote might send pass through commands, so check for
+ * Rc handle before processing pass through commands
+ **/
+ handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
}
break;
@@ -1055,13 +1779,20 @@
#endif
case BTA_AV_RC_FEAT_EVT:
{
- BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_feat.peer_features);
- btif_rc_cb.rc_features = p_data->rc_feat.peer_features;
- handle_rc_features(p_data->rc_feat.peer_addr);
-#if (AVRC_CTLR_INCLUDED == TRUE)
- if ((btif_rc_cb.rc_connected) && (bt_rc_ctrl_callbacks != NULL))
+ BTIF_TRACE_DEBUG("Peer_features:%x on RC handle: %d", p_data->rc_feat.peer_features,
+ p_data->rc_feat.rc_handle);
+ index = btif_rc_get_idx_by_rc_handle(p_data->rc_feat.rc_handle);
+ if (index == btif_max_rc_clients)
{
- handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+ BTIF_TRACE_ERROR("%s: Invalid RC index for BTA_AV_RC_FEAT_EVT", __FUNCTION__);
+ return;
+ }
+ btif_rc_cb[index].rc_features = p_data->rc_feat.peer_features;
+ handle_rc_features(index);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ if ((btif_rc_cb[index].rc_connected == TRUE) && (bt_rc_ctrl_callbacks != NULL))
+ {
+ handle_rc_ctrl_features(index);
}
#endif
}
@@ -1114,10 +1845,17 @@
else
{
BTIF_TRACE_ERROR("Neither CTRL, nor TG is up, drop meta commands");
+ osi_free(p_data->meta_msg.p_msg);
}
}
break;
-
+ case BTA_AV_BROWSE_MSG_EVT:
+ {
+ BTIF_TRACE_DEBUG("BTA_AV_BROWSE_MSG_EVT label:%d handle:%d", p_data->browse_msg.label,
+ p_data->browse_msg.rc_handle);
+ handle_rc_browsemsg_cmd(&(p_data->browse_msg));
+ }
+ break;
default:
BTIF_TRACE_DEBUG("%s Unhandled RC event : 0x%x", __FUNCTION__, event);
}
@@ -1132,13 +1870,37 @@
***************************************************************************/
BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr)
{
- if (btif_rc_cb.rc_connected == TRUE) {
- bdcpy(peer_addr, btif_rc_cb.rc_addr);
- return TRUE;
+ /*Find the device for which AV is not connected but RC is.*/
+ int i;
+
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (btif_rc_cb[i].rc_connected == TRUE)
+ {
+ if (!btif_av_is_device_connected(btif_rc_cb[i].rc_addr))
+ {
+ bdcpy(peer_addr, btif_rc_cb[i].rc_addr);
+ return TRUE;
+ }
+ }
}
return FALSE;
}
+static int btif_rc_get_idx_by_addr(BD_ADDR address)
+{
+ int i;
+
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if (bdcmp(btif_rc_cb[i].rc_addr, address) == 0)
+ {
+ break;
+ }
+ }
+ return i;
+}
+
/***************************************************************************
**
** Function btif_rc_get_connected_peer_handle
@@ -1146,9 +1908,18 @@
** Description Fetches the connected headset's handle if any
**
***************************************************************************/
-UINT8 btif_rc_get_connected_peer_handle(void)
+UINT8 btif_rc_get_connected_peer_handle(BD_ADDR peer_addr)
{
- return btif_rc_cb.rc_handle;
+ int i;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ if ((btif_rc_cb[i].rc_connected == TRUE)
+ &&(!bdcmp(peer_addr,btif_rc_cb[i].rc_addr)))
+ {
+ return btif_rc_cb[i].rc_handle;
+ }
+ }
+ return BTIF_RC_HANDLE_NONE;
}
/***************************************************************************
@@ -1162,10 +1933,17 @@
/* clear the queued PLAY command. if bSend is TRUE, forward to app */
void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp)
{
+ int index = btif_rc_get_idx_by_addr(peer_addr);
+
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
UNUSED(peer_addr);
BTIF_TRACE_DEBUG("%s: bSendToApp=%d", __FUNCTION__, bSendToApp);
- if (btif_rc_cb.rc_pending_play)
+ if (btif_rc_cb[index].rc_pending_play)
{
if (bSendToApp)
{
@@ -1173,7 +1951,7 @@
APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __FUNCTION__);
memset (&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD));
- remote_cmd.rc_handle = btif_rc_cb.rc_handle;
+ remote_cmd.rc_handle = btif_rc_cb[index].rc_handle;
remote_cmd.rc_id = AVRC_ID_PLAY;
remote_cmd.hdr.ctype = AVRC_CMD_CTRL;
remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU;
@@ -1192,7 +1970,7 @@
remote_cmd.key_state = AVRC_STATE_RELEASE;
handle_rc_passthrough_cmd( &remote_cmd );
}
- btif_rc_cb.rc_pending_play = FALSE;
+ btif_rc_cb[index].rc_pending_play = FALSE;
}
}
@@ -1232,7 +2010,14 @@
tAVRC_RESPONSE *pmetamsg_resp)
{
UINT8 ctype;
+ UINT8 index;
+ index = btif_rc_get_idx_by_rc_handle(rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: Invalid RC index", __FUNCTION__);
+ return;
+ }
if (!pmetamsg_resp)
{
BTIF_TRACE_WARNING("%s: Invalid response received from application", __FUNCTION__);
@@ -1274,24 +2059,24 @@
{
BOOLEAN bSent = FALSE;
UINT8 event_id = pmetamsg_resp->reg_notif.event_id;
- BOOLEAN bNotify = (btif_rc_cb.rc_connected) && (btif_rc_cb.rc_notif[event_id-1].bNotify);
+ BOOLEAN bNotify = (btif_rc_cb[index].rc_connected) && (btif_rc_cb[index].rc_notif[event_id-1].bNotify);
/* de-register this notification for a CHANGED response */
- btif_rc_cb.rc_notif[event_id-1].bNotify = FALSE;
+ btif_rc_cb[index].rc_notif[event_id-1].bNotify = FALSE;
BTIF_TRACE_DEBUG("%s rc_handle: %d. event_id: 0x%02d bNotify:%u", __FUNCTION__,
- btif_rc_cb.rc_handle, event_id, bNotify);
+ btif_rc_cb[index].rc_handle, event_id, bNotify);
if (bNotify)
{
BT_HDR *p_msg = NULL;
tAVRC_STS status;
- if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb.rc_handle,
+ if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb[index].rc_handle,
pmetamsg_resp, &p_msg)) )
{
BTIF_TRACE_DEBUG("%s Sending notification to rc_handle: %d. event_id: 0x%02d",
- __FUNCTION__, btif_rc_cb.rc_handle, event_id);
+ __FUNCTION__, btif_rc_cb[index].rc_handle, event_id);
bSent = TRUE;
- BTA_AvMetaRsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
+ BTA_AvMetaRsp(btif_rc_cb[index].rc_handle, btif_rc_cb[index].rc_notif[event_id-1].label,
ctype, p_msg);
}
else
@@ -1348,6 +2133,68 @@
return opcode;
}
+/****************************************************************************
+* Function send_browsemsg_rsp
+*
+* Arguments - rc_handle RC handle corresponding to the connected RC
+* label Label of the RC response
+* code Response type---->Not needed for Browsing
+* pmetamsg_resp Vendor response
+*
+* Description - Remote control browse Message Rsp
+*
+*******************************************************************************/
+static void send_browsemsg_rsp (UINT8 rc_handle, UINT8 label, tBTA_AV_CODE code,
+ tAVRC_RESPONSE *pbrowsemsg_resp)
+{
+ tAVRC_STS status;
+ BT_HDR *p_msg = NULL;
+
+ if (!pbrowsemsg_resp)
+ {
+ BTIF_TRACE_WARNING("%s: Invalid response received from application", __FUNCTION__);
+ return;
+ }
+
+ BTIF_TRACE_EVENT("+%s:rc_handle: %d, label: %d, code: 0x%02x, pdu: %s", __FUNCTION__,\
+ rc_handle, label, code, dump_rc_pdu(pbrowsemsg_resp->rsp.pdu));
+ if (pbrowsemsg_resp->rsp.status != AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_ERROR("send_browsemsg_rsp **Error**");
+ }
+ /*Browse Command and Response structure are different
+ *as comapared to Meta data response ,opcode and c-type
+ *not part of browse response hence handling browse response
+ *in seprate function
+ */
+ status = AVRC_BldBrowseResponse(rc_handle, pbrowsemsg_resp, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ BTA_AvMetaRsp(rc_handle, label, 0, p_msg);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build metamsg response. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+}
+
+/****************************************************************************
+* Function app_sendbrowsemsg
+*
+* Arguments - index Of array stored while recieving command
+* avrc_rsp Avrcp response from application
+*
+* Description - Send Browse message
+*
+*******************************************************************************/
+int app_sendbrowsemsg(UINT8 index ,tAVRC_RESPONSE *avrc_rsp, int rc_index)
+{
+ SEND_BROWSEMSG_RSP(index ,avrc_rsp, rc_index);
+ return 0;
+}
+
+
/*******************************************************************************
**
** Function btif_rc_upstreams_evt
@@ -1357,41 +2204,169 @@
** Returns void
**
*******************************************************************************/
-static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 ctype, UINT8 label)
+static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 ctype, UINT8 label,
+ int index)
{
- BTIF_TRACE_EVENT("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__,
- dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle, ctype, label);
+ bt_bdaddr_t remote_addr;
+ BD_ADDR address;
+ bdcpy(remote_addr.address, btif_rc_cb[index].rc_addr);
+ BTIF_TRACE_IMP("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__,
+ dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb[index].rc_handle, ctype, label);
+
+ if (interop_match_addr(INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS,
+ (bt_bdaddr_t *) &remote_addr))
+ {
+ if (event == AVRC_PDU_LIST_PLAYER_APP_ATTR || event == AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT ||
+ event == AVRC_PDU_GET_CUR_PLAYER_APP_VALUE || event == AVRC_PDU_SET_PLAYER_APP_VALUE ||
+ event == AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT || event == AVRC_PDU_LIST_PLAYER_APP_VALUES)
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
+ BTIF_TRACE_DEBUG("Blacklisted CK send AVRC_PDU_LIST_PLAYER_APP_ATTR reject");
+ return;
+ }
+ if ((pavrc_cmd->reg_notif.event_id == BTRC_EVT_APP_SETTINGS_CHANGED) &&
+ (event == AVRC_PDU_REGISTER_NOTIFICATION))
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
+ btif_rc_cb[index].rc_notif[BTRC_EVT_APP_SETTINGS_CHANGED - 1].bNotify = FALSE;
+ BTIF_TRACE_DEBUG("Blacklisted CK send BTRC_EVT_APP_SETTINGS_CHANGED not implemented");
+ return;
+ }
+ }
switch (event)
{
case AVRC_PDU_GET_PLAY_STATUS:
{
- FILL_PDU_QUEUE(IDX_GET_PLAY_STATUS_RSP, ctype, label, TRUE)
- HAL_CBACK(bt_rc_callbacks, get_play_status_cb);
+ BTIF_TRACE_DEBUG("AVRC_PDU_GET_PLAY_STATUS ");
+ FILL_PDU_QUEUE(IDX_GET_PLAY_STATUS_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, get_play_status_cb, &remote_addr);
}
break;
case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ {
+ BTIF_TRACE_DEBUG("AVRC_PDU_LIST_PLAYER_APP_ATTR ");
+ FILL_PDU_QUEUE(IDX_LIST_APP_ATTR_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, list_player_app_attr_cb, &remote_addr);
+ }
+ break;
case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ {
+ BTIF_TRACE_DEBUG("AVRC_PDU_LIST_PLAYER_APP_VALUES =%d" ,pavrc_cmd->list_app_values.attr_id);
+ if (pavrc_cmd->list_app_values.attr_id == 0)
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
+ break;
+ }
+ FILL_PDU_QUEUE(IDX_LIST_APP_VALUE_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, list_player_app_values_cb,
+ pavrc_cmd->list_app_values.attr_id,
+ &remote_addr);
+ }
+ break;
case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ {
+ btrc_player_attr_t player_attr[MAX_ELEM_ATTR_SIZE];
+ UINT8 player_attr_num;
+ BTIF_TRACE_DEBUG("PLAYER_APP_VALUE PDU 0x13 = %d",pavrc_cmd->get_cur_app_val.num_attr);
+ if ((pavrc_cmd->get_cur_app_val.num_attr == 0) ||
+ (pavrc_cmd->get_cur_app_val.num_attr > MAX_ELEM_ATTR_SIZE))
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
+ break;
+ }
+ memset( player_attr, 0, sizeof(player_attr));
+ for (player_attr_num = 0 ; player_attr_num < pavrc_cmd->get_cur_app_val.num_attr;
+ ++player_attr_num)
+ {
+ player_attr[player_attr_num] = pavrc_cmd->get_cur_app_val.attrs[player_attr_num];
+ }
+ FILL_PDU_QUEUE(IDX_GET_CURR_APP_VAL_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, get_player_app_value_cb ,
+ pavrc_cmd->get_cur_app_val.num_attr, player_attr, &remote_addr);
+ }
+ break;
case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ {
+ btrc_player_settings_t attr;
+ UINT8 count;
+ if ((pavrc_cmd->set_app_val.num_val== 0) ||
+ (pavrc_cmd->set_app_val.num_val > MAX_ELEM_ATTR_SIZE))
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label,
+ pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ break;
+ }
+ else
+ {
+ for(count = 0; count < pavrc_cmd->set_app_val.num_val ; ++count)
+ {
+ attr.attr_ids[count] = pavrc_cmd->set_app_val.p_vals[count].attr_id ;
+ attr.attr_values[count]= pavrc_cmd->set_app_val.p_vals[count].attr_val;
+ }
+ attr.num_attr = pavrc_cmd->set_app_val.num_val ;
+ FILL_PDU_QUEUE(IDX_SET_APP_VAL_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, set_player_app_value_cb, &attr, &remote_addr);
+ }
+ }
+ break;
case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ {
+ btrc_player_attr_t player_attr_txt [MAX_ELEM_ATTR_SIZE];
+ UINT8 count_txt = 0 ;
+ if ((pavrc_cmd->get_app_attr_txt.num_attr == 0) ||
+ (pavrc_cmd->get_app_attr_txt.num_attr > MAX_ELEM_ATTR_SIZE))
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ }
+ else
+ {
+ for (count_txt = 0;count_txt < pavrc_cmd->get_app_attr_txt.num_attr ; ++count_txt)
+ {
+ player_attr_txt[count_txt] = pavrc_cmd->get_app_attr_txt.attrs[count_txt];
+ }
+ FILL_PDU_QUEUE(IDX_GET_APP_ATTR_TXT_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, get_player_app_attrs_text_cb,
+ pavrc_cmd->get_app_attr_txt.num_attr, player_attr_txt, &remote_addr);
+ }
+ }
+ break;
case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
{
- /* TODO: Add support for Application Settings */
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_CMD);
+ if (pavrc_cmd->get_app_val_txt.attr_id == 0 ||
+ pavrc_cmd->get_app_val_txt.attr_id > AVRC_PLAYER_VAL_GROUP_REPEAT)
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ break;
+ }
+ if (pavrc_cmd->get_app_val_txt.num_val == 0)
+ {
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ }
+ else
+ {
+ FILL_PDU_QUEUE(IDX_GET_APP_VAL_TXT_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu)
+ HAL_CBACK(bt_rc_callbacks, get_player_app_values_text_cb,
+ pavrc_cmd->get_app_val_txt.attr_id, pavrc_cmd->get_app_val_txt.num_val,
+ pavrc_cmd->get_app_val_txt.vals, &remote_addr);
+ }
}
break;
case AVRC_PDU_GET_ELEMENT_ATTR:
{
- btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ btrc_media_attr_t element_attrs[MAX_ELEM_ATTR_SIZE];
UINT8 num_attr;
- memset(&element_attrs, 0, sizeof(element_attrs));
+ memset(&element_attrs, 0, sizeof(element_attrs));
if (pavrc_cmd->get_elem_attrs.num_attr == 0)
{
/* CT requests for all attributes */
int attr_cnt;
- num_attr = BTRC_MAX_ELEM_ATTR_SIZE;
- for (attr_cnt = 0; attr_cnt < BTRC_MAX_ELEM_ATTR_SIZE; attr_cnt++)
+ num_attr = MAX_ELEM_ATTR_SIZE;
+ for (attr_cnt = 0; attr_cnt < MAX_ELEM_ATTR_SIZE; attr_cnt++)
{
element_attrs[attr_cnt] = attr_cnt + 1;
}
@@ -1399,7 +2374,7 @@
else if (pavrc_cmd->get_elem_attrs.num_attr == 0xFF)
{
/* 0xff indicates, no attributes requested - reject */
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
AVRC_STS_BAD_PARAM);
return;
}
@@ -1433,8 +2408,19 @@
}
}
}
- FILL_PDU_QUEUE(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, TRUE);
- HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs);
+#if (defined(AVCT_COVER_ART_INCLUDED) && (AVCT_COVER_ART_INCLUDED == TRUE))
+ int ver = AVRC_REV_INVALID;
+ ver = sdp_get_stored_avrc_tg_version (remote_addr.address);
+ if ((!(btif_rc_cb[index].rc_features & BTA_AV_FEAT_CA)) ||
+ (ver < AVRC_REV_1_6) || (ver == AVRC_REV_INVALID))
+ {
+ BTIF_TRACE_IMP("remove the cover art elem attribute if remote doesn't support avrcp1.6");
+ if(num_attr == MAX_ELEM_ATTR_SIZE)
+ num_attr--;
+ }
+#endif
+ FILL_PDU_QUEUE(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu);
+ HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs, &remote_addr);
}
break;
case AVRC_PDU_REGISTER_NOTIFICATION:
@@ -1444,34 +2430,227 @@
{
BTIF_TRACE_WARNING("%s Device registering position changed with illegal param 0.",
__FUNCTION__);
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM);
/* de-register this notification for a rejected response */
- btif_rc_cb.rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = FALSE;
+ btif_rc_cb[index].rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = FALSE;
return;
}
HAL_CBACK(bt_rc_callbacks, register_notification_cb, pavrc_cmd->reg_notif.event_id,
- pavrc_cmd->reg_notif.param);
+ pavrc_cmd->reg_notif.param, &remote_addr);
}
break;
case AVRC_PDU_INFORM_DISPLAY_CHARSET:
{
tAVRC_RESPONSE avrc_rsp;
BTIF_TRACE_EVENT("%s() AVRC_PDU_INFORM_DISPLAY_CHARSET", __FUNCTION__);
- if (btif_rc_cb.rc_connected == TRUE)
+ if(btif_rc_cb[index].rc_connected == TRUE)
{
memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
avrc_rsp.inform_charset.opcode=opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
avrc_rsp.inform_charset.pdu=AVRC_PDU_INFORM_DISPLAY_CHARSET;
avrc_rsp.inform_charset.status=AVRC_STS_NO_ERROR;
- send_metamsg_rsp(btif_rc_cb.rc_handle, label, ctype, &avrc_rsp);
+ send_metamsg_rsp(btif_rc_cb[index].rc_handle, label, ctype, &avrc_rsp);
+ }
+ }
+ break;
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_SET_ADDRESSED_PLAYER", __FUNCTION__);
+ FILL_PDU_QUEUE(IDX_SET_ADDRESS_PLAYER_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu);
+ if (!btif_hf_is_call_vr_idle())
+ {
+ set_addrplayer_rsp(ERR_PLAYER_NOT_ADDRESED, &remote_addr); // send reject if call is in progress
+ return;
+ }
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ HAL_CBACK(bt_rc_callbacks, set_addrplayer_cb, pavrc_cmd->addr_player.player_id, &remote_addr);
+ }
+ }
+ break;
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ {
+ btrc_getfolderitem_t getfolder;
+ btrc_browse_folderitem_t scope;
+ UINT8 idx, numAttr;
+ BTIF_TRACE_EVENT("%s()AVRC_PDU_GET_FOLDER_ITEMS", __FUNCTION__);
+ FILL_PDU_QUEUE(IDX_GET_FOLDER_ITEMS_RSP,ctype, label, TRUE, index, pavrc_cmd->pdu);
+ BTIF_TRACE_EVENT("rc_connected: %d",btif_rc_cb[index].rc_connected);
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ getfolder.start_item = pavrc_cmd->get_items.start_item;
+ getfolder.end_item = pavrc_cmd->get_items.end_item;
+ getfolder.size = AVCT_GetBrowseMtu(btif_rc_cb[index].rc_handle);
+ getfolder.attr_count = pavrc_cmd->get_items.attr_count;
+ scope = (btrc_browse_folderitem_t)pavrc_cmd->get_items.scope;
+ if (getfolder.attr_count == 255)
+ {
+ numAttr = 0;
+ }
+ else
+ {
+ if (getfolder.attr_count == 0)
+ {
+ numAttr = MAX_ELEM_ATTR_SIZE;
+ for (idx = 0; idx < MAX_ELEM_ATTR_SIZE; idx++)
+ {
+ getfolder.attrs[idx] = idx + 1;
+ }
+ }
+ else
+ {
+ numAttr = getfolder.attr_count;
+ for (idx = 0; idx < numAttr; idx++)
+ {
+ getfolder.attrs[idx] = pavrc_cmd->get_items.attrs[idx];
+ BTIF_TRACE_ERROR("getfolder[%d] = %d", idx, getfolder.\
+ attrs[idx]);
+ BTIF_TRACE_ERROR("pavrc_cmd->get_items.attrs[%d] = %d",\
+ idx, pavrc_cmd->get_items.attrs[idx]);
+ }
+ }
+ }
+ HAL_CBACK(bt_rc_callbacks, get_folderitems_cb, scope, &getfolder, &remote_addr);
+ }
+ }
+ break;
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_SET_BROWSED_PLAYER", __FUNCTION__);
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_SET_BROWSE_PLAYER_RSP, ctype, label, TRUE, index,
+ pavrc_cmd->pdu);
+ HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb, pavrc_cmd->br_player.player_id, &remote_addr);
+ }
+ }
+ break;
+ case AVRC_PDU_CHANGE_PATH:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_CHANGE_PATH", __FUNCTION__);
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_CHANGE_PATH_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu);
+ HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction, \
+ pavrc_cmd->chg_path.folder_uid, &remote_addr);
+ }
+ }
+ break;
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ {
+ UINT8 num_attr = pavrc_cmd->get_attrs.attr_count;
+ UINT8 idx, num_attr_requested = 0;
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_GET_ITEM_ATTRIBUTES", __FUNCTION__);
+ btrc_media_attr_t element_attrs[MAX_ELEM_ATTR_SIZE];
+ memset(&element_attrs, 0, sizeof(element_attrs));
+ if (num_attr == 0)
+ {
+ /* CT requests for all attributes */
+ for (idx = 0; idx < MAX_ELEM_ATTR_SIZE; idx++)
+ {
+ element_attrs[idx] = idx + 1;
+ }
+ num_attr_requested = MAX_ELEM_ATTR_SIZE; /* get all */
+ }
+ else if (num_attr == 0xFF)
+ {
+ /* 0xff indicates, no attributes requested - reject */
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM);
+ return;
+ }
+ else
+ {
+ /* Attribute IDs from 1 to MAX_ELEM_ATTR_SIZE are only valid,
+ * hence HAL definition limits the attributes to BTRC_MAX_ELEM_ATTR_SIZE.
+ * Fill only valid entries.
+ */
+ for (idx = 0; (idx < num_attr) && (num_attr <= MAX_ELEM_ATTR_SIZE); idx++)
+ {
+ if ((pavrc_cmd->get_attrs.attrs[idx] > 0) &&
+ (pavrc_cmd->get_attrs.attrs[idx] <= MAX_ELEM_ATTR_SIZE))
+ {
+ element_attrs[idx] = pavrc_cmd->get_attrs.attrs[idx];
+ BTIF_TRACE_ERROR("element_attrs[%d]: %d", idx, element_attrs[idx]);
+ }
+ }
+ num_attr_requested = idx;
+ BTIF_TRACE_ERROR("num_attr_requested: %d", num_attr_requested);
+ }
+#if (defined(AVCT_COVER_ART_INCLUDED) && (AVCT_COVER_ART_INCLUDED == TRUE))
+ int ver = AVRC_REV_INVALID;
+ ver = sdp_get_stored_avrc_tg_version (remote_addr.address);
+ if ((!(btif_rc_cb[index].rc_features & BTA_AV_FEAT_CA)) ||
+ (ver < AVRC_REV_1_6) || (ver == AVRC_REV_INVALID))
+ {
+ BTIF_TRACE_IMP("remove the cover art elem attribute if remote doesn't support avrcp1.6");
+ if(num_attr_requested == MAX_ELEM_ATTR_SIZE)
+ num_attr_requested--;
+ }
+#endif
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_GET_ITEM_ATTR_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu);
+ HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, pavrc_cmd->get_attrs.scope,
+ pavrc_cmd->get_attrs.uid, num_attr_requested, element_attrs,
+ AVCT_GetBrowseMtu(btif_rc_cb[index].rc_handle), &remote_addr);
+ }
+ }
+ break;
+ case AVRC_PDU_PLAY_ITEM:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_PLAY_ITEM", __FUNCTION__);
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_PLAY_ITEM_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu);
+ HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
+ pavrc_cmd->play_item.uid, &remote_addr);
+ /*This command will trigger playback or
+ * dual a2dp handoff.. Let it play on this device. */
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ /* Trigger DUAL Handoff when support single streaming */
+ if (btif_av_is_playing() &&
+ (btif_av_get_multicast_state() == FALSE))
+ {
+ //compare the bd addr of current playing dev and this dev
+ btif_get_latest_playing_device(address);
+ if (bdcmp(btif_rc_cb[index].rc_addr, address) == 0)
+ {
+ APPL_TRACE_WARNING("Play item on the playing device");
+ } else
+ {
+ BTIF_TRACE_DEBUG("Play item on other device");
+ if (btif_av_is_device_connected(btif_rc_cb[index].rc_addr))
+ {
+ //Trigger suspend on currently playing device
+ BTIF_TRACE_DEBUG("Trigger dual handoff for this play Item command");
+ btif_rc_cb[index].rc_play_processed = TRUE;
+ btif_av_trigger_dual_handoff(TRUE, btif_rc_cb[index].rc_addr);
+ } else
+ {
+ APPL_TRACE_WARNING("%s:Play item Invalid on %d", __FUNCTION__, index);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS:
+ {
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS", __FUNCTION__);
+ if (btif_rc_cb[index].rc_connected == TRUE)
+ {
+ FILL_PDU_QUEUE(IDX_GET_TOTAL_ITEMS_RSP, ctype, label, TRUE, index, pavrc_cmd->pdu);
+ HAL_CBACK(bt_rc_callbacks, get_tot_item_cb, pavrc_cmd->get_tot_item.scope,
+ &remote_addr);
}
}
break;
default:
{
- send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu,
- (pavrc_cmd->pdu == AVRC_PDU_SEARCH)?AVRC_STS_SEARCH_NOT_SUP:AVRC_STS_BAD_CMD);
- return;
+ send_reject_response (btif_rc_cb[index].rc_handle, label, pavrc_cmd->pdu,
+ (pavrc_cmd->pdu == AVRC_PDU_SEARCH)?AVRC_STS_SEARCH_NOT_SUP:
+ AVRC_STS_BAD_CMD);
}
break;
}
@@ -1491,9 +2670,9 @@
UINT8 label)
{
BTIF_TRACE_DEBUG("%s pdu: %s handle: 0x%x", __FUNCTION__,
- dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle);
+ dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb[0].rc_handle);
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
#if (AVRC_CTLR_INCLUDED == TRUE)
switch (event)
{
@@ -1523,28 +2702,32 @@
** Returns void
**
*******************************************************************************/
-static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label)
+static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label, int index)
{
- BTIF_TRACE_EVENT("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__,
- dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb.rc_handle, ctype, label);
+ bt_bdaddr_t remote_addr;
+
+ bdcpy(remote_addr.address, btif_rc_cb[index].rc_addr);
+ BTIF_TRACE_IMP("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__,
+ dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb[index].rc_handle, ctype, label);
switch (event)
{
case AVRC_PDU_REGISTER_NOTIFICATION:
{
- if (AVRC_RSP_CHANGED==ctype)
- btif_rc_cb.rc_volume=pavrc_resp->reg_notif.param.volume;
- HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype)
+ if(AVRC_RSP_CHANGED==ctype)
+ btif_rc_cb[index].rc_volume=pavrc_resp->reg_notif.param.volume;
+ HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype,
+ &remote_addr)
}
break;
case AVRC_PDU_SET_ABSOLUTE_VOLUME:
{
- BTIF_TRACE_DEBUG("%s Set absolute volume change event received: volume %d,ctype %d",
- __FUNCTION__, pavrc_resp->volume.volume,ctype);
- if (AVRC_RSP_ACCEPT==ctype)
- btif_rc_cb.rc_volume=pavrc_resp->volume.volume;
- HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype)
+ BTIF_TRACE_DEBUG("Set absolute volume change event received: volume %d,ctype %d",
+ pavrc_resp->volume.volume,ctype);
+ if(AVRC_RSP_ACCEPT==ctype)
+ btif_rc_cb[index].rc_volume=pavrc_resp->volume.volume;
+ HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype, &remote_addr)
}
break;
@@ -1567,18 +2750,25 @@
** Returns bt_status_t
**
*******************************************************************************/
-static bt_status_t init(btrc_callbacks_t* callbacks )
+//APP can pass the max conn value here too
+static bt_status_t init(btrc_callbacks_t* callbacks, int max_connections)
{
- BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
+ BTIF_TRACE_EVENT("## %s ##, max_connections = %d", __FUNCTION__, max_connections);
bt_status_t result = BT_STATUS_SUCCESS;
+ int i;
if (bt_rc_callbacks)
return BT_STATUS_DONE;
bt_rc_callbacks = callbacks;
+ btif_max_rc_clients = max_connections;
memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
+ for (i = 0; i < btif_max_rc_clients; i++)
+ {
+ btif_rc_cb[i].rc_vol_label=MAX_LABEL;
+ btif_rc_cb[i].rc_volume=MAX_VOLUME;
+ btif_rc_cb[i].rc_handle = BTIF_RC_HANDLE_NONE;
+ }
lbl_init();
return result;
@@ -1601,10 +2791,13 @@
if (bt_rc_ctrl_callbacks)
return BT_STATUS_DONE;
+ /* Controller is used only for Certification purposes.
+ * In normal case AVRCP controller will not be used, hence
+ * updating this is required.
+ */
bt_rc_ctrl_callbacks = callbacks;
memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- btif_rc_cb.rc_volume=MAX_VOLUME;
+ btif_rc_cb[BTIF_RC_DEFAULT_INDEX].rc_vol_label=MAX_LABEL;
lbl_init();
return result;
@@ -1612,11 +2805,11 @@
static void rc_ctrl_procedure_complete ()
{
- if (btif_rc_cb.rc_procedure_complete == TRUE)
+ if (btif_rc_cb[0].rc_procedure_complete == TRUE)
{
return;
}
- btif_rc_cb.rc_procedure_complete = TRUE;
+ btif_rc_cb[0].rc_procedure_complete = TRUE;
UINT32 attr_list[] = {
AVRC_MEDIA_ATTR_ID_TITLE,
AVRC_MEDIA_ATTR_ID_ARTIST,
@@ -1626,7 +2819,9 @@
AVRC_MEDIA_ATTR_ID_GENRE,
AVRC_MEDIA_ATTR_ID_PLAYING_TIME
};
- get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+ /* Fix for below Klowkwork Issue at line 2748
+ * Array 'attr_list' of size 7 may use index value(s) 7 */
+ get_element_attribute_cmd (sizeof(attr_list)/sizeof(UINT32), attr_list);
}
/***************************************************************************
@@ -1641,20 +2836,324 @@
**
***************************************************************************/
static bt_status_t get_play_status_rsp(btrc_play_status_t play_status, uint32_t song_len,
- uint32_t song_pos)
+ uint32_t song_pos, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
+ int av_index;
CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ av_index = btif_av_idx_by_bdaddr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
avrc_rsp.get_play_status.song_len = song_len;
avrc_rsp.get_play_status.song_pos = song_pos;
avrc_rsp.get_play_status.play_status = play_status;
+ BTIF_TRACE_ERROR("%s: play_status: %d",__FUNCTION__, avrc_rsp.get_play_status.play_status);
+ if ((avrc_rsp.get_play_status.play_status == BTRC_PLAYSTATE_PLAYING) &&
+ (btif_av_check_flag_remote_suspend(av_index)))
+ {
+ BTIF_TRACE_ERROR("%s: clear remote suspend flag: %d",__FUNCTION__, av_index);
+ btif_av_clear_remote_suspend_flag();
+ if (btif_av_is_offload_supported())
+ {
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ }
+ }
avrc_rsp.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS);
avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
/* Send the response */
- SEND_METAMSG_RSP(IDX_GET_PLAY_STATUS_RSP, &avrc_rsp);
+ SEND_METAMSG_RSP(IDX_GET_PLAY_STATUS_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+
+/**************************************************************************
+**
+** Function list_player_app_attr_rsp
+**
+** Description ListPlayerApplicationSettingAttributes (PDU ID: 0x11)
+** This method is callled in response to PDU 0x11
+**
+** Returns bt_status_t
+**
+****************************************************************************/
+static bt_status_t list_player_app_attr_rsp( uint8_t num_attr, btrc_player_attr_t *p_attrs, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
+ memset(&(avrc_rsp.list_app_attr), 0, sizeof(tAVRC_LIST_APP_ATTR_RSP));
+ if (num_attr == 0)
+ {
+ avrc_rsp.list_app_attr.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ avrc_rsp.list_app_attr.num_attr = num_attr;
+ for (i = 0 ; i < num_attr ; ++i)
+ {
+ avrc_rsp.list_app_attr.attrs[i] = p_attrs[i];
+ }
+ avrc_rsp.list_app_attr.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.list_app_attr.pdu = AVRC_PDU_LIST_PLAYER_APP_ATTR ;
+ avrc_rsp.list_app_attr.opcode = opcode_from_pdu(AVRC_PDU_LIST_PLAYER_APP_ATTR);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_LIST_APP_ATTR_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function list_player_app_value_rsp
+**
+** Description ListPlayerApplicationSettingValues (PDU ID: 0x12)
+ This method is called in response to PDU 0x12
+************************************************************************/
+static bt_status_t list_player_app_value_rsp( uint8_t num_val, uint8_t *value, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
+ memset(&(avrc_rsp.list_app_values), 0, sizeof(tAVRC_LIST_APP_VALUES_RSP));
+ if ((num_val == 0) || (num_val > AVRC_MAX_APP_ATTR_SIZE))
+ {
+ avrc_rsp.list_app_values.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ avrc_rsp.list_app_values.num_val = num_val;
+ for (i = 0; i < num_val; ++i)
+ {
+ avrc_rsp.list_app_values.vals[i] = value[i];
+ }
+ avrc_rsp.list_app_values.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.list_app_values.pdu = AVRC_PDU_LIST_PLAYER_APP_VALUES;
+ avrc_rsp.list_app_attr.opcode = opcode_from_pdu(AVRC_PDU_LIST_PLAYER_APP_VALUES);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_LIST_APP_VALUE_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+**
+** Function get_player_app_value_rsp
+**
+** Description This methos is called in response to PDU ID 0x13
+**
+***********************************************************************/
+static bt_status_t get_player_app_value_rsp(btrc_player_settings_t *p_vals, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+ tAVRC_APP_SETTING app_sett[AVRC_MAX_APP_ATTR_SIZE];
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
+ memset(&(avrc_rsp.get_cur_app_val) ,0 , sizeof(tAVRC_GET_CUR_APP_VALUE_RSP));
+ avrc_rsp.get_cur_app_val.p_vals = app_sett ;
+ //Check for Error Condition
+ if ((p_vals == NULL) || (p_vals->num_attr== 0) || (p_vals->num_attr > AVRC_MAX_APP_ATTR_SIZE))
+ {
+ avrc_rsp.get_cur_app_val.status = AVRC_STS_BAD_PARAM;
+ }
+ else if (p_vals->num_attr <= BTRC_MAX_APP_SETTINGS)
+ {
+ memset(app_sett, 0, sizeof(tAVRC_APP_SETTING)*p_vals->num_attr );
+ //update num_val
+ avrc_rsp.get_cur_app_val.num_val = p_vals->num_attr ;
+ avrc_rsp.get_cur_app_val.p_vals = app_sett ;
+ for (i = 0; i < p_vals->num_attr; ++i)
+ {
+ app_sett[i].attr_id = p_vals->attr_ids[i] ;
+ app_sett[i].attr_val = p_vals->attr_values[i];
+ BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, num_element:%d",
+ __FUNCTION__, (unsigned int)app_sett[i].attr_id,
+ app_sett[i].attr_val ,p_vals->num_attr );
+ }
+ //Update PDU , status aind
+ avrc_rsp.get_cur_app_val.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
+ avrc_rsp.get_cur_app_val.opcode = opcode_from_pdu(AVRC_PDU_GET_CUR_PLAYER_APP_VALUE);
+ SEND_METAMSG_RSP(IDX_GET_CURR_APP_VAL_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/********************************************************************
+**
+** Function set_player_app_value_rsp
+**
+** Description This method is called in response to
+** application value
+**
+** Return bt_staus_t
+**
+*******************************************************************/
+static bt_status_t set_player_app_value_rsp (btrc_status_t rsp_status, bt_bdaddr_t *bd_addr )
+{
+ tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
+ CHECK_RC_CONNECTED
+ avrc_rsp.set_app_val.opcode = opcode_from_pdu(AVRC_PDU_SET_PLAYER_APP_VALUE);
+ avrc_rsp.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE ;
+ avrc_rsp.set_app_val.status = rsp_status ;
+ SEND_METAMSG_RSP(IDX_SET_APP_VAL_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/********************************************************************
+**
+** Function get_player_app_attr_text_rsp
+**
+** Description This method is called in response to get player
+** applicaton attribute text response
+**
+**
+*******************************************************************/
+static bt_status_t get_player_app_attr_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs,
+ bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_APP_SETTING_TEXT attr_txt[AVRC_MAX_APP_ATTR_SIZE];
+ int i;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("-%s on index = %d", __FUNCTION__, rc_index);
+
+ if (num_attr == 0)
+ {
+ avrc_rsp.get_app_attr_txt.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ for (i =0; i< num_attr; ++i)
+ {
+ attr_txt[i].charset_id = AVRC_CHARSET_ID_UTF8;
+ attr_txt[i].attr_id = p_attrs[i].id ;
+ attr_txt[i].str_len = (UINT8)strnlen((char *)p_attrs[i].text, BTRC_MAX_ATTR_STR_LEN);
+ attr_txt[i].p_str = p_attrs[i].text ;
+ BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, str_len:%d, str:%s",
+ __FUNCTION__, (unsigned int)attr_txt[i].attr_id,
+ attr_txt[i].charset_id , attr_txt[i].str_len, attr_txt[i].p_str);
+ }
+ avrc_rsp.get_app_attr_txt.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_app_attr_txt.p_attrs = attr_txt ;
+ avrc_rsp.get_app_attr_txt.num_attr = (UINT8)num_attr;
+ avrc_rsp.get_app_attr_txt.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
+ avrc_rsp.get_app_attr_txt.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_GET_APP_ATTR_TXT_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/********************************************************************
+**
+** Function get_player_app_value_text_rsp
+**
+** Description This method is called in response to Player application
+** value text
+**
+** Return bt_status_t
+**
+*******************************************************************/
+static bt_status_t get_player_app_value_text_rsp(int num_attr, btrc_player_setting_text_t *p_attrs, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_APP_SETTING_TEXT attr_txt[AVRC_MAX_APP_ATTR_SIZE];
+ int i;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
+ if (num_attr == 0)
+ {
+ avrc_rsp.get_app_val_txt.status = AVRC_STS_BAD_PARAM;
+ }
+ else
+ {
+ for (i =0; i< num_attr; ++i)
+ {
+ attr_txt[i].charset_id = AVRC_CHARSET_ID_UTF8;
+ attr_txt[i].attr_id = p_attrs[i].id ;
+ attr_txt[i].str_len = (UINT8)strnlen((char *)p_attrs[i].text ,BTRC_MAX_ATTR_STR_LEN );
+ attr_txt[i].p_str = p_attrs[i].text ;
+ BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, str_len:%d, str:%s",
+ __FUNCTION__, (unsigned int)attr_txt[i].attr_id,
+ attr_txt[i].charset_id , attr_txt[i].str_len,attr_txt[i].p_str);
+ }
+ avrc_rsp.get_app_val_txt.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_app_val_txt.p_attrs = attr_txt;
+ avrc_rsp.get_app_val_txt.num_attr = (UINT8)num_attr;
+ avrc_rsp.get_app_val_txt.pdu = AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT;
+ avrc_rsp.get_app_val_txt.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT);
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_GET_APP_VAL_TXT_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
@@ -1663,34 +3162,45 @@
** Function get_element_attr_rsp
**
** Description Returns the current songs' element attributes
-** in text.
+** in text.
**
** Returns bt_status_t
**
***************************************************************************/
-static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
UINT32 i;
- tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ tAVRC_ATTR_ENTRY element_attrs[MAX_ELEM_ATTR_SIZE];
+ int rc_index;
CHECK_RC_CONNECTED
- memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
- if (num_attr == 0)
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("-%s on unknown index = %d", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
+ if (num_attr == 0 || num_attr > MAX_ELEM_ATTR_SIZE)
{
avrc_rsp.get_play_status.status = AVRC_STS_BAD_PARAM;
}
else
{
- for (i=0; i<num_attr; i++) {
+ memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+ for (i=0; i<num_attr; i++)
+ {
element_attrs[i].attr_id = p_attrs[i].attr_id;
element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
element_attrs[i].name.str_len = (UINT16)strlen((char *)p_attrs[i].text);
element_attrs[i].name.p_str = p_attrs[i].text;
BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, str_len:%d, str:%s",
- __FUNCTION__, (unsigned int)element_attrs[i].attr_id,
- element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
- element_attrs[i].name.p_str);
+ __FUNCTION__, (unsigned int)element_attrs[i].attr_id,
+ element_attrs[i].name.charset_id,
+ element_attrs[i].name.str_len,
+ element_attrs[i].name.p_str);
}
avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
}
@@ -1699,7 +3209,7 @@
avrc_rsp.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
avrc_rsp.get_elem_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ELEMENT_ATTR);
/* Send the response */
- SEND_METAMSG_RSP(IDX_GET_ELEMENT_ATTR_RSP, &avrc_rsp);
+ SEND_METAMSG_RSP(IDX_GET_ELEMENT_ATTR_RSP, &avrc_rsp, rc_index);
return BT_STATUS_SUCCESS;
}
@@ -1714,25 +3224,49 @@
**
***************************************************************************/
static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
- btrc_notification_type_t type, btrc_register_notification_t *p_param)
+ btrc_notification_type_t type, btrc_register_notification_t *p_param, bt_bdaddr_t *bd_addr)
{
tAVRC_RESPONSE avrc_rsp;
+ int index = btif_rc_get_idx_by_addr(bd_addr->address);
CHECK_RC_CONNECTED
- BTIF_TRACE_EVENT("## %s ## event_id:%s", __FUNCTION__, dump_rc_notification_event_id(event_id));
- if (btif_rc_cb.rc_notif[event_id-1].bNotify == FALSE)
+
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+
+
+ BTIF_TRACE_IMP("## %s ## event_id:%s", __FUNCTION__, dump_rc_notification_event_id(event_id));
+ if (btif_rc_cb[index].rc_notif[event_id-1].bNotify == FALSE)
{
BTIF_TRACE_ERROR("Avrcp Event id not registered: event_id = %x", event_id);
return BT_STATUS_NOT_READY;
}
memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
avrc_rsp.reg_notif.event_id = event_id;
+ int av_index = btif_av_idx_by_bdaddr(bd_addr->address);
switch(event_id)
{
case BTRC_EVT_PLAY_STATUS_CHANGED:
avrc_rsp.reg_notif.param.play_status = p_param->play_status;
- if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING)
+ /* Clear remote suspend flag, as remote device issues
+ * suspend within 3s after pause, and DUT within 3s
+ * initiates Play
+ */
+ BTIF_TRACE_ERROR("%s: play_status: %d",__FUNCTION__,
+ avrc_rsp.reg_notif.param.play_status);
+ if ((avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING) &&
+ (btif_av_check_flag_remote_suspend(av_index)))
+ {
+ BTIF_TRACE_ERROR("%s: clear remote suspend flag: %d",__FUNCTION__,av_index );
btif_av_clear_remote_suspend_flag();
+ if (btif_av_is_offload_supported())
+ {
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ }
+ }
break;
case BTRC_EVT_TRACK_CHANGE:
memcpy(&(avrc_rsp.reg_notif.param.track), &(p_param->track), sizeof(btrc_uid_t));
@@ -1740,6 +3274,29 @@
case BTRC_EVT_PLAY_POS_CHANGED:
avrc_rsp.reg_notif.param.play_pos = p_param->song_pos;
break;
+ case BTRC_EVT_APP_SETTINGS_CHANGED:
+ if (interop_match_addr(INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS,
+ (bt_bdaddr_t *) bd_addr))
+ {
+ BTIF_TRACE_DEBUG("Blacklisted CK for BTRC_EVT_APP_SETTINGS_CHANGED event");
+ return BT_STATUS_UNHANDLED;
+ }
+ avrc_rsp.reg_notif.param.player_setting.num_attr = p_param->player_setting.num_attr;
+ memcpy(&avrc_rsp.reg_notif.param.player_setting.attr_id,
+ p_param->player_setting.attr_ids, 2);
+ memcpy(&avrc_rsp.reg_notif.param.player_setting.attr_value,
+ p_param->player_setting.attr_values, 2);
+ break;
+ case BTRC_EVT_ADDRESSED_PLAYER_CHANGED:
+ avrc_rsp.reg_notif.param.addr_player.player_id = p_param->player_id;
+ avrc_rsp.reg_notif.param.addr_player.uid_counter = 0;
+ break;
+ case BTRC_EVT_AVAILABLE_PLAYERS_CHANGED:
+ avrc_rsp.reg_notif.param.evt = 0x0a;
+ break;
+ case BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED:
+ avrc_rsp.reg_notif.param.evt = 0x09;
+ break;
default:
BTIF_TRACE_WARNING("%s : Unhandled event ID : 0x%x", __FUNCTION__, event_id);
return BT_STATUS_UNHANDLED;
@@ -1747,14 +3304,479 @@
avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
- avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+ if (type == BTRC_NOTIFICATION_TYPE_REJECT)
+ {
+ /* Spec AVRCP 1.5 ,section 6.9.2.2, on completion
+ * of the addressed player changed notificatons the TG shall
+ * complete all player specific notification with AV/C C-type
+ * Rejected with error code Addressed Player changed.
+ * This will happen in case when music player has changed
+ * Application should take care of sending reject response.
+ */
+ avrc_rsp.get_play_status.status = AVRC_STS_ADDR_PLAYER_CHG;
+ }
+ else
+ {
+ avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+ }
/* Send the response. */
- send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
+ send_metamsg_rsp(btif_rc_cb[index].rc_handle, btif_rc_cb[index].rc_notif[event_id-1].label,
((type == BTRC_NOTIFICATION_TYPE_INTERIM)?AVRC_CMD_NOTIF:AVRC_RSP_CHANGED), &avrc_rsp);
return BT_STATUS_SUCCESS;
}
+
+/***************************************************************************
+**
+** Function get_folderitem_rsp
+**
+** Description Response to Get Folder Items , PDU 0x71
+**
+** Returns bt_status_t
+**
+***************************************************************************/
+static bt_status_t get_folderitem_rsp(btrc_folder_list_entries_t *rsp, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_ITEM item[MAX_FOLDER_RSP_SUPPORT]; //Number of players that could be supported
+ UINT8 index, i, xx, media_attr_cnt;
+ UINT8 *p_conversion;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_EVENT("%s() AVRC_PDU_GET_FOLDER_ITEMS", __FUNCTION__);
+ index = IDX_GET_FOLDER_ITEMS_RSP ;
+ avrc_rsp.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+ avrc_rsp.get_items.opcode = AVRC_OP_BROWSE;
+ avrc_rsp.get_items.uid_counter = rsp->uid_counter;
+ avrc_rsp.get_items.status = rsp->status ;//4 means SUCCESS
+ avrc_rsp.get_items.item_count = 0;
+ BTIF_TRACE_EVENT("status =%d, item_count =%d",rsp->status, rsp->item_count);
+
+ for (i=0; (i < rsp->item_count && i < MAX_FOLDER_RSP_SUPPORT) ; ++i)
+ {
+ item[i].item_type = rsp->p_item_list[i].item_type;
+ BTIF_TRACE_EVENT("item_type = %d", rsp->p_item_list[i].item_type);
+ switch (item[i].item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ memcpy(item[i].u.player.features, rsp->p_item_list[i].u.player.features,
+ AVRC_FEATURE_MASK_SIZE);
+ item[i].u.player.major_type = rsp->p_item_list[i].u.player.major_type;
+ item[i].u.player.sub_type = rsp->p_item_list[i].u.player.sub_type;
+ item[i].u.player.play_status = rsp->p_item_list[i].u.player.play_status;
+ item[i].u.player.player_id = rsp->p_item_list[i].u.player.player_id;
+ item[i].u.player.name.charset_id = rsp->p_item_list[i].u.player.name.charset_id;
+ item[i].u.player.name.str_len = rsp->p_item_list[i].u.player.name.str_len;
+ item[i].u.player.name.p_str = rsp->p_item_list[i].u.player.name.p_str;
+ ++avrc_rsp.get_items.item_count;
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ item[i].u.folder.type = rsp->p_item_list[i].u.folder.type;
+ item[i].u.folder.playable = rsp->p_item_list[i].u.folder.playable;
+ {
+ p_conversion = (UINT8*)&(rsp->p_item_list[i].u.folder.uid);
+ for (xx = 0; xx < AVRC_UID_SIZE; xx++)
+ {
+ ((UINT8 *) item[i].u.folder.uid)[AVRC_UID_SIZE - (xx + 1)] = \
+ *p_conversion++;
+ }
+ }
+
+ item[i].u.folder.name.charset_id = rsp->p_item_list[i].u.folder.name.charset_id;
+ item[i].u.folder.name.str_len = rsp->p_item_list[i].u.folder.name.str_len;
+ item[i].u.folder.name.p_str = rsp->p_item_list[i].u.folder.name.p_str;
+ ++avrc_rsp.get_items.item_count;
+ break;
+
+ case AVRC_ITEM_MEDIA:
+ item[i].u.media.type = rsp->p_item_list[i].u.media.type;
+ {
+ p_conversion = (UINT8*)&(rsp->p_item_list[i].u.media.uid);
+ //BE_STREAM_TO_ARRAY(p_conversion, item[i].u.folder.uid, AVRC_UID_SIZE);
+ for (xx = 0; xx < AVRC_UID_SIZE; xx++)
+ {
+ ((UINT8 *) item[i].u.folder.uid)[AVRC_UID_SIZE - (xx + 1)] = \
+ *p_conversion++;
+ }
+ }
+ item[i].u.media.name.charset_id = rsp->p_item_list[i].u.media.name.charset_id;
+ item[i].u.media.name.str_len = rsp->p_item_list[i].u.media.name.str_len;
+ item[i].u.media.name.p_str = rsp->p_item_list[i].u.media.name.p_str;
+ media_attr_cnt = rsp->p_item_list[i].u.media.attr_count;
+ item[i].u.media.attr_count = rsp->p_item_list[i].u.media.attr_count;
+ BTIF_TRACE_ERROR("attr count = %d", media_attr_cnt);
+ if (media_attr_cnt > 0)
+ {
+ if ((item[i].u.media.p_attr_list = \
+ (tAVRC_ATTR_ENTRY *)osi_malloc((UINT16)(media_attr_cnt * \
+ sizeof(tAVRC_ATTR_ENTRY)))) != NULL)
+ {
+ for (xx = 0; xx < media_attr_cnt; xx++)
+ {
+ item[i].u.media.p_attr_list[xx].attr_id = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].attr_id;
+ item[i].u.media.p_attr_list[xx].name.charset_id = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].name.charset_id;
+ item[i].u.media.p_attr_list[xx].name.str_len = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len;
+ item[i].u.media.p_attr_list[xx].name.p_str = \
+ rsp->p_item_list[i].u.media.p_attr_list[xx].name.p_str;
+ BTIF_TRACE_ERROR("attr_id = %d", item[i].u.media.p_attr_list[xx].\
+ attr_id);
+ BTIF_TRACE_ERROR("str_len = %d", item[i].u.media.p_attr_list[xx].\
+ name.str_len);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("Not enough buffer allocated to accomodate attributes");
+ item[i].u.media.attr_count = 0;
+ }
+ }
+ ++avrc_rsp.get_items.item_count;
+ break;
+
+ default:
+ return BT_STATUS_UNHANDLED;
+ break;
+ }
+ }
+ if (avrc_rsp.get_items.item_count == 0) {
+ /*As per spec Send proper Error if no Music App is registered.*/
+ avrc_rsp.get_items.status = AVRC_STS_BAD_RANGE;
+ }
+ avrc_rsp.get_items.p_item_list = item;
+ app_sendbrowsemsg(IDX_GET_FOLDER_ITEMS_RSP ,&avrc_rsp, rc_index);
+ BTIF_TRACE_ERROR("free attr list");
+ for (i=0; (i < rsp->item_count && i < MAX_FOLDER_RSP_SUPPORT) ; ++i)
+ {
+ if (item[i].item_type == AVRC_ITEM_MEDIA)
+ {
+ if (rsp->p_item_list[i].u.media.attr_count > 0)
+ {
+ osi_free_and_reset((void**)&item[i].u.media.p_attr_list);
+ }
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function set_addrplayer_rsp
+**
+** Description Response to Set Addressed Player , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t set_addrplayer_rsp(btrc_status_t status_code, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
+ CHECK_RC_CONNECTED
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+ avrc_rsp.addr_player.status = status_code;
+ avrc_rsp.addr_player.opcode = opcode_from_pdu(AVRC_PDU_SET_ADDRESSED_PLAYER);
+ avrc_rsp.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_SET_ADDRESS_PLAYER_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function set_browseplayer_rsp
+**
+** Description Response to Set Browsed Player , PDU 0x70
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t set_browseplayer_rsp(btrc_set_browsed_player_rsp_t *p_param, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ int rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ CHECK_RC_CONNECTED
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
+ avrc_rsp.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+ avrc_rsp.br_player.folder_depth = p_param->folder_depth;
+ avrc_rsp.br_player.charset_id = p_param->charset_id;
+ avrc_rsp.br_player.num_items = p_param->num_items;
+ avrc_rsp.br_player.opcode = opcode_from_pdu(AVRC_PDU_SET_BROWSED_PLAYER);
+ avrc_rsp.br_player.status = p_param->status;
+ avrc_rsp.br_player.uid_counter = p_param->uid_counter;
+ avrc_rsp.br_player.p_folders = (tAVRC_NAME*)p_param->p_folders;
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_SET_BROWSE_PLAYER_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function changepath_rsp
+**
+** Description Response to Change Path , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t changepath_rsp(uint8_t status_code, uint32_t item_count, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
+ avrc_rsp.chg_path.num_items = item_count;
+ avrc_rsp.chg_path.opcode = opcode_from_pdu(AVRC_PDU_CHANGE_PATH);
+ avrc_rsp.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+ avrc_rsp.chg_path.status = status_code;
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_CHANGE_PATH_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ **
+ ** Function get_totalitems_rsp
+ **
+ ** Description Response to Get Total number of Items , PDU 0x75
+ **
+ ** Return status
+ **
+ *********************************************************************/
+
+ static bt_status_t get_total_items_rsp(uint8_t status_code, uint32_t item_count,
+ uint16_t uid_counter, bt_bdaddr_t *bd_addr)
+ {
+ tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+ avrc_rsp.get_tot_items.num_items = item_count;
+ avrc_rsp.get_tot_items.opcode = opcode_from_pdu(AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS);
+ avrc_rsp.get_tot_items.pdu = AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS;
+ avrc_rsp.get_tot_items.status = status_code;
+ avrc_rsp.get_tot_items.uid_counter = uid_counter;
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_GET_TOTAL_ITEMS_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+ }
+
+/**********************************************************************
+**
+** Function playitem_rsp
+**
+** Description Response to Play Item , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t playitem_rsp(uint8_t status_code, bt_bdaddr_t *bd_addr)
+{
+ tAVRC_RESPONSE avrc_rsp;
+ int rc_index;
+ CHECK_RC_CONNECTED
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
+ avrc_rsp.play_item.status = status_code;
+ avrc_rsp.play_item.opcode = opcode_from_pdu(AVRC_PDU_PLAY_ITEM);
+ avrc_rsp.play_item.pdu = AVRC_PDU_PLAY_ITEM;
+ /* Send the response */
+ SEND_METAMSG_RSP(IDX_PLAY_ITEM_RSP, &avrc_rsp,rc_index);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function get_itemattr_rsp
+**
+** Description Response to Get Item , PDU 0x60
+**
+** Return status
+**
+*********************************************************************/
+
+static bt_status_t get_itemattr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs, bt_bdaddr_t *bd_addr)
+
+{
+ tAVRC_RESPONSE avrc_rsp;
+ UINT32 i;
+ tAVRC_ATTR_ENTRY element_attrs[MAX_ELEM_ATTR_SIZE];
+ int rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ CHECK_RC_CONNECTED
+
+ if (rc_index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, rc_index);
+
+ if (num_attr == 0 || num_attr > MAX_ELEM_ATTR_SIZE)
+ {
+ avrc_rsp.get_attrs.status = AVRC_STS_INTERNAL_ERR;
+ }
+ else
+ {
+ memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+ for (i=0; i<num_attr; i++)
+ {
+ element_attrs[i].attr_id = p_attrs[i].attr_id;
+ element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
+ element_attrs[i].name.str_len = (UINT16)strlen((char *)p_attrs[i].text);
+ element_attrs[i].name.p_str = p_attrs[i].text;
+ BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, str_len:%d, str:%s",
+ __FUNCTION__, (unsigned int)element_attrs[i].attr_id,
+ element_attrs[i].name.charset_id,
+ element_attrs[i].name.str_len,
+ element_attrs[i].name.p_str);
+ }
+ avrc_rsp.get_attrs.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_attrs.attr_count = num_attr;
+ avrc_rsp.get_attrs.p_attr_list = element_attrs;
+ avrc_rsp.get_attrs.pdu = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+ avrc_rsp.get_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ITEM_ATTRIBUTES);
+ /* Send the response */
+ SEND_BROWSEMSG_RSP(IDX_GET_ITEM_ATTR_RSP, &avrc_rsp, rc_index);
+ return BT_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+**
+** Function is_device_active_in_handoff
+**
+** Description Check if this is the active device during hand-off
+** If the multicast is disabled when connected to more
+** than one device and the active playing device is
+** different or device to start playback is different
+** then fail this condition.
+** Return BT_STATUS_SUCCESS if active BT_STATUS_FAIL otherwise
+**
+*********************************************************************/
+static bt_status_t is_device_active_in_handoff(bt_bdaddr_t *bd_addr)
+{
+ BD_ADDR playing_device;
+ int rc_index;
+ UINT16 connected_devices, playing_devices;
+
+ rc_index = btif_rc_get_idx_by_addr(bd_addr->address);
+ if(rc_index >= btif_max_rc_clients)
+ {
+ return BT_STATUS_FAIL;
+ }
+ connected_devices = btif_av_get_num_connected_devices();
+ playing_devices = btif_av_get_num_playing_devices();
+
+ if((connected_devices < btif_max_rc_clients) || (playing_devices > 1))
+ {
+ return BT_STATUS_SUCCESS;
+ }
+
+ if((connected_devices > 1) && (playing_devices == 1))
+ {
+ /* One playing device, check the active device */
+ btif_get_latest_playing_device(playing_device);
+ if (bdcmp(bd_addr->address, playing_device) == 0)
+ {
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ return BT_STATUS_FAIL;
+ }
+ }
+ else if (playing_devices == 0)
+ {
+ /* No Playing device, find the next playing device
+ * Play initiated from remote
+ */
+ if (btif_rc_cb[rc_index].rc_play_processed == TRUE)
+ {
+ return BT_STATUS_SUCCESS;
+ }
+ else if (btif_av_is_current_device(bd_addr->address) == TRUE)
+ {
+ /* Play initiated locally. check the current device and
+ * make sure play is not initiated from other remote
+ */
+ BD_ADDR rc_play_device = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ btif_rc_get_playing_device(rc_play_device);
+ if(bdcmp(bd_addr->address, bd_addr_null) != 0)
+ {
+ /* some other playing device */
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s no playing or current device ", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s unchecked state: connected devices: %d playing devices: %d",
+ __FUNCTION__, connected_devices, playing_devices);
+ return BT_STATUS_SUCCESS;
+ }
+}
+
/***************************************************************************
**
** Function set_volume
@@ -1769,22 +3791,29 @@
** Returns bt_status_t
**
***************************************************************************/
-static bt_status_t set_volume(uint8_t volume)
+static bt_status_t set_volume(uint8_t volume, bt_bdaddr_t *bd_addr)
{
- BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ int index = btif_rc_get_idx_by_addr(bd_addr->address);
+
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ BTIF_TRACE_DEBUG("- %s on index = %d", __FUNCTION__, index);
CHECK_RC_CONNECTED
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
rc_transaction_t *p_transaction=NULL;
- if (btif_rc_cb.rc_volume==volume)
+ if(btif_rc_cb[index].rc_volume==volume)
{
status=BT_STATUS_DONE;
BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__FUNCTION__, volume);
return status;
}
- if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) &&
- (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL))
+ if ((btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG) &&
+ (btif_rc_cb[index].rc_features & BTA_AV_FEAT_ADV_CTRL))
{
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
@@ -1802,7 +3831,7 @@
{
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ BTA_AvMetaCmd(btif_rc_cb[index].rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
status = BT_STATUS_SUCCESS;
}
else
@@ -1836,13 +3865,12 @@
**
***************************************************************************/
-static void register_volumechange (UINT8 lbl)
+static void register_volumechange (UINT8 lbl, int index)
{
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS BldResp=AVRC_STS_BAD_CMD;
rc_transaction_t *p_transaction=NULL;
-
BTIF_TRACE_DEBUG("%s called with label:%d",__FUNCTION__,lbl);
avrc_cmd.cmd.opcode=0x00;
@@ -1855,7 +3883,7 @@
if (AVRC_STS_NO_ERROR == BldResp && p_msg) {
p_transaction = get_transaction_by_lbl(lbl);
if (p_transaction != NULL) {
- BTA_AvMetaCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvMetaCmd(btif_rc_cb[index].rc_handle, p_transaction->lbl,
AVRC_CMD_NOTIF, p_msg);
BTIF_TRACE_DEBUG("%s:BTA_AvMetaCmd called", __func__);
} else {
@@ -1879,11 +3907,19 @@
***************************************************************************/
static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
{
+ UINT8 index; /*For RC it is zero*/
tAVRC_RESPONSE avrc_response = {0};
UINT8 scratch_buf[512] = {0};
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
- if (AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
+ index = btif_rc_get_idx_by_rc_handle(pmeta_msg->rc_handle);
+ if (index == btif_max_rc_clients)
+ {
+ BTIF_TRACE_ERROR("%s: on unknown index", __FUNCTION__);
+ return;
+ }
+
+ if(AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
|| AVRC_RSP_INTERIM==pmeta_msg->code || AVRC_RSP_ACCEPT==pmeta_msg->code
|| AVRC_RSP_REJ==pmeta_msg->code || AVRC_RSP_NOT_IMPL==pmeta_msg->code))
{
@@ -1896,10 +3932,10 @@
{
if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
- && btif_rc_cb.rc_vol_label==pmeta_msg->label)
+ && btif_rc_cb[index].rc_vol_label==pmeta_msg->label)
{
- btif_rc_cb.rc_vol_label=MAX_LABEL;
- release_transaction(btif_rc_cb.rc_vol_label);
+ btif_rc_cb[index].rc_vol_label=MAX_LABEL;
+ release_transaction(btif_rc_cb[index].rc_vol_label);
}
else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
{
@@ -1909,7 +3945,7 @@
}
else if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
- && btif_rc_cb.rc_vol_label!=pmeta_msg->label)
+ && btif_rc_cb[index].rc_vol_label!=pmeta_msg->label)
{
// Just discard the message, if the device sends back with an incorrect label
BTIF_TRACE_DEBUG("%s:Discarding register notfn in rsp.code: %d and label %d",
@@ -1930,7 +3966,7 @@
{
/* re-register for volume change notification */
// Do not re-register for rejected case, as it might get into endless loop
- register_volumechange(btif_rc_cb.rc_vol_label);
+ register_volumechange(btif_rc_cb[index].rc_vol_label, index);
}
else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
{
@@ -1941,7 +3977,7 @@
BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s",
__FUNCTION__, dump_rc_pdu(avrc_response.pdu));
btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response, pmeta_msg->code,
- pmeta_msg->label);
+ pmeta_msg->label, index);
}
#endif
@@ -1991,7 +4027,7 @@
if (p_event->label == label)
{
- list_remove(btif_rc_cb.rc_supported_event_list, p_event);
+ list_remove(btif_rc_cb[0].rc_supported_event_list, p_event);
return false;
}
return true;
@@ -2010,13 +4046,14 @@
static void rc_notification_interim_timout (UINT8 label)
{
list_node_t *node;
-
- list_foreach(btif_rc_cb.rc_supported_event_list,
+ if (btif_rc_cb[0].rc_supported_event_list == NULL)
+ return;
+ list_foreach(btif_rc_cb[0].rc_supported_event_list,
iterate_supported_event_list_for_timeout, &label);
/* Timeout happened for interim response for the registered event,
* check if there are any pending for registration
*/
- node = list_begin(btif_rc_cb.rc_supported_event_list);
+ node = list_begin(btif_rc_cb[0].rc_supported_event_list);
while (node != NULL)
{
btif_rc_supported_event_t *p_event;
@@ -2051,7 +4088,7 @@
p_context = (btif_rc_timer_context_t *)data;
memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
- meta_msg.rc_handle = btif_rc_cb.rc_handle;
+ meta_msg.rc_handle = btif_rc_cb[0].rc_handle;
switch (p_context->rc_status_cmd.pdu_id) {
case AVRC_PDU_REGISTER_NOTIFICATION:
@@ -2136,7 +4173,7 @@
tBTA_AV_META_MSG meta_msg;
memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
- meta_msg.rc_handle = btif_rc_cb.rc_handle;
+ meta_msg.rc_handle = btif_rc_cb[0].rc_handle;
switch (p_context->rc_control_cmd.pdu_id) {
case AVRC_PDU_SET_PLAYER_APP_VALUE:
@@ -2208,12 +4245,12 @@
static void rc_start_play_status_timer(void)
{
/* Start the Play status timer only if it is not started */
- if (!alarm_is_scheduled(btif_rc_cb.rc_play_status_timer)) {
- if (btif_rc_cb.rc_play_status_timer == NULL) {
- btif_rc_cb.rc_play_status_timer =
+ if (!alarm_is_scheduled(btif_rc_cb[0].rc_play_status_timer)) {
+ if (btif_rc_cb[0].rc_play_status_timer == NULL) {
+ btif_rc_cb[0].rc_play_status_timer =
alarm_new("btif_rc.rc_play_status_timer");
}
- alarm_set_on_queue(btif_rc_cb.rc_play_status_timer,
+ alarm_set_on_queue(btif_rc_cb[0].rc_play_status_timer,
BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
btif_rc_play_status_timer_timeout, NULL,
btu_general_alarm_queue);
@@ -2230,8 +4267,8 @@
***************************************************************************/
void rc_stop_play_status_timer()
{
- if (btif_rc_cb.rc_play_status_timer != NULL)
- alarm_cancel(btif_rc_cb.rc_play_status_timer);
+ if (btif_rc_cb[0].rc_play_status_timer != NULL)
+ alarm_cancel(btif_rc_cb[0].rc_play_status_timer);
}
/***************************************************************************
@@ -2336,7 +4373,7 @@
btif_rc_supported_event_t *p_event;
/* Todo: Check if list can be active when we hit here */
- btif_rc_cb.rc_supported_event_list = list_new(osi_free);
+ btif_rc_cb[0].rc_supported_event_list = list_new(osi_free);
for (xx = 0; xx < p_rsp->count; xx++)
{
/* Skip registering for Play position change notification */
@@ -2347,10 +4384,15 @@
p_event = (btif_rc_supported_event_t *)osi_malloc(sizeof(btif_rc_supported_event_t));
p_event->event_id = p_rsp->param.event_id[xx];
p_event->status = eNOT_REGISTERED;
- list_append(btif_rc_cb.rc_supported_event_list, p_event);
+ list_append(btif_rc_cb[0].rc_supported_event_list, p_event);
}
}
- p_event = list_front(btif_rc_cb.rc_supported_event_list);
+ if (list_is_empty(btif_rc_cb[0].rc_supported_event_list))
+ {
+ BTIF_TRACE_EVENT(" Supported event list Empty, returning");
+ return;
+ }
+ p_event = list_front(btif_rc_cb[0].rc_supported_event_list);
if (p_event != NULL)
{
register_for_event_notification(p_event);
@@ -2414,11 +4456,13 @@
};
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
if (pmeta_msg->code == AVRC_RSP_INTERIM)
{
- btif_rc_supported_event_t *p_event;
+ /* Klockwork Fix for below issue 4442
+ * 'p_event' might be used uninitialized in this function.*/
+ btif_rc_supported_event_t *p_event = NULL;
list_node_t *node;
BTIF_TRACE_DEBUG("%s Interim response : 0x%2X ", __FUNCTION__, p_rsp->event_id);
@@ -2447,7 +4491,7 @@
/* Update the UID for current track
* Attributes will be fetched after the AVRCP procedure
*/
- BE_STREAM_TO_UINT64(btif_rc_cb.rc_playing_uid, p_data);
+ BE_STREAM_TO_UINT64(btif_rc_cb[0].rc_playing_uid, p_data);
}
break;
@@ -2476,11 +4520,11 @@
p_rsp->event_id);
return;
}
- list_foreach(btif_rc_cb.rc_supported_event_list,
+ list_foreach(btif_rc_cb[0].rc_supported_event_list,
iterate_supported_event_list_for_interim_rsp,
&p_rsp->event_id);
- node = list_begin(btif_rc_cb.rc_supported_event_list);
+ node = list_begin(btif_rc_cb[0].rc_supported_event_list);
while (node != NULL)
{
p_event = (btif_rc_supported_event_t *)list_node(node);
@@ -2493,13 +4537,13 @@
p_event = NULL;
}
/* Registered for all events, we can request application settings */
- if ((p_event == NULL) && (btif_rc_cb.rc_app_settings.query_started == false))
+ if ((p_event == NULL) && (btif_rc_cb[0].rc_app_settings.query_started == false))
{
/* we need to do this only if remote TG supports
* player application settings
*/
- btif_rc_cb.rc_app_settings.query_started = TRUE;
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_APP_SETTING)
+ btif_rc_cb[0].rc_app_settings.query_started = TRUE;
+ if (btif_rc_cb[0].rc_features & BTA_AV_FEAT_APP_SETTING)
{
list_player_app_setting_attrib_cmd();
}
@@ -2518,7 +4562,7 @@
BTIF_TRACE_DEBUG("%s Notification completed : 0x%2X ", __FUNCTION__,
p_rsp->event_id);
- node = list_begin(btif_rc_cb.rc_supported_event_list);
+ node = list_begin(btif_rc_cb[0].rc_supported_event_list);
while (node != NULL)
{
p_event = (btif_rc_supported_event_t *)list_node(node);
@@ -2554,7 +4598,11 @@
{
break;
}
- get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+ UINT8 *p_data = p_rsp->param.track;
+ BE_STREAM_TO_UINT64(btif_rc_cb[0].rc_playing_uid, p_data);
+ /* Fix for below Klowkwork Issue at line 4509
+ * Array 'attr_list' of size 7 may use index value(s) 7 */
+ get_element_attribute_cmd (sizeof(attr_list)/sizeof(UINT32), attr_list);
break;
case AVRC_EVT_APP_SETTING_CHANGE:
@@ -2625,26 +4673,28 @@
if (p_rsp->attrs[xx] > AVRC_PLAYER_SETTING_LOW_MENU_EXT)
{
- st_index = btif_rc_cb.rc_app_settings.num_ext_attrs;
- btif_rc_cb.rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
- btif_rc_cb.rc_app_settings.num_ext_attrs++;
+ st_index = btif_rc_cb[0].rc_app_settings.num_ext_attrs;
+ btif_rc_cb[0].rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
+ btif_rc_cb[0].rc_app_settings.num_ext_attrs++;
}
else
{
- st_index = btif_rc_cb.rc_app_settings.num_attrs;
- btif_rc_cb.rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
- btif_rc_cb.rc_app_settings.num_attrs++;
+ st_index = btif_rc_cb[0].rc_app_settings.num_attrs;
+ btif_rc_cb[0].rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
+ btif_rc_cb[0].rc_app_settings.num_attrs++;
}
}
- btif_rc_cb.rc_app_settings.attr_index = 0;
- btif_rc_cb.rc_app_settings.ext_attr_index = 0;
- btif_rc_cb.rc_app_settings.ext_val_index = 0;
+ btif_rc_cb[0].rc_app_settings.attr_index = 0;
+ btif_rc_cb[0].rc_app_settings.ext_attr_index = 0;
+ btif_rc_cb[0].rc_app_settings.ext_val_index = 0;
if (p_rsp->num_attr)
{
- list_player_app_setting_value_cmd (btif_rc_cb.rc_app_settings.attrs[0].attr_id);
+ list_player_app_setting_value_cmd (btif_rc_cb[0].rc_app_settings.attrs[0].attr_id);
}
else
{
+ /* Complete RC procedure from here */
+ rc_ctrl_procedure_complete();
BTIF_TRACE_ERROR("%s No Player application settings found",
__FUNCTION__);
}
@@ -2677,8 +4727,8 @@
return;
}
- p_app_settings = &btif_rc_cb.rc_app_settings;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ p_app_settings = &btif_rc_cb[0].rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
if (p_app_settings->attr_index < p_app_settings->num_attrs)
{
@@ -2700,8 +4750,12 @@
p_app_settings->ext_attr_index = 0;
list_player_app_setting_value_cmd (p_app_settings->ext_attrs[attr_index].attr_id);
}
+ /* Klockwork fix for below line 4661
+ * Array 'attrs' of size 16 may use index value(s) 16..254*/
else
{
+ if (p_app_settings->num_attrs > AVRC_MAX_APP_ATTR_SIZE)
+ p_app_settings->num_attrs = AVRC_MAX_APP_ATTR_SIZE;
for (xx = 0; xx < p_app_settings->num_attrs; xx++)
{
attrs[xx] = p_app_settings->attrs[xx].attr_id;
@@ -2721,21 +4775,7 @@
}
attr_index++;
p_app_settings->ext_attr_index++;
- if (attr_index < p_app_settings->num_ext_attrs)
- {
- list_player_app_setting_value_cmd (p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id);
- }
- else
- {
- UINT8 attr[AVRC_MAX_APP_ATTR_SIZE];
- UINT8 xx;
-
- for (xx = 0; xx < p_app_settings->num_ext_attrs; xx++)
- {
- attr[xx] = p_app_settings->ext_attrs[xx].attr_id;
- }
- get_player_app_setting_attr_text_cmd(attr, xx);
- }
+ list_player_app_setting_value_cmd (p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id);
}
}
@@ -2762,7 +4802,7 @@
return;
}
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
app_settings.num_attr = p_rsp->num_val;
@@ -2803,8 +4843,8 @@
btif_rc_player_app_settings_t *p_app_settings;
bt_bdaddr_t rc_addr;
- p_app_settings = &btif_rc_cb.rc_app_settings;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ p_app_settings = &btif_rc_cb[0].rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
/* Todo: Do we need to retry on command timeout */
if (p_rsp->status != AVRC_STS_NO_ERROR)
@@ -2821,8 +4861,9 @@
for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
osi_free_and_reset((void **)&p_app_settings->ext_attrs[xx].p_str);
p_app_settings->ext_attr_index = 0;
-
- for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ /* Klockwork Fix for below issue at line 4765
+ * Array 'attrs' of size 16 may use index value(s) 16..254 */
+ for (xx = 0; xx < p_app_settings->num_attrs && xx < AVRC_MAX_APP_ATTR_SIZE; xx++)
{
attrs[xx] = p_app_settings->attrs[xx].attr_id;
}
@@ -2848,7 +4889,9 @@
}
}
- for (xx = 0; xx < p_app_settings->ext_attrs[0].num_val; xx++)
+ /* Klockwork Fix for below issue at line 4791
+ * Array 'vals' of size 16 may use index value(s) 16..254*/
+ for (xx = 0; xx < p_app_settings->ext_attrs[0].num_val && xx < AVRC_MAX_APP_ATTR_SIZE; xx++)
{
vals[xx] = p_app_settings->ext_attrs[0].ext_attr_val[xx].val;
}
@@ -2874,8 +4917,8 @@
btif_rc_player_app_settings_t *p_app_settings;
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- p_app_settings = &btif_rc_cb.rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
+ p_app_settings = &btif_rc_cb[0].rc_app_settings;
/* Todo: Do we need to retry on command timeout */
if (p_rsp->status != AVRC_STS_NO_ERROR)
@@ -2902,7 +4945,9 @@
}
p_app_settings->ext_attr_index = 0;
- for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ /* Klockwork Fix for below issue 4851
+ * Array 'attrss' of size 16 may use index value(s) 16..254*/
+ for (xx = 0; xx < p_app_settings->num_attrs && xx < AVRC_MAX_APP_ATTR_SIZE; xx++)
{
attrs[xx] = p_app_settings->attrs[xx].attr_id;
}
@@ -2934,7 +4979,9 @@
if (p_app_settings->ext_val_index < p_app_settings->num_ext_attrs)
{
attr_index = p_app_settings->ext_val_index;
- for (xx = 0; xx < p_app_settings->ext_attrs[attr_index].num_val; xx++)
+ /* Klockwork Fix for below issue 4883
+ * Array 'vals' of size 16 may use index value(s) 16..254*/
+ for (xx = 0; xx < p_app_settings->ext_attrs[attr_index].num_val && xx < AVRC_MAX_APP_ATTR_SIZE; xx++)
{
vals[xx] = p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val;
}
@@ -2944,18 +4991,25 @@
{
UINT8 x;
- for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ for (xx = 0; ((xx < AVRC_MAX_APP_ATTR_SIZE) && (xx < p_app_settings->num_attrs)); xx++)
{
attrs[xx] = p_app_settings->attrs[xx].attr_id;
}
- for (x = 0; x < p_app_settings->num_ext_attrs; x++)
+ for (x = 0; ((xx + x < AVRC_MAX_APP_ATTR_SIZE) && (x < p_app_settings->num_ext_attrs)); x++)
{
attrs[xx+x] = p_app_settings->ext_attrs[x].attr_id;
}
HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
p_app_settings->num_attrs, p_app_settings->attrs,
p_app_settings->num_ext_attrs, p_app_settings->ext_attrs);
- get_player_app_setting_cmd (xx + x, attrs);
+ if(xx+x > AVRC_MAX_APP_ATTR_SIZE)
+ {
+ get_player_app_setting_cmd (AVRC_MAX_APP_ATTR_SIZE, attrs);
+ }
+ else
+ {
+ get_player_app_setting_cmd (xx + x, attrs);
+ }
/* Free the application settings information after sending to
* application.
@@ -2988,7 +5042,7 @@
uint8_t accepted = 0;
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
/* For timeout pmeta_msg will be NULL, else we need to
* check if this is accepted by TG
@@ -3018,7 +5072,7 @@
btrc_element_attr_val_t *p_attr =
(btrc_element_attr_val_t *)osi_calloc(buf_size);
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
for (int i = 0; i < p_rsp->num_attr; i++) {
p_attr[i].attr_id = p_rsp->p_attrs[i].attr_id;
@@ -3046,7 +5100,9 @@
AVRC_MEDIA_ATTR_ID_GENRE,
AVRC_MEDIA_ATTR_ID_PLAYING_TIME
};
- get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+ /* Fix for below Klowkwork Issue at line 4996
+ * Array 'attr_list' of size 7 may use index value(s) 7 */
+ get_element_attribute_cmd (sizeof(attr_list)/sizeof(UINT32), attr_list);
} else {
BTIF_TRACE_ERROR("%s: Error in get element attr procedure %d",
__func__, p_rsp->status);
@@ -3066,12 +5122,12 @@
{
bt_bdaddr_t rc_addr;
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ bdcpy(rc_addr.address, btif_rc_cb[0].rc_addr);
if (p_rsp->status == AVRC_STS_NO_ERROR)
{
HAL_CBACK(bt_rc_ctrl_callbacks, play_position_changed_cb,
- &rc_addr, p_rsp->song_len, p_rsp->song_pos);
+ &rc_addr, p_rsp->song_len, p_rsp->song_pos, p_rsp->play_status);
}
else
{
@@ -3242,6 +5298,10 @@
}
#endif
+static void btif_rc_handler_wrapper(UINT16 event, char* p_param)
+{
+ btif_rc_handler((tBTA_AV_EVT)event, (tBTA_AV *)p_param);
+}
/***************************************************************************
**
** Function cleanup
@@ -3253,16 +5313,10 @@
***************************************************************************/
static void cleanup()
{
- BTIF_TRACE_EVENT("## %s ##", __FUNCTION__);
- close_uinput();
- if (bt_rc_callbacks)
- {
- bt_rc_callbacks = NULL;
- }
- alarm_free(btif_rc_cb.rc_play_status_timer);
- memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
- lbl_destroy();
- BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
+ BTIF_TRACE_EVENT("## RC: %s ##", __FUNCTION__);
+ btif_transfer_context(btif_rc_handler_wrapper, BTIF_AV_CLEANUP_REQ_EVT,
+ NULL, 0, NULL);
+ BTIF_TRACE_EVENT("## RC: %s ## completed", __FUNCTION__);
}
/***************************************************************************
@@ -3282,7 +5336,7 @@
{
bt_rc_ctrl_callbacks = NULL;
}
- alarm_free(btif_rc_cb.rc_play_status_timer);
+ alarm_free(btif_rc_cb[0].rc_play_status_timer);
memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
lbl_destroy();
BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
@@ -3320,7 +5374,7 @@
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_CAPABILITIES, p_transaction);
@@ -3368,7 +5422,7 @@
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_ATTR, p_transaction);
@@ -3418,7 +5472,7 @@
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_VALUES, p_transaction);
@@ -3462,7 +5516,7 @@
avrc_cmd.get_cur_app_val.num_attr = num_attrib;
avrc_cmd.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
- for (count = 0; count < num_attrib; count++)
+ for (count = 0; (count < num_attrib) && (count < AVRC_MAX_APP_ATTR_SIZE); count++)
{
avrc_cmd.get_cur_app_val.attrs[count] = attrib_ids[count];
}
@@ -3472,7 +5526,7 @@
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_CUR_PLAYER_APP_VALUE, p_transaction);
@@ -3529,7 +5583,7 @@
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_control_command_timer (AVRC_PDU_SET_PLAYER_APP_VALUE, p_transaction);
@@ -3549,63 +5603,6 @@
/***************************************************************************
**
-** Function get_player_app_setting_attr_text_cmd
-**
-** Description Get text description for app attribute
-**
-** Returns void
-**
-***************************************************************************/
-static bt_status_t get_player_app_setting_attr_text_cmd (UINT8 *attrs, UINT8 num_attrs)
-{
- tAVRC_STS status = BT_STATUS_UNSUPPORTED;
- rc_transaction_t *p_transaction = NULL;
- int count = 0;
-#if (AVRC_CTLR_INCLUDED == TRUE)
- tAVRC_COMMAND avrc_cmd = {0};
- BT_HDR *p_msg = NULL;
- bt_status_t tran_status;
- CHECK_RC_CONNECTED
-
- BTIF_TRACE_DEBUG("%s: num attrs %d", __FUNCTION__, num_attrs);
-
- tran_status = get_transaction(&p_transaction);
- if (BT_STATUS_SUCCESS != tran_status)
- return BT_STATUS_FAIL;
-
- avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
- avrc_cmd.get_app_attr_txt.opcode = AVRC_OP_VENDOR;
- avrc_cmd.get_app_attr_txt.num_attr = num_attrs;
-
- for (count = 0; count < num_attrs; count++)
- {
- avrc_cmd.get_app_attr_txt.attrs[count] = attrs[count];
- }
- status = AVRC_BldCommand(&avrc_cmd, &p_msg);
- if (status == AVRC_STS_NO_ERROR)
- {
- UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
- BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
- __FUNCTION__, p_transaction->lbl);
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
- AVRC_CMD_STATUS, data_start, p_msg->len);
- osi_free(p_msg);
- status = BT_STATUS_SUCCESS;
- start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT, p_transaction);
- }
- else
- {
- BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __FUNCTION__, status);
- }
- osi_free(p_msg);
-#else
- BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
-#endif
- return status;
-}
-
-/***************************************************************************
-**
** Function get_player_app_setting_val_text_cmd
**
** Description Get text description for app attribute values
@@ -3646,7 +5643,7 @@
__FUNCTION__, p_transaction->lbl);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle, p_transaction->lbl,
AVRC_CMD_STATUS, data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT, p_transaction);
@@ -3698,7 +5695,7 @@
__FUNCTION__, label);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, label, AVRC_CMD_NOTIF,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle, label, AVRC_CMD_NOTIF,
data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
}
@@ -3759,7 +5756,7 @@
__FUNCTION__, p_transaction->lbl);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle, p_transaction->lbl,
AVRC_CMD_STATUS, data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_ELEMENT_ATTR,
@@ -3813,7 +5810,7 @@
__FUNCTION__, p_transaction->lbl);
if (p_msg != NULL)
{
- BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,
+ BTA_AvVendorCmd(btif_rc_cb[0].rc_handle,p_transaction->lbl,
AVRC_CMD_STATUS, data_start, p_msg->len);
status = BT_STATUS_SUCCESS;
start_status_command_timer (AVRC_PDU_GET_PLAY_STATUS, p_transaction);
@@ -3855,15 +5852,15 @@
avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
avrc_rsp.volume.status = AVRC_STS_NO_ERROR;
avrc_rsp.volume.volume = abs_vol;
- status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+ status = AVRC_BldResponse(btif_rc_cb[0].rc_handle, &avrc_rsp, &p_msg);
if (status == AVRC_STS_NO_ERROR)
{
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
- __FUNCTION__, btif_rc_cb.rc_vol_label);
+ __FUNCTION__, btif_rc_cb[0].rc_vol_label);
if (p_msg != NULL)
{
- BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+ BTA_AvVendorRsp(btif_rc_cb[0].rc_handle, label,
BTA_AV_RSP_ACCEPT, data_start, p_msg->len, 0);
status = BT_STATUS_SUCCESS;
}
@@ -3905,12 +5902,12 @@
avrc_rsp.reg_notif.param.volume = abs_vol;
avrc_rsp.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
- status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+ status = AVRC_BldResponse(btif_rc_cb[0].rc_handle, &avrc_rsp, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__func__, label);
UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
- BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+ BTA_AvVendorRsp(btif_rc_cb[0].rc_handle, label,
(rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM) ?
AVRC_RSP_INTERIM : AVRC_RSP_CHANGED,
data_start, p_msg->len, 0);
@@ -3945,7 +5942,7 @@
BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
key_code, key_state);
CHECK_RC_CONNECTED
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ if (btif_rc_cb[0].rc_features & BTA_AV_FEAT_RCTG)
{
bt_status_t tran_status = get_transaction(&p_transaction);
if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction)) {
@@ -3954,7 +5951,7 @@
UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
*(start)++ = 0;
UINT8_TO_BE_STREAM(start, key_code);
- BTA_AvRemoteVendorUniqueCmd(btif_rc_cb.rc_handle,
+ BTA_AvRemoteVendorUniqueCmd(btif_rc_cb[0].rc_handle,
p_transaction->lbl,
(tBTA_AV_STATE)key_state, buffer,
AVRC_PASS_THRU_GROUP_LEN);
@@ -3991,17 +5988,22 @@
static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ /* Controller is used only for Certification purposes.
+ * In normal case AVRCP controller will not be used, hence
+ * updating this is required.
+ */
+ int index = BTIF_RC_DEFAULT_INDEX; //For RC it should be 0
#if (AVRC_CTLR_INCLUDED == TRUE)
CHECK_RC_CONNECTED
rc_transaction_t *p_transaction=NULL;
BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
key_code, key_state);
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ if (btif_rc_cb[index].rc_features & BTA_AV_FEAT_RCTG)
{
bt_status_t tran_status = get_transaction(&p_transaction);
if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction)
{
- BTA_AvRemoteCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ BTA_AvRemoteCmd(btif_rc_cb[index].rc_handle, p_transaction->lbl,
(tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
status = BT_STATUS_SUCCESS;
BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA", __FUNCTION__);
@@ -4027,15 +6029,23 @@
sizeof(bt_rc_interface),
init,
get_play_status_rsp,
- NULL, /* list_player_app_attr_rsp */
- NULL, /* list_player_app_value_rsp */
- NULL, /* get_player_app_value_rsp */
- NULL, /* get_player_app_attr_text_rsp */
- NULL, /* get_player_app_value_text_rsp */
+ list_player_app_attr_rsp, /* list_player_app_attr_rsp */
+ list_player_app_value_rsp, /* list_player_app_value_rsp */
+ get_player_app_value_rsp, /* get_player_app_value_rsp PDU 0x13*/
+ get_player_app_attr_text_rsp, /* get_player_app_attr_text_rsp */
+ get_player_app_value_text_rsp,/* get_player_app_value_text_rsp */
get_element_attr_rsp,
- NULL, /* set_player_app_value_rsp */
+ set_player_app_value_rsp, /* set_player_app_value_rsp */
register_notification_rsp,
set_volume,
+ get_folderitem_rsp,
+ set_addrplayer_rsp,
+ set_browseplayer_rsp,
+ changepath_rsp,
+ playitem_rsp,
+ get_itemattr_rsp,
+ is_device_active_in_handoff,
+ get_total_items_rsp,
cleanup,
};
@@ -4230,7 +6240,11 @@
*******************************************************************************/
void lbl_destroy()
{
- pthread_mutex_destroy(&(device.lbllock));
+ if (!pthread_mutex_destroy(&(device.lbllock)))
+ {
+ device.lbllock_destroyed = TRUE;
+ BTIF_TRACE_EVENT(" %s: lbllock destroy success ", __FUNCTION__);
+ }
}
/*******************************************************************************
diff --git a/btif/src/btif_rfcomm.c b/btif/src/btif_rfcomm.c
new file mode 100644
index 0000000..9d799c8
--- /dev/null
+++ b/btif/src/btif_rfcomm.c
@@ -0,0 +1,247 @@
+/*
+ *Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the followin conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the followin disclaimer.
+ * * Redistributions in binary form must reproduce the above copyriht
+ * notice, this list of conditions and the followin disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <hardware/bluetooth.h>
+#include "port_api.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "bt_testapp.h"
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+#include "btif_api.h"
+#include "bt_utils.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+#define RFC_BUFFER_SIZE 20000
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+static void bt_rfc_mmt_cback (UINT32 code, UINT16 handle); //rfc
+static void bt_rfc_mmt_cback_msc_data (UINT32 code, UINT16 handle);
+static void bt_rfc_mmt_server_cback (UINT32 code, UINT16 handle);//rfc
+static int bt_rfc_data_cback (UINT16 port_handle, void *data, UINT16 len);//rfc
+static void bt_rfc_port_cback (UINT32 code, UINT16 handle);//rfc
+void rdut_rfcomm (UINT8 server);
+void rdut_rfcomm_test_interface (tRFC *input);
+static UINT16 rfc_handle = 0;
+char buffer[RFC_BUFFER_SIZE];
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+static const btrfcomm_interface_t btrfcInterface = {
+ sizeof(btrfcomm_interface_t),
+ NULL,
+ rdut_rfcomm,
+ rdut_rfcomm_test_interface,
+ NULL,
+ NULL,
+};
+
+const btrfcomm_interface_t *btif_rfcomm_get_interface(void)
+{
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ ALOGI("\n%s\n", __FUNCTION__);
+ return &btrfcInterface;
+}
+
+static void bt_rfc_mmt_cback (UINT32 code, UINT16 handle)
+{
+ UINT16 length = 0;
+ int count = 100;//Number of frames to be send
+
+ ALOGI("dut_rfc_mmt_cback %d, %x", code, handle);
+ memset(buffer , 0x01 ,10000); //RFC data
+ if (code == PORT_SUCCESS)
+ {
+ PORT_WriteData (handle, buffer, 10000, &length);
+ --count;
+ ALOGI("rfc mmt length: %d", length);
+ }
+}
+
+static void bt_rfc_mmt_cback_msc_data (UINT32 code, UINT16 handle)
+{
+ ALOGI("dut_rfc_mmt_cback_msc_data %d, %x", code, handle);
+}
+
+static void bt_rfc_send_data ( UINT16 handle)
+{
+ UINT16 length = 0;
+
+ ALOGI("bt_rfc_send_data %d", handle);
+ memset(buffer , 0x01 ,10000); //RFC data
+ PORT_WriteData (handle, buffer, 10000, &length);
+}
+
+static void bt_rfc_mmt_server_cback (UINT32 code, UINT16 handle)
+{
+ ALOGI("dut_rfc_mmt_Server_cback %d, %x", code, handle);
+}
+
+
+static int bt_rfc_data_cback (UINT16 port_handle, void *data, UINT16 len)
+{
+ ALOGI("dut_rfc_data_cback"); // Called from PORT_DataInd
+ return 0;
+}
+
+static void bt_rfc_port_cback (UINT32 code, UINT16 handle)
+{
+ ALOGI("bt_rfc_port_cback");
+}
+
+/*static void bdcpy (BD_ADDR a, const BD_ADDR b)
+{
+ int i;
+ for (i = BD_ADDR_LEN; i != 0; i--)
+ {
+ *a++ = *b++;
+ }
+} */
+
+
+
+void rdut_rfcomm (UINT8 server)
+{
+ UINT16 handle;
+ int status = -1;
+ BD_ADDR remote_bd = {0x00, 0x15, 0x83, 0x0A, 0x0E, 0x1F};
+ BD_ADDR any_add = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ ALOGI("dut_rfc_mode:%d",server);
+ if (server == 0)
+ {
+ BTM_SetSecurityLevel (TRUE, "", 0, 0, 0x03, 3/*BTM_SEC_PROTO_RFCOMM*/, 20);
+ status = RFCOMM_CreateConnection(0x0020, 20, FALSE, 256, (UINT8 *)remote_bd,
+ &handle, bt_rfc_mmt_cback);
+ rfc_handle = handle;
+ }
+ else if (server == 1)
+ {
+ BTM_SetSecurityLevel (FALSE, "", 0, 0, 0x03, 3/*BTM_SEC_PROTO_RFCOMM */, 20);
+ BTM_SetConnectability (1, 0, 0); //Pae Mode , window , interval
+ status = RFCOMM_CreateConnection (0x0020, 20, TRUE, 256, (UINT8 *)any_add,
+ &handle, bt_rfc_mmt_server_cback);
+ rfc_handle = handle;
+ }
+ else if (server == 3)
+ {
+ ALOGI("dut RFCOMM RemoveConnection");
+ RFCOMM_RemoveConnection(rfc_handle);
+ }
+ if (status == PORT_SUCCESS)
+ {
+ ALOGI("dut_setdata_callback");
+ PORT_SetDataCallback (handle, bt_rfc_data_cback);
+ PORT_SetEventCallback(handle, bt_rfc_port_cback);
+ }
+}
+
+void rdut_rfcomm_test_interface (tRFC *input)
+{
+ BD_ADDR remote_bd;
+ UINT16 handle;
+ int status = -1;
+ BD_ADDR any_add = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ switch (input->param)
+ {
+ case RFC_TEST_CLIENT:
+ {
+ bdcpy (remote_bd, input->data.conn.bdadd.address);
+ BTM_SetSecurityLevel (TRUE, "", 0, 0, 0x03, 3/*BTM_SEC_PROTO_RFCOMM */,
+ input->data.conn.scn);
+ status = RFCOMM_CreateConnection(0x0020, input->data.conn.scn, FALSE, 256,
+ (UINT8 *)remote_bd,&handle, bt_rfc_mmt_cback);
+ rfc_handle = handle;
+ }
+ break;
+ case RFC_TEST_CLIENT_TEST_MSC_DATA:
+ {
+ bdcpy (remote_bd, input->data.conn.bdadd.address);
+ BTM_SetSecurityLevel (TRUE, "", 0, 0, 0x03, 3/*BTM_SEC_PROTO_RFCOMM */,
+ input->data.conn.scn);
+ status = RFCOMM_CreateConnection(0x0020, input->data.conn.scn, FALSE, 256,
+ (UINT8 *)remote_bd, &handle, bt_rfc_mmt_cback_msc_data);
+ rfc_handle = handle;
+ }
+ break;
+ case RFC_TEST_FRAME_ERROR:
+ {
+ /* Framing Error */
+ PORT_SendError (rfc_handle, 0x08);
+ }
+ break;
+ case RFC_TEST_ROLE_SWITCH:
+ {
+ /* Role Switch */
+ BTM_SwitchRole(input->data.role_switch.bdadd.address, input->data.role_switch.role,
+ NULL);
+ }
+ break;
+ case RFC_TEST_SERVER:
+ {
+ BTM_SetSecurityLevel (FALSE, "", 0, 0, 0x03, 3/*BTM_SEC_PROTO_RFCOMM */, 20);
+ BTM_SetConnectability (1, 0, 0); //Pae Mode , window , interval
+ status = RFCOMM_CreateConnection (0x0020, 20, TRUE, 256, (UINT8 *)any_add,
+ &handle, bt_rfc_mmt_server_cback);
+ rfc_handle = handle;
+ }
+ break;
+ case RFC_TEST_DISCON:
+ {
+ ALOGI("dut RFCOMM RemoveConnection");
+ RFCOMM_RemoveConnection(rfc_handle);
+ }
+ break;
+ case RFC_TEST_WRITE_DATA:
+ {
+ ALOGI("dut RFC_TEST_WRITE_DATA");
+ bt_rfc_send_data(rfc_handle);
+ }
+ break;
+ default :
+ ALOGI("dut RFCOMM Unreconised command");
+ break;
+ }
+ if (status == PORT_SUCCESS)
+ {
+ ALOGI("dut_setdata_callback");
+ PORT_SetDataCallback (handle, bt_rfc_data_cback);
+ PORT_SetEventCallback(handle, bt_rfc_port_cback);
+ }
+}
diff --git a/btif/src/btif_sdp_server.c b/btif/src/btif_sdp_server.c
index 90d74cf..7ecaa33 100644
--- a/btif/src/btif_sdp_server.c
+++ b/btif/src/btif_sdp_server.c
@@ -41,6 +41,7 @@
#include "btif_util.h"
#include "osi/include/allocator.h"
#include "utl.h"
+#include "stack_manager.h"
static pthread_mutex_t sdp_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -243,6 +244,8 @@
/***
* Use this to get a reference to a SDP slot AND change the state to
* SDP_RECORD_CREATE_INITIATED.
+ *
+ * Caller of this function should held mutex with sdp_lock
*/
static const sdp_slot_t* start_create_sdp(int id) {
sdp_slot_t* sdp_slot;
@@ -250,14 +253,12 @@
APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
return NULL;
}
- pthread_mutex_lock(&sdp_lock);
if(sdp_slots[id].state == SDP_RECORD_ALLOCED) {
sdp_slot = &(sdp_slots[id]);
} else {
/* The record have been removed before this event occurred - e.g. deinit */
sdp_slot = NULL;
}
- pthread_mutex_unlock(&sdp_lock);
if(sdp_slot == NULL) {
APPL_TRACE_ERROR("%s() failed - state for id %d is "
"sdp_slots[id].state = %d expected %d", __func__,
@@ -265,11 +266,11 @@
}
return sdp_slot;
}
-
+/***
+ * Caller of this function should held mutex with sdp_lock
+ */
static void set_sdp_handle(int id, int handle) {
- pthread_mutex_lock(&sdp_lock);
sdp_slots[id].sdp_handle = handle;
- pthread_mutex_unlock(&sdp_lock);
BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __FUNCTION__, id, handle);
}
@@ -292,6 +293,11 @@
bt_status_t remove_sdp_record(int record_id) {
int handle;
+ if (!stack_manager_get_interface()->get_stack_is_running()) {
+ BTIF_TRACE_DEBUG("Sdp Server %s - Stack closed", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+
/* Get the Record handle, and free the slot */
handle = free_sdp_slot(record_id);
BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x",
@@ -319,6 +325,7 @@
* 4) What to do at fail?
* */
BTIF_TRACE_DEBUG("Sdp Server %s", __FUNCTION__);
+ pthread_mutex_lock(&sdp_lock);
const sdp_slot_t* sdp_slot = start_create_sdp(id);
/* In the case we are shutting down, sdp_slot is NULL */
if(sdp_slot != NULL) {
@@ -350,6 +357,7 @@
set_sdp_handle(id, handle);
}
}
+ pthread_mutex_unlock(&sdp_lock);
}
void on_remove_record_event(int handle) {
diff --git a/btif/src/btif_sm.c b/btif/src/btif_sm.c
index aa856c5..08bcba2 100644
--- a/btif/src/btif_sm.c
+++ b/btif/src/btif_sm.c
@@ -37,6 +37,7 @@
******************************************************************************/
typedef struct {
btif_sm_state_t state;
+ int index;
btif_sm_handler_t *p_handlers;
} btif_sm_cb_t;
@@ -57,7 +58,8 @@
**
******************************************************************************/
-btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers, btif_sm_state_t initial_state)
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers, btif_sm_state_t initial_state,
+ int index)
{
if (p_handlers == NULL) {
BTIF_TRACE_ERROR("%s : p_handlers is NULL", __FUNCTION__);
@@ -67,9 +69,10 @@
btif_sm_cb_t *p_cb = (btif_sm_cb_t *)osi_malloc(sizeof(btif_sm_cb_t));
p_cb->state = initial_state;
p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;
+ p_cb->index = index;
/* Send BTIF_SM_ENTER_EVT to the initial state */
- p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);
+ p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL, index);
return (btif_sm_handle_t)p_cb;
}
@@ -107,7 +110,6 @@
btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle)
{
btif_sm_cb_t *p_cb = (btif_sm_cb_t*)handle;
-
if (p_cb == NULL)
{
BTIF_TRACE_ERROR("%s : Invalid handle", __FUNCTION__);
@@ -141,7 +143,7 @@
return BT_STATUS_FAIL;
}
- if (p_cb->p_handlers[p_cb->state](event, data) == FALSE)
+ if (p_cb->p_handlers[p_cb->state](event, data, p_cb->index) == FALSE)
return BT_STATUS_UNHANDLED;
return status;
@@ -172,14 +174,14 @@
}
/* Send exit event to the current state */
- if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL) == FALSE)
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL, p_cb->index) == FALSE)
status = BT_STATUS_UNHANDLED;
/* Change to the new state */
p_cb->state = state;
/* Send enter event to the new state */
- if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL) == FALSE)
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL, p_cb->index) == FALSE)
status = BT_STATUS_UNHANDLED;
return status;
diff --git a/btif/src/btif_smp.c b/btif/src/btif_smp.c
new file mode 100644
index 0000000..03f6473
--- /dev/null
+++ b/btif/src/btif_smp.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+#include "bt_utils.h"
+#include "smp_api.h"
+
+#ifdef TEST_APP_INTERFACE
+#include <bt_testapp.h>
+static void SmpInit(void)
+{
+ SMP_Init();
+}
+static BOOLEAN SmpRegister(tSMP_CALLBACK *p_cback)
+{
+ BOOLEAN Ret = 0;
+ Ret = SMP_Register(p_cback);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+ return Ret;
+
+}
+
+static tSMP_STATUS SmpPair(BD_ADDR bd_addr)
+{
+ tSMP_STATUS Ret = 0;
+ Ret = SMP_Pair(bd_addr);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+ return Ret;
+}
+
+static BOOLEAN PairCancel(BD_ADDR bd_addr)
+{
+ BOOLEAN Ret = 0;
+ Ret = SMP_PairCancel(bd_addr);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+ return Ret;
+}
+
+static void SecurityGrant(BD_ADDR bd_addr, UINT8 res)
+{
+ SMP_SecurityGrant(bd_addr, res);
+ printf("%s:: executed \n", __FUNCTION__);
+}
+
+static void PasskeyReply(BD_ADDR bd_addr, UINT8 res, UINT32 passkey)
+{
+ SMP_PasskeyReply(bd_addr, res, passkey);
+ printf("%s:: executed \n", __FUNCTION__);
+}
+
+static BOOLEAN Encrypt(UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out)
+{
+ BOOLEAN Ret = 0;
+ Ret = SMP_Encrypt(key, key_len, plain_text, pt_len, p_out);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+ return Ret;
+}
+
+static const btsmp_interface_t btsmpInterface = {
+ sizeof(btsmp_interface_t),
+ SmpInit,
+ SmpRegister,
+ SmpPair,
+ PairCancel,
+ SecurityGrant,
+ PasskeyReply,
+ Encrypt
+};
+
+const btsmp_interface_t *btif_smp_get_interface(void)
+{
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ printf("\n%s\n", __FUNCTION__);
+ return &btsmpInterface;
+}
+
+#endif //TEST_APP_INTERFACE
diff --git a/btif/src/btif_sock.c b/btif/src/btif_sock.c
index 3b43545..7acbcbe 100644
--- a/btif/src/btif_sock.c
+++ b/btif/src/btif_sock.c
@@ -37,6 +37,10 @@
static bt_status_t btsock_listen(btsock_type_t type, const char *service_name, const uint8_t *uuid, int channel, int *sock_fd, int flags, int app_uid);
static bt_status_t btsock_connect(const bt_bdaddr_t *bd_addr, btsock_type_t type, const uint8_t *uuid, int channel, int *sock_fd, int flags, int app_uid);
+static bt_status_t btsock_get_sockopt(btsock_type_t type, int channel, btsock_option_type_t option_name,
+ void *option_value, int *option_len);
+static bt_status_t btsock_set_sockopt(btsock_type_t type, int channel, btsock_option_type_t option_name,
+ void *option_value, int option_len);
static void btsock_signaled(int fd, int type, int flags, uint32_t user_id);
static int thread_handle = -1;
@@ -46,10 +50,11 @@
static btsock_interface_t interface = {
sizeof(interface),
btsock_listen,
- btsock_connect
+ btsock_connect,
+ btsock_get_sockopt,
+ btsock_set_sockopt
};
-
return &interface;
}
@@ -175,6 +180,69 @@
return status;
}
+static bt_status_t btsock_get_sockopt(btsock_type_t type, int channel, btsock_option_type_t option_name,
+ void *option_value, int *option_len)
+{
+ if((channel <= 0) || (option_value == NULL) || (option_len == NULL))
+ {
+ BTIF_TRACE_ERROR("invalid parameters, channel:%d, option_value:%p, option_len:%p", channel,
+ option_value, option_len);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ bt_status_t status = BT_STATUS_FAIL;
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_get_sockopt(channel, option_name, option_value, option_len);
+ break;
+ case BTSOCK_L2CAP:
+ BTIF_TRACE_ERROR("bt l2cap socket type not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ case BTSOCK_SCO:
+ BTIF_TRACE_ERROR("bt sco socket not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ default:
+ BTIF_TRACE_ERROR("unknown bt socket type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+
+static bt_status_t btsock_set_sockopt(btsock_type_t type, int channel, btsock_option_type_t option_name,
+ void *option_value, int option_len)
+{
+ if((channel <= 0) || (option_value == NULL))
+ {
+ BTIF_TRACE_ERROR("invalid parameters, channel:%d, option_value:%p", channel, option_value);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ bt_status_t status = BT_STATUS_FAIL;
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_set_sockopt(channel, option_name, option_value, option_len);
+ break;
+ case BTSOCK_L2CAP:
+ BTIF_TRACE_ERROR("bt l2cap socket type not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ case BTSOCK_SCO:
+ BTIF_TRACE_ERROR("bt sco socket not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ default:
+ BTIF_TRACE_ERROR("unknown bt socket type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+
static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) {
switch (type) {
case BTSOCK_RFCOMM:
diff --git a/btif/src/btif_sock_l2cap.c b/btif/src/btif_sock_l2cap.c
index 03c3ef4..4d830ad 100644
--- a/btif/src/btif_sock_l2cap.c
+++ b/btif/src/btif_sock_l2cap.c
@@ -90,7 +90,7 @@
static bt_status_t btSock_start_l2cap_server_l(l2cap_socket *sock);
-static pthread_mutex_t state_lock;
+static pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER;
l2cap_socket *socks = NULL;
static uid_set_t* uid_set = NULL;
@@ -276,7 +276,7 @@
else
{
// Only call if we are non server connections
- if (sock->handle && (sock->server == FALSE)) {
+ if ((sock->handle >= 0) && (sock->server == FALSE)) {
if (sock->fixed_chan)
BTA_JvL2capCloseLE(sock->handle);
else
@@ -287,6 +287,11 @@
BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
else
BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+
+ if (!sock->fixed_chan) {
+ APPL_TRACE_DEBUG("%s stopping L2CAP server channel %d", __func__, sock->channel);
+ BTA_JvL2capStopServer(sock->channel, UINT_TO_PTR(sock->id));
+ }
}
}
@@ -362,7 +367,6 @@
bt_status_t btsock_l2cap_init(int handle, uid_set_t* set)
{
APPL_TRACE_DEBUG("%s handle = %d", __func__);
- pthread_mutex_init(&state_lock, NULL);
pthread_mutex_lock(&state_lock);
pth = handle;
socks = NULL;
@@ -379,7 +383,6 @@
while (socks)
btsock_l2cap_free_l(socks);
pthread_mutex_unlock(&state_lock);
- pthread_mutex_destroy(&state_lock);
return BT_STATUS_SUCCESS;
}
@@ -466,20 +469,24 @@
// Mutex locked by caller
accept_rs = btsock_l2cap_alloc_l(sock->name, (const bt_bdaddr_t*)p_open->rem_bda, FALSE, 0);
- accept_rs->connected = TRUE;
- accept_rs->security = sock->security;
- accept_rs->fixed_chan = sock->fixed_chan;
- accept_rs->channel = sock->channel;
- accept_rs->handle = sock->handle;
- accept_rs->app_uid = sock->app_uid;
- sock->handle = -1; /* We should no longer associate this handle with the server socket */
- accept_rs->is_le_coc = sock->is_le_coc;
+ if (accept_rs) {
+ accept_rs->connected = TRUE;
+ accept_rs->security = sock->security;
+ accept_rs->fixed_chan = sock->fixed_chan;
+ accept_rs->channel = sock->channel;
+ accept_rs->handle = sock->handle;
+ accept_rs->app_uid = sock->app_uid;
+ sock->handle = -1; /* We should no longer associate this handle with the server socket */
+ accept_rs->is_le_coc = sock->is_le_coc;
/* Swap IDs to hand over the GAP connection to the accepted socket, and start a new server on
the newly create socket ID. */
- new_listen_id = accept_rs->id;
- accept_rs->id = sock->id;
- sock->id = new_listen_id;
+ new_listen_id = accept_rs->id;
+ accept_rs->id = sock->id;
+ sock->id = new_listen_id;
+ } else {
+ APPL_TRACE_ERROR("Memory not allocated for accept_rs..");
+ }
if (accept_rs) {
//start monitor the socket
@@ -822,19 +829,21 @@
* and this function is called with the newly allocated PSM.
*/
void on_l2cap_psm_assigned(int id, int psm) {
- l2cap_socket *sock;
/* Setup ETM settings:
* mtu will be set below */
pthread_mutex_lock(&state_lock);
- sock = btsock_l2cap_find_by_id_l(id);
- sock->channel = psm;
+ l2cap_socket *sock = btsock_l2cap_find_by_id_l(id);
- if(btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS) {
- btsock_l2cap_free_l(sock);
+ if (sock) {
+ sock->channel = psm;
+
+ if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS)
+ btsock_l2cap_free_l(sock);
+ } else {
+ APPL_TRACE_ERROR("%s: Error: sock is null", __func__);
}
pthread_mutex_unlock(&state_lock);
-
}
static bt_status_t btSock_start_l2cap_server_l(l2cap_socket *sock) {
diff --git a/btif/src/btif_sock_rfc.c b/btif/src/btif_sock_rfc.c
index 0a971fd..dc014f0 100644
--- a/btif/src/btif_sock_rfc.c
+++ b/btif/src/btif_sock_rfc.c
@@ -57,6 +57,10 @@
* L2CAP functions from this file. */
#include "btif_sock_l2cap.h"
+#define MODEM_SIGNAL_DTRDSR 0x01
+#define MODEM_SIGNAL_RTSCTS 0x02
+#define MODEM_SIGNAL_RI 0x04
+#define MODEM_SIGNAL_DCD 0x08
#define MAX_RFC_CHANNEL 30 // Maximum number of RFCOMM channels (1-30 inclusive).
#define MAX_RFC_SESSION 7 // Maximum number of devices we can have an RFCOMM connection with.
@@ -128,7 +132,6 @@
void btsock_rfc_cleanup(void) {
pth = -1;
- uid_set = NULL;
pthread_mutex_lock(&slot_lock);
for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) {
@@ -170,6 +173,27 @@
return (slot == -1) ? NULL : &rfc_slots[slot];
}
+static rfc_slot_t* find_rfc_slot_by_scn(int scn)
+{
+ int i;
+ if(scn > 0)
+ {
+ /* traverse it from the last entry, as incase of
+ * server two entries will exist with the same scn
+ * and the later entry is valid
+ */
+ for(i = MAX_RFC_CHANNEL-1; i >= 0; i--)
+ {
+ if(rfc_slots[i].scn == scn)
+ {
+ if(rfc_slots[i].id)
+ return &rfc_slots[i];
+ }
+ }
+ }
+ return NULL;
+}
+
static bool is_requesting_sdp(void) {
for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
if (rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request)
@@ -375,6 +399,96 @@
return status;
}
+bt_status_t btsock_rfc_get_sockopt(int channel, btsock_option_type_t option_name,
+ void *option_value, int *option_len)
+{
+ int status = BT_STATUS_FAIL;
+
+ APPL_TRACE_DEBUG("btsock_rfc_get_sockopt channel is %d ", channel);
+ if((channel < 1) || (channel > 30) || (option_value == NULL) || (option_len == NULL))
+ {
+ APPL_TRACE_ERROR("invalid rfc channel:%d or option_value:%p, option_len:%p",
+ channel, option_value, option_len);
+ return BT_STATUS_PARM_INVALID;
+ }
+ rfc_slot_t* rs = find_rfc_slot_by_scn(channel);
+ if((rs) && ((option_name == BTSOCK_OPT_GET_MODEM_BITS)))
+ {
+ if(PORT_SUCCESS == PORT_GetModemStatus(rs->rfc_port_handle, (UINT8 *)option_value))
+ {
+ *option_len = sizeof(UINT8);
+ status = BT_STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
+bt_status_t btsock_rfc_set_sockopt(int channel, btsock_option_type_t option_name,
+ void *option_value, int option_len)
+{
+ int status = BT_STATUS_FAIL;
+
+ APPL_TRACE_DEBUG("btsock_rfc_get_sockopt channel is %d ", channel);
+ if((channel < 1) || (channel > 30) || (option_value == NULL) || (option_len <= 0)
+ || (option_len > (int)sizeof(UINT8)))
+ {
+ APPL_TRACE_ERROR("invalid rfc channel:%d or option_value:%p, option_len:%d",
+ channel, option_value, option_len);
+ return BT_STATUS_PARM_INVALID;
+ }
+ rfc_slot_t* rs = find_rfc_slot_by_scn(channel);
+ if((rs) && ((option_name == BTSOCK_OPT_SET_MODEM_BITS)))
+ {
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DTRDSR)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_DTRDSR))
+ return status;
+ }
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RTSCTS)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_CTSRTS))
+ return status;
+ }
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RI)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_RI))
+ return status;
+ }
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DCD)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_DCD))
+ return status;
+ }
+ status = BT_STATUS_SUCCESS;
+ }
+ else if((rs) && ((option_name == BTSOCK_OPT_CLR_MODEM_BITS)))
+ {
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DTRDSR)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_DTRDSR))
+ return status;
+ }
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RTSCTS)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_CTSRTS))
+ return status;
+ }
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RI)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_RI))
+ return status;
+ }
+ if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DCD)
+ {
+ if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_DCD))
+ return status;
+ }
+ status = BT_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
static int create_server_sdp_record(rfc_slot_t *slot) {
if(slot->scn == 0) {
return false;
@@ -437,13 +551,15 @@
return sock_send_all(slot->fd, (const uint8_t*)&slot->scn, sizeof(slot->scn)) == sizeof(slot->scn);
}
-static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd) {
+static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status,
+ int send_fd, int tx_mtu)
+{
sock_connect_signal_t cs;
cs.size = sizeof(cs);
cs.bd_addr = *addr;
cs.channel = channel;
cs.status = status;
- cs.max_rx_packet_size = 0; // not used for RFCOMM
+ cs.max_rx_packet_size = tx_mtu;
cs.max_tx_packet_size = 0; // not used for RFCOMM
if (send_fd == INVALID_FD)
return sock_send_all(fd, (const uint8_t *)&cs, sizeof(cs)) == sizeof(cs);
@@ -498,7 +614,8 @@
// Start monitoring the socket.
btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id);
btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id);
- send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd);
+ LOG_DEBUG(LOG_TAG, "%s mtu = %d ", __func__,p_open->mtu);
+ send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd, p_open->mtu);
accept_rs->app_fd = INVALID_FD; // Ownership of the application fd has been transferred.
new_listen_slot_id = srv_rs->id;
@@ -522,7 +639,8 @@
slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
memcpy(slot->addr.address, p_open->rem_bda, 6);
- if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1))
+ LOG_DEBUG(LOG_TAG, "%s mtu = %d ", __func__,p_open->mtu);
+ if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1, p_open->mtu))
slot->f.connected = true;
else
LOG_ERROR(LOG_TAG, "%s unable to send connect completion signal to caller.", __func__);
diff --git a/btif/src/btif_sock_sdp.c b/btif/src/btif_sock_sdp.c
index a1acaff..6980c7a 100644
--- a/btif/src/btif_sock_sdp.c
+++ b/btif/src/btif_sock_sdp.c
@@ -61,7 +61,7 @@
BTA_PBS_REALM_CHARSET, // realm_charset: Server only
BTA_PBS_USERID_REQ, // userid_req: Server only
(BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE), // supported_features
- BTA_PBS_REPOSIT_LOCAL, // supported_repositories
+ (BTA_PBS_REPOSIT_LOCAL | BTA_PBS_REPOSIT_SIM), // supported_repositories
};
// object format lookup table
@@ -93,9 +93,12 @@
#define RESERVED_SCN_PBS 19
#define RESERVED_SCN_OPS 12
+#define RESERVED_SCN_FTP 20
+#define RESERVED_SCN_DUN 25
#define UUID_MAX_LENGTH 16
#define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
+#define SPP_PROFILE_VERSION 0x0102
// Adds a protocol list and service name (if provided) to an SDP record given by
// |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
@@ -349,6 +352,11 @@
if (!SDP_AddServiceClassIdList(handle, 1, &service))
goto error;
+ // Add the FTP profile descriptor.
+ stage = "profile_descriptor_list";
+ if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_SERIAL_PORT,
+ SPP_PROFILE_VERSION))
+ goto error;
APPL_TRACE_DEBUG("add_spp_sdp: service registered successfully, "
"service_name: %s, handle 0x%08x)", name, handle);
@@ -361,6 +369,94 @@
return 0;
}
+static int add_ftp_sdp(const char *name, const int channel)
+{
+ APPL_TRACE_DEBUG("add_ftp_sdp: channel %d, service name %s", channel, name);
+
+ int handle = SDP_CreateRecord();
+ if (handle == 0) {
+ APPL_TRACE_ERROR("add_ftp_sdp: failed to create sdp record, "
+ "service_name: %s", name);
+ return 0;
+ }
+
+ // Create the base SDP record.
+ char *stage = "create_base_record";
+ if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
+ goto error;
+
+ // Add service class.
+ stage = "service_class";
+ uint16_t service = UUID_SERVCLASS_OBEX_FILE_TRANSFER;
+ if (!SDP_AddServiceClassIdList(handle, 1, &service))
+ goto error;
+
+ // Add the FTP profile descriptor.
+ stage = "profile_descriptor_list";
+ if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ 0x0101))
+ goto error;
+
+ // Notify the system that we've got a new service class UUID.
+ bta_sys_add_uuid(UUID_SERVCLASS_OBEX_FILE_TRANSFER);
+ APPL_TRACE_DEBUG("add_ftp_sdp: service registered successfully, "
+ "service_name: %s, handle 0x%08x)", name, handle);
+
+ return handle;
+
+error:
+ SDP_DeleteRecord(handle);
+ APPL_TRACE_ERROR("add_ftp_sdp: failed to register FTP service, "
+ "stage: %s, service_name: %s", stage, name);
+ return 0;
+
+}
+
+static int add_dun_sdp(const char *name, const int channel)
+{
+ APPL_TRACE_DEBUG("add_dun_sdp: channel %d, service name %s", channel, name);
+
+ int handle = SDP_CreateRecord();
+ if (handle == 0) {
+ APPL_TRACE_ERROR("add_dun_sdp: failed to create sdp record, "
+ "service_name: %s", name);
+ return 0;
+ }
+
+ // Create the base SDP record.
+ char *stage = "create_base_record";
+ if (!create_base_record(handle, name, channel, FALSE /* with_obex */))
+ goto error;
+
+ // Add service class.
+ UINT16 servclass[2];
+ servclass[0] = UUID_SERVCLASS_DIALUP_NETWORKING;
+ servclass[1] = UUID_SERVCLASS_GENERIC_NETWORKING;
+ stage = "service_class";
+ if (!SDP_AddServiceClassIdList(handle, 2, servclass))
+ goto error;
+
+ // Add the DUN profile descriptor.
+ stage = "profile_descriptor_list";
+ if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_DIALUP_NETWORKING,
+ 0x0101))
+ goto error;
+
+ // Notify the system that we've got a new service class UUID.
+ bta_sys_add_uuid(UUID_SERVCLASS_DIALUP_NETWORKING);
+ APPL_TRACE_DEBUG("add_dun_sdp: service registered successfully, "
+ "service_name: %s, handle 0x%08x)", name, handle);
+
+ return handle;
+
+error:
+ SDP_DeleteRecord(handle);
+ APPL_TRACE_ERROR("add_dun_sdp: failed to register DUN service, "
+ "stage: %s, service_name: %s", stage, name);
+ return 0;
+
+}
+
// Adds an RFCOMM SDP record for a service with the given |name|, |uuid|, and
// |channel|. This function attempts to identify the type of the service based
// upon its |uuid|, and will override the |channel| with a reserved channel
@@ -400,6 +496,10 @@
} else if (UUID_MATCHES(UUID_MAP_MAS,uuid)) {
// Record created by new SDP create record interface
handle = 0xff;
+ } else if (UUID_MATCHES(UUID_FTP,uuid)) {
+ handle = add_ftp_sdp(name, final_channel);
+ } else if (UUID_MATCHES(UUID_DUN,uuid)) {
+ handle = add_dun_sdp(name, final_channel);
} else {
handle = add_sdp_by_uuid(name, uuid, final_channel);
}
@@ -411,6 +511,8 @@
switch(channel) {
case RESERVED_SCN_PBS:
case RESERVED_SCN_OPS:
+ case RESERVED_SCN_FTP:
+ case RESERVED_SCN_DUN:
return TRUE;
}
@@ -422,6 +524,10 @@
return RESERVED_SCN_PBS;
} else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
return RESERVED_SCN_OPS;
+ } else if (UUID_MATCHES(UUID_FTP, uuid)) {
+ return RESERVED_SCN_FTP;
+ } else if (UUID_MATCHES(UUID_DUN, uuid)) {
+ return RESERVED_SCN_DUN;
}
return -1;
@@ -441,6 +547,14 @@
uuid = UUID_OBEX_OBJECT_PUSH;
break;
+ case RESERVED_SCN_FTP:
+ uuid = UUID_FTP;
+ break;
+
+ case RESERVED_SCN_DUN:
+ uuid = UUID_DUN;
+ break;
+
default:
uuid = UUID_SPP;
break;
diff --git a/btif/src/btif_sock_thread.c b/btif/src/btif_sock_thread.c
index 889c259..d1651c8 100644
--- a/btif/src/btif_sock_thread.c
+++ b/btif/src/btif_sock_thread.c
@@ -44,6 +44,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <sys/prctl.h>
#include <time.h>
#include <unistd.h>
@@ -551,7 +552,7 @@
ps_i, MAX_POLL, count, ts[h].poll_count);
return;
}
- if(ts[h].ps[ps_i].pfd.fd >= 0)
+ if(ts[h].ps[ps_i].pfd.fd >= 0 && pfd_i < MAX_POLL)
{
pfds[pfd_i] = ts[h].ps[ps_i].pfd;
ts[h].psi[pfd_i] = ps_i;
@@ -566,6 +567,8 @@
struct pollfd pfds[MAX_POLL];
memset(pfds, 0, sizeof(pfds));
int h = (intptr_t)arg;
+
+ prctl(PR_SET_NAME, (unsigned long)"btif_sock_poll", 0, 0, 0);
for(;;)
{
prepare_poll_fds(h, pfds);
diff --git a/btif/src/btif_stack_log.c b/btif/src/btif_stack_log.c
new file mode 100644
index 0000000..40612b3
--- /dev/null
+++ b/btif/src/btif_stack_log.c
@@ -0,0 +1,63 @@
+/*********************************************************************
+*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <hardware/bluetooth.h>
+
+#define LOG_TAG "STACK_LOG"
+
+#include "btif_api.h"
+#include "bt_types.h"
+#include "bt_trace.h"
+#include "logging.h"
+
+
+static void setLog( const char* log_layer, UINT16 log_level);
+
+static const btstacklog_interface_t btstacklogInterface = {
+ sizeof(btstacklog_interface_t),
+ setLog,
+};
+
+const btstacklog_interface_t *btif_stack_log_interface( void )
+{
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+ return &btstacklogInterface;
+}
+
+static void setLog( const char* log_layer, UINT16 log_level)
+{
+ BTA_setStackLog( log_layer, log_level);
+}
+
diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
index 468c6f0..d3784f9 100644
--- a/btif/src/btif_storage.c
+++ b/btif/src/btif_storage.c
@@ -167,7 +167,7 @@
static bt_status_t btif_in_fetch_bonded_ble_device(const char *remote_bd_addr,int add,
btif_bonded_devices_t *p_bonded_devices);
-static bt_status_t btif_in_fetch_bonded_device(const char *bdstr);
+static bt_status_t btif_in_fetch_bonded_device(const char *bdstr, int *dev_type);
/************************************************************************************
** Static functions
@@ -176,6 +176,8 @@
static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
{
bdstr_t bdstr = {0};
+ int name_length = 0;
+ int dev_type = BT_DEVICE_TYPE_BREDR;
if(remote_bd_addr)
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type, prop->len);
@@ -192,13 +194,19 @@
BTIF_STORAGE_PATH_REMOTE_DEVTIME, (int)time(NULL));
break;
case BT_PROPERTY_BDNAME:
- strncpy(value, (char*)prop->val, prop->len);
- value[prop->len]='\0';
+ name_length = prop->len > BTM_MAX_LOC_BD_NAME_LEN ? BTM_MAX_LOC_BD_NAME_LEN:
+ prop->len;
+ strncpy(value, (char*)prop->val, name_length);
+ value[name_length]='\0';
if(remote_bd_addr)
btif_config_set_str(bdstr,
BTIF_STORAGE_PATH_REMOTE_NAME, value);
- else btif_config_set_str("Adapter",
+ else
+ {
+ btif_config_set_str("Adapter",
BTIF_STORAGE_KEY_ADAPTER_NAME, value);
+ btif_config_flush();
+ }
break;
case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
strncpy(value, (char*)prop->val, prop->len);
@@ -226,6 +234,7 @@
uint32_t i;
char buf[64];
value[0] = 0;
+ int size = sizeof(value);
for (i=0; i < (prop->len)/sizeof(bt_uuid_t); i++)
{
bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val + i;
@@ -235,9 +244,8 @@
android_errorWriteLog(0x534e4554, "73963551");
return FALSE;
}
- strcat(value, buf);
- //strcat(value, ";");
- strcat(value, " ");
+ strlcat(value, buf, size);
+ strlcat(value, " ", size);
}
btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value);
break;
@@ -263,8 +271,14 @@
}
/* save changes if the device was bonded */
- if (btif_in_fetch_bonded_device(bdstr) == BT_STATUS_SUCCESS) {
- btif_config_save();
+ if (btif_in_fetch_bonded_device(bdstr, &dev_type) == BT_STATUS_SUCCESS) {
+ // flush is expensive, avoid for BLE devices during BLE Scanning
+ if(dev_type == BT_DEVICE_TYPE_BREDR)
+ {
+ btif_config_flush();
+ } else {
+ btif_config_save();
+ }
}
return TRUE;
@@ -394,9 +408,10 @@
** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
**
*******************************************************************************/
-static bt_status_t btif_in_fetch_bonded_device(const char *bdstr)
+static bt_status_t btif_in_fetch_bonded_device(const char *bdstr, int *p_dev_type)
{
BOOLEAN bt_linkkey_file_found=FALSE;
+ BOOLEAN bt_ltk_found=FALSE;
LINK_KEY link_key;
size_t size = sizeof(link_key);
@@ -413,17 +428,23 @@
}
}
#if (BLE_INCLUDED == TRUE)
- if((btif_in_fetch_bonded_ble_device(bdstr, FALSE, NULL) != BT_STATUS_SUCCESS)
- && (!bt_linkkey_file_found))
+ if (btif_in_fetch_bonded_ble_device(bdstr, FALSE, NULL) == BT_STATUS_SUCCESS)
+ bt_ltk_found = TRUE;
+
+ if(!bt_ltk_found && !bt_linkkey_file_found)
{
- BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", bdstr);
- return BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", bdstr);
+ return BT_STATUS_FAIL;
+ } else {
+ btif_config_get_int(bdstr, "DevType", p_dev_type);
}
#else
if((!bt_linkkey_file_found))
{
BTIF_TRACE_DEBUG("Remote device:%s, no link key found", bdstr);
return BT_STATUS_FAIL;
+ } else {
+ btif_config_get_int(bdstr, "DevType", p_dev_type);
}
#endif
return BT_STATUS_SUCCESS;
@@ -878,6 +899,27 @@
/*******************************************************************************
**
+** Function btif_storage_is_device_bonded
+**
+** Description BTIF storage API - checks if device present in bonded list
+**
+** Returns TRUE if the device is bonded
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_device_bonded(bt_bdaddr_t *remote_bd_addr)
+{
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ if((btif_config_exist(bdstr, "LinkKey")) &&
+ (btif_config_exist(bdstr, "LinkKeyType")))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*******************************************************************************
+**
** Function btif_storage_load_bonded_devices
**
** Description BTIF storage API - Loads all the bonded devices from NVRAM
@@ -1370,6 +1412,7 @@
uint16_t attr_mask;
uint8_t sub_class;
uint8_t app_id;
+ int dev_type;
memset(&dscp_info, 0, sizeof(dscp_info));
for (const btif_config_section_iter_t *iter = btif_config_section_begin(); iter != btif_config_section_end(); iter = btif_config_section_next(iter)) {
@@ -1379,7 +1422,7 @@
BTIF_TRACE_DEBUG("Remote device:%s", name);
int value;
- if(btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS)
+ if(btif_in_fetch_bonded_device(name, &dev_type) == BT_STATUS_SUCCESS)
{
if(btif_config_get_int(name, "HidAttrMask", &value))
{
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
index a8c58c9..18c9c5e 100644
--- a/btif/src/btif_util.c
+++ b/btif/src/btif_util.c
@@ -50,6 +50,7 @@
#include "btif_dm.h"
#include "btu.h"
#include "bt_common.h"
+#include "btif_av.h"
/************************************************************************************
** Constants & Macros
@@ -491,6 +492,8 @@
CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+ CASE_RETURN_STR(BTA_AV_BROWSE_MSG_EVT)
+ CASE_RETURN_STR(BTIF_AV_CLEANUP_REQ_EVT)
default:
return "UNKNOWN_EVENT";
}
@@ -509,7 +512,7 @@
CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE)
CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE)
CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE)
-
+ CASE_RETURN_STR(AVRC_EVT_NOW_PLAYING_CHANGE)
default:
return "Unhandled Event ID";
}
@@ -536,6 +539,11 @@
CASE_RETURN_STR(AVRC_PDU_SET_ADDRESSED_PLAYER)
CASE_RETURN_STR(AVRC_PDU_CHANGE_PATH)
CASE_RETURN_STR(AVRC_PDU_GET_CAPABILITIES)
+ CASE_RETURN_STR(AVRC_PDU_GET_ITEM_ATTRIBUTES)
+ CASE_RETURN_STR(AVRC_PDU_GET_FOLDER_ITEMS)
+ CASE_RETURN_STR(AVRC_PDU_SET_BROWSED_PLAYER)
+ CASE_RETURN_STR(AVRC_PDU_PLAY_ITEM)
+ CASE_RETURN_STR(AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS)
default:
return "Unknown PDU";
}
diff --git a/btif/src/btif_vendor.c b/btif/src/btif_vendor.c
new file mode 100644
index 0000000..7bc7703
--- /dev/null
+++ b/btif/src/btif_vendor.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 The Linux Foundation. All rights reserved
+ * Not a Contribution.
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_vendor.c
+ *
+ * Description: Vendor Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/vendor.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "bt_btif_vendor"
+
+#include <cutils/properties.h>
+#include "bt_utils.h"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_profile_queue.h"
+#include "stack_config.h"
+#include "stack_manager.h"
+#include "device/include/interop_config.h"
+#include "device/include/interop.h"
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+extern bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
+ BOOLEAN b_enable);
+static void get_logger_config_value(void);
+void btif_vendor_snooplog_status_event(UINT16, char *p_param);
+
+btvendor_callbacks_t *bt_vendor_callbacks = NULL;
+
+#define BTIF_VENDOR_BREDR_CLEANUP 1
+
+/*******************************************************************************
+** VENDOR INTERFACE FUNCTIONS
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_vendor_init
+**
+** Description initializes the vendor interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( btvendor_callbacks_t* callbacks)
+{
+ LOG_ERROR(LOG_TAG,"init");
+ bt_vendor_callbacks = callbacks;
+
+ get_logger_config_value();
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void ssrcleanup(void)
+{
+ LOG_INFO(LOG_TAG,"ssrcleanup");
+ int soc_type = get_soc_type();
+ if (soc_type == BT_SOC_ROME || soc_type == BT_SOC_CHEROKEE)
+ btif_ssr_cleanup();
+ return;
+}
+
+static void btif_vendor_bredr_cleanup_event(UINT16 event, char *p_param)
+{
+ tBTA_SERVICE_MASK service_mask;
+ uint32_t i;
+ service_mask = btif_get_enabled_services_mask();
+ for (i = 0; i <= BTA_MAX_SERVICE_ID; i++)
+ {
+ if (i != BTA_BLE_SERVICE_ID && (service_mask &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))))
+ {
+ btif_in_execute_service_request(i, FALSE);
+ }
+ }
+ btif_queue_release();
+ HAL_CBACK(bt_vendor_callbacks, bredr_cleanup_cb, true);
+}
+
+static void bredrcleanup(void)
+{
+ LOG_INFO(LOG_TAG,"bredrcleanup");
+ btif_transfer_context(btif_vendor_bredr_cleanup_event,BTIF_VENDOR_BREDR_CLEANUP,
+ NULL, 0, NULL);
+}
+
+static void capture_vnd_logs(void)
+{
+ LOG_INFO(LOG_TAG,"capture_vnd_logs");
+ GENERATE_VND_LOGS();
+}
+
+static void cleanup(void)
+{
+ LOG_INFO(LOG_TAG,"cleanup");
+ if (bt_vendor_callbacks)
+ bt_vendor_callbacks = NULL;
+}
+
+// API's to match entries with in dynamic interop database
+static bool interop_db_match(int feature, int type, void *value) {
+ if ( type == INTEROP_BL_TYPE_ADDR)
+ return interop_database_match_addr((interop_feature_t)feature, (bt_bdaddr_t *)value);
+ else if ( type == INTEROP_BL_TYPE_NAME)
+ return interop_database_match_name((interop_feature_t)feature, (char *)value);
+ return false;
+}
+
+static const btvendor_interface_t btvendorInterface = {
+ sizeof(btvendorInterface),
+ init,
+ ssrcleanup,
+ bredrcleanup,
+ capture_vnd_logs,
+ cleanup,
+ interop_db_match,
+};
+
+/*******************************************************************************
+** LOCAL FUNCTIONS
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_vendor_get_interface
+**
+** Description Get the vendor callback interface
+**
+** Returns btvendor_interface_t
+**
+*******************************************************************************/
+const btvendor_interface_t *btif_vendor_get_interface()
+{
+ BTIF_TRACE_EVENT("%s", __FUNCTION__);
+ return &btvendorInterface;
+}
+
+
+#ifdef BLUEDROID_DEBUG
+/*******************************************************************************
+**
+** Function set_logging_pref
+**
+** Description Set logging preference property to control BT logging
+** based on config file or developer option
+**
+** Returns void
+**
+*******************************************************************************/
+void set_logging_pref(uint16_t pref_val)
+{
+ char new_log_pref[2];
+ snprintf(new_log_pref, 2, "%d", pref_val);
+ property_set("persist.bluetooth.log_pref", new_log_pref);
+ LOG_INFO(LOG_TAG, "%s, New Logging preference value: %d", __func__, pref_val);
+}
+
+/*******************************************************************************
+**
+** Function get_logging_pref
+**
+** Description Returns current logging preference to set logging status
+** based on config file or developer option
+**
+** Returns void
+**
+*******************************************************************************/
+uint16_t get_logging_pref()
+{
+ return (uint16_t)property_get_int32("persist.bluetooth.log_pref", NO_PREFERENCE);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function get_logger_config_value
+**
+** Description Set logging option based on flag values set
+** in config file
+**
+** Returns void
+**
+*******************************************************************************/
+static void get_logger_config_value()
+{
+ bool hci_ext_dump_enabled = false;
+ bool btsnoop_conf_from_file = false;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+#ifdef BLUEDROID_DEBUG
+ uint16_t logging_pref;
+ logging_pref = get_logging_pref();
+
+ LOG_INFO(LOG_TAG, "%s, logging_pref = %d", __func__, logging_pref);
+ if(logging_pref == DEV_OPT_PREFERENCE)
+ return;
+#endif
+
+ stack_config_get_interface()->get_btsnoop_ext_options(&hci_ext_dump_enabled, &btsnoop_conf_from_file);
+
+ /* ToDo: Change dependency to work on one config option*/
+#ifdef BLUEDROID_DEBUG
+ if(!btsnoop_conf_from_file)
+ hci_ext_dump_enabled = true;
+#endif
+
+ if(hci_ext_dump_enabled)
+ bt_logger_enabled = true;
+}
+
+#ifdef BLUEDROID_DEBUG
+/*******************************************************************************
+**
+** Function enable_bt_logger_debug
+**
+** Description enable Bluetooth Unified logger based on values
+** from config file and developer option and current
+** logging preference.
+**
+** Returns void
+**
+*******************************************************************************/
+void enable_bt_logger_debug(bool enable)
+{
+ if(stack_manager_get_interface()->get_stack_is_running()) {
+ if(enable && !bt_logger_enabled)
+ {
+ property_set("bluetooth.startbtlogger", "true");
+ usleep(500000);
+ bt_logger_enabled = true;
+ init_vnd_Logger();
+ }
+ set_logging_pref(DEV_OPT_PREFERENCE);
+ } else {
+ uint16_t curr_log_pref;
+ curr_log_pref = get_logging_pref();
+
+ LOG_INFO(LOG_TAG, "config_hci_snoop_log, curr_log_pref = %d", curr_log_pref);
+ if(curr_log_pref < DEV_OPT_PREFERENCE && enable != bt_logger_enabled) {
+ if(curr_log_pref == bt_logger_enabled) {
+ /*It means user have updated the logging option
+ *from Developer Option while Bluetooth was Off.*/
+ bt_logger_enabled = enable;
+ set_logging_pref(DEV_OPT_PREFERENCE);
+ } else {
+ /*It means user have updated the logging option
+ *from bt_stack.conf file.*/
+ set_logging_pref(bt_logger_enabled);
+ }
+ } else if(curr_log_pref == DEV_OPT_PREFERENCE && enable) {
+ bt_logger_enabled = enable;
+ }
+ LOG_INFO(LOG_TAG, "config_hci_snoop_log, logging status = %d", bt_logger_enabled);
+ if(bt_logger_enabled)
+ property_set("bluetooth.startbtlogger", "true");
+ }
+}
+#else
+/*******************************************************************************
+**
+** Function enable_bt_logger
+**
+** Description Enable Bluetooth Unified Logger based on input
+** from developer option.
+**
+** Returns void
+**
+*******************************************************************************/
+void enable_bt_logger(bool enable)
+{
+ if(stack_manager_get_interface()->get_stack_is_running()) {
+ if(enable && !bt_logger_enabled)
+ {
+ property_set("bluetooth.startbtlogger", "true");
+ usleep(500000);
+ bt_logger_enabled = true;
+ init_vnd_Logger();
+ }
+ } else {
+ bt_logger_enabled = enable;
+ if(bt_logger_enabled)
+ property_set("bluetooth.startbtlogger", "true");
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btif_vendor_snooplog_status_event
+**
+** Description updates snoop log status to application layer
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_vendor_snooplog_status_event(UINT16 status, char *p_param)
+{
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ HAL_CBACK(bt_vendor_callbacks, update_snooplog_status_cb, status);
+}
diff --git a/btif/src/stack_manager.c b/btif/src/stack_manager.c
index 288f697..f6a5298 100644
--- a/btif/src/stack_manager.c
+++ b/btif/src/stack_manager.c
@@ -21,6 +21,7 @@
#include "stack_manager.h"
#include <hardware/bluetooth.h>
+#include <cutils/properties.h>
#include "btcore/include/module.h"
#include "btcore/include/osi_module.h"
@@ -53,6 +54,13 @@
static void event_signal_stack_up(void *context);
static void event_signal_stack_down(void *context);
+extern void btif_vendor_snooplog_status_event(UINT16, char *p_param);
+extern void set_logging_pref(uint16_t pref_val);
+
+#ifdef BLUEDROID_DEBUG
+extern uint16_t get_logging_pref();
+#endif
+
// Unvetted includes/imports, etc which should be removed or vetted in the future
static future_t *hack_future;
void bte_main_enable();
@@ -139,6 +147,18 @@
ensure_stack_is_initialized();
+ init_vnd_Logger();
+#ifdef BLUEDROID_DEBUG
+ uint16_t logging_pref;
+ logging_pref = get_logging_pref();
+
+ if(logging_pref != DEV_OPT_PREFERENCE) {
+ btif_transfer_context(btif_vendor_snooplog_status_event, bt_logger_enabled,
+ NULL, 0, NULL);
+ set_logging_pref(bt_logger_enabled);
+ }
+#endif
+
LOG_INFO(LOG_TAG, "%s is bringing up the stack", __func__);
future_t *local_hack_future = future_new();
hack_future = local_hack_future;
@@ -200,8 +220,6 @@
ensure_stack_is_not_running();
LOG_INFO(LOG_TAG, "%s is cleaning up the stack", __func__);
- future_t *local_hack_future = future_new();
- hack_future = local_hack_future;
stack_is_initialized = false;
btif_cleanup_bluetooth();
@@ -211,7 +229,8 @@
module_management_stop();
LOG_INFO(LOG_TAG, "%s finished", __func__);
-cleanup:;
+cleanup:
+ clean_vnd_logger();
semaphore_t *semaphore = (semaphore_t *)context;
if (semaphore)
semaphore_post(semaphore);
diff --git a/conf/Android.mk b/conf/Android.mk
index 5bc5a63..cd723da 100644
--- a/conf/Android.mk
+++ b/conf/Android.mk
@@ -20,3 +20,15 @@
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+include $(CLEAR_VARS)
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_PATH := vendor/qcom/opensource/bluetooth/system_bt_ext/conf/
+else
+LOCAL_PATH := device/qcom/msm8909w/opensource/bluetooth/system_bt_ext/conf/
+endif
+LOCAL_MODULE := interop_database.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
diff --git a/conf/bt_did.conf b/conf/bt_did.conf
index ea89c06..5a29c73 100644
--- a/conf/bt_did.conf
+++ b/conf/bt_did.conf
@@ -7,7 +7,8 @@
# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
# 0x000F = Broadcom Corporation (default)
-#vendorId = 0x000F
+# 0x001D = Qualcomm
+vendorId = 0x001D
# Vendor ID Source
# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index a0afcb5..5516ac5 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -1,6 +1,12 @@
+# Enable BtSnoop configuration from this config file
+# Snoop is enabled by default on userdebug builds, below configuration
+# enables to override it and take effect from the configurations here.
+BtSnoopConfigFromFile=false
+
# Enable BtSnoop logging function
# valid value : true, false
BtSnoopLogOutput=false
+BtSnoopExtDump=false
# BtSnoop log output file
BtSnoopFileName=/data/misc/bluetooth/logs/btsnoop_hci.log
@@ -54,6 +60,10 @@
# SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
#PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+# Enable LE non-conn adv mode
+# valid value: true, false
+#PTS_EnableNonConnAdvMode=true
+
# SMP Certification Failure Cases
# Fail case number range from 1 to 9 will set up remote device for test
# case execution. Setting PTS_SmpFailureCase to 0 means normal operation.
@@ -68,4 +78,3 @@
# 8 = SMP_PASSKEY_ENTRY_FAIL
# 9 = SMP_NUMERIC_COMPAR_FAIL;
#PTS_SmpFailureCase=0
-
diff --git a/conf/iot_devlist.conf b/conf/iot_devlist.conf
new file mode 100755
index 0000000..db09b90
--- /dev/null
+++ b/conf/iot_devlist.conf
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# Place holder for all IOT devices to be blacklisted
+# Blacklist mechanism will detect the device in runtime based on issue condition
+# and black list the device
diff --git a/device/Android.mk b/device/Android.mk
index c5b9377..bb9a061 100644
--- a/device/Android.mk
+++ b/device/Android.mk
@@ -31,10 +31,25 @@
$(LOCAL_PATH)/../stack/include \
$(bluetooth_C_INCLUDES)
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_C_INCLUDES += \
+ vendor/qcom/opensource/bluetooth/system_bt_ext
+else
+LOCAL_C_INCLUDES += \
+ device/qcom/msm8909w/opensource/bluetooth/system_bt_ext
+endif
+
LOCAL_SRC_FILES := \
src/classic/peer.c \
- src/controller.c \
- src/interop.c
+ src/controller.c
+
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_SRC_FILES += \
+ ../../../vendor/qcom/opensource/bluetooth/system_bt_ext/device/src/interop.c
+else
+LOCAL_SRC_FILES += \
+ ../../../device/qcom/msm8909w/opensource/bluetooth/system_bt_ext/device/src/interop.c
+endif
LOCAL_MODULE := libbtdevice
LOCAL_MODULE_TAGS := optional
diff --git a/device/include/controller.h b/device/include/controller.h
index 291c33d..159cd79 100644
--- a/device/include/controller.h
+++ b/device/include/controller.h
@@ -29,6 +29,10 @@
static const char CONTROLLER_MODULE[] = "controller_module";
+typedef struct controller_static_t {
+ void (*enable_soc_logging) (bool value);
+} controller_static_t;
+
typedef struct controller_t {
bool (*get_is_ready)(void);
@@ -49,11 +53,14 @@
bool (*supports_rssi_with_inquiry_results)(void);
bool (*supports_extended_inquiry_response)(void);
bool (*supports_master_slave_role_switch)(void);
+ bool (*supports_set_le_privacy_mode)(void);
bool (*supports_ble)(void);
bool (*supports_ble_packet_extension)(void);
bool (*supports_ble_connection_parameters_request)(void);
bool (*supports_ble_privacy)(void);
+ bool (*supports_ble_two_mbps_rate)(void);
+ bool (*supports_ble_extended_advertisements)(void);
// Get the cached acl data sizes for the controller.
uint16_t (*get_acl_data_size_classic)(void);
@@ -76,8 +83,14 @@
uint8_t (*get_ble_resolving_list_max_size)(void);
void (*set_ble_resolving_list_max_size)(int resolving_list_max_size);
uint8_t *(*get_local_supported_codecs)(uint8_t *number_of_codecs);
+ bool (*supports_ble_offload_features)(void);
+
+ uint8_t (*get_ble_adv_ext_size)(void);
+ void (*set_ble_adv_ext_size)(int adv_ext_size);
} controller_t;
+const controller_static_t *controller_get_static_interface();
+
const controller_t *controller_get_interface();
const controller_t *controller_get_test_interface(
diff --git a/device/include/interop.h b/device/include/interop.h
index 05778a8..8edcd01 100644
--- a/device/include/interop.h
+++ b/device/include/interop.h
@@ -25,13 +25,15 @@
static const char INTEROP_MODULE[] = "interop_module";
// NOTE:
-// Only add values at the end of this enum and do NOT delete values
-// as they may be used in dynamic device configuration.
+// Only add values at the end of this enum and before END_OF_INTEROP_LIST
+// do NOT delete values as they may be used in dynamic device configuration.
typedef enum {
+
+ BEGINING_OF_INTEROP_LIST = 0,
// Disable secure connections
// This is for pre BT 4.1/2 devices that do not handle secure mode
// very well.
- INTEROP_DISABLE_LE_SECURE_CONNECTIONS = 0,
+ INTEROP_DISABLE_LE_SECURE_CONNECTIONS = BEGINING_OF_INTEROP_LIST,
// Some devices have proven problematic during the pairing process, often
// requiring multiple retries to complete pairing. To avoid degrading the user
@@ -63,7 +65,114 @@
// re-transmissions after switching to 2DH packets.
//
// Disable 3Mbps packets and use only 2Mbps packets for ACL links when streaming audio.
- INTEROP_2MBPS_LINK_ONLY
+ INTEROP_2MBPS_LINK_ONLY,
+
+ // Some HID devices have proven problematic behaviour if SDP is initiated again
+ // while HID connection is in progress or if more than 1 SDP connection is created
+ // with those HID devices rsulting in issues of connection failure with such devices.
+ // To avoid degrading the user experience with those devices, SDP is not attempted
+ // as part of pairing process.
+ INTEROP_DISABLE_SDP_AFTER_PAIRING,
+
+ // Some HID pointing devices have proven problematic behaviour if pairing is initiated with
+ // them, resulting in no response for authentication request and ultimately resulting
+ // in connection failure.
+ // To avoid degrading the user experience with those devices, authentication request
+ // is not requested explictly.
+ INTEROP_DISABLE_AUTH_FOR_HID_POINTING,
+
+ // HID Keyboards that claim support for multitouch functionality have issue with
+ // normal functioning of keyboard because of issues in USB HID kernel driver.
+ // To avoid degrading the user experience with those devices, digitizer record
+ // is removed from the report descriptor.
+ INTEROP_REMOVE_HID_DIG_DESCRIPTOR,
+
+ // Some HID devices have problematic behaviour where when hid link is in Sniff
+ // and DUT is in Slave role for SCO link ( not eSCO) any solution cannot maintain
+ // the link as SCO scheduling over a short period will overlap with Sniff link due to
+ // slave drift.
+ // To avoid degrading the user experience with those devices, sniff is disabled from
+ // link policy when sco is active, and enabled when sco is disabled.
+ INTEROP_DISABLE_SNIFF_DURING_SCO,
+
+ //Few carkits take long time to start sending AT commands
+ //Increase AG_CONN TIMEOUT so that AG connection go through
+ INTEROP_INCREASE_AG_CONN_TIMEOUT,
+
+ // Some HOGP devices do not respond well when we switch from default LE conn parameters
+ // to preferred conn params immediately post connection. Disable automatic switching to
+ // preferred conn params for such devices and allow them to explicity ask for it.
+ INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS,
+
+ //Few carkit hfp version is hfp1.5 but it support hfp indicator, violate spec
+ //remove hfp indicator for such device
+ INTEROP_DISABLE_HF_INDICATOR,
+
+ // Few remote devices do not understand AVRCP version greater than 1.3. For these
+ // devices, we would like to blacklist them and advertise AVRCP version as 1.3
+ INTEROP_ADV_AVRCP_VER_1_3,
+
+ // certain remote A2DP sinks have issue playing back Music in AAC format.
+ // disable AAC for those headsets so that it switch to SBC
+ INTEROP_DISABLE_AAC_CODEC,
+
+ // Enable AAC only for whitelist of devices
+ INTEROP_ENABLE_AAC_CODEC,
+
+ // Some car kits notifies role switch supported but it rejects
+ // the role switch and after some attempts of role switch
+ // car kits will go to bad state.
+ INTEROP_DYNAMIC_ROLE_SWITCH,
+
+ // Disable role switch for headsets/car-kits
+ // Some car kits allow role switch but when DUT initiates role switch
+ // Remote will go to bad state and its leads to LMP time out.
+ INTEROP_DISABLE_ROLE_SWITCH,
+
+ // Disable role switch for headsets/car-kits
+ // Some car kits initiate a role switch but won't initiate encryption
+ // after role switch complete
+ INTEROP_DISABLE_ROLE_SWITCH_POLICY,
+
+ INTEROP_HFP_1_7_BLACKLIST,
+
+ // Some Carkits are not initiating AVRCP Browse Channel on
+ // seeing DUT's AVRCP version as v1.6. Hence fallback DUT's
+ // AVRCP version to v1.4 for those Carkits
+ INTEROP_STORE_REMOTE_AVRCP_VERSION_1_4,
+
+ // Devices requiring this workaround do not handle Bluetooth PBAP 1.2 version correctly,
+ // leading them to go in bad state. So for better interoperability respond with PBAP 1.1
+ // as supported version.
+ INTEROP_ADV_PBAP_VER_1_1,
+
+ // Devices requiring this workaround do not handle SSR max latency values as mentioned,
+ // in their SDP HID Record properly and lead to connection timeout or lags. To prevent
+ // such scenarios, device requiring this workaorund need to use specific ssr max latency
+ // values.
+ INTEROP_UPDATE_HID_SSR_MAX_LAT,
+ // Some Carkits being AVRCP v1.3 upon receiving Play Application Setting Command Response
+ // and notification, doesn't send Passthrough commands back to DUT in Streaming State
+ INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS,
+
+ // Some remotes are very strict in receiving the call active
+ // indicator and SCO connection request order for MT call.
+ // If CIEV1,1 and SCO connection request are sent back to back
+ // to SOC, it may send SCO connection request first then CIEV1,1
+ // which may lead to remotes not rendering SCO audio.
+ INTEROP_DELAY_SCO_FOR_MT_CALL,
+ // Some remotes are taking too long to respond for codec negotiation.
+ // Disable codec negotiation for such remotes and directly initiate
+ // SCO Connection.
+ INTEROP_DISABLE_CODEC_NEGOTIATION,
+
+ // Some remotes are going into sniff mode during SCO connection process and taking time
+ // for SCO connection to complete. For such devices, disable sniff when SCO is
+ // connecting and enable it after SCO disconnection.
+ INTEROP_DISABLE_SNIFF_POLICY_DURING_SCO,
+
+ END_OF_INTEROP_LIST
+
} interop_feature_t;
// Check if a given |addr| matches a known interoperability workaround as identified
@@ -80,6 +189,34 @@
// |name| cannot be null and must be null terminated.
bool interop_match_name(const interop_feature_t feature, const char *name);
+// Check if a given remote device |name| matches a known interoperability workaround.
+// Name comparisons are case sensitive and do not allow for partial matches. As in, if
+// |name| is "TEST" and a workaround exists for "TESTING", then this function will
+// return false. But, if |name| is "TESTING" and a workaround exists for "TEST", this
+// function will return true.
+// |name| cannot be null and must be null terminated.
+bool interop_match_name(const interop_feature_t feature, const char *name);
+
+// Check if a given |manufacturer| matches a known interoperability workaround as identified
+// by the |interop_feature_t| enum. This API is used for manufacturer based lookups
+// where more information is not available.
+bool interop_match_manufacturer(const interop_feature_t feature, uint16_t manufacturer);
+
+
+// Check if a given |vendor_id, product_id, name| matches a known interoperability workaround
+// as identified by the |interop_feature_t| enum. This API is used for simple name based lookups
+// where more information is not available.
+bool interop_match_vendor_product_ids(const interop_feature_t feature,
+ uint16_t vendor_id, uint16_t product_id);
+
+// Check if a given |addr| matches a known interoperability workaround as identified
+// by the |interop_feature_t| enum. This API is used for simple address based lookups
+// where more information is not available. No look-ups or random address resolution
+// are performed on |addr|. If address is matched, max latency for SSR stored for particular
+// remote device is returned.
+bool interop_match_addr_get_max_lat(const interop_feature_t feature,
+ const bt_bdaddr_t *addr, uint16_t *max_lat);
+
// Add a dynamic interop database entry for a device matching the first |length| bytes
// of |addr|, implementing the workaround identified by |feature|. |addr| may not be
// null and |length| must be greater than 0 and less than sizeof(bt_bdaddr_t).
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index 49cb8a5..4423aea 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -90,10 +90,60 @@
// Unknown keyboard (carried over from auto_pair_devlist.conf)
{{{0x00, 0x0F, 0xF6, 0,0,0}}, 3, INTEROP_KEYBOARD_REQUIRES_FIXED_PIN},
+
+ // Apple Magic Mouse
+ {{{0x04, 0x0C, 0xCE, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Bluetooth Laser Travel Mouse
+ {{{0x00, 0x07, 0x61, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Microsoft Bluetooth Notebook Mouse 5000
+ {{{0x00, 0x1d, 0xd8, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Logitech MX Revolution Mouse
+ {{{0x00, 0x1f, 0x20, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Rapoo 6080 mouse
+ {{{0x6c, 0x5d, 0x63, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Microsoft Sculpt Touch Mouse
+ {{{0x28, 0x18, 0x78, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Tero's Game Controller
+ {{{0x60, 0x45, 0xBD, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+
+ // Targus BT Laser Notebook Mouse
+ {{{0x00, 0x12, 0xA1, 0,0,0}}, 3, INTEROP_DISABLE_AUTH_FOR_HID_POINTING},
+
+ // Bluetooth Keyboard
+ {{{0x20, 0x4C, 0x10, 0,0,0}}, 3, INTEROP_DISABLE_SNIFF_DURING_SCO},
+
+ // Fiat Carkit
+ {{{0x00, 0x14, 0x09, 0,0,0}}, 3, INTEROP_INCREASE_AG_CONN_TIMEOUT},
+
+ // Dialog Keyboard and mouse
+ {{{0x80, 0xea, 0xca, 0,0,0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+ // Marvel CK used in Mercedes C300/BMW 640i
+ // For a more specific black listing(e.g. just for Mercedes), both BD addr
+ // and device name has to be added for AVRCP 1.3 blacklisting
+ {{{0xa0, 0x56, 0xb2, 0,0,0}}, 3, INTEROP_ADV_AVRCP_VER_1_3},
+
+ // Mazda Atenza
+ {{{0x04, 0xf8, 0xc2, 0,0,0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+ // Remote not playing back Audio, suspected to be Audio encoder version diff
+ // Beats Solo 3
+ {{{0x20, 0x3c, 0xae, 0,0,0}}, 3, INTEROP_DISABLE_AAC_CODEC},
+ //Apple Airpods Headset
+ {{{0x4c, 0x32, 0x75, 0,0,0}}, 3, INTEROP_DISABLE_AAC_CODEC},
+ // Remote sending 128 as bitrate in place of 128000
+ // Cadillac
+ {{{0x28, 0xA1, 0x83, 0,0,0}}, 3, INTEROP_DISABLE_AAC_CODEC},
+ // Buick Verona
+ {{{0xAC, 0x7A, 0x4D, 0,0,0}}, 3, INTEROP_DISABLE_AAC_CODEC},
+ //Maruthi Brezzai
+ {{{0x28, 0xa1, 0x83, 0,0,0}}, 3, INTEROP_DISABLE_AAC_CODEC},
+ // Parrot Zik2.0
+ {{{0xA0, 0x14, 0x3D, 0,0,0}}, 3, INTEROP_DISABLE_AAC_CODEC},
+
};
typedef struct {
- char name[20];
+ char name[249];
size_t length;
interop_feature_t feature;
} interop_name_entry_t;
@@ -110,5 +160,49 @@
// Subaru car kits ("CAR M_MEDIA")
{"CAR", 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // HID SDP Blacklist
+ {"Apple Magic Mouse", 17, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Bluetooth Laser Travel Mouse", 28, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Microsoft Bluetooth Notebook Mouse 5000", 39, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Logitech MX Revolution Mouse", 28, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Microsoft Sculpt Touch Mouse", 28, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Tero's Game Controller", 22, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+
+ // HID Authentication Blacklist
+ {"Targus BT Laser Notebook Mouse", 30, INTEROP_DISABLE_AUTH_FOR_HID_POINTING},
+
+ //Below devices reject connection updated with preferred
+ {"BSMBB09DS", 9, INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS},
+ {"ELECOM", 6, INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS},
+ {"MB Bluetooth", 12, INTEROP_ADV_AVRCP_VER_1_3},
+
+ // HID Moto KZ500 Keyboard - Problematic SDP digitizer descriptor
+ {"Motorola Keyboard KZ500", 23, INTEROP_REMOVE_HID_DIG_DESCRIPTOR},
+ {"Motorola Keyboard KZ500 v122", 28, INTEROP_REMOVE_HID_DIG_DESCRIPTOR},
+
};
+typedef struct {
+ uint16_t manufacturer;
+ interop_feature_t feature;
+} interop_manufacturer_t;
+
+static const interop_manufacturer_t interop_manufacturer_database[] = {
+ // Apple Devices
+ {76, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+
+ // Apple Devices
+ {76, INTEROP_DISABLE_SNIFF_DURING_SCO},
+};
+
+typedef struct {
+ uint16_t vendor_id;
+ uint16_t product_id;
+ interop_feature_t feature;
+} interop_hid_multitouch_t;
+
+static const interop_hid_multitouch_t interop_hid_multitouch_database[] = {
+ // HID Moto KZ500 Keyboard - Problematic SDP digitizer descriptor
+ {0x22b8, 0x093d, INTEROP_REMOVE_HID_DIG_DESCRIPTOR},
+};
diff --git a/device/src/controller.c b/device/src/controller.c
index 23799d8..bb53eb3 100644
--- a/device/src/controller.c
+++ b/device/src/controller.c
@@ -21,6 +21,8 @@
#include "device/include/controller.h"
#include <assert.h>
+#include <string.h>
+#include <cutils/properties.h>
#include "bt_types.h"
#include "btcore/include/event_mask.h"
@@ -29,8 +31,11 @@
#include "hcimsgs.h"
#include "osi/include/future.h"
#include "stack/include/btm_ble_api.h"
+#include "osi/include/log.h"
+#include "utils/include/bt_utils.h"
-const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x06\x7f" };
+const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x0b\xfe\x7f" };
+const bt_event_mask_t BLE_EVENT_MASK_ALE_DISABLED = { "\x00\x00\x00\x00\x00\x08\x0e\x7f" };
#if (BLE_INCLUDED)
const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_DUMO_EVENT_MASK_EXT };
@@ -46,6 +51,9 @@
#define BLE_SUPPORTED_STATES_SIZE 8
#define BLE_SUPPORTED_FEATURES_SIZE 8
#define MAX_LOCAL_SUPPORTED_CODECS_SIZE 8
+#define UNUSED(x) (void)(x)
+
+static bool soc_logging_enabled_via_api;
static const hci_t *hci;
static const hci_packet_factory_t *packet_factory;
@@ -70,18 +78,44 @@
static uint16_t ble_suggested_default_data_length;
static uint8_t local_supported_codecs[MAX_LOCAL_SUPPORTED_CODECS_SIZE];
static uint8_t number_of_local_supported_codecs = 0;
+static uint8_t ble_adv_ext_size;
static bool readable;
static bool ble_supported;
+static bool ble_offload_features_supported;
static bool simple_pairing_supported;
static bool secure_connections_supported;
+static bool adv_ext_enabled = false;
+
#define AWAIT_COMMAND(command) future_await(hci->transmit_command_futured(command))
// Module lifecycle functions
+void send_soc_log_command(bool value) {
+ int soc_type = get_soc_type();
+ UINT8 param[5] = {0x10, 0x03, 0x00, 0x00, 0x01};
+ UINT8 param_cherokee[2] = {0x14, 0x01};
+ if (!value) {
+ // Disable SoC logging
+ param[1] = 0x02;
+ param_cherokee[1] = 0x00;
+ }
+
+ if (soc_type == BT_SOC_SMD) {
+ LOG_INFO(LOG_TAG, "%s for BT_SOC_SMD.", __func__);
+ BTM_VendorSpecificCommand(HCI_VS_HOST_LOG_OPCODE, 5, param, NULL);
+ } else if (soc_type == BT_SOC_CHEROKEE) {
+ LOG_INFO(LOG_TAG, "%s for BT_SOC_CHEROKEE.", __func__);
+ BTM_VendorSpecificCommand(HCI_VS_HOST_LOG_OPCODE, 2, param_cherokee, NULL);
+ }
+
+}
+
static future_t *start_up(void) {
BT_HDR *response;
+ int ret =0;
+ char value[PROPERTY_VALUE_MAX] = {'\0'};
// Send the initial reset command
response = AWAIT_COMMAND(packet_factory->make_reset());
@@ -105,6 +139,16 @@
packet_parser->parse_generic_command_complete(response);
+ #ifdef QLOGKIT_USERDEBUG
+ send_soc_log_command(true);
+ #else
+ if (soc_logging_enabled_via_api) {
+ LOG_INFO(LOG_TAG, "%s for non-userdebug api = %d", __func__,
+ soc_logging_enabled_via_api);
+ send_soc_log_command(true);
+ }
+ #endif
+
// Read the local version info off the controller next, including
// information such as manufacturer and supported HCI version
response = AWAIT_COMMAND(packet_factory->make_read_local_version_info());
@@ -177,15 +221,30 @@
page_number++;
}
+ // read BLE offload features support from controller
+ response = AWAIT_COMMAND(packet_factory->make_ble_read_offload_features_support());
+ packet_parser->parse_ble_read_offload_features_response(response, &ble_offload_features_supported);
+
#if (SC_MODE_INCLUDED == TRUE)
- secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array);
- if (secure_connections_supported) {
- response = AWAIT_COMMAND(packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED));
- packet_parser->parse_generic_command_complete(response);
+ if(ble_offload_features_supported) {
+ secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array);
+ if (secure_connections_supported) {
+ response = AWAIT_COMMAND(packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED));
+ packet_parser->parse_generic_command_complete(response);
+ }
}
#endif
#if (BLE_INCLUDED == TRUE)
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ ret = property_get("ble.ae_supported", value, NULL);
+ if (ret) {
+ adv_ext_enabled = (strcmp(value, "true") ==0) ? true : false;
+ LOG_INFO(LOG_TAG, "%s BLE Adv Extensions enabled:%d", __func__, adv_ext_enabled);
+ }
+#endif
+
ble_supported = last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(features_classic[1].as_array);
if (ble_supported) {
// Request the ble white list size next
@@ -233,8 +292,19 @@
&ble_suggested_default_data_length);
}
+ if (adv_ext_enabled && HCI_LE_ADV_EXTENSION_SUPPORTED(features_ble.as_array)) {
+ response = AWAIT_COMMAND(packet_factory->make_ble_read_adv_ext_size());
+ packet_parser->parse_ble_read_adv_ext_size_response(
+ response,
+ &ble_adv_ext_size);
+ }
+
// Set the ble event mask next
- response = AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK));
+ if (adv_ext_enabled) {
+ response = AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK));
+ } else {
+ response = AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK_ALE_DISABLED));
+ }
packet_parser->parse_generic_command_complete(response);
}
#endif
@@ -277,6 +347,16 @@
// Interface functions
+static void enable_soc_logging(bool value) {
+ UNUSED(soc_logging_enabled_via_api);
+#ifndef QLOGKIT_USERDEBUG
+ soc_logging_enabled_via_api = value;
+
+ if (readable)
+ send_soc_log_command(value);
+#endif
+}
+
static bool get_is_ready(void) {
return readable;
}
@@ -344,6 +424,11 @@
return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands);
}
+static bool supports_set_le_privacy_mode(void) {
+ assert(readable);
+ return (HCI_LE_SET_PRIVACY_MODE_SUPPORTED(supported_commands));
+}
+
static bool supports_interlaced_inquiry_scan(void) {
assert(readable);
return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(features_classic[0].as_array);
@@ -375,6 +460,15 @@
return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array);
}
+static bool supports_ble_extended_advertisements(void) {
+ assert(readable);
+ assert(ble_supported);
+ if(adv_ext_enabled)
+ return HCI_LE_ADV_EXTENSION_SUPPORTED(features_ble.as_array);
+ else
+ return false;
+}
+
static bool supports_ble_packet_extension(void) {
assert(readable);
assert(ble_supported);
@@ -387,6 +481,18 @@
return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array);
}
+static bool supports_ble_offload_features(void) {
+ assert(readable);
+ assert(ble_supported);
+ return ble_offload_features_supported;
+}
+
+static bool supports_ble_two_mbps_rate(void) {
+ assert(readable);
+ assert(ble_supported);
+ return HCI_LE_TWO_MBPS_SUPPORTED(features_ble.as_array);
+}
+
static uint16_t get_acl_data_size_classic(void) {
assert(readable);
return acl_data_size_classic;
@@ -447,6 +553,22 @@
ble_resolving_list_max_size = resolving_list_max_size;
}
+static const controller_static_t static_interface = {
+ enable_soc_logging
+};
+
+static uint8_t get_ble_adv_ext_size(void) {
+ assert(readable);
+ assert(ble_supported);
+ return ble_adv_ext_size;
+}
+
+static void set_ble_adv_ext_size(int adv_sets) {
+ assert(readable);
+ assert(ble_supported);
+ ble_adv_ext_size = adv_sets;
+}
+
static const controller_t interface = {
get_is_ready,
@@ -467,11 +589,14 @@
supports_rssi_with_inquiry_results,
supports_extended_inquiry_response,
supports_master_slave_role_switch,
+ supports_set_le_privacy_mode,
supports_ble,
supports_ble_packet_extension,
supports_ble_connection_parameters_request,
supports_ble_privacy,
+ supports_ble_two_mbps_rate,
+ supports_ble_extended_advertisements,
get_acl_data_size_classic,
get_acl_data_size_ble,
@@ -487,9 +612,17 @@
get_ble_resolving_list_max_size,
set_ble_resolving_list_max_size,
- get_local_supported_codecs
+ get_local_supported_codecs,
+ supports_ble_offload_features,
+
+ get_ble_adv_ext_size,
+ set_ble_adv_ext_size
};
+const controller_static_t *controller_get_static_interface() {
+ return &static_interface;
+}
+
const controller_t *controller_get_interface() {
static bool loaded = false;
if (!loaded) {
diff --git a/device/src/interop.c b/device/src/interop.c
index 50020f7..33f963f 100644
--- a/device/src/interop.c
+++ b/device/src/interop.c
@@ -62,6 +62,40 @@
if (feature == interop_name_database[i].feature &&
strlen(name) >= interop_name_database[i].length &&
strncmp(name, interop_name_database[i].name, interop_name_database[i].length) == 0) {
+ LOG_WARN(LOG_TAG, "%s() Device with name: %s is a match for interop workaround %s", __func__,
+ name, interop_feature_string_(feature));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool interop_match_manufacturer(const interop_feature_t feature, uint16_t manufacturer) {
+ const size_t db_size = sizeof(interop_manufacturer_database) / sizeof(interop_manufacturer_t);
+
+ for (size_t i = 0; i != db_size; ++i) {
+ if (feature == interop_manufacturer_database[i].feature &&
+ manufacturer == interop_manufacturer_database[i].manufacturer) {
+ LOG_WARN(LOG_TAG, "%s() Device with manufacturer id: %d is a match for interop "
+ "workaround %s", __func__, manufacturer, interop_feature_string_(feature));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool interop_match_vendor_product_ids(const interop_feature_t feature,
+ uint16_t vendor_id, uint16_t product_id) {
+ const size_t db_size = sizeof(interop_hid_multitouch_database) / sizeof(interop_hid_multitouch_t);
+
+ for (size_t i = 0; i != db_size; ++i) {
+ if (vendor_id == interop_hid_multitouch_database[i].vendor_id &&
+ product_id == interop_hid_multitouch_database[i].product_id) {
+ LOG_WARN(LOG_TAG, "%s() Device with vendor_id: %d product_id: %d is a match for "
+ "interop workaround %s", __func__, vendor_id, product_id,
+ interop_feature_string_(feature));
return true;
}
}
@@ -115,6 +149,14 @@
CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
+ CASE_RETURN_STR(INTEROP_DISABLE_SDP_AFTER_PAIRING)
+ CASE_RETURN_STR(INTEROP_DISABLE_AUTH_FOR_HID_POINTING)
+ CASE_RETURN_STR(INTEROP_REMOVE_HID_DIG_DESCRIPTOR)
+ CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_DURING_SCO)
+ CASE_RETURN_STR(INTEROP_INCREASE_AG_CONN_TIMEOUT)
+ CASE_RETURN_STR(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS)
+ CASE_RETURN_STR(INTEROP_ADV_AVRCP_VER_1_3)
+ CASE_RETURN_STR(INTEROP_DISABLE_AAC_CODEC)
}
return "UNKNOWN";
diff --git a/embdrv/sbc/encoder/include/sbc_encoder.h b/embdrv/sbc/encoder/include/sbc_encoder.h
index a1c963f..977473d 100644
--- a/embdrv/sbc/encoder/include/sbc_encoder.h
+++ b/embdrv/sbc/encoder/include/sbc_encoder.h
@@ -175,6 +175,7 @@
SINT16 *ps16PcmBuffer;
#else
SINT16 as16PcmBuffer[SBC_MAX_NUM_FRAME*SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
+ SINT32 as32PcmBuffer[SBC_MAX_NUM_FRAME*SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
#endif
SINT16 s16ScartchMemForBitAlloc[16];
diff --git a/hci/Android.mk b/hci/Android.mk
index 0727100..ddb533d 100644
--- a/hci/Android.mk
+++ b/hci/Android.mk
@@ -34,9 +34,14 @@
LOCAL_MODULE := libbt-hci
-ifeq ($(BLUETOOTH_HCI_USE_MCT),true)
-LOCAL_CFLAGS += -DHCI_USE_MCT
+ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+ LOCAL_CFLAGS += -DBTSNOOP_DEFAULT=TRUE
endif
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DENABLE_DBG_FLAGS
+endif
+
LOCAL_CFLAGS += $(bluetooth_CFLAGS)
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
diff --git a/hci/include/bt_vendor_lib.h b/hci/include/bt_vendor_lib.h
index b4396ea..82c46b6 100644
--- a/hci/include/bt_vendor_lib.h
+++ b/hci/include/bt_vendor_lib.h
@@ -196,6 +196,12 @@
*/
BT_VND_OP_A2DP_OFFLOAD_STOP,
+ FM_VND_OP_POWER_CTRL,
+
+ BT_VND_OP_FM_USERIAL_OPEN,
+
+ BT_VND_OP_FM_USERIAL_CLOSE,
+
} bt_vendor_opcode_t;
/** Power on/off control states */
@@ -391,6 +397,11 @@
/** Closes the interface */
void (*cleanup)(void);
+
+ /** SSR cleanup is used in HW reset cases
+ * which would close all the client channels
+ * and turns off the chip*/
+ void (*ssr_cleanup)(int reason);
} bt_vendor_interface_t;
diff --git a/hci/include/hci_hal.h b/hci/include/hci_hal.h
index 93d9a2f..454c8ed 100644
--- a/hci/include/hci_hal.h
+++ b/hci/include/hci_hal.h
@@ -75,6 +75,9 @@
// This is safe in the bluetooth context, because there is always a buffer
// header that prefixes data you're sending.
uint16_t (*transmit_data)(serial_data_type_t type, uint8_t *data, uint16_t length);
+
+ // to detect the SSR in PR controller
+ bool (*dev_in_reset)(void);
} hci_hal_t;
// Gets the correct hal implementation, as compiled for.
diff --git a/hci/include/hci_internals.h b/hci/include/hci_internals.h
index 6b9fb01..e92af5e 100644
--- a/hci/include/hci_internals.h
+++ b/hci/include/hci_internals.h
@@ -18,6 +18,14 @@
#pragma once
+#define REMOVE_EAGER_THREADS TRUE
+
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+#include "osi/include/allocator.h"
+#include "osi/include/thread.h"
+#include "osi/include/reactor.h"
+#endif
+
// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
#define HCI_COMMAND_PREAMBLE_SIZE 3
// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
@@ -26,3 +34,31 @@
#define HCI_SCO_PREAMBLE_SIZE 3
// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
#define HCI_EVENT_PREAMBLE_SIZE 2
+
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+struct hci_reader_t {
+ int inbound_fd;
+
+ const allocator_t *allocator;
+ size_t buffer_size;
+ uint8_t *data_buffer;
+ int rd_ptr;
+ int wr_ptr;
+
+ thread_t *inbound_read_thread;
+ reactor_object_t *inbound_read_object;
+};
+typedef struct hci_reader_t hci_reader_t;
+typedef void (*hci_reader_cb)(void *context);
+
+hci_reader_t *hci_reader_new(
+ int fd_to_read,
+ size_t buffer_size,
+ size_t max_buffer_count,
+ thread_t *thread,
+ hci_reader_cb read_cb
+ );
+
+size_t hci_reader_read(hci_reader_t *reader, uint8_t *buffer, size_t max_size);
+void hci_reader_free(hci_reader_t *reader);
+#endif
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
index 54e1e4a..aba7c09 100644
--- a/hci/include/hci_layer.h
+++ b/hci/include/hci_layer.h
@@ -98,6 +98,11 @@
// Send some data downward through the HCI layer
void (*transmit_downward)(data_dispatcher_type_t type, void *data);
+
+ /** SSR cleanup is used in HW reset cases
+ ** which would close all the client channels
+ ** and turns off the chip*/
+ void (*ssr_cleanup)(int reason);
} hci_t;
const hci_t *hci_layer_get_interface();
diff --git a/hci/include/hci_packet_factory.h b/hci/include/hci_packet_factory.h
index ac6f12a..a6520ba 100644
--- a/hci/include/hci_packet_factory.h
+++ b/hci/include/hci_packet_factory.h
@@ -38,9 +38,11 @@
BT_HDR *(*make_ble_read_supported_states)(void);
BT_HDR *(*make_ble_read_local_supported_features)(void);
BT_HDR *(*make_ble_read_resolving_list_size)(void);
+ BT_HDR *(*make_ble_read_adv_ext_size)(void);
BT_HDR *(*make_ble_read_suggested_default_data_length)(void);
BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask);
BT_HDR *(*make_read_local_supported_codecs)(void);
+ BT_HDR *(*make_ble_read_offload_features_support)(void);
} hci_packet_factory_t;
const hci_packet_factory_t *hci_packet_factory_get_interface();
diff --git a/hci/include/hci_packet_parser.h b/hci/include/hci_packet_parser.h
index ba3b193..b83a71f 100644
--- a/hci/include/hci_packet_parser.h
+++ b/hci/include/hci_packet_parser.h
@@ -87,6 +87,11 @@
uint8_t *resolving_list_size_ptr
);
+ void (*parse_ble_read_adv_ext_size_response) (
+ BT_HDR *response,
+ uint8_t *ble_adv_ext_size
+ );
+
void (*parse_ble_read_suggested_default_data_length_response)(
BT_HDR *response,
uint16_t *ble_default_packet_length_ptr
@@ -96,6 +101,10 @@
BT_HDR *response,
uint8_t *number_of_local_supported_codecs, uint8_t *local_supported_codecs);
+ void (*parse_ble_read_offload_features_response)(
+ BT_HDR *response,
+ bool *ble_offload_features_supported);
+
} hci_packet_parser_t;
const hci_packet_parser_t *hci_packet_parser_get_interface();
diff --git a/hci/include/low_power_manager.h b/hci/include/low_power_manager.h
index 95f990a..138b3eb 100644
--- a/hci/include/low_power_manager.h
+++ b/hci/include/low_power_manager.h
@@ -41,6 +41,9 @@
// Tell the low power manager that you're done transmitting data. Must be
// called on the thread provided at initialization time.
void (*transmit_done)(void);
+
+ void (*start_idle_timer)(bool check_LPM);
+ void (*stop_idle_timer)();
} low_power_manager_t;
const low_power_manager_t *low_power_manager_get_interface();
diff --git a/hci/include/vendor.h b/hci/include/vendor.h
index e147b23..791c3da 100644
--- a/hci/include/vendor.h
+++ b/hci/include/vendor.h
@@ -68,6 +68,11 @@
// Registers a callback for an asynchronous vendor-specific command.
void (*set_callback)(vendor_async_opcode_t opcode, vendor_cb callback);
+
+ /** SSR cleanup is used in HW reset cases
+ ** which would close all the client channels
+ ** and turns off the chip*/
+ void (*ssr_cleanup) (int reason);
} vendor_t;
const vendor_t *vendor_get_interface();
diff --git a/hci/src/btsnoop.c b/hci/src/btsnoop.c
index dbc9bb2..88c37f7 100644
--- a/hci/src/btsnoop.c
+++ b/hci/src/btsnoop.c
@@ -20,6 +20,7 @@
#include <arpa/inet.h>
#include <assert.h>
+#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -29,8 +30,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/poll.h>
#include <unistd.h>
#include "bt_types.h"
@@ -51,6 +54,19 @@
static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
static const stack_config_t *stack_config;
+extern int client_socket_btsnoop;
+static long int gmt_offset;
+#define USEC_PER_SEC 1000000L
+#define MAX_SNOOP_BUF_SIZE 1200
+
+// External BT snoop
+bool hci_ext_dump_enabled = false;
+
+/* snoop config from the config file, required for userdebug
+ build where snoop is enabled by default.
+ power/perf measurements need the snoop to be disabled.
+*/
+bool btsnoop_conf_from_file = false;
static int logfile_fd = INVALID_FD;
static bool module_started;
@@ -68,7 +84,20 @@
// Module lifecycle functions
static future_t *start_up(void) {
+ time_t t = time(NULL);
+ struct tm tm_cur;
+
+ localtime_r (&t, &tm_cur);
+ LOG_INFO(LOG_TAG, "%s Time GMT offset %ld\n", __func__, tm_cur.tm_gmtoff);
+ gmt_offset = tm_cur.tm_gmtoff;
+
module_started = true;
+ stack_config->get_btsnoop_ext_options(&hci_ext_dump_enabled, &btsnoop_conf_from_file);
+#ifdef BLUEDROID_DEBUG
+ if (btsnoop_conf_from_file == false) {
+ hci_ext_dump_enabled = true;
+ }
+#endif
update_logging();
return NULL;
@@ -76,6 +105,9 @@
static future_t *shut_down(void) {
module_started = false;
+ if (hci_ext_dump_enabled == true) {
+ STOP_SNOOP_LOGGING();
+ }
update_logging();
return NULL;
@@ -141,17 +173,19 @@
static uint64_t btsnoop_timestamp(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
+ tv.tv_sec += gmt_offset;
// Timestamp is in microseconds.
- uint64_t timestamp = tv.tv_sec * 1000 * 1000LL;
+ uint64_t timestamp = ((uint64_t)tv.tv_sec) * 1000 * 1000LL;
timestamp += tv.tv_usec;
timestamp += BTSNOOP_EPOCH_DELTA;
return timestamp;
}
static void update_logging() {
+ bool btsnoop_log_output = stack_config->get_btsnoop_turned_on();
bool should_log = module_started &&
- (logging_enabled_via_api || stack_config->get_btsnoop_turned_on());
+ (logging_enabled_via_api || btsnoop_log_output || hci_ext_dump_enabled);
if (should_log == is_logging)
return;
@@ -159,6 +193,14 @@
is_logging = should_log;
if (should_log) {
btsnoop_net_open();
+#ifdef BLUEDROID_DEBUG
+ if(!btsnoop_log_output)
+#endif
+ {
+ if (logging_enabled_via_api || hci_ext_dump_enabled == true) {
+ START_SNOOP_LOGGING();
+ }
+ }
const char *log_path = stack_config->get_btsnoop_log_path();
@@ -192,17 +234,37 @@
}
static void btsnoop_write(const void *data, size_t length) {
+ if (client_socket_btsnoop != -1) {
+ btsnoop_net_write(data, length);
+ /* skip writing to file if external client is connected*/
+ return;
+ }
+
if (logfile_fd != INVALID_FD)
write(logfile_fd, data, length);
-
- btsnoop_net_write(data, length);
}
+#ifdef DEBUG_SNOOP
+static uint64_t time_now_us() {
+ struct timespec ts_now;
+ clock_gettime(CLOCK_BOOTTIME, &ts_now);
+ return ((uint64_t)ts_now.tv_sec * USEC_PER_SEC) + ((uint64_t)ts_now.tv_nsec / 1000);
+}
+#endif
+
static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) {
int length_he = 0;
int length;
int flags;
int drops = 0;
+ struct pollfd pfd;
+#ifdef DEBUG_SNOOP
+ uint64_t ts_begin;
+ uint64_t ts_end, ts_diff;
+#endif
+ uint8_t snoop_buf[MAX_SNOOP_BUF_SIZE] = {0};
+ uint32_t offset = 0;
+
switch (type) {
case kCommandPacket:
length_he = packet[2] + 4;
@@ -232,12 +294,73 @@
time_hi = htonl(time_hi);
time_lo = htonl(time_lo);
- btsnoop_write(&length, 4);
- btsnoop_write(&length, 4);
- btsnoop_write(&flags, 4);
- btsnoop_write(&drops, 4);
- btsnoop_write(&time_hi, 4);
- btsnoop_write(&time_lo, 4);
- btsnoop_write(&type, 1);
- btsnoop_write(packet, length_he - 1);
+ /* store the length in both original and included fields */
+ memcpy(snoop_buf + offset, &length, 4);
+ offset += 4;
+ memcpy(snoop_buf + offset, &length, 4);
+ offset += 4;
+
+ /* flags: */
+ memcpy(snoop_buf + offset, &flags, 4);
+ offset += 4;
+
+ /* drops: none */
+ memcpy(snoop_buf + offset, &drops, 4);
+ offset += 4;
+
+ /* time */
+ memcpy(snoop_buf + offset, &time_hi, 4);
+ offset += 4;
+ memcpy(snoop_buf + offset, &time_lo, 4);
+ offset = offset + 4;
+
+ snoop_buf[offset] = type;
+ offset += 1;
+ if (offset + length_he + 1 > MAX_SNOOP_BUF_SIZE) {
+ LOG_ERROR(LOG_TAG, "Bad packet length, downgrading the length to %d from %d",
+ MAX_SNOOP_BUF_SIZE - offset - 1, length_he);
+ length_he = MAX_SNOOP_BUF_SIZE - offset - 1;
+ }
+ memcpy(snoop_buf + offset, packet, length_he - 1);
+
+ if (client_socket_btsnoop != -1) {
+ pfd.fd = client_socket_btsnoop;
+ pfd.events = POLLOUT;
+#ifdef DEBUG_SNOOP
+ ts_begin = time_now_us();
+#endif
+
+ if (poll(&pfd, 1, 10) == 0) {
+ LOG_ERROR(LOG_TAG, "btsnoop poll : Taking more than 10 ms : skip dump");
+#ifdef DEBUG_SNOOP
+ ts_end = time_now_us();
+ ts_diff = ts_end - ts_begin;
+ if (ts_diff > 10000) {
+ LOG_ERROR(LOG_TAG, "btsnoop poll T/O : took more time %08lld us", ts_diff);
+ }
+#endif
+ return;
+ }
+
+#ifdef DEBUG_SNOOP
+ ts_end = time_now_us();
+ ts_diff = ts_end - ts_begin;
+ if (ts_diff > 10000) {
+ LOG_ERROR(LOG_TAG, "btsnoop poll : took more time %08lld us", ts_diff);
+ }
+#endif
+ }
+#ifdef DEBUG_SNOOP
+ ts_begin = time_now_us();
+#endif
+
+ btsnoop_write(snoop_buf, offset + length_he - 1);
+
+#ifdef DEBUG_SNOOP
+ ts_end = time_now_us();
+ ts_diff = ts_end - ts_begin;
+ if (ts_diff > 10000) {
+ LOG_ERROR(LOG_TAG, "btsnoop write : Write took more time %08lld us", ts_diff);
+ }
+#endif
}
diff --git a/hci/src/btsnoop_net.c b/hci/src/btsnoop_net.c
index 0bfad4e..274b546 100644
--- a/hci/src/btsnoop_net.c
+++ b/hci/src/btsnoop_net.c
@@ -19,6 +19,9 @@
#define LOG_TAG "bt_snoop_net"
#include <assert.h>
+#include <cutils/sockets.h>
+#include <sys/un.h>
+#include <sys/poll.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
@@ -43,12 +46,37 @@
static bool listen_thread_valid_ = false;
static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
static int listen_socket_ = -1;
-static int client_socket_ = -1;
+int client_socket_btsnoop = -1;
+
+/*
+ local socket for writing from different process
+ to limit blocking of HCI threads.
+*/
+#define LOCAL_SOCKET_NAME "bthcitraffic"
+static int listen_socket_local_ = -1;
+
+static int local_socket_create(void) {
+
+ listen_socket_local_ = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(listen_socket_local_ < 0) {
+ return -1;
+ }
+
+ if(socket_local_server_bind(listen_socket_local_, LOCAL_SOCKET_NAME,
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) {
+ LOG_ERROR(LOG_TAG, "Failed to create Local Socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (listen(listen_socket_local_, 1) < 0) {
+ LOG_ERROR(LOG_TAG, "Local socket listen failed (%s)", strerror(errno));
+ close(listen_socket_local_);
+ return -1;
+ }
+ return listen_socket_local_;
+}
void btsnoop_net_open() {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
if (!listen_thread_valid_) {
@@ -59,44 +87,55 @@
}
void btsnoop_net_close() {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
if (listen_thread_valid_) {
+#if (defined(BT_NET_DEBUG) && (NET_DEBUG == TRUE))
+ // Disable using network sockets for security reasons
shutdown(listen_socket_, SHUT_RDWR);
+#endif
+ shutdown(listen_socket_local_, SHUT_RDWR);
pthread_join(listen_thread_, NULL);
- safe_close_(&client_socket_);
+ safe_close_(&client_socket_btsnoop);
listen_thread_valid_ = false;
}
}
void btsnoop_net_write(const void *data, size_t length) {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
+ ssize_t ret;
pthread_mutex_lock(&client_socket_lock_);
- if (client_socket_ != -1) {
- ssize_t ret;
- OSI_NO_INTR(ret = send(client_socket_, data, length, 0));
-
- if (ret == -1 && errno == ECONNRESET) {
- safe_close_(&client_socket_);
- }
+ if (client_socket_btsnoop != -1) {
+ do {
+ if ((ret = send(client_socket_btsnoop, data, length, 0)) == -1 && errno == ECONNRESET) {
+ safe_close_(&client_socket_btsnoop);
+ LOG_INFO(LOG_TAG, "%s conn closed", __func__);
+ }
+ if ((size_t) ret < length) {
+ LOG_ERROR(LOG_TAG, "%s: send : not able to write complete packet", __func__);
+ }
+ length -= ret;
+ } while ((length > 0) && (ret != -1));
}
+
pthread_mutex_unlock(&client_socket_lock_);
}
static void *listen_fn_(UNUSED_ATTR void *context) {
+ fd_set sock_fds;
+ int fd_max = -1, retval;
prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
+ FD_ZERO(&sock_fds);
+
+ // Disable using network sockets for security reasons
listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_socket_ == -1) {
LOG_ERROR(LOG_TAG, "%s socket creation failed: %s", __func__, strerror(errno));
goto cleanup;
}
+ FD_SET(listen_socket_, &sock_fds);
+ fd_max = listen_socket_;
int enable = 1;
if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
@@ -118,29 +157,73 @@
goto cleanup;
}
+ if (local_socket_create() != -1) {
+ if (listen_socket_local_ > fd_max) {
+ fd_max = listen_socket_local_;
+ }
+ FD_SET(listen_socket_local_, &sock_fds);
+ }
+
+ if (fd_max == -1) {
+ LOG_ERROR(LOG_TAG, "%s No sockets to wait for conn..", __func__);
+ return NULL;
+ }
+
for (;;) {
- int client_socket;
- OSI_NO_INTR(client_socket = accept(listen_socket_, NULL, NULL));
- if (client_socket == -1) {
- if (errno == EINVAL || errno == EBADF) {
- break;
+ int client_socket = -1;
+
+ LOG_DEBUG(LOG_TAG, "waiting for client connection");
+
+ if ((retval = select(fd_max + 1, &sock_fds, NULL, NULL, NULL)) == -1) {
+ LOG_ERROR(LOG_TAG, "%s select failed %s", __func__, strerror(errno));
+ goto cleanup;
+ }
+
+ if ((listen_socket_ != -1) && FD_ISSET(listen_socket_, &sock_fds)) {
+ client_socket = accept(listen_socket_, NULL, NULL);
+ if (client_socket == -1) {
+ if (errno == EINVAL || errno == EBADF) {
+ LOG_WARN(LOG_TAG, "%s error accepting TCP socket: %s", __func__, strerror(errno));
+ break;
+ }
+ LOG_WARN(LOG_TAG, "%s error accepting TCP socket: %s", __func__, strerror(errno));
+ continue;
}
- LOG_WARN(LOG_TAG, "%s error accepting socket: %s", __func__, strerror(errno));
- continue;
+ } else if ((listen_socket_local_ != -1) && FD_ISSET(listen_socket_local_, &sock_fds)){
+ struct sockaddr_un cliaddr;
+ int length;
+
+ client_socket = accept(listen_socket_local_, (struct sockaddr *)&cliaddr, (socklen_t *)&length);
+ if (client_socket == -1) {
+ if (errno == EINVAL || errno == EBADF) {
+ LOG_WARN(LOG_TAG, "%s error accepting LOCAL socket: %s", __func__, strerror(errno));
+ break;
+ }
+ LOG_WARN(LOG_TAG, "%s error accepting LOCAL socket: %s", __func__, strerror(errno));
+ continue;
+ }
}
/* When a new client connects, we have to send the btsnoop file header. This allows
a decoder to treat the session as a new, valid btsnoop file. */
pthread_mutex_lock(&client_socket_lock_);
- safe_close_(&client_socket_);
- client_socket_ = client_socket;
-
- OSI_NO_INTR(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
+ safe_close_(&client_socket_btsnoop);
+ client_socket_btsnoop = client_socket;
+ send(client_socket_btsnoop, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0);
pthread_mutex_unlock(&client_socket_lock_);
+
+ FD_ZERO(&sock_fds);
+ if(listen_socket_ != -1) {
+ FD_SET(listen_socket_, &sock_fds);
+ }
+ if(listen_socket_local_ != -1) {
+ FD_SET(listen_socket_local_, &sock_fds);
+ }
}
cleanup:
safe_close_(&listen_socket_);
+ safe_close_(&listen_socket_local_);
return NULL;
}
diff --git a/hci/src/hci_hal.c b/hci/src/hci_hal.c
index fa526ce..8337695 100644
--- a/hci/src/hci_hal.c
+++ b/hci/src/hci_hal.c
@@ -15,14 +15,112 @@
* limitations under the License.
*
******************************************************************************/
-
+#include <string.h>
#include "hci_hal.h"
+#include "hci_internals.h"
+#include "bt_utils.h"
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+#include <assert.h>
+#include "osi/include/eager_reader.h"
+#include "osi/include/osi.h"
+#include "osi/include/log.h"
+#endif
+
+bt_soc_type soc_type;
const hci_hal_t *hci_hal_get_interface() {
-#if HCI_USE_MCT
- return hci_hal_mct_get_interface();
-#else
- return hci_hal_h4_get_interface();
-#endif
+ soc_type = get_soc_type();
+
+ if (soc_type == BT_SOC_ROME || soc_type == BT_SOC_CHEROKEE) {
+ return hci_hal_h4_get_interface();
+ } else {
+ return hci_hal_mct_get_interface();
+ }
}
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+void hci_reader_free(hci_reader_t *reader) {
+ if (!reader)
+ return;
+
+ // Only unregister from the input if we actually did register
+ if (reader->inbound_read_object)
+ reactor_unregister(reader->inbound_read_object);
+
+ // Free the current buffer, because it's not in the queue
+ // and won't be freed below
+ if (reader->data_buffer)
+ osi_free(reader->data_buffer);
+
+ osi_free(reader);
+}
+
+hci_reader_t *hci_reader_new(
+ int fd_to_read,
+ size_t buffer_size,
+ size_t max_buffer_count,
+ thread_t *thread,
+ hci_reader_cb read_cb
+ ) {
+
+ assert(fd_to_read != INVALID_FD);
+ assert(buffer_size > 0);
+ assert(max_buffer_count > 0);
+
+
+ hci_reader_t *ret = osi_calloc(sizeof(hci_reader_t));
+ if (!ret) {
+ LOG_ERROR("%s unable to allocate memory for new hci_reader.", __func__);
+ goto error;
+ }
+
+ ret->inbound_fd = fd_to_read;
+
+ ret->data_buffer = osi_calloc(buffer_size);
+ ret->buffer_size = buffer_size;
+ ret->rd_ptr = 0;
+ ret->wr_ptr = 0;
+
+ ret->inbound_read_thread = thread;
+ if (!ret->inbound_read_thread) {
+ LOG_ERROR("%s unable to make reading thread.", __func__);
+ goto error;
+ }
+
+ ret->inbound_read_object = reactor_register(
+ thread_get_reactor(ret->inbound_read_thread),
+ fd_to_read,
+ ret,
+ read_cb,
+ NULL
+ );
+
+ return ret;
+
+error:;
+ hci_reader_free(ret);
+ return NULL;
+}
+
+size_t hci_reader_read(hci_reader_t *reader, uint8_t *buffer, size_t req_size) {
+ int bytes_read = 0;
+ assert(reader != NULL);
+ assert(buffer != NULL);
+
+ // If the caller wants nonblocking behavior, poll to see if we have
+ // any bytes available before reading.
+ if (reader->rd_ptr < reader->wr_ptr) {
+ bytes_read = reader->wr_ptr - reader->rd_ptr;
+ if ((size_t) bytes_read > req_size)
+ bytes_read = req_size;
+ memcpy(buffer, reader->data_buffer+reader->rd_ptr, bytes_read);
+ reader->rd_ptr += bytes_read;
+ } else {
+ bytes_read = read(reader->inbound_fd, buffer, req_size);
+ if(bytes_read == -1)
+ bytes_read = 0;
+ }
+
+ return bytes_read;
+}
+#endif
diff --git a/hci/src/hci_hal_h4.c b/hci/src/hci_hal_h4.c
index 9c7afe5..a1a9b14 100644
--- a/hci/src/hci_hal_h4.c
+++ b/hci/src/hci_hal_h4.c
@@ -48,13 +48,23 @@
static thread_t *thread; // Not owned by us
static int uart_fd;
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static hci_reader_t *uart_stream;
+#else
static eager_reader_t *uart_stream;
+#endif
static serial_data_type_t current_data_type;
static bool stream_has_interpretation;
static bool stream_corruption_detected;
static uint8_t stream_corruption_bytes_to_ignore;
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static void event_uart_has_bytes(void *context);
+#else
static void event_uart_has_bytes(eager_reader_t *reader, void *context);
+static bool stream_corrupted_during_le_scan_workaround(const uint8_t byte_read);
+#endif
+
// Interface functions
@@ -85,20 +95,28 @@
goto error;
}
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ uart_stream = hci_reader_new(uart_fd, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, thread, event_uart_has_bytes);
+ if (!uart_stream) {
+ LOG_ERROR("%s unable to create hci reader for the uart serial port.", __func__);
+ goto error;
+ }
+#else
uart_stream = eager_reader_new(uart_fd, &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_single_channel");
if (!uart_stream) {
LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the uart serial port.", __func__);
goto error;
}
+ eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);
+ thread_set_priority(eager_reader_get_read_thread(uart_stream), HCI_THREAD_PRIORITY);
+#endif
stream_has_interpretation = false;
stream_corruption_detected = false;
stream_corruption_bytes_to_ignore = 0;
- eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);
// Raise thread priorities to keep up with audio
thread_set_priority(thread, HCI_THREAD_PRIORITY);
- thread_set_priority(eager_reader_get_read_thread(uart_stream), HCI_THREAD_PRIORITY);
return true;
@@ -110,7 +128,13 @@
static void hal_close() {
LOG_INFO(LOG_TAG, "%s", __func__);
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ hci_reader_free(uart_stream);
+#else
eager_reader_free(uart_stream);
+#endif
+ uart_stream = NULL;
+
vendor->send_command(VENDOR_CLOSE_USERIAL, NULL);
uart_fd = INVALID_FD;
}
@@ -127,16 +151,38 @@
return 0;
}
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ return hci_reader_read(uart_stream, buffer, max_size);
+#else
return eager_reader_read(uart_stream, buffer, max_size);
+#endif
}
static void packet_finished(serial_data_type_t type) {
- if (!stream_has_interpretation)
+ if (!stream_has_interpretation) {
LOG_ERROR(LOG_TAG, "%s with no existing stream interpretation.", __func__);
- else if (current_data_type != type)
+ } else if (current_data_type != type) {
LOG_ERROR(LOG_TAG, "%s with different type than existing interpretation.", __func__);
+ }
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ if (uart_stream->rd_ptr == uart_stream->wr_ptr) {
+ uart_stream->rd_ptr = uart_stream->wr_ptr = 0;
+ stream_has_interpretation = false;
+ } else {
+ uint8_t type_byte;
+ type_byte = uart_stream->data_buffer[uart_stream->rd_ptr++];
+ if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
+ LOG_ERROR("%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__,
+ type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
+ return;
+ }
+ current_data_type = type_byte;
+ callbacks->data_ready(current_data_type);
+ }
+#else
stream_has_interpretation = false;
+#endif
}
static uint16_t transmit_data(serial_data_type_t type, uint8_t *data, uint16_t length) {
@@ -184,6 +230,11 @@
return transmitted_length;
}
+static bool hal_dev_in_reset()
+{
+ return false;
+}
+
// Internal functions
// WORKAROUND:
@@ -194,6 +245,7 @@
// skip the correct amount of bytes in the stream to re-synchronize onto
// a packet boundary.
// Function returns true if |byte_read| has been processed by the workaround.
+#if (!defined(REMOVE_EAGER_THREADS) || ((defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == FALSE))))
static bool stream_corrupted_during_le_scan_workaround(const uint8_t byte_read)
{
if (!stream_corruption_detected && byte_read == HCI_BLE_EVENT) {
@@ -219,8 +271,35 @@
return false;
}
-
+#endif
// See what data is waiting, and notify the upper layer
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static void event_uart_has_bytes(void *context) {
+ uint8_t type_byte;
+ int bytes_read;
+ hci_reader_t *reader = (hci_reader_t *) context;
+ bytes_read = read(reader->inbound_fd, reader->data_buffer + reader->wr_ptr, reader->buffer_size - reader->wr_ptr);
+
+ if (bytes_read <= 0) {
+ LOG_ERROR("%s could not read HCI message type", __func__);
+ return;
+ }
+ reader->wr_ptr += bytes_read;
+ if (!stream_has_interpretation) {
+ type_byte = reader->data_buffer[reader->rd_ptr++];
+
+ if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
+ LOG_ERROR("%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
+ return;
+ }
+
+ stream_has_interpretation = true;
+ current_data_type = type_byte;
+ }
+
+ callbacks->data_ready(current_data_type);
+}
+#else
static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *context) {
if (stream_has_interpretation) {
callbacks->data_ready(current_data_type);
@@ -246,6 +325,7 @@
current_data_type = type_byte;
}
}
+#endif
static const hci_hal_t interface = {
hal_init,
@@ -256,6 +336,7 @@
read_data,
packet_finished,
transmit_data,
+ hal_dev_in_reset
};
const hci_hal_t *hci_hal_h4_get_interface() {
diff --git a/hci/src/hci_hal_mct.c b/hci/src/hci_hal_mct.c
index 669a9f8..2406567 100644
--- a/hci/src/hci_hal_mct.c
+++ b/hci/src/hci_hal_mct.c
@@ -33,6 +33,9 @@
#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
+#include <termios.h>
+#include <sys/ioctl.h>
+
// Our interface and modules we import
static const hci_hal_t interface;
static const hci_hal_callbacks_t *callbacks;
@@ -41,12 +44,22 @@
static thread_t *thread; // Not owned by us
static int uart_fds[CH_MAX];
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static hci_reader_t *event_stream;
+static hci_reader_t *acl_stream;
+#else
static eager_reader_t *event_stream;
static eager_reader_t *acl_stream;
+#endif
static uint16_t transmit_data_on(int fd, uint8_t *data, uint16_t length);
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static void event_event_stream_has_bytes(void *context);
+static void event_acl_stream_has_bytes(void *context);
+#else
static void event_event_stream_has_bytes(eager_reader_t *reader, void *context);
static void event_acl_stream_has_bytes(eager_reader_t *reader, void *context);
+#endif
// Interface functions
@@ -93,6 +106,21 @@
goto error;
}
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ event_stream = hci_reader_new(uart_fds[CH_EVT], HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX,
+ thread, event_event_stream_has_bytes);
+ if (!event_stream) {
+ LOG_ERROR("%s unable to create hci reader for the event uart serial port.", __func__);
+ goto error;
+ }
+
+ acl_stream = hci_reader_new(uart_fds[CH_ACL_IN], HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX,
+ thread, event_acl_stream_has_bytes);
+ if (!acl_stream) {
+ LOG_ERROR("%s unable to create hci reader for the acl-in uart serial port.", __func__);
+ goto error;
+ }
+#else
event_stream = eager_reader_new(uart_fds[CH_EVT], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct");
if (!event_stream) {
LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the event uart serial port.", __func__);
@@ -108,6 +136,8 @@
eager_reader_register(event_stream, thread_get_reactor(thread), event_event_stream_has_bytes, NULL);
eager_reader_register(acl_stream, thread_get_reactor(thread), event_acl_stream_has_bytes, NULL);
+#endif
+
return true;
error:;
@@ -118,20 +148,66 @@
static void hal_close() {
LOG_INFO(LOG_TAG, "%s", __func__);
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ hci_reader_free(event_stream);
+ event_stream = NULL;
+ hci_reader_free(acl_stream);
+ acl_stream = NULL;
+#else
eager_reader_free(event_stream);
+ event_stream = NULL;
+
eager_reader_free(acl_stream);
+ acl_stream = NULL;
+#endif
+
vendor->send_command(VENDOR_CLOSE_USERIAL, NULL);
for (int i = 0; i < CH_MAX; i++)
uart_fds[i] = INVALID_FD;
}
+static bool hal_dev_in_reset()
+{
+ volatile int serial_bits;
+ bool dev_reset_done =0;
+ uint8_t retry_count = 0;
+ ioctl(uart_fds[CH_EVT], TIOCMGET, &serial_bits);
+ if (serial_bits & TIOCM_OUT2) {
+ while(serial_bits & TIOCM_OUT1) {
+ LOG_WARN(LOG_TAG,"userial_device in reset \n");
+ sleep(2);
+ retry_count++;
+ ioctl(uart_fds[CH_EVT], TIOCMGET, &serial_bits);
+ if((serial_bits & TIOCM_OUT1))
+ dev_reset_done = 0;
+ else
+ dev_reset_done = 1;
+ if(retry_count == 6) {
+ //treat it as ssr completed to kill the bt
+ // process
+ dev_reset_done = 1;
+ break;
+ }
+ }
+ }
+ return dev_reset_done;
+}
+
static size_t read_data(serial_data_type_t type, uint8_t *buffer, size_t max_size) {
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ if (type == DATA_TYPE_ACL) {
+ return hci_reader_read(acl_stream, buffer, max_size);
+ } else if (type == DATA_TYPE_EVENT) {
+ return hci_reader_read(event_stream, buffer, max_size);
+ }
+#else
if (type == DATA_TYPE_ACL) {
return eager_reader_read(acl_stream, buffer, max_size);
} else if (type == DATA_TYPE_EVENT) {
return eager_reader_read(event_stream, buffer, max_size);
}
+#endif
LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
return 0;
@@ -139,6 +215,25 @@
static void packet_finished(UNUSED_ATTR serial_data_type_t type) {
// not needed by this protocol
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+ hci_reader_t *stream = NULL;
+ if (type == DATA_TYPE_ACL) {
+ stream = acl_stream;
+ } else if (type == DATA_TYPE_EVENT) {
+ stream = event_stream;
+ }
+
+ if(!stream) {
+ LOG_ERROR("%s invalid data type: %d", __func__, type);
+ return;
+ }
+
+ if (stream->rd_ptr == stream->wr_ptr) {
+ stream->rd_ptr = stream->wr_ptr = 0;
+ } else {
+ callbacks->data_ready(type);
+ }
+#endif
}
static uint16_t transmit_data(serial_data_type_t type, uint8_t *data, uint16_t length) {
@@ -180,14 +275,45 @@
return transmitted_length;
}
-static void event_event_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) {
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static void event_event_stream_has_bytes(void *context) {
+ int bytes_read;
+ hci_reader_t *reader = (hci_reader_t *) context;
+ bytes_read = read(reader->inbound_fd, reader->data_buffer+reader->wr_ptr,
+ reader->buffer_size - reader->wr_ptr);
+ if (bytes_read <= 0) {
+ LOG_ERROR("%s could not read HCI message type", __func__);
+ return;
+ }
+ reader->wr_ptr += bytes_read;
callbacks->data_ready(DATA_TYPE_EVENT);
}
+#else
+static void event_event_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) {
+ callbacks->data_ready(DATA_TYPE_EVENT);
+}
+#endif
-static void event_acl_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) {
+#if (defined(REMOVE_EAGER_THREADS) && (REMOVE_EAGER_THREADS == TRUE))
+static void event_acl_stream_has_bytes(void *context) {
// No real concept of incoming SCO typed data, just ACL
+ int bytes_read;
+ hci_reader_t *reader = (hci_reader_t *) context;
+ bytes_read = read(reader->inbound_fd, reader->data_buffer+reader->wr_ptr,
+ reader->buffer_size - reader->wr_ptr);
+ if (bytes_read <= 0) {
+ LOG_ERROR("%s could not read HCI message type", __func__);
+ return;
+ }
+ reader->wr_ptr += bytes_read;
callbacks->data_ready(DATA_TYPE_ACL);
}
+#else
+static void event_acl_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) {
+ // No real concept of incoming SCO typed data, just ACL
+ callbacks->data_ready(DATA_TYPE_ACL);
+}
+#endif
static const hci_hal_t interface = {
hal_init,
@@ -198,6 +324,7 @@
read_data,
packet_finished,
transmit_data,
+ hal_dev_in_reset
};
const hci_hal_t *hci_hal_mct_get_interface() {
diff --git a/hci/src/hci_layer.c b/hci/src/hci_layer.c
index 3a45135..0b7e35a 100644
--- a/hci/src/hci_layer.c
+++ b/hci/src/hci_layer.c
@@ -80,6 +80,12 @@
FINISHED
} receive_state_t;
+typedef enum {
+ HCI_SHUTDOWN,
+ HCI_STARTED,
+ HCI_READY
+} hci_layer_state;
+
typedef struct {
receive_state_t state;
uint16_t bytes_remaining;
@@ -97,13 +103,33 @@
BT_HDR *command;
} waiting_command_t;
+typedef enum {
+ BT_SOC_DEFAULT = 0,
+ BT_SOC_SMD = BT_SOC_DEFAULT,
+ BT_SOC_AR3K,
+ BT_SOC_ROME,
+ BT_SOC_CHEROKEE,
+ /* Add chipset type here */
+ BT_SOC_RESERVED
+} bt_soc_type;
+
+typedef enum {
+ LPM_CONFIG_ALL,
+ LPM_CONFIG_TX,
+ LPM_CONFIG_NONE
+} low_power_config_t;
+
// Using a define here, because it can be stringified for the property lookup
#define DEFAULT_STARTUP_TIMEOUT_MS 8000
#define STRING_VALUE_OF(x) #x
+low_power_config_t lpm_config = LPM_CONFIG_NONE;
+
static const uint32_t EPILOG_TIMEOUT_MS = 3000;
static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 8000;
+extern int soc_type;
+
// Our interface
static bool interface_created;
static hci_t interface;
@@ -125,6 +151,7 @@
static volatile bool firmware_is_configured = false;
static alarm_t *epilog_timer;
static alarm_t *startup_timer;
+static alarm_t *hardware_error_timer;
// Outbound-related
static int command_credits = 1;
@@ -134,12 +161,14 @@
// Inbound-related
static alarm_t *command_response_timer;
static list_t *commands_pending_response;
+static list_t *commands_pending_in_queue;
static pthread_mutex_t commands_pending_response_lock;
static packet_receive_data_t incoming_packets[INBOUND_PACKET_TYPE_COUNT];
// The hand-off point for data going to a higher layer, set by the higher layer
static fixed_queue_t *upwards_data_queue;
+static int hci_state;
static future_t *shut_down();
static void event_finish_startup(void *context);
@@ -152,6 +181,7 @@
static void event_epilog(void *context);
static void epilog_finished_callback(bool success);
static void epilog_timer_expired(void *context);
+static void hardware_error_timer_expired(void *context);
static void event_command_ready(fixed_queue_t *queue, void *context);
static void event_packet_ready(fixed_queue_t *queue, void *context);
@@ -164,6 +194,10 @@
static waiting_command_t *get_waiting_command(command_opcode_t opcode);
static void update_command_response_timer(void);
+static bool create_hw_reset_evt_packet(packet_receive_data_t *incoming);
+
+void ssr_cleanup (int reason);
+
// Module lifecycle functions
static future_t *start_up(void) {
@@ -175,6 +209,22 @@
command_credits = 1;
firmware_is_configured = false;
+ char prop_lpm_config[PROPERTY_VALUE_MAX];
+ osi_property_get("persist.service.bdroid.lpmcfg", prop_lpm_config, "all");
+ if (!strcmp(prop_lpm_config, "all")) {
+ // LPM configured for both Tx and Rx channels
+ lpm_config = LPM_CONFIG_ALL;
+ }
+ else if (!strcmp(prop_lpm_config, "tx")) {
+ // LPM configured for Tx channel only
+ lpm_config = LPM_CONFIG_TX;
+ }
+ else {
+ lpm_config = LPM_CONFIG_NONE;
+ }
+
+ LOG_INFO(LOG_TAG, "%s lpm configure value = %d.", __func__, lpm_config);
+
pthread_mutex_init(&commands_pending_response_lock, NULL);
// TODO(armansito): cutils/properties.h is only being used to pull-in runtime
@@ -230,6 +280,11 @@
LOG_ERROR(LOG_TAG, "%s unable to create list for commands pending response.", __func__);
goto error;
}
+ commands_pending_in_queue = list_new(NULL);
+ if (!commands_pending_in_queue) {
+ LOG_ERROR("%s unable to create list for commands pending response.", __func__);
+ goto error;
+ }
memset(incoming_packets, 0, sizeof(incoming_packets));
@@ -273,6 +328,7 @@
LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
thread_post(thread, event_finish_startup, NULL);
+ hci_state = HCI_STARTED;
return local_startup_future;
error:
@@ -296,12 +352,16 @@
thread_join(thread);
}
+ hci_state = HCI_SHUTDOWN;
+
fixed_queue_free(command_queue, osi_free);
command_queue = NULL;
fixed_queue_free(packet_queue, buffer_allocator->free);
packet_queue = NULL;
list_free(commands_pending_response);
commands_pending_response = NULL;
+ list_free(commands_pending_in_queue);
+ commands_pending_in_queue = NULL;
pthread_mutex_destroy(&commands_pending_response_lock);
@@ -358,6 +418,11 @@
command_complete_cb complete_callback,
command_status_cb status_callback,
void *context) {
+ if (hci_state < HCI_STARTED) {
+ LOG_ERROR("%s Returning, hci_layer not ready", __func__);
+ return;
+ }
+
waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t));
uint8_t *stream = command->data + command->offset;
@@ -395,9 +460,14 @@
if (type == MSG_STACK_TO_HC_HCI_CMD) {
// TODO(zachoverflow): eliminate this call
transmit_command((BT_HDR *)data, NULL, NULL, NULL);
- LOG_WARN(LOG_TAG, "%s legacy transmit of command. Use transmit_command instead.", __func__);
+ LOG_WARN("%s legacy transmit of command. Use transmit_command instead.", __func__);
} else {
+ if (hci_state < HCI_STARTED) {
+ LOG_ERROR("%s Returning, hci_layer not ready", __func__);
+ return;
+ } else {
fixed_queue_enqueue(packet_queue, data);
+ }
}
}
@@ -471,28 +541,64 @@
thread_stop(thread);
}
-// Command/packet transmitting functions
+static void hardware_error_timer_expired(UNUSED_ATTR void *context) {
+ LOG_INFO("%s", __func__);
+ alarm_free(hardware_error_timer);
+ hardware_error_timer = NULL;
+ ssr_cleanup(0x33);//SSR reason 0x33 = HW ERR EVT
+ usleep(20000);
+ kill(getpid(), SIGKILL);
+}
-static void event_command_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
- if (command_credits > 0) {
- waiting_command_t *wait_entry = fixed_queue_dequeue(queue);
- command_credits--;
-
- // Move it to the list of commands awaiting response
+static void send_cmd_to_lower(waiting_command_t *wait_entry) {
+ // Move it to the list of commands awaiting response
pthread_mutex_lock(&commands_pending_response_lock);
list_append(commands_pending_response, wait_entry);
pthread_mutex_unlock(&commands_pending_response_lock);
// Send it off
- low_power_manager->wake_assert();
+ if (LPM_CONFIG_TX == lpm_config) {
+ low_power_manager->stop_idle_timer();;
+ }
+ else {
+ low_power_manager->wake_assert();
+ }
+
+ if (LPM_CONFIG_TX == lpm_config) {
+ low_power_manager->start_idle_timer(false);
+ }
+ else {
+ low_power_manager->transmit_done();
+ }
+
packet_fragmenter->fragment_and_dispatch(wait_entry->command);
- low_power_manager->transmit_done();
update_command_response_timer();
+}
+
+// Command/packet transmitting functions
+
+static void event_command_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+ if (hci_state < HCI_STARTED) {
+ LOG_ERROR("%s Returning, hci_layer not ready", __func__);
+ return;
+ }
+ if (command_credits > 0) {
+ waiting_command_t *wait_entry = fixed_queue_dequeue(queue);
+ command_credits--;
+
+ send_cmd_to_lower(wait_entry);
+ } else {
+ waiting_command_t *wait_entry = fixed_queue_dequeue(queue);
+ list_append(commands_pending_in_queue, wait_entry);
}
}
static void event_packet_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+ if (hci_state < HCI_STARTED) {
+ LOG_ERROR("%s Returning, hci_layer not ready", __func__);
+ return;
+ }
// The queue may be the command queue or the packet queue, we don't care
BT_HDR *packet = (BT_HDR *)fixed_queue_dequeue(queue);
@@ -539,8 +645,39 @@
LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
}
- LOG_ERROR(LOG_TAG, "%s restarting the bluetooth process.", __func__);
- usleep(10000);
+ LOG_ERROR("%s restarting the bluetooth process.", __func__);
+ ssr_cleanup(0x22);//SSR reasno 0x22 = CMD TO
+
+ //Reset SOC status to trigger hciattach service
+ if (property_set("bluetooth.status", "off") < 0) {
+ LOG_ERROR(LOG_TAG, "hci_cmd_timeout: Error resetting SOC status\n ");
+ } else {
+ LOG_ERROR(LOG_TAG, "hci_cmd_timeout: SOC Status is reset\n ");
+ }
+
+ if (soc_type == BT_SOC_ROME || soc_type == BT_SOC_CHEROKEE) {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ uint32_t hardware_error_timeout_ms = 2000;
+ bool enabled = false;
+#ifdef ENABLE_DBG_FLAGS
+ enabled = true;
+#endif
+ if (property_get("wc_transport.force_special_byte", value, NULL))
+ enabled = (strcmp(value, "false") == 0) ? false : true;
+ if (enabled) {
+ hardware_error_timer = alarm_new("hci.hardware_error_timer");
+ if (!hardware_error_timer) {
+ LOG_ERROR("%s unable to create hardware error timer.", __func__);
+ usleep(2000000);
+ kill(getpid(), SIGKILL);
+ }
+ if(soc_type == BT_SOC_CHEROKEE)
+ hardware_error_timeout_ms = 5000;
+ alarm_set(hardware_error_timer, hardware_error_timeout_ms, hardware_error_timer_expired, NULL);
+ return;
+ }
+ }
+ usleep(20000);
kill(getpid(), SIGKILL);
}
@@ -551,71 +688,100 @@
static void hal_says_data_ready(serial_data_type_t type) {
packet_receive_data_t *incoming = &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type)];
+ uint8_t reset;
+
uint8_t byte;
while (hal->read_data(type, &byte, 1) != 0) {
+ if (soc_type == BT_SOC_SMD) {
+ reset = hal->dev_in_reset();
+ if (reset) {
+ incoming = &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type = DATA_TYPE_EVENT)];
+ if(!create_hw_reset_evt_packet(incoming))
+ break;
+ else {
+ //Reset SOC status to trigger hciattach service
+ if(property_set("bluetooth.status", "off") < 0) {
+ LOG_ERROR(LOG_TAG, "SSR: Error resetting SOC status\n ");
+ } else {
+ ALOGE("SSR: SOC Status is reset\n ");
+ }
+ }
+ }
+ }
+
switch (incoming->state) {
- case BRAND_NEW:
- // Initialize and prepare to jump to the preamble reading state
- incoming->bytes_remaining = preamble_sizes[PACKET_TYPE_TO_INDEX(type)];
- memset(incoming->preamble, 0, PREAMBLE_BUFFER_SIZE);
- incoming->index = 0;
- incoming->state = PREAMBLE;
- // INTENTIONAL FALLTHROUGH
- case PREAMBLE:
- incoming->preamble[incoming->index] = byte;
- incoming->index++;
- incoming->bytes_remaining--;
+ case BRAND_NEW:
+ // Initialize and prepare to jump to the preamble reading state
+ incoming->bytes_remaining = preamble_sizes[PACKET_TYPE_TO_INDEX(type)];
+ memset(incoming->preamble, 0, PREAMBLE_BUFFER_SIZE);
+ incoming->index = 0;
+ incoming->state = PREAMBLE;
+ // INTENTIONAL FALLTHROUGH
+ case PREAMBLE:
+ incoming->preamble[incoming->index] = byte;
+ incoming->index++;
+ incoming->bytes_remaining--;
- if (incoming->bytes_remaining == 0) {
- // For event and sco preambles, the last byte we read is the length
- incoming->bytes_remaining = (type == DATA_TYPE_ACL) ? RETRIEVE_ACL_LENGTH(incoming->preamble) : byte;
+ if (incoming->bytes_remaining == 0) {
+ // For event and sco preambles, the last byte we read is the length
+ incoming->bytes_remaining = (type == DATA_TYPE_ACL) ? RETRIEVE_ACL_LENGTH(incoming->preamble) : byte;
- size_t buffer_size = BT_HDR_SIZE + incoming->index + incoming->bytes_remaining;
- incoming->buffer = (BT_HDR *)buffer_allocator->alloc(buffer_size);
+ size_t buffer_size = BT_HDR_SIZE + incoming->index + incoming->bytes_remaining;
- if (!incoming->buffer) {
- LOG_ERROR(LOG_TAG, "%s error getting buffer for incoming packet of type %d and size %zd", __func__, type, buffer_size);
- // Can't read any more of this current packet, so jump out
- incoming->state = incoming->bytes_remaining == 0 ? BRAND_NEW : IGNORE;
+ if (buffer_size > MCA_USER_RX_BUF_SIZE) {
+ LOG_ERROR(LOG_TAG, "%s buffer_size(%zu) exceeded allowed packet size, allocation not possible", __func__, buffer_size);
+ incoming = &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type = DATA_TYPE_EVENT)];
+ if(create_hw_reset_evt_packet(incoming))
+ break;
+ else
+ return;
+ }
+
+ incoming->buffer = (BT_HDR *)buffer_allocator->alloc(buffer_size);
+
+ if (!incoming->buffer) {
+ LOG_ERROR(LOG_TAG, "%s error getting buffer for incoming packet of type %d and size %zd", __func__, type, buffer_size);
+ // Can't read any more of this current packet, so jump out
+ incoming->state = incoming->bytes_remaining == 0 ? BRAND_NEW : IGNORE;
+ break;
+ }
+
+ // Initialize the buffer
+ incoming->buffer->offset = 0;
+ incoming->buffer->layer_specific = 0;
+ incoming->buffer->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
+ memcpy(incoming->buffer->data, incoming->preamble, incoming->index);
+
+ incoming->state = incoming->bytes_remaining > 0 ? BODY : FINISHED;
+ }
+
break;
- }
+ case BODY:
+ incoming->buffer->data[incoming->index] = byte;
+ incoming->index++;
+ incoming->bytes_remaining--;
- // Initialize the buffer
- incoming->buffer->offset = 0;
- incoming->buffer->layer_specific = 0;
- incoming->buffer->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
- memcpy(incoming->buffer->data, incoming->preamble, incoming->index);
+ size_t bytes_read = hal->read_data(type, (incoming->buffer->data + incoming->index), incoming->bytes_remaining);
+ incoming->index += bytes_read;
+ incoming->bytes_remaining -= bytes_read;
- incoming->state = incoming->bytes_remaining > 0 ? BODY : FINISHED;
- }
+ incoming->state = incoming->bytes_remaining == 0 ? FINISHED : incoming->state;
+ break;
+ case IGNORE:
+ incoming->bytes_remaining--;
+ if (incoming->bytes_remaining == 0) {
+ incoming->state = BRAND_NEW;
+ // Don't forget to let the hal know we finished the packet we were ignoring.
+ // Otherwise we'll get out of sync with hals that embed extra information
+ // in the uart stream (like H4). #badnewsbears
+ hal->packet_finished(type);
+ return;
+ }
- break;
- case BODY:
- incoming->buffer->data[incoming->index] = byte;
- incoming->index++;
- incoming->bytes_remaining--;
-
- size_t bytes_read = hal->read_data(type, (incoming->buffer->data + incoming->index), incoming->bytes_remaining);
- incoming->index += bytes_read;
- incoming->bytes_remaining -= bytes_read;
-
- incoming->state = incoming->bytes_remaining == 0 ? FINISHED : incoming->state;
- break;
- case IGNORE:
- incoming->bytes_remaining--;
- if (incoming->bytes_remaining == 0) {
- incoming->state = BRAND_NEW;
- // Don't forget to let the hal know we finished the packet we were ignoring.
- // Otherwise we'll get out of sync with hals that embed extra information
- // in the uart stream (like H4). #badnewsbears
- hal->packet_finished(type);
- return;
- }
-
- break;
- case FINISHED:
- LOG_ERROR(LOG_TAG, "%s the state machine should not have been left in the finished state.", __func__);
- break;
+ break;
+ case FINISHED:
+ LOG_ERROR(LOG_TAG, "%s the state machine should not have been left in the finished state.", __func__);
+ break;
}
if (incoming->state == FINISHED) {
@@ -623,18 +789,28 @@
btsnoop->capture(incoming->buffer, true);
if (type != DATA_TYPE_EVENT) {
- packet_fragmenter->reassemble_and_dispatch(incoming->buffer);
+ if(hci_state == HCI_READY) {
+ packet_fragmenter->reassemble_and_dispatch(incoming->buffer);
+ } else {
+ LOG_WARN("%s, Ignoring the ACL pkt received", __func__);
+ buffer_allocator->free(incoming->buffer);
+ }
} else if (!filter_incoming_event(incoming->buffer)) {
- // Dispatch the event by event code
- uint8_t *stream = incoming->buffer->data;
- uint8_t event_code;
- STREAM_TO_UINT8(event_code, stream);
+ if (hci_state == HCI_READY) {
+ // Dispatch the event by event code
+ uint8_t *stream = incoming->buffer->data;
+ uint8_t event_code;
+ STREAM_TO_UINT8(event_code, stream);
- data_dispatcher_dispatch(
- interface.event_dispatcher,
- event_code,
- incoming->buffer
- );
+ data_dispatcher_dispatch(
+ interface.event_dispatcher,
+ event_code,
+ incoming->buffer
+ );
+ } else {
+ LOG_WARN("%s, Ignoring the event pkt received", __func__);
+ buffer_allocator->free(incoming->buffer);
+ }
}
// We don't control the buffer anymore
@@ -666,6 +842,10 @@
STREAM_TO_UINT8(command_credits, stream);
STREAM_TO_UINT16(opcode, stream);
+ if (HCI_RESET == opcode) {
+ hci_state = HCI_READY;
+ }
+
wait_entry = get_waiting_command(opcode);
if (!wait_entry) {
// TODO: Currently command_credits aren't parsed at all; here or in higher layers...
@@ -689,9 +869,9 @@
// If a command generates a command status event, it won't be getting a command complete event
wait_entry = get_waiting_command(opcode);
- if (!wait_entry)
+ if (!wait_entry) {
LOG_WARN(LOG_TAG, "%s command status event with no matching command. opcode: 0x%x", __func__, opcode);
- else if (wait_entry->status_callback)
+ } else if (wait_entry->status_callback)
wait_entry->status_callback(status, wait_entry->command, wait_entry->context);
goto intercepted;
@@ -716,9 +896,35 @@
buffer_allocator->free(packet);
}
+ if(command_credits > 0) {
+ const list_node_t *node = list_begin(commands_pending_in_queue);
+
+ if(node != list_end(commands_pending_in_queue)) {
+ waiting_command_t *wait_entry = list_node(node);
+ command_credits--;
+ list_remove(commands_pending_in_queue, wait_entry);
+ send_cmd_to_lower(wait_entry);
+ }
+ }
return true;
}
+/** SSR cleanup is used in HW reset cases
+** which would close all the client channels
+** and turns off the chip*/
+void ssr_cleanup (int reason) {
+ LOG_INFO("%s", __func__);
+ if (hci_state < HCI_STARTED) {
+ LOG_ERROR("%s Returning, hci_layer already shut down", __func__);
+ return;
+ }
+ if (vendor != NULL) {
+ vendor->ssr_cleanup(reason);
+ } else {
+ LOG_ERROR("%s: vendor is NULL", __func__);
+ }
+}
+
// Callback for the fragmenter to dispatch up a completely reassembled packet
static void dispatch_reassembled(BT_HDR *packet) {
// Events should already have been dispatched before this point
@@ -765,6 +971,26 @@
pthread_mutex_unlock(&commands_pending_response_lock);
return wait_entry;
}
+ // look for any command complete with improper VS Opcode
+ for (const list_node_t *node = list_begin(commands_pending_response);
+ node != list_end(commands_pending_response);
+ node = list_next(node)) {
+ waiting_command_t *wait_entry = list_node(node);
+
+ if (wait_entry && (wait_entry->opcode != opcode) &&
+ (((wait_entry->opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) &&
+ ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC))) {
+ LOG_DEBUG("%s VS event found treat it as valid 0x%x", __func__, opcode);
+ }
+ else {
+ continue;
+ }
+
+ list_remove(commands_pending_response, wait_entry);
+
+ pthread_mutex_unlock(&commands_pending_response_lock);
+ return wait_entry;
+ }
pthread_mutex_unlock(&commands_pending_response_lock);
return NULL;
@@ -796,6 +1022,7 @@
interface.transmit_command = transmit_command;
interface.transmit_command_futured = transmit_command_futured;
interface.transmit_downward = transmit_downward;
+ interface.ssr_cleanup = ssr_cleanup;
interface_created = true;
}
}
@@ -815,6 +1042,23 @@
interface_created = false;
}
}
+static bool create_hw_reset_evt_packet(packet_receive_data_t *incoming) {
+ uint8_t dev_ssr_event[3] = { 0x10, 0x01, 0x0A };
+ incoming->buffer = (BT_HDR *)buffer_allocator->alloc(BT_HDR_SIZE + 3);
+ if (incoming->buffer) {
+ LOG_ERROR(LOG_TAG, "sending H/w error event to stack\n ");
+ incoming->buffer->offset = 0;
+ incoming->buffer->layer_specific = 0;
+ incoming->buffer->event = MSG_HC_TO_STACK_HCI_EVT;
+ incoming->index = 3;
+ memcpy(incoming->buffer->data, &dev_ssr_event, 3);
+ incoming->state = FINISHED;
+ return true;
+ } else {
+ LOG_ERROR(LOG_TAG, "error getting buffer for H/W event\n ");
+ return false;
+ }
+}
static const hci_hal_callbacks_t hal_callbacks = {
hal_says_data_ready
diff --git a/hci/src/hci_packet_factory.c b/hci/src/hci_packet_factory.c
index 96f578a..1e95ee3 100644
--- a/hci/src/hci_packet_factory.c
+++ b/hci/src/hci_packet_factory.c
@@ -133,6 +133,10 @@
return make_command_no_params(HCI_BLE_READ_RESOLVING_LIST_SIZE);
}
+static BT_HDR *make_ble_read_adv_ext_size(void) {
+ return make_command_no_params(HCI_BLE_READ_NUM_ADV_SETS);
+}
+
static BT_HDR *make_ble_read_suggested_default_data_length(void) {
return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH);
}
@@ -141,6 +145,10 @@
return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CODECS);
}
+static BT_HDR *make_ble_read_offload_features_support(void) {
+ return make_command_no_params(HCI_BLE_VENDOR_CAP_OCF);
+}
+
static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask) {
uint8_t *stream;
uint8_t parameter_size = sizeof(bt_event_mask_t);
@@ -196,9 +204,11 @@
make_ble_read_supported_states,
make_ble_read_local_supported_features,
make_ble_read_resolving_list_size,
+ make_ble_read_adv_ext_size,
make_ble_read_suggested_default_data_length,
make_ble_set_event_mask,
- make_read_local_supported_codecs
+ make_read_local_supported_codecs,
+ make_ble_read_offload_features_support
};
const hci_packet_factory_t *hci_packet_factory_get_interface() {
diff --git a/hci/src/hci_packet_parser.c b/hci/src/hci_packet_parser.c
index 9f7dae8..3209e1f 100644
--- a/hci/src/hci_packet_parser.c
+++ b/hci/src/hci_packet_parser.c
@@ -37,9 +37,10 @@
size_t minimum_bytes_after);
static void parse_generic_command_complete(BT_HDR *response) {
- read_command_complete_header(response, NO_OPCODE_CHECKING, 0 /* bytes after */);
-
- buffer_allocator->free(response);
+ if (response) {
+ read_command_complete_header(response, NO_OPCODE_CHECKING, 0 /* bytes after */);
+ buffer_allocator->free(response);
+ }
}
static void parse_read_buffer_size_response(
@@ -88,6 +89,21 @@
buffer_allocator->free(response);
}
+
+static void parse_ble_read_offload_features_response(
+ BT_HDR *response,
+ bool *ble_offload_features_supported) {
+
+ uint8_t *stream = read_command_complete_header(response, NO_OPCODE_CHECKING, 0 /* bytes after */);
+ if(stream) {
+ *ble_offload_features_supported = true;
+ } else {
+ *ble_offload_features_supported = false;
+ }
+
+ buffer_allocator->free(response);
+}
+
static void parse_read_bd_addr_response(
BT_HDR *response,
bt_bdaddr_t *address_ptr) {
@@ -185,16 +201,29 @@
uint8_t *resolving_list_size_ptr) {
uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_RESOLVING_LIST_SIZE, 1 /* bytes after */);
+ assert(stream != NULL);
STREAM_TO_UINT8(*resolving_list_size_ptr, stream);
buffer_allocator->free(response);
}
+static void parse_ble_read_adv_ext_size_response(
+ BT_HDR *response,
+ uint8_t *ble_adv_ext_size) {
+
+ uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_NUM_ADV_SETS, 1 /* bytes after */);
+ assert(stream != NULL);
+ STREAM_TO_UINT8(*ble_adv_ext_size, stream);
+
+ buffer_allocator->free(response);
+}
+
static void parse_ble_read_suggested_default_data_length_response(
BT_HDR *response,
uint16_t *ble_default_packet_length_ptr) {
uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_DEFAULT_DATA_LENGTH, 2 /* bytes after */);
+ assert(stream != NULL);
STREAM_TO_UINT8(*ble_default_packet_length_ptr, stream);
buffer_allocator->free(response);
@@ -255,8 +284,10 @@
parse_ble_read_supported_states_response,
parse_ble_read_local_supported_features_response,
parse_ble_read_resolving_list_size_response,
+ parse_ble_read_adv_ext_size_response,
parse_ble_read_suggested_default_data_length_response,
- parse_read_local_supported_codecs_response
+ parse_read_local_supported_codecs_response,
+ parse_ble_read_offload_features_response
};
const hci_packet_parser_t *hci_packet_parser_get_interface() {
diff --git a/hci/src/low_power_manager.c b/hci/src/low_power_manager.c
index f82a69f..3c5984a 100644
--- a/hci/src/low_power_manager.c
+++ b/hci/src/low_power_manager.c
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2014 Google, Inc.
*
@@ -56,8 +61,8 @@
static void event_idle_timeout(void *context);
static void reset_state();
-static void start_idle_timer();
-static void stop_idle_timer();
+void start_idle_timer(bool check_LPM);
+void stop_idle_timer();
static thread_fn event_functions[] = {
event_disable,
@@ -124,7 +129,7 @@
transmit_is_done = true;
if (wake_state == LPM_WAKE_W4_TX_DONE || wake_state == LPM_WAKE_ASSERTED) {
wake_state = LPM_WAKE_W4_TIMEOUT;
- start_idle_timer();
+ start_idle_timer(true);
}
}
@@ -132,15 +137,17 @@
static void enable(bool enable) {
if (state == LPM_DISABLING) {
- if (enable)
+ if (enable) {
LOG_ERROR(LOG_TAG, "%s still processing prior disable request, cannot enable.", __func__);
- else
+ } else {
LOG_WARN(LOG_TAG, "%s still processing prior disable request, ignoring new request to disable.", __func__);
+ }
} else if (state == LPM_ENABLING) {
- if (enable)
+ if (enable) {
LOG_ERROR(LOG_TAG, "%s still processing prior enable request, ignoring new request to enable.", __func__);
- else
+ } else {
LOG_WARN(LOG_TAG, "%s still processing prior enable request, cannot disable.", __func__);
+ }
} else if (state == LPM_ENABLED && enable) {
LOG_INFO(LOG_TAG, "%s already enabled.", __func__);
} else if (state == LPM_DISABLED && !enable) {
@@ -158,7 +165,7 @@
if (state == LPM_ENABLED && wake_state == LPM_WAKE_ASSERTED) {
if (transmit_is_done) {
wake_state = LPM_WAKE_W4_TIMEOUT;
- start_idle_timer();
+ start_idle_timer(true);
} else {
wake_state = LPM_WAKE_W4_TX_DONE;
}
@@ -185,18 +192,22 @@
thread_post(thread, event_idle_timeout, NULL);
}
-static void start_idle_timer() {
- if (state == LPM_ENABLED) {
+void start_idle_timer(bool check_LPM) {
+ if (state == LPM_ENABLED || !check_LPM) {
if (idle_timeout_ms == 0) {
wake_deassert();
- } else {
+ }
+ else {
alarm_set(idle_alarm, idle_timeout_ms, idle_timer_expired, NULL);
}
+
+ LOG_VERBOSE(LOG_TAG,"%s check_LPM = %d", __func__, check_LPM);
}
}
-static void stop_idle_timer() {
+void stop_idle_timer() {
alarm_cancel(idle_alarm);
+ LOG_VERBOSE(LOG_TAG, "%s", __func__);
}
static void event_disable(UNUSED_ATTR void *context) {
@@ -235,7 +246,9 @@
cleanup,
post_command,
wake_assert,
- transmit_done
+ transmit_done,
+ start_idle_timer,
+ stop_idle_timer
};
const low_power_manager_t *low_power_manager_get_interface() {
diff --git a/hci/src/packet_fragmenter.c b/hci/src/packet_fragmenter.c
index eae6905..06fb972 100644
--- a/hci/src/packet_fragmenter.c
+++ b/hci/src/packet_fragmenter.c
@@ -153,6 +153,7 @@
if (acl_length < L2CAP_HEADER_SIZE) {
LOG_WARN(LOG_TAG, "%s L2CAP packet too small (%d < %d). Dropping it.", __func__, packet->len, L2CAP_HEADER_SIZE);
buffer_allocator->free(packet);
+ GENERATE_VND_LOGS();
return;
}
@@ -164,6 +165,7 @@
((full_length + sizeof(BT_HDR)) > BT_DEFAULT_BUFFER_SIZE)) {
LOG_ERROR(LOG_TAG, "%s L2CAP packet has invalid length (%d). Dropping it.", __func__, l2cap_length);
buffer_allocator->free(packet);
+ GENERATE_VND_LOGS();
return;
}
@@ -194,6 +196,7 @@
if (!partial_packet) {
LOG_WARN(LOG_TAG, "%s got continuation for unknown packet. Dropping it.", __func__);
buffer_allocator->free(packet);
+ GENERATE_VND_LOGS();
return;
}
diff --git a/hci/src/vendor.c b/hci/src/vendor.c
index c6bbd43..46ae0ac 100644
--- a/hci/src/vendor.c
+++ b/hci/src/vendor.c
@@ -90,6 +90,13 @@
lib_interface = NULL;
lib_handle = NULL;
}
+void vendor_ssrcleanup(int reason) {
+ if (lib_interface)
+ lib_interface->ssr_cleanup(reason);
+ else
+ LOG_ERROR("%s lib_interface is NULL", __func__);
+
+}
static int send_command(vendor_opcode_t opcode, void *param) {
assert(lib_interface != NULL);
@@ -220,6 +227,7 @@
send_command,
send_async_command,
set_callback,
+ vendor_ssrcleanup
};
const vendor_t *vendor_get_interface() {
diff --git a/include/bt_logger_lib.h b/include/bt_logger_lib.h
new file mode 100644
index 0000000..30467af
--- /dev/null
+++ b/include/bt_logger_lib.h
@@ -0,0 +1,78 @@
+/*********************************************************************
+*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+************************************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+
+/**
+ * Commands
+ */
+typedef enum {
+ VENDOR_LOGGER_LOGS = 201, // Signifies Packet containing Logger Log
+ GENERATE_VND_LOG_SIGNAL, // Signifies command to generate logs
+ START_SNOOP_SIGNAL,
+ STOP_SNOOP_SIGNAL,
+ STOP_LOGGING_SIGNAL,
+} CommandTypes;
+
+void init_vnd_Logger(void);
+void clean_vnd_logger(void);
+
+typedef struct {
+ /** Set to sizeof(bt_vndor_interface_t) */
+ size_t size;
+
+ /*
+ * Functions need to be implemented in Logger libray (libbt-logClient.so).
+ */
+
+ /*
+ * Initialize logging by conneting client socket
+ * to Logger process
+ */
+ int (*init)(void);
+
+ /** Sending Logs of Logger process */
+ void (*send_log_msg)(const char *tag, const char *fmt_str, va_list ap);
+ void (*send_log_data)(const char *tag, const char *fmt_str, ...);
+
+ /** Sending Logs of Logger process */
+ void (*send_event)(char evt);
+
+ /** Closes the socket connection to logger process */
+ int (*cleanup)(void);
+
+} bt_logger_interface_t;
+
+#define GENERATE_VND_LOGS() if(logger_interface)logger_interface->send_event(GENERATE_VND_LOG_SIGNAL)
+#define START_SNOOP_LOGGING() if(logger_interface)logger_interface->send_event(START_SNOOP_SIGNAL)
+#define STOP_SNOOP_LOGGING() if(logger_interface)logger_interface->send_event(STOP_SNOOP_SIGNAL)
diff --git a/include/bt_target.h b/include/bt_target.h
index 184a6cd..37ef9ae 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -1,3 +1,9 @@
+ /******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
/******************************************************************************
*
* Copyright (c) 2014 The Android Open Source Project
@@ -42,6 +48,11 @@
#define L2CAP_EXTFEA_SUPPORTED_MASK (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS)
#endif
+/* This feature is used to update any QCOM related changes in the stack*/
+#ifndef BLUETOOTH_QTI_SW
+#define BLUETOOTH_QTI_SW TRUE
+#endif
+
#ifndef BTUI_OPS_FORMATS
#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_ANY_MASK)
#endif
@@ -87,7 +98,7 @@
#endif
#ifndef BTA_AV_SINK_INCLUDED
-#define BTA_AV_SINK_INCLUDED FALSE
+#define BTA_AV_SINK_INCLUDED TRUE
#endif
#ifndef BTA_DISABLE_DELAY
@@ -127,7 +138,7 @@
#endif
#ifndef BTIF_A2DP_SRC_BIT_DEPTH
-#define BTIF_A2DP_SRC_BIT_DEPTH 16
+#define BTIF_A2DP_SRC_BIT_DEPTH 32
#endif
#ifndef BTIF_A2DP_SRC_NUM_CHANNELS
@@ -143,6 +154,15 @@
#define BT_USE_TRACES TRUE
#endif
+#ifndef BT_TRACE_BTIF
+#define BT_TRACE_BTIF TRUE
+#endif
+
+
+#ifndef BT_TRACE_LATENCY_AUDIO
+#define BT_TRACE_LATENCY_AUDIO TRUE
+#endif
+
#ifndef BT_TRACE_VERBOSE
#define BT_TRACE_VERBOSE FALSE
#endif
@@ -155,6 +175,11 @@
#define HL_INCLUDED TRUE
#endif
+#ifndef AAC_ENCODER_INCLUDED
+#define AAC_ENCODER_INCLUDED TRUE
+#endif
+
+
#ifndef AG_VOICE_SETTINGS
#define AG_VOICE_SETTINGS HCI_DEFAULT_VOICE_SETTINGS
#endif
@@ -171,6 +196,15 @@
//------------------End added from bdroid_buildcfg.h---------------------
+/******************************************************************************
+**
+** Test Application interface
+**
+******************************************************************************/
+
+#ifndef TEST_APP_INTERFACE
+#define TEST_APP_INTERFACE TRUE
+#endif
/******************************************************************************
**
@@ -330,10 +364,15 @@
#define BTM_SCO_HCI_INCLUDED FALSE /* TRUE includes SCO over HCI code */
#endif
+#if (BLUETOOTH_QTI_SW == TRUE) /* Enable WBS only under this flag.*/
+#define BTM_WBS_INCLUDED TRUE
+#else
/* Includes WBS if TRUE */
#ifndef BTM_WBS_INCLUDED
#define BTM_WBS_INCLUDED FALSE /* TRUE includes WBS code */
#endif
+#endif
+
/* This is used to work around a controller bug that doesn't like Disconnect
** issued while there is a role switch in progress
@@ -477,6 +516,11 @@
#define BTM_MAX_VSE_CALLBACKS 3
#endif
+/* Safe reattempt even after device is blacklisted for role switch */
+#ifndef BTM_SAFE_REATTEMPT_ROLE_SWITCH
+#define BTM_SAFE_REATTEMPT_ROLE_SWITCH TRUE
+#endif
+
/******************************************
** Lisbon Features
*******************************************/
@@ -531,21 +575,21 @@
**
******************************************************************************/
-/* The maximum number of simultaneous links that L2CAP can support. */
-#ifndef MAX_ACL_CONNECTIONS
-#define MAX_L2CAP_LINKS 7
-#else
-#define MAX_L2CAP_LINKS MAX_ACL_CONNECTIONS
-#endif
-
/* The maximum number of simultaneous channels that L2CAP can support. */
#ifndef MAX_L2CAP_CHANNELS
-#define MAX_L2CAP_CHANNELS 16
+#define MAX_L2CAP_CHANNELS 20
+#endif
+
+/* The maximum number of simultaneous links that L2CAP can support. */
+#ifndef MAX_L2CAP_CHANNELS
+#define MAX_L2CAP_LINKS 7
+#else
+#define MAX_L2CAP_LINKS MAX_L2CAP_CHANNELS
#endif
/* The maximum number of simultaneous applications that can register with L2CAP. */
#ifndef MAX_L2CAP_CLIENTS
-#define MAX_L2CAP_CLIENTS 15
+#define MAX_L2CAP_CLIENTS 19
#endif
/* The number of seconds of link inactivity before a link is disconnected. */
@@ -588,7 +632,7 @@
/* Whether link wants to be the master or the slave. */
#ifndef L2CAP_DESIRED_LINK_ROLE
-#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE
+#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_MASTER
#endif
/* Include Non-Flushable Packet Boundary Flag feature of Lisbon */
@@ -665,6 +709,11 @@
#endif
+
+#ifndef HCI_RAW_CMD_INCLUDED
+#define HCI_RAW_CMD_INCLUDED TRUE
+#endif
+
/******************************************************************************
**
** BLE
@@ -675,6 +724,14 @@
#define BLE_INCLUDED TRUE
#endif
+/*LE_L2CAP_CODE*/
+/*LE Credit Based Flow Control Mode*/
+#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+#ifndef LE_L2CAP_CFC_INCLUDED
+#define LE_L2CAP_CFC_INCLUDED TRUE
+#endif /*LE_L2CAP_CFC_INCLUDED */
+#endif /* BLE_INCLUDED */
+
#ifndef BLE_ANDROID_CONTROLLER_SCAN_FILTER
#define BLE_ANDROID_CONTROLLER_SCAN_FILTER TRUE
#endif
@@ -691,6 +748,10 @@
#define BLE_PRIVACY_SPT TRUE
#endif
+#ifndef BLE_EXTENDED_ADV_SUPPORT
+#define BLE_EXTENDED_ADV_SUPPORT TRUE
+#endif
+
/*
* Enables or disables support for local privacy (ex. address rotation)
*/
@@ -715,6 +776,11 @@
#define BLE_MAX_L2CAP_CLIENTS 15
#endif
+#ifndef BLE_HH_QUALIFICATION_ENABLED
+#define BLE_HH_QUALIFICATION_ENABLED FALSE
+#endif
+
+
/******************************************************************************
**
** ATT/GATT Protocol/Profile Settings
@@ -771,7 +837,11 @@
#endif
#ifndef GATT_MAX_PHY_CHANNEL
+#ifndef MAX_L2CAP_CHANNELS
#define GATT_MAX_PHY_CHANNEL 7
+#else
+#define GATT_MAX_PHY_CHANNEL MAX_L2CAP_CHANNELS
+#endif
#endif
/* Used for conformance testing ONLY */
@@ -1156,9 +1226,15 @@
#define AVDT_NUM_LINKS 2
#endif
-/* Number of simultaneous stream endpoints. */
+/* Number of simultaneous stream endpoints.
+ * Audio*2 + Video*2 + 1 Additional
+ */
#ifndef AVDT_NUM_SEPS
-#define AVDT_NUM_SEPS 3
+#if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE)
+#define AVDT_NUM_SEPS 9
+#else
+#define AVDT_NUM_SEPS 7
+#endif
#endif
/* Number of transport channels setup by AVDT for all media streams */
@@ -1168,7 +1244,7 @@
/* Maximum size in bytes of the codec capabilities information element. */
#ifndef AVDT_CODEC_SIZE
-#define AVDT_CODEC_SIZE 10
+#define AVDT_CODEC_SIZE 20
#endif
/* Maximum size in bytes of the content protection information element. */
@@ -1333,7 +1409,11 @@
#endif
#ifndef HID_HOST_MAX_DEVICES
+#ifndef MAX_L2CAP_CHANNELS
#define HID_HOST_MAX_DEVICES 7
+#else
+#define HID_HOST_MAX_DEVICES MAX_L2CAP_CHANNELS
+#endif
#endif
#ifndef HID_HOST_MTU
@@ -1359,6 +1439,10 @@
#define A2D_INCLUDED TRUE
#endif
+#ifndef A2D_M24_INCLUDED
+#define A2D_M24_INCLUDED A2D_INCLUDED
+#endif
+
/******************************************************************************
**
** AVCTP
@@ -1370,9 +1454,36 @@
#define AVCT_NUM_LINKS 2
#endif
-/* Number of simultaneous AVCTP connections. */
+/* Number of simultaneous AVCTP connections.
+ * Audio*2 + Video*2 + 1 Additional */
#ifndef AVCT_NUM_CONN
-#define AVCT_NUM_CONN 3
+#define AVCT_NUM_CONN 5
+#endif
+
+/* Buffer size to reassemble the SDU. */
+#ifndef AVCT_BR_USER_RX_BUF_SIZE
+#define AVCT_BR_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Buffer size to hold the SDU. */
+#ifndef AVCT_BR_USER_TX_BUF_SIZE
+#define AVCT_BR_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Buffer size used to hold MPS segments during SDU reassembly
+ */
+#ifndef AVCT_BR_FCR_RX_BUF_SIZE
+#define AVCT_BR_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Default buffer size used to hold MPS segments used in (re)transmissions.
+ * The size of each buffer must be able to hold the maximum MPS segment size
+ * passed in tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) +
+ * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).+1452 */
+#ifndef AVCT_BR_FCR_TX_BUF_SIZE
+#define AVCT_BR_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
#endif
/******************************************************************************
@@ -1393,6 +1504,30 @@
#define AVRC_CTLR_INCLUDED TRUE
#endif
+#ifndef SDP_AVRCP_1_6
+#define SDP_AVRCP_1_6 TRUE
+#endif
+
+#ifndef SDP_AVRCP_1_5
+#define SDP_AVRCP_1_5 FALSE
+#endif
+
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+#ifndef AVCT_COVER_ART_INCLUDED
+#define AVCT_COVER_ART_INCLUDED TRUE
+#endif
+#endif
+
+#if ((defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE)) || \
+ (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE)))
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED TRUE
+#else
+#ifndef AVCT_BROWSE_INCLUDED
+#define AVCT_BROWSE_INCLUDED FALSE
+#endif
+#endif
+#endif
/******************************************************************************
**
** MCAP
@@ -1407,6 +1542,7 @@
#define MCA_CTRL_MTU 60
#endif
+
/* The maximum number of registered MCAP instances. */
#ifndef MCA_NUM_REGS
#define MCA_NUM_REGS 12
@@ -1499,6 +1635,11 @@
#define MCA_FCR_OPT_MPS_SIZE 1000
#endif
+/* Enable this flag if require ,default value is false */
+#ifndef MCA_DELAY_DELETE_MDL_RSP
+#define MCA_DELAY_DELETE_MDL_RSP FALSE
+#endif
+
/******************************************************************************
**
** Sleep Mode (Low Power Mode)
diff --git a/include/bt_testapp.h b/include/bt_testapp.h
new file mode 100644
index 0000000..421b3fd
--- /dev/null
+++ b/include/bt_testapp.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef TEST_APP_INTERFACE
+#ifndef ANDROID_INCLUDE_BT_TESTAPP_H
+#define ANDROID_INCLUDE_BT_TESTAPP_H
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <linux/capability.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+#include <hardware/bluetooth.h>
+#include "l2c_api.h"
+#include "sdp_api.h"
+#include "gatt_api.h"
+#include "gap_api.h"
+#include "mca_api.h"
+#include <hardware/hardware.h>
+#include "btm_api.h"
+
+__BEGIN_DECLS
+
+typedef void (tREMOTE_DEVICE_NAME_CB) (void *p1);
+
+enum {
+ SUCCESS,
+ FAIL
+};
+
+typedef enum {
+ DUMMY,
+ ALL,
+ SPP,
+ FTP,
+ OPP,
+ MAP,
+ PBAP,
+ DUN,
+ NOT_SUPPORTED,
+}profileName;
+typedef enum {
+ TEST_APP_L2CAP,
+ TEST_APP_RFCOMM,
+ TEST_APP_MCAP,
+ TEST_APP_GATT,
+ TEST_APP_GAP,
+ TEST_APP_SMP
+} test_app_profile;
+typedef struct {
+
+ /** set to sizeof(Btl2capInterface) */
+ size_t size;
+ /** Register the L2cap callbacks */
+ bt_status_t (*Init)(tL2CAP_APPL_INFO* callbacks);
+ bt_status_t (*RegisterPsm)(UINT16 psm, BOOLEAN conn_type, UINT16 sec_level);
+ bt_status_t (*Deregister)(UINT16 psm);
+ UINT16 (*AllocatePsm)(void);
+ UINT16 (*Connect)(UINT16 psm, bt_bdaddr_t *bd_addr);
+ BOOLEAN (*ConnectRsp)(BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result, UINT16 status);
+ UINT16 (*ErtmConnectReq)(UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info);
+ BOOLEAN (*ErtmConnectRsp)(BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid,
+ UINT16 result, UINT16 status,
+ tL2CAP_ERTM_INFO *p_ertm_info);
+ BOOLEAN (*ConfigReq)(UINT16 cid, tL2CAP_CFG_INFO *p_cfg);
+ BOOLEAN (*ConfigRsp)(UINT16 cid, tL2CAP_CFG_INFO *p_cfg);
+ BOOLEAN (*DisconnectReq)(UINT16 cid);
+ BOOLEAN (*DisconnectRsp)(UINT16 cid);
+ UINT8 (*DataWrite)(UINT16 cid, char *p_data, UINT32 len);
+ BOOLEAN (*Ping)(BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_cb);
+ BOOLEAN (*Echo)(BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback);
+ BOOLEAN (*SetIdleTimeout)(UINT16 cid, UINT16 timeout, BOOLEAN is_global);
+ BOOLEAN (*SetIdleTimeoutByBdAddr)(BD_ADDR bd_addr, UINT16 timeout);
+ UINT8 (*SetDesireRole)(UINT8 new_role);
+ void (*SetSecConnOnlyMode)(BOOLEAN secvalue);
+ UINT16 (*LocalLoopbackReq)(UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr);
+ UINT16 (*FlushChannel)(UINT16 lcid, UINT16 num_to_flush);
+ BOOLEAN (*SetAclPriority)(BD_ADDR bd_addr, UINT8 priority);
+ BOOLEAN (*FlowControl)(UINT16 cid, BOOLEAN data_enabled);
+ BOOLEAN (*SendTestSFrame)(UINT16 cid, BOOLEAN rr_or_rej, UINT8 back_track);
+ BOOLEAN (*SetTxPriority)(UINT16 cid, tL2CAP_CHNL_PRIORITY priority);
+ BOOLEAN (*RegForNoCPEvt)(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda);
+ BOOLEAN (*SetChnlDataRate)(UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx);
+ BOOLEAN (*SetFlushTimeout)(BD_ADDR bd_addr, UINT16 flush_tout);
+ UINT8 (*DataWriteEx)(UINT16 cid, BT_HDR *p_data, UINT16 flags);
+ BOOLEAN (*SetChnlFlushability)(UINT16 cid, BOOLEAN is_flushable);
+ BOOLEAN (*GetPeerFeatures)(BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask);
+ BOOLEAN (*GetBDAddrbyHandle)(UINT16 handle, BD_ADDR bd_addr);
+ UINT8 (*GetChnlFcrMode)(UINT16 lcid);
+ UINT16 (*SendFixedChnlData)(UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf);
+ void (*Cleanup)(void);
+ bt_status_t (*RegisterLePsm) (UINT16 le_psm, BOOLEAN ConnType, UINT16 SecLevel,
+ UINT8 enc_key_size);
+ bt_status_t (*LeDeregister)(UINT16 psm);
+ UINT16 (*LeConnect) (UINT16 le_psm , BD_ADDR address, tL2CAP_LE_CFG_INFO *p_cfg);
+ BOOLEAN (*LeConnectRsp) (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result,
+ UINT16 status, tL2CAP_LE_CFG_INFO *p_cfg);
+ BOOLEAN (*LeFlowControl) (UINT16 lcid, UINT16 credits);
+ void (*LeFreeBuf)(BT_HDR *p_buf);
+} btl2cap_interface_t;
+
+typedef struct
+{
+ size_t size;
+ void (*Init)(void);
+ tMCA_HANDLE (*Register)(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback);
+ void (*Deregister)(tMCA_HANDLE handle);
+ tMCA_RESULT (*CreateDep)(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs);
+ tMCA_RESULT (*DeleteDep)(tMCA_HANDLE handle, tMCA_DEP dep);
+ tMCA_RESULT (*ConnectReq)(tMCA_HANDLE handle, BD_ADDR bd_addr,
+ UINT16 ctrl_psm,
+ UINT16 sec_mask);
+ tMCA_RESULT (*DisconnectReq)(tMCA_CL mcl);
+ tMCA_RESULT (*CreateMdl)(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, UINT8 peer_dep_id,
+ UINT8 cfg, const tMCA_CHNL_CFG *p_chnl_cfg);
+ tMCA_RESULT (*CreateMdlRsp)(tMCA_CL mcl, tMCA_DEP dep,
+ UINT16 mdl_id, UINT8 cfg, UINT8 rsp_code,
+ const tMCA_CHNL_CFG *p_chnl_cfg);
+ tMCA_RESULT (*CloseReq)(tMCA_DL mdl);
+ tMCA_RESULT (*ReconnectMdl)(tMCA_CL mcl, tMCA_DEP dep, UINT16 data_psm,
+ UINT16 mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg);
+ tMCA_RESULT (*ReconnectMdlRsp)(tMCA_CL mcl, tMCA_DEP dep,
+ UINT16 mdl_id, UINT8 rsp_code,
+ const tMCA_CHNL_CFG *p_chnl_cfg);
+ tMCA_RESULT (*DataChnlCfg)(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg);
+ tMCA_RESULT (*Abort)(tMCA_CL mcl);
+ tMCA_RESULT (*Delete)(tMCA_CL mcl, UINT16 mdl_id);
+ tMCA_RESULT (*WriteReq)(tMCA_DL mdl, BT_HDR *p_pkt);
+ UINT16 (*GetL2CapChannel) (tMCA_DL mdl);
+}btmcap_interface_t;
+
+typedef struct
+{
+ size_t size;
+ //GATT common APIs (Both client and server)
+ tGATT_IF (*Register) (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info);
+ void (*Deregister) (tGATT_IF gatt_if);
+ void (*StartIf) (tGATT_IF gatt_if);
+ BOOLEAN (*Connect) (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct,tBT_TRANSPORT transport);
+ tGATT_STATUS (*Disconnect) (UINT16 conn_id);
+ BOOLEAN (*Listen) (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr);
+
+ //GATT Client APIs
+ tGATT_STATUS (*cConfigureMTU) (UINT16 conn_id, UINT16 mtu);
+ tGATT_STATUS (*cDiscover) (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_PARAM *p_param );
+ tGATT_STATUS (*cRead) (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read);
+ tGATT_STATUS (*cWrite) (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write);
+ tGATT_STATUS (*cExecuteWrite) (UINT16 conn_id, BOOLEAN is_execute);
+ tGATT_STATUS (*cSendHandleValueConfirm) (UINT16 conn_id, UINT16 handle);
+ void (*cSetIdleTimeout)(BD_ADDR bd_addr, UINT16 idle_tout);
+ void (*cSetVisibility) (UINT16 disc_mode, UINT16 conn_mode);
+
+ //GATT Server APIs
+ //TODO - Add api on the need basis
+
+}btgatt_test_interface_t;
+
+typedef struct
+{
+ size_t size;
+ void (*init)(void);
+ BOOLEAN (*Register) (tSMP_CALLBACK *p_cback);
+ tSMP_STATUS (*Pair) (BD_ADDR bd_addr);
+ BOOLEAN (*PairCancel) (BD_ADDR bd_addr);
+ void (*SecurityGrant)(BD_ADDR bd_addr, UINT8 res);
+ void (*PasskeyReply) (BD_ADDR bd_addr, UINT8 res, UINT32 passkey);
+ BOOLEAN (*Encrypt) (UINT8 *key, UINT8 key_len, UINT8 *plain_text, UINT8 pt_len, tSMP_ENC *p_out);
+}btsmp_interface_t;
+typedef struct
+{
+ size_t size;
+ void (*Gap_AttrInit)();
+ void (*Gap_BleAttrDBUpdate)(BD_ADDR bd_addr, UINT16 int_min, UINT16 int_max, UINT16 latency, UINT16 sp_tout);
+}btgap_interface_t;
+
+/** Bluetooth RFC tool commands */
+typedef enum {
+ RFC_TEST_CLIENT =1,
+ RFC_TEST_FRAME_ERROR,
+ RFC_TEST_ROLE_SWITCH,
+ RFC_TEST_SERVER,
+ RFC_TEST_DISCON,
+ RFC_TEST_CLIENT_TEST_MSC_DATA, //For PTS test case BV 21 and 22
+ RFC_TEST_WRITE_DATA
+}rfc_test_cmd_t;
+
+
+typedef struct {
+ bt_bdaddr_t bdadd;
+ uint8_t scn; //Server Channel Number
+}bt_rfc_conn_t;
+
+typedef struct {
+ bt_bdaddr_t bdadd;
+ uint8_t role; //0x01 for master
+}bt_role_sw;
+
+typedef union {
+ bt_rfc_conn_t conn;
+ uint8_t server;
+ bt_role_sw role_switch;
+}tRfcomm_test;
+
+typedef struct {
+ rfc_test_cmd_t param;
+ tRfcomm_test data;
+}tRFC;
+
+typedef struct {
+ size_t size;
+ bt_status_t (*init)( tL2CAP_APPL_INFO* callbacks );
+ void (*rdut_rfcomm)( UINT8 server );
+ void (*rdut_rfcomm_test_interface)( tRFC *input);
+ bt_status_t (*connect)( bt_bdaddr_t *bd_addr );
+ void (*cleanup)( void );
+} btrfcomm_interface_t;
+
+#endif
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_BT_TESTAPP_H */
diff --git a/include/bt_trace.h b/include/bt_trace.h
index fea0c3c..744c63d 100644
--- a/include/bt_trace.h
+++ b/include/bt_trace.h
@@ -112,7 +112,8 @@
/* LayerIDs for BT APP */
#define BTTRC_ID_BTAPP 87
-#define BTTRC_ID_BT_PROTOCOL 88 /* this is a temporary solution to allow dynamic
+#define BTTRC_ID_LATENCY_AUDIO 88
+#define BTTRC_ID_BT_PROTOCOL 89 /* this is a temporary solution to allow dynamic
enable/disable of BT_PROTOCOL_TRACE */
#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL
#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */
@@ -120,6 +121,7 @@
#define BTTRC_PARAM_UINT8 1
#define BTTRC_PARAM_UINT16 2
#define BTTRC_PARAM_UINT32 3
+extern void BTA_setStackLog( const char* log_layer, int log_level);
/* Enables or disables verbose trace information. */
#ifndef BT_TRACE_VERBOSE
@@ -220,150 +222,158 @@
#define BT_TRACE(l,t,...) LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__)
#define BT_ERROR_TRACE(l,...) LogMsg(TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | TRACE_TYPE_ERROR, ##__VA_ARGS__)
+#define VND_TRACE(l,t,...) vnd_LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__)
+#define GENERATE_VENDOR_LOGS() vnd_GenerateLogs()
+
/* Define tracing for the HCI unit
*/
-#define HCI_TRACE_ERROR(...) {if (btu_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define HCI_TRACE_WARNING(...) {if (btu_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define HCI_TRACE_EVENT(...) {if (btu_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define HCI_TRACE_DEBUG(...) {if (btu_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define HCI_TRACE_ERROR(...) {if (btu_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define HCI_TRACE_WARNING(...) {if (btu_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define HCI_TRACE_EVENT(...) {if (btu_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define HCI_TRACE_DEBUG(...) {if (btu_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Define tracing for BTM
*/
-#define BTM_TRACE_ERROR(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define BTM_TRACE_WARNING(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define BTM_TRACE_API(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define BTM_TRACE_EVENT(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define BTM_TRACE_DEBUG(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define BTM_TRACE_ERROR(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define BTM_TRACE_WARNING(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define BTM_TRACE_API(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define BTM_TRACE_EVENT(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define BTM_TRACE_DEBUG(...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Define tracing for the L2CAP unit
*/
-#define L2CAP_TRACE_ERROR(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define L2CAP_TRACE_WARNING(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define L2CAP_TRACE_API(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define L2CAP_TRACE_EVENT(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define L2CAP_TRACE_DEBUG(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define L2CAP_TRACE_ERROR(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define L2CAP_TRACE_WARNING(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define L2CAP_TRACE_API(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define L2CAP_TRACE_EVENT(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define L2CAP_TRACE_DEBUG(...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Define tracing for the SDP unit
*/
-#define SDP_TRACE_ERROR(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define SDP_TRACE_WARNING(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define SDP_TRACE_API(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define SDP_TRACE_EVENT(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define SDP_TRACE_DEBUG(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define SDP_TRACE_ERROR(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define SDP_TRACE_WARNING(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define SDP_TRACE_API(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define SDP_TRACE_EVENT(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define SDP_TRACE_DEBUG(...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Define tracing for the RFCOMM unit
*/
-#define RFCOMM_TRACE_ERROR(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define RFCOMM_TRACE_WARNING(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define RFCOMM_TRACE_API(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define RFCOMM_TRACE_EVENT(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define RFCOMM_TRACE_DEBUG(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define RFCOMM_TRACE_ERROR(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define RFCOMM_TRACE_WARNING(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define RFCOMM_TRACE_API(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define RFCOMM_TRACE_EVENT(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define RFCOMM_TRACE_DEBUG(...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Generic Access Profile traces */
-#define GAP_TRACE_ERROR(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define GAP_TRACE_EVENT(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define GAP_TRACE_API(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define GAP_TRACE_WARNING(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define GAP_TRACE_ERROR(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define GAP_TRACE_EVENT(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define GAP_TRACE_API(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define GAP_TRACE_WARNING(...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
/* define traces for HID Host */
-#define HIDH_TRACE_ERROR(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define HIDH_TRACE_WARNING(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define HIDH_TRACE_API(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define HIDH_TRACE_EVENT(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define HIDH_TRACE_DEBUG(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define HIDH_TRACE_ERROR(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define HIDH_TRACE_WARNING(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define HIDH_TRACE_API(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define HIDH_TRACE_EVENT(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define HIDH_TRACE_DEBUG(...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* define traces for BNEP */
-#define BNEP_TRACE_ERROR(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define BNEP_TRACE_WARNING(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define BNEP_TRACE_API(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define BNEP_TRACE_EVENT(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define BNEP_TRACE_DEBUG(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define BNEP_TRACE_ERROR(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define BNEP_TRACE_WARNING(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define BNEP_TRACE_API(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define BNEP_TRACE_EVENT(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define BNEP_TRACE_DEBUG(...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* define traces for PAN */
-#define PAN_TRACE_ERROR(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define PAN_TRACE_WARNING(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define PAN_TRACE_API(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define PAN_TRACE_EVENT(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define PAN_TRACE_DEBUG(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define PAN_TRACE_ERROR(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define PAN_TRACE_WARNING(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define PAN_TRACE_API(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define PAN_TRACE_EVENT(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define PAN_TRACE_DEBUG(...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Define tracing for the A2DP profile
*/
-#define A2D_TRACE_ERROR(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,##__VA_ARGS__);}
-#define A2D_TRACE_WARNING(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,##__VA_ARGS__);}
-#define A2D_TRACE_EVENT(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,##__VA_ARGS__);}
-#define A2D_TRACE_DEBUG(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,##__VA_ARGS__);}
-#define A2D_TRACE_API(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_API,##__VA_ARGS__);}
+#define A2D_TRACE_ERROR(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_ERROR,##__VA_ARGS__);}
+#define A2D_TRACE_WARNING(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_WARNING,##__VA_ARGS__);}
+#define A2D_TRACE_EVENT(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_EVENT,##__VA_ARGS__);}
+#define A2D_TRACE_DEBUG(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_DEBUG,##__VA_ARGS__);}
+#define A2D_TRACE_API(...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_API,##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_A2D, TRACE_TYPE_API,##__VA_ARGS__);}
/* AVDTP
*/
-#define AVDT_TRACE_ERROR(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define AVDT_TRACE_WARNING(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define AVDT_TRACE_EVENT(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define AVDT_TRACE_DEBUG(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
-#define AVDT_TRACE_API(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define AVDT_TRACE_ERROR(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define AVDT_TRACE_WARNING(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define AVDT_TRACE_EVENT(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define AVDT_TRACE_DEBUG(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define AVDT_TRACE_API(...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__);}
/* Define tracing for the AVCTP protocol
*/
-#define AVCT_TRACE_ERROR(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define AVCT_TRACE_WARNING(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define AVCT_TRACE_EVENT(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define AVCT_TRACE_DEBUG(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
-#define AVCT_TRACE_API(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define AVCT_TRACE_ERROR(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define AVCT_TRACE_WARNING(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define AVCT_TRACE_EVENT(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define AVCT_TRACE_DEBUG(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define AVCT_TRACE_API(...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__);}
/* Define tracing for the AVRCP profile
*/
-#define AVRC_TRACE_ERROR(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define AVRC_TRACE_WARNING(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define AVRC_TRACE_EVENT(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define AVRC_TRACE_DEBUG(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
-#define AVRC_TRACE_API(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define AVRC_TRACE_ERROR(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define AVRC_TRACE_WARNING(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define AVRC_TRACE_EVENT(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define AVRC_TRACE_DEBUG(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define AVRC_TRACE_API(...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__);}
/* MCAP
*/
-#define MCA_TRACE_ERROR(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define MCA_TRACE_WARNING(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define MCA_TRACE_EVENT(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define MCA_TRACE_DEBUG(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
-#define MCA_TRACE_API(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define MCA_TRACE_ERROR(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define MCA_TRACE_WARNING(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define MCA_TRACE_EVENT(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define MCA_TRACE_DEBUG(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define MCA_TRACE_API(...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__);}
/* Define tracing for the ATT/GATT unit
*/
-#define GATT_TRACE_ERROR(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define GATT_TRACE_WARNING(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define GATT_TRACE_API(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define GATT_TRACE_EVENT(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define GATT_TRACE_DEBUG(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define GATT_TRACE_ERROR(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define GATT_TRACE_WARNING(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define GATT_TRACE_API(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define GATT_TRACE_EVENT(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define GATT_TRACE_DEBUG(...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Define tracing for the SMP unit
*/
-#define SMP_TRACE_ERROR(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define SMP_TRACE_WARNING(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define SMP_TRACE_API(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_API, ##__VA_ARGS__);}
-#define SMP_TRACE_EVENT(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define SMP_TRACE_DEBUG(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define SMP_TRACE_ERROR(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define SMP_TRACE_WARNING(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define SMP_TRACE_API(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_API, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_API, ##__VA_ARGS__);}
+#define SMP_TRACE_EVENT(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define SMP_TRACE_DEBUG(...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); else VND_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
extern UINT8 btif_trace_level;
+extern UINT8 audio_latency_trace_level;
/* define traces for application */
-#define BTIF_TRACE_ERROR(...) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define BTIF_TRACE_WARNING(...) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define BTIF_TRACE_API(...) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, ##__VA_ARGS__);}
-#define BTIF_TRACE_EVENT(...) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define BTIF_TRACE_DEBUG(...) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define BTIF_TRACE_IMP(...) {LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define BTIF_TRACE_ERROR(...) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define BTIF_TRACE_WARNING(...) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, ##__VA_ARGS__);}
+#define BTIF_TRACE_API(...) {if (btif_trace_level >= BT_TRACE_LEVEL_API) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, ##__VA_ARGS__);}
+#define BTIF_TRACE_EVENT(...) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define BTIF_TRACE_DEBUG(...) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
#define BTIF_TRACE_VERBOSE(...) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+
/* define traces for application */
-#define APPL_TRACE_ERROR(...) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__);}
-#define APPL_TRACE_WARNING(...) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, ##__VA_ARGS__);}
-#define APPL_TRACE_API(...) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, ##__VA_ARGS__);}
-#define APPL_TRACE_EVENT(...) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, ##__VA_ARGS__);}
-#define APPL_TRACE_DEBUG(...) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define APPL_TRACE_IMP(...) {LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define APPL_TRACE_ERROR(...) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define APPL_TRACE_WARNING(...) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_WARNING, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_ERROR, ##__VA_ARGS__);}
+#define APPL_TRACE_API(...) {if (appl_trace_level >= BT_TRACE_LEVEL_API) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_API, ##__VA_ARGS__);}
+#define APPL_TRACE_EVENT(...) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_EVENT, ##__VA_ARGS__);}
+#define APPL_TRACE_DEBUG(...) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__); else vnd_LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
#define APPL_TRACE_VERBOSE(...) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
+#define APPL_TRACE_LATENCY_AUDIO(...) {if (audio_latency_trace_level >= BT_TRACE_LEVEL_VERBOSE) LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, ##__VA_ARGS__);}
/* Simplified Trace Helper Macro
*/
@@ -414,3 +424,5 @@
extern UINT8 appl_trace_level;
void LogMsg (UINT32 trace_set_mask, const char *fmt_str, ...);
+void vnd_LogMsg (UINT32 trace_set_mask, const char *fmt_str, ...);
+void vnd_GenerateLogs();
diff --git a/include/logging.h b/include/logging.h
new file mode 100644
index 0000000..bd70b39
--- /dev/null
+++ b/include/logging.h
@@ -0,0 +1,45 @@
+/*********************************************************************
+*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+************************************************************************/
+
+#include <stdio.h>
+#include "bt_types.h"
+
+__BEGIN_DECLS
+
+typedef struct {
+
+ size_t size;
+ void (*setLog)( const char *log_layer, UINT16 log_level);
+} btstacklog_interface_t;
+
+__END_DECLS
+
diff --git a/include/stack_config.h b/include/stack_config.h
index b5278ce..837fdbe 100644
--- a/include/stack_config.h
+++ b/include/stack_config.h
@@ -32,6 +32,7 @@
typedef struct {
const char *(*get_btsnoop_log_path)(void);
bool (*get_btsnoop_turned_on)(void);
+ void (*get_btsnoop_ext_options)(bool *hci_ext_dump_enabled, bool *btsnoop_conf_from_file);
bool (*get_btsnoop_should_save_last)(void);
bool (*get_trace_config_enabled)(void);
bool (*get_pts_secure_only_mode)(void);
@@ -39,6 +40,7 @@
bool (*get_pts_crosskey_sdp_disable)(void);
const char* (*get_pts_smp_options)(void);
int (*get_pts_smp_failure_case)(void);
+ bool (*get_pts_le_nonconn_adv_enabled)(void);
config_t *(*get_all)(void);
} stack_config_t;
diff --git a/main/Android.mk b/main/Android.mk
index 25a0358..594b4d2 100644
--- a/main/Android.mk
+++ b/main/Android.mk
@@ -26,6 +26,16 @@
LOCAL_SRC_FILES+= \
../udrv/ulinux/uipc.c
+ifeq ($(BOARD_USES_WIPOWER),true)
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_SRC_FILES += \
+ ../../../vendor/qcom/opensource/bluetooth/wipower-host/core/src/wipower.c
+else
+LOCAL_SRC_FILES += \
+ ../../../device/qcom/msm8909w/opensource/bluetooth/wipower-host/core/src/wipower.c
+endif
+endif
+
LOCAL_C_INCLUDES+= . \
$(LOCAL_PATH)/../ \
$(LOCAL_PATH)/../bta/include \
@@ -53,7 +63,20 @@
$(LOCAL_PATH)/../utils/include \
$(bluetooth_C_INCLUDES) \
external/tinyxml2 \
- external/zlib
+ external/zlib \
+ $(call include-path-for, audio-utils)
+
+ifeq ($(BOARD_USES_WIPOWER),true)
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_C_INCLUDES+= \
+ vendor/qcom/opensource/bluetooth/hal/include \
+ vendor/qcom/opensource/bluetooth/wipower-host/core/include
+else
+LOCAL_C_INCLUDES+= \
+ device/qcom/msm8909w/opensource/bluetooth/hal/include \
+ device/qcom/msm8909w/opensource/bluetooth/wipower-host/core/include
+endif
+endif
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -64,7 +87,8 @@
libprotobuf-cpp-full \
libmedia \
libutils \
- libchrome
+ libchrome \
+ libaudioutils
LOCAL_STATIC_LIBRARIES := \
libtinyxml2 \
@@ -98,6 +122,7 @@
LOCAL_REQUIRED_MODULES := \
bt_did.conf \
bt_stack.conf \
+ interop_database.conf \
libbt-hci \
libbt-vendor
diff --git a/main/bte_logmsg.c b/main/bte_logmsg.c
index 4a59eac..2d6d208 100644
--- a/main/bte_logmsg.c
+++ b/main/bte_logmsg.c
@@ -25,6 +25,7 @@
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
+#include <dlfcn.h>
#include "avrc_api.h"
#include "bta_api.h"
@@ -66,6 +67,10 @@
#define BTE_LOG_BUF_SIZE 1024
#endif
+#define VND_PKT_SIZE_BLOCKS 4
+#define VND_PKT_HEADER_SIZE 5 //(VND_PKT_SIZE_BLOCKS + 1)
+#define VND_PKT_BODY_SIZE 1021
+
#define BTE_LOG_MAX_SIZE (BTE_LOG_BUF_SIZE - 12)
#define MSG_BUFFER_OFFSET 0
@@ -125,6 +130,7 @@
static uint8_t BTAPP_SetTraceLevel(uint8_t new_level);
static uint8_t BTIF_SetTraceLevel(uint8_t new_level);
static uint8_t BTU_SetTraceLevel(uint8_t new_level);
+static uint8_t AUDIO_Latency_SetTraceLevel(uint8_t new_level);
/* make sure list is order by increasing layer id!!! */
static tBTTRC_FUNC_MAP bttrc_set_level_map[] = {
@@ -154,6 +160,9 @@
{BTTRC_ID_STK_GATT, BTTRC_ID_STK_GATT, GATT_SetTraceLevel, "TRC_GATT", DEFAULT_CONF_TRACE_LEVEL},
{BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP", DEFAULT_CONF_TRACE_LEVEL},
#endif
+#if (BT_TRACE_LATENCY_AUDIO == TRUE)
+ {BTTRC_ID_LATENCY_AUDIO, BTTRC_ID_LATENCY_AUDIO, AUDIO_Latency_SetTraceLevel, "TRC_LATENCY_AUDIO", DEFAULT_CONF_TRACE_LEVEL},
+#endif
/* LayerIDs for BTA, currently everything maps onto appl_trace_level.
*/
@@ -194,6 +203,26 @@
}
}
+void vnd_LogMsg(uint32_t trace_set_mask, const char *fmt_str, ...) {
+ int trace_layer = TRACE_GET_LAYER(trace_set_mask);
+ const char *tag;
+ if (trace_layer >= TRACE_LAYER_MAX_NUM)
+ trace_layer = 0;
+
+ tag = bt_layer_tags[trace_layer];
+
+ va_list ap;
+ va_start(ap, fmt_str);
+ if(logger_interface)
+ logger_interface->send_log_msg(tag, fmt_str, ap);
+ va_end(ap);
+}
+
+void vnd_GenerateLogs() {
+ if(logger_interface)
+ logger_interface->send_event(GENERATE_VND_LOG_SIGNAL);
+}
+
/* this function should go into BTAPP_DM for example */
static uint8_t BTAPP_SetTraceLevel(uint8_t new_level) {
if (new_level != 0xFF)
@@ -209,6 +238,15 @@
return btif_trace_level;
}
+static uint8_t AUDIO_Latency_SetTraceLevel( uint8_t new_level )
+{
+ if (new_level != 0xFF)
+ audio_latency_trace_level = new_level;
+
+ return (audio_latency_trace_level);
+}
+
+
static uint8_t BTU_SetTraceLevel(uint8_t new_level) {
if (new_level != 0xFF)
btu_trace_level = new_level;
@@ -236,7 +274,6 @@
LOG_INFO(LOG_TAG, "using compile default trace settings");
return NULL;
}
-
load_levels_from_config(stack_config->get_all());
return NULL;
}
@@ -252,3 +289,43 @@
NULL
}
};
+
+/********************************************************************************
+ **
+ ** Function Name: BTA_setStackLog
+ **
+ ** Purpose: Set the trace level of the different layers of stack
+ based on the stack layer and level as input
+ **
+ ** Input Parameters: const char* log_layer, int log_level
+ Example : TRC_HCI, 5
+ **
+ ** Returns: void
+ **
+ *********************************************************************************/
+
+void BTA_setStackLog( const char* log_layer, int log_level)
+{
+ const tBTTRC_FUNC_MAP *p_f_map;
+ int new_level = 0;
+ int layer_found = 0;
+ p_f_map = &bttrc_set_level_map[0];
+
+ while ( 0 != p_f_map->layer_id_start )
+ {
+
+ if( (NULL != p_f_map->p_f) && !strcmp( p_f_map->trc_name, log_layer))
+ {
+ new_level = p_f_map->p_f(log_level);
+ LOG_INFO("BTA_setStackLog: New trace level set for layer %s is %d", log_layer, new_level);
+ layer_found = 1;
+ break;
+ }
+ p_f_map++;
+ }
+
+ if ( layer_found == 0 )
+ {
+ LOG_INFO("BTA_setStackLog: Unable to set Layer %s with level %d. Layer not found", log_layer, log_level);
+ }
+}
diff --git a/main/bte_main.c b/main/bte_main.c
index da36056..7ab0440 100644
--- a/main/bte_main.c
+++ b/main/bte_main.c
@@ -267,3 +267,22 @@
osi_free(p_msg);
}
}
+/******************************************************************************
+**
+** Function bte_ssr_cleanup
+**
+** Description sends PWR_OFF to vendor library so that harware would be
+** turned off as part of hardware subsystem crash
+**
+** Returns None
+**
+******************************************************************************/
+void bte_ssr_cleanup(int reason)
+{
+ APPL_TRACE_DEBUG("%s", __FUNCTION__);
+ if (hci != NULL) {
+ hci->ssr_cleanup(reason);
+ } else {
+ APPL_TRACE_ERROR("%s hci is NULL", __FUNCTION__);
+ }
+}
diff --git a/main/stack_config.c b/main/stack_config.c
index df0e0ef..f12a789 100644
--- a/main/stack_config.c
+++ b/main/stack_config.c
@@ -27,6 +27,8 @@
const char *BTSNOOP_LOG_PATH_KEY = "BtSnoopFileName";
const char *BTSNOOP_TURNED_ON_KEY = "BtSnoopLogOutput";
+const char *BTSNOOP_EXT_DUMP_KEY = "BtSnoopExtDump";
+const char *BTSNOOP_CONFIG_FROM_FILE_KEY = "BtSnoopConfigFromFile";
const char *BTSNOOP_SHOULD_SAVE_LAST_KEY = "BtSnoopSaveLog";
const char *TRACE_CONFIG_ENABLED_KEY = "TraceConf";
const char *PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly";
@@ -34,6 +36,7 @@
const char *PTS_DISABLE_SDP_LE_PAIR = "PTS_DisableSDPOnLEPair";
const char *PTS_SMP_PAIRING_OPTIONS_KEY = "PTS_SmpOptions";
const char *PTS_SMP_FAILURE_CASE_KEY = "PTS_SmpFailureCase";
+const char *PTS_LE_NONCONN_ADV_MODE = "PTS_EnableNonConnAdvMode";
static config_t *config;
@@ -115,6 +118,15 @@
return config_get_int(config, CONFIG_DEFAULT_SECTION, PTS_SMP_FAILURE_CASE_KEY, 0);
}
+static void get_btsnoop_ext_options(bool *hci_ext_dump_enabled, bool *btsnoop_conf_from_file) {
+ *hci_ext_dump_enabled = config_get_bool(config, CONFIG_DEFAULT_SECTION, BTSNOOP_EXT_DUMP_KEY, false);
+ *btsnoop_conf_from_file = config_get_bool(config, CONFIG_DEFAULT_SECTION, BTSNOOP_CONFIG_FROM_FILE_KEY, false);
+}
+
+static bool get_pts_le_nonconn_adv_enabled(void) {
+ return config_get_bool(config, CONFIG_DEFAULT_SECTION, PTS_LE_NONCONN_ADV_MODE, false);
+}
+
static config_t *get_all(void) {
return config;
}
@@ -122,6 +134,7 @@
const stack_config_t interface = {
get_btsnoop_log_path,
get_btsnoop_turned_on,
+ get_btsnoop_ext_options,
get_btsnoop_should_save_last,
get_trace_config_enabled,
get_pts_secure_only_mode,
@@ -129,6 +142,7 @@
get_pts_crosskey_sdp_disable,
get_pts_smp_options,
get_pts_smp_failure_case,
+ get_pts_le_nonconn_adv_enabled,
get_all
};
diff --git a/osi/Android.mk b/osi/Android.mk
index d1937d1..bab6cd1 100644
--- a/osi/Android.mk
+++ b/osi/Android.mk
@@ -51,7 +51,8 @@
./src/socket_utils/socket_local_server.c \
./src/thread.c \
./src/time.c \
- ./src/wakelock.c
+ ./src/wakelock.c \
+ ./src/vnd_log.c
btosiCommonTestSrc := \
./test/AlarmTestHarness.cpp \
diff --git a/osi/include/list.h b/osi/include/list.h
index a510178..82c6b5a 100644
--- a/osi/include/list.h
+++ b/osi/include/list.h
@@ -16,6 +16,7 @@
// user defined value passed into |list_foreach|.
// Callback must return true to continue iterating or false to stop iterating.
typedef bool (*list_iter_cb)(void *data, void *context);
+typedef bool (*list_iter_cb_ext)(void *data, void *cb_data);
// Returns a new, empty list. Returns NULL if not enough memory could be allocated
// for the list structure. The returned list must be freed with |list_free|. The
@@ -91,6 +92,7 @@
// there will be no callback for the newly-inserted node. Neither |list| nor
// |callback| may be NULL.
list_node_t *list_foreach(const list_t *list, list_iter_cb callback, void *context);
+void list_foreach_ext(const list_t *list, list_iter_cb_ext callback, void *cb_data);
// Returns an iterator to the first element in |list|. |list| may not be NULL.
// The returned iterator is valid as long as it does not equal the value returned
diff --git a/osi/include/log.h b/osi/include/log.h
index 738462e..a579ded 100644
--- a/osi/include/log.h
+++ b/osi/include/log.h
@@ -17,6 +17,12 @@
******************************************************************************/
#pragma once
+#include <string.h>
+#include <stdbool.h>
+#include "include/bt_logger_lib.h"
+
+extern bt_logger_interface_t *logger_interface;
+extern bool bt_logger_enabled;
/*
* TODO(armansito): Work-around until we figure out a way to generate logs in a
@@ -39,14 +45,16 @@
#include <cutils/log.h>
+//#define VNDLOG(tag, fmt, ## args) if(logger_interface)logger_interface->send_log_data(tag, fmt, ## args)
+
#if LOG_NDEBUG
#define LOG_VERBOSE(...) ((void)0)
#else // LOG_NDEBUG
#define LOG_VERBOSE(tag, fmt, args...) ALOG(LOG_VERBOSE, tag, fmt, ## args)
#endif // !LOG_NDEBUG
-#define LOG_DEBUG(tag, fmt, args...) ALOG(LOG_DEBUG, tag, fmt, ## args )
-#define LOG_INFO(tag, fmt, args...) ALOG(LOG_INFO, tag, fmt, ## args)
-#define LOG_WARN(tag, fmt, args...) ALOG(LOG_WARN, tag, fmt, ## args)
-#define LOG_ERROR(tag, fmt, args...) ALOG(LOG_ERROR, tag, fmt, ## args)
+#define LOG_DEBUG(tag, fmt, args...) {if(logger_interface)logger_interface->send_log_data(tag, fmt, ## args);ALOG(LOG_DEBUG, tag, fmt, ## args);}
+#define LOG_INFO(tag, fmt, args...) {if(logger_interface)logger_interface->send_log_data(tag, fmt, ## args);ALOG(LOG_INFO, tag, fmt, ## args);}
+#define LOG_WARN(tag, fmt, args...) {if(logger_interface)logger_interface->send_log_data(tag, fmt, ## args);ALOG(LOG_WARN, tag, fmt, ## args);}
+#define LOG_ERROR(tag, fmt, args...) {if(logger_interface)logger_interface->send_log_data(tag, fmt, ## args);ALOG(LOG_ERROR, tag, fmt, ## args);}
#endif /* defined(OS_GENERIC) */
diff --git a/osi/src/alarm.c b/osi/src/alarm.c
index ab4ed12..7ac6434 100644
--- a/osi/src/alarm.c
+++ b/osi/src/alarm.c
@@ -94,13 +94,11 @@
// unit tests to run faster. It should not be modified by production code.
int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
-
#if defined(KERNEL_MISSING_CLOCK_BOOTTIME_ALARM) && (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
#else
static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
#endif
-
// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
// functions execute serially and not concurrently. As a result, this mutex
// also protects the |alarms| list.
@@ -606,6 +604,7 @@
alarm->deadline = 0;
alarm->callback = NULL;
alarm->data = NULL;
+ alarm->queue = NULL;
}
pthread_mutex_lock(&alarm->callback_lock);
@@ -632,19 +631,21 @@
// thread for that alarm.
static void callback_dispatch(UNUSED_ATTR void *context) {
while (true) {
+ period_ms_t just_now;
semaphore_wait(alarm_expired);
if (!dispatcher_thread_active)
break;
pthread_mutex_lock(&monitor);
alarm_t *alarm;
+ just_now = now();
// Take into account that the alarm may get cancelled before we get to it.
// We're done here if there are no alarms or the alarm at the front is in
// the future. Release the monitor lock and exit right away since there's
// nothing left to do.
if (list_is_empty(alarms) ||
- (alarm = list_front(alarms))->deadline > now()) {
+ (alarm = list_front(alarms))->deadline > just_now) {
reschedule_root_alarm();
pthread_mutex_unlock(&monitor);
continue;
@@ -652,6 +653,9 @@
list_remove(alarms, alarm);
+ if(just_now - alarm->deadline > 1000)
+ LOG_DEBUG(LOG_TAG, "%s Delay in timer callback", __func__);
+
if (alarm->is_periodic) {
alarm->prev_deadline = alarm->deadline;
schedule_next_instance(alarm);
diff --git a/osi/src/allocation_tracker.c b/osi/src/allocation_tracker.c
index b4e1a84..c5cb6cd 100644
--- a/osi/src/allocation_tracker.c
+++ b/osi/src/allocation_tracker.c
@@ -133,10 +133,14 @@
hash_map_set(allocations, return_ptr, allocation);
}
- allocation->allocator_id = allocator_id;
- allocation->freed = false;
- allocation->size = requested_size;
- allocation->ptr = return_ptr;
+ if (allocation) {
+ allocation->allocator_id = allocator_id;
+ allocation->freed = false;
+ allocation->size = requested_size;
+ allocation->ptr = return_ptr;
+ } else {
+ LOG_ERROR(LOG_TAG, "%s Memory not allocated for allocation." ,__func__);
+ }
pthread_mutex_unlock(&lock);
diff --git a/osi/src/config.c b/osi/src/config.c
index 9145ce6..e2c577c 100644
--- a/osi/src/config.c
+++ b/osi/src/config.c
@@ -34,6 +34,7 @@
#include "osi/include/allocator.h"
#include "osi/include/list.h"
#include "osi/include/log.h"
+#include "osi/include/compat.h"
#include "log/log.h"
typedef struct {
@@ -214,7 +215,11 @@
section_t *sec = section_find(config, section);
if (!sec) {
sec = section_new(section);
- list_append(config->sections, sec);
+ if (sec)
+ list_append(config->sections, sec);
+ else {
+ LOG_ERROR(LOG_TAG,"%s: Unable to allocate memory for section", __func__);
+ }
}
size_t value_len = strlen(value);
@@ -227,19 +232,21 @@
}
}
- for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
- entry_t *entry = list_node(node);
- if (!strcmp(entry->key, key)) {
- osi_free(entry->value);
- entry->value = osi_strdup(value_no_newline);
- osi_free(value_no_newline);
- return;
+ if (sec) {
+ for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
+ entry_t *entry = list_node(node);
+ if (!strcmp(entry->key, key)) {
+ osi_free(entry->value);
+ entry->value = osi_strdup(value_no_newline);
+ osi_free(value_no_newline);
+ return;
+ }
}
- }
- entry_t *entry = entry_new(key, value_no_newline);
- osi_free(value_no_newline);
- list_append(sec->entries, entry);
+ entry_t *entry = entry_new(key, value_no_newline);
+ osi_free(value_no_newline);
+ list_append(sec->entries, entry);
+ }
}
bool config_remove_section(config_t *config, const char *section) {
@@ -333,7 +340,12 @@
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
const section_t *section = (const section_t *)list_node(node);
- if (fprintf(fp, "[%s]\n", section->name) < 0) {
+ if (section->name[0] == '#') {
+ if (fprintf(fp, "%s", section->name) < 0) {
+ LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
+ goto error;
+ }
+ } else if (fprintf(fp, "[%s]\n", section->name) < 0) {
LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
goto error;
}
@@ -424,31 +436,55 @@
assert(config != NULL);
int line_num = 0;
- char line[1024];
- char section[1024];
+ char line[1024] = { '\0' };
+ char section[1024] = { '\0' };
+ char comment[1024] = { '\0' };
+ bool skip_entries = false;
strcpy(section, CONFIG_DEFAULT_SECTION);
while (fgets(line, sizeof(line), fp)) {
char *line_ptr = trim(line);
++line_num;
- // Skip blank and comment lines.
- if (*line_ptr == '\0' || *line_ptr == '#')
+ // ignore the line if the line length is more than 1023
+ if (strlen(line) == 1023){
+ int ch = '\0';
+ // read until next line or EOF
+ while(((ch = fgetc(fp)) != EOF) && (ch != '\n'));
+ continue;
+ }
+
+ // Skip blanks.
+ if (*line_ptr == '\0')
continue;
- if (*line_ptr == '[') {
+ if (*line_ptr == '#') {
+ strlcpy(comment, line_ptr, 1024);
+
+ if(!section_find(config, comment)) {
+ section_t *sec = section_new(comment);
+ if (sec)
+ list_append(config->sections, sec);
+ }
+ } else if (*line_ptr == '[') {
size_t len = strlen(line_ptr);
if (line_ptr[len - 1] != ']') {
LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__, line_num);
- return false;
+ skip_entries = true;
+ continue;
}
strncpy(section, line_ptr + 1, len - 2);
section[len - 2] = '\0';
+ skip_entries = false;
} else {
char *split = strchr(line_ptr, '=');
+ if(skip_entries) {
+ LOG_DEBUG(LOG_TAG, "%s skip entries due invalid section line %d.", __func__, line_num);
+ continue;
+ }
if (!split) {
LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.", __func__, line_num);
- return false;
+ continue;
}
*split = '\0';
diff --git a/osi/src/eager_reader.c b/osi/src/eager_reader.c
index 07a944c..86fcecc 100644
--- a/osi/src/eager_reader.c
+++ b/osi/src/eager_reader.c
@@ -259,9 +259,9 @@
// the semaphore by the number of bytes we just read
eventfd_write(reader->bytes_available_fd, bytes_read);
} else {
- if (bytes_read == 0)
+ if (bytes_read == 0){
LOG_WARN(LOG_TAG, "%s fd said bytes existed, but none were found.", __func__);
- else
+ } else
LOG_WARN(LOG_TAG, "%s unable to read from file descriptor: %s", __func__, strerror(errno));
reader->allocator->free(buffer);
diff --git a/osi/src/list.c b/osi/src/list.c
index 9468579..4688ce9 100644
--- a/osi/src/list.c
+++ b/osi/src/list.c
@@ -188,6 +188,23 @@
return NULL;
}
+// Iterates through the entire |list| and calls |callback| for each data element.
+// Passes the caller provided data along with node
+// If the list is empty, |callback| will never be called. It is safe to mutate the
+// list inside the callback. If an element is added before the node being visited,
+// there will be no callback for the newly-inserted node. Neither |list| nor
+// |callback| may be NULL.
+void list_foreach_ext(const list_t *list, list_iter_cb_ext callback, void *cb_data) {
+ assert(list != NULL);
+ assert(callback != NULL);
+ if (list)
+ for (list_node_t *node = list->head; node; ) {
+ list_node_t *next = node->next;
+ callback(node->data, cb_data);
+ node = next;
+ }
+}
+
list_node_t *list_begin(const list_t *list) {
assert(list != NULL);
return list->head;
diff --git a/osi/src/socket.c b/osi/src/socket.c
index 4ebb3b8..abcf483 100644
--- a/osi/src/socket.c
+++ b/osi/src/socket.c
@@ -51,6 +51,11 @@
socket_t *socket_new(void) {
socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
+ if (ret == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate : %s", __func__, strerror(errno));
+ return NULL;
+ }
+
ret->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ret->fd == INVALID_FD) {
LOG_ERROR(LOG_TAG, "%s unable to create socket: %s", __func__, strerror(errno));
diff --git a/osi/src/thread.c b/osi/src/thread.c
index ebeab56..c7b1eb2 100644
--- a/osi/src/thread.c
+++ b/osi/src/thread.c
@@ -66,7 +66,10 @@
assert(work_queue_capacity != 0);
thread_t *ret = osi_calloc(sizeof(thread_t));
-
+ if (ret == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory" , __func__);
+ return NULL;
+ }
ret->reactor = reactor_new();
if (!ret->reactor)
goto error;
diff --git a/osi/src/vnd_log.c b/osi/src/vnd_log.c
new file mode 100644
index 0000000..a330f88
--- /dev/null
+++ b/osi/src/vnd_log.c
@@ -0,0 +1,89 @@
+/******************************************************************************
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#define LOG_TAG "bt_vnd_log"
+
+#include <errno.h>
+#include <string.h>
+#include <dlfcn.h>
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+static const char *LOGGER_LIBRARY_NAME = "libbt-logClient.so";
+static const char *LOGGER_LIBRARY_SYMBOL_NAME = "BLUETOOTH_LOGGER_LIB_INTERFACE";
+
+static void *lib_handle;
+bt_logger_interface_t *logger_interface = NULL;
+bool bt_logger_enabled = false;
+
+void init_vnd_Logger(void)
+{
+ if(!bt_logger_enabled)
+ {
+ LOG_ERROR(LOG_TAG, "%s, Logger Not enabled from config file", __func__);
+ return;
+ }
+
+ if(logger_interface)
+ {
+ LOG_ERROR(LOG_TAG, "%s, Vendor Logger is already initialized", __func__);
+ return;
+ }
+
+ lib_handle = dlopen(LOGGER_LIBRARY_NAME, RTLD_NOW);
+
+ if (!lib_handle) {
+ LOG_ERROR(LOG_TAG, "%s unable to open %s: %s", __func__, LOGGER_LIBRARY_NAME, dlerror());
+ return;
+ }
+
+ logger_interface = (bt_logger_interface_t *)dlsym(lib_handle, LOGGER_LIBRARY_SYMBOL_NAME);
+ if (!logger_interface) {
+ LOG_ERROR(LOG_TAG, "%s unable to find symbol %s in %s: %s", __func__, LOGGER_LIBRARY_SYMBOL_NAME, LOGGER_LIBRARY_NAME, dlerror());
+ return;
+ }
+
+ logger_interface->init();
+}
+
+void clean_vnd_logger()
+{
+ if(!bt_logger_enabled)
+ return;
+
+ if(logger_interface)
+ logger_interface->cleanup();
+
+ logger_interface = NULL;
+
+ if(lib_handle)
+ dlclose(lib_handle);
+
+ lib_handle = NULL;
+}
diff --git a/service/gatt_server_old.cpp b/service/gatt_server_old.cpp
index f775be9..9c535d0 100644
--- a/service/gatt_server_old.cpp
+++ b/service/gatt_server_old.cpp
@@ -44,6 +44,8 @@
#include "osi/include/osi.h"
} // extern "C"
+bt_logger_interface_t *logger_interface = NULL;
+
namespace {
const size_t kMaxGattAttributeSize = 512;
diff --git a/service/hal/bluetooth_interface.cpp b/service/hal/bluetooth_interface.cpp
index a551fee..d2e48ea 100644
--- a/service/hal/bluetooth_interface.cpp
+++ b/service/hal/bluetooth_interface.cpp
@@ -207,7 +207,8 @@
ThreadEventCallback,
nullptr, /* dut_mode_recv_cb */
nullptr, /* le_test_mode_cb */
- nullptr /* energy_info_cb */
+ nullptr, /* energy_info_cb */
+ nullptr /*hci_event_recv_cb */
};
bt_os_callouts_t bt_os_callouts = {
diff --git a/service/hal/fake_bluetooth_interface.cpp b/service/hal/fake_bluetooth_interface.cpp
index 5036c63..07de595 100644
--- a/service/hal/fake_bluetooth_interface.cpp
+++ b/service/hal/fake_bluetooth_interface.cpp
@@ -74,7 +74,9 @@
nullptr, /* dump */
nullptr, /* config clear */
nullptr, /* interop_database_clear */
- nullptr /* interop_database_add */
+ nullptr, /* interop_database_add */
+ nullptr, /* hci_cmd_send */
+ nullptr /* bt test app interface */
};
} // namespace
diff --git a/stack/Android.mk b/stack/Android.mk
index 40ae5a6..8e5d7c6 100644
--- a/stack/Android.mk
+++ b/stack/Android.mk
@@ -35,9 +35,19 @@
$(LOCAL_PATH)/../ \
$(bluetooth_C_INCLUDES)
+ifneq ($(TARGET_SUPPORTS_WEARABLES),true)
+LOCAL_C_INCLUDES+= \
+ vendor/qcom/opensource/bluetooth/system_bt_ext
+else
+LOCAL_C_INCLUDES+= \
+ device/qcom/msm8909w/opensource/bluetooth/system_bt_ext
+endif
LOCAL_SRC_FILES:= \
./a2dp/a2d_api.c \
./a2dp/a2d_sbc.c \
+ ./a2dp/a2d_aptx.c \
+ ./a2dp/a2d_aptx_hd.c \
+ ./a2dp/a2d_aac.c \
./avrc/avrc_api.c \
./avrc/avrc_sdp.c \
./avrc/avrc_opt.c \
@@ -153,6 +163,7 @@
LOCAL_STATIC_LIBRARIES := libbt-hci
LOCAL_SHARED_LIBRARIES := libcutils
+
LOCAL_CFLAGS += $(bluetooth_CFLAGS)
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
diff --git a/stack/a2dp/a2d_aac.c b/stack/a2dp/a2d_aac.c
new file mode 100644
index 0000000..d299e00
--- /dev/null
+++ b/stack/a2dp/a2d_aac.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ * Utility functions to help build and parse AAC Codec Information
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include <string.h>
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_aac.h"
+#include "bt_utils.h"
+
+#if (A2D_M24_INCLUDED == TRUE)
+static UINT8 A2D_UINT32_BitsSet(UINT32 num);
+/******************************************************************************
+**
+** Function A2D_BldAacInfo
+**
+** Description This function builds byte sequence for
+** Aac Codec Capabilities.
+** Input : media_type: Audio or MultiMedia.
+** p_ie: AAC Codec Information Element
+**
+** Output : p_result: codec info.
+**
+** Returns A2D_SUCCESS if successful.
+** Error otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_BldAacInfo(UINT8 media_type, tA2D_AAC_CIE *p_ie, UINT8 *p_result)
+{
+ tA2D_STATUS status;
+ if( p_ie == NULL || p_result == NULL ||
+ (p_ie->object_type & ~A2D_AAC_IE_OBJ_TYPE_MSK) ||
+ (p_ie->samp_freq & ~A2D_AAC_IE_SAMP_FREQ_MSK) ||
+ (p_ie->channels & ~A2D_AAC_IE_CHANNELS_MSK) ||
+ (p_ie->bit_rate & ~A2D_AAC_IE_BIT_RATE_MSK) ||
+ (p_ie->vbr & ~A2D_AAC_IE_VBR_MSK) )
+ {
+ /* return invalid params if invalid bit is set */
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_AAC_INFO_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_MEDIA_CT_M24;
+
+ /* Codec information */
+ *p_result++ = p_ie->object_type; // object type
+
+ *p_result++ = (UINT8)(p_ie->samp_freq >> 8);
+
+ *p_result++ = (p_ie->samp_freq & 0x00F0)|p_ie->channels;
+ *p_result++ = p_ie->vbr | ((p_ie->bit_rate >> 16)& 0x007F);
+ *p_result++ = (p_ie->bit_rate >> 8)& 0x00FF;
+ *p_result = p_ie->bit_rate & 0x000000FF;
+ }
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsAacInfo
+**
+** Description This function parse byte sequence for
+** Aac Codec Capabilities.
+** Input : p_info: input byte sequence.
+** for_caps: True for getcap, false otherwise
+**
+** Output : p_ie: Aac codec information.
+**
+** Returns A2D_SUCCESS if successful.
+** Error otherwise.
+******************************************************************************/
+tA2D_STATUS A2D_ParsAacInfo(tA2D_AAC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 losc;
+ UINT8 media_type;
+
+ if( p_ie == NULL || p_info == NULL)
+ status = A2D_INVALID_PARAMS;
+ else
+ {
+ losc = *p_info++;
+ media_type = *p_info++;
+ /* Check for wrong length, media type */
+ if(losc != A2D_AAC_INFO_LEN || *p_info != A2D_MEDIA_CT_M24)
+ status = A2D_WRONG_CODEC;
+ else
+ {
+ p_info++;
+ /* obj type */
+ p_ie->object_type = *p_info & A2D_AAC_IE_OBJ_TYPE_MSK; p_info++;
+ /* samping freq */
+ p_ie->samp_freq = *p_info; p_info++;
+ p_ie->samp_freq = p_ie->samp_freq << 8;
+ p_ie->samp_freq |= (*p_info & 0xF0);
+ /* channels */
+ p_ie->channels = *p_info & A2D_AAC_IE_CHANNELS_MSK; p_info++;
+ /* variable bit rate */
+ p_ie->vbr = *p_info & A2D_AAC_IE_VBR_MSK;
+ /* bit rate */
+ p_ie->bit_rate = *p_info & 0x7F;p_ie->bit_rate = p_ie->bit_rate << 8; p_info++;
+ p_ie->bit_rate |= *p_info;p_ie->bit_rate = p_ie->bit_rate << 8; p_info++;
+ p_ie->bit_rate |= *p_info;
+ status = A2D_SUCCESS;
+
+ if(for_caps == FALSE)
+ {
+ if(A2D_UINT32_BitsSet(p_ie->object_type) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_OBJ_TYPE;
+ if(A2D_UINT32_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+ if(A2D_UINT32_BitsSet(p_ie->channels) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CHANNEL;
+ }
+ }
+ }
+ return status;
+}
+/******************************************************************************
+** Function A2D_UINT32_BitsSet
+**
+** Description Check the given number of 32bit for the number of bits set
+** Returns A2D_SET_ONE_BIT, if one and only one bit is set
+** A2D_SET_ZERO_BIT, if all bits clear
+** A2D_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+static UINT8 A2D_UINT32_BitsSet(UINT32 num)
+{
+ UINT8 count;
+ BOOLEAN res;
+ if(num == 0)
+ res = A2D_SET_ZERO_BIT;
+ else
+ {
+ count = (num & (num - 1));
+ res = ((count==0)?A2D_SET_ONE_BIT:A2D_SET_MULTL_BIT);
+ }
+ return res;
+}
+#endif /* A2D_M24_INCLUDED == TRUE */
diff --git a/stack/a2dp/a2d_api.c b/stack/a2dp/a2d_api.c
index 2f31d1b..99d2104 100644
--- a/stack/a2dp/a2d_api.c
+++ b/stack/a2dp/a2d_api.c
@@ -28,6 +28,7 @@
#include "a2d_api.h"
#include "a2d_int.h"
#include "avdt_api.h"
+#include "osi/include/allocator.h"
/*****************************************************************************
** Global data
@@ -35,7 +36,16 @@
#if A2D_DYNAMIC_MEMORY == FALSE
tA2D_CB a2d_cb;
#endif
-
+/* Fix for below klockwork issue.
+ * Address of a local variable is returned through formal argument 'p_db->p_attrs' in
+ * API A2D_FindService removed local declaration and defined globally renamed from a2d_attr_list
+ * to a2d_attribute_list as there is a conflict in another file avrc_sdp.c */
+UINT16 a2d_attribute_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_PROVIDER_NAME};
/******************************************************************************
**
@@ -272,12 +282,6 @@
{
tSDP_UUID uuid_list;
BOOLEAN result = TRUE;
- UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */
- ATTR_ID_BT_PROFILE_DESC_LIST,
- ATTR_ID_SUPPORTED_FEATURES,
- ATTR_ID_SERVICE_NAME,
- ATTR_ID_PROTOCOL_DESC_LIST,
- ATTR_ID_PROVIDER_NAME};
A2D_TRACE_API("A2D_FindService uuid: %x", service_uuid);
if( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
@@ -294,7 +298,7 @@
if(p_db->p_attrs == NULL || p_db->num_attr == 0)
{
- p_db->p_attrs = a2d_attr_list;
+ p_db->p_attrs = a2d_attribute_list;
p_db->num_attr = A2D_NUM_ATTR;
}
@@ -306,7 +310,7 @@
if (result == TRUE)
{
- /* store service_uuid */
+ /* store service_uuid and discovery db pointer */
a2d_cb.find.service_uuid = service_uuid;
a2d_cb.find.p_cback = p_cback;
@@ -396,4 +400,17 @@
a2d_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
}
+/*******************************************************************************
+**
+** Function a2d_get_avdt_sdp_ver
+**
+** Description This function fetches current version of AVDT.
+**
+** Returns Current version of AVDT
+**
+*******************************************************************************/
+int a2d_get_avdt_sdp_ver ()
+{
+ return a2d_cb.avdt_sdp_ver;
+}
diff --git a/stack/a2dp/a2d_aptx.c b/stack/a2dp/a2d_aptx.c
new file mode 100644
index 0000000..05011bb
--- /dev/null
+++ b/stack/a2dp/a2d_aptx.c
@@ -0,0 +1,380 @@
+/******************************************************************************
+ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse the aptX Codec Information
+ * Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include <dlfcn.h>
+#include "osi/include/mutex.h"
+#include "osi/include/thread.h"
+#include "bt_utils.h"
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_aptx.h"
+#include "a2d_aptx_hd.h"
+#include <utils/Log.h>
+
+const char* A2D_APTX_SCHED_LIB_NAME = "libaptXScheduler.so";
+void *A2dAptXSchedLibHandle = NULL;
+thread_t *A2d_aptx_thread = NULL;
+BOOLEAN isA2dAptXEnabled = FALSE;
+
+int (*A2D_aptx_encoder_init)(void);
+A2D_AptXThreadFn (*A2D_aptx_sched_start)(void *encoder,
+ A2D_AptXCodecType aptX_codec_type,
+ BOOLEAN use_SCMS_T, BOOLEAN is_24bit_audio,
+ UINT16 sample_rate, UINT8 format_bits,
+ UINT8 channel, UINT16 MTU, A2D_AptXReadFn read_fn,
+ A2D_AptXBufferSendFn send_fn,
+ A2D_AptXSetPriorityFn set_priority_fn,
+ BOOLEAN test, BOOLEAN trace);
+BOOLEAN (*A2D_aptx_sched_stop)(void);
+void (*A2D_aptx_encoder_deinit)(void);
+A2D_AptXThreadFn A2d_aptx_thread_fn;
+
+/******************************************************************************
+**
+** Function A2D_BldAptxInfo
+**
+******************************************************************************/
+UINT8 A2D_BldAptxInfo(UINT8 media_type, tA2D_APTX_CIE *p_ie, UINT8 *p_result)
+{
+ A2D_TRACE_API("%s: - MediaType:%d", __func__, media_type);
+
+ UINT8 status = 0;
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_APTX_CODEC_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_NON_A2DP_MEDIA_CT;
+ *p_result++ = (UINT8)(p_ie->vendorId & 0x000000FF);
+ *p_result++ = (UINT8)(p_ie->vendorId & 0x0000FF00)>> 8;
+ *p_result++ = (UINT8)(p_ie->vendorId & 0x00FF0000)>> 16;
+ *p_result++ = (UINT8)(p_ie->vendorId & 0xFF000000)>> 24;
+ *p_result++ = (UINT8)(p_ie->codecId & 0x00FF);
+ *p_result++ = (UINT8)(p_ie->codecId & 0xFF00) >> 8;
+ *p_result++ = p_ie->sampleRate | p_ie->channelMode;
+
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsAptxInfo
+**
+******************************************************************************/
+tA2D_STATUS A2D_ParsAptxInfo(tA2D_APTX_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 losc;
+ UINT8 mt;
+
+ A2D_TRACE_API("%s: - MediaType:%d", __func__, for_caps);
+
+ if (p_ie == NULL || p_info == NULL)
+ {
+ A2D_TRACE_ERROR("A2D_ParsAptxInfo - Invalid Params");
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ losc = *p_info++;
+ mt = *p_info++;
+ A2D_TRACE_DEBUG("%s: losc %d, mt %02x", __func__, losc, mt);
+
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ if (losc != A2D_APTX_CODEC_LEN || *p_info != A2D_NON_A2DP_MEDIA_CT) {
+ A2D_TRACE_ERROR("%s: wrong media type %02x", __func__, *p_info);
+ status = A2D_WRONG_CODEC;
+ }
+ else
+ {
+ p_info++;
+ p_ie->vendorId = (*p_info & 0x000000FF) |
+ (*(p_info+1) << 8 & 0x0000FF00) |
+ (*(p_info+2) << 16 & 0x00FF0000) |
+ (*(p_info+3) << 24 & 0xFF000000);
+ p_info = p_info+4;
+ p_ie->codecId = (*p_info & 0x00FF) |(*(p_info+1) << 8 & 0xFF00);
+ p_info = p_info+2;
+ p_ie->channelMode= *p_info & 0x0F;
+ p_ie->sampleRate = *p_info & 0xF0;
+
+ status = A2D_SUCCESS;
+
+ if (for_caps == FALSE)
+ {
+ if (A2D_BitsSet(p_ie->sampleRate) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+ if (A2D_BitsSet(p_ie->channelMode) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CH_MODE;
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function a2d_av_aptx_cfg_in_cap
+**
+** Description This function checks whether an aptX codec configuration
+** is allowable for the given codec capabilities.
+**
+** Returns 0 if ok, nonzero if error.
+**
+*******************************************************************************/
+UINT8 a2d_av_aptx_cfg_in_cap(UINT8 *p_cfg, tA2D_APTX_CIE *p_cap)
+{
+ UINT8 status = 0;
+ tA2D_APTX_CIE cfg_cie;
+
+ A2D_TRACE_API("%s", __func__);
+
+ /* parse configuration */
+ if ((status = A2D_ParsAptxInfo(&cfg_cie, p_cfg, FALSE)) != 0)
+ {
+ A2D_TRACE_ERROR("%s:, aptx parse failed", __func__);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ /* sampling frequency */
+ if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0)
+ status = A2D_NS_SAMP_FREQ;
+ /* channel mode */
+ else if ((cfg_cie.channelMode & p_cap->channelMode) == 0)
+ status = A2D_NS_CH_MODE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function A2D_check_and_init_aptX
+**
+** Description This function checks if all the libraries required for
+** aptX are present and needed function pointers are resolved
+**
+** Returns returns true if aptX codec initialization succeeds
+**
+*******************************************************************************/
+BOOLEAN A2D_check_and_init_aptX(void)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+
+ if (A2dAptXSchedLibHandle == NULL)
+ {
+ A2dAptXSchedLibHandle = dlopen(A2D_APTX_SCHED_LIB_NAME, RTLD_NOW);
+
+ if (!A2dAptXSchedLibHandle)
+ {
+ A2D_TRACE_ERROR("%s: aptX scheduler library missing", __func__);
+ goto error_exit;
+ }
+
+ A2D_aptx_encoder_init = (int (*)(void))dlsym(A2dAptXSchedLibHandle,
+ "aptx_encoder_init");
+ if (!A2D_aptx_encoder_init)
+ {
+ A2D_TRACE_ERROR("%s: aptX encoder init missing", __func__);
+ goto error_exit;
+ }
+
+ A2D_aptx_sched_start = (A2D_AptXThreadFn (*)(void*, A2D_AptXCodecType, BOOLEAN,
+ BOOLEAN, UINT16, UINT8, UINT8, UINT16, A2D_AptXReadFn,
+ A2D_AptXBufferSendFn,
+ A2D_AptXSetPriorityFn, BOOLEAN,
+ BOOLEAN))dlsym(A2dAptXSchedLibHandle,
+ "aptx_scheduler_start");
+
+ if (!A2D_aptx_sched_start)
+ {
+ A2D_TRACE_ERROR("%s: aptX scheduler start missing", __func__);
+ goto error_exit;
+ }
+
+ A2D_aptx_sched_stop = (BOOLEAN (*)(void))dlsym(A2dAptXSchedLibHandle,
+ "aptx_scheduler_stop");
+ if (!A2D_aptx_sched_stop)
+ {
+ A2D_TRACE_ERROR("%s: aptX scheduler stop missing", __func__);
+ goto error_exit;
+ }
+
+ A2D_aptx_encoder_deinit = (void (*)(void))dlsym(A2dAptXSchedLibHandle,
+ "aptx_encoder_deinit");
+ if (!A2D_aptx_encoder_deinit)
+ {
+ A2D_TRACE_ERROR("%s: aptX encoder deinit missing ", __func__);
+ goto error_exit;
+ }
+
+ if (A2D_aptx_encoder_init())
+ {
+ A2D_TRACE_ERROR("%s: aptX encoder init failed - %s", __func__, dlerror());
+ goto error_exit;
+ }
+ }
+ isA2dAptXEnabled = true;
+ return isA2dAptXEnabled;
+
+ error_exit:;
+ if (A2dAptXSchedLibHandle)
+ {
+ dlclose(A2dAptXSchedLibHandle);
+ A2dAptXSchedLibHandle = NULL;
+ }
+ isA2dAptXEnabled = false;
+ return isA2dAptXEnabled;
+
+}
+
+/*******************************************************************************
+**
+** Function A2D_start_aptX
+**
+** Description This function Start aptX
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void A2D_start_aptX(void *encoder, A2D_AptXCodecType aptX_codec_type,
+ BOOLEAN use_SCMS_T, BOOLEAN is_24bit_audio,
+ UINT16 sample_rate, UINT8 format_bits,
+ UINT8 channel, UINT16 MTU, A2D_AptXReadFn read_fn,
+ A2D_AptXBufferSendFn send_fn,
+ A2D_AptXSetPriorityFn set_priority_fn,
+ BOOLEAN test, BOOLEAN trace)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+ mutex_global_lock();
+
+ A2d_aptx_thread_fn = A2D_aptx_sched_start (encoder, aptX_codec_type,
+ use_SCMS_T, is_24bit_audio, sample_rate, format_bits,
+ channel, MTU, read_fn, send_fn, set_priority_fn, test, trace);
+
+ A2d_aptx_thread = thread_new("aptx_media_worker");
+ if (A2d_aptx_thread)
+ {
+ thread_post(A2d_aptx_thread, A2d_aptx_thread_fn, NULL);
+ }
+
+ mutex_global_unlock();
+ return;
+}
+
+
+
+/*******************************************************************************
+**
+** Function A2D_deinit_aptX
+**
+** Description This function de-initialized aptX
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void A2D_deinit_aptX(void)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+
+ if (isA2dAptXEnabled && A2dAptXSchedLibHandle)
+ {
+ A2D_aptx_encoder_deinit();
+ isA2dAptXEnabled = false;
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function A2D_stop_aptX
+**
+** Description This function remove aptX thread
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void A2D_stop_aptX(void)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+ mutex_global_lock();
+ if (A2dAptXSchedLibHandle)
+ {
+ // remove aptX thread
+ if (A2d_aptx_thread)
+ {
+ A2D_aptx_sched_stop();
+ thread_free(A2d_aptx_thread);
+ A2d_aptx_thread = NULL;
+ }
+ }
+ mutex_global_unlock();
+ return;
+}
+/*******************************************************************************
+**
+** Function A2D_close_aptX
+**
+** Description This function close aptX
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void A2D_close_aptX(void)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+
+ // remove aptX thread
+ A2D_stop_aptX();
+
+ // de-initialize aptX HD
+ A2D_deinit_aptX_HD();
+
+ // de-initialize aptX
+ A2D_deinit_aptX();
+
+ if (A2dAptXSchedLibHandle)
+ {
+ dlclose(A2dAptXSchedLibHandle);
+ A2dAptXSchedLibHandle = NULL;
+ }
+
+ return;
+}
diff --git a/stack/a2dp/a2d_aptx_hd.c b/stack/a2dp/a2d_aptx_hd.c
new file mode 100644
index 0000000..ee6d65e
--- /dev/null
+++ b/stack/a2dp/a2d_aptx_hd.c
@@ -0,0 +1,251 @@
+/******************************************************************************
+
+ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ******************************************************************************/
+/******************************************************************************
+
+ Utility functions to help build and parse the aptX HD Codec Information
+ Element and Media Payload.
+
+******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include <dlfcn.h>
+#include "osi/include/thread.h"
+#include "bt_utils.h"
+#include "a2d_api.h"
+#include "a2d_int.h"
+#include "a2d_aptx.h"
+#include "a2d_aptx_hd.h"
+#include <utils/Log.h>
+
+
+BOOLEAN isA2dAptXHdEnabled = FALSE;
+
+int (*A2D_aptx_hd_encoder_init)(void);
+void (*A2D_aptx_hd_encoder_deinit)(void);
+
+/******************************************************************************
+**
+** Function A2D_BldAptx_hdInfo
+**
+******************************************************************************/
+UINT8 A2D_BldAptx_hdInfo(UINT8 media_type, tA2D_APTX_HD_CIE *p_ie, UINT8 *p_result)
+{
+ A2D_TRACE_API("%s: - MediaType:%d", __func__, media_type);
+
+ UINT8 status = 0;
+ status = A2D_SUCCESS;
+ *p_result++ = A2D_APTX_HD_CODEC_LEN;
+ *p_result++ = media_type;
+ *p_result++ = A2D_NON_A2DP_MEDIA_CT;
+ *p_result++ = (UINT8)(p_ie->vendorId & 0x000000FF);
+ *p_result++ = (UINT8)(p_ie->vendorId & 0x0000FF00)>> 8;
+ *p_result++ = (UINT8)(p_ie->vendorId & 0x00FF0000)>> 16;
+ *p_result++ = (UINT8)(p_ie->vendorId & 0xFF000000)>> 24;
+ *p_result++ = (UINT8)(p_ie->codecId & 0x00FF);
+ *p_result++ = (UINT8)(p_ie->codecId & 0xFF00) >> 8;
+ *p_result++ = p_ie->sampleRate | p_ie->channelMode;
+ *p_result++ = p_ie->acl_sprint_reserved0;
+ *p_result++ = p_ie->acl_sprint_reserved1;
+ *p_result++ = p_ie->acl_sprint_reserved2;
+ *p_result++ = p_ie->acl_sprint_reserved3;
+ return status;
+}
+
+/******************************************************************************
+**
+** Function A2D_ParsAptx_hdInfo
+**
+******************************************************************************/
+tA2D_STATUS A2D_ParsAptx_hdInfo(tA2D_APTX_HD_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
+{
+ tA2D_STATUS status;
+ UINT8 losc;
+ UINT8 mt;
+
+ A2D_TRACE_API("%s: - MediaType:%d", __func__, for_caps);
+
+ if (p_ie == NULL || p_info == NULL)
+ {
+ A2D_TRACE_ERROR("A2D_ParsAptx_hdInfo - Invalid Params");
+ status = A2D_INVALID_PARAMS;
+ }
+ else
+ {
+ losc = *p_info++;
+ mt = *p_info++;
+ A2D_TRACE_DEBUG("%s: losc %d, mt %02x", __func__, losc, mt);
+
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ if (losc != A2D_APTX_HD_CODEC_LEN || *p_info != A2D_NON_A2DP_MEDIA_CT) {
+ A2D_TRACE_ERROR("%s: wrong media type %02x", __func__, *p_info);
+ status = A2D_WRONG_CODEC;
+ }
+ else
+ {
+ p_info++;
+ p_ie->vendorId = (*p_info & 0x000000FF) |
+ (*(p_info+1) << 8 & 0x0000FF00) |
+ (*(p_info+2) << 16 & 0x00FF0000) |
+ (*(p_info+3) << 24 & 0xFF000000);
+ p_info = p_info+4;
+ p_ie->codecId = (*p_info & 0x00FF) | (*(p_info+1) << 8 & 0xFF00);
+ p_info = p_info+2;
+ p_ie->channelMode= *p_info & 0x0F;
+ p_ie->sampleRate = *p_info & 0xF0;
+ p_info = p_info+1;
+ p_ie->acl_sprint_reserved0 = *(p_info ++);
+ p_ie->acl_sprint_reserved1 = *(p_info ++);
+ p_ie->acl_sprint_reserved2 = *(p_info ++);
+ p_ie->acl_sprint_reserved3 = *(p_info ++);
+
+ status = A2D_SUCCESS;
+
+ if (for_caps == FALSE)
+ {
+ if (A2D_BitsSet(p_ie->sampleRate) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_SAMP_FREQ;
+ if (A2D_BitsSet(p_ie->channelMode) != A2D_SET_ONE_BIT)
+ status = A2D_BAD_CH_MODE;
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function a2d_av_aptx_hd_cfg_in_cap
+**
+** Description This function checks whether an aptX HD codec configuration
+** is allowable for the given codec capabilities.
+**
+** Returns 0 if ok, nonzero if error.
+**
+*******************************************************************************/
+UINT8 a2d_av_aptx_hd_cfg_in_cap(UINT8 *p_cfg, tA2D_APTX_HD_CIE *p_cap)
+{
+ UINT8 status = 0;
+ tA2D_APTX_HD_CIE cfg_cie;
+
+ A2D_TRACE_API("%s", __func__);
+
+ /* parse configuration */
+ if ((status = A2D_ParsAptx_hdInfo(&cfg_cie, p_cfg, FALSE)) != 0)
+ {
+ A2D_TRACE_ERROR("%s: aptX HD parse failed", __func__);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ /* sampling frequency */
+ if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0)
+ status = A2D_NS_SAMP_FREQ;
+ /* channel mode */
+ else if ((cfg_cie.channelMode & p_cap->channelMode) == 0)
+ status = A2D_NS_CH_MODE;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function A2D_check_and_init_aptX_HD
+**
+** Description This function checks if all the libraries required for
+** aptX HD are present and needed function pointers are resolved
+**
+** Returns returns true if aptX HD codec initialization succeeds
+**
+*******************************************************************************/
+BOOLEAN A2D_check_and_init_aptX_HD(void)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+
+ if (isA2dAptXEnabled && A2dAptXSchedLibHandle)
+ {
+ A2D_aptx_hd_encoder_init = (int (*)(void))dlsym(A2dAptXSchedLibHandle,
+ "aptx_hd_encoder_init");
+ if (!A2D_aptx_hd_encoder_init)
+ {
+ A2D_TRACE_ERROR("%s: aptX HD encoder init missing", __func__);
+ goto error_exit;
+ }
+
+ A2D_aptx_hd_encoder_deinit = (void (*)(void))dlsym(A2dAptXSchedLibHandle,
+ "aptx_hd_encoder_deinit");
+ if (!A2D_aptx_hd_encoder_deinit)
+ {
+ A2D_TRACE_ERROR("%s: aptX HD encoder deinit missing", __func__);
+ goto error_exit;
+ }
+
+ if (A2D_aptx_hd_encoder_init())
+ {
+ A2D_TRACE_ERROR("%s: aptX HD encoder init failed - %s", __func__, dlerror());
+ goto error_exit;
+ }
+ } else {
+ A2D_TRACE_ERROR("%s: isA2dAptXEnabled = false", __func__);
+ goto error_exit;
+ }
+ isA2dAptXHdEnabled = true;
+ return isA2dAptXHdEnabled;
+
+ error_exit:;
+ isA2dAptXHdEnabled = false;
+ return isA2dAptXHdEnabled;
+
+}
+
+/*******************************************************************************
+**
+** Function A2D_deinit_aptX_HD
+**
+** Description This function de-initialized aptX HD
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void A2D_deinit_aptX_HD(void)
+{
+ A2D_TRACE_DEBUG("%s", __func__);
+
+ if (isA2dAptXHdEnabled && isA2dAptXEnabled && A2dAptXSchedLibHandle)
+ {
+ A2D_aptx_hd_encoder_deinit();
+ isA2dAptXHdEnabled = false;
+ }
+
+ return;
+}
diff --git a/stack/a2dp/a2d_int.h b/stack/a2dp/a2d_int.h
index d4bb4c2..c65127e 100644
--- a/stack/a2dp/a2d_int.h
+++ b/stack/a2dp/a2d_int.h
@@ -75,6 +75,9 @@
/* Used only for conformance testing */
extern void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver);
+/* Used to check local version of AVDTP */
+extern int a2d_get_avdt_sdp_ver ();
+
#ifdef __cplusplus
}
#endif
diff --git a/stack/avct/avct_api.c b/stack/avct/avct_api.c
index 60647a5..df5615d 100644
--- a/stack/avct/avct_api.c
+++ b/stack/avct/avct_api.c
@@ -38,6 +38,31 @@
tAVCT_CB avct_cb;
#endif
+
+/*******************************************************************************
+**
+** Function AVCT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Init(void)
+{
+ /* initialize AVCTP data structures */
+ memset(&avct_cb, 0, sizeof(tAVCT_CB));
+
+#if defined(AVCT_INITIAL_TRACE_LEVEL)
+ avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
+#else
+ avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
/*******************************************************************************
**
** Function AVCT_Register
@@ -80,12 +105,6 @@
avct_cb.mtu_br = mtu_br;
#endif
-#if defined(AVCT_INITIAL_TRACE_LEVEL)
- avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
-#else
- avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
-#endif
-
if (mtu < AVCT_MIN_CONTROL_MTU)
mtu = AVCT_MIN_CONTROL_MTU;
/* store mtu */
@@ -112,6 +131,9 @@
/* deregister PSM with L2CAP */
L2CA_Deregister(AVCT_PSM);
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+ L2CA_Deregister(AVCT_BR_PSM);
+#endif
}
/*******************************************************************************
@@ -458,7 +480,13 @@
else
{
p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
- avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ if (p_ccb->p_bcb)
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+ else
+ {
+ result = AVCT_BAD_HANDLE;
+ osi_free(p_msg);
+ }
}
}
/* send msg event to lcb */
@@ -471,3 +499,55 @@
return result;
}
+/*******************************************************************************
+**
+** Function AVCT_CheckIncomingConn
+**
+** Description Check for incoming connection in progress
+**
+** Return TRUE if incoming connection in progress, FALSE otherwise
+******************************************************************************/
+BOOLEAN AVCT_CheckIncomingConn(BD_ADDR peer_addr)
+{
+ tAVCT_LCB *p_lcb;
+
+ p_lcb = avct_lcb_by_bd(peer_addr);
+ if (p_lcb != NULL)
+ {
+ if (p_lcb->ch_state != AVCT_CH_IDLE)
+ {
+ AVCT_TRACE_ERROR("%s: Incoming AVCT connection in progress",__func__);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+/******************************************************************************
+**
+** Function AVCT_SetTraceLevel
+**
+** Description Sets the trace level for AVCT. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVCT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVCT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ avct_cb.trace_level = new_level;
+
+ return (avct_cb.trace_level);
+}
+
diff --git a/stack/avct/avct_ccb.c b/stack/avct/avct_ccb.c
index e0f87de..11c45db 100644
--- a/stack/avct/avct_ccb.c
+++ b/stack/avct/avct_ccb.c
@@ -88,6 +88,7 @@
/* control channel is down, but the browsing channel is still connected 0 disconnect it now */
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
p_ccb->p_lcb = NULL;
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
}
#else
memset(p_ccb, 0, sizeof(tAVCT_CCB));
@@ -148,3 +149,41 @@
}
return p_ccb;
}
+
+
+/*******************************************************************************
+**
+** Function avct_get_peer_addr_by_ccb
+**
+** Description Return peer BD address on ccb index (or handle).
+**
+**
+** Returns BD Address.
+**
+*******************************************************************************/
+BOOLEAN avct_get_peer_addr_by_ccb (UINT8 idx, BD_ADDR addr)
+{
+ tAVCT_CCB *p_ccb;
+ BOOLEAN value = FALSE;
+ p_ccb = avct_ccb_by_idx(idx);
+ if (p_ccb == NULL)
+ {
+ AVCT_TRACE_WARNING("No ccb for idx %d", idx);
+ }
+ else
+ {
+ if (p_ccb->p_lcb != NULL)
+ {
+ memcpy(addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN);
+ value = TRUE;
+ }
+ else
+ {
+ AVCT_TRACE_WARNING("No lcb for idx %d", idx);
+ }
+ }
+ return value;
+}
+
+
+
diff --git a/stack/avct/avct_int.h b/stack/avct/avct_int.h
index 4f1705c..4f32e21 100644
--- a/stack/avct/avct_int.h
+++ b/stack/avct/avct_int.h
@@ -97,6 +97,8 @@
UINT8 ch_flags; /* L2CAP configuration flags */
BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */
+ fixed_queue_t *tx_q; /* Transmit data buffer queue */
+ BOOLEAN cong; /* TRUE, if congested */
} tAVCT_BCB;
#define AVCT_ALOC_LCB 0x01
diff --git a/stack/avct/avct_l2c.c b/stack/avct/avct_l2c.c
index ab91d7a..4ae2f65 100644
--- a/stack/avct/avct_l2c.c
+++ b/stack/avct/avct_l2c.c
@@ -35,6 +35,13 @@
#define AVCT_L2C_CFG_IND_DONE (1<<0)
#define AVCT_L2C_CFG_CFM_DONE (1<<1)
+/*L2CAP Browsing Parameter */
+#define AVCT_L2C_TX_WINDOW_SIZE 1
+#define AVCT_L2C_MAX_TRANSMISSION 20
+#define AVCT_L2C_RETRANS_TIMEOUT 2000
+#define AVCT_L2C_MONITOR_TIMEOUT 12000
+#define AVCT_L2C_MPS_SEGMENT_SIZE 1000
+
/* callback function declarations */
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
@@ -45,6 +52,19 @@
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def =
+{
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for Browsing */
+ AVCT_L2C_TX_WINDOW_SIZE, /* Tx window size to be #define in bt_target.h*/
+ AVCT_L2C_MAX_TRANSMISSION, /* Maximum transmissions before disconnecting */
+ AVCT_L2C_RETRANS_TIMEOUT, /* Retransmission timeout (2 secs) */
+ AVCT_L2C_MONITOR_TIMEOUT, /* Monitor timeout (12 secs) */
+ AVCT_L2C_MPS_SEGMENT_SIZE /* MPS segment size */
+};
+#endif
+
+
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avct_l2c_appl = {
avct_l2c_connect_ind_cback,
@@ -60,6 +80,36 @@
NULL /* tL2CA_TX_COMPLETE_CB */
};
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/* L2CAP Callback function for Browsing AVRCP 1.4 structure */
+
+/* callback function declarations */
+/* callback function declarations */
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
+void avct_l2c_br_connect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_br_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
+void avct_l2c_br_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
+void avct_l2c_br_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
+void avct_l2c_br_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
+
+
+
+const tL2CAP_APPL_INFO avct_l2c_br_appl = {
+ avct_l2c_br_connect_ind_cback,
+ avct_l2c_br_connect_cfm_cback,
+ NULL,
+ avct_l2c_br_config_ind_cback,
+ avct_l2c_br_config_cfm_cback,
+ avct_l2c_br_disconnect_ind_cback,
+ avct_l2c_br_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_br_data_ind_cback,
+ avct_l2c_br_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+#endif
/*******************************************************************************
**
** Function avct_l2c_is_passive
@@ -165,6 +215,113 @@
#endif
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_l2c_br_connect_ind_cback
+**
+** Description This is the L2CAP connect indication callback function.
+**
+** Return void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+ tAVCT_BCB *p_bcb = &avct_cb.bcb[0] ;
+ tAVCT_LCB *p_lcb = NULL;
+ UINT16 result = L2CAP_CONN_OK;
+ tL2CAP_ERTM_INFO ertm_info;
+ tL2CAP_ERTM_INFO *p_ertm_info = NULL;
+ tL2CAP_CFG_INFO cfg;
+ UINT8 index;
+
+ AVCT_TRACE_DEBUG("avct_l2c_br_connect_ind_cback lcid:%x, psm:%x, id:%x",
+ lcid , psm , id);
+
+ /*Check for associated lcb*/
+ if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
+ {
+ AVCT_TRACE_ERROR("### LCB not found");
+ result = L2CAP_CONN_NO_RESOURCES;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+ }
+ else
+ {
+ /* We will only support one browsing connection.
+ * Second incoming BR conn is rejected.*/
+ for (index = 0; index < AVCT_NUM_LINKS; index++)
+ {
+ p_bcb = &avct_cb.bcb[index];
+ if (p_bcb && p_bcb->allocated)
+ {
+ AVCT_TRACE_ERROR("Browsing already connected to other device");
+ AVCT_TRACE_ERROR("Reject Browsing connection:%d", p_bcb->allocated);
+ result = L2CAP_CONN_NO_RESOURCES;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, &ertm_info);
+ return;
+ }
+ }
+ index = (UINT8) (p_lcb - &avct_cb.lcb[0]); //calculate offset.
+ AVCT_TRACE_DEBUG("index value = %d",index);
+ p_bcb = &avct_cb.bcb[index];
+ if (p_bcb == NULL)
+ {
+ /*Disconnect as browsing channel = NULL */
+ AVCT_TRACE_ERROR("### BCB NULL");
+ result = L2CAP_CONN_NO_RESOURCES;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, &ertm_info);
+ }
+ else
+ {
+ p_bcb->allocated = index +1 ;
+ for (index = 0; index < AVCT_NUM_CONN; ++index)
+ {
+ if (avct_cb.ccb[index].p_lcb == p_lcb)
+ {
+ AVCT_TRACE_ERROR("index value = %d",index);
+ avct_cb.ccb[index].p_bcb = p_bcb ;
+ avct_cb.ccb[index].allocated = AVCT_ALOC_BCB ;
+ }
+
+ }
+ AVCT_TRACE_DEBUG("Channel RSP");
+ p_bcb->ch_lcid = lcid; /*Updadate LCID so that on config associated bcb could be found*/
+ ertm_info.preferred_mode = L2CAP_FCR_ERTM_MODE;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_buf_size = AVCT_BR_USER_RX_BUF_SIZE;
+ ertm_info.user_tx_buf_size = AVCT_BR_USER_TX_BUF_SIZE;
+ ertm_info.fcr_rx_buf_size = AVCT_BR_FCR_RX_BUF_SIZE;
+ ertm_info.fcr_tx_buf_size = AVCT_BR_FCR_TX_BUF_SIZE;
+ p_ertm_info = &ertm_info;
+ L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+ }
+ /*Send L2CAP Channel Rsp if result = ok
+ * proceed with connection
+ */
+ if (result == L2CAP_CONN_OK)
+ {
+ /* transition to configuration state */
+ p_bcb->ch_state = AVCT_CH_CFG;
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = TRUE;
+ cfg.mtu = avct_cb.mtu_br; //As per initial config it's 1008
+ cfg.fcr_present = TRUE;
+ memcpy(&cfg.fcr, &avct_l2c_br_fcr_opts_def, sizeof (tL2CAP_FCR_OPTS));
+ /*Send Configue Request*/
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG("Browse Channel mtu size = %d",cfg.mtu);
+ }
+ // Send L2CAP Config Rsp
+ }
+
+#if (BT_USE_TRACES == TRUE)
+ if (p_bcb)
+ AVCT_TRACE_DEBUG("ch_state cni: %d ", p_bcb->ch_state);
+#endif
+}
+
+#endif
/*******************************************************************************
**
** Function avct_l2c_connect_cfm_cback
@@ -226,6 +383,21 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/********************************************************************************
+** Function avct_l2c_br_connect_cfm_cback
+** Description Function is not expected to be called
+** as browsing is initiated by remote device.
+**
+*********************************************************************************/
+
+void avct_l2c_br_connect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ AVCT_TRACE_ERROR("avct_l2c_br_connect_cfm_cback %x: lcid , %x: result", lcid, result );
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_l2c_config_cfm_cback
@@ -264,7 +436,7 @@
/* else failure */
else
{
- AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
+ AVCT_TRACE_ERROR("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq = %d ", p_lcb->ch_state);
/* store result value */
p_lcb->ch_result = p_cfg->result;
@@ -276,6 +448,66 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*************************************************************************
+** Function : avct_l2c_br_config_cfm_cback
+**
+** Description: This is the L2CAP config confirm callback function.
+**
+**
+** Returns void
+**
+*************************************************************************/
+
+void avct_l2c_br_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO * p_cfg)
+{
+ tAVCT_BCB *p_bcb;
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_cfm_cback lcid : %x",lcid);
+
+ /*lookup for bcb channel, for given lcid there
+ * should be a bcb associated
+ */
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_cfm_cback: 0x%x, ch_state: %d, res: %d, ch_flags",
+ lcid, p_bcb->ch_state, p_cfg->result ,p_bcb->ch_flags );
+ AVCT_TRACE_DEBUG("MTU :%x ",p_cfg->mtu);
+ /*Check for the state , it should be in config*/
+ if (p_bcb->ch_state == AVCT_CH_CFG)
+ {
+ /*Check for remote l2cap response */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ /*Update BCB ch_flags ,either IND_DONE , CFM_DONE */
+ p_bcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+ /* Check for Configuraiton Flag , if configuration complete*/
+ if (p_bcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+ {
+ p_bcb->ch_state = AVCT_CH_OPEN;
+ p_bcb->state = 0;
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /*IF L2CAP response result is != L2CAP_CFG_OK*/
+ else
+ {
+ AVCT_TRACE_ERROR("###config_cfm_cback error, ch_state:%d ", p_bcb->ch_state);
+ /* store result value */
+ p_bcb->ch_result = p_cfg->result;
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_bcb->ch_state);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### BCB NULL");
+ L2CA_DisconnectReq(lcid);
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_config_ind_cback
@@ -324,8 +556,71 @@
}
AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
}
+ else
+ {
+ AVCT_TRACE_ERROR("%s: p_lcb is null",__func__);
+ L2CA_DisconnectReq(lcid);
+ }
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/**************************************************************************
+** Function : avct_l2c_config_ind_cback
+**
+** Description: This is the L2CAP config indication callback function.
+**
+**
+** Returns: void
+**
+****************************************************************************/
+void avct_l2c_br_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tAVCT_BCB *p_bcb;
+
+ AVCT_TRACE_DEBUG("config_ind_cback tx_win_sz:%x, max_transmit:%x, rtrans:%x,mon_tout : %x",p_cfg->fcr.tx_win_sz ,\
+ p_cfg->fcr.max_transmit , p_cfg->fcr.rtrans_tout , p_cfg->fcr.mon_tout);
+
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_ind_cback: 0x%x, ch_state: %d", lcid, p_bcb->ch_state);
+ /* store the mtu in tbl Start from here */
+ AVCT_TRACE_DEBUG("avct_l2c_br_config_ind_cback mtu_present: 0x%x, peer mtu: %d", p_cfg->mtu_present, p_cfg->mtu);
+ if (p_cfg->mtu_present)
+ {
+ AVCT_TRACE_DEBUG("PEER MTU: 0x%x", p_bcb->peer_mtu);
+ p_bcb->peer_mtu = p_cfg->mtu;
+ }
+ else
+ {
+ p_bcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+ /* if first config ind */
+ if ((p_bcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+ {
+ /* update flags */
+ p_bcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_bcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+ {
+ p_bcb->ch_state = AVCT_CH_OPEN;
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_bcb->ch_state);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### BCB= NULL");
+ L2CA_DisconnectReq(lcid);
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_disconnect_ind_cback
@@ -356,6 +651,40 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/********************************************************************************************
+** Function: avct_l2c_br_disconnect_ind_cback
+**
+** Description: This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns void
+**
+********************************************************************************************/
+void avct_l2c_br_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
+{
+ tAVCT_BCB *p_bcb;
+ UINT16 result = AVCT_RESULT_FAIL;
+ AVCT_TRACE_DEBUG("avct_l2c_br_disconnect_ind_cback lcid : %d ", lcid);
+ //Lookup BCB for this event
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d",\
+ lcid, p_bcb->ch_state);
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("###BCB NULL");
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_disconnect_cfm_cback
@@ -385,6 +714,32 @@
}
}
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*********************************************************************************
+**
+** Function avct_l2c_br_disconnect_cfm_cback
+**
+** Description This is the L2CAP disconnect Confirmation callback function
+**
+**
+** Returns Void
+**
+***********************************************************************************/
+void avct_l2c_br_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
+{
+ tAVCT_BCB *p_bcb;
+ AVCT_TRACE_DEBUG("avct_l2c_br_disconnect_cfm_cback lcid : %d ", lcid);
+
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_bcb->ch_state, result);
+ p_bcb->ch_result = 0;
+ }
+}
+
+#endif
/*******************************************************************************
**
** Function avct_l2c_congestion_ind_cback
@@ -407,6 +762,34 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+
+/*********************************************************************************
+** Function avct_l2c_br_congestion_ind_cback
+**
+** Description This is the L2CAP congestion indication callback function.
+**
+** Returns void
+****************************************************************************/
+void avct_l2c_br_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
+{
+ tAVCT_BCB *p_bcb = NULL;
+ AVCT_TRACE_DEBUG("avct_l2c_br_congestion_ind_cback lcid:%d, congestion:%d",
+ lcid,is_congested);
+
+ /* look up for Browse Control Block for this channel */
+ p_bcb = avct_bcb_by_lcid(lcid);
+ if (p_bcb != NULL)
+ {
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### No BCB associated with lcid");
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_l2c_data_ind_cback
@@ -434,3 +817,32 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*****************************************************************************
+**
+** Function avct_l2c_br_data_ind_cback
+**
+** Description This is the L2CAP data indication callback function.
+**
+** Returns void
+**
+*****************************************************************************/
+void avct_l2c_br_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
+{
+ tAVCT_BCB *p_bcb;
+
+ AVCT_TRACE_DEBUG("avct_l2c_br_data_ind_cback lcid : %d ", lcid);
+ AVCT_TRACE_DEBUG("BT_HDR event: %x , len: %x , offset: %x, layer_spec: %x ", p_buf->event,
+ p_buf->len,p_buf->offset , p_buf->layer_specific );
+ if ((p_bcb = avct_bcb_by_lcid(lcid)) != NULL)
+ {
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+ }
+ else /* prevent buffer leak */
+ {
+ AVCT_TRACE_WARNING("avct_l2c_br_data_ind_cback drop buffer");
+ osi_free_and_reset((void**)&p_buf);
+ }
+
+}
+#endif
diff --git a/stack/avct/avct_lcb.c b/stack/avct/avct_lcb.c
index 2f01548..364b15b 100644
--- a/stack/avct/avct_lcb.c
+++ b/stack/avct/avct_lcb.c
@@ -37,6 +37,7 @@
#if BT_TRACE_VERBOSE == TRUE
+
/* verbose state strings for trace */
const char * const avct_lcb_st_str[] = {
"LCB_IDLE_ST",
@@ -113,6 +114,27 @@
avct_lcb_free_msg_ind
};
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+const tAVCT_BCB_ACTION avct_bcb_action[] = {
+ avct_bcb_chnl_open,
+ avct_bcb_chnl_disc,
+ avct_bcb_send_msg,
+ avct_bcb_open_ind,
+ avct_bcb_open_fail,
+ avct_bcb_close_ind,
+ avct_bcb_close_cfm,
+ avct_bcb_msg_ind,
+ avct_bcb_cong_ind,
+ avct_bcb_bind_conn,
+ avct_bcb_bind_fail,
+ avct_bcb_unbind_disc,
+ avct_bcb_chk_disc,
+ avct_bcb_discard_msg,
+ avct_bcb_dealloc,
+ avct_bcb_free_msg_ind
+};
+#endif
+
/* state table information */
#define AVCT_LCB_ACTIONS 2 /* number of actions */
#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
@@ -198,9 +220,9 @@
int i;
#if BT_TRACE_VERBOSE == TRUE
- AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
+ BTIF_TRACE_IMP("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
#else
- AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
+ BTIF_TRACE_IMP("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
#endif
/* look up the state table for the current state */
@@ -212,7 +234,7 @@
/* execute action functions */
for (i = 0; i < AVCT_LCB_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ if ((action = state_table[event][i]) < AVCT_LCB_IGNORE)
{
(*avct_lcb_action[action])(p_lcb, p_data);
}
@@ -241,9 +263,9 @@
int i;
#if BT_TRACE_VERBOSE == TRUE
- AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
+ BTIF_TRACE_IMP("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
#else
- AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
+ BTIF_TRACE_IMP("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
#endif
/* look up the state table for the current state */
@@ -255,7 +277,7 @@
/* execute action functions */
for (i = 0; i < AVCT_LCB_ACTIONS; i++)
{
- if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+ if ((action = state_table[event][i]) < AVCT_LCB_IGNORE)
{
(*avct_bcb_action[action])(p_bcb, p_data);
}
@@ -302,6 +324,55 @@
return p_lcb;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*****************************************************************************
+**
+** Function avct_bcb_by_lcb
+**
+** Description This function finds bcb associated to a lcb
+**
+** Returns pointer to the bcb , or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb)
+{
+ int i;
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_by_lcb %d , ccb ", p_ccb->allocated);
+ if ( p_ccb->p_lcb == p_lcb )
+ {
+ return avct_cb.ccb[i].p_bcb;
+ }
+ }
+ AVCT_TRACE_ERROR("###avct_bcb_by_lcb ERROR");
+ return NULL ;
+}
+
+/*****************************************************************************
+**
+** Function avct_lcb_by_bcb
+**
+** Description This
+**
+** Returns pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ for (i = 0; i < AVCT_NUM_CONN; i++)
+ {
+ AVCT_TRACE_DEBUG("avct_lcb_alloc= %d", p_bcb->allocated);
+ if(p_ccb[i].allocated && p_ccb[i].p_bcb == p_bcb)
+ return avct_cb.ccb[i].p_lcb;
+ }
+ AVCT_TRACE_ERROR("###avct_lcb_by_bcb ERROR");
+ return NULL ;
+}
+#endif
/*******************************************************************************
**
** Function avct_lcb_alloc
@@ -374,6 +445,55 @@
memset(p_lcb, 0, sizeof(tAVCT_LCB));
}
+#if AVCT_BROWSE_INCLUDED
+
+/*******************************************************************************
+**
+** Function avct_bcb_dealloc
+**
+** Description Deallocate a browse control block.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ BOOLEAN found = FALSE;
+ int i;
+
+ if (p_bcb != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_dealloc %d", p_bcb->allocated);
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ /* if ccb allocated and */
+ if (p_ccb->allocated)
+ {
+ if (p_ccb->p_bcb == p_bcb)
+ {
+ AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_dealloc now");
+ memset(p_bcb, 0, sizeof(tAVCT_BCB));
+ }
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### dealloc Null bcb");
+ }
+
+}
+
+#endif
/*******************************************************************************
**
** Function avct_lcb_by_lcid
@@ -407,6 +527,41 @@
return p_lcb;
}
+#if AVCT_BROWSE_INCLUDED
+/******************************************************************************
+**
+** Function avct_bcb_by_lcid(UINT16 lcid);
+**
+** Description Find the BCB associated with the L2CAP LCID
+**
+** Return pointer to browse control block
+**
+*******************************************************************************/
+
+tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid)
+{
+ AVCT_TRACE_DEBUG("avct_bcb_by_lcid :=%x",lcid);
+ tAVCT_BCB *p_bcb = &avct_cb.bcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_bcb++)
+ {
+ if (p_bcb->allocated && ((p_bcb->ch_lcid == lcid)))
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_by_lcid :=%x",p_bcb->ch_lcid);
+ break;
+ }
+ }
+ if (i == AVCT_NUM_LINKS)
+ {
+ /*out of bcbs */
+ p_bcb = NULL;
+ AVCT_TRACE_WARNING("###No bcb for lcid %x", lcid);
+ }
+ return p_bcb;
+}
+
+#endif
/*******************************************************************************
**
** Function avct_lcb_has_pid
@@ -426,9 +581,11 @@
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
{
+ AVCT_TRACE_DEBUG("avct_lcb_has_pid, found");
return p_ccb;
}
}
+ AVCT_TRACE_WARNING("avct_lcb_has_pid, not found");
return NULL;
}
diff --git a/stack/avct/avct_lcb_act.c b/stack/avct/avct_lcb_act.c
index c927622..878dd82 100644
--- a/stack/avct/avct_lcb_act.c
+++ b/stack/avct/avct_lcb_act.c
@@ -168,6 +168,60 @@
return p_ret;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function avct_bcb_msg_asmbl
+**
+** Description Reassemble incoming message.
+**
+**
+** Returns Pointer to reassembled message; NULL if no message
+** available.
+**
+*******************************************************************************/
+static BT_HDR *avct_bcb_msg_asmbl(tAVCT_BCB *p_bcb, BT_HDR *p_buf)
+{
+ UINT8 *p;
+ UINT8 pkt_type;
+ BT_HDR *p_ret;
+
+ /* parse the message header */
+ AVCT_TRACE_DEBUG("bcb_msg_asmbl peer_mtu:%x, ch_lcid:%x",p_bcb->peer_mtu, \
+ p_bcb->ch_lcid);
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_PRS_PKT_TYPE(p, pkt_type);
+ AVCT_TRACE_DEBUG("bcb_msg_asmbl pkt_type:%d, p_buf->offset:%x",pkt_type, \
+ p_buf->offset);
+ /* quick sanity check on length */
+ if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
+ {
+ osi_free_and_reset((void**)&p_buf);
+ AVCT_TRACE_WARNING("### Bad length during reassembly");
+ p_ret = NULL;
+ }
+
+ /* As Per AVRCP 1.5 Spec,Fragmentation is not allowed
+ * Section 7.2 AVCTP fragmentation shall not be used on the AVCTP Browsing Channel.
+ * packet type wil be single else return error
+ */
+ else if (pkt_type == AVCT_PKT_TYPE_SINGLE)
+ {
+ AVCT_TRACE_DEBUG("Got single during reassembly");
+ p_ret = p_buf;
+ }
+ else
+ {
+ osi_free_and_reset((void**)&p_buf);
+ p_ret =NULL;
+ AVCT_TRACE_WARNING("### Got Fragmented packet");
+ }
+ return p_ret;
+}
+#endif
+
+
/*******************************************************************************
**
@@ -194,6 +248,49 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_chnl_open
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /*DUT does not initiate Browsing channel connect */
+ AVCT_TRACE_ERROR("###avct_bcb_chnl_open");
+}
+
+
+/********************************************************************************
+**
+** Function avct_close_bcb
+**
+** Description Clear BCB data structure
+**
+**
+** Returns void.
+**
+******************************************************************************/
+void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_BCB *p_bcb = NULL;
+
+ AVCT_TRACE_DEBUG("avct_close_bcb");
+ p_bcb = avct_bcb_by_lcb(p_lcb);
+ if (p_bcb != NULL)
+ {
+ AVCT_TRACE_DEBUG("Send Disconnect Event");
+ p_bcb->allocated = 0;
+ avct_bcb_event( p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_unbind_disc
@@ -211,6 +308,24 @@
avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_unbind_disc
+**
+** Description Deallocate ccb and call callback with disconnect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_ERROR("### avct_bcb_unbind_disc");
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_open_ind
@@ -236,8 +351,10 @@
if (p_ccb->allocated)
{
/* if bound to this lcb send connect confirm event */
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, %d", p_ccb->allocated);
if (p_ccb->p_lcb == p_lcb)
{
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, bind true");
bind = TRUE;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
@@ -248,6 +365,7 @@
(avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL))
{
/* bind ccb to lcb and send connect ind event */
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, bind and update");
bind = TRUE;
p_ccb->p_lcb = p_lcb;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
@@ -260,10 +378,63 @@
/* if no ccbs bound to this lcb, disconnect */
if (bind == FALSE)
{
+ AVCT_TRACE_DEBUG("avct_lcb_open_ind, send disconnect");
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_open_ind
+**
+** Description Handle an LL_OPEN event. For each allocated ccb already
+** bound to this lcb, send a connect event. For each
+** unbound ccb with a new PID, bind that ccb to this lcb and
+** send a connect event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ tAVCT_LCB *p_lcb =NULL;
+ int i;
+ BOOLEAN bind = FALSE;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_open_ind: %d",p_ccb->allocated);
+ /*if ccb allocated */
+ if (p_ccb->allocated & AVCT_ALOC_BCB)
+ {
+ /* if bound to this bcb then send connect confirm event */
+ if (p_ccb->p_bcb == p_bcb)
+ {
+ AVCT_TRACE_DEBUG("open_ind success");
+ p_lcb = avct_cb.ccb[i].p_lcb;
+ if (p_lcb != NULL)
+ {
+ bind = TRUE;
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
+ 0, p_lcb->peer_addr);
+ break;
+ }
+ }
+ }
+
+ }
+ if (bind == FALSE)
+ {
+ AVCT_TRACE_ERROR("### open_ind error");
+ avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_open_fail
@@ -289,7 +460,25 @@
}
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_open_fail
+**
+** Description L2CAP channel open attempt failed. Deallocate any ccbs
+** on this lcb and send connect confirm event with failure.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* DUT does not initiate browsing channel open */
+ AVCT_TRACE_ERROR("###avct_bcb_open_fail");
+}
+#endif
/*******************************************************************************
**
** Function avct_lcb_close_ind
@@ -326,6 +515,37 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_lcb_close_ind
+**
+** Description L2CAP channel closed by peer. Deallocate any initiator
+** ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+ int i;
+ AVCT_TRACE_DEBUG("avct_bcb_close_ind");
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+ {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+ {
+ //set avct_cb.bcb to 0
+ memset(p_ccb->p_bcb, 0 ,sizeof(tAVCT_BCB));
+ p_ccb->p_bcb = NULL;
+ AVCT_TRACE_DEBUG("**close_ind");
+ }
+ }
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_close_cfm
@@ -372,6 +592,32 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_close_cfm
+**
+** Description
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_DEBUG("avct_bcb_close_cfm");
+ if (p_bcb != NULL)
+ {
+ memset(p_bcb, 0, sizeof(tAVCT_BCB));
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### avct_bcb_close_cfm");
+ }
+}
+#endif
+
+
/*******************************************************************************
**
** Function avct_lcb_bind_conn
@@ -389,6 +635,24 @@
AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_lcb_bind_conn
+**
+** Description Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* DUT does not initiate browse connect*/
+ AVCT_TRACE_ERROR("###avct_bcb_bind_conn");
+}
+
+#endif
/*******************************************************************************
**
** Function avct_lcb_chk_disc
@@ -420,6 +684,23 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_chk_disc
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* BCB disconnecton done during lcb_chk_disc */
+ AVCT_TRACE_ERROR("### avct_bcb_chk_disc");
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_chnl_disc
@@ -433,10 +714,29 @@
void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_data);
-
+ AVCT_TRACE_DEBUG("avct_lcb_chnl_disc");
L2CA_DisconnectReq(p_lcb->ch_lcid);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_chnl_disc
+**
+** Description Disconnect L2CAP channel.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_ERROR("avct_bcb_chnl_disc");
+ /* Disconnect L2CAP Browsing channel */
+ L2CA_DisconnectReq(p_bcb->ch_lcid);
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_bind_fail
@@ -455,6 +755,23 @@
avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_bind_fail
+**
+** Description
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ /* Not expected to be called */
+ AVCT_TRACE_ERROR("###avct_bcb_bind_fail");
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_cong_ind
@@ -497,6 +814,48 @@
}
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_cong_ind
+**
+** Description Handle congestion indication from L2CAP.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT8 event;
+ BT_HDR *p_buf;
+
+ AVCT_TRACE_DEBUG("avct_bcb_cong_ind");
+ if (p_bcb != NULL)
+ {
+ AVCT_TRACE_DEBUG("avct_bcb_cong_ind = %d", p_data->cong);
+
+ event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
+ p_bcb->cong = p_data->cong;
+ if (p_bcb->cong == FALSE && !fixed_queue_is_empty(p_bcb->tx_q))
+ {
+ while (!p_bcb->cong &&
+ (p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_bcb->tx_q)) != NULL)
+ {
+ if (L2CA_DataWrite(p_bcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ p_bcb->cong = TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### bcb NULL");
+ }
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_discard_msg
@@ -515,6 +874,24 @@
osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_discard_msg
+**
+** Description Discard a message sent in from the API.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_ERROR("### avct_bcb_discard_msg");
+ osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_send_msg
@@ -627,7 +1004,66 @@
fixed_queue_length(p_lcb->tx_q));
return;
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_lcb_send_msg
+**
+** Description Build and send an AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT16 curr_msg_len;
+ UINT8 pkt_type;
+ UINT8 *p;
+ BT_HDR *p_buf;
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+ AVCT_TRACE_DEBUG("avct_bcb_send_msg length: %x",curr_msg_len);
+ AVCT_TRACE_DEBUG("Remote PEER MTU: %x",p_bcb->peer_mtu);
+ /* initialize packet type and other stuff */
+ if (curr_msg_len <= (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+ {
+ pkt_type = AVCT_PKT_TYPE_SINGLE;
+ //No need to do segmentation need to send data as a single packet
+ p_buf = p_data->ul_msg.p_buf;
+ /* set up to build header */
+ p_buf->len += AVCT_HDR_LEN_SINGLE;
+ p_buf->offset -= AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ p_data->ul_msg.cr = AVCT_RSP ;
+ AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ //UINT8_TO_STREAM(p, nosp);
+ p_data->ul_msg.p_ccb->cc.pid = 0x110E;
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+ if (p_bcb->cong == TRUE)
+ {
+ AVCT_TRACE_ERROR("L2CAP congestion");
+ fixed_queue_enqueue(p_bcb->tx_q, p_buf);
+ }
+ else
+ {
+ if (L2CA_DataWrite(p_bcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+ {
+ AVCT_TRACE_DEBUG("L2CAP Data Write");
+ p_bcb->cong = TRUE;
+ //Flag to be cleared
+ }
+ }
+ }
+ else
+ {
+ AVCT_TRACE_ERROR("### bcb_send_msg, length incorrect");
+ }
+}
+#endif
/*******************************************************************************
**
** Function avct_lcb_free_msg_ind
@@ -648,6 +1084,26 @@
osi_free_and_reset((void **)&p_data->p_buf);
}
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_free_msg_ind
+**
+** Description Discard an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ AVCT_TRACE_DEBUG("avct_bcb_free_msg_ind");
+ if (p_data)
+ osi_free_and_reset((void**)&p_data->p_buf);
+
+}
+#endif
+
/*******************************************************************************
**
** Function avct_lcb_msg_ind
@@ -718,3 +1174,107 @@
}
}
}
+
+#if (AVCT_BROWSE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avct_bcb_msg_ind
+**
+** Description Handle an incoming AVCTP message.
+**
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+ UINT8 *p;
+ UINT8 label, type, cr_ipid;
+ UINT16 pid;
+ tAVCT_LCB *p_lcb;
+ tAVCT_CCB *p_ccb;
+ BT_HDR *p_buf;
+
+ AVCT_TRACE_DEBUG("avct_bcb_msg_ind");
+ /* Update layer specific information so that while
+ * responding AVCT_MsgReq, AVCT layer knows to respond to
+ * Browsing channel
+ */
+ p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+ /*
+ AVCTP fragmentation shall not be used on the AVCTP Browsing Channel
+ */
+
+ if ((p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf)) == NULL)
+ {
+ AVCT_TRACE_ERROR("### Error bcb_msg_asmbl");
+ return;
+ }
+
+ /* Data passed is HCI+L2CAP+AVCT_AVRCP
+ * Point to AVCT start
+ */
+
+ p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse AVCT header byte */
+ AVCT_PRS_HDR(p, label, type, cr_ipid);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID)
+ {
+ AVCT_TRACE_WARNING("### Invalid cr_ipid", cr_ipid);
+ osi_free_and_reset((void**)&p_data->p_buf);
+ return;
+ }
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ p_lcb = avct_lcb_by_bcb(p_bcb);
+ if (p_lcb == NULL)
+ {
+ AVCT_TRACE_ERROR("### Error lcb is NULL");
+ osi_free_and_reset((void**)&p_data->p_buf);
+ }
+ else
+ {
+ AVCT_TRACE_DEBUG("p_lcb param: p[0]: %x, p[1]: %x,\
+ p[2] : %x, p[3] : %x ",p_lcb->peer_addr[0], p_lcb->peer_addr[1],p_lcb->peer_addr[2],\
+ p_lcb->peer_addr[3]);
+ /* Irrespective of browsing or control
+ * message recieved is passed on to above layer
+ */
+
+ /* Check if p_lcb is correct */
+ if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
+ {
+ /* PID found, send msg to upper laer, adjust
+ * bt hdr and call msg callback
+ */
+ AVCT_TRACE_DEBUG("label: %x ,cr_ipid : %d ",label, cr_ipid );
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+ }
+ else
+ {
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING("### No ccb for PID=%x", pid);
+ osi_free_and_reset((void**)&p_data->p_buf);
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD)
+ {
+ if ((p_buf = (BT_HDR *) osi_malloc(AVCT_CMD_BUF_SIZE)) != NULL)
+ {
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
index 5201054..50c5f90 100644
--- a/stack/avdt/avdt_api.c
+++ b/stack/avdt/avdt_api.c
@@ -39,6 +39,29 @@
tAVDT_CB avdt_cb;
#endif
+/*******************************************************************************
+**
+** Function AVDT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_Init(void)
+{
+ memset(&avdt_cb, 0, sizeof(tAVDT_CB));
+
+#if defined(AVDT_INITIAL_TRACE_LEVEL)
+ avdt_cb.trace_level = AVDT_INITIAL_TRACE_LEVEL;
+#else
+ avdt_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
void avdt_ccb_idle_ccb_timer_timeout(void *data)
{
tAVDT_CCB *p_ccb = (tAVDT_CCB *)data;
@@ -144,6 +167,40 @@
/*******************************************************************************
**
+** Function AVDT_UpdateServiceBusyState
+**
+** Description This function is used to set the service busy state
+** during outgoing connection to properly handle the
+** connections in upper layers.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_UpdateServiceBusyState(BOOLEAN state)
+{
+ AVDT_TRACE_DEBUG("AVDT_UpdateServiceBusyState: %d", state);
+ avdt_cb.conn_in_progress = state;
+}
+
+/*******************************************************************************
+**
+** Function AVDT_GetServiceBusyState
+**
+** Description This function is used to get the service busy state
+**
+**
+** Returns outgoing connection in progress or not
+**
+*******************************************************************************/
+BOOLEAN AVDT_GetServiceBusyState(void)
+{
+ AVDT_TRACE_DEBUG("AVDT_GetServiceBusyState: %d", avdt_cb.conn_in_progress);
+ return avdt_cb.conn_in_progress;
+}
+
+/*******************************************************************************
+**
** Function AVDT_SINK_Activate
**
** Description Activate SEP of A2DP Sink. In Use parameter is adjusted.
@@ -237,16 +294,19 @@
/* Verify parameters; if invalid, return failure */
if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL))
{
+ AVDT_TRACE_ERROR("%s: bad param", __FUNCTION__);
result = AVDT_BAD_PARAMS;
}
/* Allocate scb; if no scbs, return failure */
else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL)
{
+ AVDT_TRACE_ERROR("%s: noresource", __FUNCTION__);
result = AVDT_NO_RESOURCES;
}
else
{
*p_handle = avdt_scb_to_hdl(p_scb);
+ AVDT_TRACE_DEBUG("%s: allocated SCB", __FUNCTION__);
}
return result;
}
@@ -1127,6 +1187,22 @@
return (lcid);
}
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/*******************************************************************************
+**
+** Function AVDT_GetStreamingDestChannel
+**
+** Description Get the Dest L2CAP CID used by the stream channel.
+**
+** Returns Destination CID.
+**
+*******************************************************************************/
+UINT16 AVDT_GetStreamingDestChannelId(UINT16 lcid)
+{
+ return L2CA_GetDestChannelID(lcid);
+}
+#endif
+
#if AVDT_MULTIPLEXING == TRUE
/*******************************************************************************
**
@@ -1292,7 +1368,19 @@
return result;
}
#endif
-
+/*******************************************************************************
+**
+** Function AVDT_UpdateMaxAvClients
+**
+** Description Update max simultaneous AV connections supported
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_UpdateMaxAvClients(UINT8 max_clients)
+{
+ avdt_scb_set_max_av_client(max_clients);
+}
/******************************************************************************
**
** Function AVDT_SetTraceLevel
diff --git a/stack/avdt/avdt_ccb_act.c b/stack/avdt/avdt_ccb_act.c
index 41b74e1..8cc9bf4 100644
--- a/stack/avdt/avdt_ccb_act.c
+++ b/stack/avdt/avdt_ccb_act.c
@@ -24,6 +24,7 @@
******************************************************************************/
#include <string.h>
+#include "btif_av_co.h"
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
@@ -33,6 +34,9 @@
#include "bt_common.h"
#include "btu.h"
#include "btm_api.h"
+#include "device/include/interop.h"
+#include "a2d_api.h"
+#include <hardware/bluetooth.h>
extern fixed_queue_t *btu_general_alarm_queue;
@@ -160,15 +164,42 @@
tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS];
tAVDT_SCB *p_scb = &avdt_cb.scb[0];
int i;
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, p_ccb->peer_addr);
p_data->msg.discover_rsp.p_sep_info = sep_info;
p_data->msg.discover_rsp.num_seps = 0;
+ /* If this ccb, has done setconf and is doing discover again
+ * we should show SEP for which setconfig was done earlier
+ * This is done for IOP with some remotes */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if((p_ccb != NULL)&& (p_scb->p_ccb != NULL)&&(p_scb->p_ccb == p_ccb))
+ {
+ AVDT_TRACE_EVENT(" CCB already tied to SCB[%d] ",i);
+ /* copy sep info */
+ sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use;
+ sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1;
+ sep_info[p_data->msg.discover_rsp.num_seps].media_type = p_scb->cs.media_type;
+ sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep;
+ p_data->msg.discover_rsp.num_seps++;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data);
+ return;
+ }
+ }
+ p_scb = &avdt_cb.scb[0];
/* for all allocated scbs */
for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
{
- if (p_scb->allocated)
+ if ((p_scb->allocated) && (!p_scb->in_use))
{
+ /* if the codec type is AAC and if the peer address is blacklisted */
+ if (p_scb->cs.cfg.codec_info[AVDT_CODEC_TYPE_INDEX] == A2D_MEDIA_CT_M24 &&
+ !bta_av_co_audio_is_aac_enabled(&remote_bdaddr)) {
+ AVDT_TRACE_EVENT("%s: skipping AAC advertise\n", __func__);
+ continue;
+ }
/* copy sep info */
sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use;
sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1;
diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h
index 1ab5f18..f356a32 100644
--- a/stack/avdt/avdt_int.h
+++ b/stack/avdt/avdt_int.h
@@ -552,6 +552,7 @@
tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */
tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */
UINT8 trace_level; /* trace level */
+ BOOLEAN conn_in_progress; /* outgoing connection in progress */
} tAVDT_CB;
@@ -615,7 +616,8 @@
extern UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code);
extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi);
extern UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb);
-
+extern void avdt_scb_set_max_av_client(UINT8 num_clients);
+extern UINT8 avdt_scb_get_max_av_client(void);
/* SCB action functions */
extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
diff --git a/stack/avdt/avdt_l2c.c b/stack/avdt/avdt_l2c.c
index 87c7ad9..8e8b5fc 100644
--- a/stack/avdt/avdt_l2c.c
+++ b/stack/avdt/avdt_l2c.c
@@ -181,8 +181,17 @@
tBTM_STATUS rc;
UNUSED(psm);
+ /* Check if outgoing connection is in progress
+ * if yes, reject incoming connection at L2CAP
+ * level itself.
+ */
+ if(avdt_cb.conn_in_progress == TRUE)
+ {
+ AVDT_TRACE_WARNING("connect_ind: outgoing conn in progress: Reject incoming conn");
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
/* do we already have a control channel for this peer? */
- if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
{
/* no, allocate ccb */
if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
@@ -201,11 +210,16 @@
p_tbl->id = id;
p_tbl->state = AVDT_AD_ST_SEC_ACP;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
-
- if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *)&bd_addr)) {
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, bd_addr);
+ if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *)&remote_bdaddr)) {
// Disable 3DH packets for AVDT ACL to improve sensitivity on HS
tACL_CONN *p_acl_cb = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
- btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
+ /* Fix for below klockwork issue
+ * Pointer 'p_acl_cb' returned from call to function 'btm_bda_to_acl' at line 216
+ * may be NULL and will be dereferenced at line 217*/
+ if (p_acl_cb)
+ btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
HCI_PKT_TYPES_MASK_NO_3_DH1 |
HCI_PKT_TYPES_MASK_NO_3_DH3 |
HCI_PKT_TYPES_MASK_NO_3_DH5));
@@ -329,11 +343,17 @@
p_tbl->state = AVDT_AD_ST_SEC_INT;
p_tbl->lcid = lcid;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
+ bt_bdaddr_t remote_address;
+ bdcpy(remote_address.address, p_ccb->peer_addr);
- if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *) &p_ccb->peer_addr)) {
+ if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *) &remote_address)) {
// Disable 3DH packets for AVDT ACL to improve sensitivity on HS
tACL_CONN *p_acl_cb = btm_bda_to_acl(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
- btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
+ /* Fix for below klockwork issue
+ * Pointer 'p_acl_cb' returned from call to function 'btm_bda_to_acl' at line 344
+ * may be NULL and will be dereferenced at line 345*/
+ if (p_acl_cb)
+ btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
HCI_PKT_TYPES_MASK_NO_3_DH1 |
HCI_PKT_TYPES_MASK_NO_3_DH3 |
HCI_PKT_TYPES_MASK_NO_3_DH5));
diff --git a/stack/avdt/avdt_scb.c b/stack/avdt/avdt_scb.c
index e4e7340..f02e078 100644
--- a/stack/avdt/avdt_scb.c
+++ b/stack/avdt/avdt_scb.c
@@ -511,7 +511,7 @@
avdt_scb_st_closing
};
-
+UINT8 max_av_clients = 1;
/*******************************************************************************
**
** Function avdt_scb_event
@@ -743,13 +743,20 @@
switch (state) {
case AVDT_VERIFY_OPEN:
case AVDT_VERIFY_START:
- if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST)
+ /* Fix for below klockwork issue
+ * Pointer 'p_scb' checked for NULL at line 736 may be dereferenced below at line 746.
+ * need to put NULL check for p_scb */
+ if (p_scb != NULL && p_scb->state != AVDT_SCB_OPEN_ST &&
+ p_scb->state != AVDT_SCB_STREAM_ST)
*p_err_code = AVDT_ERR_BAD_STATE;
break;
case AVDT_VERIFY_SUSPEND:
case AVDT_VERIFY_STREAMING:
- if (p_scb->state != AVDT_SCB_STREAM_ST)
+ /* Fix for below klockwork issue
+ * Pointer 'p_scb' checked for NULL at line 736 may be dereferenced below at line 752.
+ * need to put NULL check for p_scb */
+ if (p_scb != NULL && p_scb->state != AVDT_SCB_STREAM_ST)
*p_err_code = AVDT_ERR_BAD_STATE;
break;
}
@@ -788,3 +795,31 @@
}
}
+/*******************************************************************************
+**
+** Function avdt_scb_max_av_client
+**
+** Description Update max simultaneous AV connections supported
+**
+** Returns Nothing.
+**
+*******************************************************************************/
+void avdt_scb_set_max_av_client(UINT8 max_clients)
+{
+ max_av_clients = max_clients;
+}
+
+/*******************************************************************************
+**
+** Function avdt_scb_get_max_av_client
+**
+** Description Return max simultaneous AV connections supported
+**
+** Returns max av clients supported
+**
+*******************************************************************************/
+UINT8 avdt_scb_get_max_av_client()
+{
+ return max_av_clients;
+}
+
diff --git a/stack/avdt/avdt_scb_act.c b/stack/avdt/avdt_scb_act.c
index a634ad2..0ef3ca7 100644
--- a/stack/avdt/avdt_scb_act.c
+++ b/stack/avdt/avdt_scb_act.c
@@ -1,4 +1,9 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+/******************************************************************************
*
* Copyright (C) 2002-2012 Broadcom Corporation
*
@@ -65,6 +70,7 @@
AVDT_OPEN_CFM_EVT /* AVDT_OPEN_INT */
};
+
/*******************************************************************************
**
** Function avdt_scb_gen_ssrc
@@ -312,6 +318,7 @@
{
/* report sequence number */
p_data->p_pkt->layer_specific = seq;
+ APPL_TRACE_LATENCY_AUDIO("AVDTP Recv Packet, seq number %d", seq);
(*p_scb->cs.p_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt,
time_stamp, (UINT8)(m_pt | (marker<<7)));
}
@@ -864,6 +871,91 @@
(tAVDT_CTRL *) &p_data->msg.security_cmd);
}
+void avdt_set_scbs_busy(tAVDT_SCB *ptr_scb)
+{
+ AVDT_TRACE_DEBUG(" avdt_set_scbs_busy ");
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ UINT8 reg_id = ptr_scb->cs.registration_id;
+ int i = 0;
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ AVDT_TRACE_DEBUG(" avdt_set_scbs_busy SCB[%d] reg_id, sep_type ", i, p_scb->cs.registration_id, p_scb->cs.tsep);
+ if ((p_scb->allocated) && (p_scb->cs.registration_id == reg_id) && (p_scb->cs.tsep == ptr_scb->cs.tsep))
+ {
+ AVDT_TRACE_DEBUG(" Setting SCB[%d].in_use as true", i);
+ p_scb->in_use = TRUE;
+ }
+ }
+}
+
+void avdt_set_scbs_free(tAVDT_SCB *ptr_scb)
+{
+ AVDT_TRACE_DEBUG(" avdt_set_scbs_free ");
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ UINT8 reg_id = ptr_scb->cs.registration_id;
+ int i = 0;
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ AVDT_TRACE_DEBUG(" avdt_set_scbs_free SCB[%d] reg_id, sep_type ", i, p_scb->cs.registration_id, p_scb->cs.tsep);
+ if ((p_scb->allocated) && (p_scb->cs.registration_id == reg_id) && (p_scb->cs.tsep == ptr_scb->cs.tsep))
+ {
+ AVDT_TRACE_DEBUG(" Setting SCB[%d].in_use as false ", i);
+ p_scb->in_use = FALSE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_check_sep_state
+**
+** Description This function checks if either of the SEID is in use in the
+** cluster of a stream in which the ACP SEP for the remote
+** initiated connection belongs to.
+**
+** Returns True if one SEID in the cluster is busy, False otherwise
+**
+*******************************************************************************/
+BOOLEAN avdt_check_sep_state(tAVDT_SCB *p_scb)
+{
+ int i,j;
+ int num_sep = 0,sep_offset;
+ int num_stream = avdt_scb_get_max_av_client();
+ if (num_stream == 1)
+ return false;
+ for (i = 0;i < AVDT_NUM_SEPS; i++)
+ {
+ tAVDT_SCB *temp_scb = &avdt_cb.scb[i];
+ if (p_scb == temp_scb)
+ break;
+ }
+ if (i < AVDT_NUM_SEPS)
+ {
+ sep_offset = i;
+ tAVDT_SCB *temp_scb = &avdt_cb.scb[0];
+ for (j = 0; j < AVDT_NUM_SEPS; j++, temp_scb++)
+ {
+ if (temp_scb->allocated)
+ num_sep++;
+ }
+ int num_stream = avdt_scb_get_max_av_client();
+ int num_codecs = num_sep/num_stream;
+ for (i = 0; i < num_sep;i += num_codecs)
+ {
+ BOOLEAN in_use = false;
+ for (j = i;j < (i+num_codecs); j++)
+ {
+ tAVDT_SCB *temp_scb = &avdt_cb.scb[j];
+ if (temp_scb->in_use)
+ in_use = true;
+ }
+ if (in_use && (sep_offset >= i && sep_offset < j))
+ return true;
+ }
+ }
+ return false;
+}
+
/*******************************************************************************
**
** Function avdt_scb_hdl_setconfig_cmd
@@ -878,8 +970,10 @@
void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
{
tAVDT_CFG *p_cfg;
+ AVDT_TRACE_WARNING("avdt_scb_hdl_setconfig_cmd: SCB in use: %d, Conn in progress: %d",
+ p_scb->in_use, avdt_cb.conn_in_progress);
- if (!p_scb->in_use)
+ if ((!p_scb->in_use) && !(avdt_check_sep_state(p_scb)) && (!avdt_cb.conn_in_progress))
{
p_cfg = p_data->msg.config_cmd.p_cfg;
if(p_scb->cs.cfg.codec_info[AVDT_CODEC_TYPE_INDEX] == p_cfg->codec_info[AVDT_CODEC_TYPE_INDEX])
@@ -889,6 +983,7 @@
/* copy info to scb */
p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ avdt_set_scbs_busy(p_scb);
p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
/* call app callback */
@@ -1735,7 +1830,7 @@
}
#endif
memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
-
+ avdt_set_scbs_busy(p_scb);
avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
/* tell ccb to open channel */
@@ -2108,6 +2203,7 @@
void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
{
UNUSED(p_data);
+ avdt_set_scbs_free(p_scb);
p_scb->in_use = FALSE;
p_scb->p_ccb = NULL;
p_scb->peer_seid = 0;
diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
index 17c8597..d1f10ea 100644
--- a/stack/avrc/avrc_api.c
+++ b/stack/avrc/avrc_api.c
@@ -108,6 +108,29 @@
/******************************************************************************
**
+** Function avrc_get_packet_type
+**
+** Description Gets a packet type for fragmanted packet.
+**
+** Returns Type of fragmenatation packet.
+**
+******************************************************************************/
+static UINT8 avrc_get_packet_type(BT_HDR *pp_pkt)
+{
+ BT_HDR *p_pkt = pp_pkt;
+ UINT8 *p_data;
+ UINT8 pkt_type;
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */
+ p_data += AVRC_VENDOR_HDR_SIZE;
+
+ pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+
+ return pkt_type;
+}
+
+/******************************************************************************
+**
** Function avrc_copy_packet
**
** Description Copies an AVRC packet to a new buffer. In the new buffer,
@@ -149,7 +172,7 @@
UINT8 *p_data, *p_orig_data;
UINT8 rsp_type;
- AVRC_TRACE_DEBUG ("avrc_prep_end_frag" );
+ AVRC_TRACE_DEBUG("avrc_prep_end_frag" );
p_fcb = &avrc_cb.fcb[handle];
/* The response type of the end fragment should be the same as the the PDU of "End Fragment
@@ -249,7 +272,7 @@
if (pkt_type != AVRC_PKT_SINGLE)
{
/* reject - commands can only be in single packets at AVRCP level */
- AVRC_TRACE_ERROR ("commands must be in single packet pdu:0x%x", *p_data );
+ AVRC_TRACE_ERROR("commands must be in single packet pdu:0x%x", *p_data );
/* use the current GKI buffer to send the reject */
status = AVRC_STS_BAD_CMD;
}
@@ -363,7 +386,7 @@
p_data += AVRC_VENDOR_HDR_SIZE;
pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
- AVRC_TRACE_DEBUG ("pkt_type %d", pkt_type );
+ AVRC_TRACE_DEBUG("pkt_type %d", pkt_type );
p_rcb = &avrc_cb.rcb[handle];
if (p_msg->company_id == AVRC_CO_METADATA)
{
@@ -408,7 +431,7 @@
} else if (p_rcb->p_rmsg == NULL) {
/* Received a CONTINUE/END, but no corresponding START
(or previous fragmented response was dropped) */
- AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \
+ AVRC_TRACE_DEBUG("Received a CONTINUE/END without no corresponding START \
(or previous fragmented response was dropped)");
drop_code = 5;
osi_free(p_pkt);
@@ -566,136 +589,126 @@
p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
memset(&msg, 0, sizeof(tAVRC_MSG) );
+ /* layer_specific value use to distinguish
+ * Browsing and control channel PDU ID.
+ * AVCT_DATA_BROWSE to be used for browsing
+ * channel
+ */
+ AVRC_TRACE_DEBUG("layer_specific %x",p_pkt->layer_specific);
+ if (p_pkt->layer_specific != AVCT_DATA_BROWSE)
{
- if (p_pkt->len < AVRC_AVC_HDR_SIZE) {
- android_errorWriteLog(0x534e4554, "111803925");
- AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
- __func__, p_pkt->len, AVRC_AVC_HDR_SIZE);
- osi_free(p_pkt);
- return;
- }
- msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
- AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
- handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
- msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
- msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
- opcode = p_data[2];
- }
-
- if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
- ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
- {
-
- switch(opcode)
{
- case AVRC_OP_UNIT_INFO:
- if (cr == AVCT_CMD)
- {
- /* send the response to the peer */
- p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
- p_rsp_data = avrc_get_data_ptr(p_rsp);
- *p_rsp_data = AVRC_RSP_IMPL_STBL;
- /* check & set the offset. set response code, set subunit_type & subunit_id,
- set AVRC_OP_UNIT_INFO */
- /* 3 bytes: ctype, subunit*, opcode */
- p_rsp_data += AVRC_AVC_HDR_SIZE;
- *p_rsp_data++ = 7;
- /* Panel subunit & id=0 */
- *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
- AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
- p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
- cr = AVCT_RSP;
-#if (BT_USE_TRACES == TRUE)
- p_drop_msg = "auto respond";
-#endif
+ if (p_pkt->len < AVRC_AVC_HDR_SIZE) {
+ android_errorWriteLog(0x534e4554, "111803925");
+ AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
+ __func__, p_pkt->len, AVRC_AVC_HDR_SIZE);
+ osi_free(p_pkt);
+ return;
}
- else
+ msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
+ AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
+ handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
+ msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
+ opcode = p_data[2];
+ }
+ AVRC_TRACE_DEBUG("opcode %d",opcode);
+ if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
+ ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
+ {
+
+ switch(opcode)
{
- /* parse response */
- if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) {
- AVRC_TRACE_WARNING(
- "%s: message length %d too short: must be at least %d",
- __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN);
- android_errorWriteLog(0x534e4554, "79883824");
- drop = TRUE;
- p_drop_msg = "UNIT_INFO_RSP too short";
- break;
- }
- p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
- msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
- msg.unit.unit = *p_data & AVRC_SUBID_MASK;
- p_data++;
- AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
- }
- break;
-
- case AVRC_OP_SUB_INFO:
- if (cr == AVCT_CMD)
- {
- /* send the response to the peer */
- p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
- p_rsp_data = avrc_get_data_ptr(p_rsp);
- *p_rsp_data = AVRC_RSP_IMPL_STBL;
- /* check & set the offset. set response code, set (subunit_type & subunit_id),
- set AVRC_OP_SUB_INFO, set (page & extention code) */
- p_rsp_data += 4;
- /* Panel subunit & id=0 */
- *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
- memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
- p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
- p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
- cr = AVCT_RSP;
-#if (BT_USE_TRACES == TRUE)
- p_drop_msg = "auto responded";
-#endif
- }
- else
- {
- /* parse response */
- if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) {
- AVRC_TRACE_WARNING(
- "%s: message length %d too short: must be at least %d",
- __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
- android_errorWriteLog(0x534e4554, "79883824");
- drop = TRUE;
- p_drop_msg = "SUB_UNIT_INFO_RSP too short";
- break;
- }
- p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
- msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
- xx = 0;
- while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
- {
- msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
- if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
- msg.sub.panel = TRUE;
- xx++;
- }
- }
- break;
-
- case AVRC_OP_VENDOR:
- p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
- p_begin = p_data;
- if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
- {
+ case AVRC_OP_UNIT_INFO:
if (cr == AVCT_CMD)
- reject = TRUE;
+ {
+ /* send the response to the peer */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_IMPL_STBL;
+ /* check & set the offset. set response code, set subunit_type & subunit_id,
+ set AVRC_OP_UNIT_INFO */
+ /* 3 bytes: ctype, subunit*, opcode */
+ p_rsp_data += AVRC_AVC_HDR_SIZE;
+ *p_rsp_data++ = 7;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto respond";
+#endif
+ }
else
- drop = TRUE;
+ {
+ /* parse response */
+ if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) {
+ AVRC_TRACE_WARNING(
+ "%s: message length %d too short: must be at least %d",
+ __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN);
+ android_errorWriteLog(0x534e4554, "79883824");
+ drop = TRUE;
+ p_drop_msg = "UNIT_INFO_RSP too short";
+ break;
+ }
+ p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
+ msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.unit.unit = *p_data & AVRC_SUBID_MASK;
+ p_data++;
+ AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
+ }
break;
- }
- p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
- AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
- p_msg->p_vendor_data = p_data;
- p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
-#if (AVRC_METADATA_INCLUDED == TRUE)
- UINT8 drop_code = 0;
- if (p_msg->company_id == AVRC_CO_METADATA)
- {
- /* Validate length for metadata message */
- if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE))
+ case AVRC_OP_SUB_INFO:
+ if (cr == AVCT_CMD)
+ {
+ /* send the response to the peer */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_IMPL_STBL;
+ /* check & set the offset. set response code, set (subunit_type & subunit_id),
+ set AVRC_OP_SUB_INFO, set (page & extention code) */
+ p_rsp_data += 4;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
+ p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto responded";
+#endif
+ }
+ else
+ {
+ /* parse response */
+ if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) {
+ AVRC_TRACE_WARNING(
+ "%s: message length %d too short: must be at least %d",
+ __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
+ android_errorWriteLog(0x534e4554, "79883824");
+ drop = TRUE;
+ p_drop_msg = "SUB_UNIT_INFO_RSP too short";
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
+ xx = 0;
+ while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
+ {
+ msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
+ if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
+ msg.sub.panel = TRUE;
+ xx++;
+ }
+ }
+ break;
+
+ case AVRC_OP_VENDOR:
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ p_begin = p_data;
+ if (p_pkt->len <= AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
{
if (cr == AVCT_CMD)
reject = TRUE;
@@ -703,117 +716,157 @@
drop = TRUE;
break;
}
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
+ p_msg->p_vendor_data = p_data;
+ p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
+ AVRC_TRACE_DEBUG(" vendor_len %d", p_msg->vendor_len);
- /* Check+handle fragmented messages */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ UINT8 drop_code = 0;
+ if (p_msg->vendor_len > AVRC_META_CMD_BUF_SIZE)
+ {
+ int packet_type = avrc_get_packet_type(p_pkt);
+ AVRC_TRACE_DEBUG("packet_type %d", packet_type);
+ //single packet size is greater then MTU size, reject it
+ if (packet_type == AVRC_PKT_SINGLE)
+ {
+ AVRC_TRACE_ERROR("Incorrect lenght for single packet");
+ reject = TRUE;
+ break;
+ }
+ }
drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
if (drop_code > 0)
drop = TRUE;
- }
- if (drop_code > 0)
- {
- if (drop_code != 4)
- do_free = FALSE;
-#if (BT_USE_TRACES == TRUE)
- switch (drop_code)
+ if (drop_code > 0)
{
- case 1:
- p_drop_msg = "sent_frag";
- break;
- case 2:
- p_drop_msg = "req_cont";
- break;
- case 3:
- p_drop_msg = "sent_frag3";
- break;
- case 4:
- p_drop_msg = "sent_frag_free";
- break;
- default:
- p_drop_msg = "sent_fragd";
- }
+ if (drop_code != 4)
+ do_free = FALSE;
+#if (BT_USE_TRACES == TRUE)
+ switch (drop_code)
+ {
+ case 1:
+ p_drop_msg = "sent_frag";
+ break;
+ case 2:
+ p_drop_msg = "req_cont";
+ break;
+ case 3:
+ p_drop_msg = "sent_frag3";
+ break;
+ case 4:
+ p_drop_msg = "sent_frag_free";
+ break;
+ default:
+ p_drop_msg = "sent_fragd";
+ }
#endif
- }
+ }
#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
- break;
+ break;
- case AVRC_OP_PASS_THRU:
- if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
- {
- if (cr == AVCT_CMD)
- reject = TRUE;
+ case AVRC_OP_PASS_THRU:
+ if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
+ {
+ if (cr == AVCT_CMD)
+ reject = TRUE;
+ else
+ drop = TRUE;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
+ if (AVRC_PASS_STATE_MASK & *p_data)
+ msg.pass.state = TRUE;
else
- drop = TRUE;
+ msg.pass.state = FALSE;
+ p_data++;
+ msg.pass.pass_len = *p_data++;
+ if (msg.pass.pass_len != p_pkt->len - 5)
+ msg.pass.pass_len = p_pkt->len - 5;
+ if (msg.pass.pass_len)
+ msg.pass.p_pass_data = p_data;
+ else
+ msg.pass.p_pass_data = NULL;
+ break;
+
+
+ default:
+ if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
+ {
+ /* reject unsupported opcode */
+ reject = TRUE;
+ }
+ drop = TRUE;
break;
}
- p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
- msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
- if (AVRC_PASS_STATE_MASK & *p_data)
- msg.pass.state = TRUE;
- else
- msg.pass.state = FALSE;
- p_data++;
- msg.pass.pass_len = *p_data++;
- if (msg.pass.pass_len != p_pkt->len - 5)
- msg.pass.pass_len = p_pkt->len - 5;
- if (msg.pass.pass_len)
- msg.pass.p_pass_data = p_data;
- else
- msg.pass.p_pass_data = NULL;
- break;
-
-
- default:
- if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
- {
- /* reject unsupported opcode */
- reject = TRUE;
- }
- drop = TRUE;
- break;
}
- }
- else /* drop the event */
- {
+ else /* drop the event */
+ {
drop = TRUE;
- }
+ }
- if (reject)
- {
- /* reject unsupported opcode */
- p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
- p_rsp_data = avrc_get_data_ptr(p_rsp);
- *p_rsp_data = AVRC_RSP_REJ;
+ if (reject)
+ {
+ /* reject unsupported opcode */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_REJ;
#if (BT_USE_TRACES == TRUE)
- p_drop_msg = "rejected";
+ p_drop_msg = "rejected";
#endif
- cr = AVCT_RSP;
- drop = TRUE;
- }
+ cr = AVCT_RSP;
+ drop = TRUE;
+ }
- if (p_rsp)
- {
- /* set to send response right away */
- AVCT_MsgReq( handle, label, cr, p_rsp);
- drop = TRUE;
- }
+ if (p_rsp)
+ {
+ /* set to send response right away */
+ AVCT_MsgReq( handle, label, cr, p_rsp);
+ drop = TRUE;
+ }
- if (drop == FALSE)
- {
- msg.hdr.opcode = opcode;
- (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
- }
+ if (drop == FALSE)
+ {
+ msg.hdr.opcode = opcode;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ }
#if (BT_USE_TRACES == TRUE)
+ else
+ {
+ AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+ p_drop_msg,
+ handle, avrc_cb.ccb[handle].control, cr, opcode);
+ }
+#endif
+
+
+ if (do_free)
+ osi_free(p_pkt);
+ }
else
{
- AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
- p_drop_msg,
- handle, avrc_cb.ccb[handle].control, cr, opcode);
- }
-#endif
-
-
- if (do_free)
+ opcode = p_data[0];
+ AVRC_TRACE_DEBUG("opcode:%x, length:%x",opcode, p_pkt->len);
+ /*Do sanity Check here*/
+ if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
+ {
+ opcode = AVRC_OP_BROWSE;
+ msg.browse.browse_len = p_pkt->len;
+ AVRC_TRACE_DEBUG("Browsing length %x",msg.browse.browse_len);
+ /* Browse data remains same */
+ msg.browse.p_browse_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ }
+ else
+ {
+ AVRC_TRACE_ERROR("### expect AVCT_CMD");
+ }
+ /*Free the packet as the same already got copied in BTA*/
osi_free(p_pkt);
+ }
+
}
@@ -933,9 +986,8 @@
memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
#endif
}
- AVRC_TRACE_DEBUG("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control,
- status, *p_handle);
-
+ BTIF_TRACE_IMP(" %s AVRC_Open role: %d, control:%d status:%d, handle:%d",
+ __FUNCTION__, cc.role, cc.control, status, *p_handle);
return status;
}
@@ -1158,3 +1210,15 @@
return AVRC_NO_RESOURCES;
}
+/******************************************************************************
+**
+** Function AVRC_CheckIncomfingConn
+**
+** Description Check for incoming connection in progress
+**
+** Returns TRUE if incoming ocnnection in progress, FALSE otherwise
+******************************************************************************/
+BOOLEAN AVRC_CheckIncomingConn(BD_ADDR peer_addr)
+{
+ return AVCT_CheckIncomingConn(peer_addr);
+}
diff --git a/stack/avrc/avrc_bld_ct.c b/stack/avrc/avrc_bld_ct.c
index a69f05f..b4345e7 100644
--- a/stack/avrc/avrc_bld_ct.c
+++ b/stack/avrc/avrc_bld_ct.c
@@ -199,7 +199,7 @@
/* add length -*/
UINT16_TO_BE_STREAM(p_data, param_len);
UINT8_TO_BE_STREAM(p_data,num_attrib_id);
- for(int count = 0; count < num_attrib_id; count ++)
+ for(int count = 0; count < num_attrib_id && count < AVRC_MAX_APP_ATTR_SIZE; count ++)
{
UINT8_TO_BE_STREAM(p_data,attrib_ids[count]);
}
@@ -321,7 +321,7 @@
UINT32_TO_BE_STREAM(p_data,0);
UINT32_TO_BE_STREAM(p_data,0);
UINT8_TO_BE_STREAM(p_data,num_attrib);
- for(int count = 0; count < num_attrib; count ++)
+ for(int count = 0; count < num_attrib && count < AVRC_MAX_ELEM_ATTR_SIZE; count ++)
{
UINT32_TO_BE_STREAM(p_data,attrib_ids[count]);
}
@@ -473,6 +473,10 @@
status = avrc_bld_list_player_app_values_cmd(p_pkt,p_cmd->list_app_values.attr_id);
break;
case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ /* Fix for below Klockwork Issue,taken care in the function
+ * defination avrc_bld_get_current_player_app_values_cmd()
+ * Array 'p_cmd->get_cur_app_val.attrs' of
+ * size 8 may use index value(s) 16..254*/
status = avrc_bld_get_current_player_app_values_cmd(p_pkt,
p_cmd->get_cur_app_val.num_attr,p_cmd->get_cur_app_val.attrs);
break;
@@ -487,6 +491,10 @@
avrc_bld_get_player_app_setting_value_text_cmd(p_pkt, &p_cmd->get_app_val_txt);
break;
case AVRC_PDU_GET_ELEMENT_ATTR:
+ /* Fix for below Klockwork Issue,taken care in the function
+ * defination avrc_bld_get_element_attr_cmd()
+ * Array 'p_cmd->get_elem_attrs.attrs' of
+ * size 8 may use index value(s) 8..254*/
status = avrc_bld_get_element_attr_cmd(p_pkt,
p_cmd->get_elem_attrs.num_attr,p_cmd->get_elem_attrs.attrs);
break;
diff --git a/stack/avrc/avrc_bld_tg.c b/stack/avrc/avrc_bld_tg.c
index 129b386..5c184e7 100644
--- a/stack/avrc/avrc_bld_tg.c
+++ b/stack/avrc/avrc_bld_tg.c
@@ -28,6 +28,10 @@
*****************************************************************************/
#if (AVRC_METADATA_INCLUDED == TRUE)
+#define EVT_AVAIL_PLAYER_CHANGE_RSP_LENGTH 1
+#define EVT_ADDR_PLAYER_CHANGE_RSP_LENGTH 5
+#define EVT_NOW_PLAYING_CHANGE_RSP_LENGTH 1
+
/*******************************************************************************
**
** Function avrc_bld_get_capability_rsp
@@ -645,11 +649,23 @@
status = AVRC_STS_BAD_PARAM;
break;
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ len = EVT_AVAIL_PLAYER_CHANGE_RSP_LENGTH;
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ UINT16_TO_BE_STREAM(p_data,p_rsp->param.addr_player.player_id);
+ UINT16_TO_BE_STREAM(p_data,p_rsp->param.addr_player.uid_counter);
+ len = EVT_ADDR_PLAYER_CHANGE_RSP_LENGTH;
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ len = EVT_NOW_PLAYING_CHANGE_RSP_LENGTH;
+ break;
case AVRC_EVT_VOLUME_CHANGE:
len = 2;
UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_rsp->param.volume));
break;
-
default:
status = AVRC_STS_BAD_PARAM;
AVRC_TRACE_ERROR("%s unknown event_id", __func__);
@@ -748,6 +764,7 @@
return AVRC_STS_NO_ERROR;
}
+
/*******************************************************************************
**
** Function avrc_bld_group_navigation_rsp
@@ -773,6 +790,282 @@
return AVRC_STS_NO_ERROR;
}
+/*****************************************************************************
+**
+** Function avrc_bld_folder_item_values_rsp
+**
+** Description This function builds the folder item response.
+**
+** Returns AVRC_STS_NO_ERROR,if the response is built successfully
+** otherwise error code
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_folder_item_values_rsp(tAVRC_GET_ITEMS_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start, *p_length, *p_media_element_len;
+ UINT16 itemlength, param_length;
+ UINT16 item_numb = 0, i, xx, media_attr_count;
+
+ AVRC_TRACE_DEBUG(" avrc_bld_folder_item_values_rsp offset :x%x", p_pkt->offset);
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* As per AVRCP spec, first byte of response is PDU ID
+ * and Response does not have any opcode
+ */
+ p_data = p_start;
+ /*First OCT carry PDU information */
+ *p_data++ = p_rsp->pdu;
+
+ /* Refer Media Play list AVRCP 1.5 22.19 (Get Folder Items)
+ * Mark a pointer to be filled once length is calculated at last
+ */
+ p_length = p_data;
+
+ /*increment to adjust length*/
+ p_data = p_data + 2;
+ /*Status is checked in Btif layer*/
+ *p_data++ = p_rsp->status;
+ if(p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ //TODO Response
+ AVRC_TRACE_ERROR(" ### Folder_item_values response error");
+ return p_rsp->status;
+ }
+ /*UID Counter OCT 4 and 5*/
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ /*Number of Items OCT 6 and 7*/
+ item_numb = p_rsp->item_count;
+ UINT16_TO_BE_STREAM(p_data, p_rsp->item_count);
+ param_length = 0;
+ for (i = 0; i < item_numb; i++)
+ {
+ itemlength = 0;
+ switch(p_rsp->p_item_list[i].item_type)
+ {
+ case AVRC_ITEM_PLAYER:
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].item_type);
+ itemlength = 28 + p_rsp->p_item_list[i].u.player.name.str_len;
+ UINT16_TO_BE_STREAM(p_data, itemlength);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.player_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.major_type);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.sub_type);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.play_status);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.features,\
+ AVRC_FEATURE_MASK_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.player.name.p_str,\
+ p_rsp->p_item_list[i].u.player.name.str_len);
+ break;
+ case AVRC_ITEM_FOLDER:
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].item_type);
+ itemlength = 14 + p_rsp->p_item_list[i].u.folder.name.str_len;
+ UINT16_TO_BE_STREAM(p_data, itemlength);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.uid ,AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.type);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.playable);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.folder.name.p_str,\
+ p_rsp->p_item_list[i].u.folder.name.str_len);
+ break;
+ case AVRC_ITEM_MEDIA:
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].item_type);
+ p_media_element_len = p_data;
+ itemlength = 13 + p_rsp->p_item_list[i].u.media.name.str_len;
+ p_data = p_data + 2; /* for length */
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.uid ,AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.type);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.name.p_str,\
+ p_rsp->p_item_list[i].u.media.name.str_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_item_list[i].u.media.attr_count);
+ media_attr_count = p_rsp->p_item_list[i].u.media.attr_count;
+ itemlength += 1; /* for attribute count */
+ for (xx = 0; xx < media_attr_count; xx++)
+ {
+ itemlength += 8 + p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len;
+ UINT32_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.p_str,\
+ p_rsp->p_item_list[i].u.media.p_attr_list[xx].name.str_len);
+ }
+ UINT16_TO_BE_STREAM(p_media_element_len, itemlength);
+ break;
+ }
+ param_length += itemlength + 3; /* 3 to accommodate item_len and item_type */
+ }
+ param_length = param_length + 5; //Add explicit 5, 2 num items+ 2UID Counter + 1 status counter
+ UINT16_TO_BE_STREAM(p_length, param_length);
+ p_pkt->len = p_data - p_start;
+ return AVRC_STS_NO_ERROR;
+}
+
+/**************************************************************************************
+**
+** Function avrc_bld_change_path_rsp
+**
+** Description
+**
+** Returns
+**
+************************************************************************************/
+static tAVRC_STS avrc_bld_change_path_rsp (tAVRC_CHG_PATH_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len; /* parameter length feild of Rsp */
+
+ AVRC_TRACE_DEBUG("avrc_bld_change_path_rsp offset :x%x", p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+ param_len = 5; /* refer spec */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("length = %d",p_pkt->len);
+ return AVRC_STS_NO_ERROR ;
+}
+
+/**************************************************************************************
+**
+** Function avrc_bld_set_browse_player_rsp
+**
+** Description
+**
+** Returns
+**
+************************************************************************************/
+static tAVRC_STS avrc_bld_set_browse_player_rsp (tAVRC_SET_BR_PLAYER_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len_folder_name = 0;
+ UINT16 param_len; /* parameter length feild of Rsp */
+ UINT8 folder_index = 0;
+
+ AVRC_TRACE_DEBUG("avrc_bld_set_browse_player_rsp offset :x%x", p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+
+ for(folder_index = 0; folder_index < p_rsp->folder_depth; folder_index++)
+ {
+ param_len_folder_name += p_rsp->p_folders[folder_index].str_len;
+ }
+ param_len = 10 + (p_rsp->folder_depth * 2) + param_len_folder_name; /* refer spec */
+
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->folder_depth);
+
+ for(folder_index = 0; folder_index < p_rsp->folder_depth; folder_index++)
+ {
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_folders[folder_index].str_len);
+ ARRAY_TO_BE_STREAM(p_data,p_rsp->p_folders[folder_index].p_str, \
+ p_rsp->p_folders[folder_index].str_len);
+ }
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("length = %d",p_pkt->len);
+ return AVRC_STS_NO_ERROR ;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_item_attrs_rsp
+**
+** Description This function builds the Get Item Attributes
+** response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_item_attrs_rsp (tAVRC_GET_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len;
+ UINT8 xx;
+
+ AVRC_TRACE_API("avrc_bld_get_item_attrs_rsp");
+ if (!p_rsp->p_attr_list)
+ {
+ AVRC_TRACE_ERROR("avrc_bld_get_item_attrs_rsp NULL parameter");
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+
+ param_len = 2; /* for status and num_attr*/
+ for(xx = 0; xx < p_rsp->attr_count; xx++)
+ {
+ /* 8 for attr_id, char_set_id, attr_value_len */
+ param_len = param_len + 8 + p_rsp->p_attr_list[xx].name.str_len;
+ }
+ AVRC_TRACE_API(" param_len = %d ", param_len);
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->attr_count);
+
+ for (xx=0; xx < p_rsp->attr_count; xx++)
+ {
+ if ( !p_rsp->p_attr_list[xx].name.p_str )
+ {
+ p_rsp->p_attr_list[xx].name.str_len = 0;
+ }
+ UINT32_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.p_str, \
+ p_rsp->p_attr_list[xx].name.str_len);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/**************************************************************************************
+**
+** Function avrc_bld_change_path_rsp
+**
+** Description
+**
+** Returns
+**
+************************************************************************************/
+static tAVRC_STS avrc_bld_tot_num_items_rsp (tAVRC_GET_TOT_ITEMS_RSP *p_rsp, BT_HDR *p_pkt )
+{
+ UINT8 *p_data, *p_start;
+ UINT16 param_len; /* parameter length field of Rsp */
+
+ AVRC_TRACE_DEBUG("avrc_bld_tot_num_items_rsp offset :x%x", p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->pdu);
+ param_len = 7; /* refer spec */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("length = %d", p_pkt->len);
+ return AVRC_STS_NO_ERROR;
+}
+
+
/*******************************************************************************
**
** Function avrc_bld_rejected_rsp
@@ -799,6 +1092,34 @@
/*******************************************************************************
**
+** Function avrc_bld_browse_rejected_rsp
+**
+** Description This function builds the Browse Reject response.
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_browse_rejected_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ UINT8 *p_data, *p_start;
+
+ AVRC_TRACE_API("avrc_bld_browse_rejected_rsp: status=%d, pdu:x%x, offset=%d", p_rsp->status,
+ p_rsp->pdu, p_pkt->offset);
+
+ p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start;
+ *p_data++ = p_rsp->pdu;
+
+ UINT16_TO_BE_STREAM(p_data, 1); //Parameter length
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = p_data - p_start;
+ AVRC_TRACE_DEBUG("Browse rejected rsp length=%d", p_pkt->len);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
** Function avrc_bld_init_rsp_buffer
**
** Description This function initializes the response buffer based on PDU
@@ -990,5 +1311,115 @@
return status;
}
+/*******************************************************************************
+**
+** Function avrc_bld_init_browse_rsp_buffer
+**
+** Description This function initializes the response buffer based on PDU
+**
+** Returns NULL, if no GKI buffer or failure to build the message.
+** Otherwise, the GKI buffer that contains the initialized message.
+**
+*******************************************************************************/
+static BT_HDR *avrc_bld_init_browse_rsp_buffer(tAVRC_RESPONSE *p_rsp)
+{
+ UINT16 offset = AVCT_BROWSE_OFFSET;
+ UINT16 chnl = AVCT_DATA_BROWSE;
+ UINT16 len = BT_DEFAULT_BUFFER_SIZE;
+ BT_HDR *p_pkt = NULL;
+
+ AVRC_TRACE_API("avrc_bld_init_browse_rsp_buffer ");
+ /* allocate and initialize the buffer */
+ p_pkt = (BT_HDR *)osi_malloc(len);
+
+ if (p_pkt != NULL)
+ {
+ p_pkt->layer_specific = chnl;
+ p_pkt->event = AVRC_OP_BROWSE; /* Browsing Opcode */
+ p_pkt->offset = offset;
+ }
+ else
+ {
+ AVRC_TRACE_ERROR("### browse_rsp_buffer BUFF not allocated");
+ }
+ return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function AVRC_BldBrowseResponse
+**
+** Description This function builds the given AVRCP response to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldBrowseResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt)
+{
+ tAVRC_STS status = AVRC_STS_BAD_PARAM;
+ BT_HDR *p_pkt;
+ BOOLEAN alloc = FALSE;
+
+ if (!p_rsp || !pp_pkt)
+ {
+ AVRC_TRACE_ERROR("### BldResponse error p_rsp=%p, pp_pkt=%p",
+ p_rsp, pp_pkt);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ if (*pp_pkt == NULL)
+ {
+ if ((*pp_pkt = avrc_bld_init_browse_rsp_buffer(p_rsp)) == NULL)
+ {
+ AVRC_TRACE_ERROR("### BldResponse: Failed to initialize response buffer");
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ alloc = TRUE;
+ }
+ status = AVRC_STS_NO_ERROR;
+ p_pkt = *pp_pkt;
+
+ AVRC_TRACE_API("BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status);
+ if (p_rsp->rsp.status != AVRC_STS_NO_ERROR)
+ {
+ AVRC_TRACE_ERROR("###ERROR AVRC_BldBrowseResponse");
+ return (avrc_bld_browse_rejected_rsp(&p_rsp->rsp, p_pkt));
+ }
+
+ switch (p_rsp->pdu)
+ {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ status = avrc_bld_folder_item_values_rsp(&p_rsp->get_items, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ status = avrc_bld_set_browse_player_rsp(&p_rsp->br_player, p_pkt);
+ break;
+
+ case AVRC_PDU_CHANGE_PATH:
+ status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS:
+ status = avrc_bld_tot_num_items_rsp(&p_rsp->get_tot_items, p_pkt);
+ break;
+
+ default :
+ break;
+ }
+ if (alloc && (status != AVRC_STS_NO_ERROR) )
+ {
+ osi_free_and_reset((void **)&p_pkt);
+ *pp_pkt = NULL;
+ AVRC_TRACE_ERROR("### error status:%d",status);
+ }
+ return status;
+}
#endif /* (AVRC_METADATA_INCLUDED == TRUE)*/
diff --git a/stack/avrc/avrc_int.h b/stack/avrc/avrc_int.h
index 36bb0c5..7c37300 100644
--- a/stack/avrc/avrc_int.h
+++ b/stack/avrc/avrc_int.h
@@ -42,6 +42,11 @@
/* Number of protocol elements in protocol element list. */
#define AVRC_NUM_PROTO_ELEMS 2
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+#define AVRC_NUM_ADDL_PROTO_ELEMS 2
+#else
+#define AVRC_NUM_ADDL_PROTO_ELEMS 1
+#endif
#ifndef AVRC_MIN_CMD_LEN
#define AVRC_MIN_CMD_LEN 20
diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
index 71e0e34..b5786ba 100644
--- a/stack/avrc/avrc_pars_ct.c
+++ b/stack/avrc/avrc_pars_ct.c
@@ -547,7 +547,7 @@
if (len < min_len) goto length_error;
BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
- BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+ BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p);
break;
default:
diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
index 820e99f..81eb9db 100644
--- a/stack/avrc/avrc_pars_tg.c
+++ b/stack/avrc/avrc_pars_tg.c
@@ -342,7 +342,31 @@
/* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
/* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ if (len != 2)
+ {
+ status = AVRC_STS_NOT_FOUND;
+ AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER: bad len");
+ }
+ else
+ {
+ BE_STREAM_TO_UINT16 (p_result->addr_player.player_id, p);
+ }
+ break;
+ case AVRC_PDU_PLAY_ITEM:
+ if (len != 11)
+ {
+ status = AVRC_STS_NOT_FOUND;
+ AVRC_TRACE_ERROR("AVRC_PDU_PLAY_ITEM: bad len");
+ }
+ else
+ {
+ BE_STREAM_TO_UINT8 (p_result->play_item.scope, p);
+ BE_STREAM_TO_UINT64(p_result->play_item.uid, p);
+ BE_STREAM_TO_UINT16 (p_result->play_item.uid_counter, p);
+ }
+ break;
default:
status = AVRC_STS_BAD_CMD;
break;
@@ -425,7 +449,7 @@
p_result->cmd.opcode = p_msg->hdr.opcode;
p_result->cmd.status = status;
}
- AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
+ BTIF_TRACE_IMP("AVRC_ParsCommand() return status:0x%x", status);
return status;
}
diff --git a/stack/avrc/avrc_sdp.c b/stack/avrc/avrc_sdp.c
index da26523..0a71f21 100644
--- a/stack/avrc/avrc_sdp.c
+++ b/stack/avrc/avrc_sdp.c
@@ -42,6 +42,21 @@
tAVRC_CB avrc_cb;
#endif
+#if (defined(AVCT_COVER_ART_INCLUDED) && (AVCT_COVER_ART_INCLUDED == TRUE))
+#define AVCT_CA_PSM 0X1021
+#endif
+
+/* Fix for below klockwork issue.
+ * Address of a local variable is returned through formal argument 'p_db->p_attrs' in
+ * API AVRC_FindService, removed local declaration and defined globally */
+UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_PROVIDER_NAME};
+/* update AVRC_NUM_PROTO_ELEMS if this constant is changed */
+
/******************************************************************************
**
** Function avrc_sdp_cback
@@ -112,13 +127,6 @@
{
tSDP_UUID uuid_list;
BOOLEAN result = TRUE;
- UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
- ATTR_ID_PROTOCOL_DESC_LIST,
- ATTR_ID_BT_PROFILE_DESC_LIST,
- ATTR_ID_SERVICE_NAME,
- ATTR_ID_SUPPORTED_FEATURES,
- ATTR_ID_PROVIDER_NAME};
-
AVRC_TRACE_API("AVRC_FindService uuid: %x", service_uuid);
if( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
@@ -235,20 +243,32 @@
(tSDP_PROTOCOL_ELEM *)avrc_proto_desc_list);
/* additional protocal descriptor, required only for version > 1.3 */
- if ((profile_version > AVRC_REV_1_3) && (browse_supported))
+ if ((profile_version > AVRC_REV_1_3 ) && (browse_supported))
{
- tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list;
- avrc_add_proto_desc_list.num_elems = 2;
- avrc_add_proto_desc_list.list_elem[0].num_params = 1;
- avrc_add_proto_desc_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
- avrc_add_proto_desc_list.list_elem[0].params[0] = AVCT_BR_PSM;
- avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
- avrc_add_proto_desc_list.list_elem[1].num_params = 1;
- avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
- avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
- avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
+ tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list[AVRC_NUM_ADDL_PROTO_ELEMS];
+ avrc_add_proto_desc_list[0].num_elems = 2;
+ avrc_add_proto_desc_list[0].list_elem[0].num_params = 1;
+ avrc_add_proto_desc_list[0].list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ avrc_add_proto_desc_list[0].list_elem[0].params[0] = AVCT_BR_PSM;
+ avrc_add_proto_desc_list[0].list_elem[0].params[1] = 0;
+ avrc_add_proto_desc_list[0].list_elem[1].num_params = 1;
+ avrc_add_proto_desc_list[0].list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
+ avrc_add_proto_desc_list[0].list_elem[1].params[0] = AVCT_REV_1_4;
+ avrc_add_proto_desc_list[0].list_elem[1].params[1] = 0;
+ for (index = 1; index < AVRC_NUM_ADDL_PROTO_ELEMS; index++)
+ {
+ avrc_add_proto_desc_list[index].num_elems = 2;
+ avrc_add_proto_desc_list[index].list_elem[0].num_params = 1;
+ avrc_add_proto_desc_list[index].list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ avrc_add_proto_desc_list[index].list_elem[0].params[0] = AVCT_CA_PSM;
+ avrc_add_proto_desc_list[index].list_elem[0].params[1] = 0;
+ avrc_add_proto_desc_list[index].list_elem[1].num_params = 0;
+ avrc_add_proto_desc_list[index].list_elem[1].protocol_uuid = UUID_PROTOCOL_OBEX;
+ avrc_add_proto_desc_list[index].list_elem[1].params[0] = 0;
+ avrc_add_proto_desc_list[index].list_elem[1].params[1] = 0;
- result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)&avrc_add_proto_desc_list);
+ }
+ result &= SDP_AddAdditionProtoLists( sdp_handle, AVRC_NUM_ADDL_PROTO_ELEMS, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_desc_list);
}
/* add profile descriptor list */
result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, profile_version);
diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
index 4819012..481a6ce 100644
--- a/stack/btm/btm_acl.c
+++ b/stack/btm/btm_acl.c
@@ -47,7 +47,7 @@
#include "l2c_int.h"
#include "hcidefs.h"
#include "bt_utils.h"
-
+#include "device/include/interop_config.h"
extern fixed_queue_t *btu_general_alarm_queue;
@@ -217,7 +217,7 @@
tACL_CONN *p;
UINT8 xx;
- BTM_TRACE_DEBUG ("btm_acl_created hci_handle=%d link_role=%d transport=%d",
+ BTM_TRACE_WARNING ("btm_acl_created hci_handle=%d link_role=%d transport=%d",
hci_handle,link_role, transport);
/* Ensure we don't have duplicates */
p = btm_bda_to_acl(bda, transport);
@@ -257,6 +257,7 @@
#endif
#endif
+ p->switch_role_failed_attempts = 0;
p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
btm_pm_sm_alloc(xx);
@@ -271,7 +272,6 @@
/* if BR/EDR do something more */
if (transport == BT_TRANSPORT_BR_EDR)
{
- btsnd_hcic_read_rmt_clk_offset (p->hci_handle);
btsnd_hcic_rmt_ver_req (p->hci_handle);
}
p_dev_rec = btm_find_dev_by_handle (hci_handle);
@@ -328,11 +328,7 @@
btm_establish_continue(p);
}
}
- else
#endif
- {
- btm_read_remote_features (p->hci_handle);
- }
/* read page 1 - on rmt feature event for buffer reasons */
return;
@@ -498,48 +494,53 @@
void btm_acl_update_busy_level (tBTM_BLI_EVENT event)
{
tBTM_BL_UPDATE_DATA evt;
- UINT8 busy_level;
+ UINT8 busy_level = btm_cb.busy_level;
BTM_TRACE_DEBUG ("btm_acl_update_busy_level");
BOOLEAN old_inquiry_state = btm_cb.is_inquiry;
+ /*Initialize busy_level_flags to 0*/
+ evt.busy_level_flags = 0;
switch (event)
{
case BTM_BLI_ACL_UP_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_ACL_UP_EVT");
+ busy_level = BTM_GetNumAclLinks();
break;
case BTM_BLI_ACL_DOWN_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_ACL_DOWN_EVT");
+ busy_level = BTM_GetNumAclLinks();
break;
case BTM_BLI_PAGE_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_PAGE_EVT");
btm_cb.is_paging = TRUE;
evt.busy_level_flags= BTM_BL_PAGING_STARTED;
+ busy_level = BTM_BL_PAGING_STARTED;
break;
case BTM_BLI_PAGE_DONE_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_PAGE_DONE_EVT");
btm_cb.is_paging = FALSE;
evt.busy_level_flags = BTM_BL_PAGING_COMPLETE;
+ busy_level = BTM_BL_PAGING_COMPLETE;
break;
case BTM_BLI_INQ_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_INQ_EVT");
btm_cb.is_inquiry = TRUE;
evt.busy_level_flags = BTM_BL_INQUIRY_STARTED;
+ busy_level = BTM_BL_INQUIRY_STARTED;
break;
case BTM_BLI_INQ_CANCEL_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_INQ_CANCEL_EVT");
btm_cb.is_inquiry = FALSE;
evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED;
+ busy_level = BTM_BL_INQUIRY_COMPLETE;
break;
case BTM_BLI_INQ_DONE_EVT:
BTM_TRACE_DEBUG ("BTM_BLI_INQ_DONE_EVT");
btm_cb.is_inquiry = FALSE;
evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
+ busy_level = BTM_BL_INQUIRY_COMPLETE;
break;
}
- if (btm_cb.is_paging || btm_cb.is_inquiry)
- busy_level = 10;
- else
- busy_level = BTM_GetNumAclLinks();
if ((busy_level != btm_cb.busy_level) ||(old_inquiry_state != btm_cb.is_inquiry))
{
@@ -576,6 +577,10 @@
/* Get the current role */
*p_role = p->link_role;
+ BTM_TRACE_WARNING ("BTM: Local device role : 0x%02x", *p_role );
+ BTM_TRACE_WARNING ("BTM: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2], remote_bd_addr[3],
+ remote_bd_addr[4], remote_bd_addr[5]);
return(BTM_SUCCESS);
}
@@ -610,12 +615,9 @@
#if (BT_USE_TRACES == TRUE)
BD_ADDR_PTR p_bda;
#endif
- BTM_TRACE_API ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x",
- remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
- remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
- /* Make sure the local device supports switching */
- if (!controller_get_interface()->supports_master_slave_role_switch())
+ /* Make sure the local/remote devices supports switching */
+ if (!btm_dev_support_switch(remote_bd_addr))
return(BTM_MODE_UNSUPPORTED);
if (btm_cb.devcb.p_switch_role_cb && p_cb)
@@ -632,8 +634,10 @@
if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
return(BTM_UNKNOWN_ADDR);
+ bt_bdaddr_t remote_address;
+ bdcpy(remote_address.address, remote_bd_addr);
/* Finished if already in desired role */
- if (p->link_role == new_role)
+ if ((p->link_role == new_role) || (interop_database_match_addr(INTEROP_DISABLE_ROLE_SWITCH, (bt_bdaddr_t *)&remote_address)))
return(BTM_SUCCESS);
#if BTM_SCO_INCLUDED == TRUE
@@ -652,6 +656,32 @@
return(BTM_BUSY);
}
+ if (interop_database_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH, (bt_bdaddr_t *)&remote_address))
+ {
+#if (defined(BTM_SAFE_REATTEMPT_ROLE_SWITCH) && BTM_SAFE_REATTEMPT_ROLE_SWITCH == TRUE)
+ p_dev_rec = btm_find_dev (remote_bd_addr);
+ if(!p_dev_rec || (p_dev_rec->switch_role_attempts >= BTM_MAX_BL_SW_ROLE_ATTEMPTS))
+ {
+ BTM_TRACE_DEBUG (" Below device is Blacklisted ....");
+ BTM_TRACE_DEBUG (" SwitchRole can't be initiated for 0x%02x%02x%02x%02x%02x%02x",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+ return BTM_REPEATED_ATTEMPTS;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG (" Device blacklisted, trying for role change again");
+ p_dev_rec->switch_role_attempts++;
+ }
+#else
+ BTM_TRACE_DEBUG (" Below device is Blacklisted ....");
+ BTM_TRACE_DEBUG (" SwitchRole can't be initiated for 0x%02x%02x%02x%02x%02x%02x",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+ return BTM_REPEATED_ATTEMPTS;
+#endif
+ }
+
if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS)
return(status);
@@ -709,6 +739,10 @@
btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE;
btm_cb.devcb.p_switch_role_cb = p_cb;
}
+ BTM_TRACE_WARNING ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+ BTM_TRACE_WARNING ("Requested New Role: %d", new_role)
return(BTM_CMD_STARTED);
}
@@ -735,10 +769,15 @@
handle, status, encr_enable);
xx = btm_handle_to_acl_index(handle);
/* don't assume that we can never get a bad hci_handle */
- if (xx < MAX_L2CAP_LINKS)
+ if (xx < MAX_L2CAP_LINKS) {
p = &btm_cb.acl_db[xx];
- else
+ } else {
+ GENERATE_VENDOR_LOGS();
return;
+ }
+
+ if (status != HCI_SUCCESS)
+ GENERATE_VENDOR_LOGS();
/* Process Role Switch if active */
if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF)
@@ -825,11 +864,19 @@
/* First, check if hold mode is supported */
if (*settings != HCI_DISABLE_ALL_LM_MODES)
{
+ bt_bdaddr_t remote_address;
+ bdcpy(remote_address.address, remote_bda);
if ( (*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures)) )
{
*settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
BTM_TRACE_API ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)", *settings );
}
+ if ( (*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) &&
+ (interop_database_match_addr(INTEROP_DISABLE_ROLE_SWITCH_POLICY, (bt_bdaddr_t *)&remote_address)) )
+ {
+ *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ BTM_TRACE_API ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)", *settings );
+ }
if ( (*settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)) )
{
*settings &= (~HCI_ENABLE_HOLD_MODE);
@@ -966,6 +1013,11 @@
STREAM_TO_UINT8 (p_acl_cb->lmp_version, p);
STREAM_TO_UINT16 (p_acl_cb->manufacturer, p);
STREAM_TO_UINT16 (p_acl_cb->lmp_subversion, p);
+ if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR)
+ {
+ BTM_TRACE_DEBUG("Calling btm_read_remote_features");
+ btm_read_remote_features (p_acl_cb->hci_handle);
+ }
}
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
@@ -974,12 +1026,16 @@
btm_use_preferred_conn_params(p_acl_cb->remote_addr);
}
#endif // (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+ BTM_TRACE_WARNING ("btm_read_remote_version_complete: BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ p_acl_cb->remote_addr[0], p_acl_cb->remote_addr[1], p_acl_cb->remote_addr[2],
+ p_acl_cb->remote_addr[3], p_acl_cb->remote_addr[4], p_acl_cb->remote_addr[5]);
+ BTM_TRACE_WARNING ("btm_read_remote_version_complete lmp_version %d manufacturer %d lmp_subversion %d",
+ p_acl_cb->lmp_version,p_acl_cb->manufacturer, p_acl_cb->lmp_subversion);
break;
}
}
}
-
/*******************************************************************************
**
** Function btm_process_remote_ext_features
@@ -995,6 +1051,7 @@
UINT16 handle = p_acl_cb->hci_handle;
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
UINT8 page_idx;
+ UINT8 status;
BTM_TRACE_DEBUG ("btm_process_remote_ext_features");
@@ -1020,6 +1077,12 @@
HCI_FEATURE_BYTES_PER_PAGE);
}
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator)
+ {
+ BTM_TRACE_DEBUG ("Calling Next Security Procedure");
+ if ((status = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event (p_dev_rec, status , FALSE);
+ }
const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
/* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
@@ -1266,24 +1329,28 @@
BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
}
#endif
- p_acl_cb->link_up_issued = TRUE;
-
- /* If anyone cares, tell him database changed */
- if (btm_cb.p_bl_changed_cb)
+ if(p_acl_cb->link_up_issued == FALSE)
{
- evt_data.event = BTM_BL_CONN_EVT;
- evt_data.conn.p_bda = p_acl_cb->remote_addr;
- evt_data.conn.p_bdn = p_acl_cb->remote_name;
- evt_data.conn.p_dc = p_acl_cb->remote_dc;
- evt_data.conn.p_features = p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0];
+
+ p_acl_cb->link_up_issued = TRUE;
+
+ /* If anyone cares, tell him database changed */
+ if (btm_cb.p_bl_changed_cb)
+ {
+ evt_data.event = BTM_BL_CONN_EVT;
+ evt_data.conn.p_bda = p_acl_cb->remote_addr;
+ evt_data.conn.p_bdn = p_acl_cb->remote_name;
+ evt_data.conn.p_dc = p_acl_cb->remote_dc;
+ evt_data.conn.p_features = p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0];
#if BLE_INCLUDED == TRUE
- evt_data.conn.handle = p_acl_cb->hci_handle;
- evt_data.conn.transport = p_acl_cb->transport;
+ evt_data.conn.handle = p_acl_cb->hci_handle;
+ evt_data.conn.transport = p_acl_cb->transport;
#endif
- (*btm_cb.p_bl_changed_cb)(&evt_data);
- }
- btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+ btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);
+ }
}
@@ -1478,6 +1545,59 @@
/*******************************************************************************
**
+** Function btm_blacklist_role_change_device
+**
+** Description This function is used to blacklist the device if the role
+** switch fails for maximum number of times. It also removes
+** the device from black list if the role switch succedes.
+
+** Input Parms bd_addr - remote BD addr
+** hci_status - role switch status
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_blacklist_role_change_device (BD_ADDR bd_addr, UINT8 hci_status)
+{
+ tACL_CONN *p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ UINT32 cod = 0;
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, bd_addr);
+
+ if(!p || !p_dev_rec)
+ {
+ return;
+ }
+ cod = (p_dev_rec->dev_class[2]) | (p_dev_rec->dev_class[1] << 8) |
+ (p_dev_rec->dev_class[0] << 16);
+
+ /* check for carkits */
+ if ((hci_status != HCI_SUCCESS) &&
+ ((p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) ||
+ (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)) &&
+ ((cod & COD_AUDIO_DEVICE) == COD_AUDIO_DEVICE) &&
+ (!interop_database_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH, (bt_bdaddr_t *)&remote_bdaddr)))
+ {
+ p->switch_role_failed_attempts++;
+ if(p->switch_role_failed_attempts == BTM_MAX_SW_ROLE_FAILED_ATTEMPTS)
+ {
+ BTM_TRACE_WARNING ("btm_blacklist_device: BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ interop_database_add_addr(INTEROP_DYNAMIC_ROLE_SWITCH, (bt_bdaddr_t *)&remote_bdaddr, 3);
+ }
+ }
+ else if(hci_status == HCI_SUCCESS)
+ {
+#if (defined(BTM_SAFE_REATTEMPT_ROLE_SWITCH) && BTM_SAFE_REATTEMPT_ROLE_SWITCH == TRUE)
+ interop_database_remove_addr(INTEROP_DYNAMIC_ROLE_SWITCH, (bt_bdaddr_t *)&remote_bdaddr);
+#endif
+ p->switch_role_failed_attempts = 0;
+ }
+}
+
+/*******************************************************************************
+**
** Function btm_acl_role_changed
**
** Description This function is called whan a link's master/slave role change
@@ -1498,12 +1618,17 @@
tBTM_BL_ROLE_CHG_DATA evt;
BTM_TRACE_DEBUG ("btm_acl_role_changed");
+ BTM_TRACE_WARNING ("btm_acl_role_changed: BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+ BTM_TRACE_WARNING ("btm_acl_role_changed: New role: %d", new_role);
/* Ignore any stray events */
if (p == NULL)
{
/* it could be a failure */
if (hci_status != HCI_SUCCESS)
btm_acl_report_role_change(hci_status, bd_addr);
+
+ GENERATE_VENDOR_LOGS();
return;
}
@@ -1526,6 +1651,7 @@
else
{
/* so the BTM_BL_ROLE_CHG_EVT uses the old role */
+ GENERATE_VENDOR_LOGS();
new_role = p->link_role;
}
@@ -1629,7 +1755,7 @@
/* Make sure we don't exceed max port range.
* Stack reserves scn 1 for HFP, HSP we still do the correct way.
*/
- if ( (scn>=BTM_MAX_SCN) || (scn == 1) )
+ if ( (scn>=BTM_MAX_SCN) || (scn <= 1) )
return FALSE;
/* check if this port is available */
@@ -1654,7 +1780,7 @@
BOOLEAN BTM_FreeSCN(UINT8 scn)
{
BTM_TRACE_DEBUG ("BTM_FreeSCN ");
- if (scn <= BTM_MAX_SCN)
+ if (scn <= BTM_MAX_SCN && scn > 0)
{
btm_cb.btm_scn[scn-1] = FALSE;
return(TRUE);
@@ -2253,10 +2379,12 @@
*******************************************************************************/
void btm_read_rssi_timeout(UNUSED_ATTR void *data)
{
+ tBTM_RSSI_RESULTS results;
tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+ results.status = BTM_DEVICE_TIMEOUT;
if (p_cb)
- (*p_cb)((void *) NULL);
+ (*p_cb)(&results);
}
/*******************************************************************************
@@ -2620,6 +2748,7 @@
{
tBTM_BL_EVENT_DATA evt_data;
+ GENERATE_VENDOR_LOGS();
/* Report possible collision to the upper layer. */
if (btm_cb.p_bl_changed_cb)
{
diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
index fe44525..04f800c 100644
--- a/stack/btm/btm_ble.c
+++ b/stack/btm/btm_ble.c
@@ -33,6 +33,7 @@
#include "bt_types.h"
#include "bt_utils.h"
+#include "btif/include/btif_storage.h"
#include "btm_ble_api.h"
#include "btm_int.h"
#include "btu.h"
@@ -121,6 +122,37 @@
/*******************************************************************************
**
+** Function BTM_GetRemoteDeviceName
+**
+** Description This function is called to get the dev name of remote device
+** from NV
+**
+** Returns TRUE if success; otherwise failed.
+**
+*******************************************************************************/
+BOOLEAN BTM_GetRemoteDeviceName(BD_ADDR bda, BD_NAME bd_name)
+{
+ BTM_TRACE_DEBUG("%s", __func__);
+ BOOLEAN ret = FALSE;
+ bt_bdname_t bdname;
+ bt_property_t prop_name;
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, bda);
+
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(
+ &bd_addr, &prop_name) == BT_STATUS_SUCCESS)
+ {
+ APPL_TRACE_DEBUG("%s, NV name = %s", __func__, bdname.name);
+ strlcpy((char*) bd_name, (char*) bdname.name, BD_NAME_LEN);
+ ret = TRUE;
+ }
+ return ret;
+}
+
+/*******************************************************************************
+**
** Function BTM_SecAddBleKey
**
** Description Add/modify LE device information. This function will be
@@ -756,6 +788,31 @@
/*******************************************************************************
**
+** Function BTM_BleEnhReceiverTest
+**
+** Description This function is called to start the LE Enhanced Receiver
+** test
+**
+** Parameter rx_freq - Frequency Range
+** phy - Phy to be used
+** mod_index - Modulation index
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleEnhReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 mod_index,
+ tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+ if (btsnd_hcic_ble_enh_receiver_test(rx_freq, phy, mod_index) == FALSE)
+ {
+ BTM_TRACE_ERROR("%s: Unable to Trigger LE Enhanced receiver test",
+ __FUNCTION__);
+ }
+}
+
+/*******************************************************************************
+**
** Function BTM_BleTransmitterTest
**
** Description This function is called to start the LE Transmitter test
@@ -778,6 +835,32 @@
/*******************************************************************************
**
+** Function BTM_BleEnhTransmitterTest
+**
+** Description This function is called to start the LE Enhanced Transmitter test
+**
+** Parameter tx_freq - Frequency Range
+** test_data_len - Length in bytes of payload data in each packet
+** packet_payload - Pattern to use in the payload
+** phy - Phy to be used
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleEnhTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
+ UINT8 packet_payload, UINT8 phy,
+ tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+ if (btsnd_hcic_ble_enh_transmitter_test(tx_freq, test_data_len,
+ packet_payload, phy) == FALSE)
+ {
+ BTM_TRACE_ERROR("%s: Unable to Trigger LE Enhanced transmitter test",
+ __FUNCTION__);
+ }
+}
+
+/*******************************************************************************
+**
** Function BTM_BleTestEnd
**
** Description This function is called to stop the in-progress TX or RX test
@@ -854,6 +937,8 @@
tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length)
{
tACL_CONN *p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+ UINT16 tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY;
+
BTM_TRACE_DEBUG("%s: tx_pdu_length =%d", __FUNCTION__, tx_pdu_length);
if (!controller_get_interface()->supports_ble_packet_extension())
@@ -875,9 +960,11 @@
else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN)
tx_pdu_length = BTM_BLE_DATA_SIZE_MIN;
+ if (controller_get_interface()->get_bt_version()->hci_version >= HCI_PROTO_VERSION_5_0)
+ tx_time = BTM_BLE_DATA_TX_TIME_MAX;
+
/* always set the TxTime to be max, as controller does not care for now */
- btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
- BTM_BLE_DATA_TX_TIME_MAX);
+ btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length, tx_time);
return BTM_SUCCESS;
}
@@ -979,6 +1066,47 @@
/*******************************************************************************
**
+** Function BTM_SetBlePhy
+**
+** Description This function is to set BLE tx and rx PHY
+**
+** Returns BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetBlePhy(BD_ADDR bd_addr, UINT8 all_phy, UINT8 tx_phy,
+ UINT8 rx_phy, UINT16 phy_options)
+{
+ tACL_CONN *p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+ BTM_TRACE_DEBUG("%s: all_phy=0x%0x, tx_phy=0x%0x, rx_phy=0x%0x",
+ __func__, all_phy, tx_phy, rx_phy);
+
+ if (!controller_get_interface()->supports_ble_two_mbps_rate())
+ {
+ BTM_TRACE_ERROR("%s failed, request not supported", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if ((p_acl != NULL) && (!HCI_LE_TWO_MBPS_SUPPORTED(p_acl->peer_le_features)))
+ {
+ BTM_TRACE_ERROR("%s failed, peer does not support request", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (p_acl != NULL)
+ {
+ btsnd_hcic_ble_set_data_rate (p_acl->hci_handle, all_phy, tx_phy,
+ rx_phy, phy_options);
+ return BTM_SUCCESS;
+ }
+ else
+ {
+ BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",__func__);
+ return BTM_WRONG_MODE;
+ }
+}
+
+/*******************************************************************************
+**
** Function btm_ble_start_sec_check
**
** Description This function is to check and set the security required for
@@ -1053,6 +1181,30 @@
/*******************************************************************************
**
+** Function BTM_SetDefaultBlePhy
+**
+** Description This function is to set default BLE tx and rx PHY
+**
+** Returns BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDefaultBlePhy(UINT8 all_phy, UINT8 tx_phy, UINT8 rx_phy)
+{
+ BTM_TRACE_DEBUG("%s: all_phy=0x%0x, tx_phy=0x%0x, rx_phy=0x%0x",
+ __func__, all_phy, tx_phy, rx_phy);
+
+ if (!controller_get_interface()->supports_ble_two_mbps_rate())
+ {
+ BTM_TRACE_ERROR("%s failed, request not supported", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ btsnd_hcic_ble_set_default_data_rate (all_phy, tx_phy, rx_phy);
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
** Function btm_ble_rand_enc_complete
**
** Description This function is the callback functions for HCI_Rand command
@@ -1807,21 +1959,30 @@
** Returns void
**
*******************************************************************************/
-static void btm_ble_resolve_random_addr_on_conn_cmpl(void * p_rec, void *p_data)
+static void btm_ble_resolve_random_addr_on_conn_cmpl(void * p_rec, void *p_data, BOOLEAN extended)
{
UINT8 *p = (UINT8 *)p_data;
tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
- UINT8 role, bda_type;
+ UINT8 role, bda_type, sub_code;
UINT16 handle;
BD_ADDR bda;
+ BD_ADDR local_rpa, peer_rpa;
UINT16 conn_interval, conn_latency, conn_timeout;
BOOLEAN match = FALSE;
+ UNUSED(extended);
+ --p;
+ STREAM_TO_UINT8(sub_code, p);
++p;
STREAM_TO_UINT16 (handle, p);
STREAM_TO_UINT8 (role, p);
STREAM_TO_UINT8 (bda_type, p);
STREAM_TO_BDADDR (bda, p);
+ if (sub_code == BTM_BLE_ENHC_CONN_SUB_CODE)
+ {
+ STREAM_TO_BDADDR (local_rpa, p);
+ STREAM_TO_BDADDR (peer_rpa, p);
+ }
STREAM_TO_UINT16 (conn_interval, p);
STREAM_TO_UINT16 (conn_latency, p);
STREAM_TO_UINT16 (conn_timeout, p);
@@ -1975,7 +2136,7 @@
the device has been paired */
if (!match && BTM_BLE_IS_RESOLVE_BDA(bda))
{
- btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data);
+ btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data, FALSE);
}
else
#endif
@@ -1990,16 +2151,16 @@
l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
conn_latency, conn_timeout);
-#if (BLE_PRIVACY_SPT == TRUE)
- if (enhanced)
- {
- btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
-
- if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
- btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa, BLE_ADDR_RANDOM);
- }
-#endif
}
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (enhanced)
+ {
+ btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
+
+ if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
+ btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa, BLE_ADDR_RANDOM);
+ }
+#endif
}
else
{
@@ -2089,7 +2250,7 @@
(*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data);
}
- if (event == SMP_COMPLT_EVT)
+ if (event == SMP_COMPLT_EVT && !p_data->cmplt.smp_over_br)
{
p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec == NULL)
@@ -2129,6 +2290,7 @@
{
BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL");
l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+ GENERATE_VENDOR_LOGS();
}
#endif
@@ -2696,6 +2858,47 @@
}
}
+/*******************************************************************************
+**
+** Function btm_ble_set_random_address
+**
+** Description This function set a random address to local controller.
+** It also temporarily disable scans and adv before sending
+** the command to the controller
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_random_address(BD_ADDR random_bda)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode;
+
+ BTM_TRACE_DEBUG ("%s", __func__);
+ if (btm_ble_get_conn_st() == BLE_DIR_CONN)
+ {
+ BTM_TRACE_ERROR("%s: Cannot set random address. Direct conn ongoing", __func__);
+ return;
+ }
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE)
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+ if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+ btm_ble_stop_scan();
+ btm_ble_suspend_bg_conn();
+
+ memcpy(p_cb->private_addr, random_bda, BD_ADDR_LEN);
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE)
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE);
+ if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+ btm_ble_start_scan();
+ btm_ble_resume_bg_conn();
+
+}
+
#if BTM_BLE_CONFORMANCE_TESTING == TRUE
/*******************************************************************************
**
@@ -2789,6 +2992,7 @@
btm_cb.devcb.keep_rfu_in_auth_req = keep_rfu;
}
+
#endif /* BTM_BLE_CONFORMANCE_TESTING */
#endif /* BLE_INCLUDED */
diff --git a/stack/btm/btm_ble_addr.c b/stack/btm/btm_ble_addr.c
index 81fff53..b1b7167 100644
--- a/stack/btm/btm_ble_addr.c
+++ b/stack/btm/btm_ble_addr.c
@@ -60,7 +60,7 @@
p_cb->private_addr[4] = p->param_buf[1];
p_cb->private_addr[3] = p->param_buf[2];
/* set it to controller */
- btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+ btm_ble_set_random_address(p_cb->private_addr);
p_cb->own_addr_type = BLE_ADDR_RANDOM;
@@ -356,7 +356,7 @@
** address is matched to.
**
*******************************************************************************/
-void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p)
+void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p, BOOLEAN extended)
{
tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
@@ -365,6 +365,7 @@
p_mgnt_cb->p = p;
p_mgnt_cb->busy = TRUE;
memcpy(p_mgnt_cb->random_bda, random_bda, BD_ADDR_LEN);
+ p_mgnt_cb->extended = extended;
/* start to resolve random address */
/* check for next security record */
@@ -374,9 +375,9 @@
BTM_TRACE_EVENT("%s: %sresolved", __func__, (p_dev_rec == NULL ? "not " : ""));
p_mgnt_cb->busy = FALSE;
- (*p_cback)(p_dev_rec, p);
+ (*p_cback)(p_dev_rec, p, extended);
} else {
- (*p_cback)(NULL, p);
+ (*p_cback)(NULL, p, extended);
}
}
#endif
@@ -463,7 +464,8 @@
{
* p_static_addr_type = p_dev_rec->ble.static_addr_type;
memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
- if (controller_get_interface()->supports_ble_privacy())
+ if (controller_get_interface()->supports_ble_privacy() &&
+ !controller_get_interface()->supports_ble_extended_advertisements())
*p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
return TRUE;
}
diff --git a/stack/btm/btm_ble_bgconn.c b/stack/btm/btm_ble_bgconn.c
index 4d2e38a..3dd01bc 100644
--- a/stack/btm/btm_ble_bgconn.c
+++ b/stack/btm/btm_ble_bgconn.c
@@ -126,18 +126,32 @@
p_inq->sfp = scan_policy;
p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE ? BTM_BLE_SCAN_MODE_ACTI : p_inq->scan_type;
- if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
{
- btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
- (UINT16)scan_window,
- btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
- scan_policy);
+ btsnd_hcic_ble_set_extended_scan_params(1 /*LE 1M PHY*/, p_inq->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ (UINT16)scan_interval,
+ (UINT16)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ BTM_BLE_DEFAULT_SFP);
}
else
+#endif
{
- btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
- btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
- scan_policy);
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+ {
+ btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ scan_policy);
+ }
+ else
+ {
+ btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ scan_policy);
+ }
}
}
/*******************************************************************************
@@ -390,30 +404,61 @@
&& controller_get_interface()->supports_ble_privacy())
{
own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
- peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ if (!controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ }
}
#endif
-
- if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */
- scan_win, /* UINT16 scan_win */
- 0x01, /* UINT8 white_list */
- peer_addr_type, /* UINT8 addr_type_peer */
- dummy_bda, /* BD_ADDR bda_peer */
- own_addr_type, /* UINT8 addr_type_own */
- BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */
- BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */
- BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */
- BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */
- 0, /* UINT16 min_len */
- 0)) /* UINT16 max_len */
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
{
- /* start auto connection failed */
- exec = FALSE;
- p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+ if (!btsnd_hcic_ble_ext_create_ll_conn (1 /*LE 1M PHY*/, scan_int, /* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ 0x01, /* UINT8 white_list */
+ peer_addr_type, /* UINT8 addr_type_peer */
+ dummy_bda, /* BD_ADDR bda_peer */
+ own_addr_type, /* UINT8 addr_type_own */
+ BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */
+ BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */
+ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */
+ BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) /* UINT16 max_len */
+ {
+ /* start auto connection failed */
+ exec = FALSE;
+ p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+ }
+ else
+ {
+ btm_ble_set_conn_st (BLE_BG_CONN);
+ }
}
else
+#endif
{
- btm_ble_set_conn_st (BLE_BG_CONN);
+ if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ 0x01, /* UINT8 white_list */
+ peer_addr_type, /* UINT8 addr_type_peer */
+ dummy_bda, /* BD_ADDR bda_peer */
+ own_addr_type, /* UINT8 addr_type_own */
+ BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */
+ BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */
+ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */
+ BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) /* UINT16 max_len */
+ {
+ /* start auto connection failed */
+ exec = FALSE;
+ p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+ }
+ else
+ {
+ btm_ble_set_conn_st (BLE_BG_CONN);
+ }
}
}
else
@@ -472,27 +517,41 @@
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_PASS;
/* Process advertising packets only from devices in the white list */
- if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
{
- /* use passive scan by default */
- if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS,
- scan_int,
- scan_win,
- p_cb->addr_mgnt_cb.own_addr_type,
- SP_ADV_WL))
- {
- return FALSE;
- }
+ btsnd_hcic_ble_set_extended_scan_params(1 /*LE 1M PHY*/, BTM_BLE_SCAN_MODE_PASS, scan_int,
+ scan_win,
+ scan_int,
+ scan_win,
+ p_cb->addr_mgnt_cb.own_addr_type,
+ SP_ADV_WL);
}
else
+#endif
{
- if (!btm_ble_send_extended_scan_params(BTM_BLE_SCAN_MODE_PASS,
- scan_int,
- scan_win,
- p_cb->addr_mgnt_cb.own_addr_type,
- SP_ADV_WL))
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
{
- return FALSE;
+ /* use passive scan by default */
+ if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS,
+ scan_int,
+ scan_win,
+ p_cb->addr_mgnt_cb.own_addr_type,
+ SP_ADV_WL))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!btm_ble_send_extended_scan_params(BTM_BLE_SCAN_MODE_PASS,
+ scan_int,
+ scan_win,
+ p_cb->addr_mgnt_cb.own_addr_type,
+ SP_ADV_WL))
+ {
+ return FALSE;
+ }
}
}
@@ -506,8 +565,18 @@
#if BLE_PRIVACY_SPT == TRUE
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
- if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */
- return FALSE;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ if (!btsnd_hcic_ble_set_extended_scan_enable(TRUE,TRUE, 0, 0))
+ return FALSE;
+ }
+ else
+#endif
+ {
+ if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */
+ return FALSE;
+ }
/* mark up inquiry status flag */
p_cb->scan_activity |= BTM_LE_SELECT_CONN_ACTIVE;
@@ -701,6 +770,37 @@
}
/*******************************************************************************
**
+** Function btm_ble_dequeue_direct_conn_req
+**
+** Description This function dequeues the direct connection request
+**
+** Returns None.
+**
+*******************************************************************************/
+void btm_ble_dequeue_direct_conn_req(BD_ADDR rem_bda)
+{
+ if (fixed_queue_is_empty(btm_cb.ble_ctr_cb.conn_pending_q))
+ return;
+
+ list_t *list = fixed_queue_get_list(btm_cb.ble_ctr_cb.conn_pending_q);
+ for (const list_node_t *node = list_begin(list); node != list_end(list);
+ node = list_next(node)) {
+ tBTM_BLE_CONN_REQ *p_req = (tBTM_BLE_CONN_REQ *)list_node(node);
+ tL2C_LCB *p_lcb = (tL2C_LCB *)p_req->p_param;
+ if ((p_lcb == NULL) || (!p_lcb->in_use)) {
+ continue;
+ }
+ //If BD address matches
+ if (!memcmp (rem_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN)) {
+ fixed_queue_try_remove_from_queue(btm_cb.ble_ctr_cb.conn_pending_q, p_req);
+ l2cu_release_lcb((tL2C_LCB *)p_req->p_param);
+ osi_free((void *)p_req);
+ break;
+ }
+ }
+}
+/*******************************************************************************
+**
** Function btm_send_pending_direct_conn
**
** Description This function send the pending direct connection request in queue
diff --git a/stack/btm/btm_ble_gap.c b/stack/btm/btm_ble_gap.c
index 7fe3c99..7b4e750 100644
--- a/stack/btm/btm_ble_gap.c
+++ b/stack/btm/btm_ble_gap.c
@@ -38,6 +38,7 @@
#include "device/include/controller.h"
#include "gap_api.h"
#include "hcimsgs.h"
+#include "stack_config.h"
#if BLE_INCLUDED == TRUE
@@ -46,6 +47,7 @@
#include "gattdefs.h"
#include "l2c_int.h"
#include "osi/include/log.h"
+#include "osi/include/time.h"
#define BTM_BLE_NAME_SHORT 0x01
#define BTM_BLE_NAME_CMPL 0x02
@@ -66,13 +68,15 @@
static tBTM_BLE_CTRL_FEATURES_CBACK *p_ctrl_le_feature_rd_cmpl_cback = NULL;
#endif
+static tBTM_BLE_CTRL_FEATURES_CBACK *p_ext_adv_ctrl_le_feature_rd_cmpl_cback = NULL;
+
/*******************************************************************************
** Local functions
*******************************************************************************/
static void btm_ble_update_adv_flag(UINT8 flag);
-static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p);
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT16 evt_type, UINT8 *p, BOOLEAN extended);
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
- tBTM_BLE_ADV_DATA *p_data);
+ tBTM_BLE_ADV_DATA *p_data, UINT16 max_len);
static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb,
BD_ADDR_PTR p_peer_addr_ptr,
tBLE_ADDR_TYPE *p_peer_addr_type,
@@ -352,17 +356,21 @@
** Returns void
**
*******************************************************************************/
-tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration,
+tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT16 duration, UINT16 period,
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
{
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
tBTM_STATUS status = BTM_WRONG_MODE;
- UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
- UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+ UINT16 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+ UINT16 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
- BTM_TRACE_EVENT ("%s : scan_type:%d, %d, %d", __func__, btm_cb.btm_inq_vars.scan_type,
- p_inq->scan_interval, p_inq->scan_window);
+ p_inq->scan_duration = duration;
+ p_inq->scan_period = period;
+
+ BTM_TRACE_EVENT ("%s : scan_type:%d, scan_interval_phy1 ::%d, scan_window_phy1::%d scan_interval_phy2 ::%d, scan_window_phy2:: %d",
+ __func__, btm_cb.btm_inq_vars.scan_type,
+ scan_interval, scan_window, p_inq->scan_interval_coded, p_inq->scan_window_coded);
if (!controller_get_interface()->supports_ble())
return BTM_ILLEGAL_VALUE;
@@ -392,18 +400,32 @@
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
- if (cmn_ble_vsc_cb.extended_scan_support == 0)
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
{
- btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
- (UINT16)scan_window,
- btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
- BTM_BLE_DEFAULT_SFP);
+ btsnd_hcic_ble_set_extended_scan_params(p_inq->scan_phys, p_inq->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ p_inq->scan_interval_coded,
+ p_inq->scan_window_coded,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ BTM_BLE_DEFAULT_SFP);
}
else
+#endif
{
- btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
- btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
- BTM_BLE_DEFAULT_SFP);
+ if (cmn_ble_vsc_cb.extended_scan_support == 0)
+ {
+ btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ BTM_BLE_DEFAULT_SFP);
+ }
+ else
+ {
+ btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ BTM_BLE_DEFAULT_SFP);
+ }
}
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
@@ -558,8 +580,13 @@
btm_cb.cmn_ble_vsc_cb.adv_inst_max, btm_cb.cmn_ble_vsc_cb.rpa_offloading,
btm_cb.cmn_ble_vsc_cb.energy_support, btm_cb.cmn_ble_vsc_cb.extended_scan_support);
- if (BTM_BleMaxMultiAdvInstanceCount() > 0)
- btm_ble_multi_adv_init();
+ if ((btm_cb.cmn_ble_vsc_cb.adv_inst_max > 0)
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ &&
+ (controller_get_interface()->get_ble_adv_ext_size() == 0)
+#endif
+ )
+ btm_ble_multi_adv_init(btm_cb.cmn_ble_vsc_cb.adv_inst_max);
if (btm_cb.cmn_ble_vsc_cb.max_filter > 0)
btm_ble_adv_filter_init();
@@ -600,6 +627,25 @@
}
}
+/*******************************************************************************
+**
+** Function BTM_BleGetAdvExtCapabilities
+**
+** Description This function reads local LE features
+**
+** Parameters p_cmn_vsc_cb : Locala LE capability structure
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_BleGetAdvExtCapabilities(tBTM_BLE_ADV_EXT_CB *p_ble_adv_ext_cb)
+{
+ BTM_TRACE_DEBUG("BTM_BleGetAdvExtCapabilities");
+
+ if (NULL != p_ble_adv_ext_cb)
+ *p_ble_adv_ext_cb = btm_cb.ble_adv_ext_cb;
+}
+
/******************************************************************************
**
** Function BTM_BleReadControllerFeatures
@@ -634,6 +680,69 @@
return ;
}
+/******************************************************************************
+**
+** Function BTM_BleReadExtAdvControllerFeatures
+**
+** Description Reads BLE specific controller features
+**
+** Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when features are read
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_BleReadExtAdvControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_cback)
+{
+
+ BTM_TRACE_DEBUG("BTM_BleReadExtAdvControllerFeatures");
+
+ p_ext_adv_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ btm_ble_extended_configure_inst_size();
+ }
+#endif
+
+ return ;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_inst_length_complete
+**
+** Description This function is a callback event of read instance length
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btm_ble_read_inst_length_complete(UINT8* p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 inst_len;
+
+ UNUSED(evt_len);
+
+ STREAM_TO_UINT8 (status, p);
+
+ if (status != HCI_SUCCESS)
+ {
+ BTM_TRACE_ERROR ("%s, HCI command failure", __func__);
+ return;
+ }
+
+ STREAM_TO_UINT16 (inst_len, p);
+
+ BTM_TRACE_EVENT ("%s, status: %d, inst size = %d", __func__, status, inst_len);
+ btm_ble_update_multi_adv_inst_data_length(inst_len);
+
+ btm_cb.ble_adv_ext_cb.adv_inst_max = controller_get_interface()->get_ble_adv_ext_size();
+ btm_cb.ble_adv_ext_cb.adv_data_len_max = inst_len;
+ if (p_ext_adv_ctrl_le_feature_rd_cmpl_cback != NULL)
+ p_ext_adv_ctrl_le_feature_rd_cmpl_cback(status);
+}
+
/*******************************************************************************
**
** Function BTM_BleEnableMixedPrivacyMode
@@ -724,8 +833,13 @@
*******************************************************************************/
extern UINT8 BTM_BleMaxMultiAdvInstanceCount(void)
{
- return btm_cb.cmn_ble_vsc_cb.adv_inst_max < BTM_BLE_MULTI_ADV_MAX ?
- btm_cb.cmn_ble_vsc_cb.adv_inst_max : BTM_BLE_MULTI_ADV_MAX;
+ if (!controller_get_interface()->get_is_ready()) {
+ BTM_TRACE_ERROR("%s() controller interface not ready", __func__);
+ return 0;
+ }
+
+ return controller_get_interface()->get_ble_adv_ext_size() < BTM_BLE_MULTI_ADV_MAX ?
+ controller_get_interface()->get_ble_adv_ext_size() : BTM_BLE_MULTI_ADV_MAX;
}
#if BLE_PRIVACY_SPT == TRUE
@@ -738,17 +852,25 @@
** Returns void
**
*******************************************************************************/
-static void btm_ble_resolve_random_addr_on_adv(void * p_rec, void *p)
+static void btm_ble_resolve_random_addr_on_adv(void * p_rec, void *p, BOOLEAN extended)
{
tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
UINT8 addr_type = BLE_ADDR_RANDOM;
BD_ADDR bda;
UINT8 *pp = (UINT8 *)p + 1;
- UINT8 evt_type;
+ UINT16 evt_type;
BTM_TRACE_EVENT ("btm_ble_resolve_random_addr_on_adv ");
- STREAM_TO_UINT8 (evt_type, pp);
+ if(extended)
+ {
+ STREAM_TO_UINT16 (evt_type, pp);
+ }
+ else
+ {
+ STREAM_TO_UINT8 (evt_type, pp);
+ }
+
STREAM_TO_UINT8 (addr_type, pp);
STREAM_TO_BDADDR (bda, pp);
@@ -767,7 +889,7 @@
}
}
- btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp);
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp, extended);
return;
}
@@ -953,6 +1075,7 @@
tBTM_SEC_DEV_REC *p_dev_rec;
#endif
+ BTM_TRACE_EVENT ("%s connectable mode=0x%0x scan_rsp=0x%x", __FUNCTION__, p_cb->connectable_mode, p_cb->scan_rsp);
evt_type = (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE) ? \
((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT )\
: BTM_BLE_CONNECT_EVT;
@@ -1143,8 +1266,9 @@
** Returns void
**
*******************************************************************************/
-void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
- tBLE_SCAN_MODE scan_mode,
+void BTM_BleSetScanParams(tGATT_IF client_if, UINT8 scan_phys, UINT32 scan_interval,
+ UINT32 scan_window, UINT16 scan_interval_coded,
+ UINT16 scan_window_coded, tBLE_SCAN_MODE scan_mode,
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback)
{
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
@@ -1173,9 +1297,21 @@
(scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS))
{
p_cb->scan_type = scan_mode;
+ p_cb->scan_phys = scan_phys;
p_cb->scan_interval = scan_interval;
p_cb->scan_window = scan_window;
+ if(scan_interval_coded > 0 && scan_window_coded >0)
+ {
+ if(BTM_BLE_ISVALID_PARAM(scan_interval_coded, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
+ BTM_BLE_ISVALID_PARAM(scan_window_coded, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
+ (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS))
+ {
+ p_cb->scan_interval_coded = scan_interval_coded;
+ p_cb->scan_window_coded = scan_window_coded;
+ }
+ }
+
if (scan_setup_status_cback != NULL)
scan_setup_status_cback(client_if, BTM_SUCCESS);
}
@@ -1212,7 +1348,7 @@
return BTM_ILLEGAL_VALUE;
memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN);
- btm_ble_build_adv_data(&data_mask, &p, p_data);
+ btm_ble_build_adv_data(&data_mask, &p, p_data, BTM_BLE_AD_DATA_LEN);
if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data))
{
@@ -1255,7 +1391,7 @@
p = p_cb_data->ad_data;
p_cb_data->data_mask = data_mask;
- p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data);
+ p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data, BTM_BLE_AD_DATA_LEN);
p_cb_data->p_pad = p;
@@ -1287,7 +1423,7 @@
** Returns pointer of ADV data
**
*******************************************************************************/
-UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length)
+UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length, UINT16 adv_data_len)
{
UINT8 *p = p_adv;
UINT8 length;
@@ -1296,7 +1432,7 @@
STREAM_TO_UINT8(length, p);
- while ( length && (p - p_adv <= BTM_BLE_CACHE_ADV_DATA_MAX))
+ while ( length && (p - p_adv <= adv_data_len))
{
STREAM_TO_UINT8(adv_type, p);
@@ -1356,12 +1492,12 @@
** Description This function is called build the adv data and rsp data.
*******************************************************************************/
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
- tBTM_BLE_ADV_DATA *p_data)
+ tBTM_BLE_ADV_DATA *p_data, UINT16 max_len)
{
UINT32 data_mask = *p_data_mask;
UINT8 *p = *p_dst,
*p_flag = NULL;
- UINT16 len = BTM_BLE_AD_DATA_LEN, cp_len = 0;
+ UINT16 len = max_len, cp_len = 0;
UINT8 i = 0;
tBTM_BLE_PROP_ELEM *p_elem;
@@ -1884,8 +2020,13 @@
evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &peer_addr_type, &own_addr_type);
- if (mode == BTM_BLE_NON_CONNECTABLE && p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
- new_mode = BTM_BLE_ADV_DISABLE;
+ if (stack_config_get_interface()->get_pts_le_nonconn_adv_enabled())
+ {
+ if (combined_mode == BTM_BLE_ADV_STOP && p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+ else if (mode == BTM_BLE_NON_CONNECTABLE && p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
+ new_mode = BTM_BLE_ADV_DISABLE;
btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
@@ -1982,28 +2123,63 @@
if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
{
- btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
- BTM_BLE_LOW_LATENCY_SCAN_INT,
- BTM_BLE_LOW_LATENCY_SCAN_WIN,
- btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
- SP_ADV_ALL);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ btsnd_hcic_ble_set_extended_scan_params(0x01 /*LE 1M */,BTM_BLE_SCAN_MODE_ACTI,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ SP_ADV_ALL);
+ }
+ else
+#endif
+ {
+ btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ SP_ADV_ALL);
+ }
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
/* enable IRK list */
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
p_ble_cb->inq_var.scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
+ p_ble_cb->inq_var.scan_duration = 0;
+ p_ble_cb->inq_var.scan_period = 0;
status = btm_ble_start_scan();
}
else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
(p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params", __FUNCTION__);
- btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
- btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
- BTM_BLE_LOW_LATENCY_SCAN_INT,
- BTM_BLE_LOW_LATENCY_SCAN_WIN,
- btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
- SP_ADV_ALL);
- btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ btsnd_hcic_ble_set_extended_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE,0/*duration*/, 0/*period*/);
+ btsnd_hcic_ble_set_extended_scan_params(0x01 /*LE 1M */,BTM_BLE_SCAN_MODE_ACTI,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ SP_ADV_ALL);
+ btsnd_hcic_ble_set_extended_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE,0/*duration*/, 0/*period*/);
+ }
+ else
+#endif
+ {
+ btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ SP_ADV_ALL);
+ btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+ }
}
if (status == BTM_CMD_STARTED)
@@ -2287,44 +2463,52 @@
** Returns void
**
*******************************************************************************/
-BOOLEAN btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
+BOOLEAN btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT16 evt_type, BOOLEAN extended)
{
- tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
- UINT8 *p_cache;
- UINT8 length;
- UNUSED(p_cur);
+ tBTM_BLE_INQ_DATA_CB *p_le_inq_cb = &p_cur->inq_data;
+ UINT8 *p_adv_data_cache;
+ tBTM_BLE_INQ_CB *p_le_adv_data_cb = &btm_cb.ble_ctr_cb.inq_var;
- /* cache adv report/scan response data */
- if (evt_type != BTM_BLE_SCAN_RSP_EVT)
+ if(p_le_inq_cb->adv_len == 0)
{
- p_le_inq_cb->adv_len = 0;
- memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ //if evt type is Extended and Complete data, then allocate 255 bytes of adv data
+ if(extended && ((evt_type & BTM_BLE_EXT_LEGACY_ADV_MASK) == 0) &&
+ ((evt_type & BTM_BLE_EXT_ADV_EVT_DATA_MASK) == 0))
+ {
+ p_le_inq_cb->adv_data_cache = osi_calloc((sizeof(UINT8)) * (HCI_COMMAND_SIZE));
+ }
+ //if evt type is Extended and Incomplete data, then allocate controller's max supported bytes
+ else if(extended && ((evt_type & BTM_BLE_EXT_LEGACY_ADV_MASK) == 0) &&
+ ((evt_type & BTM_BLE_EXT_ADV_EVT_DATA_INCMPL_MASK) == BTM_BLE_EXT_ADV_EVT_DATA_INCMPL_MASK))
+ {
+ p_le_inq_cb->adv_data_cache = osi_calloc(sizeof(UINT8) * (btm_cb.ble_adv_ext_cb.adv_data_len_max));
+ }
+ else
+ {
+ p_le_inq_cb->adv_data_cache = osi_calloc((sizeof(UINT8)) * (BTM_BLE_CACHE_ADV_DATA_MAX));
+ }
+ }
+ else
+ p_le_inq_cb->adv_data_cache = p_le_adv_data_cb->adv_data_cache;
}
- if (data_len > 0)
+ /* cache adv report/scan response data ,check for only legacy adv's scan rsp evt*/
+ if (((!extended && (evt_type != BTM_BLE_SCAN_RSP_EVT)) ||
+ (extended && ((evt_type & BTM_BLE_EXT_LEGACY_ADV_MASK) == BTM_BLE_EXT_LEGACY_ADV_MASK) &&
+ ((evt_type & BTM_BLE_EXT_SCAN_RSP_EVT_MASK) != BTM_BLE_EXT_SCAN_RSP_EVT_MASK))))
{
- p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
- STREAM_TO_UINT8(length, p);
- while ( length && ((p_le_inq_cb->adv_len + length + 1) <= BTM_BLE_CACHE_ADV_DATA_MAX))
- {
- /* adv record size must be smaller than the total adv data size */
- if ((length + 1) > data_len) {
- BTM_TRACE_ERROR("BTM - got incorrect LE advertising data");
- android_errorWriteLog(0x534e4554, "33899337");
- return FALSE;
- }
- /* copy from the length byte & data into cache */
- memcpy(p_cache, p-1, length+1);
- /* reduce the total data size by size of data copied */
- data_len -= length + 1;
- /* advance the cache pointer past data */
- p_cache += length+1;
- /* increment cache length */
- p_le_inq_cb->adv_len += length+1;
- /* skip the length of data */
- p += length;
- STREAM_TO_UINT8(length, p);
- }
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_data_cache, 0, sizeof(UINT8) * (BTM_BLE_CACHE_ADV_DATA_MAX));
+ }
+
+ p_adv_data_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
+
+ if(data_len > 0)
+ {
+ p_le_inq_cb->adv_len += data_len;
+ memcpy(p_adv_data_cache, p, sizeof(UINT8) * data_len);
}
return TRUE;
@@ -2349,10 +2533,14 @@
UINT8 *p_flag, flag = 0, rt = 0;
UINT8 data_len;
tBTM_INQ_PARMS *p_cond = &btm_cb.btm_inq_vars.inqparms;
- tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_BLE_INQ_DATA_CB *p_le_inq_cb;
+ tINQ_DB_ENT *p_i;
UNUSED(p);
+ p_i = btm_inq_db_find (bda);
+ p_le_inq_cb = &p_i->inq_info.results.inq_data;
+
/* for observer, always "discoverable */
if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
rt |= BTM_BLE_OBS_RESULT;
@@ -2372,7 +2560,7 @@
if (p_le_inq_cb->adv_len != 0)
{
if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache,
- BTM_BLE_AD_TYPE_FLAG, &data_len)) != NULL)
+ BTM_BLE_AD_TYPE_FLAG, &data_len, p_le_inq_cb->adv_len)) != NULL)
{
flag = * p_flag;
@@ -2523,6 +2711,39 @@
/*******************************************************************************
**
+** Function btm_ble_is_adv_reportable
+**
+** Description Checks whether the adv event type is reportable to upper layers.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_is_adv_reportable(BOOLEAN extended, UINT16 evt_type)
+{
+ BOOLEAN to_report = TRUE;
+ if ((!extended && btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+ (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT)) ||
+ //Legacy adv in extended adv report, update only the scan response evt
+ (extended && btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+ ((evt_type & BTM_BLE_EXT_LEGACY_ADV_MASK) == BTM_BLE_EXT_LEGACY_ADV_MASK) &&
+ ((evt_type & BTM_BLE_EXT_SCAN_RSP_EVT_MASK) != BTM_BLE_EXT_SCAN_RSP_EVT_MASK)) ||
+ /*Non Legacy adv in extended adv report, update scan rsp evt,connectable only and
+ non connectable-non scannable adv evts */
+ (extended && btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+ ((evt_type & BTM_BLE_EXT_LEGACY_ADV_MASK) == 0) &&
+ ((evt_type & BTM_BLE_EXT_SCAN_RSP_EVT_MASK) != BTM_BLE_EXT_SCAN_RSP_EVT_MASK) &&
+ ((evt_type & BTM_BLE_EXT_CONN_ADV_MASK) != BTM_BLE_EXT_CONN_ADV_MASK) &&
+ (evt_type != 0)))
+ {
+ to_report = FALSE;
+ }
+ return to_report;
+}
+
+/*******************************************************************************
+**
** Function btm_ble_update_inq_result
**
** Description Update adv packet information into inquiry result.
@@ -2532,7 +2753,7 @@
** Returns void
**
*******************************************************************************/
-BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
+BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT16 evt_type, UINT8 *p, BOOLEAN extended)
{
BOOLEAN to_report = TRUE;
tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results;
@@ -2540,32 +2761,82 @@
UINT8 *p_flag;
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
UINT8 data_len, rssi;
- tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
UINT8 *p1;
UINT8 *p_uuid16;
+ UINT8 pri_phy, sec_phy, adv_sid, txpower, direct_addr_type;
+ UINT16 periodic_adv_int;
+ BD_ADDR direct_bda;
+ tBTM_BLE_INQ_DATA_CB *p_le_inq_cb = &p_cur->inq_data;
+ UINT8 *p_cache;
+ UINT8 length = 0;
+ UINT16 adv_data_size = 0;
+
+
+ BTM_TRACE_EVENT("btm_ble_update_inq_result evt_type= %d", evt_type);
+
+ if(extended)
+ {
+ STREAM_TO_UINT8 (pri_phy, p);
+ STREAM_TO_UINT8 (sec_phy, p);
+ STREAM_TO_UINT8 (adv_sid, p);
+ STREAM_TO_UINT8 (txpower, p);
+ STREAM_TO_UINT8 (rssi, p);
+ STREAM_TO_UINT16 (periodic_adv_int, p);
+ STREAM_TO_UINT8 (direct_addr_type, p);
+ STREAM_TO_BDADDR (direct_bda, p);
+ }
STREAM_TO_UINT8 (data_len, p);
- if (data_len > BTM_BLE_ADV_DATA_LEN_MAX)
+ if (!extended && (data_len > BTM_BLE_ADV_DATA_LEN_MAX))
{
- BTM_TRACE_WARNING("EIR data too long %d. discard", data_len);
+ BTM_TRACE_WARNING("EIR data too long for legacy adv %d. discard", data_len);
return FALSE;
}
- if (!btm_ble_cache_adv_data(p_cur, data_len, p, evt_type)) {
+ else if (extended && (data_len > btm_cb.ble_adv_ext_cb.adv_data_len_max))
+ {
+ BTM_TRACE_WARNING("Adv data too long for extended adv %d. discard", data_len);
return FALSE;
}
- p1 = (p + data_len);
- STREAM_TO_UINT8 (rssi, p1);
+ if(extended && ((evt_type & BTM_BLE_EXT_ADV_EVT_DATA_MASK) == BTM_BLE_EXT_ADV_EVT_DATA_INCMPL_TRUNC_MASK))
+ {
+ BTM_TRACE_WARNING("Adv data for extended adv is truncated:: discard");
+ p_le_inq_cb->adv_len = 0;
+ if (controller_get_interface()->supports_ble_extended_advertisements() && p_le_inq_cb->adv_data_cache)
+ {
+ osi_free_and_reset((void **)&p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_data_cache = NULL;
+ }
+
+ return FALSE;
+ }
+
+ if (!btm_ble_cache_adv_data(p_cur, data_len, p, evt_type, extended))
+ {
+ return FALSE;
+ }
+
+ if(!extended)
+ {
+ p1 = (p + data_len);
+ STREAM_TO_UINT8 (rssi, p1);
+ }
/* Save the info */
p_cur->inq_result_type = BTM_INQ_RESULT_BLE;
p_cur->ble_addr_type = addr_type;
p_cur->rssi = rssi;
+ p_cur->pri_phy = pri_phy;
+ p_cur->sec_phy = sec_phy;
+ p_cur->adv_sid = adv_sid;
+ p_cur->periodic_adv_int = periodic_adv_int;
+ p_cur->direct_addr_type = direct_addr_type;
+ memcpy(p_cur->direct_bda, direct_bda, BD_ADDR_LEN);
+
/* active scan, always wait until get scan_rsp to report the result */
- if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
- (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT)))
+ if (!btm_ble_is_adv_reportable(extended, evt_type))
{
BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\
scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type);
@@ -2580,14 +2851,38 @@
else
p_cur->device_type |= BT_DEVICE_TYPE_BLE;
- if (evt_type != BTM_BLE_SCAN_RSP_EVT)
+ if ((!extended && evt_type != BTM_BLE_SCAN_RSP_EVT) ||
+ (extended && ((evt_type & BTM_BLE_EXT_SCAN_RSP_EVT_MASK) != BTM_BLE_EXT_SCAN_RSP_EVT_MASK)))
p_cur->ble_evt_type = evt_type;
p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+ if(extended && ((evt_type & BTM_BLE_EXT_ADV_EVT_DATA_MASK) == BTM_BLE_EXT_ADV_EVT_DATA_INCMPL_MASK))
+ return FALSE;
+
+ /* Perform length check of each adv data */
+ if (p_le_inq_cb->adv_len > 0 && p_le_inq_cb->adv_data_cache)
+ {
+ p_cache = &p_le_inq_cb->adv_data_cache[0];
+
+ STREAM_TO_UINT8(length, p_cache);
+ while (length && ((adv_data_size + length + 1) <= p_le_inq_cb->adv_len))
+ {
+ adv_data_size += length+1;
+ p_cache += length;
+ if (adv_data_size < p_le_inq_cb->adv_len)
+ {
+ /* skip the length of data */
+ STREAM_TO_UINT8(length, p_cache);
+ }
+ }
+
+ p_le_inq_cb->adv_len = adv_data_size;
+ }
+
if (p_le_inq_cb->adv_len != 0)
{
- if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_FLAG, &len)) != NULL)
+ if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_FLAG, &len, p_le_inq_cb->adv_len)) != NULL)
p_cur->flag = * p_flag;
}
@@ -2597,7 +2892,7 @@
* then try to convert the appearance value to a class of device value Bluedroid can use.
* Otherwise fall back to trying to infer if it is a HID device based on the service class.
*/
- p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_APPEARANCE, &len);
+ p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_APPEARANCE, &len, p_le_inq_cb->adv_len);
if (p_uuid16 && len == 2)
{
btm_ble_appearance_to_cod((UINT16)p_uuid16[0] | (p_uuid16[1] << 8), p_cur->dev_class);
@@ -2605,7 +2900,7 @@
else
{
if ((p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache,
- BTM_BLE_AD_TYPE_16SRV_CMPL, &len)) != NULL)
+ BTM_BLE_AD_TYPE_16SRV_CMPL, &len, p_le_inq_cb->adv_len)) != NULL)
{
UINT8 i;
for (i = 0; i + 2 <= len; i = i + 2)
@@ -2625,7 +2920,8 @@
/* if BR/EDR not supported is not set, assume is a DUMO device */
if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0 &&
- evt_type != BTM_BLE_CONNECT_DIR_EVT)
+ ((!extended && evt_type != BTM_BLE_CONNECT_DIR_EVT) ||
+ (extended && ((evt_type & BTM_BLE_EXT_CONNECT_DIR_EVT_MASK) != BTM_BLE_EXT_CONNECT_DIR_EVT_MASK))))
{
if (p_cur->ble_addr_type != BLE_ADDR_RANDOM)
{
@@ -2696,10 +2992,10 @@
/* get the device name if exist in ADV data */
if (data_len != 0)
{
- p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_CMPL, &len);
+ p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_CMPL, &len, BTM_BLE_ADV_DATA_LEN_MAX);
if (p_dev_name == NULL)
- p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_SHORT, &len);
+ p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_SHORT, &len, BTM_BLE_ADV_DATA_LEN_MAX);
if (p_dev_name)
memcpy(remname, p_dev_name, len);
@@ -2714,6 +3010,26 @@
/*******************************************************************************
**
+** Function btm_ble_scan_timeout_evt
+**
+** Description This function is called when adv packet report events are
+** received from the device. It updates the inquiry database.
+** If the inquiry database is full, the oldest entry is discarded.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_scan_timeout_evt (void)
+{
+ BTM_TRACE_DEBUG("btm_ble_scan_timeout_evt:");
+
+}
+
+
+/*******************************************************************************
+**
** Function btm_ble_process_adv_pkt
**
** Description This function is called when adv packet report events are
@@ -2725,13 +3041,15 @@
** Returns void
**
*******************************************************************************/
-void btm_ble_process_adv_pkt (UINT8 *p_data)
+void btm_ble_process_adv_pkt (UINT8 *p_data, BOOLEAN extended)
{
BD_ADDR bda;
- UINT8 evt_type = 0, *p = p_data;
+ UINT8 *p = p_data;
UINT8 addr_type = 0;
UINT8 num_reports;
UINT8 data_len;
+ UINT16 evt_type=0;
+ UINT8 *p1;
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
BOOLEAN match = FALSE;
#endif
@@ -2746,10 +3064,19 @@
while (num_reports--)
{
/* Extract inquiry results */
- STREAM_TO_UINT8 (evt_type, p);
+ if(extended)
+ {
+ STREAM_TO_UINT16 (evt_type, p);
+ }
+ else
+ {
+ STREAM_TO_UINT8 (evt_type, p);
+ }
+
STREAM_TO_UINT8 (addr_type, p);
STREAM_TO_BDADDR (bda, p);
+ p1 = p;
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
/* map address to security record */
match = btm_identity_addr_to_random_pseudo(bda, &addr_type, FALSE);
@@ -2759,16 +3086,29 @@
/* always do RRA resolution on host */
if (!match && BTM_BLE_IS_RESOLVE_BDA(bda))
{
- btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data);
+ btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data, extended);
}
else
#endif
- btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p);
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p, extended);
- STREAM_TO_UINT8(data_len, p);
-
- /* Advance to the next event data_len + rssi byte */
- p += data_len + 1;
+ if(num_reports)
+ {
+ if(extended)
+ {
+ p1 += 14;
+ STREAM_TO_UINT8(data_len, p1);
+ p1 += data_len;
+ }
+ else
+ {
+ STREAM_TO_UINT8(data_len, p1);
+ /* Advance to the next event data_len + rssi byte */
+ p1 += data_len + 1;
+ }
+ p = p1;
+ p_data = p1;
+ }
}
}
@@ -2784,16 +3124,18 @@
** Returns void
**
*******************************************************************************/
-static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT16 evt_type, UINT8 *p, BOOLEAN extended)
{
tINQ_DB_ENT *p_i;
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
- tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_BLE_INQ_DATA_CB *p_le_inq_cb;
BOOLEAN update = TRUE;
UINT8 result = 0;
+ BTM_TRACE_EVENT("%s::bda::%02x%02x%02x%02x%02x%02x",__func__, bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]);
+
p_i = btm_inq_db_find (bda);
/* Check if this address has already been processed for this inquiry */
@@ -2822,6 +3164,9 @@
{
if ((p_i = btm_inq_db_new (bda)) != NULL)
{
+ p_le_inq_cb = &p_i->inq_info.results.inq_data;
+ p_le_inq_cb->adv_len = 0;
+
p_inq->inq_cmpl_info.num_resp++;
}
else
@@ -2831,14 +3176,19 @@
{
p_inq->inq_cmpl_info.num_resp++;
}
+ p_le_inq_cb = &p_i->inq_info.results.inq_data;
+
+ p_i->time_of_resp = time_get_os_boottime_ms();
+
/* update the LE device information in inquiry database */
- if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p))
+ if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p, extended))
return;
+
if ((result = btm_ble_is_discoverable(bda, evt_type, p)) == 0)
{
- LOG_WARN(LOG_TAG, "%s device is no longer discoverable so discarding advertising packet pkt",
- __func__);
+ LOG_WARN(LOG_TAG, "%s device is no longer discoverable so discarding advertising packet pkt",
+ __func__);
return;
}
if (!update)
@@ -2870,6 +3220,7 @@
if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
{
if (result & BTM_BLE_SEL_CONN_RESULT)
+ //TODO might need to take care of UINT16 evt_type in this callback.
btm_send_sel_conn_callback(bda, evt_type, p, addr_type);
else
{
@@ -2878,6 +3229,8 @@
}
else
{
+ p_i->inq_info.results.adv_data_len = p_le_inq_cb->adv_len;
+
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT))
{
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
@@ -2886,6 +3239,15 @@
{
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
}
+
+ //Deallocate memory for adv data cache
+ if(controller_get_interface()->supports_ble_extended_advertisements() && p_le_inq_cb->adv_data_cache)
+ {
+ osi_free_and_reset((void **)&p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_data_cache = NULL;
+ }
+
+ p_le_inq_cb->adv_len = 0;
}
}
@@ -2903,12 +3265,26 @@
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
tBTM_STATUS status = BTM_CMD_STARTED;
+ BTM_TRACE_ERROR("btm_ble_start_scan extended scan");
/* start scan, disable duplicate filtering */
- if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter))
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
{
- status = BTM_NO_RESOURCES;
+ if (!btsnd_hcic_ble_set_extended_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter, p_inq->scan_duration, p_inq->scan_period))
+ {
+ status = BTM_NO_RESOURCES;
+ }
}
else
+#endif
+ {
+ if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter))
+ {
+ status = BTM_NO_RESOURCES;
+ }
+ }
+
+ if(status == BTM_CMD_STARTED)
{
if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI)
btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
@@ -2929,13 +3305,22 @@
*******************************************************************************/
void btm_ble_stop_scan(void)
{
- BTM_TRACE_EVENT ("btm_ble_stop_scan ");
+ BTM_TRACE_EVENT ("btm_ble_stop_scan");
/* Clear the inquiry callback if set */
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
/* stop discovery now */
- btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ btsnd_hcic_ble_set_extended_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE, 0, 0);
+ }
+ else
+#endif
+ {
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ }
btm_update_scanner_filter_policy(SP_ADV_ALL);
@@ -2959,6 +3344,8 @@
p_ble_cb->scan_activity &= ~BTM_BLE_INQUIRY_MASK;
+ p_ble_cb->inq_var.scan_duration = 0;
+ p_ble_cb->inq_var.scan_period = 0;
/* If no more scan activity, stop LE scan now */
if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
btm_ble_stop_scan();
@@ -3235,6 +3622,10 @@
break;
}
}
+ /* Set PHY for the connection to 2Mbps, no coding preference */
+ BTM_SetBlePhy(p_acl_cb->remote_addr, 0,
+ BTM_DATA_RATE_TWO|BTM_DATA_RATE_ONE,
+ BTM_DATA_RATE_TWO|BTM_DATA_RATE_ONE, 0);
}
}
@@ -3405,6 +3796,8 @@
p_cb->cur_states = 0;
p_cb->conn_pending_q = fixed_queue_new(SIZE_MAX);
+ memset(&(btm_cb.ble_adv_ext_cb), 0 , sizeof(tBTM_BLE_ADV_EXT_CB));
+
p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
p_cb->inq_var.adv_chnl_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index 3b16abb..70ee1a9 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -50,8 +50,11 @@
#define BTM_BLE_NAME_REQUEST 0x40
#define BTM_BLE_OBSERVE 0x80
-#define BTM_BLE_MAX_WL_ENTRY 1
-#define BTM_BLE_AD_DATA_LEN 31
+#define BTM_BLE_MAX_WL_ENTRY 1
+#define BTM_BLE_AD_DATA_LEN 31
+#define BTM_BLE_EXTENDED_AD_DATA_LEN 2000
+
+#define BTM_BLE_EXT_ADV_MAX_FRAG_NUM 20
#define BTM_BLE_ENC_MASK 0x03
@@ -135,10 +138,15 @@
{
UINT16 discoverable_mode;
UINT16 connectable_mode;
+ UINT8 scan_phys;
UINT32 scan_window;
UINT32 scan_interval;
+ UINT16 scan_window_coded;
+ UINT16 scan_interval_coded;
UINT8 scan_type; /* current scan type: active or passive */
UINT8 scan_duplicate_filter; /* duplicate filter enabled for scan */
+ UINT16 scan_duration;
+ UINT16 scan_period;
UINT16 adv_interval_min;
UINT16 adv_interval_max;
tBTM_BLE_AFP afp; /* advertising filter policy */
@@ -169,7 +177,7 @@
/* random address resolving complete callback */
-typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p);
+typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p, BOOLEAN extended);
typedef void (tBTM_BLE_ADDR_CBACK) (BD_ADDR_PTR static_random, void *p);
@@ -183,6 +191,7 @@
tBTM_BLE_ADDR_CBACK *p_generate_cback;
void *p;
alarm_t *refresh_raddr_timer;
+ BOOLEAN extended;
} tBTM_LE_RANDOM_CB;
#define BTM_BLE_MAX_BG_CONN_DEV_NUM 10
@@ -217,6 +226,9 @@
#define BTM_BLE_RL_INIT 1
#define BTM_BLE_RL_SCAN 2
#define BTM_BLE_RL_ADV 4
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+#define BTM_BLE_RL_EXT_ADV 8
+#endif
typedef UINT8 tBTM_BLE_RL_STATE;
/* BLE connection state */
@@ -290,6 +302,10 @@
#define BTM_PRIVACY_MIXED 3 /* BLE privacy mixed mode, broadcom propietary mode */
typedef UINT8 tBTM_PRIVACY_MODE;
+/* 2Mbps PHY support*/
+#define BTM_DATA_RATE_TWO 2
+#define BTM_DATA_RATE_ONE 1
+
/* data length change event callback */
typedef void (tBTM_DATA_LENGTH_CHANGE_CBACK) (UINT16 max_tx_length, UINT16 max_rx_length);
@@ -350,7 +366,8 @@
extern void btm_ble_adv_raddr_timer_timeout(void *data);
extern void btm_ble_refresh_raddr_timer_timeout(void *data);
-extern void btm_ble_process_adv_pkt (UINT8 *p);
+extern void btm_ble_process_adv_pkt (UINT8 *p, BOOLEAN extended);
+
extern void btm_ble_proc_scan_rsp_rpt (UINT8 *p);
extern tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb);
extern BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda);
@@ -375,7 +392,7 @@
extern tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
extern void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
extern UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
- tBTM_BLE_ADV_DATA *p_data);
+ tBTM_BLE_ADV_DATA *p_data, UINT16 max_len);
extern tBTM_STATUS btm_ble_start_adv(void);
extern tBTM_STATUS btm_ble_stop_adv(void);
extern tBTM_STATUS btm_ble_start_scan(void);
@@ -433,11 +450,12 @@
/* direct connection utility */
extern BOOLEAN btm_send_pending_direct_conn(void);
extern void btm_ble_enqueue_direct_conn_req(void *p_param);
+extern void btm_ble_dequeue_direct_conn_req(BD_ADDR rem_bda);
/* BLE address management */
extern void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback);
extern void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p);
-extern void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p);
+extern void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p, BOOLEAN extended);
extern void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p);
/* privacy function */
@@ -459,8 +477,18 @@
extern void btm_ble_resolving_list_cleanup(void);
#endif
+#if (defined BLE_EXTENDED_ADV_SUPPORT && BLE_EXTENDED_ADV_SUPPORT == TRUE)
+extern void btm_ble_read_inst_length_complete (UINT8* p, UINT16 evt_len);
+extern void btm_ble_adv_extension_operation_complete (UINT8* p, UINT16 hcidm);
+extern void btm_ble_adv_set_terminated_evt (UINT8* p);
+extern void btm_ble_multi_adv_enable_all(UINT8 enable);
+extern void btm_ble_scan_timeout_evt(void);
+extern void btm_ble_extended_configure_inst_size(void);
+#endif
+
+extern void btm_ble_update_multi_adv_inst_data_length (UINT16 inst_len);
extern void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst);
-extern void btm_ble_multi_adv_init(void);
+extern void btm_ble_multi_adv_init(UINT8 max_adv_inst);
extern void* btm_ble_multi_adv_get_ref(UINT8 inst_id);
extern void btm_ble_multi_adv_cleanup(void);
extern void btm_ble_multi_adv_reenable(UINT8 inst_id);
@@ -473,6 +501,7 @@
extern BOOLEAN btm_ble_topology_check(tBTM_BLE_STATE_MASK request);
extern BOOLEAN btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state);
extern BOOLEAN btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state);
+extern void btm_ble_set_random_address(BD_ADDR random_bda);
#if BTM_BLE_CONFORMANCE_TESTING == TRUE
extern void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc);
diff --git a/stack/btm/btm_ble_multi_adv.c b/stack/btm/btm_ble_multi_adv.c
index 5efe752..1d6840a 100644
--- a/stack/btm/btm_ble_multi_adv.c
+++ b/stack/btm/btm_ble_multi_adv.c
@@ -17,9 +17,11 @@
******************************************************************************/
#include <string.h>
+#include <pthread.h>
#include "bt_target.h"
#include "device/include/controller.h"
+#include "stack_config.h"
#if (BLE_INCLUDED == TRUE)
#include "bt_types.h"
@@ -38,15 +40,30 @@
#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24
#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3)
#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8
+#define BTM_BLE_EXTENDED_ADV_TIMEOUT 0x3C
#define BTM_BLE_MULTI_ADV_CB_EVT_MASK 0xF0
#define BTM_BLE_MULTI_ADV_SUBCODE_MASK 0x0F
+#ifdef WIPOWER_SUPPORTED
+#define WIPOWER_16_UUID_LSB 0xFE
+#define WIPOWER_16_UUID_MSB 0xFF
+static bool is_wipower_adv = false;
+#endif
+
+#define BTM_BLE_EXTENDED_LEGACY_MASK 0x10
+
/************************************************************************************
** Static variables
************************************************************************************/
tBTM_BLE_MULTI_ADV_CB btm_multi_adv_cb;
tBTM_BLE_MULTI_ADV_INST_IDX_Q btm_multi_adv_idx_q;
+pthread_mutex_t btm_multi_adv_lock = PTHREAD_MUTEX_INITIALIZER;
+tBTM_BLE_EXT_ADV_ENABLE_CB btm_ble_ext_enable_cb;
+
+#ifdef WIPOWER_SUPPORTED
+UINT8 wipower_inst_id = BTM_BLE_MULTI_ADV_DEFAULT_STD;
+#endif
/************************************************************************************
** Externs
@@ -55,6 +72,25 @@
extern void btm_ble_update_dmt_flag_bits(UINT8 *flag_value,
const UINT16 connect_mode, const UINT16 disc_mode);
+static inline BOOLEAN is_btm_multi_adv_cb_valid()
+{
+ if (!btm_multi_adv_cb.p_adv_inst ||
+ !btm_multi_adv_cb.op_q.p_sub_code ||
+ !btm_multi_adv_cb.op_q.p_inst_id)
+ return FALSE;
+ else
+ return TRUE;
+}
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+/************************************************************************************
+** Local declaration
+************************************************************************************/
+static tBTM_STATUS btm_ble_extended_adv_set_params (tBTM_BLE_MULTI_ADV_INST *p_inst,
+ tBTM_BLE_ADV_PARAMS *p_params,
+ UINT8 cb_evt);
+static tBTM_STATUS btm_ble_enable_extended_adv (BOOLEAN enable, UINT8 inst_id, UINT16 duration, UINT8 max_ext_adv_evts, UINT8 cb_evt);
+#endif
+
/*******************************************************************************
**
** Function btm_ble_multi_adv_enq_op_q
@@ -67,13 +103,15 @@
*******************************************************************************/
void btm_ble_multi_adv_enq_op_q(UINT8 opcode, UINT8 inst_id, UINT8 cb_evt)
{
+ UINT8 max_adv_instance = BTM_BleMaxMultiAdvInstanceCount();
tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q;
p_op_q->p_inst_id[p_op_q->next_idx] = inst_id;
p_op_q->p_sub_code[p_op_q->next_idx] = (opcode |(cb_evt << 4));
- p_op_q->next_idx = (p_op_q->next_idx + 1) % BTM_BleMaxMultiAdvInstanceCount();
+ if (max_adv_instance > 0)
+ p_op_q->next_idx = (p_op_q->next_idx + 1) % max_adv_instance;
}
/*******************************************************************************
@@ -88,13 +126,15 @@
*******************************************************************************/
void btm_ble_multi_adv_deq_op_q(UINT8 *p_opcode, UINT8 *p_inst_id, UINT8 *p_cb_evt)
{
+ UINT8 max_adv_instance = BTM_BleMaxMultiAdvInstanceCount();
tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q;
*p_inst_id = p_op_q->p_inst_id[p_op_q->pending_idx] & 0x7F;
*p_cb_evt = (p_op_q->p_sub_code[p_op_q->pending_idx] >> 4);
*p_opcode = (p_op_q->p_sub_code[p_op_q->pending_idx] & BTM_BLE_MULTI_ADV_SUBCODE_MASK);
- p_op_q->pending_idx = (p_op_q->pending_idx + 1) % BTM_BleMaxMultiAdvInstanceCount();
+ if (max_adv_instance > 0)
+ p_op_q->pending_idx = (p_op_q->pending_idx + 1) % max_adv_instance;
}
/*******************************************************************************
@@ -116,6 +156,12 @@
tBTM_BLE_MULTI_ADV_INST *p_inst ;
UINT8 cb_evt = 0, opcode;
+ if (!controller_get_interface()->get_is_ready())
+ {
+ BTM_TRACE_ERROR("btm_ble_multi_adv_vsc_cmpl_cback controller not ready. returning!");
+ return;
+ }
+
if (len < 2)
{
BTM_TRACE_ERROR("wrong length for btm_ble_multi_adv_vsc_cmpl_cback");
@@ -125,6 +171,9 @@
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT8(subcode, p);
+ pthread_mutex_lock(&btm_multi_adv_lock);
+ if (!is_btm_multi_adv_cb_valid())
+ goto error;
btm_ble_multi_adv_deq_op_q(&opcode, &inst_id, &cb_evt);
BTM_TRACE_DEBUG("op_code = %02x inst_id = %d cb_evt = %02x", opcode, inst_id, cb_evt);
@@ -132,7 +181,7 @@
if (opcode != subcode || inst_id == 0)
{
BTM_TRACE_ERROR("get unexpected VSC cmpl, expect: %d get: %d",subcode,opcode);
- return;
+ goto error;
}
p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
@@ -181,6 +230,9 @@
{
(p_inst->p_cback)(cb_evt, inst_id, p_inst->p_ref, status);
}
+
+error:
+ pthread_mutex_unlock(&btm_multi_adv_lock);
return;
}
@@ -339,22 +391,34 @@
tBTM_STATUS btm_ble_multi_adv_write_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst, BD_ADDR random_addr)
{
UINT8 param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN], *pp = param;
- tBTM_STATUS rt;
+ tBTM_STATUS rt = BTM_NO_RESOURCES;
BTM_TRACE_EVENT ("%s-BD_ADDR:%02x-%02x-%02x-%02x-%02x-%02x,inst_id:%d",
__FUNCTION__, random_addr[5], random_addr[4], random_addr[3], random_addr[2],
random_addr[1], random_addr[0], p_inst->inst_id);
- memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ rt = btm_ble_add_multi_adv_rpa(random_addr, BLE_ADDR_RANDOM);
+ return rt;
+ }
+ else
+#endif
+ {
+ memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN);
- UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR);
- BDADDR_TO_STREAM(pp, random_addr);
- UINT8_TO_STREAM(pp, p_inst->inst_id);
-
- if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
+ UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR);
+ BDADDR_TO_STREAM(pp, random_addr);
+ UINT8_TO_STREAM(pp, p_inst->inst_id);
+ rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN,
param,
- btm_ble_multi_adv_vsc_cmpl_cback)) == BTM_CMD_STARTED)
+ btm_ble_multi_adv_vsc_cmpl_cback);
+ }
+
+
+ if (rt == BTM_CMD_STARTED)
{
/* start a periodical timer to refresh random addr */
/* TODO: is the above comment correct - is the timer periodical? */
@@ -380,6 +444,12 @@
*******************************************************************************/
void btm_ble_multi_adv_gen_rpa_cmpl(tBTM_RAND_ENC *p)
{
+ if (!controller_get_interface()->get_is_ready())
+ {
+ BTM_TRACE_ERROR("btm_ble_multi_adv_gen_rpa_cmpl controller module is not ready!");
+ return;
+ }
+
#if (SMP_INCLUDED == TRUE)
tSMP_ENC output;
UINT8 index = 0;
@@ -405,6 +475,9 @@
}
}
+ pthread_mutex_lock(&btm_multi_adv_lock);
+ if (!is_btm_multi_adv_cb_valid())
+ goto error;
p_inst = &(btm_multi_adv_cb.p_adv_inst[index]);
BTM_TRACE_EVENT ("btm_ble_multi_adv_gen_rpa_cmpl inst_id = %d", p_inst->inst_id);
@@ -436,6 +509,8 @@
btm_ble_multi_adv_write_rpa(p_inst, p_inst->rpa);
}
}
+error:
+ pthread_mutex_unlock(&btm_multi_adv_lock);
#endif
}
@@ -475,6 +550,29 @@
/*******************************************************************************
**
+** Function btm_ble_update_multi_adv_inst_data_length
+**
+** Description This function set the random address for the adv instance
+**
+** Parameters advertise parameters used for this instance.
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_update_multi_adv_inst_data_length (UINT16 inst_len)
+{
+ int index;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
+ BTM_TRACE_ERROR("btm_ble_update_multi_adv_inst_data_length inst_len:%d",inst_len);
+
+ for (index = 0; index < BTM_BleMaxMultiAdvInstanceCount() - 1; index++, p_inst++)
+ {
+ p_inst->len = inst_len;
+ }
+}
+
+/*******************************************************************************
+**
** Function btm_ble_multi_adv_reenable
**
** Description This function re-enable adv instance upon a connection establishment.
@@ -514,7 +612,7 @@
*******************************************************************************/
void btm_ble_multi_adv_enb_privacy(BOOLEAN enable)
{
- UINT8 i;
+ int i;
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++)
@@ -527,6 +625,25 @@
}
}
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+/*******************************************************************************
+**
+** Function btm_ble_extended_configure_inst_size
+**
+** Description This function gathers max length of advertiement sets
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_extended_configure_inst_size()
+{
+ BTM_TRACE_DEBUG ("%s", __func__);
+ btsnd_hcic_ble_read_extended_max_adv_len();
+}
+#endif
+
/*******************************************************************************
**
** Function BTM_BleEnableAdvInstance
@@ -545,13 +662,13 @@
tBTM_STATUS BTM_BleEnableAdvInstance (tBTM_BLE_ADV_PARAMS *p_params,
tBTM_BLE_MULTI_ADV_CBACK *p_cback,void *p_ref)
{
- UINT8 i;
+ int i;
tBTM_STATUS rt = BTM_NO_RESOURCES;
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
BTM_TRACE_EVENT("BTM_BleEnableAdvInstance called");
- if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max)
+ if (0 == BTM_BleMaxMultiAdvInstanceCount())
{
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
@@ -569,8 +686,18 @@
{
p_inst->in_use = TRUE;
/* configure adv parameter */
- if (p_params)
- rt = btm_ble_multi_adv_set_params(p_inst, p_params, 0);
+ if (p_params) {
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ rt = btm_ble_extended_adv_set_params(p_inst, p_params, 0);
+ }
+ else
+#endif
+ {
+ rt = btm_ble_multi_adv_set_params(p_inst, p_params, 0);
+ }
+ }
else
rt = BTM_CMD_STARTED;
@@ -580,8 +707,22 @@
if (BTM_CMD_STARTED == rt)
{
- if ((rt = btm_ble_enable_multi_adv (TRUE, p_inst->inst_id,
- BTM_BLE_MULTI_ADV_ENB_EVT)) == BTM_CMD_STARTED)
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements()) {
+ p_inst->in_use = FALSE;
+ btm_ble_enable_resolving_list (BTM_BLE_RL_EXT_ADV);
+ p_inst->in_use = TRUE;
+ rt = btm_ble_enable_extended_adv (TRUE, p_inst->inst_id,
+ p_inst->duration, p_params->max_ext_adv_evts, BTM_BLE_EXTENDED_ADV_ENB_EVT);
+ }
+ else
+#endif
+ {
+ rt = btm_ble_enable_multi_adv (TRUE, p_inst->inst_id,
+ BTM_BLE_MULTI_ADV_ENB_EVT);
+ }
+
+ if (rt == BTM_CMD_STARTED)
{
p_inst->p_cback = p_cback;
p_inst->p_ref = p_ref;
@@ -616,10 +757,11 @@
{
tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+ UINT8 cb_evt = BTM_BLE_MULTI_ADV_PARAM_EVT;
BTM_TRACE_EVENT("BTM_BleUpdateAdvInstParam called with inst_id:%d", inst_id);
- if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max)
+ if (0 == BTM_BleMaxMultiAdvInstanceCount())
{
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
@@ -634,11 +776,39 @@
BTM_TRACE_DEBUG("adv instance %d is not active", inst_id);
return BTM_WRONG_MODE;
}
- else
- btm_ble_enable_multi_adv(FALSE, inst_id, 0);
+ else {
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ btm_ble_enable_extended_adv(FALSE, inst_id, 0, 0/*p_params->max_ext_adv_evts*/, 0);
+ else
+#endif
+ {
+ btm_ble_enable_multi_adv(FALSE, inst_id, 0);
+ }
+ }
- if (BTM_CMD_STARTED == btm_ble_multi_adv_set_params(p_inst, p_params, 0))
- rt = btm_ble_enable_multi_adv(TRUE, inst_id, BTM_BLE_MULTI_ADV_PARAM_EVT);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ rt = btm_ble_extended_adv_set_params(p_inst, p_params, 0);
+ cb_evt = BTM_BLE_EXTENDED_ADV_PARAM_EVT;
+ }
+ else
+#endif
+ {
+ rt = btm_ble_multi_adv_set_params(p_inst, p_params, 0);
+ }
+
+ if (BTM_CMD_STARTED == rt) {
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ rt = btm_ble_enable_extended_adv(TRUE, inst_id, p_inst->duration, p_params->max_ext_adv_evts, cb_evt);
+ else
+#endif
+ {
+ rt = btm_ble_enable_multi_adv(TRUE, inst_id, cb_evt);
+ }
+ }
}
return rt;
}
@@ -659,7 +829,7 @@
**
*******************************************************************************/
tBTM_STATUS BTM_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp,
- tBTM_BLE_AD_MASK data_mask,
+ tBTM_BLE_AD_MASK data_mask, UINT8 frag_pref,
tBTM_BLE_ADV_DATA *p_data)
{
UINT8 param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN], *pp = param;
@@ -670,8 +840,16 @@
UINT8 *pp_temp = (UINT8*)(param + BTM_BLE_MULTI_ADV_WRITE_DATA_LEN -1);
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ return BTM_BleWriteExtendedAdvData (inst_id, is_scan_rsp, data_mask,
+ BTM_BLE_EXT_ADV_COMPLETE ,frag_pref, p_data);
+ }
+#endif
+
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
- if (0 == cmn_ble_vsc_cb.adv_inst_max)
+ if (0 == BTM_BleMaxMultiAdvInstanceCount())
{
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
@@ -688,9 +866,16 @@
UINT8_TO_STREAM(pp, sub_code);
p_len = pp ++;
- btm_ble_build_adv_data(&data_mask, &pp, p_data);
+ btm_ble_build_adv_data(&data_mask, &pp, p_data, BTM_BLE_AD_DATA_LEN);
*p_len = (UINT8)(pp - param - 2);
UINT8_TO_STREAM(pp_temp, inst_id);
+#ifdef WIPOWER_SUPPORTED
+ if (param[7] == WIPOWER_16_UUID_LSB && param[8] == WIPOWER_16_UUID_MSB)
+ {
+ is_wipower_adv = true;
+ wipower_inst_id = inst_id;
+ }
+#endif
if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
(UINT8)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN,
@@ -716,29 +901,45 @@
*******************************************************************************/
tBTM_STATUS BTM_BleDisableAdvInstance (UINT8 inst_id)
{
- tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
- tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
- BTM_TRACE_EVENT("BTM_BleDisableAdvInstance with inst_id:%d", inst_id);
+ BTM_TRACE_EVENT("BTM_BleDisableAdvInstance with inst_id:%d", inst_id);
- BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
- if (0 == cmn_ble_vsc_cb.adv_inst_max)
- {
- BTM_TRACE_ERROR("Controller does not support Multi ADV");
- return BTM_ERR_PROCESSING;
- }
+ if (0 == BTM_BleMaxMultiAdvInstanceCount())
+ {
+ BTM_TRACE_ERROR("Controller does not support Multi ADV");
+ return BTM_ERR_PROCESSING;
+ }
- if (inst_id < BTM_BleMaxMultiAdvInstanceCount() &&
- inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD)
- {
- if ((rt = btm_ble_enable_multi_adv(FALSE, inst_id, BTM_BLE_MULTI_ADV_DISABLE_EVT))
- == BTM_CMD_STARTED)
- {
+ if (inst_id < BTM_BleMaxMultiAdvInstanceCount() &&
+ inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD)
+ {
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+ if (controller_get_interface()->supports_ble_extended_advertisements()) {
+ rt = btm_ble_enable_extended_adv (FALSE, inst_id,
+ p_inst->duration, 0/*p_params->max_ext_adv_evts*/,
+ BTM_BLE_MULTI_ADV_DISABLE_EVT);
+ }
+ else
+#endif
+ {
+ rt = btm_ble_enable_multi_adv(FALSE, inst_id, BTM_BLE_MULTI_ADV_DISABLE_EVT);
+ }
+
+ if (rt == BTM_CMD_STARTED
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ && !controller_get_interface()->supports_ble_extended_advertisements()
+#endif
+ )
+ {
btm_ble_multi_adv_configure_rpa(&btm_multi_adv_cb.p_adv_inst[inst_id - 1]);
alarm_cancel(btm_multi_adv_cb.p_adv_inst[inst_id - 1].adv_raddr_timer);
- btm_multi_adv_cb.p_adv_inst[inst_id - 1].in_use = FALSE;
- }
+ }
+ btm_multi_adv_cb.p_adv_inst[inst_id - 1].in_use = FALSE;
}
return rt;
}
@@ -784,7 +985,13 @@
adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD)
{
BTM_TRACE_EVENT("btm_ble_multi_adv_reenable called");
- btm_ble_multi_adv_reenable(adv_inst);
+#ifdef WIPOWER_SUPPORTED
+ if (!(is_wipower_adv && (adv_inst == wipower_inst_id))) {
+ btm_ble_multi_adv_reenable(adv_inst);
+ }
+#else
+ btm_ble_multi_adv_reenable(adv_inst);
+#endif
}
/* re-enable connectibility */
else if (adv_inst == BTM_BLE_MULTI_ADV_DEFAULT_STD)
@@ -804,39 +1011,54 @@
**
** Description This function initialize the multi adv control block.
**
-** Parameters None
+** Parameters UINT8 max_adv_inst
**
** Returns void
**
*******************************************************************************/
-void btm_ble_multi_adv_init()
+void btm_ble_multi_adv_init(UINT8 max_adv_inst)
{
+ BTM_TRACE_ERROR("%s: max adv instances: %d", __func__, max_adv_inst);
UINT8 i = 0;
memset(&btm_multi_adv_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB));
memset (&btm_multi_adv_idx_q,0, sizeof (tBTM_BLE_MULTI_ADV_INST_IDX_Q));
+
btm_multi_adv_idx_q.front = -1;
btm_multi_adv_idx_q.rear = -1;
- if (btm_cb.cmn_ble_vsc_cb.adv_inst_max > 0) {
+ if (max_adv_inst > 0)
+ {
btm_multi_adv_cb.p_adv_inst = osi_calloc(sizeof(tBTM_BLE_MULTI_ADV_INST) *
- (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ (max_adv_inst));
btm_multi_adv_cb.op_q.p_sub_code = osi_calloc(sizeof(UINT8) *
- (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ (max_adv_inst));
btm_multi_adv_cb.op_q.p_inst_id = osi_calloc(sizeof(UINT8) *
- (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ (max_adv_inst));
+
+ btm_ble_ext_enable_cb.set_ids = osi_calloc(sizeof(UINT8) * max_adv_inst);
+
+ btm_ble_ext_enable_cb.durations = osi_calloc(sizeof(UINT16) * max_adv_inst);
+
+ btm_ble_ext_enable_cb.max_adv_events = osi_calloc(sizeof(UINT8) * max_adv_inst);
}
/* Initialize adv instance indices and IDs. */
- for (i = 0; i < btm_cb.cmn_ble_vsc_cb.adv_inst_max; i++) {
+ for (i = 0; i < max_adv_inst; i++) {
btm_multi_adv_cb.p_adv_inst[i].index = i;
btm_multi_adv_cb.p_adv_inst[i].inst_id = i + 1;
btm_multi_adv_cb.p_adv_inst[i].adv_raddr_timer =
alarm_new("btm_ble.adv_raddr_timer");
}
+ controller_get_interface()->set_ble_adv_ext_size(max_adv_inst);
- BTM_RegisterForVSEvents(btm_ble_multi_adv_vse_cback, TRUE);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if(!controller_get_interface()->supports_ble_extended_advertisements())
+#endif
+ {
+ BTM_RegisterForVSEvents(btm_ble_multi_adv_vse_cback, TRUE);
+ }
}
/*******************************************************************************
@@ -851,6 +1073,12 @@
*******************************************************************************/
void btm_ble_multi_adv_cleanup(void)
{
+#ifdef WIPOWER_SUPPORTED
+ is_wipower_adv = false;
+ wipower_inst_id = BTM_BLE_MULTI_ADV_DEFAULT_STD;
+#endif
+
+ pthread_mutex_lock(&btm_multi_adv_lock);
if (btm_multi_adv_cb.p_adv_inst) {
for (size_t i = 0; i < btm_cb.cmn_ble_vsc_cb.adv_inst_max; i++) {
alarm_free(btm_multi_adv_cb.p_adv_inst[i].adv_raddr_timer);
@@ -860,6 +1088,11 @@
osi_free_and_reset((void **)&btm_multi_adv_cb.op_q.p_sub_code);
osi_free_and_reset((void **)&btm_multi_adv_cb.op_q.p_inst_id);
+ osi_free_and_reset((void **)&btm_multi_adv_cb.op_q.p_inst_id);
+ osi_free_and_reset((void **)&btm_ble_ext_enable_cb.set_ids);
+ osi_free_and_reset((void **)&btm_ble_ext_enable_cb.durations);
+ osi_free_and_reset((void **)&btm_ble_ext_enable_cb.max_adv_events);
+ pthread_mutex_unlock(&btm_multi_adv_lock);
}
/*******************************************************************************
@@ -886,5 +1119,690 @@
return NULL;
}
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+
+/*******************************************************************************
+**
+** Function btm_ble_enable_extended_adv
+**
+** Description This function enables the extended adv
+**
+** Parameters enable: enable or disable
+** inst_id: adv instance ID, can not be 0
+** duration: duration of the adv
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_enable_extended_adv (BOOLEAN enable, UINT8 inst_id, UINT16 duration, UINT8 max_ext_adv_evts, UINT8 cb_evt)
+{
+ UINT8 enb = enable ? 1: 0;
+ tBTM_STATUS rt;
+
+ BTM_TRACE_EVENT ("%s: enb %d, Inst ID %d, dur = %d(s)",__func__, enb,inst_id, duration);
+ inst_id = inst_id - 1;
+ duration = duration * 100; //duration is interpreted as t*10msec
+
+ if ((rt = btsnd_hcic_ble_set_extended_adv_enable (enb,
+ 1, //Num of sets
+ &inst_id,
+ &duration,
+ &max_ext_adv_evts))
+ == BTM_CMD_STARTED)
+ {
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_ENB, inst_id + 1, cb_evt);
+ }
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_save_extended_adv_params
+**
+** Description This function sets the extended adv params
+**
+** Parameters p_inst: pointer to instance variable
+** p_params: adv parameters
+** cb_evt: callback event
+**
+** Returns status
+**
+*******************************************************************************/
+void btm_ble_save_extended_adv_params (tBTM_BLE_MULTI_ADV_INST *p_inst,UINT32 adv_int_min, UINT32 adv_int_max,
+ UINT8 own_addr_type, UINT8 pri_phy, UINT8 adv_sid ,UINT8 sec_adv_max_skip, UINT8 sec_adv_phy,
+ UINT8 scan_req_notf_enb, UINT8 channel_map, UINT8 adv_filter_policy, UINT8 tx_power)
+{
+ if(p_inst != NULL)
+ {
+ p_inst->adv_int_min = adv_int_min;
+ p_inst->adv_int_max = adv_int_max;
+ p_inst->own_addr_type = own_addr_type;
+ p_inst->pri_phy = pri_phy;
+ p_inst->adv_sid = adv_sid;
+ p_inst->sec_adv_max_skip = sec_adv_max_skip;
+ p_inst->sec_adv_phy = sec_adv_phy;
+ p_inst->scan_req_notf_enb = scan_req_notf_enb;
+ p_inst->channel_map = channel_map;
+ p_inst->adv_filter_policy = adv_filter_policy;
+ p_inst->tx_power = tx_power;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_extended_adv_set_params
+**
+** Description This function sets the extended adv params
+**
+** Parameters p_inst: pointer to instance variable
+** p_params: adv parameters
+** cb_evt: callback event
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_extended_adv_set_params (tBTM_BLE_MULTI_ADV_INST *p_inst,
+ tBTM_BLE_ADV_PARAMS *p_params,
+ UINT8 cb_evt)
+{
+ UINT8 set_id;
+ tBTM_BLE_EXT_EVT evt_prop = BTM_BLE_EXT_CONNECT_EVT;
+ tBTM_STATUS rt;
+ tBLE_ADDR_TYPE own_addr_type;
+ tBLE_ADDR_TYPE dir_addr_type = BLE_ADDR_RANDOM;
+ UINT32 adv_int_min = 0, adv_int_max =0;
+ UINT8 adv_filter_policy = 0, tx_power =0, channel_map = 0;
+ UINT8 pri_phy = 0,sec_adv_max_skip=0, sec_adv_phy=0, adv_sid=1, scan_req_notf_enb=0;
+
+ if (!p_inst)
+ {
+ BTM_TRACE_ERROR ("%s: instance variable is null", __func__);
+ return BTM_ERR_PROCESSING;
+ }
+
+ if (0 == BTM_BleMaxMultiAdvInstanceCount())
+ {
+ BTM_TRACE_ERROR ("%s: Controller does not support extended Multi ADV", __func__);
+ return BTM_ERR_PROCESSING;
+ }
+
+ set_id = p_inst->inst_id;
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE)
+ {
+ own_addr_type = BLE_ADDR_RANDOM_ID;
+ }
+ else
+#endif
+ {
+ own_addr_type = BLE_ADDR_PUBLIC;
+ }
+
+ if(p_params != NULL)
+ {
+ p_inst->duration = p_params->duration;
+ p_inst->adv_evt = p_params->adv_type;
+
+ adv_int_min = p_params->adv_int_min;
+ adv_int_max = p_params->adv_int_max;
+ //To identify that event type(adv type) parameter was read from bt_stack.conf and not sent from fwks
+ if(p_params->sec_adv_phy > 0)
+ {
+ evt_prop = p_params->adv_type;
+ pri_phy = p_params->pri_phy;
+ adv_sid = p_params->adv_sid;
+ scan_req_notf_enb =p_params->scan_req_notf_enb;
+ sec_adv_phy = p_params->sec_adv_phy;
+ sec_adv_max_skip = p_params->sec_adv_max_skip;
+ }
+ else
+ {
+ switch (p_params->adv_type)
+ {
+ case BTM_BLE_CONNECT_EVT:
+ evt_prop = BTM_BLE_EXT_CONNECT_EVT;
+ break;
+ case BTM_BLE_CONNECT_DIR_EVT:
+ evt_prop = BTM_BLE_EXT_CONNECT_DIR_EVT;
+ break;
+ case BTM_BLE_DISCOVER_EVT:
+ evt_prop = BTM_BLE_EXT_DISCOVER_EVT;
+ break;
+ case BTM_BLE_NON_CONNECT_EVT:
+ evt_prop = BTM_BLE_EXT_NON_CONNECT_EVT;
+ break;
+ case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+ evt_prop = BTM_BLE_EXT_CONNECT_LO_DUTY_DIR_EVT;
+ break;
+ }
+ pri_phy = BTM_DATA_RATE_ONE;
+ adv_sid = 0x01;
+
+ }
+ p_inst->evt_prop = evt_prop;
+
+ if (p_params->channel_map == 0 || p_params->channel_map > BTM_BLE_DEFAULT_ADV_CHNL_MAP)
+ channel_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
+ else
+ channel_map = p_params->channel_map;
+
+ if (p_params->adv_filter_policy >= AP_SCAN_CONN_POLICY_MAX)
+ adv_filter_policy = AP_SCAN_CONN_ALL;
+ else
+ adv_filter_policy = p_params->adv_filter_policy;
+
+ if (p_params->tx_power > BTM_BLE_ADV_TX_POWER_MAX)
+ tx_power = BTM_BLE_ADV_TX_POWER_MAX;
+ else
+ tx_power = p_params->tx_power;
+
+ //save ext adv params in p_inst for reenabling adv for chained ext advs
+ btm_ble_save_extended_adv_params(p_inst, adv_int_min, adv_int_max, own_addr_type, pri_phy, adv_sid ,sec_adv_max_skip,
+ sec_adv_phy, scan_req_notf_enb, channel_map, adv_filter_policy,tx_power);
+ }
+ //else case is reached when adv is disabled and re enabled again for chained advs
+ else
+ {
+ evt_prop = p_inst->evt_prop;
+ adv_int_min = p_inst->adv_int_min;
+ adv_int_max =p_inst->adv_int_max;
+ channel_map =p_inst->channel_map;
+ adv_filter_policy =p_inst->adv_filter_policy;
+ tx_power=p_inst->tx_power;
+ pri_phy=p_inst->pri_phy;
+ sec_adv_max_skip=p_inst->sec_adv_max_skip;
+ sec_adv_phy =p_inst->sec_adv_phy;
+ adv_sid =p_inst->adv_sid;
+ scan_req_notf_enb=p_inst->scan_req_notf_enb;
+ }
+
+ BTM_TRACE_ERROR ("%s: evt_prop::%d, primary_phy=%d,p_params->sec_adv_max_skip=%d, p_params->sec_adv_phy=%d, p_params->adv_sid=%d, p_params->scan_req_notf_enb=%d", __func__,
+ evt_prop, pri_phy, sec_adv_max_skip, sec_adv_phy, adv_sid, scan_req_notf_enb);
+
+ rt = btsnd_hcic_ble_set_extended_adv_params (set_id - 1, evt_prop,
+ adv_int_min, adv_int_max,
+ channel_map, own_addr_type,
+ dir_addr_type, p_inst->rpa,
+ adv_filter_policy, btm_ble_map_adv_tx_power(tx_power),
+ pri_phy, sec_adv_max_skip,
+ sec_adv_phy, adv_sid, scan_req_notf_enb);
+
+ if (rt == BTM_CMD_STARTED)
+ {
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_PARAM, set_id, cb_evt);
+ }
+
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_send_ext_adv_data
+**
+** Description This function configure a Multi-ADV instance with the specified
+** adv data or scan response data.
+**
+** Parameters inst_id: adv instance ID
+** is_scan_rsp: is this scan response. if no, set as adv data.
+** data_mask: adv data mask.
+** p_data: pointer to the adv data structure.
+** operation:
+** 0x00: Intermediate fragment
+** 0x01: first fragment
+** 0x02: Last fragment
+** 0x03: complete data, ctrlr fragmentation permitted
+** 0x04: complete data, ctrlr fragmentation not permitted
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_send_ext_adv_data (BOOLEAN is_scan_rsp, UINT8 inst_id, UINT8 operation, UINT8 frag_pref, UINT8 data_len, UINT8 *param)
+{
+ tBTM_STATUS rt;
+ UINT8 sub_code;
+ if (!is_scan_rsp)
+ {
+ rt = btsnd_hcic_ble_set_extended_adv_data(inst_id - 1,
+ operation,
+ frag_pref,
+ data_len,
+ param);
+ sub_code = BTM_BLE_MULTI_ADV_WRITE_ADV_DATA;
+ }
+ else
+ {
+ rt = btsnd_hcic_ble_set_extended_scan_rsp_data(inst_id - 1,
+ operation,
+ frag_pref,
+ data_len,
+ param);
+ sub_code = BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA;
+ }
+
+ if (rt == BTM_CMD_STARTED)
+ {
+ btm_ble_multi_adv_enq_op_q(sub_code, inst_id, BTM_BLE_MULTI_ADV_DATA_EVT);
+ }
+ return rt;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_compute_frag_lens
+**
+** Description This function configure a Multi-ADV instance with the specified
+** adv data or scan response data.
+**
+** Parameters inst_id: adv instance ID
+** is_scan_rsp: is this scan response. if no, set as adv data.
+** data_mask: adv data mask.
+** p_data: pointer to the adv data structure.
+** operation:
+** 0x00: Intermediate fragment
+** 0x01: first fragment
+** 0x02: Last fragment
+** 0x03: complete data, ctrlr fragmentation permitted
+** 0x04: complete data, ctrlr fragmentation not permitted
+**
+** Returns status
+**
+*******************************************************************************/
+void btm_ble_compute_frag_lens (UINT16 data_len, UINT8* num_hci_cmds, UINT8 *pp_data_len)
+{
+ UINT8 index = 0;
+ *num_hci_cmds = (data_len/(HCI_COMMAND_SIZE-4));
+ for(index=0; index < *num_hci_cmds; index++)
+ pp_data_len[index] = (HCI_COMMAND_SIZE -4);
+
+ if(data_len % (HCI_COMMAND_SIZE-4))
+ {
+ pp_data_len[index] = (data_len % (HCI_COMMAND_SIZE-4));
+ (*num_hci_cmds)++;
+ }
+ BTM_TRACE_EVENT("btm_ble_compute_frag_lens::Final num_hci_cmds=%d",*num_hci_cmds);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_get_operation
+**
+** Description This function configure a Multi-ADV instance with the specified
+** adv data or scan response data.
+**
+** Parameters inst_id: adv instance ID
+** is_scan_rsp: is this scan response. if no, set as adv data.
+** data_mask: adv data mask.
+** p_data: pointer to the adv data structure.
+** operation:
+** 0x00: Intermediate fragment
+** 0x01: first fragment
+** 0x02: Last fragment
+** 0x03: complete data, ctrlr fragmentation permitted
+** 0x04: complete data, ctrlr fragmentation not permitted
+**
+** Returns status
+**
+*******************************************************************************/
+UINT8 btm_ble_get_operation (UINT8 num_hci_cmds_copy, UINT8 num_hci_cmds)
+{
+ UINT8 op = 0;
+ if(num_hci_cmds_copy == num_hci_cmds)
+ op = BTM_BLE_EXT_ADV_FIRST_FRAG;
+ else if(num_hci_cmds != 1)
+ op = BTM_BLE_EXT_ADV_INT_FRAG;
+ else
+ op = BTM_BLE_EXT_ADV_LAST_FRAG;
+ return op;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteExtendedAdvData
+**
+** Description This function configure a Multi-ADV instance with the specified
+** adv data or scan response data.
+**
+** Parameters inst_id: adv instance ID
+** is_scan_rsp: is this scan response. if no, set as adv data.
+** data_mask: adv data mask.
+** p_data: pointer to the adv data structure.
+** operation:
+** 0x00: Intermediate fragment
+** 0x01: first fragment
+** 0x02: Last fragment
+** 0x03: complete data, ctrlr fragmentation permitted
+** 0x04: complete data, ctrlr fragmentation not permitted
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteExtendedAdvData (UINT8 inst_id, BOOLEAN is_scan_rsp,
+ tBTM_BLE_AD_MASK data_mask,
+ UINT8 operation, UINT8 frag_pref,
+ tBTM_BLE_ADV_DATA *p_data)
+{
+ UINT8 param[BTM_BLE_EXTENDED_AD_DATA_LEN], *pp = param, frag_data[HCI_COMMAND_SIZE-4];
+ UINT8 frag_data_len[BTM_BLE_EXT_ADV_MAX_FRAG_NUM], index=0;
+ UINT16 data_len, offset =0, j=0;
+ tBTM_STATUS rt;
+ UINT8 num_hci_cmds = 0, num_hci_cmds_copy = 0;
+ tBTM_BLE_MULTI_ADV_INST *p_inst;
+ tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+
+ if (0 == BTM_BleMaxMultiAdvInstanceCount())
+ {
+ BTM_TRACE_ERROR ("%s: Controller does not support extended Multi ADV", __func__);
+ return BTM_ERR_PROCESSING;
+ }
+ BTM_TRACE_EVENT("BTM_BleWriteExtendedAdvData");
+ if (stack_config_get_interface()->get_pts_le_nonconn_adv_enabled())
+ {
+ if (p_adv_data->p_flags != NULL)
+ {
+ p_data->flag = *(p_adv_data->p_flags);
+ }
+ }
+
+ btm_ble_update_dmt_flag_bits(&p_data->flag, btm_cb.btm_inq_vars.connectable_mode,
+ btm_cb.btm_inq_vars.discoverable_mode);
+
+ BTM_TRACE_EVENT("%s called with inst_id:%d", __func__, inst_id);
+ // inst_id will range from 1 to 16 max, so the below should ideally fail
+ if (inst_id > BTM_BLE_MULTI_ADV_MAX || inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD)
+ return BTM_ILLEGAL_VALUE;
+
+ p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+
+ /* check if adv is not enabled for operations 0 to 3 */
+ if (p_inst->in_use && (operation < BTM_BLE_EXT_ADV_COMPLETE))
+ {
+ BTM_TRACE_ERROR ("%s: Illegal operation: %d while adv is enabled", __func__, operation);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ memset(param, 0, BTM_BLE_EXTENDED_AD_DATA_LEN);
+
+ if (p_inst->len == 0 || (p_inst->evt_prop & BTM_BLE_EXTENDED_LEGACY_MASK)) {
+ BTM_TRACE_ERROR("%s: using default length 31 bytes", __func__);
+ p_inst->len = BTM_BLE_AD_DATA_LEN;
+ }
+
+ btm_ble_build_adv_data(&data_mask, &pp, p_data, p_inst->len);
+ data_len = (UINT16) (pp - param);
+ BTM_TRACE_ERROR("%s: data len is %d", __func__, data_len);
+
+ if(data_len > HCI_COMMAND_SIZE)
+ btm_ble_compute_frag_lens(data_len, &num_hci_cmds, frag_data_len);
+
+ num_hci_cmds_copy = num_hci_cmds;
+
+ if(num_hci_cmds > 0)
+ {
+ //Disable advertisement
+ rt = btm_ble_enable_extended_adv (FALSE, inst_id,
+ p_inst->duration, 0/*p_params->max_ext_adv_evts*/,
+ 0/*instead of BTM_BLE_MULTI_ADV_DISABLE_EVT*/);
+ p_inst->in_use = FALSE;
+
+ //set ext adv params
+ if (rt == BTM_CMD_STARTED)
+ {
+ p_inst->in_use = TRUE;
+ rt = btm_ble_extended_adv_set_params(p_inst, NULL, 0);
+ }
+
+ //set ext adv data
+ if (rt == BTM_CMD_STARTED)
+ {
+ while(num_hci_cmds)
+ {
+ memset(frag_data, 0, frag_data_len[index]);
+ BTM_TRACE_ERROR("offset =%d , index =%d ,frag_data_len[index] ::%d",offset, index, frag_data_len[index]);
+ for(j=0; j< frag_data_len[index]; j++)
+ {
+ BTM_TRACE_ERROR("Adv data ::%02x",param[offset+j]);
+ }
+ memcpy(frag_data, (param+offset), frag_data_len[index]);
+ operation = btm_ble_get_operation(num_hci_cmds_copy, num_hci_cmds);
+ offset += frag_data_len[index];
+ rt = btm_ble_send_ext_adv_data(is_scan_rsp, inst_id, operation, frag_pref, frag_data_len[index++], frag_data);
+ num_hci_cmds--;
+ }
+ }
+ //enable ext adv
+ if (rt == BTM_CMD_STARTED)
+ {
+ rt = btm_ble_enable_extended_adv (TRUE, p_inst->inst_id, p_inst->duration, 0, 0/*instead of BTM_BLE_EXTENDED_ADV_ENB_EVT*/);
+ }
+ }
+ else
+ rt = btm_ble_send_ext_adv_data(is_scan_rsp, inst_id, operation, frag_pref, data_len, param);
+
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ext_adv_reenable
+**
+** Description This function re-enable adv instance upon a connection establishment.
+**
+** Parameters instance id
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_ext_adv_reenable(UINT8 inst_id)
+{
+ BTM_TRACE_DEBUG("%s, instance id: %d", __func__, inst_id);
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+ //TODO: Use expired ticks instead. GKI_get_os_tick_count
+ // provides time in msec. Diff between current and start time
+ // to figure out remaining duration
+ UINT16 duration = p_inst->duration;
+
+ if (TRUE == p_inst->in_use)
+ {
+ // Verify the evt prop directed adv bit is 0
+ if (!(p_inst->evt_prop & 0x04))
+ btm_ble_enable_extended_adv (TRUE, p_inst->inst_id, duration, 0, 0);
+ else
+ {
+ //mark directed adv as disabled if adv has been stopped
+ (p_inst->p_cback)(BTM_BLE_MULTI_ADV_DISABLE_EVT,p_inst->inst_id,p_inst->p_ref,0);
+ p_inst->in_use = FALSE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_enable_all
+**
+** Description This function enables/disables all adv instances at once
+**
+** Parameters enable/disable
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_multi_adv_enable_all(UINT8 enable)
+{
+ BTM_TRACE_DEBUG("%s, enable = %d", __func__, enable);
+ int i;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
+ UINT8 enb = enable? 1:0;
+ UINT8 num_instances = 0;
+
+ for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i++, p_inst++)
+ {
+ if (p_inst->in_use) {
+ btm_ble_ext_enable_cb.set_ids[num_instances] = p_inst->inst_id - 1;
+ btm_ble_ext_enable_cb.durations[num_instances] = p_inst->duration * 100;
+ btm_ble_ext_enable_cb.max_adv_events[num_instances] = 0x00;
+ num_instances++;
+ }
+ }
+
+ if (num_instances == 0) return;
+
+ if (!enable)
+ {
+ if (btsnd_hcic_ble_set_extended_adv_enable(enb, 0, NULL, NULL, NULL)
+ == BTM_CMD_STARTED)
+ {
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_ENB, 1, 0);
+ }
+ }
+ else
+ {
+ if ((btsnd_hcic_ble_set_extended_adv_enable (enb,
+ num_instances,
+ btm_ble_ext_enable_cb.set_ids,
+ btm_ble_ext_enable_cb.durations,
+ btm_ble_ext_enable_cb.max_adv_events))
+ == BTM_CMD_STARTED)
+ {
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_ENB, 1, 0);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_adv_set_terminated_evt
+**
+** Description This function is a callback event when an adv set is
+** terminiated due to connection complete or due to duration
+** timeout
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btm_ble_adv_set_terminated_evt (UINT8* p)
+{
+ BTM_TRACE_EVENT("%s", __func__);
+ UINT8 status;
+ UINT8 inst_id;
+ UINT16 handle;
+ tBTM_BLE_MULTI_ADV_INST *p_inst;
+
+ STREAM_TO_UINT8(status,p);
+ STREAM_TO_UINT8(inst_id, p);
+
+ //Adjust inst_id to base 1
+ inst_id++;
+
+ STREAM_TO_UINT16(handle, p);
+ BTM_TRACE_DEBUG("%s, status = %d, inst_id = %d, handle = %x",
+ __func__, status, inst_id, handle);
+
+ if (inst_id > BTM_BleMaxMultiAdvInstanceCount() ||
+ inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD)
+ {
+ BTM_TRACE_ERROR("%s:Invalid instance received", __func__);
+ return;
+ }
+
+ p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+
+ if (status == BTM_BLE_EXTENDED_ADV_TIMEOUT)
+ {
+ p_inst->in_use = FALSE;
+ if (p_inst->p_cback)
+ (p_inst->p_cback)(BTM_BLE_MULTI_ADV_DISABLE_EVT,p_inst->inst_id, p_inst->p_ref, 0);
+ }
+
+ else if (status == HCI_SUCCESS)
+ {
+ btm_ble_ext_adv_reenable(inst_id);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_adv_extension_operation_complete
+**
+** Description This function is a callback event of adv extension operation
+** including write rpa, set adv data/scan rsp data
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btm_ble_adv_extension_operation_complete(UINT8* p, UINT16 hcicmd)
+{
+ UINT8 status;
+ UINT8 cb_evt = 0, opcode;
+ UINT8 subcode = 0;
+ UINT8 inst_id;
+ tBTM_BLE_MULTI_ADV_INST *p_inst ;
+ STREAM_TO_UINT8 (status, p);
+
+ BTM_TRACE_EVENT ("%s, status: %d, opcode = %d", __func__, status, hcicmd);
+
+ if (status != HCI_SUCCESS)
+ {
+ BTM_TRACE_ERROR ("%s, HCI command failure", __func__);
+ return;
+ }
+
+ btm_ble_multi_adv_deq_op_q(&opcode, &inst_id, &cb_evt);
+
+ switch (hcicmd)
+ {
+ case HCI_BLE_WRITE_EXTENDED_ADV_RPA:
+ subcode = BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR;
+ break;
+ case HCI_BLE_WRITE_EXTENDED_ADV_DATA:
+ subcode = BTM_BLE_MULTI_ADV_WRITE_ADV_DATA;
+ break;
+ case HCI_BLE_WRITE_EXTENDED_SCAN_RSP_DATA:
+ subcode = BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA;
+ break;
+ case HCI_BLE_WRITE_EXTENDED_ADV_PARAMS:
+ subcode = BTM_BLE_MULTI_ADV_SET_PARAM;
+ break;
+ case HCI_BLE_WRITE_EXTENDED_ADV_ENABLE:
+ subcode = BTM_BLE_MULTI_ADV_ENB;
+ break;
+ }
+
+ if (opcode != subcode)
+ {
+ BTM_TRACE_ERROR("got unexpected Event, expected: %d got: %d", opcode, subcode);
+ return;
+ }
+ p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+
+ if (cb_evt != 0 && p_inst->p_cback != NULL)
+ {
+ (p_inst->p_cback)(cb_evt, inst_id, p_inst->p_ref, status);
+ }
+ return;
+}
+
+UINT8 BTM_BleGetAvailableMAInstance ()
+{
+ int index = 0;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
+
+ BTM_TRACE_EVENT("BTM_BleGetAvailableMAInstance");
+
+ for (index = 0; index < BTM_BleMaxMultiAdvInstanceCount() - 1; index++, p_inst++)
+ {
+ if (FALSE == p_inst->in_use)
+ break;
+ }
+ return index;
+}
+
+#endif
#endif
diff --git a/stack/btm/btm_ble_privacy.c b/stack/btm/btm_ble_privacy.c
index c8fe541..0805d34 100644
--- a/stack/btm/btm_ble_privacy.c
+++ b/stack/btm/btm_ble_privacy.c
@@ -610,6 +610,15 @@
if (btm_ble_suspend_bg_conn())
p_ble_cb->suspended_rl_state |= BTM_BLE_RL_INIT;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ /* Disable extended adv sets if any is enabled*/
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_EXT_ADV;
+ btm_ble_multi_adv_enable_all(FALSE);
+ }
+#endif
+
return TRUE;
}
@@ -628,6 +637,8 @@
{
tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+ p_ble_cb->inq_var.scan_duration = 0;
+ p_ble_cb->inq_var.scan_period = 0;
if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV)
btm_ble_start_adv();
@@ -637,6 +648,14 @@
if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT)
btm_ble_resume_bg_conn();
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_EXT_ADV)
+ btm_ble_multi_adv_enable_all(TRUE);
+ }
+#endif
+
p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
}
@@ -747,6 +766,61 @@
return TRUE;
}
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+/*******************************************************************************
+**
+** Function btm_ble_add_multi_adv_rpa
+**
+** Description This function adds a dummy rpa to the resolving list for
+** auto generating the mutli adv set rpa
+**
+** Parameters peer rpa to be added, addr_type
+**
+** Returns TRUE if device added, otherwise false
+**
+*******************************************************************************/
+BOOLEAN btm_ble_add_multi_adv_rpa(BD_ADDR bda, tBLE_ADDR_TYPE addr_type)
+{
+ BOOLEAN rt = FALSE;
+ UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state;
+ BTM_TRACE_DEBUG("%s, mask = %d", __func__, rl_mask);
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ BTM_TRACE_ERROR("%s, resolving list not available", __func__);
+ return rt;
+ }
+
+ if (!controller_get_interface()->supports_ble_privacy()) {
+ BTM_TRACE_ERROR("%s, privacy not supported", __func__);
+ return rt;
+ }
+
+ if (btm_cb.ble_ctr_cb.resolving_list_avail_size == 0) {
+ BTM_TRACE_ERROR("%s, resolving list already full", __func__);
+ return rt;
+ }
+
+ if (rl_mask)
+ {
+ if (!btm_ble_disable_resolving_list (rl_mask, FALSE)) {
+ return rt;
+ }
+ }
+
+ UINT8 *local_irk = btm_cb.devcb.id_keys.irk;
+ BT_OCTET16 peer_irk = {0};
+ BTM_TRACE_DEBUG("%s:adding device to controller resolving list", __func__);
+ rt = btsnd_hcic_ble_add_device_resolving_list(addr_type, bda, peer_irk, local_irk);
+
+ if (rt)
+ btm_ble_enq_resolving_list_pending(bda, BTM_BLE_META_ADD_IRK_ENTRY);
+
+ if (rl_mask)
+ btm_ble_enable_resolving_list(rl_mask);
+ return rt;
+}
+#endif
+
/*******************************************************************************
**
** Function btm_ble_resolving_list_load_dev
@@ -807,6 +881,12 @@
// use identical IRK for now
rt = btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type,
p_dev_rec->ble.static_addr, peer_irk, local_irk);
+ if (rt && controller_get_interface()->supports_set_le_privacy_mode()) {
+ BTM_TRACE_DEBUG("%s:adding device privacy mode", __func__);
+ rt = btsnd_hcic_ble_set_privacy_mode(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr,
+ 0x01);
+ }
}
else
{
diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
index c7a0b38..8794e4e 100644
--- a/stack/btm/btm_dev.c
+++ b/stack/btm/btm_dev.c
@@ -296,6 +296,11 @@
*******************************************************************************/
void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec)
{
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+ p_dev_rec->sec_flags = 0;
+ p_dev_rec->sm4 = BTM_SM4_UNKNOWN;
+ p_dev_rec->p_callback = NULL;
+
#if BLE_INCLUDED == TRUE
/* Clear out any saved BLE keys */
btm_sec_clear_ble_keys (p_dev_rec);
@@ -470,7 +475,8 @@
/* remove the combined record */
list_remove(btm_cb.sec_dev_rec, p_dev_rec);
- break;
+
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
}
/* an RPA device entry is a duplicate of the target record */
@@ -484,7 +490,6 @@
/* remove the combined record */
list_remove(btm_cb.sec_dev_rec, p_dev_rec);
}
- break;
}
}
#endif
diff --git a/stack/btm/btm_devctl.c b/stack/btm/btm_devctl.c
index 18e20b5..8105298 100644
--- a/stack/btm/btm_devctl.c
+++ b/stack/btm/btm_devctl.c
@@ -178,7 +178,15 @@
btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
btm_cb.ble_ctr_cb.p_select_cback = NULL;
gatt_reset_bgdev_list();
- btm_ble_multi_adv_init();
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller->supports_ble() && controller->supports_ble_extended_advertisements() &&
+ controller->get_ble_adv_ext_size() > 0) {
+ // provide an extra instance to accomodate for the 0th instance
+ btm_ble_multi_adv_init(controller->get_ble_adv_ext_size() + 1);
+ }
+#endif
+
#endif
btm_pm_reset();
@@ -200,6 +208,12 @@
btm_ble_white_list_init(controller->get_ble_white_list_size());
l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble());
}
+
+ if(controller->supports_ble_two_mbps_rate()) {
+ /* set 2mbps Tx and Rx if supported*/
+ btsnd_hcic_ble_set_default_data_rate(0, BTM_DATA_RATE_TWO|BTM_DATA_RATE_ONE,
+ BTM_DATA_RATE_TWO|BTM_DATA_RATE_ONE);
+ }
#endif
BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len);
@@ -226,6 +240,17 @@
);
}
+void BTM_HCI_Reset(void)
+{
+ /* Flush all ACL connections */
+ btm_acl_device_down();
+
+ /* Clear the callback, so application would not hang on reset */
+ btm_db_reset();
+
+ btsnd_hcic_reset(LOCAL_BR_EDR_CONTROLLER_ID);
+}
+
/*******************************************************************************
**
** Function BTM_IsDeviceUp
@@ -426,6 +451,11 @@
/* Nothing to do for page 2 */
break;
+ /* Extended Page 3 */
+ case HCI_EXT_FEATURES_PAGE_3:
+ /* Nothing to do for page 3 */
+ break;
+
default:
BTM_TRACE_ERROR("btm_decode_ext_features_page page=%d unknown", page_number);
break;
@@ -632,6 +662,58 @@
return (p_prev);
}
+
+/*******************************************************************************
+**
+** Function BTM_Hci_Raw_Command
+**
+** Description Send HCI raw command to the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent. Does not expect command complete
+** event. (command cmpl callback param is NULL)
+** BTM_CMD_STARTED Command sent. Waiting for command cmpl event.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_Hci_Raw_Command(UINT16 opcode, UINT8 param_len,
+ UINT8 *p_param_buf, tBTM_RAW_CMPL_CB *p_cb)
+{
+ void *p_buf;
+#if HCI_RAW_CMD_INCLUDED == TRUE
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+#endif
+
+ BTM_TRACE_EVENT ("BTM: BTM_Hci_Raw_Command: Opcode: 0x%04X, ParamLen: %i.",
+ opcode, param_len);
+
+ /* Allocate a buffer to hold HCI command plus the callback function */
+ p_buf = osi_malloc((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) +
+ param_len + HCIC_PREAMBLE_SIZE));
+ if (p_buf != NULL)
+ {
+ btsnd_hcic_raw_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb);
+
+ /* Return value */
+#if HCI_RAW_CMD_INCLUDED == TRUE
+ if (p_cb != NULL) {
+ if(p_cb != (p_devcb->p_hci_evt_cb)) {
+ p_devcb->p_hci_evt_cb = p_cb;
+ }
+ return BTM_CMD_STARTED;
+ }
+#else
+ if (p_cb != NULL)
+ return BTM_CMD_STARTED;
+#endif
+ else
+ return BTM_SUCCESS;
+ }
+ else
+ return BTM_NO_RESOURCES;
+
+}
+
/*******************************************************************************
**
** Function BTM_VendorSpecificCommand
@@ -667,6 +749,33 @@
return (BTM_SUCCESS);
}
+#if HCI_RAW_CMD_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_hci_event
+**
+** Description This function is called when HCI event is received
+** from the HCI layer.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_hci_event(UINT8 *p, UINT8 event_code, UINT8 param_len)
+{
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+ tBTM_RAW_CMPL raw_cplt_params;
+
+ /* If there was a callback address for raw cmd complete, call it */
+ if (p_devcb->p_hci_evt_cb)
+ {
+ /* Pass paramters to the callback function */
+ raw_cplt_params.event_code = event_code; /* Number of bytes in return info */
+ raw_cplt_params.param_len = param_len; /* Number of bytes in return info */
+ raw_cplt_params.p_param_buf = p;
+ (p_devcb->p_hci_evt_cb) (&raw_cplt_params); /* Call the cmd complete callback function */
+ }
+}
+#endif
/*******************************************************************************
**
diff --git a/stack/btm/btm_inq.c b/stack/btm/btm_inq.c
index d315c11..9d9a213 100644
--- a/stack/btm/btm_inq.c
+++ b/stack/btm/btm_inq.c
@@ -171,6 +171,11 @@
BOOLEAN cod_limited;
BTM_TRACE_API ("BTM_SetDiscoverability");
+
+ /* Make sure the controller is active */
+ if (!controller_get_interface()->get_is_ready())
+ return (BTM_DEV_RESET);
+
#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
if (controller_get_interface()->supports_ble())
{
@@ -188,10 +193,6 @@
if (inq_mode > BTM_MAX_DISCOVERABLE)
return (BTM_ILLEGAL_VALUE);
- /* Make sure the controller is active */
- if (!controller_get_interface()->get_is_ready())
- return (BTM_DEV_RESET);
-
/* If the window and/or interval is '0', set to default values */
if (!window)
window = BTM_DEFAULT_DISC_WINDOW;
@@ -844,7 +845,17 @@
p_inq->scan_type = INQ_GENERAL;
p_inq->inq_active = BTM_INQUIRY_INACTIVE;
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
- btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
+ {
+ btsnd_hcic_ble_set_extended_scan_enable(BTM_BLE_SCAN_DISABLE,BTM_BLE_DUPLICATE_ENABLE, 0, 0);
+ }
+ else
+#endif
+ {
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ }
}
else
#endif
@@ -1993,6 +2004,10 @@
p_cur->dev_class[2] = dc[2];
p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+ BTM_TRACE_WARNING ("btm_process_inq_results: BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ bda[0], bda[1], bda[2],bda[3], bda[4], bda[5]);
+ BTM_TRACE_WARNING ("btm_process_inq_results: Dev class: %02x-%02x-%02x",
+ p_cur->dev_class[0], p_cur->dev_class[1], p_cur->dev_class[2]);
p_i->time_of_resp = time_get_os_boottime_ms();
if (p_i->inq_count != p_inq->inq_counter)
@@ -2048,6 +2063,8 @@
else
p_eir_data = NULL;
+ /* Set EIR data length */
+ p_cur->adv_data_len = HCI_EXT_INQ_RESPONSE_LEN;
/* If a callback is registered, call it with the results */
if (p_inq_results_cb)
(p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
@@ -2194,7 +2211,7 @@
if(p_inq->p_inq_ble_results_cb != NULL)
{
BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan");
- BTM_BleObserve(1,0, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb);
+ BTM_BleObserve(1,0/*duration*/, 0 /*period*/, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb);
}
#endif
}
@@ -2521,7 +2538,7 @@
** Returns pointer of EIR data
**
*******************************************************************************/
-UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length )
+UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length, UINT16 adv_data_len )
{
UINT8 *p = p_eir;
UINT8 length;
@@ -2529,7 +2546,7 @@
BTM_TRACE_API("BTM_CheckEirData type=0x%02X", type);
STREAM_TO_UINT8(length, p);
- while( length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN))
+ while( length && (p - p_eir <= adv_data_len))
{
STREAM_TO_UINT8(eir_type, p);
if( eir_type == type )
@@ -2826,10 +2843,10 @@
break;
}
- p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len );
+ p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len, HCI_EXT_INQ_RESPONSE_LEN);
if(p_uuid_data == NULL)
{
- p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len );
+ p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len, HCI_EXT_INQ_RESPONSE_LEN);
*p_uuid_list_type = more_type;
}
else
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index c3357c2..d633c33 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -104,6 +104,8 @@
#define BTM_ACL_SWKEY_STATE_ENCRYPTION_ON 4
#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5
UINT8 switch_role_state;
+#define BTM_MAX_SW_ROLE_FAILED_ATTEMPTS 3
+ UINT8 switch_role_failed_attempts;
#define BTM_ACL_ENCRYPT_STATE_IDLE 0
#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF 1 /* encryption turning off */
@@ -182,6 +184,11 @@
#endif /* BLE_INCLUDED */
+#if HCI_RAW_CMD_INCLUDED == TRUE
+ tBTM_RAW_CMPL_CB *p_hci_evt_cb; /* Callback function to be called when
+ HCI event is received successfully */
+#endif
+
tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */
tBTM_AUTH_REQ loc_auth_req; /* the auth_req flag */
BOOLEAN secure_connections_only; /* Rejects service level 0 connections if */
@@ -615,6 +622,11 @@
#define BTM_SEC_NO_LAST_SERVICE_ID 0
UINT8 last_author_service_id; /* ID of last serviced authorized: Reset after each l2cap connection */
+#if (defined(BTM_SAFE_REATTEMPT_ROLE_SWITCH) && BTM_SAFE_REATTEMPT_ROLE_SWITCH == TRUE)
+#define BTM_MAX_BL_SW_ROLE_ATTEMPTS 1
+ UINT8 switch_role_attempts;
+#endif
+
} tBTM_SEC_DEV_REC;
#define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
@@ -819,6 +831,7 @@
UINT16 ediv; /* received ediv value from LTK request */
UINT8 key_size;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ tBTM_BLE_ADV_EXT_CB ble_adv_ext_cb;
#endif
/* Packet types supported by the local device */
@@ -971,6 +984,7 @@
extern tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types);
extern void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset);
extern void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role);
+extern void btm_blacklist_role_change_device (BD_ADDR bd_addr, UINT8 hci_status);
extern void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
extern UINT16 btm_get_acl_disc_reason_code (void);
extern tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport);
@@ -1041,8 +1055,15 @@
extern tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec);
extern BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec);
extern void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+extern BOOLEAN btm_ble_add_multi_adv_rpa(BD_ADDR bda, tBLE_ADDR_TYPE addr_type);
+#endif
#endif /* BLE_INCLUDED */
+/* HCI event handler */
+#if HCI_RAW_CMD_INCLUDED == TRUE
+extern void btm_hci_event(UINT8 *p, UINT8 event_code, UINT8 param_len);
+#endif
/* Vendor Specific Command complete evt handler */
extern void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len,
tBTM_CMPL_CB *p_vsc_cplt_cback);
@@ -1077,6 +1098,8 @@
extern tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
UINT32 mx_proto_id, UINT32 mx_chan_id,
tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+
+extern tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec);
extern void btm_sec_conn_req (UINT8 *bda, UINT8 *dc);
extern void btm_create_conn_cancel_complete (UINT8 *p);
diff --git a/stack/btm/btm_pm.c b/stack/btm/btm_pm.c
index e24563b..986c60d 100644
--- a/stack/btm/btm_pm.c
+++ b/stack/btm/btm_pm.c
@@ -207,7 +207,7 @@
/* check if the requested mode is supported */
ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
p_features = BTM_ReadLocalFeatures();
- if( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) )
+ if(ind < BTM_PM_NUM_SET_MODES && !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) )
return BTM_MODE_UNSUPPORTED;
}
@@ -386,7 +386,7 @@
tBTM_PM_STATUS_CBACK *cb = NULL;
/* clear the pending request for application */
- if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ if( (btm_cb.pm_pend_id < BTM_PM_SET_ONLY_ID) &&
(btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
{
cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
@@ -777,10 +777,11 @@
else /* the command was not successfull. Stay in the same state */
{
pm_status = BTM_PM_STS_ERROR;
+ GENERATE_VENDOR_LOGS();
}
/* notify the caller is appropriate */
- if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ if( (btm_cb.pm_pend_id < BTM_PM_SET_ONLY_ID) &&
(btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
{
(*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
diff --git a/stack/btm/btm_sco.c b/stack/btm/btm_sco.c
index 4ceb640..0cc96ef 100644
--- a/stack/btm/btm_sco.c
+++ b/stack/btm/btm_sco.c
@@ -35,7 +35,8 @@
#include "hcidefs.h"
#include "bt_utils.h"
#include "device/include/controller.h"
-
+#include "device/include/interop.h"
+extern void bta_dm_pm_set_sniff_policy_toggle(BD_ADDR peer_addr, BOOLEAN bDisable);
#if BTM_SCO_INCLUDED == TRUE
@@ -641,6 +642,10 @@
{
BTM_TRACE_DEBUG("%s In sniff, park or pend mode: %d", __func__, state);
memset( (void*)&pm, 0, sizeof(pm));
+ if (interop_match_addr(INTEROP_DISABLE_SNIFF_POLICY_DURING_SCO,
+ (const bt_bdaddr_t *)&remote_bda)) {
+ bta_dm_pm_set_sniff_policy_toggle(remote_bda, true);
+ }
pm.mode = BTM_PM_MD_ACTIVE;
BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
p->state = SCO_ST_PEND_UNPARK;
@@ -708,7 +713,10 @@
{
BTM_TRACE_API("BTM_CreateSco -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d",
acl_handle, btm_cb.sco_cb.desired_sco_mode);
-
+ if (interop_match_addr(INTEROP_DISABLE_SNIFF_POLICY_DURING_SCO,
+ (const bt_bdaddr_t *)&remote_bda)) {
+ bta_dm_pm_set_sniff_policy_toggle(remote_bda, true);
+ }
if ((btm_send_connect_request(acl_handle, p_setup)) != BTM_CMD_STARTED)
return (BTM_NO_RESOURCES);
@@ -967,12 +975,18 @@
BTM_TRACE_API("Role Change pending for HCI handle 0x%04x",hci_handle);
p->state = SCO_ST_PEND_ROLECHANGE;
}
- /* avoid calling disconnect callback because of sco creation race */
- else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION)
- {
- p->state = SCO_ST_UNUSED;
- (*p->p_disc_cb)(xx);
- }
+
+ /* call disconnect callback to allow SCO state machine move to proper state.
+ * In sco creation race condition when remote rejects our sco request with
+ * error LMP_ERR_TRANS_COLLISION and doesn't even send its request to us,
+ * our SCO state machine remains stuck in SCO_ST_CONNECTING (BTA state machine
+ * in SCO_OPENING_ST). We need to call SCO disconnect callback in such case
+ * also to recover the SCO states. BTA SCO state will move to Listening after
+ * recovery allowing further outgoing connections successfully. Any incoming
+ * connection from remote will also be allowed.
+ */
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
}
else
{
@@ -1063,14 +1077,21 @@
tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
{
#if (BTM_MAX_SCO_LINKS>0)
- tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+ tSCO_CONN *p;
UINT16 tempstate;
tBTM_PM_STATE state = BTM_PM_ST_INVALID;
BTM_TRACE_DEBUG("%s", __func__);
/* Validity check */
- if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED))
+ if (sco_inx >= BTM_MAX_SCO_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ /* Fix for below Klockwork Issue
+ * Array 'btm_cb.sco_cb.sco_db' of size 3 may use index value(s) 0..USHRT_MAX-1 */
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ if ((p == NULL) || (p->state == SCO_ST_UNUSED))
return (BTM_UNKNOWN_ADDR);
/* If no HCI handle, simply drop the connection and return */
diff --git a/stack/btm/btm_sec.c b/stack/btm/btm_sec.c
index 5b3a576..099d512 100644
--- a/stack/btm/btm_sec.c
+++ b/stack/btm/btm_sec.c
@@ -68,7 +68,7 @@
UINT32 mx_proto_id,
UINT32 mx_chan_id);
-static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec);
+
static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec);
static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec);
static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec);
@@ -215,10 +215,12 @@
*******************************************************************************/
static BOOLEAN btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec)
{
- if(BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, p_serv_rec->service_id))
+ if(p_serv_rec->service_id < BTM_SEC_MAX_SERVICES && BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, p_serv_rec->service_id))
{
return(TRUE);
}
+ else
+ BTM_TRACE_ERROR("BTM_Sec: Service Id: %d not found", p_serv_rec->service_id);
return(FALSE);
}
@@ -609,7 +611,7 @@
{
p_srec->orig_mx_chan_id = mx_chan_id;
#if BTM_SEC_SERVICE_NAME_LEN > 0
- strlcpy ((char *)p_srec->orig_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN);
+ strlcpy ((char *)p_srec->orig_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN + 1);
#endif
/* clear out the old setting, just in case it exists */
#if (L2CAP_UCD_INCLUDED == TRUE)
@@ -657,7 +659,7 @@
{
p_srec->term_mx_chan_id = mx_chan_id;
#if BTM_SEC_SERVICE_NAME_LEN > 0
- strlcpy ((char *)p_srec->term_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN);
+ strlcpy ((char *)p_srec->term_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN + 1);
#endif
/* clear out the old setting, just in case it exists */
#if (L2CAP_UCD_INCLUDED == TRUE)
@@ -894,6 +896,7 @@
btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ LOG_INFO(LOG_TAG, "%s: Negative pin code reply: btm_cb.pairing_flags : %d", __func__, btm_cb.pairing_flags);
btsnd_hcic_pin_code_neg_reply (bd_addr);
}
else
@@ -906,6 +909,7 @@
if (trusted_mask)
BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ p_dev_rec->pin_code_length = pin_len;
if (pin_len >= 16) {
p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
}
@@ -916,7 +920,6 @@
{
/* This is start of the dedicated bonding if local device is 2.0 */
btm_cb.pin_code_len = pin_len;
- p_dev_rec->pin_code_length = pin_len;
memcpy (btm_cb.pin_code, p_pin, pin_len);
btm_cb.security_mode_changed = TRUE;
@@ -997,22 +1000,28 @@
{
return(BTM_NO_RESOURCES);
}
-
+ if (!controller_get_interface()->get_is_ready())
+ {
+ BTM_TRACE_ERROR ("%s controller module is not ready", __func__);
+ return(BTM_NO_RESOURCES);
+ }
BTM_TRACE_DEBUG ("before update sec_flags=0x%x", p_dev_rec->sec_flags);
/* Finished if connection is active and already paired */
- if ( ((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR
+ if ((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR
&& (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
-#if (BLE_INCLUDED == TRUE)
- ||((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE
- && (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))
-#endif
-
- )
{
BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
return(BTM_SUCCESS);
}
+#if (BLE_INCLUDED == TRUE)
+ if ((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE
+ && (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))
+ {
+ BTM_TRACE_WARNING("BTM_SecBond. Last Pairing still in progress. Wait!");
+ return(BTM_CMD_STARTED);
+ }
+#endif
/* Tell controller to get rid of the link key if it has one stored */
if ((BTM_DeleteStoredLinkKey (bd_addr, NULL)) != BTM_SUCCESS)
@@ -1546,8 +1555,10 @@
if (res == BTM_SUCCESS)
{
if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
}
btsnd_hcic_user_conf_reply (bd_addr, TRUE);
@@ -2417,7 +2428,7 @@
p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
(*p_callback) (bd_addr, transport, p_ref_data, rc);
- return BTM_SUCCESS;
+ return BTM_CMD_STARTED;
}
}
@@ -3006,6 +3017,7 @@
if (p_lcb && (p_lcb->link_state == LST_CONNECTED || p_lcb->link_state == LST_CONNECTING))
{
BTM_TRACE_WARNING("%s Connection already exists", __func__);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
return BTM_CMD_STARTED;
}
@@ -3184,7 +3196,12 @@
return;
}
- if (status != HCI_SUCCESS)
+ if (status == HCI_ERR_CONTROLLER_BUSY)
+ {
+ BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete() Wait for incoming connection");
+ return;
+ }
+ else if (status != HCI_SUCCESS)
{
btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
@@ -3456,6 +3473,7 @@
Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
*/
+ LOG_INFO(LOG_TAG, "%s: btsnd_hcic_io_cap_req_neg_reply: err_code : %d" , __func__, err_code);
btsnd_hcic_io_cap_req_neg_reply(evt_data.bd_addr, err_code);
return;
}
@@ -3472,12 +3490,12 @@
if (btm_cb.security_mode == BTM_SEC_MODE_SC)
{
/* SC only mode device requires MITM protection */
- evt_data.auth_req = BTM_AUTH_SP_YES;
+ evt_data.auth_req = BTM_AUTH_SPGB_YES;
}
else
{
evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags &
- BTM_SEC_OUT_MITM)? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO;
+ BTM_SEC_OUT_MITM)? BTM_AUTH_SPGB_YES : BTM_AUTH_SPGB_NO;
}
}
}
@@ -4031,8 +4049,23 @@
}
if (!p_dev_rec)
- return;
+ {
+ /* check if the handle is BTM_INVALID_HCI_HANDLE */
+ if(handle == BTM_INVALID_HCI_HANDLE)
+ {
+ /* get the device with auth type as BTM_SEC_STATE_AUTHENTICATING */
+ p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_AUTHENTICATING);
+ if ( p_dev_rec && (btm_cb.api.p_auth_complete_callback))
+ {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ BTM_TRACE_DEBUG("btm_sec_auth_complete: Invalid Handle, send Auth failure");
+ }
+ }
+ return;
+ }
/* keep the old sm4 flag and clear the retry bit in control block */
old_sm4 = p_dev_rec->sm4;
p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
@@ -4074,8 +4107,13 @@
/* User probably Disabled the keyboard while it was asleap. Let her try */
if (btm_cb.api.p_auth_complete_callback)
{
- /* report the suthentication status */
- if (old_state != BTM_PAIR_STATE_IDLE)
+
+ /* don't post auth status key missing,peer user disc and connection timeout cases */
+ if ((old_state != BTM_PAIR_STATE_IDLE) ||
+ ((status != HCI_SUCCESS) &&
+ (status != HCI_ERR_PEER_USER) &&
+ (status != HCI_ERR_CONNECTION_TOUT) &&
+ (status != HCI_ERR_LMP_RESPONSE_TIMEOUT)))
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
@@ -4105,12 +4143,10 @@
{
BTM_TRACE_DEBUG ("link encrypted afer dedic bonding can use SMP_BR_CHNL");
- if (btm_sec_is_master(p_dev_rec))
- {
- // Encryption is required to start SM over BR/EDR
- // indicate that this is encryption after authentication
- BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL, 0);
- }
+ // Encryption is required to start SM over BR/EDR
+ // from DD bonding initiator.
+ // indicate that this is encryption after authentication
+ BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL, 0);
}
l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
}
@@ -4151,6 +4187,11 @@
}
}
+ if (btm_cb.api.p_auth_complete_callback && (status == HCI_ERR_KEY_MISSING))
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+
btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE);
if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
@@ -4249,11 +4290,16 @@
if (p_acl && p_acl->transport == BT_TRANSPORT_LE)
{
- if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE ||
+ if (status == HCI_ERR_AUTH_FAILURE ||
status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)
{
p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN);
p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+ GENERATE_VENDOR_LOGS();
+ }
+ else if (status == HCI_ERR_KEY_MISSING)
+ {
+ btm_sec_disconnect(handle, status);
}
btm_ble_link_encrypted(p_dev_rec->ble.pseudo_addr, encr_enable);
return;
@@ -4309,6 +4355,7 @@
BTM_TRACE_DEBUG("updated link key type to %d", p_dev_rec->link_key_type);
btm_send_link_key_notif(p_dev_rec);
+ GENERATE_VENDOR_LOGS();
}
}
}
@@ -4359,6 +4406,7 @@
BTM_TRACE_EVENT("%s", __func__);
btm_cb.p_collided_dev_rec = 0;
+ btm_cb.collision_start_time = 0;
if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
{
@@ -4390,6 +4438,7 @@
BOOLEAN is_pairing_device = FALSE;
tACL_CONN *p_acl_cb;
UINT8 bit_shift = 0;
+ BTM_TRACE_DEBUG ("%s",__func__);
btm_acl_resubmit_page();
@@ -4398,10 +4447,10 @@
#if (BT_USE_TRACES == TRUE)
if (p_dev_rec)
{
- BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x RName:%s",
+ BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x RName:%s,new_encr_key_256 to %d",
btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
(bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5],
- p_dev_rec->sec_bd_name);
+ p_dev_rec->sec_bd_name,p_dev_rec->new_encryption_key_is_p256);
}
else
{
@@ -4526,7 +4575,7 @@
return;
}
/* wait for incoming connection without resetting pairing state */
- else if (status == HCI_ERR_CONNECTION_EXISTS)
+ else if ((status == HCI_ERR_CONNECTION_EXISTS) || (status == HCI_ERR_CONTROLLER_BUSY))
{
BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: Wait for incoming connection");
return;
@@ -4568,7 +4617,6 @@
(((status == HCI_ERR_AUTH_FAILURE) ||
(status == HCI_ERR_KEY_MISSING) ||
(status == HCI_ERR_HOST_REJECT_SECURITY) ||
- (status == HCI_ERR_PAIRING_NOT_ALLOWED) ||
(status == HCI_ERR_UNIT_KEY_USED) ||
(status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
(status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
@@ -4593,6 +4641,14 @@
p_dev_rec->sec_bd_name, status);
}
}
+ /*as p_auth_complete_callback may remove p_de_rec from list, so we
+ * need find it again */
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if(p_dev_rec == NULL)
+ {
+ BTM_TRACE_ERROR("%s p_dev_rec have been removed, return", __func__);
+ return;
+ }
if (status == HCI_ERR_CONNECTION_TOUT || status == HCI_ERR_LMP_RESPONSE_TIMEOUT ||
status == HCI_ERR_UNSPECIFIED || status == HCI_ERR_PAGE_TIMEOUT)
@@ -4682,12 +4738,7 @@
/* After connection is established we perform security if we do not know */
/* the name, or if we are originator because some procedure can have */
/* been scheduled while connection was down */
- BTM_TRACE_DEBUG ("is_originator:%d ", p_dev_rec->is_originator);
- if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator)
- {
- if ((res = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
- btm_sec_dev_rec_cback_event (p_dev_rec, res, FALSE);
- }
+ BTM_TRACE_DEBUG ("is_originator:%d ,new_encr_key_256 to %d", p_dev_rec->is_originator,p_dev_rec->new_encryption_key_is_p256);
return;
}
@@ -4767,7 +4818,7 @@
" remote_name:%s", __func__, p_dev_rec->security_required, btm_pair_state_descr(btm_cb.pairing_state),
reason, bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5], p_dev_rec->sec_bd_name);
- BTM_TRACE_EVENT("%s before update sec_flags=0x%x", __func__, p_dev_rec->sec_flags);
+ BTM_TRACE_EVENT("%s before update sec_flags=0x%x, new_encr_key_256 to %d ", __func__, p_dev_rec->sec_flags,p_dev_rec->new_encryption_key_is_p256);
/* If we are in the process of bonding we need to tell client that auth failed */
if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
@@ -4837,7 +4888,7 @@
p_dev_rec->security_required = BTM_SEC_NONE;
p_callback = p_dev_rec->p_callback;
-
+ p_dev_rec->new_encryption_key_is_p256 = FALSE;
/* if security is pending, send callback to clean up the security state */
if(p_callback)
{
@@ -4846,7 +4897,7 @@
(*p_callback) (p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, BTM_ERR_PROCESSING);
}
- BTM_TRACE_EVENT("%s after update sec_flags=0x%x", __func__, p_dev_rec->sec_flags);
+ BTM_TRACE_EVENT("%s after update sec_flags=0x%x,new_encr_key_256 to %d", __func__, p_dev_rec->sec_flags,p_dev_rec->new_encryption_key_is_p256);
}
/*******************************************************************************
@@ -5024,6 +5075,7 @@
l2c_pin_code_request (p_bda);
/* The link key is not in the database and it is not known to the manager */
+ LOG_INFO(LOG_TAG, "%s: btsnd_hcic_link_key_neg_reply: p_dev_rec->sec_flags : %d" , __func__, p_dev_rec->sec_flags);
btsnd_hcic_link_key_neg_reply (p_bda);
}
@@ -5064,7 +5116,10 @@
case BTM_PAIR_STATE_WAIT_LOCAL_PIN:
if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0)
+ {
+ LOG_INFO(LOG_TAG, "%s: btsnd_hcic_pin_code_neg_reply: btm_cb.pairing_flags : %d" , __func__, btm_cb.pairing_flags);
btsnd_hcic_pin_code_neg_reply (p_cb->pairing_bda);
+ }
btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
/* We need to notify the UI that no longer need the PIN */
if (btm_cb.api.p_auth_complete_callback)
@@ -5090,6 +5145,7 @@
#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
case BTM_PAIR_STATE_KEY_ENTRY:
+ LOG_INFO(LOG_TAG, "%s: btsnd_hcic_user_passkey_neg_reply: BTM_LOCAL_IO_CAPS : %d" , __func__, BTM_LOCAL_IO_CAPS);
btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
/* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
break;
@@ -5128,6 +5184,23 @@
case BTM_PAIR_STATE_GET_REM_NAME:
/* We need to notify the UI that timeout has happened while waiting for authentication*/
btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (p_cb->pairing_bda, BT_TRANSPORT_BR_EDR);
+ /* If no channels on the connection, start idle timeout */
+ if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED))
+ {
+ if (!p_lcb->ccb_queue.p_first_ccb)
+ {
+ BTM_TRACE_WARNING("%s start idle timeout if no ccbs", __func__ );
+ l2cu_no_dynamic_ccbs (p_lcb);
+ }
+ else
+ {
+ BTM_TRACE_ERROR("%s hci disc triggered when last channel disconnects BDA: %08x%04x",
+ __func__,
+ (p_cb->pairing_bda[0]<<24) + (p_cb->pairing_bda[1]<<16) + (p_cb->pairing_bda[2]<<8) + p_cb->pairing_bda[3],
+ (p_cb->pairing_bda[4] << 8) + p_cb->pairing_bda[5]);
+ }
+ }
if (btm_cb.api.p_auth_complete_callback)
{
if (p_dev_rec == NULL)
@@ -5175,6 +5248,7 @@
if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) &&
(btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) )
{
+ LOG_INFO(LOG_TAG, "%s: btsnd_hcic_pin_code_neg_reply: btm_cb.pairing_state : %d", __func__, btm_cb.pairing_state);
btsnd_hcic_pin_code_neg_reply (p_bda);
return;
}
@@ -5183,6 +5257,7 @@
{
BTM_TRACE_WARNING ("btm_sec_pin_code_request() rejected - state: %s",
btm_pair_state_descr(btm_cb.pairing_state));
+ LOG_INFO(LOG_TAG,"%s btsnd_hcic_pin_code_neg_reply", __func__);
btsnd_hcic_pin_code_neg_reply (p_bda);
return;
}
@@ -5274,6 +5349,12 @@
}
else
{
+ if ((p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) &&
+ (memcmp (p_dev_rec->bd_addr, p_bda, BD_ADDR_LEN) == 0))
+ {
+ BTM_TRACE_WARNING("RNR initiated by security module and in progress");
+ return;
+ }
BTM_TRACE_EVENT ("btm_sec_pin_code_request going for remote name");
/* We received PIN code request for the device with unknown name */
@@ -5345,7 +5426,7 @@
** BTM_NO_RESOURCES - permission declined
**
*******************************************************************************/
-static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
+extern tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
{
BTM_TRACE_EVENT ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
@@ -5455,8 +5536,7 @@
{
BTM_TRACE_EVENT ("service id:%d, is trusted:%d",
p_dev_rec->p_cur_service->service_id,
- (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
- p_dev_rec->p_cur_service->service_id)));
+ btm_serv_trusted(p_dev_rec,p_dev_rec->p_cur_service));
if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == FALSE) &&
(p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
(BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
@@ -5958,6 +6038,7 @@
{
tBTM_SEC_CALLBACK *p_callback = p_dev_rec->p_callback;
+ BTM_TRACE_DEBUG ("%s ",__func__);
if (p_dev_rec->p_callback)
{
p_dev_rec->p_callback = NULL;
diff --git a/stack/btu/btu_hcif.c b/stack/btu/btu_hcif.c
index ee72841..5476f53 100644
--- a/stack/btu/btu_hcif.c
+++ b/stack/btu/btu_hcif.c
@@ -36,6 +36,7 @@
#include "device/include/controller.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "osi/include/properties.h"
#include "bt_types.h"
#include "bt_utils.h"
#include "btm_api.h"
@@ -125,7 +126,13 @@
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
static void btu_ble_proc_enhanced_conn_cmpl (UINT8 *p, UINT16 evt_len);
#endif
+static void btu_ble_data_rate_update_evt(UINT8 *p, UINT16 evt_len);
+#if (defined BLE_EXTENDED_ADV_SUPPORT && BLE_EXTENDED_ADV_SUPPORT == TRUE)
+static void btu_ble_adv_terminated_evt (UINT8* p);
+static void btu_ble_process_ext_adv_pkt (UINT8 *p);
+static void btu_ble_scan_timeout_evt (void);
+#endif
#endif
/*******************************************************************************
@@ -333,6 +340,23 @@
case HCI_BLE_DATA_LENGTH_CHANGE_EVT:
btu_ble_data_length_change_evt(p, hci_evt_len);
break;
+
+ case HCI_BLE_PHY_UPDATE_EVT:
+ btu_ble_data_rate_update_evt(p, hci_evt_len);
+ break;
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && BLE_EXTENDED_ADV_SUPPORT == TRUE)
+ case HCI_BLE_EXT_ADV_TERMINATED_EVT:
+ btu_ble_adv_terminated_evt(p);
+ break;
+
+ case HCI_BLE_EXT_ADV_PKT_RPT_EVT:
+ btu_ble_process_ext_adv_pkt(p);
+ break;
+ case HCI_BLE_SCAN_TIMEOUT_EVT:
+ btu_ble_scan_timeout_evt();
+ break;
+#endif
}
break;
#endif /* BLE_INCLUDED */
@@ -340,6 +364,9 @@
btm_vendor_specific_evt (p, hci_evt_len);
break;
}
+#if HCI_RAW_CMD_INCLUDED == TRUE
+ btm_hci_event (p, hci_evt_code , hci_evt_len);
+#endif
}
/*******************************************************************************
@@ -951,6 +978,8 @@
case HCI_BLE_TRANSMITTER_TEST:
case HCI_BLE_RECEIVER_TEST:
+ case HCI_BLE_ENH_TRANSMITTER_TEST:
+ case HCI_BLE_ENH_RECEIVER_TEST:
case HCI_BLE_TEST_END:
btm_ble_test_command_complete(p);
break;
@@ -975,8 +1004,23 @@
case HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL:
case HCI_BLE_SET_ADDR_RESOLUTION_ENABLE:
case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT:
- break;
+ break;
#endif
+ /* adv extension complete events*/
+#if (defined BLE_EXTENDED_ADV_SUPPORT && BLE_EXTENDED_ADV_SUPPORT == TRUE)
+ case HCI_BLE_WRITE_EXTENDED_ADV_RPA:
+ case HCI_BLE_WRITE_EXTENDED_ADV_DATA:
+ case HCI_BLE_WRITE_EXTENDED_SCAN_RSP_DATA:
+ case HCI_BLE_WRITE_EXTENDED_ADV_PARAMS:
+ case HCI_BLE_WRITE_EXTENDED_ADV_ENABLE:
+ btm_ble_adv_extension_operation_complete(p, opcode);
+ break;
+ case HCI_BLE_READ_MAX_ADV_LENGTH:
+ btm_ble_read_inst_length_complete (p, evt_len);
+ break;
+
+#endif
+
#endif /* (BLE_INCLUDED == TRUE) */
default:
@@ -1243,7 +1287,25 @@
/* Reset the controller */
if (BTM_IsDeviceUp())
- BTM_DeviceReset (NULL);
+ BTM_HCI_Reset();
+
+ if(*p == 0x0f || (*p == 0x0a))
+ {
+ HCI_TRACE_ERROR("Ctlr H/w error event - code:Tigger SSR");
+ bte_ssr_cleanup(0x33);//SSR reason 0x33 = HW ERR EVT
+ usleep(20000); /* 20 milliseconds */
+ //Reset SOC status to trigger hciattach service
+ if(osi_property_set("bluetooth.status", "off") < 0)
+ {
+ ALOGE("SSR: Error resetting SOC status\n ");
+ }
+ else
+ {
+ ALOGE("SSR: SOC Status is reset\n ");
+ }
+ /* Killing the process to force a restart as part of fault tolerance */
+ kill(getpid(), SIGKILL);
+ }
}
/*******************************************************************************
@@ -1277,7 +1339,7 @@
STREAM_TO_UINT8 (status, p);
STREAM_TO_BDADDR (bda, p);
STREAM_TO_UINT8 (role, p);
-
+ btm_blacklist_role_change_device(bda, status);
l2c_link_role_changed (bda, role, status);
btm_acl_role_changed(status, bda, role);
}
@@ -1713,13 +1775,33 @@
{
HCI_TRACE_EVENT("btu_ble_process_adv_pkt");
- btm_ble_process_adv_pkt(p);
+ btm_ble_process_adv_pkt(p, FALSE);
}
+
+
static void btu_ble_ll_conn_complete_evt ( UINT8 *p, UINT16 evt_len)
{
btm_ble_conn_complete(p, evt_len, FALSE);
}
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && BLE_EXTENDED_ADV_SUPPORT == TRUE)
+static void btu_ble_adv_terminated_evt (UINT8 *p)
+{
+ btm_ble_adv_set_terminated_evt(p);
+}
+
+static void btu_ble_process_ext_adv_pkt (UINT8 *p)
+{
+ btm_ble_process_adv_pkt(p, TRUE);
+}
+
+static void btu_ble_scan_timeout_evt (void)
+{
+ btm_ble_scan_timeout_evt();
+}
+#endif
+
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
static void btu_ble_proc_enhanced_conn_cmpl( UINT8 *p, UINT16 evt_len)
{
@@ -1804,5 +1886,25 @@
}
#endif /* BLE_LLT_INCLUDED */
+static void btu_ble_data_rate_update_evt(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT8 tx_phy;
+ UINT8 rx_phy;
+
+ if(!controller_get_interface()->supports_ble_two_mbps_rate())
+ {
+ HCI_TRACE_WARNING("%s, request not supported", __func__);
+ return;
+ }
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(tx_phy, p);
+ STREAM_TO_UINT8(rx_phy, p);
+ HCI_TRACE_DEBUG("%s Phy update evt, status=%d, handle = 0x%0x, tx_phy=%d, rx_phy=%d",
+ __func__, status, handle, tx_phy, rx_phy);
+}
+
#endif /* BLE_INCLUDED */
diff --git a/stack/gap/gap_conn.c b/stack/gap/gap_conn.c
index 1ee2c97..55df7cf 100644
--- a/stack/gap/gap_conn.c
+++ b/stack/gap/gap_conn.c
@@ -137,8 +137,9 @@
if ((p_ccb = gap_allocate_ccb()) == NULL)
return (GAP_INVALID_HANDLE);
- /* update the transport */
+ /* update the transport ,service_id */
p_ccb->transport = transport;
+ p_ccb->service_id = service_id;
/* If caller specified a BD address, save it */
if (p_rem_bda)
@@ -168,7 +169,7 @@
p_ccb->cfg = *p_cfg;
/* Configure L2CAP COC, if transport is LE */
- if (transport == BT_TRANSPORT_LE)
+ if (p_cfg && transport == BT_TRANSPORT_LE)
{
p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
@@ -216,7 +217,6 @@
}
/* Register with Security Manager for the specific security level */
- p_ccb->service_id = service_id;
if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name,
p_ccb->service_id, security, p_ccb->psm, 0, 0))
{
@@ -690,7 +690,7 @@
/*******************************************************************************
**
-** Function gap_tx_connect_ind
+** Function gap_tx_complete_ind
**
** Description Sends out GAP_EVT_TX_EMPTY when transmission has been
** completed.
@@ -709,6 +709,11 @@
GAP_TRACE_EVENT("%s: GAP_EVT_TX_EMPTY", __func__);
p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
}
+ else if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent >= 1))
+ {
+ GAP_TRACE_EVENT("%s: GAP_EVT_TX_DONE", __func__);
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_TX_DONE);
+ }
}
/*******************************************************************************
@@ -1201,6 +1206,7 @@
UINT16 xx;
UINT16 psm = p_ccb->psm;
UINT8 service_id = p_ccb->service_id;
+ tGAP_CCB *p_ccb_local = NULL;
/* Drop any buffers we may be holding */
p_ccb->rx_queue_size = 0;
@@ -1218,10 +1224,13 @@
p_ccb->con_state = GAP_CCB_STATE_IDLE;
/* If no-one else is using the PSM, deregister from L2CAP */
- for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+ for (xx = 0, p_ccb_local = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb_local++)
{
- if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->psm == psm))
+ if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) && (p_ccb_local->psm == psm))
+ {
+ GAP_TRACE_WARNING(" %s : %d PSM is already in use", __func__,p_ccb_local->psm);
return;
+ }
}
/* Free the security record for this PSM */
diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c
index 597dc63..e343d18 100644
--- a/stack/gatt/gatt_api.c
+++ b/stack/gatt/gatt_api.c
@@ -34,6 +34,8 @@
#include "l2c_api.h"
#include "btm_int.h"
+#define SYSTEM_APP_GATT_IF 3
+
/*******************************************************************************
**
** Function GATT_SetTraceLevel
@@ -1277,6 +1279,11 @@
if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
{
gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, TRUE);
+ if ((gatt_if > SYSTEM_APP_GATT_IF) && (!gatt_num_apps_hold_link(p_tcb)))
+ {
+ /* this will disconnect the link or cancel the pending connect request at lower layer*/
+ gatt_disconnect(p_tcb);
+ }
}
for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
diff --git a/stack/gatt/gatt_db.c b/stack/gatt/gatt_db.c
index cffcc70..3be01a1 100644
--- a/stack/gatt/gatt_db.c
+++ b/stack/gatt/gatt_db.c
@@ -62,7 +62,8 @@
BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri,
UINT16 s_hdl, UINT16 num_handle)
{
- p_db->svc_buffer = fixed_queue_new(SIZE_MAX);
+ if(!p_db->svc_buffer)
+ p_db->svc_buffer = fixed_queue_new(SIZE_MAX);
if (!allocate_svc_db_buf(p_db))
{
@@ -990,14 +991,16 @@
}
else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_32)
{
- GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid32 = [0x%08x] perm=0x%02x ",
- p_attr32->handle, p_attr32->uuid, p_attr32->permission);
+ if (p_attr32)
+ GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid32 = [0x%08x] perm=0x%02x ",
+ p_attr32->handle, p_attr32->uuid, p_attr32->permission);
}
else
{
- GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ",
- p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1],
- p_attr128->permission);
+ if (p_attr128)
+ GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ",
+ p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1],
+ p_attr128->permission);
}
return(void *)p_attr16;
}
diff --git a/stack/gatt/gatt_main.c b/stack/gatt/gatt_main.c
index 4f1568a..72d56a3 100644
--- a/stack/gatt/gatt_main.c
+++ b/stack/gatt/gatt_main.c
@@ -29,6 +29,7 @@
#include "bt_common.h"
#include "gatt_int.h"
#include "l2c_api.h"
+#include "l2c_int.h"
#include "btm_int.h"
#include "btm_ble_int.h"
#include "bt_utils.h"
@@ -240,7 +241,12 @@
{
if (p_tcb->att_lcid == L2CAP_ATT_CID)
{
- if (ch_state == GATT_CH_OPEN)
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_tcb->peer_bda, p_tcb->transport);
+ tL2C_LINK_STATE link_state = p_lcb != NULL ? p_lcb->link_state : LST_DISCONNECTED;
+ GATT_TRACE_WARNING("%s, ch_state=%d, link_state=%d", __func__, ch_state, link_state);
+
+ if ((ch_state == GATT_CH_OPEN) ||
+ ((ch_state == GATT_CH_CONN) && (link_state == LST_CONNECTED)))
{
/* only LCB exist between remote device and local */
ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, p_tcb->peer_bda);
@@ -249,6 +255,8 @@
{
gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
ret = L2CA_CancelBleConnectReq (p_tcb->peer_bda);
+ if (!ret)
+ gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
}
}
else
@@ -279,6 +287,13 @@
*******************************************************************************/
BOOLEAN gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add)
{
+ for (int i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->app_hold_link[i] == gatt_if && is_add) {
+ GATT_TRACE_DEBUG("%s: gatt_if %d already exists at idx %d", __func__, gatt_if, i);
+ return true;
+ }
+ }
+
for (int i=0; i<GATT_MAX_APPS; i++) {
if (p_tcb->app_hold_link[i] == 0 && is_add) {
p_tcb->app_hold_link[i] = gatt_if;
@@ -398,7 +413,7 @@
if (ret)
{
if (!opportunistic)
- gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE);
else
GATT_TRACE_DEBUG("%s: connection is opportunistic, not updating app usage",
__func__);
@@ -432,6 +447,8 @@
(bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
(bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
+ if (reason == GATT_CONN_TIMEOUT || reason == GATT_CONN_LMP_TIMEOUT)
+ GENERATE_VENDOR_LOGS();
if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
{
check_srv_chg = TRUE;
diff --git a/stack/gatt/gatt_sr.c b/stack/gatt/gatt_sr.c
index e159bae..3ffac96 100644
--- a/stack/gatt/gatt_sr.c
+++ b/stack/gatt/gatt_sr.c
@@ -330,6 +330,7 @@
UINT32 trans_id = 0;
tGATT_IF gatt_if;
UINT16 conn_id;
+ BT_HDR *p_buf;
#if GATT_CONFORMANCE_TESTING == TRUE
if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
@@ -379,7 +380,8 @@
else /* nothing needs to be executed , send response now */
{
GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending");
- gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, FALSE);
+ if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_EXEC_WRITE, NULL)) != NULL)
+ attp_send_sr_msg (p_tcb, p_buf);
}
}
diff --git a/stack/gatt/gatt_utils.c b/stack/gatt/gatt_utils.c
index c2db770..a899110 100644
--- a/stack/gatt/gatt_utils.c
+++ b/stack/gatt/gatt_utils.c
@@ -23,6 +23,7 @@
******************************************************************************/
#include "bt_target.h"
#include "bt_utils.h"
+#include "stack_config.h"
#if BLE_INCLUDED == TRUE
#include <string.h>
@@ -1287,6 +1288,7 @@
GATT_TRACE_WARNING("%s disconnecting...", __func__);
gatt_disconnect (p_clcb->p_tcb);
+ GENERATE_VENDOR_LOGS();
}
/*******************************************************************************
@@ -2840,12 +2842,18 @@
if (listening != GATT_LISTEN_TO_NONE)
{
- connectability |= BTM_BLE_CONNECTABLE;
+ GATT_TRACE_DEBUG ("connectability =%d\n", connectability);
+ connectability |= BTM_BLE_CONNECTABLE;
}
else
{
if ((connectability & BTM_BLE_CONNECTABLE) == 0)
- connectability &= ~BTM_BLE_CONNECTABLE;
+ {
+ if (stack_config_get_interface()->get_pts_le_nonconn_adv_enabled())
+ connectability = BTM_BLE_ADV_STOP;
+ else
+ connectability &= ~BTM_BLE_CONNECTABLE;
+ }
}
/* turning on the adv now */
btm_ble_set_connectability(connectability);
diff --git a/stack/hcic/hciblecmds.c b/stack/hcic/hciblecmds.c
index 5d58449..08d077e 100644
--- a/stack/hcic/hciblecmds.c
+++ b/stack/hcic/hciblecmds.c
@@ -221,6 +221,72 @@
return (TRUE);
}
+BOOLEAN btsnd_hcic_ble_set_extended_scan_params (UINT8 scan_phys,
+ UINT8 scan_type,
+ UINT16 scan_int, UINT16 scan_win,
+ UINT16 scan_int_coded, UINT16 scan_win_coded,
+ UINT8 addr_type_own, UINT8 scan_filter_policy)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ if(scan_phys == 0)
+ scan_phys = HCIC_SCAN_PHY_LE_1M;
+
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXT_SCAN_PARAMS);
+
+ if((scan_phys == HCIC_SCAN_PHY_LE_1M) || (scan_phys == HCIC_SCAN_PHY_LE_CODED))
+ {
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_PARAM;
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_PARAM);
+ }
+ else if(scan_phys == HCIC_SCAN_PHY_LE_1M_CODED)
+ {
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_PARAM + 5;
+ UINT8_TO_STREAM (pp, (HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_PARAM + 5));
+ }
+ UINT8_TO_STREAM (pp, addr_type_own);
+ UINT8_TO_STREAM (pp, scan_filter_policy);
+ UINT8_TO_STREAM (pp, scan_phys);
+ UINT8_TO_STREAM (pp, scan_type);
+ UINT16_TO_STREAM (pp, scan_int);
+ UINT16_TO_STREAM (pp, scan_win);
+
+
+ if(scan_phys == HCIC_SCAN_PHY_LE_1M_CODED)
+ {
+ UINT8_TO_STREAM (pp, scan_type);
+ UINT16_TO_STREAM (pp, scan_int_coded);
+ UINT16_TO_STREAM (pp, scan_win_coded);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_extended_scan_enable (UINT8 scan_enable, UINT8 duplicate,
+ UINT16 duraton, UINT16 period)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_ENABLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXT_SCAN_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_ENABLE);
+
+ UINT8_TO_STREAM (pp, scan_enable);
+ UINT8_TO_STREAM (pp, duplicate);
+ UINT16_TO_STREAM (pp, duraton);
+ UINT16_TO_STREAM (pp, period);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
/* link layer connection management commands */
BOOLEAN btsnd_hcic_ble_create_ll_conn (UINT16 scan_int, UINT16 scan_win,
UINT8 init_filter_policy,
@@ -259,6 +325,63 @@
return (TRUE);
}
+BOOLEAN btsnd_hcic_ble_ext_create_ll_conn (UINT8 ini_phy, UINT16 scan_int, UINT16 scan_win,
+ UINT8 init_filter_policy,
+ UINT8 addr_type_peer, BD_ADDR bda_peer,
+ UINT8 addr_type_own,
+ UINT16 conn_int_min, UINT16 conn_int_max,
+ UINT16 conn_latency, UINT16 conn_timeout,
+ UINT16 min_ce_len, UINT16 max_ce_len)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_EXT_CREATE_LL_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_EXT_CREATE_LL_CONN);
+ if(ini_phy == HCIC_SCAN_PHY_LE_1M || ini_phy == HCIC_SCAN_PHY_LE_CODED)
+ {
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_EXT_CREATE_LL_CONN;
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_EXT_CREATE_LL_CONN);
+ }
+ else if(ini_phy == HCIC_SCAN_PHY_LE_1M_CODED)
+ {
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_EXT_CREATE_LL_CONN + 16;
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_EXT_CREATE_LL_CONN + 16);
+ }
+
+ UINT8_TO_STREAM (pp, init_filter_policy);
+ UINT8_TO_STREAM (pp, addr_type_own);
+ UINT8_TO_STREAM (pp, addr_type_peer);
+ BDADDR_TO_STREAM (pp, bda_peer);
+ UINT8_TO_STREAM (pp, ini_phy);
+
+ UINT16_TO_STREAM (pp, scan_int);
+ UINT16_TO_STREAM (pp, scan_win);
+ UINT16_TO_STREAM (pp, conn_int_min);
+ UINT16_TO_STREAM (pp, conn_int_max);
+ UINT16_TO_STREAM (pp, conn_latency);
+ UINT16_TO_STREAM (pp, conn_timeout);
+ UINT16_TO_STREAM (pp, min_ce_len);
+ UINT16_TO_STREAM (pp, max_ce_len);
+
+ if(ini_phy == HCIC_SCAN_PHY_LE_1M_CODED)
+ {
+ UINT16_TO_STREAM (pp, scan_int);
+ UINT16_TO_STREAM (pp, scan_win);
+ UINT16_TO_STREAM (pp, conn_int_min);
+ UINT16_TO_STREAM (pp, conn_int_max);
+ UINT16_TO_STREAM (pp, conn_latency);
+ UINT16_TO_STREAM (pp, conn_timeout);
+ UINT16_TO_STREAM (pp, min_ce_len);
+ UINT16_TO_STREAM (pp, max_ce_len);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
BOOLEAN btsnd_hcic_ble_create_conn_cancel (void)
{
BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
@@ -525,6 +648,25 @@
return (TRUE);
}
+BOOLEAN btsnd_hcic_ble_enh_receiver_test(UINT8 rx_freq, UINT8 phy, UINT8 mod_index)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_ENH_RECEIVER_TEST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM3);
+
+ UINT8_TO_STREAM (pp, rx_freq);
+ UINT8_TO_STREAM (pp, phy);
+ UINT8_TO_STREAM (pp, mod_index);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
BOOLEAN btsnd_hcic_ble_transmitter_test(UINT8 tx_freq, UINT8 test_data_len, UINT8 payload)
{
BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
@@ -544,6 +686,26 @@
return (TRUE);
}
+BOOLEAN btsnd_hcic_ble_enh_transmitter_test(UINT8 tx_freq, UINT8 test_data_len, UINT8 payload, UINT8 phy)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM4;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_ENH_TRANSMITTER_TEST);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM4);
+
+ UINT8_TO_STREAM (pp, tx_freq);
+ UINT8_TO_STREAM (pp, test_data_len);
+ UINT8_TO_STREAM (pp, payload);
+ UINT8_TO_STREAM (pp, phy);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
BOOLEAN btsnd_hcic_ble_test_end(void)
{
BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
@@ -661,6 +823,26 @@
return (TRUE);
}
+BOOLEAN btsnd_hcic_ble_set_privacy_mode (UINT8 addr_type_peer, BD_ADDR bda_peer, UINT8 privacy_type)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_PRIVACY_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_SET_PRIVACY_MODE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_SET_PRIVACY_MODE);
+ UINT8_TO_STREAM (pp, addr_type_peer);
+ BDADDR_TO_STREAM (pp, bda_peer);
+ UINT8_TO_STREAM (pp, privacy_type);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+ return (TRUE);
+}
+
+
BOOLEAN btsnd_hcic_ble_clear_resolving_list (void)
{
BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
@@ -766,5 +948,217 @@
return TRUE;
}
-#endif
+BOOLEAN btsnd_hcic_ble_set_default_data_rate(UINT8 all_phy, UINT8 tx_phy, UINT8 rx_phy)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_DEFAULT_PHY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_DEFAULT_PHY_RATE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_DEFAULT_PHY);
+
+ UINT8_TO_STREAM(pp, all_phy);
+ UINT8_TO_STREAM(pp, tx_phy);
+ UINT8_TO_STREAM(pp, rx_phy);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return TRUE;
+}
+
+BOOLEAN btsnd_hcic_ble_set_data_rate(UINT16 handle, UINT8 all_phy, UINT8 tx_phy,
+ UINT8 rx_phy, UINT16 phy_options)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_PHY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_PHY_RATE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_PHY);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, all_phy);
+ UINT8_TO_STREAM(pp, tx_phy);
+ UINT8_TO_STREAM(pp, rx_phy);
+ UINT16_TO_STREAM(pp, phy_options);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return TRUE;
+}
+
+BOOLEAN btsnd_hcic_ble_set_extended_adv_params (UINT8 set_id, UINT16 event_properties,
+ UINT32 adv_int_min, UINT32 adv_int_max,
+ UINT8 channel_map, UINT8 addr_type_own,
+ UINT8 addr_type_dir, BD_ADDR direct_bda,
+ UINT8 adv_filter_policy, UINT8 adv_tx_power,
+ UINT8 primary_adv_phy, UINT8 secondary_max_skip,
+ UINT8 secondary_adv_phy, UINT8 advertising_sid,
+ UINT8 scan_req_not_enb)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_ADV_PARAMS ;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXTENDED_ADV_PARAMS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_ADV_PARAMS);
+ UINT8_TO_STREAM (pp, set_id);
+ UINT16_TO_STREAM (pp, event_properties);
+ UINT24_TO_STREAM (pp, adv_int_min);
+ UINT24_TO_STREAM (pp, adv_int_max);
+ UINT8_TO_STREAM (pp, channel_map);
+ UINT8_TO_STREAM (pp, addr_type_own);
+ UINT8_TO_STREAM (pp, addr_type_dir);
+ BDADDR_TO_STREAM (pp, direct_bda);
+ UINT8_TO_STREAM (pp, adv_filter_policy);
+ UINT8_TO_STREAM (pp, adv_tx_power);
+ UINT8_TO_STREAM (pp, primary_adv_phy);
+ UINT8_TO_STREAM (pp, secondary_max_skip);
+ UINT8_TO_STREAM (pp, secondary_adv_phy);
+ UINT8_TO_STREAM (pp, advertising_sid);
+ UINT8_TO_STREAM (pp, scan_req_not_enb);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_extended_adv_data (UINT8 set_id, UINT8 operation, UINT8 fragment_pref,
+ UINT8 data_len, UINT8 *p_data)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + data_len + 4;
+ p->offset = 0;
+
+ if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_ADV_DATA)
+ data_len = HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_ADV_DATA;
+
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXTENDED_ADV_DATA);
+ UINT8_TO_STREAM (pp, data_len + 4);
+ UINT8_TO_STREAM (pp, set_id);
+ UINT8_TO_STREAM (pp, operation);
+ UINT8_TO_STREAM (pp, fragment_pref);
+
+ memset(pp, 0, data_len + 1);
+
+ if (p_data != NULL && data_len > 0)
+ {
+ UINT8_TO_STREAM (pp, data_len);
+ ARRAY_TO_STREAM (pp, p_data, data_len);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_extended_scan_rsp_data (UINT8 set_id, UINT8 operation, UINT8 fragment_pref,
+ UINT8 data_len, UINT8 *p_scan_rsp)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + data_len + 4;
+ p->offset = 0;
+
+ if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_RSP )
+ data_len = HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_RSP;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXTENDED_SCAN_RSP_DATA);
+ UINT8_TO_STREAM (pp, data_len + 4);
+ UINT8_TO_STREAM (pp, set_id);
+ UINT8_TO_STREAM (pp, operation);
+ UINT8_TO_STREAM (pp, fragment_pref);
+
+ memset(pp, 0, data_len + 1);
+
+ if (p_scan_rsp != NULL && data_len > 0)
+ {
+ UINT8_TO_STREAM (pp, data_len);
+ ARRAY_TO_STREAM (pp, p_scan_rsp, data_len);
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_set_extended_adv_enable (UINT8 adv_enable, UINT8 num_sets, UINT8* handles,
+ UINT16* durations, UINT8* max_adv_events)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_EXTENDED_ADV_ENABLE + num_sets*4;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXTENDED_ADV_ENABLE);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_EXTENDED_ADV_ENABLE + 4*num_sets);
+
+ UINT8_TO_STREAM (pp, adv_enable);
+ UINT8_TO_STREAM (pp, num_sets);
+
+ if (num_sets > 0) {
+ for (UINT8 count = 0; count < num_sets; count++) {
+ UINT8_TO_STREAM(pp, handles[count]);
+ UINT16_TO_STREAM (pp, durations[count]);
+ UINT8_TO_STREAM(pp, max_adv_events[count]);
+ }
+ }
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_num_adv_sets (void)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_NUM_ADV_SETS);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_write_extended_rpa (UINT8 set_id, BD_ADDR rpa)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_EXTENDED_ADV_RPA;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_WRITE_EXTENDED_ADV_RPA);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_EXTENDED_ADV_RPA);
+ UINT8_TO_STREAM (pp, set_id);
+ BDADDR_TO_STREAM (pp, rpa);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+BOOLEAN btsnd_hcic_ble_read_extended_max_adv_len (void)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_BLE_READ_MAX_ADV_LENGTH);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ return (TRUE);
+}
+
+#endif
diff --git a/stack/hcic/hcicmds.c b/stack/hcic/hcicmds.c
index 97e83b7..ba1f6d4 100644
--- a/stack/hcic/hcicmds.c
+++ b/stack/hcic/hcicmds.c
@@ -726,6 +726,21 @@
return (TRUE);
}
+BOOLEAN btsnd_hcic_reset (UINT8 local_controller_id)
+{
+ BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RESET;
+ p->offset = 0;
+
+ UINT16_TO_STREAM (pp, HCI_RESET);
+ UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RESET);
+
+ btu_hcif_send_cmd (local_controller_id, p);
+ return (TRUE);
+}
+
BOOLEAN btsnd_hcic_set_event_filter (UINT8 filt_type, UINT8 filt_cond_type,
UINT8 *filt_cond, UINT8 filt_cond_len)
{
@@ -1443,6 +1458,26 @@
#error "HCI_CMD_BUF_SIZE must be larger than 268"
#endif
+
+void btsnd_hcic_raw_cmd (void *buffer, UINT16 opcode, UINT8 len,
+ UINT8 *p_data, void *p_cmd_cplt_cback)
+{
+ BT_HDR *p = (BT_HDR *)buffer;
+ UINT8 *pp = (UINT8 *)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + len;
+ p->offset = sizeof(void *);
+
+ *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */
+ pp += sizeof(void *); /* Skip over callback pointer */
+
+ UINT16_TO_STREAM (pp, opcode);
+ UINT8_TO_STREAM (pp, len);
+ ARRAY_TO_STREAM (pp, p_data, len);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, UINT8 len,
UINT8 *p_data, void *p_cmd_cplt_cback)
{
diff --git a/stack/hid/hidh_api.c b/stack/hid/hidh_api.c
index db173f1..eb4bf05 100644
--- a/stack/hid/hidh_api.c
+++ b/stack/hid/hidh_api.c
@@ -81,16 +81,20 @@
if ((p_attr = SDP_FindAttributeInRec(p_rec, attr_id)) != NULL)
{
- if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len )
+ if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len && name_len < 3)
{
memcpy( str, (char *) p_attr->attr_value.v.array, name_len );
str[name_len] = '\0';
}
- else
+ else if (max_len < 4)
{
memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 );
str[max_len-1] = '\0';
}
+ else
+ {
+ str[0] = '\0';
+ }
}
else
str[0] = '\0';
diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c
index 39ba8bc..a719a0e 100644
--- a/stack/hid/hidh_conn.c
+++ b/stack/hid/hidh_conn.c
@@ -46,6 +46,7 @@
#include "osi/include/osi.h"
+#include "device/include/interop.h"
extern fixed_queue_t *btu_general_alarm_queue;
@@ -227,6 +228,15 @@
p_hcon = &hh_cb.devices[i].conn;
p_dev = &hh_cb.devices[i];
+ /* Stop the retry timer if active */
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+#if (HID_HOST_REPAGE_WIN > 0)
+ HIDH_TRACE_DEBUG ("HID-Host stopping retry timer as l2cap is connected from remote side");
+ p_dev->conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+ alarm_cancel(p_dev->conn.process_repage_timer);
+#endif
+#endif
+
/* Check we are in the correct state for this */
if (psm == HID_PSM_INTERRUPT)
{
@@ -265,18 +275,31 @@
if (psm == HID_PSM_CONTROL)
{
+ bt_bdaddr_t remote_bdaddr;
p_hcon->conn_flags = 0;
p_hcon->ctrl_cid = l2cap_cid;
p_hcon->ctrl_id = l2cap_id;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
- if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
- FALSE, BTM_SEC_PROTO_HID,
- (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
- &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+ bdcpy(remote_bdaddr.address, p_dev->addr);
+
+ if (!interop_match_addr(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, (bt_bdaddr_t *)&remote_bdaddr))
{
+ if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ FALSE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+ }
+ else
+ {
+ /* device is blacklisted, don't perform authentication */
L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ hidh_sec_check_complete_term(p_dev->addr, BT_TRANSPORT_BR_EDR,
+ p_dev, BTM_SUCCESS);
}
return;
@@ -299,6 +322,7 @@
void hidh_process_repage_timer_timeout(void *data)
{
uint8_t dhandle = PTR_TO_UINT(data);
+ GENERATE_VENDOR_LOGS();
hidh_try_repage(dhandle);
}
@@ -313,15 +337,17 @@
*******************************************************************************/
void hidh_try_repage(UINT8 dhandle)
{
- tHID_HOST_DEV_CTB *device;
+ HIDH_TRACE_DEBUG ("HID-Host Connection retry timeout fired");
+ if (HID_SUCCESS == hidh_conn_initiate(dhandle))
+ {
- hidh_conn_initiate(dhandle);
+ tHID_HOST_DEV_CTB *device;
+ device = &hh_cb.devices[dhandle];
+ device->conn_tries++;
- device = &hh_cb.devices[dhandle];
- device->conn_tries++;
-
- hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
- device->conn_tries, NULL ) ;
+ hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
+ device->conn_tries, NULL ) ;
+ }
}
/*******************************************************************************
@@ -368,6 +394,7 @@
}
}
#endif
+ GENERATE_VENDOR_LOGS();
p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
hidh_conn_disconnect(dhandle);
}
@@ -429,21 +456,35 @@
#endif
{
reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
+ HIDH_TRACE_WARNING ("HID-Host: l2cap connect failed, reason = %d", reason);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ GENERATE_VENDOR_LOGS();
}
return;
}
/* receive Control Channel connect confirmation */
if (l2cap_cid == p_hcon->ctrl_cid)
{
+ bt_bdaddr_t remote_address;
+
/* check security requirement */
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
+ bdcpy(remote_address.address, p_dev->addr);
- btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
- TRUE, BTM_SEC_PROTO_HID,
- (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
- &hidh_sec_check_complete_orig, p_dev);
+ if (!interop_match_addr(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, (bt_bdaddr_t *)&remote_address))
+ {
+ btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ TRUE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_orig, p_dev);
+ }
+ else
+ {
+ /* device is blacklisted, don't perform authentication */
+ hidh_sec_check_complete_orig(p_dev->addr, BT_TRANSPORT_BR_EDR,
+ p_dev, BTM_SUCCESS);
+ }
}
else
{
@@ -513,7 +554,9 @@
reason = HID_L2CAP_REQ_FAIL ;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hidh_conn_disconnect (dhandle);
+ HIDH_TRACE_WARNING ("HID-Host: l2cap config failed, reason = %d", reason);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ GENERATE_VENDOR_LOGS();
return;
}
else
@@ -573,7 +616,9 @@
{
hidh_conn_disconnect (dhandle);
reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
+ HIDH_TRACE_WARNING ("HID-Host: l2cap config ind failed, reason = %d", reason);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ GENERATE_VENDOR_LOGS();
return;
}
@@ -591,7 +636,9 @@
reason = HID_L2CAP_REQ_FAIL ;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hidh_conn_disconnect (dhandle);
+ HIDH_TRACE_WARNING ("HID-Host: l2cap config ind failed 2, reason = %d", reason);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ GENERATE_VENDOR_LOGS();
return;
}
else
@@ -665,6 +712,8 @@
if( !ack_needed )
disc_res = btm_get_acl_disc_reason_code();
+ HIDH_TRACE_EVENT ("HID-Host: acl disconnect reason %d", disc_res);
+
#if (HID_HOST_MAX_CONN_RETRY > 0)
if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
(!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
@@ -672,10 +721,12 @@
{
hh_cb.devices[dhandle].conn_tries = 0;
period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+ HIDH_TRACE_EVENT ("HID-Host: starting timer for reconnection");
alarm_set_on_queue(hh_cb.devices[dhandle].conn.process_repage_timer,
interval_ms, hidh_process_repage_timer_timeout,
UINT_TO_PTR(dhandle), btu_general_alarm_queue);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
+ GENERATE_VENDOR_LOGS();
}
else
#endif
@@ -695,7 +746,7 @@
{
hid_close_evt_reason = HID_ERR_AUTH_FAILED;
}
-
+ HIDH_TRACE_EVENT ("HID-Host: disconnect ind, reason = %d", hid_close_evt_reason);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
}
}
@@ -745,6 +796,7 @@
{
hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ HIDH_TRACE_EVENT ("HID-Host: disconnect cfm, reason = %d", p_hcon->disc_reason);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
}
}
@@ -1032,7 +1084,10 @@
tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
+ {
+ HIDH_TRACE_WARNING ("HID-Host connection state not unused (%d)", p_dev->conn.conn_state);
return( HID_ERR_CONN_IN_PROCESS );
+ }
p_dev->conn.ctrl_cid = 0;
p_dev->conn.intr_cid = 0;
@@ -1054,6 +1109,8 @@
HIDH_TRACE_WARNING ("HID-Host Originate failed");
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
HID_ERR_L2CAP_FAILED, NULL ) ;
+ GENERATE_VENDOR_LOGS();
+ return HID_ERR_L2CAP_FAILED;
}
else
{
@@ -1110,10 +1167,12 @@
p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
#if (HID_HOST_REPAGE_WIN > 0)
period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+ HIDH_TRACE_DEBUG ("HID-Host starting timer of %d sec", interval_ms);
alarm_set_on_queue(p_dev->conn.process_repage_timer,
interval_ms, hidh_process_repage_timer_timeout,
UINT_TO_PTR(dhandle), btu_general_alarm_queue);
#else
- hidh_process_repage_process(dhandle);
+ HIDH_TRACE_DEBUG ("HID-Host calling timeout function");
+ hidh_try_repage(dhandle);
#endif
}
diff --git a/stack/include/a2d_aac.h b/stack/include/a2d_aac.h
new file mode 100644
index 0000000..413d486
--- /dev/null
+++ b/stack/include/a2d_aac.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#ifndef A2D_AAC_H
+#define A2D_AAC_H
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+#define A2D_AAC_MPL_HDR_LEN 1
+
+/* AAC media codec capabilitiy len*/
+#define A2D_AAC_INFO_LEN 8
+
+/* AAC Codec Specific */
+#define A2D_AAC_IE_OBJ_TYPE_MSK 0xF0 /* b7-b4 Object Type */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC 0x80 /* b7:MPEG-2 AAC LC */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LC 0x40 /* b7:MPEG-4 AAC LC */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LTP 0x20 /* b7:MPEG-4 AAC LTP */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_SCA 0x10 /* b7:MPEG-4 AAC SCALABLE */
+
+#define A2D_AAC_IE_SAMP_FREQ_MSK 0xFFF0 /* b15-b4 sampling frequency */
+#define A2D_AAC_IE_SAMP_FREQ_8000 0x8000 /* b15: 8000 */
+#define A2D_AAC_IE_SAMP_FREQ_11025 0x4000 /* b15: 11025 */
+#define A2D_AAC_IE_SAMP_FREQ_12000 0x2000 /* b15: 12000 */
+#define A2D_AAC_IE_SAMP_FREQ_16000 0x1000 /* b15: 16000 */
+#define A2D_AAC_IE_SAMP_FREQ_22050 0x0800 /* b15: 22050 */
+#define A2D_AAC_IE_SAMP_FREQ_24000 0x0400 /* b15: 24000 */
+#define A2D_AAC_IE_SAMP_FREQ_32000 0x0200 /* b15: 32000 */
+#define A2D_AAC_IE_SAMP_FREQ_44100 0x0100 /* b15: 441000 */
+#define A2D_AAC_IE_SAMP_FREQ_48000 0x0080 /* b15: 48000 */
+#define A2D_AAC_IE_SAMP_FREQ_64000 0x0040 /* b15: 64000 */
+#define A2D_AAC_IE_SAMP_FREQ_88200 0x0020 /* b15: 88200 */
+#define A2D_AAC_IE_SAMP_FREQ_96000 0x0010 /* b15: 96000 */
+
+
+#define A2D_AAC_IE_CHANNELS_MSK 0x0C /* b7-b6 channels supported */
+#define A2D_AAC_IE_CHANNELS_1 0x08 /* Channel 1 */
+#define A2D_AAC_IE_CHANNELS_2 0x04 /* Channel 2 */
+
+#define A2D_AAC_IE_VBR_MSK 0x80 /* b7 variable bit rate */
+#define A2D_AAC_IE_VBR_SUPP 0x80 /* supported */
+#define A2D_AAC_IE_VBR_NOT_SUPP 0x00 /* supported */
+
+#define A2D_AAC_IE_BIT_RATE_MSK 0x007FFFFF /* bit rate */
+#define A2D_AAC_IE_BIT_RATE 0x007FFFFF
+
+
+#define BTIF_AAC_DEFAULT_BIT_RATE 0x00028488 //165kbps
+#define BTIF_AAC_MIN_BITRATE 0x0000FA00
+
+typedef struct {
+ INT16 s16SamplingFreq; /* 16k, 32k, 44.1k or 48k*/
+ INT16 s16ChannelMode; /* mono, dual, streo or joint streo*/
+ UINT16 u16BitRate;
+ UINT16 *ps16NextPcmBuffer;
+ UINT8 *pu8Packet;
+ UINT8 *pu8NextPacket;
+ UINT16 u16PacketLength;
+ void* encoder;
+} A2D_AAC_ENC_PARAMS;
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+/* AAC Codec Information data type */
+typedef struct
+{
+ UINT8 object_type; /* Object Type */
+ UINT16 samp_freq; /* Sampling Frequency */
+ UINT8 channels; /* Channels */
+ UINT32 bit_rate; /* bit_rate */
+ UINT8 vbr; /* variable bit rate */
+} tA2D_AAC_CIE;
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/******************************************************************************
+**
+** Function A2D_BldAacInfo
+**
+** Description This function builds byte sequence for
+** Aac Codec Capabilities.
+** Input : media_type: Audio or MultiMedia.
+** p_ie: AAC Codec Information Element
+**
+** Output : p_result: codec info.
+**
+** Returns A2D_SUCCESS if successful.
+** Error otherwise.
+******************************************************************************/
+extern tA2D_STATUS A2D_BldAacInfo(UINT8 media_type, tA2D_AAC_CIE *p_ie, UINT8 *p_result);
+
+/******************************************************************************
+**
+** Function A2D_ParsAacInfo
+**
+** Description This function parse byte sequence for
+** Aac Codec Capabilities.
+** Input : p_info: input byte sequence.
+** for_caps: True for getcap, false otherwise
+**
+** Output : p_ie: Aac codec information.
+**
+** Returns A2D_SUCCESS if successful.
+** Error otherwise.
+******************************************************************************/
+extern tA2D_STATUS A2D_ParsAacInfo(tA2D_AAC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_AAC_H */
diff --git a/stack/include/a2d_api.h b/stack/include/a2d_api.h
index 75d2755..fb98368 100644
--- a/stack/include/a2d_api.h
+++ b/stack/include/a2d_api.h
@@ -85,6 +85,9 @@
#define A2D_BAD_CP_TYPE 0xE0 /* The requested CP Type is not supported. */
#define A2D_BAD_CP_FORMAT 0xE1 /* The format of Content Protection Service Capability/Content Protection Scheme Dependent Data is not correct. */
+
+#define A2D_NON_A2DP_MEDIA_CT 0xFF /* NON A2DP media codec */
+
typedef UINT8 tA2D_STATUS;
/* the return values from A2D_BitsSet() */
@@ -203,6 +206,9 @@
extern tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback);
+/* Used to check local version of AVDTP */
+extern int a2d_get_avdt_sdp_ver ();
+
/******************************************************************************
**
** Function A2D_SetTraceLevel
diff --git a/stack/include/a2d_aptx.h b/stack/include/a2d_aptx.h
new file mode 100644
index 0000000..2fb9613
--- /dev/null
+++ b/stack/include/a2d_aptx.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+
+ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * interface to aptX codec
+ *
+ ******************************************************************************/
+#ifndef A2D_APTX_H
+#define A2D_APTX_H
+
+/* aptX codec specific settings*/
+#define A2D_APTX_CODEC_LEN 9
+
+#define A2D_APTX_VENDOR_ID (0x0000004F)
+#define A2D_APTX_CODEC_ID_BLUETOOTH (0x0001)
+#define A2D_APTX_SAMPLERATE_44100 (0x20)
+#define A2D_APTX_SAMPLERATE_48000 (0x10)
+#define A2D_APTX_CHANNELS_STEREO (0x02)
+#define A2D_APTX_CHANNELS_MONO (0x01)
+#define A2D_APTX_FUTURE_1 (0x00)
+#define A2D_APTX_FUTURE_2 (0x00)
+#define A2D_APTX_OTHER_FEATURES_NONE (0x00000000)
+#define A2D_AV_APTX_AUDIO (0x00)
+#define A2D_APTX_CHANNEL (0x0001)
+#define A2D_APTX_SAMPLERATE (0x22)
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+typedef enum {
+ APTX_CODEC_NONE=0,
+ APTX_CODEC,
+ APTX_HD_CODEC,
+} A2D_AptXCodecType;
+
+typedef void (*A2D_AptXThreadFn)(void *context);
+typedef UINT32 (*A2D_AptXReadFn) (UINT8 ch_id, UINT16 *p_msg_evt, UINT8* p_buf,
+ UINT32 len);
+typedef int (*A2D_AptXBufferSendFn) (UINT8*, int, int);
+typedef void (*A2D_AptXSetPriorityFn)(tHIGH_PRIORITY_TASK task);
+
+typedef struct
+{
+ UINT32 vendorId;
+ UINT16 codecId; /* Codec ID for aptX */
+ UINT8 sampleRate; /* Sampling Frequency */
+ UINT8 channelMode; /* STEREO/DUAL/MONO */
+ UINT8 future1;
+ UINT8 future2;
+} tA2D_APTX_CIE;
+
+typedef struct {
+ INT16 s16SamplingFreq; /* 16k, 32k, 44.1k or 48k*/
+ INT16 s16ChannelMode; /* mono, dual, streo or joint streo*/
+ UINT16 u16BitRate;
+ UINT16 *ps16NextPcmBuffer;
+ UINT8 *pu8Packet;
+ UINT8 *pu8NextPacket;
+ UINT16 u16PacketLength;
+ void* encoder;
+} A2D_APTX_ENC_PARAMS;
+
+extern const char* A2D_APTX_SCHED_LIB_NAME;
+extern void *A2dAptXSchedLibHandle;
+extern BOOLEAN isA2dAptXEnabled;
+extern thread_t *A2d_aptx_thread;
+extern A2D_AptXThreadFn A2d_aptx_thread_fn;
+
+/*****************************************************************************
+** external function declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+extern UINT8 A2D_BldAptxInfo(UINT8 media_type, tA2D_APTX_CIE *p_ie,
+ UINT8 *p_result);
+extern UINT8 A2D_ParsAptxInfo(tA2D_APTX_CIE *p_ie, UINT8 *p_info,
+ BOOLEAN for_caps);
+extern int (*A2D_aptx_encoder_init)(void);
+extern A2D_AptXThreadFn (*A2D_aptx_sched_start)(void *encoder,
+ A2D_AptXCodecType aptX_codec_type,
+ BOOLEAN use_SCMS_T, BOOLEAN is_24bit_audio,
+ UINT16 sample_rate, UINT8 format_bits,
+ UINT8 channel, UINT16 mtu, A2D_AptXReadFn read_fn,
+ A2D_AptXBufferSendFn send_fn,
+ A2D_AptXSetPriorityFn set_priority_fn,
+ BOOLEAN test, BOOLEAN trace);
+extern BOOLEAN (*A2D_aptx_sched_stop)(void);
+extern void (*A2D_aptx_encoder_deinit)(void);
+extern UINT8 a2d_av_aptx_cfg_in_cap(UINT8 *p_cfg, tA2D_APTX_CIE *p_cap);
+extern BOOLEAN A2D_check_and_init_aptX();
+extern void A2D_start_aptX(void *encoder, A2D_AptXCodecType aptX_codec_type,
+ BOOLEAN use_SCMS_T, BOOLEAN is_24bit_audio,
+ UINT16 sample_rate, UINT8 format_bits,
+ UINT8 channel, UINT16 MTU, A2D_AptXReadFn read_fn,
+ A2D_AptXBufferSendFn send_fn,
+ A2D_AptXSetPriorityFn set_priority_fn,
+ BOOLEAN test, BOOLEAN trace);
+extern void A2D_deinit_aptX();
+extern void A2D_stop_aptX (void);
+extern void A2D_close_aptX();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_APTX_H */
diff --git a/stack/include/a2d_aptx_hd.h b/stack/include/a2d_aptx_hd.h
new file mode 100644
index 0000000..eca6f26
--- /dev/null
+++ b/stack/include/a2d_aptx_hd.h
@@ -0,0 +1,105 @@
+/******************************************************************************
+
+ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ******************************************************************************/
+/******************************************************************************
+ interface to aptX HD codec
+ ******************************************************************************/
+#ifndef A2D_APTX_HD_H
+#define A2D_APTX_HD_H
+
+/* aptX HD codec specific settings*/
+#define A2D_APTX_HD_CODEC_LEN 13
+
+#define A2D_APTX_HD_VENDOR_ID (0x000000D7)
+#define A2D_APTX_HD_CODEC_ID_BLUETOOTH ((UINT16) 0x0024)
+#define A2D_APTX_HD_SAMPLERATE_44100 (0x20)
+#define A2D_APTX_HD_SAMPLERATE_48000 (0x10)
+#define A2D_APTX_HD_CHANNELS_STEREO (0x02)
+#define A2D_APTX_HD_CHANNELS_MONO (0x01)
+#define A2D_APTX_HD_ACL_SPRINT_RESERVED0 (0x00)
+#define A2D_APTX_HD_ACL_SPRINT_RESERVED1 (0x00)
+#define A2D_APTX_HD_ACL_SPRINT_RESERVED2 (0x00)
+#define A2D_APTX_HD_ACL_SPRINT_RESERVED3 (0x00)
+#define A2D_APTX_HD_OTHER_FEATURES_NONE (0x00000000)
+#define A2D_APTX_HD_AV_AUDIO (0x00)
+#define A2D_APTX_HD_CODEC_ID (0xff)
+#define A2D_APTX_HD_CHANNEL (0x0001)
+#define A2D_APTX_HD_SAMPLERATE (0x22)
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef struct {
+ UINT32 vendorId;
+ UINT16 codecId; /* Codec ID for aptX HD */
+ UINT8 sampleRate; /* Sampling Frequency */
+ UINT8 channelMode; /* STEREO/DUAL/MONO */
+ UINT8 acl_sprint_reserved0;
+ UINT8 acl_sprint_reserved1;
+ UINT8 acl_sprint_reserved2;
+ UINT8 acl_sprint_reserved3;
+} tA2D_APTX_HD_CIE;
+
+typedef struct {
+ INT16 s16SamplingFreq; /* 16k, 32k, 44.1k or 48k*/
+ INT16 s16ChannelMode; /* mono, dual, streo or joint streo*/
+ UINT16 u16BitRate;
+ UINT16 *ps16NextPcmBuffer;
+ UINT8 *pu8Packet;
+ UINT8 *pu8NextPacket;
+ UINT16 u16PacketLength;
+ void* encoder;
+} A2D_APTX_HD_ENC_PARAMS;
+
+extern BOOLEAN isA2dAptXHdEnabled;
+
+/*****************************************************************************
+** external function declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+extern UINT8 A2D_BldAptx_hdInfo(UINT8 media_type, tA2D_APTX_HD_CIE *p_ie,
+ UINT8 *p_result);
+extern UINT8 A2D_ParsAptx_hdInfo(tA2D_APTX_HD_CIE *p_ie, UINT8 *p_info,
+ BOOLEAN for_caps);
+extern int (*A2D_aptx_hd_encoder_init)(void);
+extern void (*A2D_aptx_hd_encoder_deinit)(void);
+extern UINT8 a2d_av_aptx_hd_cfg_in_cap(UINT8 *p_cfg, tA2D_APTX_HD_CIE *p_cap);
+extern BOOLEAN A2D_check_and_init_aptX_HD();
+extern void A2D_deinit_aptX_HD();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2D_APTX_HD_H */
diff --git a/stack/include/avct_api.h b/stack/include/avct_api.h
index c2713fd..350afdd 100644
--- a/stack/include/avct_api.h
+++ b/stack/include/avct_api.h
@@ -127,6 +127,20 @@
/*******************************************************************************
**
+** Function AVCT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVCT_Init(void);
+
+/*******************************************************************************
+**
** Function AVCT_Register
**
** Description This is the system level registration function for the
@@ -271,6 +285,59 @@
*******************************************************************************/
extern UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg);
+
+
+/******************************************************************************
+**
+** Function AVCT_SetTraceLevel
+**
+** Description Sets the trace level for AVCT. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVCT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVCT_SetTraceLevel (UINT8 new_level);
+
+
+/*******************************************************************************
+**
+** Function avct_get_peer_addr_by_ccb
+**
+**
+** Description Return peer BD address on ccb index (or handle).
+**
+**
+**
+**
+** Returns BD Address.
+**
+*******************************************************************************/
+extern BOOLEAN avct_get_peer_addr_by_ccb (UINT8 idx, BD_ADDR addr);
+
+/*******************************************************************************
+**
+** Function AVCT_CheckIncomingConn
+**
+**
+** Description Check if remote AVCTP incoming connection in progress
+**
+** Returns TRUE if icoming connection is in progress,
+**
+*******************************************************************************/
+extern BOOLEAN AVCT_CheckIncomingConn(BD_ADDR peer_addr);
+
#ifdef __cplusplus
}
#endif
diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h
index e10faf0..f52420f 100644
--- a/stack/include/avdt_api.h
+++ b/stack/include/avdt_api.h
@@ -1,4 +1,10 @@
/******************************************************************************
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Not a contribution.
+ ******************************************************************************/
+
+/******************************************************************************
*
* Copyright (C) 2002-2012 Broadcom Corporation
*
@@ -47,6 +53,12 @@
/* The index to access the codec type in codec_info[]. */
#define AVDT_CODEC_TYPE_INDEX 2
+/* The index to access the vendorId in codec_info[]. */
+#define AVDT_VENDOR_ID_TYPE_INDEX 3
+
+/* The index to access the codecId in codec_info[]. */
+#define AVDT_CODEC_ID_TYPE_INDEX 7
+
/* The size in bytes of a Adaptation Layer header. */
#define AVDT_AL_HDR_SIZE 3
@@ -400,6 +412,7 @@
UINT8 tsep; /* SEP type */
UINT8 media_type; /* Media type */
UINT16 nsc_mask; /* Nonsupported protocol command messages */
+ UINT8 registration_id;/* All SCBs created during single registration will have same value.*/
} tAVDT_CS;
/* AVDT data option mask is used in the write request */
@@ -420,6 +433,20 @@
/*******************************************************************************
**
+** Function AVDT_Init
+**
+** Description This function is called to initialize the control block
+** for this layer. It must be called before accessing any
+** other API functions for this layer. It is typically called
+** once during the start up of the stack.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_Init(void);
+
+/*******************************************************************************
+**
** Function AVDT_Register
**
** Description This is the system level registration function for the
@@ -452,6 +479,32 @@
/*******************************************************************************
**
+** Function AVDT_UpdateServiceBusyState
+**
+** Description This function is used to set the service busy state
+** during outgoing connection to properly handle the
+** connections in upper layers.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void AVDT_UpdateServiceBusyState(BOOLEAN state);
+
+/*******************************************************************************
+**
+** Function AVDT_GetServiceBusyState
+**
+** Description This function is used to get the service busy state
+**
+**
+** Returns outgoing connection in progress or not
+**
+*******************************************************************************/
+BOOLEAN AVDT_GetServiceBusyState(void);
+
+/*******************************************************************************
+**
** Function AVDT_SINK_Activate
**
** Description Activate SEP of A2DP Sink. In Use parameter is adjusted.
@@ -894,6 +947,20 @@
*******************************************************************************/
extern UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr);
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/*******************************************************************************
+**
+** Function AVDT_GetStreamingDestChannel
+**
+** Description Get the Dest L2CAP CID used by the stream channel.
+**
+** Returns Destination CID.
+**
+*******************************************************************************/
+UINT16 AVDT_GetStreamingDestChannelId(UINT16 lcid);
+#endif
+
+
/*******************************************************************************
**
** Function AVDT_SetMediaBuf
@@ -928,6 +995,17 @@
extern UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
tAVDT_REPORT_DATA *p_data);
+/*******************************************************************************
+**
+** Function AVDT_UpdateMaxAvClients
+**
+** Description Update max simultaneous AV connections supported
+**
+** Returns
+**
+*******************************************************************************/
+extern void AVDT_UpdateMaxAvClients(UINT8 num_clients);
+
/******************************************************************************
**
** Function AVDT_SetTraceLevel
diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h
index d6fa4d9..7245b6b 100644
--- a/stack/include/avrc_api.h
+++ b/stack/include/avrc_api.h
@@ -120,7 +120,6 @@
#define AVRC_METADATA_RESP 0x0001
-
/*****************************************************************************
** data type definitions
*****************************************************************************/
@@ -641,6 +640,21 @@
*******************************************************************************/
extern tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt);
+/*******************************************************************************
+**
+** Function AVRC_BldBrowseResponse
+**
+** Description This function builds the given AVRCP response to the given
+** GKI buffer
+**
+** Returns AVRC_STS_NO_ERROR, if the response is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldBrowseResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt);
+
+
+
/**************************************************************************
**
** Function AVRC_IsValidAvcType
@@ -665,6 +679,18 @@
*******************************************************************************/
extern BOOLEAN AVRC_IsValidPlayerAttr(UINT8 attr);
+/*******************************************************************************
+**
+** Function AVRC_CheckIncomingConn
+**
+** Description Check if AVRC incoming connection in progress
+**
+**
+** Returns returns TRUE if incoming connection in progress
+**
+*******************************************************************************/
+extern BOOLEAN AVRC_CheckIncomingConn(BD_ADDR peer_addr);
+
#ifdef __cplusplus
}
#endif
diff --git a/stack/include/avrc_defs.h b/stack/include/avrc_defs.h
index cb6178c..0b6cf00 100644
--- a/stack/include/avrc_defs.h
+++ b/stack/include/avrc_defs.h
@@ -31,9 +31,12 @@
*****************************************************************************/
/* Profile revision numbers */
+#define AVRC_REV_INVALID 0x0000
#define AVRC_REV_1_0 0x0100
#define AVRC_REV_1_3 0x0103
#define AVRC_REV_1_4 0x0104
+#define AVRC_REV_1_5 0x0105
+#define AVRC_REV_1_6 0x0106
#define AVRC_PACKET_LEN 512 /* Per the spec, you must support 512 byte RC packets */
@@ -203,7 +206,7 @@
#define AVRC_PDU_REGISTER_NOTIFICATION 0x31
#define AVRC_PDU_REQUEST_CONTINUATION_RSP 0x40
#define AVRC_PDU_ABORT_CONTINUATION_RSP 0x41
-/* added in 1.4 */
+/* added in 1.4 and above*/
#define AVRC_PDU_SET_ABSOLUTE_VOLUME 0x50
#define AVRC_PDU_SET_ADDRESSED_PLAYER 0x60
#define AVRC_PDU_SET_BROWSED_PLAYER 0x70
@@ -211,6 +214,7 @@
#define AVRC_PDU_CHANGE_PATH 0x72
#define AVRC_PDU_GET_ITEM_ATTRIBUTES 0x73
#define AVRC_PDU_PLAY_ITEM 0x74
+#define AVRC_PDU_GET_TOTAL_NUMBER_OF_ITEMS 0x75
#define AVRC_PDU_SEARCH 0x80
#define AVRC_PDU_ADD_TO_NOW_PLAYING 0x90
#define AVRC_PDU_GENERAL_REJECT 0xA0
@@ -299,7 +303,8 @@
#define AVRC_MEDIA_ATTR_ID_NUM_TRACKS 0x00000005
#define AVRC_MEDIA_ATTR_ID_GENRE 0x00000006
#define AVRC_MEDIA_ATTR_ID_PLAYING_TIME 0x00000007 /* in miliseconds */
-#define AVRC_MAX_NUM_MEDIA_ATTR_ID 7
+#define AVRC_MEDIA_ATTR_ID_COVER_ART 0x00000008
+#define AVRC_MAX_NUM_MEDIA_ATTR_ID 8
/* Define the possible values of play state
*/
@@ -846,7 +851,7 @@
(a >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? TRUE : FALSE)
#define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a) ((a >= AVRC_MEDIA_ATTR_ID_TITLE) && \
- (a <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) ? TRUE : FALSE)
+ (a <= AVRC_MEDIA_ATTR_ID_COVER_ART) ? TRUE : FALSE)
#define AVRC_IS_VALID_BATTERY_STATUS(a) ((a <= AVRC_BATTERY_STATUS_FULL_CHARGE) ? TRUE : FALSE)
@@ -1094,7 +1099,7 @@
UINT32 start_item;
UINT32 end_item;
UINT8 attr_count;
- UINT32 *p_attr_list;
+ UINT32 attrs[AVRC_MAX_ELEM_ATTR_SIZE];
} tAVRC_GET_ITEMS_CMD;
/* ChangePath */
@@ -1105,7 +1110,7 @@
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
UINT16 uid_counter;
UINT8 direction;
- tAVRC_UID folder_uid;
+ UINT64 folder_uid;
} tAVRC_CHG_PATH_CMD;
/* GetItemAttrs */
@@ -1115,10 +1120,10 @@
tAVRC_STS status;
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
UINT8 scope;
- tAVRC_UID uid;
+ UINT64 uid;
UINT16 uid_counter;
UINT8 attr_count;
- UINT32 *p_attr_list;
+ UINT32 attrs[AVRC_MAX_ELEM_ATTR_SIZE];
} tAVRC_GET_ATTRS_CMD;
/* Search */
@@ -1137,7 +1142,7 @@
tAVRC_STS status;
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
UINT8 scope;
- tAVRC_UID uid;
+ UINT64 uid;
UINT16 uid_counter;
} tAVRC_PLAY_ITEM_CMD;
@@ -1157,6 +1162,14 @@
UINT8 pdu;
tAVRC_STS status;
UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ UINT8 scope;
+} tAVRC_GET_TOTAL_ITEM_CMD;
+
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
} tAVRC_CMD;
/* Continue and Abort */
@@ -1196,6 +1209,7 @@
tAVRC_SEARCH_CMD search; /* Search */
tAVRC_PLAY_ITEM_CMD play_item; /* PlayItem */
tAVRC_ADD_TO_PLAY_CMD add_to_play; /* AddToNowPlaying */
+ tAVRC_GET_TOTAL_ITEM_CMD get_tot_item; /* GetTotalNumberOfItems*/
} tAVRC_COMMAND;
/* GetCapability */
@@ -1300,6 +1314,7 @@
tAVRC_ADDR_PLAYER_PARAM addr_player;
UINT16 uid_counter;
UINT8 volume;
+ UINT8 evt;//For Available Player Changed Notification
} tAVRC_NOTIF_RSP_PARAM;
/* RegNotify */
@@ -1374,6 +1389,16 @@
UINT32 num_items;
} tAVRC_SEARCH_RSP;
+/* GetTotItems*/
+typedef struct
+{
+ UINT8 pdu;
+ tAVRC_STS status;
+ UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+ UINT16 uid_counter;
+ UINT32 num_items;
+} tAVRC_GET_TOT_ITEMS_RSP;
+
typedef struct
{
UINT8 pdu;
@@ -1409,6 +1434,7 @@
tAVRC_SEARCH_RSP search; /* Search */
tAVRC_RSP play_item; /* PlayItem */
tAVRC_RSP add_to_play; /* AddToNowPlaying */
+ tAVRC_GET_TOT_ITEMS_RSP get_tot_items; /* GetTotalItems */
} tAVRC_RESPONSE;
#endif
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index ce98592..ebc1e00 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -20,6 +20,7 @@
#define BT_TYPES_H
#include <stdint.h>
+#include <stdio.h>
#include <stdbool.h>
#include <string.h>
@@ -731,6 +732,9 @@
*******************************************************************************/
static inline void bdcpy(BD_ADDR a, const BD_ADDR b)
{
+ if (a == NULL || b == NULL)
+ return;
+
int i;
for (i = BD_ADDR_LEN; i != 0; i--)
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 360dd48..b806037 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -30,6 +30,7 @@
#include "hcidefs.h"
#include "smp_api.h"
+
/*****************************************************************************
** DEVICE CONTROL and COMMON
*****************************************************************************/
@@ -110,6 +111,21 @@
UINT8 *p_param_buf;
} tBTM_VSC_CMPL;
+/* Structure returned with HCI Raw Command complete callback */
+typedef struct
+{
+ UINT8 event_code;
+ UINT8 param_len;
+ UINT8 *p_param_buf;
+} tBTM_RAW_CMPL;
+
+typedef struct
+{
+ UINT16 adv_len;
+ UINT8 *adv_data_cache;
+} tBTM_BLE_INQ_DATA_CB;
+
+
#define BTM_VSC_CMPL_DATA_SIZE (BTM_MAX_VENDOR_SPECIFIC_LEN + sizeof(tBTM_VSC_CMPL))
/**************************************************
** Device Control and General Callback Functions
@@ -149,6 +165,11 @@
*/
typedef void (tBTM_VSC_CMPL_CB) (tBTM_VSC_CMPL *p1);
+/* HCI RAW CMD callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_RAW_CMPL_CB) (tBTM_RAW_CMPL *p1);
+
/* Callback for apps to check connection and inquiry filters.
** Parameters are the BD Address of remote and the Dev Class of remote.
** If the app returns none zero, the connection or inquiry result will be dropped.
@@ -184,6 +205,7 @@
#define BTM_BLE_MAX_CONNECTABLE BTM_BLE_CONNECTABLE
#define BTM_BLE_CONNECTABLE_MASK (BTM_BLE_NON_CONNECTABLE | BTM_BLE_CONNECTABLE)
+#define BTM_BLE_ADV_STOP 2
/* Inquiry modes
* Note: These modes are associated with the inquiry active values (BTM_*ACTIVE) */
#define BTM_INQUIRY_NONE 0
@@ -590,7 +612,7 @@
#define BTM_BLE_EVT_DISC_ADV 0x02
#define BTM_BLE_EVT_NON_CONN_ADV 0x03
#define BTM_BLE_EVT_SCAN_RSP 0x04
-typedef UINT8 tBTM_BLE_EVT_TYPE;
+typedef UINT16 tBTM_BLE_EVT_TYPE;
#endif
/* These are the fields returned in each device's response to the inquiry. It
@@ -607,12 +629,20 @@
INT8 rssi; /* Set to BTM_INQ_RES_IGNORE_RSSI if not valid */
UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
BOOLEAN eir_complete_list;
+ UINT16 adv_data_len;
#if (BLE_INCLUDED == TRUE)
tBT_DEVICE_TYPE device_type;
UINT8 inq_result_type;
UINT8 ble_addr_type;
tBTM_BLE_EVT_TYPE ble_evt_type;
UINT8 flag;
+ tBTM_BLE_INQ_DATA_CB inq_data;
+ UINT8 pri_phy;
+ UINT8 sec_phy;
+ UINT8 adv_sid;
+ UINT16 periodic_adv_int;
+ UINT8 direct_addr_type;
+ BD_ADDR direct_bda;
#endif
} tBTM_INQ_RESULTS;
@@ -835,7 +865,8 @@
typedef struct
{
tBTM_BL_EVENT event; /* The event reported. */
- UINT8 busy_level;/* when paging or inquiring, level is 10.
+ UINT8 busy_level;/* when paging or inquiring, level is between
+ 17 to 21 as the max links can be 16.
* Otherwise, the number of ACL links. */
UINT8 busy_level_flags; /* Notifies actual inquiry/page activities */
} tBTM_BL_UPDATE_DATA;
@@ -1594,13 +1625,14 @@
#define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT /* 1 << 2 */
typedef UINT8 tBTM_LE_AUTH_REQ;
#define BTM_LE_SC_SUPPORT_BIT SMP_SC_SUPPORT_BIT /* (1 << 3) */
-#define BTM_LE_KP_SUPPORT_BIT SMP_KP_SUPPORT_BIT /* (1 << 4) */
+#define BTM_LE_KP_SUPPORT_BIT SMP_KP_SUPPORT_BIT /* (1 << 4) */`
+#define BTM_LE_H7_SUPPORT_BIT SMP_H7_SUPPORT_BIT /* (1 << 5) */`
-#define BTM_LE_AUTH_REQ_SC_ONLY SMP_AUTH_SC_ENC_ONLY /* 1 << 3 */
-#define BTM_LE_AUTH_REQ_SC_BOND SMP_AUTH_SC_GB /* 1001 */
-#define BTM_LE_AUTH_REQ_SC_MITM SMP_AUTH_SC_MITM_NB /* 1100 */
-#define BTM_LE_AUTH_REQ_SC_MITM_BOND SMP_AUTH_SC_MITM_GB /* 1101 */
-#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x1D */
+#define BTM_LE_AUTH_REQ_SC_ONLY SMP_AUTH_SC_ENC_ONLY /* 00101000 */
+#define BTM_LE_AUTH_REQ_SC_BOND SMP_AUTH_SC_GB /* 00101001 */
+#define BTM_LE_AUTH_REQ_SC_MITM SMP_AUTH_SC_MITM_NB /* 00101100 */
+#define BTM_LE_AUTH_REQ_SC_MITM_BOND SMP_AUTH_SC_MITM_GB /* 00101101 */
+#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x3D */
/* LE security level */
#define BTM_LE_SEC_NONE SMP_SEC_NONE
@@ -1921,6 +1953,17 @@
/*******************************************************************************
**
+** Function BTM_HCI_Reset
+**
+** Description This function is called to send reset command to the controller.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_HCI_Reset (void);
+
+/*******************************************************************************
+**
** Function BTM_IsDeviceUp
**
** Description This function is called to check if the device is up.
@@ -2038,6 +2081,18 @@
/*******************************************************************************
**
+** Function BTM_Hci_Raw_Command
+**
+** Description Send a HCI RAW started testingcommand to the controller.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_Hci_Raw_Command(UINT16 opcode,
+ UINT8 param_len,
+ UINT8 *p_param_buf,
+ tBTM_RAW_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
** Function BTM_VendorSpecificCommand
**
** Description Send a vendor specific HCI command to the controller.
@@ -3769,7 +3824,7 @@
** Returns pointer of EIR data
**
*******************************************************************************/
-extern UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length );
+extern UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length, UINT16 adv_data_len );
/*******************************************************************************
**
diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
index 0cc2e18..e065ae3 100644
--- a/stack/include/btm_ble_api.h
+++ b/stack/include/btm_ble_api.h
@@ -48,7 +48,25 @@
#define BTM_BLE_UNKNOWN_EVT 0xff
+#define BTM_BLE_EXT_SCAN_RSP_EVT_MASK 0x08
+#define BTM_BLE_EXT_CONNECT_DIR_EVT_MASK 0x04
+#define BTM_BLE_EXT_LEGACY_ADV_MASK 0x10
+#define BTM_BLE_EXT_CONN_ADV_MASK 0x01
+#define BTM_BLE_EXT_ADV_EVT_DATA_MASK 0x60
+
+#define BTM_BLE_EXT_ADV_EVT_DATA_CMPL_MASK 0x00
+#define BTM_BLE_EXT_ADV_EVT_DATA_INCMPL_MASK 0x20
+#define BTM_BLE_EXT_ADV_EVT_DATA_INCMPL_TRUNC_MASK 0x40
+
typedef UINT8 tBTM_BLE_EVT;
+
+#define BTM_BLE_EXT_CONNECT_EVT 0x0013
+#define BTM_BLE_EXT_CONNECT_DIR_EVT 0x001D
+#define BTM_BLE_EXT_DISCOVER_EVT 0x0012
+#define BTM_BLE_EXT_NON_CONNECT_EVT 0x0010
+#define BTM_BLE_EXT_CONNECT_LO_DUTY_DIR_EVT 0x0015
+typedef UINT16 tBTM_BLE_EXT_EVT;
+
typedef UINT8 tBTM_BLE_CONN_MODE;
typedef UINT32 tBTM_BLE_REF_VALUE;
@@ -357,7 +375,8 @@
/* Preferred maximum number of microseconds that the local Controller
should use to transmit a single Link Layer Data Channel PDU. */
#define BTM_BLE_DATA_TX_TIME_MIN 0x0148
-#define BTM_BLE_DATA_TX_TIME_MAX 0x0848
+#define BTM_BLE_DATA_TX_TIME_MAX_LEGACY 0x0848
+#define BTM_BLE_DATA_TX_TIME_MAX 0x4290
/* adv tx power level */
#define BTM_BLE_ADV_TX_POWER_MIN 0 /* minimum tx power */
@@ -367,6 +386,11 @@
#define BTM_BLE_ADV_TX_POWER_MAX 4 /* maximum tx power */
typedef UINT8 tBTM_BLE_ADV_TX_POWER;
+/* Subevent code for LE Connection Complete event */
+#if (BLE_PRIVACY_SPT == TRUE )
+#define BTM_BLE_ENHC_CONN_SUB_CODE 0x0A
+#endif
+
/* adv tx power in dBm */
typedef struct
{
@@ -384,6 +408,12 @@
UINT8 debug_logging_supported;
}tBTM_BLE_VSC_CB;
+typedef struct
+{
+ UINT8 adv_inst_max; /* max adv instance supported in controller */
+ UINT16 adv_data_len_max;
+}tBTM_BLE_ADV_EXT_CB;
+
/* slave preferred connection interval range */
typedef struct
{
@@ -466,28 +496,48 @@
}tBTM_BLE_ADV_DATA;
#ifndef BTM_BLE_MULTI_ADV_MAX
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+#define BTM_BLE_MULTI_ADV_MAX 17 /* An extra instance for Extended adv in order to use the 0 inst_id*/
+#else
#define BTM_BLE_MULTI_ADV_MAX 16 /* controller returned adv_inst_max should be less
than this number */
#endif
+#endif
+
#define BTM_BLE_MULTI_ADV_INVALID 0
#define BTM_BLE_MULTI_ADV_ENB_EVT 1
#define BTM_BLE_MULTI_ADV_DISABLE_EVT 2
#define BTM_BLE_MULTI_ADV_PARAM_EVT 3
#define BTM_BLE_MULTI_ADV_DATA_EVT 4
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+#define BTM_BLE_EXTENDED_ADV_ENB_EVT 5
+#define BTM_BLE_EXTENDED_ADV_PARAM_EVT 6
+#endif
typedef UINT8 tBTM_BLE_MULTI_ADV_EVT;
#define BTM_BLE_MULTI_ADV_DEFAULT_STD 0
typedef struct
{
- UINT16 adv_int_min;
- UINT16 adv_int_max;
- UINT8 adv_type;
+ UINT32 adv_int_min;
+ UINT32 adv_int_max;
+ UINT16 adv_type;
tBTM_BLE_ADV_CHNL_MAP channel_map;
tBTM_BLE_AFP adv_filter_policy;
tBTM_BLE_ADV_TX_POWER tx_power;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ UINT8 pri_phy;
+ UINT8 sec_adv_max_skip;
+ UINT8 sec_adv_phy;
+ UINT8 adv_sid;
+ UINT8 scan_req_notf_enb;
+ UINT16 duration;
+ UINT8 max_ext_adv_evts;
+ UINT8 frag_pref;
+#endif
}tBTM_BLE_ADV_PARAMS;
typedef struct
@@ -511,6 +561,24 @@
tBTM_BLE_MULTI_ADV_CBACK *p_cback;
void *p_ref;
UINT8 index;
+ UINT16 len;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ UINT16 duration;
+ tBTM_BLE_EXT_EVT evt_prop;
+
+ //for chained ext advs
+ UINT32 adv_int_min;
+ UINT32 adv_int_max;
+ UINT8 channel_map;
+ UINT8 adv_filter_policy;
+ UINT8 tx_power;
+ UINT8 pri_phy;
+ UINT8 sec_adv_max_skip;
+ UINT8 sec_adv_phy;
+ UINT8 adv_sid;
+ UINT8 scan_req_notf_enb;
+ UINT8 own_addr_type;
+#endif
}tBTM_BLE_MULTI_ADV_INST;
typedef struct
@@ -526,6 +594,15 @@
tBTM_BLE_MULTI_ADV_OPQ op_q;
}tBTM_BLE_MULTI_ADV_CB;
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+typedef struct
+{
+ UINT8 *set_ids;
+ UINT16 *durations;
+ UINT8 *max_adv_events;
+}tBTM_BLE_EXT_ADV_ENABLE_CB;
+#endif
+
typedef UINT8 tGATT_IF;
typedef void (tBTM_BLE_SCAN_THRESHOLD_CBACK)(tBTM_BLE_REF_VALUE ref_value);
@@ -1006,8 +1083,9 @@
** Returns void
**
*******************************************************************************/
-extern void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval,
- UINT32 scan_window, tBLE_SCAN_MODE scan_type,
+extern void BTM_BleSetScanParams(tGATT_IF client_if, UINT8 scan_phys, UINT32 scan_interval,
+ UINT32 scan_window, UINT16 scan_interval_coded,
+ UINT16 scan_window_coded, tBLE_SCAN_MODE scan_type,
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback);
/*******************************************************************************
@@ -1022,6 +1100,19 @@
**
*******************************************************************************/
extern void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb);
+
+/*******************************************************************************
+**
+** Function BTM_BleGetAdvExtCapabilities
+**
+** Description This function reads local LE features
+**
+** Parameters p_cmn_vsc_cb : Locala LE capability structure
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_BleGetAdvExtCapabilities(tBTM_BLE_ADV_EXT_CB *p_ble_adv_ext_cb);
/*******************************************************************************
**
** Function BTM_BleSetStorageConfig
@@ -1136,7 +1227,7 @@
** Returns void
**
*******************************************************************************/
-extern tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration,
+extern tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT16 duration, UINT16 period,
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb);
@@ -1444,6 +1535,32 @@
*******************************************************************************/
extern void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_cback);
+/******************************************************************************
+**
+** Function BTM_BleReadExtAdvControllerFeatures
+**
+** Description Reads BLE specific controller features
+**
+** Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when features are read
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_BleReadExtAdvControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_cback);
+
+/******************************************************************************
+**
+** Function BTM_BleGetAvailableMAInstance
+**
+** Description Gets Available Multi Adv instance
+**
+** Parameters: void
+**
+** Returns Multi advertisement instance id
+**
+*******************************************************************************/
+extern UINT8 BTM_BleGetAvailableMAInstance(void);
+
/*******************************************************************************
**
** Function BTM_CheckAdvData
@@ -1457,7 +1574,7 @@
** Returns pointer of ADV data
**
*******************************************************************************/
-extern UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length);
+extern UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length, UINT16 adv_data_len);
/*******************************************************************************
**
@@ -1647,6 +1764,21 @@
*******************************************************************************/
void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback);
+/*******************************************************************************
+**
+** Function BTM_BleEnhReceiverTest
+**
+** Description This function is called to start the LE Enhanced Receiver
+** test
+**
+** Parameter rx_freq - Frequency Range
+** phy - Phy to be used
+** mod_index - Modulation index
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleEnhReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 mod_index,
+ tBTM_CMPL_CB *p_cmd_cmpl_cback);
/*******************************************************************************
**
@@ -1665,6 +1797,23 @@
/*******************************************************************************
**
+** Function BTM_BleEnhTransmitterTest
+**
+** Description This function is called to start the LE Enhanced Transmitter test
+**
+** Parameter tx_freq - Frequency Range
+** test_data_len - Length in bytes of payload data in each packet
+** packet_payload - Pattern to use in the payload
+** phy - Phy to be used
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleEnhTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
+ UINT8 packet_payload, UINT8 phy,
+ tBTM_CMPL_CB *p_cmd_cmpl_cback);
+
+/*******************************************************************************
+**
** Function BTM_BleTestEnd
**
** Description This function is called to stop the in-progress TX or RX test
@@ -1790,7 +1939,7 @@
**
*******************************************************************************/
extern tBTM_STATUS BTM_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp,
- tBTM_BLE_AD_MASK data_mask,
+ tBTM_BLE_AD_MASK data_mask, UINT8 frag_pref,
tBTM_BLE_ADV_DATA *p_data);
/*******************************************************************************
@@ -1887,6 +2036,68 @@
*******************************************************************************/
extern tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length);
+
+
+/*******************************************************************************
+**
+** Function BTM_GetRemoteDeviceName
+**
+** Description This function is called to get the dev name of remote device
+** from NV
+**
+** Returns TRUE if success; otherwise failed.
+**
+*******************************************************************************/
+extern BOOLEAN BTM_GetRemoteDeviceName(BD_ADDR bda, BD_NAME bdname);
+/*******************************************************************************
+**
+** Function BTM_SetBlePhy
+**
+** Description This function is called to set BLE Tx and Rx Phy
+**
+** Returns BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetBlePhy(BD_ADDR bd_addr, UINT8 all_phy, UINT8 tx_phy,
+ UINT8 rx_phy, UINT16 phy_options);
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultBlePhy
+**
+** Description This function is to set default BLE tx and rx PHY
+**
+** Returns BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDefaultBlePhy(UINT8 all_phy, UINT8 tx_phy, UINT8 rx_phy);
+
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteExtendedAdvData
+**
+** Description This function configure a Multi-ADV instance with the specified
+** adv data or scan response data.
+**
+** Parameters inst_id: adv instance ID
+** is_scan_rsp: is this scan response. if no, set as adv data.
+** data_mask: adv data mask.
+** p_data: pointer to the adv data structure.
+** operation:
+** 0x00: Intermediate fragment
+** 0x01: first fragment
+** 0x02: Last fragment
+** 0x03: complete data, ctrlr fragmentation permitted
+** 0x04: complete data, ctrlr fragmentation not permitted
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteExtendedAdvData (UINT8 inst_id, BOOLEAN is_scan_rsp,
+ tBTM_BLE_AD_MASK data_mask,
+ UINT8 operation, UINT8 frag_pref,
+ tBTM_BLE_ADV_DATA *p_data);
#ifdef __cplusplus
}
#endif
diff --git a/stack/include/btu.h b/stack/include/btu.h
index d0415f9..bf617d0 100644
--- a/stack/include/btu.h
+++ b/stack/include/btu.h
@@ -50,6 +50,7 @@
void *context;
} command_status_hack_t;
+void bte_ssr_cleanup(int reason);
#ifdef __cplusplus
extern "C" {
diff --git a/stack/include/gap_api.h b/stack/include/gap_api.h
index e1be352..394fbd3 100644
--- a/stack/include/gap_api.h
+++ b/stack/include/gap_api.h
@@ -56,6 +56,7 @@
#define GAP_EVT_CONN_CONGESTED 0x0103
#define GAP_EVT_CONN_UNCONGESTED 0x0104
#define GAP_EVT_TX_EMPTY 0x0105
+#define GAP_EVT_TX_DONE 0x0106
/* Values for 'chan_mode_mask' field */
/* GAP_ConnOpen() - optional channels to negotiate */
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index 71d5046..59771e8 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -27,6 +27,7 @@
#define HCI_PROTO_VERSION_4_0 0x06 /* Version for BT spec 4.0 */
#define HCI_PROTO_VERSION_4_1 0x07 /* Version for BT spec 4.1 */
#define HCI_PROTO_VERSION_4_2 0x08 /* Version for BT spec 4.2 */
+#define HCI_PROTO_VERSION_5_0 0x09 /* Version for BT spec 5.0 */
/*
** Definitions for HCI groups
@@ -312,6 +313,7 @@
#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_SCAN_PARAMS (0x000B | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_SCAN_ENABLE (0x000C | HCI_GRP_BLE_CMDS)
+
#define HCI_BLE_CREATE_LL_CONN (0x000D | HCI_GRP_BLE_CMDS)
#define HCI_BLE_CREATE_CONN_CANCEL (0x000E | HCI_GRP_BLE_CMDS)
#define HCI_BLE_READ_WHITE_LIST_SIZE (0x000F | HCI_GRP_BLE_CMDS)
@@ -348,6 +350,30 @@
#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL (0x002C | HCI_GRP_BLE_CMDS)
#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE (0x002D | HCI_GRP_BLE_CMDS)
#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT (0x002E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_SET_DEFAULT_PHY_RATE (0x0031 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PHY_RATE (0x0032 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_ENH_RECEIVER_TEST (0x0033 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENH_TRANSMITTER_TEST (0x0034 | HCI_GRP_BLE_CMDS)
+
+/* BLE ADV EXTENSION COMMANDS */
+#define HCI_BLE_WRITE_EXTENDED_ADV_RPA (0x0035 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_EXTENDED_ADV_PARAMS (0x0036 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_EXTENDED_ADV_DATA (0x0037 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_EXTENDED_SCAN_RSP_DATA (0x0038 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_EXTENDED_ADV_ENABLE (0x0039 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_NUM_ADV_SETS (0x003B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_MAX_ADV_LENGTH (0x003A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_EXT_SCAN_PARAMS (0x0041 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_EXT_SCAN_ENABLE (0x0042 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_EXT_CREATE_LL_CONN (0x0043 | HCI_GRP_BLE_CMDS)
+
+#define BTM_BLE_EXT_ADV_INT_FRAG 0x00
+#define BTM_BLE_EXT_ADV_FIRST_FRAG 0x01
+#define BTM_BLE_EXT_ADV_LAST_FRAG 0x02
+#define BTM_BLE_EXT_ADV_COMPLETE 0x03
/* LE Get Vendor Capabilities Command OCF */
#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
@@ -372,6 +398,14 @@
/* Controller debug info OCF */
#define HCI_CONTROLLER_DEBUG_INFO_OCF (0x015B | HCI_GRP_VENDOR_SPECIFIC)
+/* SOC Logging OCF */
+#define HCI_VS_HOST_LOG_OPCODE (0x0017 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* VOIP Network Wifi OCF */
+#define HCI_VSC_VOIP_NETWORK_WIFI_OCF (0x001C | HCI_GRP_VENDOR_SPECIFIC)
+
+/* subcode for VOIP Network Wifi */
+#define HCI_VSC_SUBCODE_VOIP_NETWORK_WIFI 0x01
/* subcode for multi adv feature */
#define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
@@ -705,6 +739,14 @@
#define HCI_BLE_DATA_LENGTH_CHANGE_EVT 0x07
#define HCI_BLE_ENHANCED_CONN_COMPLETE_EVT 0x0a
#define HCI_BLE_DIRECT_ADV_EVT 0x0b
+#define HCI_BLE_PHY_UPDATE_EVT 0x0c
+#if (defined BLE_EXTENDED_ADV_SUPPORT && BLE_EXTENDED_ADV_SUPPORT == TRUE)
+#define HCI_BLE_EXT_ADV_PKT_RPT_EVT 0x0d
+#define HCI_BLE_SCAN_TIMEOUT_EVT 0x11
+#define HCI_BLE_EXT_ADV_TERMINATED_EVT 0x12
+#endif
+
+
/* Definitions for LE Channel Map */
#define HCI_BLE_CHNL_MAP_SIZE 5
@@ -1442,7 +1484,8 @@
#define HCI_EXT_FEATURES_PAGE_0 0 /* Extended Feature Page 0 (regular features) */
#define HCI_EXT_FEATURES_PAGE_1 1 /* Extended Feature Page 1 */
#define HCI_EXT_FEATURES_PAGE_2 2 /* Extended Feature Page 2 */
-#define HCI_EXT_FEATURES_PAGE_MAX HCI_EXT_FEATURES_PAGE_2
+#define HCI_EXT_FEATURES_PAGE_3 3 /* Extended Feature Page 3 */
+#define HCI_EXT_FEATURES_PAGE_MAX HCI_EXT_FEATURES_PAGE_3
#define HCI_FEATURE_BYTES_PER_PAGE 8
@@ -1783,6 +1826,17 @@
#define HCI_LE_FEATURE_DATA_LEN_EXT_OFF 0
#define HCI_LE_DATA_LEN_EXT_SUPPORTED(x) ((x)[HCI_LE_FEATURE_DATA_LEN_EXT_OFF] & HCI_LE_FEATURE_DATA_LEN_EXT_MASK)
+/* 2Mbps support */
+#define HCI_LE_FEATURE_TWO_MBPS_MASK 0x01
+#define HCI_LE_FEATURE_TWO_MBPS 1
+#define HCI_LE_TWO_MBPS_SUPPORTED(x) ((x)[HCI_LE_FEATURE_TWO_MBPS] & HCI_LE_FEATURE_TWO_MBPS_MASK)
+
+/* Advertisement Length Extensions */
+#define HCI_LE_FEATURE_ADV_EXT_MASK 0x10
+#define HCI_LE_FEATURE_ADV_EXT_OFF 1
+#define HCI_LE_ADV_EXTENSION_SUPPORTED(x) ((x)[HCI_LE_FEATURE_ADV_EXT_OFF] & HCI_LE_FEATURE_ADV_EXT_MASK)
+
+
/*
** Local Supported Commands encoding
*/
@@ -2605,5 +2659,11 @@
#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF 33
#define HCI_LE_RC_CONN_PARAM_UPD_NEG_RPY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF] & HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK)
+/* support for LE privacy mode command (byte 39 bit 2)*/
+#define HCI_SUPP_COMMANDS_LE_SET_PRIVACY_MODE_MASK 0x04
+#define HCI_SUPP_COMMANDS_LE_SET_PRIVACY_MODE_OFF 39
+#define HCI_LE_SET_PRIVACY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LE_SET_PRIVACY_MODE_OFF] & HCI_SUPP_COMMANDS_LE_SET_PRIVACY_MODE_MASK)
+
+
#endif
diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
index 30d861f..ae2f966 100644
--- a/stack/include/hcimsgs.h
+++ b/stack/include/hcimsgs.h
@@ -494,6 +494,10 @@
#define HCI_DELETE_KEY_ALL_FLAG_OFF 6
/* Delete Stored Key */
+extern BOOLEAN btsnd_hcic_reset(UINT8 local_controller_id); /* Reset */
+
+#define HCIC_PARAM_SIZE_RESET 0 /* Reset */
+
/* Change Local Name */
extern BOOLEAN btsnd_hcic_change_name(BD_NAME name);
@@ -517,6 +521,8 @@
#define HCIC_WRITE_PARAM3_PARAM_OFF 0
+#define HCIC_PARAM_SIZE_WRITE_PARAM4 4
+
#define HCIC_PARAM_SIZE_SET_AFH_CHANNELS 10
extern BOOLEAN btsnd_hcic_write_pin_type(UINT8 type); /* Write PIN Type */
@@ -630,6 +636,8 @@
#define HCID_HEADER_SIZE 4
#define HCID_GET_SCO_LEN(p) (*((UINT8 *)((p) + 1) + p->offset + 2))
+extern void btsnd_hcic_raw_cmd (void *buffer, UINT16 opcode, UINT8 len,
+ UINT8 *p_data, void *p_cmd_cplt_cback);
extern void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode,
UINT8 len, UINT8 *p_data,
@@ -651,8 +659,13 @@
#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1
#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM 7
#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE 2
+
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_PARAM 8
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXT_SCAN_ENABLE 6
+
#define HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN 25
#define HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL 0
+#define HCIC_PARAM_SIZE_BLE_EXT_CREATE_LL_CONN 26
#define HCIC_PARAM_SIZE_CLEAR_WHITE_LIST 0
#define HCIC_PARAM_SIZE_ADD_WHITE_LIST 7
#define HCIC_PARAM_SIZE_REMOVE_WHITE_LIST 7
@@ -674,6 +687,7 @@
#define HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST (7 + HCIC_BLE_IRK_SIZE * 2)
#define HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST 7
+#define HCIC_PARAM_SIZE_BLE_SET_PRIVACY_MODE 8
#define HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST 0
#define HCIC_PARAM_SIZE_BLE_READ_RESOLVING_LIST_SIZE 0
#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER 7
@@ -682,6 +696,18 @@
#define HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT 2
#define HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH 6
#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11
+#define HCIC_PARAM_SIZE_BLE_WRITE_DEFAULT_PHY 3
+#define HCIC_PARAM_SIZE_BLE_WRITE_PHY 7
+
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_ADV_PARAMS 25
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_ADV_DATA 251
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_RSP 251
+#define HCIC_PARAM_SIZE_WRITE_EXTENDED_ADV_ENABLE 2
+#define HCIC_PARAM_SIZE_WRITE_EXTENDED_ADV_RPA 7
+
+#define HCIC_SCAN_PHY_LE_1M 1
+#define HCIC_SCAN_PHY_LE_CODED 4
+#define HCIC_SCAN_PHY_LE_1M_CODED 5
/* ULP HCI command */
extern BOOLEAN btsnd_hcic_ble_set_evt_mask (BT_EVENT_MASK event_mask);
@@ -757,8 +783,14 @@
extern BOOLEAN btsnd_hcic_ble_receiver_test(UINT8 rx_freq);
+extern BOOLEAN btsnd_hcic_ble_enh_receiver_test(UINT8 rx_freq, UINT8 phy, UINT8 mod_index);
+
extern BOOLEAN btsnd_hcic_ble_transmitter_test(UINT8 tx_freq, UINT8 test_data_len,
UINT8 payload);
+
+extern BOOLEAN btsnd_hcic_ble_enh_transmitter_test(UINT8 tx_freq, UINT8 test_data_len,
+ UINT8 payload, UINT8 phy);
+
extern BOOLEAN btsnd_hcic_ble_test_end(void);
#if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE)
@@ -785,6 +817,8 @@
extern BOOLEAN btsnd_hcic_ble_rm_device_resolving_list (UINT8 addr_type_peer,
BD_ADDR bda_peer);
+extern BOOLEAN btsnd_hcic_ble_set_privacy_mode (UINT8 addr_type_peer, BD_ADDR bda_peer, UINT8 privacy_type);
+
extern BOOLEAN btsnd_hcic_ble_clear_resolving_list (void);
extern BOOLEAN btsnd_hcic_ble_read_resolvable_addr_peer (UINT8 addr_type_peer,
@@ -797,6 +831,54 @@
extern BOOLEAN btsnd_hcic_ble_set_rand_priv_addr_timeout (UINT16 rpa_timout);
+extern BOOLEAN btsnd_hcic_ble_set_default_data_rate(UINT8 all_phy, UINT8 tx_phy, UINT8 rx_phy);
+
+extern BOOLEAN btsnd_hcic_ble_set_data_rate(UINT16 handle, UINT8 all_phy, UINT8 tx_phy,
+ UINT8 rx_phy, UINT16 phy_options);
+
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+extern BOOLEAN btsnd_hcic_ble_set_extended_adv_params (UINT8 set_id, UINT16 event_properties,
+ UINT32 adv_int_min, UINT32 adv_int_max,
+ UINT8 channel_map, UINT8 addr_type_own,
+ UINT8 addr_type_dir, BD_ADDR direct_bda,
+ UINT8 adv_filter_policy, UINT8 adv_tx_power,
+ UINT8 primary_adv_phy, UINT8 secondary_max_skip,
+ UINT8 secondary_adv_phy, UINT8 advertising_sid,
+ UINT8 scan_req_not_enb);
+
+extern BOOLEAN btsnd_hcic_ble_set_extended_adv_data (UINT8 set_id, UINT8 operation, UINT8 fragment_pref,
+ UINT8 data_len, UINT8 *p_data);
+
+extern BOOLEAN btsnd_hcic_ble_set_extended_scan_rsp_data (UINT8 set_id, UINT8 operation, UINT8 fragement_pref,
+ UINT8 data_len, UINT8 *p_scan_rsp);
+
+extern BOOLEAN btsnd_hcic_ble_set_extended_adv_enable (UINT8 adv_enable, UINT8 num_sets, UINT8* handles,
+ UINT16* durations, UINT8* max_adv_events);
+
+extern BOOLEAN btsnd_hcic_ble_read_num_adv_sets (void);
+
+extern BOOLEAN btsnd_hcic_ble_read_extended_max_adv_len (void);
+
+extern BOOLEAN btsnd_hcic_ble_write_extended_rpa (UINT8 set_id, BD_ADDR rpa);
+
+extern BOOLEAN btsnd_hcic_ble_set_extended_scan_params (UINT8 scan_phys,
+ UINT8 scan_type,
+ UINT16 scan_int, UINT16 scan_win,
+ UINT16 scan_int_coded, UINT16 scan_win_coded,
+ UINT8 addr_type_own, UINT8 scan_filter_policy);
+
+extern BOOLEAN btsnd_hcic_ble_set_extended_scan_enable (UINT8 scan_enable, UINT8 duplicate,
+ UINT16 duraton, UINT16 period);
+
+extern BOOLEAN btsnd_hcic_ble_ext_create_ll_conn (UINT8 ini_phy, UINT16 scan_int, UINT16 scan_win,
+ UINT8 init_filter_policy,
+ UINT8 addr_type_peer, BD_ADDR bda_peer,
+ UINT8 addr_type_own,
+ UINT16 conn_int_min, UINT16 conn_int_max,
+ UINT16 conn_latency, UINT16 conn_timeout,
+ UINT16 min_ce_len, UINT16 max_ce_len);
+#endif
+
#endif /* BLE_INCLUDED */
extern BOOLEAN btsnd_hcic_read_authenticated_payload_tout(UINT16 handle);
diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h
index e8b21fe..518af3a 100644
--- a/stack/include/l2c_api.h
+++ b/stack/include/l2c_api.h
@@ -178,6 +178,7 @@
UINT16 credits;
} tL2CAP_LE_CFG_INFO;
+
/* L2CAP channel configured field bitmap */
#define L2CAP_CH_CFG_MASK_MTU 0x0001
#define L2CAP_CH_CFG_MASK_QOS 0x0002
@@ -585,6 +586,19 @@
*******************************************************************************/
extern UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data);
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/*******************************************************************************
+**
+** Function L2CA_GetDestChannelID
+**
+** Description Higher layers call this function to fetch destination channel id.
+**
+** Returns Destination Channel ID
+**
+*******************************************************************************/
+UINT16 L2CA_GetDestChannelID (UINT16 cid);
+#endif
+
/*******************************************************************************
**
** Function L2CA_Ping
@@ -881,6 +895,21 @@
*******************************************************************************/
extern UINT8 L2CA_GetChnlFcrMode (UINT16 lcid);
+#if (defined(LE_L2CAP_CFC_INCLUDED) && (LE_L2CAP_CFC_INCLUDED == TRUE))
+/*******************************************************************************
+**
+** Function L2CA_LE_SetFlowControlCredits
+**
+** Description Set flow control credits
+**
+** Parameters: Local CID,Credits to set
+**
+** Return value: TRUE if flow control set,FALSE otherwise
+**
+*******************************************************************************/
+
+extern BOOLEAN L2CA_LE_SetFlowControlCredits (UINT16 cid, UINT16 credits);
+#endif
/*******************************************************************************
**
diff --git a/stack/include/port_api.h b/stack/include/port_api.h
index f24887b..66c6202 100644
--- a/stack/include/port_api.h
+++ b/stack/include/port_api.h
@@ -301,6 +301,19 @@
*******************************************************************************/
extern int PORT_SetEventMask (UINT16 port_handle, UINT32 mask);
+/*******************************************************************************
+**
+** Function PORT_GetRemoteMtu
+**
+** Description This function feteches remote mtu from port
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+** Returns: UINT16 - Maximum rfcomm frame size that can be
+** transmitted to the peer
+**
+*******************************************************************************/
+extern UINT16 PORT_GetRemoteMtu (UINT16 handle);
/*******************************************************************************
**
diff --git a/stack/include/sdp_api.h b/stack/include/sdp_api.h
index 16f2dbc..20b47fd 100644
--- a/stack/include/sdp_api.h
+++ b/stack/include/sdp_api.h
@@ -676,4 +676,17 @@
*******************************************************************************/
BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid);
+/*********************************************************************************
+**
+** Function SDP_Dev_Blacklisted_For_Avrcp15
+**
+** Description This function is called to know is local Avrcp Version
+** 1.3 as local Avrcp version is send as 1.3 for black listed
+** devices
+**
+** Returns TRUE if AVRCP local Avrcp Version 1.3 else FALSE
+**
+********************************************************************************/
+BOOLEAN SDP_Dev_Blacklisted_For_Avrcp15 (BD_ADDR addr);
+
#endif /* SDP_API_H */
diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h
index a4d6cc2..44d87e7 100644
--- a/stack/include/sdpdefs.h
+++ b/stack/include/sdpdefs.h
@@ -281,9 +281,6 @@
#define UUID_CODEC_MSBC 0x0002 /* mSBC */
#endif
-#define UUID_HF_IND_ENHANCED_DRIVER_SAFETY 0x0001 /* Assigned number for Enhanced Safety */
-#define UUID_HF_IND_BATTERY_LEVEL_STATUS 0x0002 /* Assigned number for Battery Status */
-
/* Define all the 'Descriptor Type' values.
*/
#define NULL_DESC_TYPE 0
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
index 87f526d..6d77d7f 100644
--- a/stack/include/smp_api.h
+++ b/stack/include/smp_api.h
@@ -146,8 +146,9 @@
#define SMP_AUTH_YN_BIT (1 << 2)
#define SMP_SC_SUPPORT_BIT (1 << 3)
#define SMP_KP_SUPPORT_BIT (1 << 4)
+#define SMP_H7_SUPPORT_BIT (1 << 5)
-#define SMP_AUTH_MASK (SMP_AUTH_GEN_BOND|SMP_AUTH_YN_BIT|SMP_SC_SUPPORT_BIT|SMP_KP_SUPPORT_BIT)
+#define SMP_AUTH_MASK (SMP_AUTH_GEN_BOND|SMP_AUTH_YN_BIT|SMP_SC_SUPPORT_BIT|SMP_KP_SUPPORT_BIT|SMP_H7_SUPPORT_BIT)
#define SMP_AUTH_BOND SMP_AUTH_GEN_BOND
@@ -164,16 +165,16 @@
#define SMP_AUTH_GB_IOCAP (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT)
/* Secure Connections, no MITM, no Bonding */
-#define SMP_AUTH_SC_ENC_ONLY (SMP_SC_SUPPORT_BIT)
+#define SMP_AUTH_SC_ENC_ONLY (SMP_SC_SUPPORT_BIT | SMP_H7_SUPPORT_BIT)
/* Secure Connections, no MITM, Bonding */
-#define SMP_AUTH_SC_GB (SMP_SC_SUPPORT_BIT | SMP_AUTH_GEN_BOND)
+#define SMP_AUTH_SC_GB (SMP_SC_SUPPORT_BIT | SMP_AUTH_GEN_BOND | SMP_H7_SUPPORT_BIT)
/* Secure Connections, MITM, no Bonding */
-#define SMP_AUTH_SC_MITM_NB (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_NO_BOND)
+#define SMP_AUTH_SC_MITM_NB (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_NO_BOND | SMP_H7_SUPPORT_BIT)
/* Secure Connections, MITM, Bonding */
-#define SMP_AUTH_SC_MITM_GB (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_GEN_BOND)
+#define SMP_AUTH_SC_MITM_GB (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_GEN_BOND | SMP_H7_SUPPORT_BIT)
/* All AuthReq RFU bits are set to 1 - NOTE: reserved bit in Bonding_Flags is not set */
#define SMP_AUTH_ALL_RFU_SET 0xF8
diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c
index 62012c6..d7bfb16 100644
--- a/stack/l2cap/l2c_api.c
+++ b/stack/l2cap/l2c_api.c
@@ -62,7 +62,7 @@
tL2C_RCB *p_rcb;
UINT16 vpsm = psm;
- L2CAP_TRACE_API ("L2CAP - L2CA_Register() called for PSM: 0x%04x", psm);
+ L2CAP_TRACE_WARNING ("L2CAP - L2CA_Register() called for PSM: 0x%04x", psm);
/* Verify that the required callback info has been filled in
** Note: Connection callbacks are required but not checked
@@ -131,7 +131,7 @@
tL2C_LCB *p_lcb;
int ii;
- L2CAP_TRACE_API ("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm);
+ L2CAP_TRACE_WARNING ("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm);
if ((p_rcb = l2cu_find_rcb_by_psm (psm)) != NULL)
{
@@ -242,7 +242,7 @@
tL2C_CCB *p_ccb;
tL2C_RCB *p_rcb;
- L2CAP_TRACE_API ("L2CA_ErtmConnectReq() PSM: 0x%04x BDA: %08x%04x p_ertm_info: 0x%08x allowed:0x%x preferred:%d", psm,
+ L2CAP_TRACE_WARNING ("L2CA_ErtmConnectReq() PSM: 0x%04x BDA: %08x%04x p_ertm_info: 0x%08x allowed:0x%x preferred:%d", psm,
(p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
(p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info,
(p_ertm_info) ? p_ertm_info->allowed_modes : 0,
@@ -703,7 +703,7 @@
tL2C_LCB *p_lcb;
tL2C_CCB *p_ccb;
- L2CAP_TRACE_API ("L2CA_ErtmConnectRsp() CID: 0x%04x Result: %d Status: %d BDA: %08x%04x p_ertm_info:0x%08x",
+ L2CAP_TRACE_WARNING ("L2CA_ErtmConnectRsp() CID: 0x%04x Result: %d Status: %d BDA: %08x%04x p_ertm_info:0x%08x",
lcid, result, status,
(p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
(p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info);
@@ -879,7 +879,7 @@
{
tL2C_CCB *p_ccb;
- L2CAP_TRACE_API ("L2CA_DisconnectReq() CID: 0x%04x", cid);
+ L2CAP_TRACE_WARNING ("L2CA_DisconnectReq() CID: 0x%04x", cid);
/* Find the channel control block. We don't know the link it is on. */
if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
@@ -907,7 +907,7 @@
{
tL2C_CCB *p_ccb;
- L2CAP_TRACE_API ("L2CA_DisconnectRsp() CID: 0x%04x", cid);
+ L2CAP_TRACE_WARNING ("L2CA_DisconnectRsp() CID: 0x%04x", cid);
/* Find the channel control block. We don't know the link it is on. */
if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
@@ -1198,7 +1198,7 @@
*******************************************************************************/
UINT8 L2CA_SetDesireRole (UINT8 new_role)
{
- L2CAP_TRACE_API ("L2CA_SetDesireRole() new:x%x, disallow_switch:%d",
+ L2CAP_TRACE_WARNING ("L2CA_SetDesireRole() new:x%x, disallow_switch:%d",
new_role, l2cb.disallow_switch);
if (L2CAP_ROLE_CHECK_SWITCH != (L2CAP_ROLE_CHECK_SWITCH & new_role))
@@ -1313,7 +1313,7 @@
tL2C_CCB *p_ccb;
BOOLEAN on_off = !data_enabled;
- L2CAP_TRACE_API ("L2CA_FlowControl(%d) CID: 0x%04x", on_off, cid);
+ L2CAP_TRACE_WARNING ("L2CA_FlowControl(%d) CID: 0x%04x", on_off, cid);
/* Find the channel control block. We don't know the link it is on. */
if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
@@ -2136,6 +2136,30 @@
return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
}
+#ifdef BTA_AV_SPLIT_A2DP_ENABLED
+/*******************************************************************************
+**
+** Function L2CA_GetDestChannelID
+**
+** Description Higher layers call this function to fetch destination channel id.
+**
+** Returns Destination Channel ID
+**
+*******************************************************************************/
+UINT16 L2CA_GetDestChannelID (UINT16 cid)
+{
+ tL2C_CCB *p_ccb;
+ L2CAP_TRACE_API ("L2CA_GetDestChannelID: local cid: %d", cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid (NULL, cid);
+ L2CAP_TRACE_DEBUG("local cid: %d, dest cid: %d",
+ p_ccb->local_cid, p_ccb->remote_cid);
+
+ return p_ccb->remote_cid;
+}
+#endif
+
/*******************************************************************************
**
** Function L2CA_SetChnlFlushability
diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c
index 307903e..c1edce2 100644
--- a/stack/l2cap/l2c_ble.c
+++ b/stack/l2cap/l2c_ble.c
@@ -31,6 +31,7 @@
#include "btm_int.h"
#include "hcimsgs.h"
#include "device/include/controller.h"
+#include "device/include/interop.h"
#include "stack_config.h"
#include "btif_debug_l2c.h"
#include "log/log.h"
@@ -59,17 +60,17 @@
/* There can be only one BLE connection request outstanding at a time */
if (btm_ble_get_conn_st() == BLE_CONN_IDLE)
{
- L2CAP_TRACE_WARNING ("L2CA_CancelBleConnectReq - no connection pending");
+ L2CAP_TRACE_WARNING ("%s - no connection pending", __func__);
return(FALSE);
}
if (memcmp (rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN))
{
- L2CAP_TRACE_WARNING ("L2CA_CancelBleConnectReq - different BDA Connecting: %08x%04x Cancel: %08x%04x",
+ L2CAP_TRACE_WARNING ("%s - different BDA Connecting: %08x%04x Cancel: %08x%04x", __func__,
(l2cb.ble_connecting_bda[0]<<24)+(l2cb.ble_connecting_bda[1]<<16)+(l2cb.ble_connecting_bda[2]<<8)+l2cb.ble_connecting_bda[3],
(l2cb.ble_connecting_bda[4]<<8)+l2cb.ble_connecting_bda[5],
(rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
-
+ btm_ble_dequeue_direct_conn_req(rem_bda);
return(FALSE);
}
@@ -249,6 +250,7 @@
tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
tACL_CONN *p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE) ;
tL2C_CCB *p_ccb;
+ /*BD_NAME bdname;*/
if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED)
{
@@ -267,6 +269,13 @@
l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, NULL);
}
}
+
+
+ /*if (!BTM_GetRemoteDeviceName(bda, bdname) || !*bdname ||
+ (!interop_match_name(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, (const char*) bdname)))
+ {
+ l2cble_use_preferred_conn_params(bda);
+ }*/
}
/*******************************************************************************
@@ -657,6 +666,9 @@
if (min_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
min_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+ if (max_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
+ max_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+
if (min_interval < BTM_BLE_CONN_INT_MIN || min_interval > BTM_BLE_CONN_INT_MAX ||
max_interval < BTM_BLE_CONN_INT_MIN || max_interval > BTM_BLE_CONN_INT_MAX ||
latency > BTM_BLE_CONN_LATENCY_MAX ||
@@ -903,6 +915,7 @@
UINT8 peer_addr_type = BLE_ADDR_PUBLIC;
UINT8 own_addr_type = BLE_ADDR_PUBLIC;
+ L2CAP_TRACE_WARNING ("l2cble_init_direct_conn");
/* There can be only one BLE connection request outstanding at a time */
if (p_dev_rec == NULL)
{
@@ -942,40 +955,68 @@
return FALSE;
}
- if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */
- scan_win, /* UINT16 scan_win */
- FALSE, /* UINT8 white_list */
- peer_addr_type, /* UINT8 addr_type_peer */
- peer_addr, /* BD_ADDR bda_peer */
- own_addr_type, /* UINT8 addr_type_own */
- (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
- p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), /* UINT16 conn_int_min */
- (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
- p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), /* UINT16 conn_int_max */
- (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ?
- p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* UINT16 conn_latency */
- (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ?
- p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */
- 0, /* UINT16 min_len */
- 0)) /* UINT16 max_len */
+#if (defined BLE_EXTENDED_ADV_SUPPORT && (BLE_EXTENDED_ADV_SUPPORT == TRUE))
+ if (controller_get_interface()->supports_ble_extended_advertisements())
{
- l2cu_release_lcb (p_lcb);
- L2CAP_TRACE_ERROR("initate direct connection fail, no resources");
- return (FALSE);
+ L2CAP_TRACE_WARNING ("l2cble_init_direct_conn::Calling btsnd_hcic_ble_ext_create_ll_conn");
+ if (!btsnd_hcic_ble_ext_create_ll_conn (1 /*LE 1M PHY*/, scan_int,/* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ FALSE, /* UINT8 white_list */
+ peer_addr_type, /* UINT8 addr_type_peer */
+ peer_addr, /* BD_ADDR bda_peer */
+ own_addr_type, /* UINT8 addr_type_own */
+ (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), /* UINT16 conn_int_min */
+ (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), /* UINT16 conn_int_max */
+ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* UINT16 conn_latency */
+ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) /* UINT16 max_len */
+ {
+ l2cu_release_lcb (p_lcb);
+ L2CAP_TRACE_ERROR("initate direct connection fail, no resources");
+ return (FALSE);
+ }
}
else
+#endif
{
- p_lcb->link_state = LST_CONNECTING;
- l2cb.is_ble_connecting = TRUE;
- memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN);
- alarm_set_on_queue(p_lcb->l2c_lcb_timer,
- L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS,
- l2c_lcb_timer_timeout, p_lcb,
- btu_general_alarm_queue);
- btm_ble_set_conn_st (BLE_DIR_CONN);
-
- return (TRUE);
+ if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ FALSE, /* UINT8 white_list */
+ peer_addr_type, /* UINT8 addr_type_peer */
+ peer_addr, /* BD_ADDR bda_peer */
+ own_addr_type, /* UINT8 addr_type_own */
+ (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), /* UINT16 conn_int_min */
+ (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), /* UINT16 conn_int_max */
+ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* UINT16 conn_latency */
+ (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ?
+ p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) /* UINT16 max_len */
+ {
+ l2cu_release_lcb (p_lcb);
+ L2CAP_TRACE_ERROR("initate direct connection fail, no resources");
+ return (FALSE);
+ }
}
+
+ p_lcb->link_state = LST_CONNECTING;
+ l2cb.is_ble_connecting = TRUE;
+ memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+ L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb,
+ btu_general_alarm_queue);
+ btm_ble_set_conn_st (BLE_DIR_CONN);
+
+ return (TRUE);
}
/*******************************************************************************
@@ -1488,6 +1529,33 @@
}
}
+#if (defined(LE_L2CAP_CFC_INCLUDED) && (LE_L2CAP_CFC_INCLUDED == TRUE))
+/*******************************************************************************
+**
+** Function L2CA_LE_SetFlowControlCredits
+**
+** Description This function sets the credits for LE incase credits did
+** not set during the LE connection establishment.
+**
+** Returns TRUE if flow control set,false otherwise
+**
+*******************************************************************************/
+BOOLEAN L2CA_LE_SetFlowControlCredits (UINT16 cid, UINT16 credits)
+{
+ tL2C_CCB *p_ccb;
+ L2CAP_TRACE_WARNING ("LE-L2CAP: %s credits: %d CID: 0x%04x", __FUNCTION__,
+ credits, cid);
+ /* Find the channel control block. We don't know the link it is on. */
+ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+ {
+ L2CAP_TRACE_WARNING ("LE-L2CAP: no CCB found");
+ return (FALSE);
+ }
+ l2cble_send_flow_control_credit(p_ccb, credits);
+ return (TRUE);
+}
+
+#endif //LE_L2CAP_CFC_INCLUDED
/*******************************************************************************
**
** Function l2ble_sec_access_req
diff --git a/stack/l2cap/l2c_csm.c b/stack/l2cap/l2c_csm.c
index dedffc8..9b10de3 100644
--- a/stack/l2cap/l2c_csm.c
+++ b/stack/l2cap/l2c_csm.c
@@ -67,6 +67,11 @@
*******************************************************************************/
void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
{
+ if (!l2cu_is_ccb_active(p_ccb)) {
+ L2CAP_TRACE_WARNING("%s This ccb is not in use, the event(%d) can't be processed", __func__, event);
+ return;
+ }
+
switch (p_ccb->chnl_state)
{
case CST_CLOSED:
@@ -157,7 +162,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: CLOSED evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: CLOSED evt: %d", event);
#endif
switch (event)
@@ -333,7 +338,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: ORIG_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
#endif
#if (L2CAP_UCD_INCLUDED == TRUE)
@@ -447,7 +452,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
#endif
#if (L2CAP_UCD_INCLUDED == TRUE)
@@ -475,7 +480,7 @@
p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
/* Wait for the info resp in next state before sending connect ind (if needed) */
- if (!p_ccb->p_lcb->w4_info_rsp)
+ if ((!p_ccb->p_lcb->w4_info_rsp)||(BT_PSM_SDP == p_ccb->p_rcb->psm))
{
/* Don't need to get info from peer or already retrieved so continue */
alarm_set_on_queue(p_ccb->l2c_ccb_timer,
@@ -573,13 +578,14 @@
{
tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
UINT16 local_cid = p_ccb->local_cid;
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
#endif
switch (event)
@@ -655,7 +661,14 @@
btu_general_alarm_queue);
}
else
+ {
l2cu_release_ccb (p_ccb);
+ if(disconnect_cfm)
+ {
+ L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+ }
+ }
break;
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
@@ -708,7 +721,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
#endif
switch (event)
@@ -827,7 +840,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CONFIG evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: CONFIG evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: CONFIG evt: %d", event);
#endif
switch (event)
@@ -912,8 +925,8 @@
}
}
}
-
- L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid);
+ L2CAP_TRACE_WARNING ("L2CAP-peer_Config_Rsp,Local CID: 0x%04x,Remote CID: 0x%04x,PSM: %d,peer MTU present: %d,peer MTU: %d",
+ p_ccb->local_cid,p_ccb->remote_cid,p_ccb->p_rcb->psm ,p_ccb->peer_cfg.mtu_present,p_ccb->peer_cfg.mtu);
(*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
break;
@@ -1000,6 +1013,8 @@
{
l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
}
+ L2CAP_TRACE_WARNING ("L2CAP-Upper layer Config_Rsp,Local CID: 0x%04x,Remote CID: 0x%04x,PSM: %d,our MTU present:%d,our MTU:%d",
+ p_ccb->local_cid,p_ccb->remote_cid, p_ccb->p_rcb->psm, p_ccb->our_cfg.mtu_present,p_ccb->our_cfg.mtu);
break;
case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config reject */
@@ -1117,7 +1132,7 @@
tempstate = p_ccb->chnl_state;
tempcfgdone = p_ccb->config_done;
p_ccb->chnl_state = CST_CONFIG;
- p_ccb->config_done &= ~CFG_DONE_MASK;
+ p_ccb->config_done &= ~IB_CFG_DONE;
alarm_set_on_queue(p_ccb->l2c_ccb_timer,
L2CAP_CHNL_CFG_TIMEOUT_MS,
@@ -1267,7 +1282,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
#endif
switch (event)
@@ -1332,7 +1347,7 @@
#if (BT_TRACE_VERBOSE == TRUE)
L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
#else
- L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
+ L2CAP_TRACE_WARNING ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
#endif
switch (event)
diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c
index 4c0fb41..e9d373d 100644
--- a/stack/l2cap/l2c_fcr.c
+++ b/stack/l2cap/l2c_fcr.c
@@ -198,6 +198,37 @@
/*******************************************************************************
**
+** Function l2c_fcr_restart_timer
+**
+** Description This function starts the (monitor or retransmission) timer.
+**
+** Returns -
+**
+*******************************************************************************/
+void l2c_fcr_restart_timer (tL2C_CCB *p_ccb)
+{
+ assert(p_ccb != NULL);
+ UINT32 tout;
+
+ /* The timers which are in milliseconds */
+ if (p_ccb->fcrb.wait_ack)
+ {
+ tout = (UINT32)p_ccb->our_cfg.fcr.mon_tout;
+ }
+ else
+ {
+ tout = (UINT32)p_ccb->our_cfg.fcr.rtrans_tout;
+ }
+
+ /* restart the mentioned timer */
+ alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, tout,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+}
+
+
+/*******************************************************************************
+**
** Function l2c_fcr_stop_timer
**
** Description This function stops the (monitor or transmission) timer.
@@ -1048,6 +1079,10 @@
for (xx = 0; xx < num_bufs_acked; xx++)
{
BT_HDR *p_tmp = (BT_HDR *)fixed_queue_try_dequeue(p_fcrb->waiting_for_ack_q);
+ if (p_tmp == NULL) {
+ L2CAP_TRACE_WARNING ("%s: Unable to dequeue", __func__);
+ return (FALSE);
+ }
ls = p_tmp->layer_specific & L2CAP_FCR_SAR_BITS;
if ( (ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU) )
@@ -1057,8 +1092,6 @@
}
/* If we are still in a wait_ack state, do not mess with the timer */
- if (!p_ccb->fcrb.wait_ack)
- l2c_fcr_stop_timer (p_ccb);
/* Check if we need to call the "packet_sent" callback */
if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (full_sdus_xmitted) )
@@ -1074,8 +1107,15 @@
}
/* If anything still waiting for ack, restart the timer if it was stopped */
- if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
- l2c_fcr_start_timer(p_ccb);
+ if(!p_ccb->fcrb.wait_ack) {
+ if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q)) {
+// l2c_fcr_start_timer(p_ccb);
+ l2c_fcr_restart_timer (p_ccb);
+ }
+ else
+ l2c_fcr_stop_timer (p_ccb);
+ }
+
return (TRUE);
}
@@ -1230,8 +1270,12 @@
if (p_fcrb->srej_sent)
{
/* If SREJ sent, save the frame for later processing as long as it is in sequence */
- next_srej = (((BT_HDR *)fixed_queue_try_peek_last(p_fcrb->srej_rcv_hold_q))->layer_specific + 1) & L2CAP_FCR_SEQ_MODULO;
-
+ void * frame_msg = fixed_queue_try_peek_last(p_fcrb->srej_rcv_hold_q);
+ if (frame_msg == NULL) {
+ L2CAP_TRACE_WARNING ("%s: Unable to process frame", __func__);
+ return;
+ }
+ next_srej = (((BT_HDR *)frame_msg)->layer_specific + 1) & L2CAP_FCR_SEQ_MODULO;
if ( (tx_seq == next_srej) && (fixed_queue_length(p_fcrb->srej_rcv_hold_q) < p_ccb->our_cfg.fcr.tx_win_sz) )
{
/* If user gave us a pool for held rx buffers, use that */
@@ -1731,6 +1775,10 @@
}
p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_ERROR ("%s: L2CAP - fixed_queue_try_peek_first returned queue as empty", __func__);
+ return NULL;
+ }
/* If there is more data than the MPS, it requires segmentation */
if (p_buf->len > max_pdu)
@@ -1767,8 +1815,12 @@
}
else /* Use the original buffer if no segmentation, or the last segment */
{
- p_xmit = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
-
+ void *seg_msg = fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+ if (seg_msg == NULL) {
+ L2CAP_TRACE_WARNING ("%s: Unable to process frame", __func__);
+ return (NULL);
+ }
+ p_xmit = (BT_HDR *)seg_msg;
if (p_xmit->event != 0)
last_seg = TRUE;
@@ -1882,6 +1934,10 @@
UINT16 max_pdu = p_ccb->peer_conn_cfg.mps;
p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_ERROR ("%s: L2CAP - fixed_queue_try_peek_first returned queue as empty", __func__);
+ return (NULL);
+ }
/* We are using the "event" field to tell is if we already started segmentation */
if (p_buf->event == 0)
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 8af47d7..bbf2409 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -250,7 +250,7 @@
#ifndef L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA
-#define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 100
+#define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 10
#endif
typedef void (tL2CAP_SEC_CBACK) (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
@@ -640,6 +640,7 @@
extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
+extern BOOLEAN l2cu_is_ccb_active (tL2C_CCB *p_ccb);
/* Functions provided by l2c_ucd.c
************************************
diff --git a/stack/l2cap/l2c_link.c b/stack/l2cap/l2c_link.c
index 2fefd13..dcf1362 100644
--- a/stack/l2cap/l2c_link.c
+++ b/stack/l2cap/l2c_link.c
@@ -41,12 +41,13 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btcore/include/bdaddr.h"
-
+#include "device/include/interop_config.h"
extern fixed_queue_t *btu_general_alarm_queue;
static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf);
+#define HI_PRI_LINK_QUOTA 2 //Mininum ACL buffer quota for high priority link
/*******************************************************************************
**
** Function l2c_link_hci_conn_req
@@ -63,6 +64,7 @@
tL2C_LCB *p_lcb_cur;
int xx;
BOOLEAN no_links;
+ bt_bdaddr_t remote_bdaddr;
/* See if we have a link control block for the remote device */
p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR);
@@ -75,6 +77,7 @@
{
btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_RESOURCES);
L2CAP_TRACE_ERROR ("L2CAP failed to allocate LCB");
+ GENERATE_VENDOR_LOGS();
return FALSE;
}
@@ -101,7 +104,11 @@
else
p_lcb->link_role = l2cu_get_conn_role(p_lcb);
}
-
+ bdcpy(remote_bdaddr.address, bd_addr);
+ if ((p_lcb->link_role == BTM_ROLE_MASTER)&&(interop_database_match_addr(INTEROP_DISABLE_ROLE_SWITCH, (bt_bdaddr_t *)&remote_bdaddr))) {
+ p_lcb->link_role = BTM_ROLE_SLAVE;
+ L2CAP_TRACE_WARNING ("l2c_link_hci_conn_req:set link_role= %d",p_lcb->link_role);
+ }
/* Tell the other side we accept the connection */
btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role);
@@ -175,6 +182,13 @@
if (!p_lcb)
{
L2CAP_TRACE_WARNING ("L2CAP got conn_comp for unknown BD_ADDR");
+
+ /* Connection complete received when no link control block is present for this address
+ * However ACL entry is already created
+ * Removing connection entry at ACL and sending disconnect because l2c and acl are out of sync */
+ btm_remove_acl(p_bda, BT_TRANSPORT_BR_EDR);
+ btm_acl_removed(p_bda, BT_TRANSPORT_BR_EDR);
+
return (FALSE);
}
@@ -276,6 +290,7 @@
{
/* we are in collision situation, wait for connecttion request from controller */
p_lcb->link_state = LST_CONNECTING;
+ GENERATE_VENDOR_LOGS();
}
else
{
@@ -487,6 +502,28 @@
}
#endif
}
+ if (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+ {
+ if (p_lcb->sent_not_acked > 0)
+ {
+ l2cb.controller_xmit_window += p_lcb->sent_not_acked;
+ if (l2cb.controller_xmit_window > l2cb.num_lm_acl_bufs)
+ {
+ l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
+ }
+ p_lcb->sent_not_acked = 0;
+ }
+ p_lcb->partial_segment_being_sent = FALSE;
+
+ /* Stop the link connect timer if sent */
+ if (p_lcb->w4_info_rsp)
+ {
+ alarm_cancel(p_lcb->l2c_lcb_timer);
+ p_lcb->w4_info_rsp = FALSE;
+ }
+
+ btm_acl_removed(p_lcb->remote_bd_addr, BT_TRANSPORT_BR_EDR);
+ }
if (l2cu_create_conn(p_lcb, transport))
lcb_is_free = FALSE; /* still using this lcb */
}
@@ -587,6 +624,9 @@
#endif
/* Release the LCB */
l2cu_release_lcb (p_lcb);
+
+ /*Generate logs for link timeout while connecting/disconnecting*/
+ GENERATE_VENDOR_LOGS();
}
/* If link is connected, check for inactivity timeout */
@@ -652,6 +692,9 @@
l2cu_process_fixed_disc_cback(p_lcb);
p_lcb->link_state = LST_DISCONNECTING;
timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+
+ /*Link timeout must not occur while bonding*/
+ GENERATE_VENDOR_LOGS();
}
else
{
@@ -775,6 +818,14 @@
while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota )
high_pri_link_quota--;
+ /*Adjust high pri link with min 3 buffers*/
+ if(num_hipri_links > 0)
+ {
+ if(high_pri_link_quota < HI_PRI_LINK_QUOTA)
+ {
+ high_pri_link_quota = HI_PRI_LINK_QUOTA;
+ }
+ }
/* Work out the xmit quota and buffer quota high and low priorities */
hi_quota = num_hipri_links * high_pri_link_quota;
low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;
diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
index 92e92ca..c9344f8 100644
--- a/stack/l2cap/l2c_main.c
+++ b/stack/l2cap/l2c_main.c
@@ -114,7 +114,7 @@
}
return;
- } else {
+ } else if (handle != 0xedc) { /* Handle 0xedc used for SOC Logging */
L2CAP_TRACE_ERROR ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d"
" opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid,
cmd_code, list_length(l2cb.rcv_pending_q));
@@ -316,6 +316,12 @@
STREAM_TO_UINT8 (id, p);
STREAM_TO_UINT16 (cmd_len, p);
+ if(cmd_len > BT_SMALL_BUFFER_SIZE)
+ {
+ L2CAP_TRACE_WARNING ("L2CAP - Invalid MTU Size");
+ l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id, 0, 0);
+ return;
+ }
/* Check command length does not exceed packet length */
if ((p_next_cmd = p + cmd_len) > p_pkt_end)
{
@@ -475,7 +481,7 @@
p_cfg_start = p;
cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
- cfg_info.fcr_present = cfg_info.fcs_present = FALSE;
+ cfg_info.fcr_present = cfg_info.fcs_present = FALSE;
while (p < p_cfg_end)
{
@@ -780,7 +786,7 @@
break;
case L2CAP_CMD_ECHO_REQ:
- l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0);
+ l2cu_send_peer_echo_rsp (p_lcb, id, p, cmd_len);
break;
case L2CAP_CMD_ECHO_RSP:
diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c
index 72bd52e..6e51747 100644
--- a/stack/l2cap/l2c_utils.c
+++ b/stack/l2cap/l2c_utils.c
@@ -1677,16 +1677,22 @@
*******************************************************************************/
void l2cu_release_ccb (tL2C_CCB *p_ccb)
{
- tL2C_LCB *p_lcb = p_ccb->p_lcb;
- tL2C_RCB *p_rcb = p_ccb->p_rcb;
+ tL2C_LCB *p_lcb = NULL;
+ tL2C_RCB *p_rcb = NULL;
L2CAP_TRACE_DEBUG ("l2cu_release_ccb: cid 0x%04x in_use: %u", p_ccb->local_cid, p_ccb->in_use);
/* If already released, could be race condition */
- if (!p_ccb->in_use)
+ if (!p_ccb || !p_ccb->in_use)
return;
+ p_lcb = p_ccb->p_lcb;
+ p_rcb = p_ccb->p_rcb;
+#if (defined(LE_L2CAP_CFC_INCLUDED) && (LE_L2CAP_CFC_INCLUDED == TRUE))
+ if (p_rcb && p_lcb && (p_rcb->psm != p_rcb->real_psm))
+#else
if (p_rcb && (p_rcb->psm != p_rcb->real_psm))
+#endif
{
btm_sec_clr_service_by_psm(p_rcb->psm);
}
@@ -1698,7 +1704,8 @@
p_ccb->should_free_rcb = false;
}
- btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr);
+ if(p_lcb)
+ btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr);
/* Free the timer */
alarm_free(p_ccb->l2c_ccb_timer);
@@ -2568,6 +2575,12 @@
return (FALSE);
}
+ if (p_lcb->acl_priority != priority)
+ {
+ p_lcb->acl_priority = priority;
+ l2c_link_adjust_allocation();
+ }
+
if (BTM_IS_BRCM_CONTROLLER())
{
/* Called from above L2CAP through API; send VSC if changed */
@@ -2860,13 +2873,17 @@
}
}
+ if (timeout_ms == (1000) * (0xFFFF))
+ start_timeout = false;
+
if (start_timeout) {
- L2CAP_TRACE_DEBUG("%s starting IDLE timeout: %d ms", __func__,
+ L2CAP_TRACE_DEBUG("%s starting IDLE timeout: %llu ms", __func__,
timeout_ms);
alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
l2c_lcb_timer_timeout, p_lcb,
btu_general_alarm_queue);
} else {
+ L2CAP_TRACE_DEBUG("%s, alarm cancel", __func__);
alarm_cancel(p_lcb->l2c_lcb_timer);
}
}
@@ -3790,7 +3807,7 @@
p_ccb->cong_sent = TRUE;
if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
{
- L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
+ L2CAP_TRACE_WARNING ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
p_ccb->local_cid, q_count, p_ccb->buff_quota);
(*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
@@ -3828,3 +3845,17 @@
}
}
+/*******************************************************************************
+**
+** Function l2cu_is_ccb_active
+**
+** Description Check if Channel Control Block is in use or released
+**
+** Returns BOOLEAN - TRUE if Channel Control Block is in use
+** FALSE if p_ccb is null or is released.
+**
+*******************************************************************************/
+BOOLEAN l2cu_is_ccb_active (tL2C_CCB *p_ccb)
+{
+ return (p_ccb && p_ccb->in_use);
+}
diff --git a/stack/l2cap/l2cap_client.c b/stack/l2cap/l2cap_client.c
index cd7edfe..e96d3d3 100644
--- a/stack/l2cap/l2cap_client.c
+++ b/stack/l2cap/l2cap_client.c
@@ -98,6 +98,10 @@
}
l2cap_client_t *ret = (l2cap_client_t *)osi_calloc(sizeof(l2cap_client_t));
+ if (ret == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client.", __func__);
+ return NULL;
+ }
ret->callbacks = *callbacks;
ret->context = context;
diff --git a/stack/mcap/mca_cact.c b/stack/mcap/mca_cact.c
index 8a75283..4b42f0f 100644
--- a/stack/mcap/mca_cact.c
+++ b/stack/mcap/mca_cact.c
@@ -31,7 +31,7 @@
#include "mca_api.h"
#include "mca_defs.h"
#include "mca_int.h"
-
+#include <unistd.h>
#include "btu.h"
@@ -110,8 +110,11 @@
p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
/* the Abort API does not have the associated mdl_id.
* Get the mdl_id in dcb to compose the request */
- p_msg->mdl_id = p_dcb->mdl_id;
- mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ if(p_dcb)
+ {
+ p_msg->mdl_id = p_dcb->mdl_id;
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
osi_free_and_reset((void **)&p_ccb->p_tx_req);
p_ccb->status = MCA_CCB_STAT_NORM;
is_abort = TRUE;
@@ -402,6 +405,9 @@
case MCA_OP_MDL_DELETE_REQ:
/* delete the associated mdl */
mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+#if (defined(MCA_DELAY_DELETE_MDL_RSP) && MCA_DELAY_DELETE_MDL_RSP == TRUE)
+ sleep(5);
+#endif
send_rsp = TRUE;
break;
}
@@ -503,7 +509,7 @@
if (chk_mdl)
{
p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
- if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
+ if (p_dcb && evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
{
if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
{
diff --git a/stack/mcap/mca_csm.c b/stack/mcap/mca_csm.c
index 1ded765..f643e92 100644
--- a/stack/mcap/mca_csm.c
+++ b/stack/mcap/mca_csm.c
@@ -198,7 +198,7 @@
p_ccb->state = state_table[event][MCA_CCB_NEXT_STATE];
/* execute action functions */
- if ((action = state_table[event][MCA_CCB_ACT_COL]) != MCA_CCB_IGNORE)
+ if ((action = state_table[event][MCA_CCB_ACT_COL]) < MCA_CCB_IGNORE)
{
(*mca_ccb_action[action])(p_ccb, p_data);
}
@@ -366,10 +366,18 @@
{
BOOLEAN uses = FALSE;
tMCA_DCB *p_dcb;
- int i;
+ unsigned int i;
i = mca_ccb_to_hdl(p_ccb)-1;
- p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ if (i*MCA_NUM_MDLS < MCA_NUM_DCBS)
+ {
+ p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ }
+ else
+ {
+ MCA_TRACE_WARNING("dcb index out of range");
+ return uses;
+ }
for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
{
if (p_dcb->state != MCA_DCB_NULL_ST && p_dcb->mdl_id == mdl_id)
diff --git a/stack/mcap/mca_dsm.c b/stack/mcap/mca_dsm.c
index c76e020..e122d43 100644
--- a/stack/mcap/mca_dsm.c
+++ b/stack/mcap/mca_dsm.c
@@ -154,7 +154,7 @@
p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
/* execute action functions */
- if ((action = state_table[event][MCA_DCB_ACT_COL]) != MCA_DCB_IGNORE)
+ if ((action = state_table[event][MCA_DCB_ACT_COL]) < MCA_DCB_IGNORE)
{
(*mca_dcb_action[action])(p_dcb, p_data);
}
@@ -175,13 +175,21 @@
tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
tMCA_RCB *p_rcb = p_ccb->p_rcb;
tMCA_CS *p_cs;
- int i, max;
+ unsigned int i, max;
if (dep < MCA_NUM_DEPS)
{
p_cs = &p_rcb->dep[dep];
i = mca_ccb_to_hdl(p_ccb)-1;
- p_dcb_tmp = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ if( i*MCA_NUM_MDLS < MCA_NUM_DCBS)
+ {
+ p_dcb_tmp = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ }
+ else
+ {
+ MCA_TRACE_WARNING("dcb index out of range");
+ return NULL;
+ }
/* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
max = p_cs->max_mdl;
for (i=0; i<max; i++, p_dcb_tmp++)
@@ -215,7 +223,7 @@
tMCA_DCB *p_dcb;
tMCA_RCB *p_rcb = p_ccb->p_rcb;
tMCA_CS *p_cs;
- int i, max;
+ unsigned int i, max;
UINT8 count = 0;
UINT8 left;
@@ -223,7 +231,15 @@
{
p_cs = &p_rcb->dep[dep];
i = mca_ccb_to_hdl(p_ccb)-1;
- p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ if( i*MCA_NUM_MDLS < MCA_NUM_DCBS)
+ {
+ p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ }
+ else
+ {
+ MCA_TRACE_WARNING("dcb index out of range");
+ return 0;
+ }
/* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
max = p_cs->max_mdl;
for (i=0; i<max; i++, p_dcb++)
@@ -327,7 +343,15 @@
MCA_TRACE_DEBUG("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
i = mca_ccb_to_hdl(p_ccb)-1;
- p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+ if( i*MCA_NUM_MDLS < MCA_NUM_DCBS)
+ {
+ p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ }
+ else
+ {
+ MCA_TRACE_WARNING("dcb index out of range");
+ return;
+ }
for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
{
if (p_dcb->state)
diff --git a/stack/mcap/mca_l2c.c b/stack/mcap/mca_l2c.c
index 62caf78..9456d3d 100644
--- a/stack/mcap/mca_l2c.c
+++ b/stack/mcap/mca_l2c.c
@@ -204,7 +204,7 @@
/* if result ok, proceed with connection and send L2CAP
config req */
- if (result == L2CAP_CONN_OK)
+ if (result == L2CAP_CONN_OK && p_tbl)
{
/* set channel state */
p_tbl->state = MCA_TC_ST_CFG;
diff --git a/stack/mcap/mca_main.c b/stack/mcap/mca_main.c
index d1591b3..14ca09a 100644
--- a/stack/mcap/mca_main.c
+++ b/stack/mcap/mca_main.c
@@ -255,7 +255,7 @@
void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl)
{
tMCA_DCB *p_dcb;
- const tL2CAP_FCR_OPTS *p_opt;
+ const tL2CAP_FCR_OPTS *p_opt = NULL;
tMCA_FCS_OPT fcs = MCA_FCS_NONE;
if (p_tbl->tcid == MCA_CTRL_TCID)
@@ -265,7 +265,7 @@
else
{
p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
- if (p_dcb)
+ if (p_dcb != NULL)
{
p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
fcs = p_dcb->p_chnl_cfg->fcs;
@@ -275,7 +275,8 @@
p_cfg->mtu_present = TRUE;
p_cfg->mtu = p_tbl->my_mtu;
p_cfg->fcr_present = TRUE;
- memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
+ if (p_opt != NULL)
+ memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
if (fcs & MCA_FCS_PRESNT_MASK)
{
p_cfg->fcs_present = TRUE;
@@ -323,7 +324,10 @@
if (p_tbl->tcid == MCA_CTRL_TCID)
{
p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
+ if(p_ccb != NULL)
+ {
+ mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
+ }
}
/* notify dcb that channel close */
else
@@ -372,8 +376,10 @@
if (p_tbl->tcid == MCA_CTRL_TCID)
{
p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
-
- mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
+ if(p_ccb != NULL)
+ {
+ mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
+ }
}
/* must be data channel, notify dcb that channel open */
else
@@ -415,7 +421,10 @@
if (p_tbl->tcid == MCA_CTRL_TCID)
{
p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
- mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
+ if (p_ccb != NULL)
+ {
+ mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
+ }
}
/* notify dcb that channel open */
else
diff --git a/stack/pan/pan_api.c b/stack/pan/pan_api.c
index a20ed57..d56bf1f 100644
--- a/stack/pan/pan_api.c
+++ b/stack/pan/pan_api.c
@@ -407,6 +407,7 @@
result = BNEP_Connect (rem_bda, &src_uuid, &dst_uuid, &(pcb->handle));
if (result != BNEP_SUCCESS)
{
+ pan_cb.num_conns--;
pan_release_pcb (pcb);
return result;
}
diff --git a/stack/rfcomm/port_api.c b/stack/rfcomm/port_api.c
index 13457f9..0c90866 100644
--- a/stack/rfcomm/port_api.c
+++ b/stack/rfcomm/port_api.c
@@ -527,6 +527,51 @@
/*******************************************************************************
**
+** Function PORT_GetRemoteMtu
+**
+** Description This function feteches remote mtu from port
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+** Returns: UINT16 - Maximum rfcomm frame size that can be
+** transmitted to the peer
+**
+*******************************************************************************/
+UINT16 PORT_GetRemoteMtu (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API ("PORT_GetRemoteMtu() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (0);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_ERROR ("PORT_GetRemoteMtu() p_port->in_use = %d, p_port->state = %d",
+ p_port->in_use, p_port->state);
+ return (0);
+ }
+
+ if (!p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ RFCOMM_TRACE_ERROR ("PORT_GetRemoteMtu() peer not ready or p_port->rfc.state = %d",
+ p_port->rfc.state );
+ return (0);
+ }
+
+ return (p_port->peer_mtu);
+}
+
+/*******************************************************************************
+**
** Function PORT_IsOpening
**
** Description This function returns TRUE if there is any RFCOMM connection
diff --git a/stack/rfcomm/port_rfc.c b/stack/rfcomm/port_rfc.c
index aaad62a..374b191 100644
--- a/stack/rfcomm/port_rfc.c
+++ b/stack/rfcomm/port_rfc.c
@@ -312,6 +312,7 @@
problem, they don't disconnect if we send DM */
rfc_check_mcb_active( p_mcb );
RFCOMM_TRACE_EVENT( "PORT_ParNegInd: port not found" );
+ GENERATE_VENDOR_LOGS();
return;
}
p_mcb->port_inx[dlci] = p_port->inx;
diff --git a/stack/rfcomm/rfc_l2cap_if.c b/stack/rfcomm/rfc_l2cap_if.c
index 05f4994..6ae3863 100644
--- a/stack/rfcomm/rfc_l2cap_if.c
+++ b/stack/rfcomm/rfc_l2cap_if.c
@@ -35,7 +35,9 @@
#include "l2cdefs.h"
#include "rfc_int.h"
#include "bt_utils.h"
+#include "port_ext.h"
+extern fixed_queue_t *btu_general_alarm_queue;
/*
** Define Callback functions to be called by L2CAP
@@ -104,10 +106,13 @@
/* wait random timeout (2 - 12) to resolve collision */
/* if peer gives up then local device rejects incoming connection and continues as initiator */
/* if timeout, local device disconnects outgoing connection and continues as acceptor */
- RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectInd start timer for collision, initiator's LCID(0x%x), acceptor's LCID(0x%x)",
- p_mcb->lcid, p_mcb->pending_lcid);
-
- rfc_timer_start(p_mcb, (UINT16)(time_get_os_boottime_ms() % 10 + 2));
+ period_ms_t interval_ms = (((time_get_os_boottime_ms() % 20) * 500) + 2000);
+ RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectInd start collision timer = %d ms , initiator's LCID(0x%x), acceptor's LCID(0x%x)",
+ interval_ms, p_mcb->lcid, p_mcb->pending_lcid);
+ alarm_set_on_queue(p_mcb->mcb_timer, interval_ms,
+ rfcomm_mcb_timer_timeout, p_mcb,
+ btu_general_alarm_queue);
+ GENERATE_VENDOR_LOGS();
return;
}
else
diff --git a/stack/rfcomm/rfc_mx_fsm.c b/stack/rfcomm/rfc_mx_fsm.c
index a12ae96..0d80b26 100644
--- a/stack/rfcomm/rfc_mx_fsm.c
+++ b/stack/rfcomm/rfc_mx_fsm.c
@@ -375,6 +375,8 @@
*******************************************************************************/
void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data)
{
+ tPORT *p_port;
+ int i;
RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_wait_sabme - evt:%d", event);
switch (event)
{
@@ -414,7 +416,15 @@
p_mcb->state = RFC_MX_STATE_CONNECTED;
p_mcb->peer_ready = TRUE;
- PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+ break;
+ }
+ }
}
return;
@@ -603,7 +613,7 @@
{
RFCOMM_TRACE_EVENT ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0);
- if (p_cfg->result != L2CAP_CFG_OK)
+ if (p_cfg && p_cfg->result != L2CAP_CFG_OK)
{
if (p_mcb->is_initiator)
{
diff --git a/stack/rfcomm/rfc_utils.c b/stack/rfcomm/rfc_utils.c
index 2fa7ca8..692d985 100644
--- a/stack/rfcomm/rfc_utils.c
+++ b/stack/rfcomm/rfc_utils.c
@@ -325,6 +325,7 @@
tPORT *p_port = (tPORT *)data;
rfc_port_sm_execute(p_port, RFC_EVENT_TIMEOUT, NULL);
+ GENERATE_VENDOR_LOGS();
}
void rfcomm_mcb_timer_timeout(void *data)
@@ -332,6 +333,8 @@
tRFC_MCB *p_mcb = (tRFC_MCB *)data;
rfc_mx_sm_execute(p_mcb, RFC_EVENT_TIMEOUT, NULL);
+
+ GENERATE_VENDOR_LOGS();
}
/*******************************************************************************
@@ -375,7 +378,7 @@
{
tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
- RFCOMM_TRACE_DEBUG ("rfc_port_closed");
+ RFCOMM_TRACE_WARNING ("rfc_port_closed");
rfc_port_timer_stop (p_port);
@@ -436,6 +439,8 @@
if (p_port->credit_tx > 0)
p_port->credit_tx--;
+ RFCOMM_TRACE_EVENT ("rfc_dec_credit:%d", p_port->credit_tx);
+
if (p_port->credit_tx == 0)
p_port->tx.peer_fc = TRUE;
}
diff --git a/stack/sdp/sdp_api.c b/stack/sdp/sdp_api.c
index f5033cf..a8bada5 100644
--- a/stack/sdp/sdp_api.c
+++ b/stack/sdp/sdp_api.c
@@ -32,6 +32,7 @@
#include "l2cdefs.h"
#include "hcidefs.h"
#include "hcimsgs.h"
+#include "avrc_defs.h"
#include "sdp_api.h"
#include "sdpint.h"
@@ -1275,3 +1276,35 @@
return(sdp_cb.trace_level);
}
+
+/****************************************************************************
+**
+** Function SDP_Dev_Blacklisted_For_Avrcp15
+**
+** Description This function is called to check if Remote device
+** is blacklisted for Avrcp version.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN SDP_Dev_Blacklisted_For_Avrcp15 (BD_ADDR addr)
+{
+ int ver;
+ BOOLEAN ret = sdp_dev_blacklisted_for_avrcp15(addr);
+ SDP_TRACE_ERROR("%s", __func__);
+ if (ret != TRUE)
+ {
+ ver = sdp_get_stored_avrc_tg_version (addr);
+ SDP_TRACE_ERROR("Stored AVRC TG version: 0x%x", ver);
+ if (ver >= AVRC_REV_1_4)
+ {
+ ret = FALSE;
+ }
+ else
+ {
+ ret = TRUE;
+ }
+ }
+ SDP_TRACE_ERROR("%s: blacklisted: %d", __func__, ret);
+ return ret;
+}
diff --git a/stack/sdp/sdp_db.c b/stack/sdp/sdp_db.c
index 1c81202..d0d293c 100644
--- a/stack/sdp/sdp_db.c
+++ b/stack/sdp/sdp_db.c
@@ -357,6 +357,8 @@
for (yy = xx; yy < sdp_cb.server_db.num_records; yy++, p_rec++)
{
*p_rec = *(p_rec + 1);
+ /* Adjust continuation info in the CCB */
+ sdpu_update_ccb_cont_info(p_rec->record_handle);
/* Adjust the attribute value pointer for each attribute */
for (zz = 0; zz < p_rec->num_attributes; zz++)
@@ -400,7 +402,7 @@
UINT32 attr_len, UINT8 *p_val)
{
#if SDP_SERVER_ENABLED == TRUE
- UINT16 xx, yy, zz;
+ UINT16 xx;
tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
#if (BT_TRACE_VERBOSE == TRUE)
@@ -438,81 +440,84 @@
#endif
/* Find the record in the database */
- for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++)
+ for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
{
if (p_rec->record_handle == handle)
- {
- tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
-
- /* Found the record. Now, see if the attribute already exists */
- for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
- {
- /* The attribute exists. replace it */
- if (p_attr->id == attr_id)
- {
- SDP_DeleteAttribute (handle, attr_id);
- break;
- }
- if (p_attr->id > attr_id)
- break;
- }
-
- if (p_rec->num_attributes == SDP_MAX_REC_ATTR)
- return (FALSE);
-
- /* If not found, see if we can allocate a new entry */
- if (xx == p_rec->num_attributes)
- p_attr = &p_rec->attribute[p_rec->num_attributes];
- else
- {
- /* Since the attributes are kept in sorted order, insert ours here */
- for (yy = p_rec->num_attributes; yy > xx; yy--)
- p_rec->attribute[yy] = p_rec->attribute[yy - 1];
- }
-
- p_attr->id = attr_id;
- p_attr->type = attr_type;
- p_attr->len = attr_len;
-
- if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN)
- {
- /* do truncate only for text string type descriptor */
- if (attr_type == TEXT_STR_DESC_TYPE)
- {
- SDP_TRACE_WARNING("SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
- attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr );
-
- attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
- p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
- p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr+1] = '\0';
- }
- else
- attr_len = 0;
- }
-
- if ((attr_len > 0) && (p_val != 0))
- {
- p_attr->len = attr_len;
- memcpy (&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
- p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
- p_rec->free_pad_ptr += attr_len;
- }
- else if ((attr_len == 0 && p_attr->len != 0) || /* if truncate to 0 length, simply don't add */
- p_val == 0)
- {
- SDP_TRACE_ERROR("SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
- attr_id, attr_len );
- p_attr->id = p_attr->type = p_attr->len = 0;
- return (FALSE);
- }
- p_rec->num_attributes++;
- return (TRUE);
- }
+ return SDP_AddAttributetoRecord (p_rec, attr_id, attr_type, attr_len, p_val);
}
#endif
return (FALSE);
}
+BOOLEAN SDP_AddAttributetoRecord (tSDP_RECORD *p_rec, UINT16 attr_id, UINT8 attr_type,
+ UINT32 attr_len, UINT8 *p_val)
+{
+ UINT16 xx, yy;
+ tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
+ /* Found the record. Now, see if the attribute already exists */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+ {
+ /* The attribute exists. replace it */
+ if (p_attr->id == attr_id)
+ {
+ SDP_DeleteAttributefromRecord (p_rec, attr_id);
+ break;
+ }
+ if (p_attr->id > attr_id)
+ break;
+ }
+
+ if (p_rec->num_attributes == SDP_MAX_REC_ATTR)
+ return (FALSE);
+
+ /* If not found, see if we can allocate a new entry */
+ if (xx == p_rec->num_attributes)
+ p_attr = &p_rec->attribute[p_rec->num_attributes];
+ else
+ {
+ /* Since the attributes are kept in sorted order, insert ours here */
+ for (yy = p_rec->num_attributes; yy > xx; yy--)
+ p_rec->attribute[yy] = p_rec->attribute[yy - 1];
+ }
+
+ p_attr->id = attr_id;
+ p_attr->type = attr_type;
+ p_attr->len = attr_len;
+
+ if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN)
+ {
+ /* do truncate only for text string type descriptor */
+ if (attr_type == TEXT_STR_DESC_TYPE)
+ {
+ SDP_TRACE_WARNING("SDP_AddAttributetoRecord: attr_len:%d too long. truncate to (%d)",
+ attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr );
+
+ attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
+ p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
+ p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr+1] = '\0';
+ }
+ else
+ attr_len = 0;
+ }
+
+ if ((attr_len > 0) && (p_val != 0))
+ {
+ p_attr->len = attr_len;
+ memcpy (&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
+ p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
+ p_rec->free_pad_ptr += attr_len;
+ }
+ else if ((attr_len == 0 && p_attr->len != 0) || /* if truncate to 0 length, simply don't add */
+ p_val == 0)
+ {
+ SDP_TRACE_ERROR("SDP_AddAttributetoRecord fail, length exceed maximum: ID %d: attr_len:%d ",
+ attr_id, attr_len );
+ p_attr->id = p_attr->type = p_attr->len = 0;
+ return (FALSE);
+ }
+ p_rec->num_attributes++;
+ return (TRUE);
+}
/*******************************************************************************
**
@@ -759,6 +764,36 @@
#endif
}
+BOOLEAN SDP_AddProfileDescriptorListtoRecord (tSDP_RECORD *prec, UINT16 profile_uuid,
+ UINT16 version)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ UINT8 *p;
+ BOOLEAN result;
+ UINT8 *p_buff = (UINT8 *)osi_malloc(sizeof(UINT8) * SDP_MAX_ATTR_LEN);
+
+ p = p_buff + 2;
+
+ /* First, build the profile descriptor list. This consists of a data element sequence. */
+ /* The sequence consists of profile's UUID and version number */
+ UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, profile_uuid);
+
+ UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM (p, version);
+
+ /* Add in type and length fields */
+ *p_buff = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ *(p_buff+1) = (UINT8) (p - (p_buff+2));
+
+ result = SDP_AddAttributetoRecord (prec, ATTR_ID_BT_PROFILE_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (FALSE);
+#endif
+}
/*******************************************************************************
**
@@ -855,56 +890,17 @@
BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id)
{
#if SDP_SERVER_ENABLED == TRUE
- UINT16 xx, yy;
+ UINT16 xx;
tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
- UINT8 *pad_ptr;
- UINT32 len; /* Number of bytes in the entry */
/* Find the record in the database */
for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
{
if (p_rec->record_handle == handle)
{
- tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
-
SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
- /* Found it. Now, find the attribute */
- for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
- {
- if (p_attr->id == attr_id)
- {
- pad_ptr = p_attr->value_ptr;
- len = p_attr->len;
-
- if (len)
- {
- for (yy = 0; yy < p_rec->num_attributes; yy++)
- {
- if( p_rec->attribute[yy].value_ptr > pad_ptr )
- p_rec->attribute[yy].value_ptr -= len;
- }
- }
-
- /* Found it. Shift everything up one */
- p_rec->num_attributes--;
-
- for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++)
- {
- *p_attr = *(p_attr + 1);
- }
-
- /* adjust attribute values if needed */
- if (len)
- {
- xx = (p_rec->free_pad_ptr - ((pad_ptr+len) -
- &p_rec->attr_pad[0]));
- for( yy=0; yy<xx; yy++, pad_ptr++)
- *pad_ptr = *(pad_ptr+len);
- p_rec->free_pad_ptr -= len;
- }
- return (TRUE);
- }
- }
+ if (SDP_DeleteAttributefromRecord (p_rec, attr_id))
+ return (TRUE);
}
}
#endif
@@ -912,6 +908,60 @@
return (FALSE);
}
+BOOLEAN SDP_DeleteAttributefromRecord (tSDP_RECORD *p_rec, UINT16 attr_id)
+{
+ UINT16 xx, yy;
+ tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
+ UINT8 *pad_ptr;
+ UINT32 len; /* Number of bytes in the entry */
+
+ /* Found it. Now, find the attribute */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+ {
+ if (p_attr->id == attr_id)
+ {
+ pad_ptr = p_attr->value_ptr;
+ len = p_attr->len;
+ if (p_rec->free_pad_ptr + p_attr->len >= SDP_MAX_PAD_LEN)
+ {
+ SDP_TRACE_ERROR("Deleting attr_id 0x%04x len %d exceeds 600", attr_id, len);
+ if (p_attr->type == TEXT_STR_DESC_TYPE)
+ len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
+ else
+ len = 0;
+ }
+ if (len)
+ {
+ for (yy = 0; yy < p_rec->num_attributes; yy++)
+ {
+ if( p_rec->attribute[yy].value_ptr > pad_ptr )
+ p_rec->attribute[yy].value_ptr -= len;
+ }
+ }
+
+ /* Found it. Shift everything up one */
+ p_rec->num_attributes--;
+
+ for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++)
+ {
+ *p_attr = *(p_attr + 1);
+ }
+
+ /* adjust attribute values if needed */
+ if (len)
+ {
+ xx = (p_rec->free_pad_ptr - ((pad_ptr+len) -
+ &p_rec->attr_pad[0]));
+ for( yy=0; yy<xx; yy++, pad_ptr++)
+ *pad_ptr = *(pad_ptr+len);
+ p_rec->free_pad_ptr -= len;
+ }
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
/*******************************************************************************
**
** Function SDP_ReadRecord
diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
index d2bbc58..9560400 100644
--- a/stack/sdp/sdp_discovery.c
+++ b/stack/sdp/sdp_discovery.c
@@ -98,11 +98,15 @@
UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
UINT32_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid32);
}
- else
+ else if (p_uuid_list->len == 16)
{
UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
ARRAY_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid128, p_uuid_list->len);
}
+ else
+ {
+ SDP_TRACE_ERROR("SDP: Passed Uuid is of Invalid length: %x",p_uuid_list->len);
+ }
}
/* Now, put in the length */
@@ -371,13 +375,14 @@
UINT8 type;
#if (SDP_DEBUG_RAW == TRUE)
- UINT8 num_array[SDP_MAX_LIST_BYTE_COUNT];
+ UINT8 num_array[2 * SDP_MAX_LIST_BYTE_COUNT + 1]; // Need double the space to store hex data
UINT32 i;
for (i = 0; i < p_ccb->list_len; i++)
{
sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_ccb->rsp_list[i]));
}
+ (char)num_array[2*i] = '\0';
SDP_TRACE_WARNING("result :%s",num_array);
#endif
@@ -408,8 +413,9 @@
{
cpy_len = list_len;
}
- rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int)(p - &p_ccb->rsp_list[0]);
- if (cpy_len > rem_len) {
+ rem_len = SDP_MAX_LIST_BYTE_COUNT - (unsigned int) (p - &p_ccb->rsp_list[0]);
+ if (cpy_len > rem_len)
+ {
SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
cpy_len = rem_len;
}
diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c
index a5aac8e..e295167 100644
--- a/stack/sdp/sdp_server.c
+++ b/stack/sdp/sdp_server.c
@@ -32,15 +32,22 @@
#include "bt_common.h"
#include "bt_types.h"
#include "bt_utils.h"
+#include "bt_trace.h"
#include "btu.h"
#include "l2cdefs.h"
#include "hcidefs.h"
#include "hcimsgs.h"
+#include "avrc_defs.h"
#include "sdp_api.h"
#include "sdpint.h"
-
+#include "device/include/interop.h"
+#include "btif/include/btif_storage.h"
+#include "device/include/interop_config.h"
+#include <errno.h>
+#include <cutils/properties.h>
+#include <hardware/bluetooth.h>
#if SDP_SERVER_ENABLED == TRUE
@@ -50,6 +57,13 @@
#define SDP_MAX_SERVICE_RSPHDR_LEN 12
#define SDP_MAX_SERVATTR_RSPHDR_LEN 10
#define SDP_MAX_ATTR_RSPHDR_LEN 10
+#define PROFILE_VERSION_POSITION 7
+#define SDP_PROFILE_DESC_LENGTH 8
+#define AVRCP_SUPPORTED_FEATURES_POSITION 1
+#define AVRCP_BROWSE_SUPPORT_BITMASK 0x40
+#define AVRCP_CA_SUPPORT_BITMASK 0x01
+#define PBAP_SKIP_GOEP_L2CAP_PSM_LEN 0x06
+#define PBAP_SKIP_SUPP_FEA_LEN 0x08
/********************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
@@ -66,6 +80,10 @@
UINT16 param_len, UINT8 *p_req,
UINT8 *p_req_end);
+static BOOLEAN is_pbap_record_blacklisted (tSDP_ATTRIBUTE attr, BD_ADDR remote_address);
+
+static tSDP_RECORD *sdp_update_pbap_record_if_blacklisted(tSDP_RECORD *p_rec,
+ BD_ADDR remote_address);
/********************************************************************************/
/* E R R O R T E X T S T R I N G S */
@@ -105,6 +123,259 @@
#define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
#endif
+#ifndef SDP_TEXT_BAD_MAX_ATTR_LIST
+#define SDP_TEXT_BAD_MAX_ATTR_LIST NULL
+#endif
+
+struct blacklist_entry
+{
+ int ver;
+ char addr[3];
+};
+
+int sdp_get_stored_avrc_tg_version(BD_ADDR addr)
+{
+ int stored_ver = AVRC_REV_INVALID;
+ struct blacklist_entry data;
+ FILE *fp;
+
+ SDP_TRACE_DEBUG("%s target BD Addr: %x:%x:%x", __func__,\
+ addr[0], addr[1], addr[2]);
+
+ fp = fopen(AVRC_PEER_VERSION_CONF_FILE, "rb");
+ if (!fp)
+ {
+ SDP_TRACE_ERROR("%s unable to open AVRC Conf file for read: err: (%s)",\
+ __func__, strerror(errno));
+ return stored_ver;
+ }
+ while (fread(&data, sizeof(data), 1, fp) != 0)
+ {
+ SDP_TRACE_DEBUG("Entry: addr = %x:%x:%x, ver = 0x%x",\
+ data.addr[0], data.addr[1], data.addr[2], data.ver);
+ if(!memcmp(addr, data.addr, 3))
+ {
+ stored_ver = data.ver;
+ SDP_TRACE_DEBUG("Entry found with version: 0x%x", stored_ver);
+ break;
+ }
+ }
+ fclose(fp);
+ return stored_ver;
+}
+
+/****************************************************************************
+**
+** Function sdp_dev_blacklisted_for_avrcp15
+**
+** Description This function is called to check if Remote device
+** is blacklisted for Avrcp version.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN sdp_dev_blacklisted_for_avrcp15 (BD_ADDR addr)
+{
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, addr);
+
+ if (interop_match_addr(INTEROP_ADV_AVRCP_VER_1_3, &remote_bdaddr)) {
+ bt_property_t prop_name;
+ bt_bdname_t bdname;
+
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(&remote_bdaddr,
+ &prop_name) != BT_STATUS_SUCCESS)
+ {
+ SDP_TRACE_ERROR("%s: BT_PROPERTY_BDNAME failed, returning false", __func__);
+ return FALSE;
+ }
+
+ if (strlen((const char *)bdname.name) != 0 &&
+ interop_match_name(INTEROP_ADV_AVRCP_VER_1_3, (const char *)bdname.name))
+ {
+ SDP_TRACE_DEBUG("%s: advertise AVRCP version 1.3 for device", __func__);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_fallback_avrcp_version
+**
+** Description Checks if UUID is AV Remote Control, attribute id
+** is Profile descriptor list and remote BD address
+** matches device blacklist, change Avrcp version to 1.3
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+BOOLEAN sdp_fallback_avrcp_version (tSDP_ATTRIBUTE *p_attr, BD_ADDR remote_address)
+{
+ char a2dp_role[PROPERTY_VALUE_MAX] = "false";
+ if ((p_attr->id == ATTR_ID_BT_PROFILE_DESC_LIST) &&
+ (p_attr->len >= SDP_PROFILE_DESC_LENGTH))
+ {
+ /* As per current DB implementation UUID is condidered as 16 bit */
+ if (((p_attr->value_ptr[3] << 8) | (p_attr->value_ptr[4])) ==
+ UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ {
+ int ver;
+ if (sdp_dev_blacklisted_for_avrcp15 (remote_address))
+ {
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x03; // Update AVRCP version as 1.3
+ SDP_TRACE_ERROR("SDP Change AVRCP Version = 0x%x",
+ p_attr->value_ptr[PROFILE_VERSION_POSITION]);
+ return TRUE;
+ }
+ property_get("persist.service.bt.a2dp.sink", a2dp_role, "false");
+ if (!strncmp("false", a2dp_role, 5)) {
+ ver = sdp_get_stored_avrc_tg_version (remote_address);
+ if (ver != AVRC_REV_INVALID)
+ {
+ SDP_TRACE_DEBUG("Stored AVRC TG version: 0x%x", ver);
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = (UINT8)(ver & 0x00ff);
+ SDP_TRACE_DEBUG("SDP Change AVRCP Version = 0x%x",
+ p_attr->value_ptr[PROFILE_VERSION_POSITION]);
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ if (ver != AVRC_REV_1_6)
+#else
+#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
+ if (ver != AVRC_REV_1_5)
+#endif
+#endif
+ return TRUE;
+ else
+ return FALSE;
+ }
+ else
+ {
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x03; // Update AVRCP ver as 1.3
+ SDP_TRACE_DEBUG("Device not stored, Change AVRCP Version = 0x%x",
+ p_attr->value_ptr[PROFILE_VERSION_POSITION]);
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_reset_avrcp_browsing_bit
+**
+** Description Checks if Service Class ID is AV Remote Control TG, attribute id
+** is Supported features and remote BD address
+** matches device blacklist, reset Browsing Bit
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+BOOLEAN sdp_reset_avrcp_browsing_bit (tSDP_ATTRIBUTE attr, tSDP_ATTRIBUTE *p_attr,
+BD_ADDR remote_address)
+{
+ if ((p_attr->id == ATTR_ID_SUPPORTED_FEATURES) && (attr.id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (((attr.value_ptr[1] << 8) | (attr.value_ptr[2])) == UUID_SERVCLASS_AV_REM_CTRL_TARGET))
+ {
+ int ver;
+ if (sdp_dev_blacklisted_for_avrcp15 (remote_address))
+ {
+ SDP_TRACE_ERROR("Reset Browse feature bitmask");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION] &= ~AVRCP_BROWSE_SUPPORT_BITMASK;
+ return TRUE;
+ }
+ ver = sdp_get_stored_avrc_tg_version (remote_address);
+ SDP_TRACE_ERROR("Stored AVRC TG version: 0x%x", ver);
+ if ((ver < AVRC_REV_1_4) || (ver == AVRC_REV_INVALID))
+ {
+ SDP_TRACE_ERROR("Reset Browse feature bitmask");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION] &= ~AVRCP_BROWSE_SUPPORT_BITMASK;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_change_hfp_version
+**
+** Description Checks if UUID is AG_HANDSFREE, attribute id
+** is Profile descriptor list and remote BD address
+** matches device blacklist, change hfp version to 1.7
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+BOOLEAN sdp_change_hfp_version (tSDP_ATTRIBUTE *p_attr, BD_ADDR remote_address)
+{
+ bool is_blacklisted = FALSE;
+ char value[PROPERTY_VALUE_MAX];
+ if ((p_attr->id == ATTR_ID_BT_PROFILE_DESC_LIST) &&
+ (p_attr->len >= SDP_PROFILE_DESC_LENGTH))
+ {
+ /* As per current DB implementation UUID is condidered as 16 bit */
+ if (((p_attr->value_ptr[3] << 8) | (p_attr->value_ptr[4])) ==
+ UUID_SERVCLASS_HF_HANDSFREE)
+ {
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, remote_address);
+ is_blacklisted = interop_database_match_addr(INTEROP_HFP_1_7_BLACKLIST, (bt_bdaddr_t *)&remote_bdaddr);
+ SDP_TRACE_DEBUG("%s: HF version is 1.7 for BD addr: %x:%x:%x",\
+ __func__, remote_address[0], remote_address[1], remote_address[2]);
+ /* For PTS we should show AG's HFP version as 1.7 */
+ if (is_blacklisted ||
+ (property_get("bt.pts.certification", value, "false") &&
+ strcmp(value, "true") == 0))
+ {
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x07; // Update HFP version as 1.7
+ SDP_TRACE_ERROR("SDP Change HFP Version = 0x%x",
+ p_attr->value_ptr[PROFILE_VERSION_POSITION]);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_reset_avrcp_cover_art_bit
+**
+** Description Checks if Service Class ID is AV Remote Control TG, attribute id
+** is Supported features and remote BD address
+** matches device blacklist, reset Cover Art Bit
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+
+BOOLEAN sdp_reset_avrcp_cover_art_bit (tSDP_ATTRIBUTE attr, tSDP_ATTRIBUTE *p_attr,
+ BD_ADDR remote_address)
+{
+ if ((p_attr->id == ATTR_ID_SUPPORTED_FEATURES) && (attr.id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (((attr.value_ptr[1] << 8) | (attr.value_ptr[2])) == UUID_SERVCLASS_AV_REM_CTRL_TARGET))
+ {
+ int ver;
+ ver = sdp_get_stored_avrc_tg_version (remote_address);
+ SDP_TRACE_ERROR("Stored AVRC TG version: 0x%x", ver);
+ if ((ver < AVRC_REV_1_6) || (ver == AVRC_REV_INVALID))
+ {
+ SDP_TRACE_ERROR("Reset Cover Art feature bitmask +1, 0x%x", p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION+1]);
+ SDP_TRACE_ERROR("Reset Cover Art feature bitmask -1, 0x%x", p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION-1]);
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION-1] &= ~AVRCP_CA_SUPPORT_BITMASK;
+ SDP_TRACE_ERROR("Reset Cover Art feature bitmask, new -1, 0x%x", p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION-1]);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/*******************************************************************************
**
** Function sdp_server_handle_client_req
@@ -217,6 +488,12 @@
}
BE_STREAM_TO_UINT16 (max_replies, p_req);
+ if (!max_replies)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_ATTR_LIST);
+ return;
+ }
+
if (max_replies > SDP_MAX_RECORDS)
max_replies = SDP_MAX_RECORDS;
@@ -252,10 +529,20 @@
return;
}
+ if (p_req != p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
}
else
{
+ if (p_req+1 != p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
rem_handles = num_rsp_handles;
cont_offset = 0;
p_ccb->cont_offset = 0;
@@ -340,6 +627,10 @@
tSDP_RECORD *p_rec;
tSDP_ATTRIBUTE *p_attr;
BOOLEAN is_cont = FALSE;
+ BOOLEAN is_avrcp_fallback = FALSE;
+ BOOLEAN is_avrcp_browse_bit_reset = FALSE;
+ BOOLEAN is_hfp_fallback = FALSE;
+ BOOLEAN is_avrcp_ca_bit_reset = FALSE;
UINT16 attr_len;
if (p_req + sizeof(rec_handle) + sizeof(max_list_len) > p_req_end) {
@@ -357,6 +648,12 @@
BE_STREAM_TO_UINT16 (max_list_len, p_req);
param_len -= sizeof(max_list_len);
+ if (!max_list_len)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_ATTR_LIST);
+ return;
+ }
+
if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
@@ -385,6 +682,8 @@
return;
}
+ p_rec = sdp_update_pbap_record_if_blacklisted(p_rec, p_ccb->device_address);
+
/* Free and reallocate buffer */
osi_free(p_ccb->rsp_list);
p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
@@ -404,6 +703,11 @@
SDP_TEXT_BAD_CONT_INX);
return;
}
+ if (p_req != p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
is_cont = TRUE;
/* Initialise for continuation response */
@@ -411,11 +715,18 @@
attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
p_ccb->cont_info.next_attr_start_id;
} else {
+ if (p_req+1 != p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
+
p_ccb->cont_offset = 0;
p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
/* Reset continuation parameters in p_ccb */
p_ccb->cont_info.prev_sdp_rec = NULL;
+ p_ccb->cont_info.curr_sdp_rec = NULL;
p_ccb->cont_info.next_attr_index = 0;
p_ccb->cont_info.attr_offset = 0;
}
@@ -427,6 +738,20 @@
if (p_attr)
{
+#if ((defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE)) || \
+ (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE)))
+ /* Check for UUID Remote Control and Remote BD address */
+ is_avrcp_fallback = sdp_fallback_avrcp_version (p_attr, p_ccb->device_address);
+#if (defined(AVCT_BROWSE_INCLUDED)&&(AVCT_BROWSE_INCLUDED == TRUE))
+ is_avrcp_browse_bit_reset = sdp_reset_avrcp_browsing_bit(
+ p_rec->attribute[1], p_attr, p_ccb->device_address);
+#endif
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ is_avrcp_ca_bit_reset = sdp_reset_avrcp_cover_art_bit(
+ p_rec->attribute[1], p_attr, p_ccb->device_address);
+#endif
+#endif
+ is_hfp_fallback = sdp_change_hfp_version (p_attr, p_ccb->device_address);
/* Check if attribute fits. Assume 3-byte value type/length */
rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
@@ -487,8 +812,80 @@
xx--;
}
+ if (is_avrcp_fallback)
+ {
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ /* Update AVRCP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+#else
+#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x05;
+#endif
+#endif
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
+ if (is_hfp_fallback)
+ {
+ SDP_TRACE_ERROR("Restore HFP version to 1.6");
+ /* Update HFP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+ is_hfp_fallback = FALSE;
+ }
+ if (is_avrcp_ca_bit_reset)
+ {
+ /* Restore Cover Art bit */
+ SDP_TRACE_ERROR("Restore Cover Art bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION - 1]
+ |= AVRCP_CA_SUPPORT_BITMASK;
+ is_avrcp_ca_bit_reset = FALSE;
+ }
}
}
+ if (is_avrcp_fallback)
+ {
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ /* Update AVRCP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+#else
+#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x05;
+#endif
+#endif
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
+ if (is_hfp_fallback)
+ {
+ SDP_TRACE_ERROR("Restore HFP version to 1.6");
+ /* Update HFP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+ is_hfp_fallback = FALSE;
+ }
+ if (is_avrcp_ca_bit_reset)
+ {
+ /* Restore Cover Art bit */
+ SDP_TRACE_ERROR("Restore Cover Art bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION - 1]
+ |= AVRCP_CA_SUPPORT_BITMASK;
+ is_avrcp_ca_bit_reset = FALSE;
+ }
/* If all the attributes have been accomodated in p_rsp,
reset next_attr_index */
if (xx == attr_seq.num_attr)
@@ -586,11 +983,18 @@
UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
UINT16 rsp_param_len, xx;
tSDP_RECORD *p_rec;
+ tSDP_RECORD *p_prev_rec;
tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
tSDP_ATTRIBUTE *p_attr;
+ BT_HDR *p_buf;
BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
- UINT8 *p_seq_start;
+ BOOLEAN is_avrcp_fallback = FALSE;
+ BOOLEAN is_avrcp_browse_bit_reset = FALSE;
+ BOOLEAN is_hfp_fallback = FALSE;
+ BOOLEAN is_avrcp_ca_bit_reset = FALSE;
+ UINT8 *p_seq_start = NULL;
UINT16 seq_len, attr_len;
+ UINT16 blacklist_skip_len = 0;
UNUSED(p_req_end);
/* Extract the UUID sequence to search for */
@@ -605,6 +1009,12 @@
/* Get the max list length we can send. Cap it at our max list length. */
BE_STREAM_TO_UINT16 (max_list_len, p_req);
+ if (!max_list_len)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_ATTR_LIST);
+ return;
+ }
+
if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
@@ -644,6 +1054,11 @@
SDP_TEXT_BAD_CONT_INX);
return;
}
+ if (p_req != p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
is_cont = TRUE;
/* Initialise for continuation response */
@@ -651,11 +1066,18 @@
attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
p_ccb->cont_info.next_attr_start_id;
} else {
+ if (p_req+1 != p_req_end)
+ {
+ sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+ return;
+ }
+
p_ccb->cont_offset = 0;
p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
/* Reset continuation parameters in p_ccb */
p_ccb->cont_info.prev_sdp_rec = NULL;
+ p_ccb->cont_info.curr_sdp_rec = NULL;
p_ccb->cont_info.next_attr_index = 0;
p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
p_ccb->cont_info.attr_offset = 0;
@@ -664,6 +1086,35 @@
/* Get a list of handles that match the UUIDs given to us */
for (p_rec = sdp_db_service_search (p_ccb->cont_info.prev_sdp_rec, &uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, &uid_seq))
{
+ p_ccb->cont_info.curr_sdp_rec = p_rec;
+ /* Store the actual record pointer which would be reused later */
+ p_prev_rec = p_rec;
+ p_rec = sdp_update_pbap_record_if_blacklisted(p_rec, p_ccb->device_address);
+ if (p_rec != p_prev_rec) {
+ /* Remote device is blacklisted for PBAP, calculate the reduction in length */
+ for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq_sav.num_attr; xx++) {
+ if (attr_seq_sav.attr_entry[xx].start == attr_seq_sav.attr_entry[xx].end) {
+ if (attr_seq_sav.attr_entry[xx].start == ATTR_ID_GOEP_L2CAP_PSM) {
+ blacklist_skip_len += PBAP_SKIP_GOEP_L2CAP_PSM_LEN;
+ SDP_TRACE_ERROR("%s: ATTR_ID_GOEP_L2CAP_PSM requested,"
+ " need to reduce length by %d", __func__,
+ blacklist_skip_len);
+ } else if (attr_seq_sav.attr_entry[xx].start ==
+ ATTR_ID_PBAP_SUPPORTED_FEATURES) {
+ blacklist_skip_len += PBAP_SKIP_SUPP_FEA_LEN;
+ SDP_TRACE_DEBUG("%s: ATTR_ID_PBAP_SUPPORTED_FEATURES requested,"
+ " need to reduce length by %d", __func__,
+ blacklist_skip_len);
+ }
+ } else {
+ blacklist_skip_len = PBAP_SKIP_GOEP_L2CAP_PSM_LEN +
+ PBAP_SKIP_SUPP_FEA_LEN;
+ SDP_TRACE_DEBUG("%s: All attributes requested"
+ " need to reduce length by %d", __func__,
+ blacklist_skip_len);
+ }
+ }
+ }
/* Allow space for attribute sequence type and length */
p_seq_start = p_rsp;
if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
@@ -687,6 +1138,20 @@
if (p_attr)
{
+#if ((defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE)) || \
+ (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE)))
+ /* Check for UUID Remote Control and Remote BD address */
+ is_avrcp_fallback = sdp_fallback_avrcp_version (p_attr, p_ccb->device_address);
+#if (defined(AVCT_BROWSE_INCLUDED)&&(AVCT_BROWSE_INCLUDED == TRUE))
+ is_avrcp_browse_bit_reset = sdp_reset_avrcp_browsing_bit(
+ p_rec->attribute[1], p_attr, p_ccb->device_address);
+#endif
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ is_avrcp_ca_bit_reset = sdp_reset_avrcp_cover_art_bit(
+ p_rec->attribute[1], p_attr, p_ccb->device_address);
+#endif
+#endif
+ is_hfp_fallback = sdp_change_hfp_version (p_attr, p_ccb->device_address);
/* Check if attribute fits. Assume 3-byte value type/length */
rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
@@ -752,8 +1217,80 @@
xx--;
}
+ if (is_avrcp_fallback)
+ {
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ /* Update AVRCP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+#else
+#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x05;
+#endif
+#endif
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
+ if (is_hfp_fallback)
+ {
+ SDP_TRACE_ERROR("Restore HFP version to 1.6");
+ /* Update HFP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+ is_hfp_fallback = FALSE;
+ }
+ if (is_avrcp_ca_bit_reset)
+ {
+ /* Restore Cover Art bit */
+ SDP_TRACE_ERROR("Restore Cover Art bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION - 1]
+ |= AVRCP_CA_SUPPORT_BITMASK;
+ is_avrcp_ca_bit_reset = FALSE;
+ }
}
}
+ if (is_avrcp_fallback)
+ {
+#if (defined(SDP_AVRCP_1_6) && (SDP_AVRCP_1_6 == TRUE))
+ /* Update AVRCP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+#else
+#if (defined(SDP_AVRCP_1_5) && (SDP_AVRCP_1_5 == TRUE))
+ /* Update AVRCP version back to 1.5 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x05;
+#endif
+#endif
+ is_avrcp_fallback = FALSE;
+ }
+ if (is_avrcp_browse_bit_reset)
+ {
+ /* Restore Browsing bit */
+ SDP_TRACE_ERROR("Restore Browsing bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION]
+ |= AVRCP_BROWSE_SUPPORT_BITMASK;
+ is_avrcp_browse_bit_reset = FALSE;
+ }
+ if (is_hfp_fallback)
+ {
+ SDP_TRACE_ERROR("Restore HFP version to 1.6");
+ /* Update HFP version back to 1.6 */
+ p_attr->value_ptr[PROFILE_VERSION_POSITION] = 0x06;
+ is_hfp_fallback = FALSE;
+ }
+ if (is_avrcp_ca_bit_reset)
+ {
+ /* Restore Cover Art bit */
+ SDP_TRACE_ERROR("Restore Cover Art bit");
+ p_attr->value_ptr[AVRCP_SUPPORTED_FEATURES_POSITION - 1]
+ |= AVRCP_CA_SUPPORT_BITMASK;
+ is_avrcp_ca_bit_reset = FALSE;
+ }
/* Go back and put the type and length into the buffer */
if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
@@ -761,8 +1298,15 @@
seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
if (seq_len != 0)
{
- UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
- UINT16_TO_BE_STREAM (p_seq_start, seq_len);
+ if (p_seq_start)
+ {
+ UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM (p_seq_start, seq_len);
+ }
+ else
+ {
+ SDP_TRACE_DEBUG("SDP service and attribute rsp: Attribute sequence p_seq_start is NULL");
+ }
if (maxxed_out)
p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
@@ -779,6 +1323,8 @@
/* Reset the next attr index */
p_ccb->cont_info.next_attr_index = 0;
+ /* restore the record pointer.*/
+ p_rec = p_prev_rec;
p_ccb->cont_info.prev_sdp_rec = p_rec;
p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
}
@@ -813,6 +1359,13 @@
{
/* Get the total list length for requested uid and attribute sequence */
p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
+ if (blacklist_skip_len &&
+ p_ccb->list_len > blacklist_skip_len) {
+ p_ccb->list_len -= blacklist_skip_len;
+ SDP_TRACE_DEBUG("%s: reducing list_len by %d for blacklisted device",
+ __func__, blacklist_skip_len);
+ blacklist_skip_len = 0;
+ }
/* Put in the sequence header (2 or 3 bytes) */
if (p_ccb->list_len > 255)
{
@@ -833,7 +1386,7 @@
}
/* Get a buffer to use to build the response */
- BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+ p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
p_buf->offset = L2CAP_MIN_OFFSET;
p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
@@ -854,6 +1407,14 @@
p_ccb->cont_offset += len_to_send;
+ if (blacklist_skip_len &&
+ p_ccb->list_len > blacklist_skip_len) {
+ p_ccb->list_len -= blacklist_skip_len;
+ SDP_TRACE_DEBUG("%s: reducing list_len by %d for blacklisted device",
+ __func__, blacklist_skip_len);
+ blacklist_skip_len = 0;
+ }
+
/* If anything left to send, continuation needed */
if (p_ccb->cont_offset < p_ccb->list_len)
{
@@ -877,4 +1438,97 @@
L2CA_DataWrite (p_ccb->connection_id, p_buf);
}
+/*************************************************************************************
+**
+** Function is_pbap_record_blacklisted
+**
+** Description Checks if given PBAP record is for PBAP PSE and blacklisted
+**
+** Returns BOOLEAN
+**
+***************************************************************************************/
+static BOOLEAN is_pbap_record_blacklisted (tSDP_ATTRIBUTE attr,
+ BD_ADDR remote_address)
+{
+ if ((attr.id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (((attr.value_ptr[1] << 8) | (attr.value_ptr[2])) ==
+ UUID_SERVCLASS_PBAP_PSE))
+ {
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, remote_address);
+
+ bt_property_t prop_name;
+ bt_bdname_t bdname;
+
+ memset(&bdname, 0, sizeof(bt_bdname_t));
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(&remote_bdaddr,
+ &prop_name) != BT_STATUS_SUCCESS) {
+ SDP_TRACE_DEBUG("%s: BT_PROPERTY_BDNAME failed", __func__);
+ }
+ if (interop_match_addr(INTEROP_ADV_PBAP_VER_1_1, &remote_bdaddr) ||
+ (strlen((const char *)bdname.name) != 0 &&
+ interop_match_name(INTEROP_ADV_PBAP_VER_1_1,
+ (const char *)bdname.name))) {
+ SDP_TRACE_DEBUG("%s: device is blacklisted for pbap version downgrade", __func__);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*************************************************************************************
+**
+** Function sdp_update_pbap_record_if_blacklisted
+**
+** Description updates pbap record after checking if blacklisted
+**
+** Returns the address of updated record
+**
+***************************************************************************************/
+static tSDP_RECORD *sdp_update_pbap_record_if_blacklisted(tSDP_RECORD *p_rec,
+ BD_ADDR remote_address)
+{
+ static tSDP_RECORD pbap_temp_sdp_rec;
+ static BOOLEAN is_blacklisted_rec_created = FALSE;
+
+ /* Check if the given SDP record is blacklisted and requires updatiion */
+ if (is_pbap_record_blacklisted(p_rec->attribute[1], remote_address)) {
+ if (is_blacklisted_rec_created)
+ return &pbap_temp_sdp_rec;
+
+ bool status = TRUE;
+ int xx;
+ UINT8 supported_repositories = 0x03;
+ UINT16 legacy_version = 0x0101;
+ memset(&pbap_temp_sdp_rec, 0, sizeof(tSDP_RECORD));
+
+ tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
+
+ /* Copying contents of the PBAP PSE record to a temporary record */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+ SDP_AddAttributetoRecord (&pbap_temp_sdp_rec, p_attr->id,
+ p_attr->type, p_attr->len, p_attr->value_ptr);
+
+ status &= SDP_DeleteAttributefromRecord (&pbap_temp_sdp_rec,
+ ATTR_ID_PBAP_SUPPORTED_FEATURES);
+ status &= SDP_DeleteAttributefromRecord (&pbap_temp_sdp_rec,
+ ATTR_ID_GOEP_L2CAP_PSM);
+ status &= SDP_AddAttributetoRecord (&pbap_temp_sdp_rec,
+ ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE, (UINT32)1,
+ (UINT8*)&supported_repositories);
+ status &= SDP_AddProfileDescriptorListtoRecord(&pbap_temp_sdp_rec,
+ UUID_SERVCLASS_PHONE_ACCESS, legacy_version);
+ if (!status) {
+ SDP_TRACE_ERROR("%s() FAILED", __func__);
+ return p_rec;
+ }
+ is_blacklisted_rec_created = TRUE;
+ return &pbap_temp_sdp_rec;
+ }
+ return p_rec;
+}
+
#endif /* SDP_SERVER_ENABLED == TRUE */
diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c
index cbfb874..c5fd811 100644
--- a/stack/sdp/sdp_utils.c
+++ b/stack/sdp/sdp_utils.c
@@ -158,6 +158,41 @@
osi_free_and_reset((void **)&p_ccb->rsp_list);
}
+/*******************************************************************************
+**
+** Function sdpu_update_ccb_cont_info
+**
+** Description This function updates CCB's continuation information in the
+** case of a record being moved up one place in DB following
+** deletion of a record above.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdpu_update_ccb_cont_info (UINT32 handle)
+{
+ UINT16 xx;
+ tCONN_CB *p_ccb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+ {
+ if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->cont_info.curr_sdp_rec) && (p_ccb->cont_info.curr_sdp_rec->record_handle == handle))
+ {
+ if (handle == sdp_cb.server_db.record[0].record_handle)
+ {
+ /* The record is moved to the top of database. Resetting the prev_sdp_rec to NULL */
+ p_ccb->cont_info.curr_sdp_rec = NULL;
+ p_ccb->cont_info.prev_sdp_rec = NULL;
+ }
+ else
+ {
+ p_ccb->cont_info.curr_sdp_rec -= 1;
+ p_ccb->cont_info.prev_sdp_rec = p_ccb->cont_info.curr_sdp_rec -1;
+ }
+ }
+ }
+}
/*******************************************************************************
**
@@ -226,6 +261,8 @@
*******************************************************************************/
UINT8 *sdpu_build_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr)
{
+ if(!p_out)
+ return p_out;
/* First, store the attribute ID. Goes as a UINT */
UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
UINT16_TO_BE_STREAM (p_out, p_attr->id);
@@ -1044,10 +1081,13 @@
}
size_t len_to_copy = ((attr_len - *offset) < len) ? (attr_len - *offset) : len;
- memcpy(p_out, &p_attr_buff[*offset], len_to_copy);
+ if(p_out)
+ {
+ memcpy(p_out, &p_attr_buff[*offset], len_to_copy);
- p_out = &p_out[len_to_copy];
- *offset += len_to_copy;
+ p_out = &p_out[len_to_copy];
+ *offset += len_to_copy;
+ }
osi_free(p_attr_buff);
return p_out;
diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h
index b0548f5..4763e79 100644
--- a/stack/sdp/sdpint.h
+++ b/stack/sdp/sdpint.h
@@ -157,6 +157,7 @@
UINT16 next_attr_index; /* attr index for next continuation response */
UINT16 next_attr_start_id; /* attr id to start with for the attr index in next cont. response */
tSDP_RECORD *prev_sdp_rec; /* last sdp record that was completely sent in the response */
+ tSDP_RECORD *curr_sdp_rec; /* sdp record that is currently being sent in the response */
BOOLEAN last_attr_seq_desc_sent; /* whether attr seq length has been sent previously */
UINT16 attr_offset; /* offset within the attr to keep trak of partial attributes in the responses */
} tSDP_CONT_INFO;
@@ -274,6 +275,7 @@
extern tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db);
extern tCONN_CB *sdpu_allocate_ccb (void);
extern void sdpu_release_ccb (tCONN_CB *p_ccb);
+extern void sdpu_update_ccb_cont_info (UINT32 handle);
extern UINT8 *sdpu_build_attrib_seq (UINT8 *p_out, UINT16 *p_attr, UINT16 num_attrs);
extern UINT8 *sdpu_build_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr);
@@ -300,6 +302,11 @@
extern tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq);
extern tSDP_RECORD *sdp_db_find_record (UINT32 handle);
extern tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, UINT16 start_attr, UINT16 end_attr);
+extern BOOLEAN SDP_AddAttributetoRecord (tSDP_RECORD *p_rec, UINT16 attr_id, UINT8 attr_type,
+ UINT32 attr_len, UINT8 *p_val);
+extern BOOLEAN SDP_AddProfileDescriptorListtoRecord (tSDP_RECORD *p_rec, UINT16 profile_uuid,
+ UINT16 version);
+extern BOOLEAN SDP_DeleteAttributefromRecord (tSDP_RECORD *p_rec, UINT16 attr_id);
/* Functions provided by sdp_server.c
@@ -310,6 +317,10 @@
#define sdp_server_handle_client_req(p_ccb, p_msg)
#endif
+extern BOOLEAN sdp_dev_blacklisted_for_avrcp15 (BD_ADDR addr);
+extern int sdp_get_stored_avrc_tg_version(BD_ADDR addr);
+
+
/* Functions provided by sdp_discovery.c
*/
#if SDP_CLIENT_ENABLED == TRUE
diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
index a986cbd..00ae046 100644
--- a/stack/smp/smp_act.c
+++ b/stack/smp/smp_act.c
@@ -193,6 +193,8 @@
if (callback_rc == SMP_SUCCESS)
{
+ bt_bdaddr_t remote_bdaddr;
+ bdcpy(remote_bdaddr.address, p_cb->pairing_bda);
switch (p_cb->cb_evt)
{
case SMP_IO_CAP_REQ_EVT:
@@ -227,7 +229,7 @@
if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)
|| lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2)
|| interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
- (const bt_bdaddr_t *)&p_cb->pairing_bda))
+ (const bt_bdaddr_t *)&remote_bdaddr))
{
p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT;
p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
@@ -244,13 +246,15 @@
p_cb->loc_enc_size = cb_data.io_req.max_key_size;
p_cb->local_i_key = cb_data.io_req.init_keys;
p_cb->local_r_key = cb_data.io_req.resp_keys;
+ p_cb->loc_auth_req |= SMP_H7_SUPPORT_BIT;
p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
SMP_TRACE_WARNING ( "for SMP over BR max_key_size: 0x%02x,\
- local_i_key: 0x%02x, local_r_key: 0x%02x",
- p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key);
+ local_i_key: 0x%02x, local_r_key: 0x%02x, auth_req = %d",
+ p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key, p_cb->loc_auth_req);
+
smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL);
break;
@@ -956,6 +960,13 @@
p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
}
+ /* Check if H7 function needs to be used for key derivation*/
+ if ((p_cb->loc_auth_req & SMP_H7_SUPPORT_BIT) && (p_cb->peer_auth_req & SMP_H7_SUPPORT_BIT))
+ {
+ p_cb->key_derivation_h7_used = TRUE;
+ }
+ SMP_TRACE_DEBUG("%s use h7 = %d", __func__, p_cb->key_derivation_h7_used);
+
SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
"(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key,
p_cb->local_r_key);
diff --git a/stack/smp/smp_cmac.c b/stack/smp/smp_cmac.c
index b164669..1989292 100644
--- a/stack/smp/smp_cmac.c
+++ b/stack/smp/smp_cmac.c
@@ -134,7 +134,7 @@
tSMP_ENC output;
UINT8 i = 1, err = 0;
UINT8 x[16] = {0};
- UINT8 *p_mac;
+ UINT8 *p_mac = NULL;
SMP_TRACE_EVENT ("cmac_aes_k_calculate ");
@@ -154,6 +154,8 @@
if (!err)
{
+ if (tlen > BT_OCTET16_LEN)
+ tlen = BT_OCTET16_LEN;
p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
memcpy(p_signature, p_mac, tlen);
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
index aea8538..f11fe49 100644
--- a/stack/smp/smp_int.h
+++ b/stack/smp/smp_int.h
@@ -312,6 +312,7 @@
/* either in Secure Connections mode or not at all */
tSMP_ASSO_MODEL selected_association_model;
BOOLEAN le_secure_connections_mode_is_used;
+ BOOLEAN key_derivation_h7_used;
BOOLEAN le_sc_kp_notif_is_used;
tSMP_SC_KEY_TYPE local_keypress_notification;
tSMP_SC_KEY_TYPE peer_keypress_notification;
@@ -532,6 +533,7 @@
extern BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap,
UINT8 *a1, UINT8 *a2, UINT8 *f3);
extern BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *h2);
+extern BOOLEAN smp_calculate_h7(UINT8 *salt, UINT8 *w, UINT8 *h2);
#if SMP_DEBUG == TRUE
extern void smp_debug_print_nbyte_little_endian (UINT8 *p, const UINT8 *key_name,
UINT8 len);
diff --git a/stack/smp/smp_keys.c b/stack/smp/smp_keys.c
index a985f97..6860f95 100644
--- a/stack/smp/smp_keys.c
+++ b/stack/smp/smp_keys.c
@@ -1909,6 +1909,11 @@
tBTM_SEC_DEV_REC *p_dev_rec;
BD_ADDR bda_for_lk;
tBLE_ADDR_TYPE conn_addr_type;
+ BT_OCTET16 salt = {
+ 0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
SMP_TRACE_DEBUG ("%s", __func__);
@@ -1937,7 +1942,11 @@
BT_OCTET16 intermediate_link_key;
BOOLEAN ret = TRUE;
- ret = smp_calculate_h6(p_cb->ltk, (UINT8 *)"1pmt" /* reversed "tmp1" */,intermediate_link_key);
+ if (p_cb->key_derivation_h7_used)
+ ret = smp_calculate_h7((UINT8*)salt, p_cb->ltk, intermediate_link_key);
+ else
+ ret = smp_calculate_h6(p_cb->ltk, (UINT8 *)"1pmt" /* reversed "tmp1" */,intermediate_link_key);
+
if (!ret)
{
SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__);
@@ -2011,6 +2020,10 @@
BOOLEAN ret = TRUE;
tBTM_SEC_DEV_REC *p_dev_rec;
UINT8 rev_link_key[16];
+ BT_OCTET16 salt = {
+ 0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
SMP_TRACE_DEBUG ("%s", __FUNCTION__);
@@ -2043,9 +2056,17 @@
REVERSE_ARRAY_TO_STREAM(p1, p2, 16);
BT_OCTET16 intermediate_long_term_key;
- /* "tmp2" obtained from the spec */
- ret = smp_calculate_h6(rev_link_key, (UINT8 *) "2pmt" /* reversed "tmp2" */,
- intermediate_long_term_key);
+
+ if (p_cb->key_derivation_h7_used)
+ {
+ ret = smp_calculate_h7((UINT8*)salt, rev_link_key, intermediate_long_term_key);
+ }
+ else
+ {
+ /* "tmp2" obtained from the spec */
+ ret = smp_calculate_h6(rev_link_key, (UINT8 *) "2pmt" /* reversed "tmp2" */,
+ intermediate_long_term_key);
+ }
if (!ret)
{
@@ -2145,6 +2166,78 @@
/*******************************************************************************
**
+** Function smp_calculate_h7
+**
+** Description The function calculates
+** C = h7(SALT, W) = AES-CMAC (W)
+** SALT
+** where
+** input: W is 128 bit,
+** SALT is 128 bit,
+** output: C is 128 bit.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_h7(UINT8 *salt, UINT8 *w, UINT8 *c)
+{
+#if SMP_DEBUG == TRUE
+ UINT8 *p_print = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s",__FUNCTION__);
+#if SMP_DEBUG == TRUE
+ p_print = w;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN);
+ p_print = salt;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"SALT", BT_OCTET16_LEN);
+#endif
+
+ UINT8 *p = NULL;
+ UINT8 key[BT_OCTET16_LEN];
+
+ p = key;
+ ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
+
+#if SMP_DEBUG == TRUE
+ p_print = key;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN);
+#endif
+
+ UINT8 msg_len = BT_OCTET16_LEN /* msg size */;
+ UINT8 msg[BT_OCTET16_LEN];
+
+ p = msg;
+ ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+
+#if SMP_DEBUG == TRUE
+ p_print = msg;
+ smp_debug_print_nbyte_little_endian (p_print,(const UINT8 *) "M", msg_len);
+#endif
+
+ BOOLEAN ret = TRUE;
+ UINT8 cmac[BT_OCTET16_LEN];
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac))
+ {
+ SMP_TRACE_ERROR("%s failed",__FUNCTION__);
+ ret = FALSE;
+ }
+
+#if SMP_DEBUG == TRUE
+ p_print = cmac;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+**
** Function smp_start_nonce_generation
**
** Description This function starts nonce generation.
diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
index 2727af8..09b3999 100644
--- a/stack/smp/smp_main.c
+++ b/stack/smp/smp_main.c
@@ -824,7 +824,7 @@
/* execute action functions */
for (i = 0; i < SMP_NUM_ACTIONS; i++)
{
- if ((action = state_table[entry-1][i]) != SMP_SM_NO_ACTION)
+ if ((action = state_table[entry-1][i]) < SMP_SM_NO_ACTION)
{
(*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data);
}
@@ -859,7 +859,7 @@
{
const char *p_str = smp_event_name[SMP_MAX_EVT];
- if (event <= SMP_MAX_EVT)
+ if (event && event <= SMP_MAX_EVT)
{
p_str = smp_event_name[event- 1];
}
diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
index 883e83b..e372689 100644
--- a/stack/smp/smp_utils.c
+++ b/stack/smp/smp_utils.c
@@ -1197,7 +1197,13 @@
p_cb->le_secure_connections_mode_is_used = TRUE;
}
- SMP_TRACE_DEBUG("use_sc_process = %d", p_cb->le_secure_connections_mode_is_used);
+ if ((p_cb->peer_auth_req & SMP_H7_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_H7_SUPPORT_BIT))
+ {
+ p_cb->key_derivation_h7_used = TRUE;
+ }
+
+ SMP_TRACE_DEBUG("use_sc_process = %d, h7 use = %d", p_cb->le_secure_connections_mode_is_used,
+ p_cb->key_derivation_h7_used);
if (p_cb->le_secure_connections_mode_is_used)
{
diff --git a/stack/srvc/srvc_battery.c b/stack/srvc/srvc_battery.c
index 90632df..a3ce3ae 100644
--- a/stack/srvc/srvc_battery.c
+++ b/stack/srvc/srvc_battery.c
@@ -203,7 +203,7 @@
tBA_INST *p_inst;
tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ;
- if (battery_cb.inst_id == BA_MAX_INT_NUM)
+ if (battery_cb.inst_id >= BA_MAX_INT_NUM)
{
GATT_TRACE_ERROR("MAX battery service has been reached");
return 0;
diff --git a/stack/srvc/srvc_eng.c b/stack/srvc/srvc_eng.c
index 92d1d6e..fd7eaf0 100644
--- a/stack/srvc/srvc_eng.c
+++ b/stack/srvc/srvc_eng.c
@@ -270,6 +270,11 @@
tGATTS_RSP rsp_msg ;
UINT8 act = SRVC_ACT_IGNORE;
UINT8 clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
+ if( clcb_idx == SRVC_MAX_APPS)
+ {
+ GATT_TRACE_ERROR("srvc_eng_s_request_cback received for unknown connection");
+ return;
+ }
GATT_TRACE_EVENT("srvc_eng_s_request_cback : recv type (0x%02x)", type);
diff --git a/test/blegatt_test/Android.mk b/test/blegatt_test/Android.mk
new file mode 100644
index 0000000..95b548b
--- /dev/null
+++ b/test/blegatt_test/Android.mk
@@ -0,0 +1,43 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+
+LOCAL_SRC_FILES:= gatt_test.c
+
+LOCAL_C_INCLUDES += . \
+ $(LOCAL_PATH)/../../stack/include \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../stack/l2cap \
+ $(LOCAL_PATH)/../../utils/include \
+ $(LOCAL_PATH)/../../ \
+ $(LOCAL_PATH)/btif/include \
+ $(LOCAL_PATH)/../../stack/gatt \
+ $(LOCAL_PATH)/../../stack/btm \
+ $(LOCAL_PATH)/../../stack/avdt \
+ $(LOCAL_PATH)/../../stack/btm \
+ $(LOCAL_PATH)/../../hcis \
+ $(LOCAL_PATH)/../../hci/include \
+ $(LOCAL_PATH)/../../bta/include \
+ $(LOCAL_PATH)/../../bta/sys \
+ $(LOCAL_PATH)/../../osi/include \
+ $(bluetooth_C_INCLUDES)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug optional
+LOCAL_MODULE:= gatt_test
+
+#LOCAL_LDLIBS += -ldl -llog
+#LIBS_c += -lreadline
+
+LOCAL_SHARED_LIBRARIES += libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy
+
+LOCAL_MULTILIB := 32
+
+include $(BUILD_EXECUTABLE)
diff --git a/test/blegatt_test/README.txt b/test/blegatt_test/README.txt
new file mode 100644
index 0000000..1b4f478
--- /dev/null
+++ b/test/blegatt_test/README.txt
@@ -0,0 +1,191 @@
+Bluedroid LE Test Application
+==========================
+The test application provides a small console shell interface that allows
+access to the Bluetooth HAL API library though ASCII commands. This is similar
+to how the real JNI service would operate. The primary objective of this
+application is to allow Bluetooth to be put in DUT Mode for RF/BB BQB test purposes.
+
+This application is mutually exclusive with the Java based Bluetooth.apk. Hence
+before launching the application, it should be ensured that the Settings->Bluetooth is OFF.
+
+This application is built as 'bdt' and shall be available in '/system/bin/bdt'
+
+Limitations
+===========
+1.) Settings->Bluetooth must be OFF for this application to work
+2.) Currently, only the SIG 'HCI Test Mode' commands are supported. The vendor
+specific HCI test mode commands to be added.
+
+
+==================
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+proceduredure to create LE-L2CAP Connection Oriented Channal
+============================================================
+Step 1:
+ --> Run the gatt_testtool executable on both side (i.e, peripheral & central)
+
+Step 2:
+ Start Advertisement
+ ===================
+
+ > start_adv <uuid> <flag> ( peripheral side )
+
+ Where,
+ flag --> 1 (start advertisement)
+ 0 (stop advertisement)
+
+ option --> 1 (Doing registration with only Gatt_cb which is required for LE-L2CAP)
+ 0 (Doing the existing s_registration for gatt_testtool)
+
+ This will start the advertisement and listen for the incoming LE connection.
+
+Step 3:
+ Start&Stop scanning
+ ===================
+
+ > c_scan_start ( central side )
+ > c_scan_stop ( stop it as and when we find the remote device) ( Central side)
+
+Step 4:
+ listen for incoming LE COC
+ ==========================
+
+ > le_l2cap_listen <le_psm> <mtu> <mps> <init_credits> <sec_level> ( peripheral side )
+
+ Where,
+ le_psm --> 1 to 127 (Fixed Range, SIG assigned)
+ 128 to 255 (Dynamic Range)
+ mtu --> 23 to 65535
+ mps --> 23 to 65533
+ init_credits --> 0 to 65535
+ sec_level --> 0 for no security
+ 1 for authentication
+ --> 2 for encryption
+
+ Example : le_l2cap_listen 128 23 23 100 0
+ Note : MTU value should not be less then MPS
+
+Step 5:
+ Initiate LE COC connection
+ ==========================
+
+ > le_l2cap_coc_connect <le_psm> <mtu> <mps> <init_credits> <sec_level> <bd_addr> ( central side)
+
+ Where,
+ le_psm --> 1 to 127 (Fixed Range, SIG assigned)
+ 128 to 255 (Dynamic Range)
+ mtu --> 23 to 65535
+ mps --> 23 to 65533
+ init_credits --> 0 to 65535
+ bd_addr --> remote BD address
+ sec_level --> 0 for no security
+ 1 for authentication
+ --> 2 for encryption
+
+ Example : le_l2cap_coc_connect 128 23 23 100 0 7e58587530b8
+ Note : MTU value should not be less then MPS
+
+Step 6:
+ Send Credits [LE Credit Based Flow Control Mode]
+ ================================================
+
+ [Initiating the LE credit based flow control with the no.of credits incase of initial credits were
+ not provided i.e set as 0 as part of connection establishment, this command will be ignored
+ if the intial credits were given as part of conneciton establishment.]
+
+ > le_l2cap_coc_flow_ctrl <cid> <credits>
+
+ Where,
+ cid --> 64 to 127 (Dynamic Range)
+ [ Use the allocated CID during LE COC connection initialization]
+ credits --> 1 to 65535
+
+ Note : When we plan to send this command, the initial credit value has to be set with zero
+ during the initialization LE COC connection.
+
+Step 7:
+ Send file
+ =========
+
+ push the file in to the device "/system" directory which you want to sent.
+
+ > send_file <cid> < file_path >
+
+ Where,
+ cid --> 64 to 127 (Dynamic Range)
+ [ Use the allocated CID during LE COC connection initialization]
+ file_path --> give the file path which is going to be sent.
+
+ Example : send_file 65 /system/bt_stack_file.txt
+
+Step 8:
+ Disconnect LE COC
+ =================
+
+ > le_coc_disconnect <cid>
+
+ Where,
+ cid --> 64 to 127 (Dynamic Range)
+ [ Use the allocated CID during LE COC connection initialization]
+
diff --git a/test/blegatt_test/gatt_test.c b/test/blegatt_test/gatt_test.c
new file mode 100644
index 0000000..982c80c
--- /dev/null
+++ b/test/blegatt_test/gatt_test.c
@@ -0,0 +1,3010 @@
+/******************************************************************************
+ ** Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+
+/************************************************************************************
+ *
+ * Filename: gatt_tool.c
+ *
+ * Description: Bluedroid GATT TOOL application
+ *
+ ***********************************************************************************/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+//#include <sys/time.h>
+//#include <signal.h>
+//#include <time.h>
+#include "bt_target.h"
+#include "l2c_api.h"
+#include "bta_api.h"
+#include "l2c_int.h"
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_gatt_client.h>
+#include <hardware/bt_gatt_server.h>
+#include <hardware/bt_gatt_types.h>
+//#include "../../osi/include/allocator.h"
+#include <bt_testapp.h>
+
+#include <signal.h>
+#include <time.h>
+
+
+#ifdef TEST_APP_INTERFACE
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define PID_FILE "/data/.bdt_pid"
+
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+static void register_client_cb(int status, int client_if, bt_uuid_t *app_uuid);
+static void scan_result_cb(bt_bdaddr_t* remote_bd_addr, int rssi, uint8_t* adv_data);
+static void listen_cb(int status, int server_if);
+
+static void register_server_cb(int status, int server_if, bt_uuid_t *app_uuid);
+
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static unsigned char main_done = 0;
+static bt_status_t status;
+typedef struct
+{
+ UINT16 result; /* Only used in confirm messages */
+ UINT16 credits; /* used to send the outstanding credits */
+ UINT16 le_psm;
+ UINT16 le_mps;
+ UINT16 le_mtu;
+ UINT16 init_credits; /* initial credits */
+} tL2CAP_LE_CONN_INFO;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT16 psm;
+ UINT16 lcid;
+ tL2CAP_LE_CONN_INFO loc_conn_info;
+ tL2CAP_LE_CONN_INFO rmt_conn_info;
+ BOOLEAN is_server;
+} t_le_chnl_info;
+
+t_le_chnl_info le_chnl_conn_info[MAX_L2CAP_CLIENTS];
+#define LE_ACL_MAX_BUFF_SIZE 4096
+static int num_frames = 1;
+static unsigned long g_delay = 1; /* Default delay before data transfer */
+static int count = 1;
+static UINT16 g_BleEncKeySize = 16;
+//static int g_omps = 0;
+//static int rcv_count = 0;
+static int g_le_coc_if = 0;
+static int rcv_itration = 0;
+static volatile BOOLEAN cong_status = FALSE;
+/* Control channel LE-L2CAP default options */
+static tL2CAP_LE_CONN_INFO le_conn_info;
+static tL2CAP_LE_CFG_INFO local_coc_cfg;
+
+/* Main API */
+static bluetooth_device_t* bt_device;
+
+const bt_interface_t* sBtInterface = NULL;
+
+static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
+ AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
+ AID_NET_ADMIN, AID_VPN};
+
+enum {
+ DISCONNECT,
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTING
+};
+static unsigned char bt_enabled = 0;
+static int g_ConnectionState = DISCONNECT;
+static int g_AdapterState = BT_STATE_OFF;
+static int g_PairState = BT_BOND_STATE_NONE;
+
+
+static int g_conn_id = 0;
+static int g_client_if = 0;
+static int g_server_if = 0;
+static int g_client_if_scan = 0;
+static int g_server_if_scan = 0;
+
+const btgatt_test_interface_t *sGattInterface = NULL;
+const btgatt_interface_t *sGattIfaceScan = NULL;
+const btsmp_interface_t *sSmpIface = NULL;
+const btgap_interface_t *sGapInterface = NULL;
+const btl2cap_interface_t *sL2capInterface = NULL;
+
+
+int Btif_gatt_layer = TRUE;
+bt_bdaddr_t *remote_bd_address;
+
+static UINT16 g_SecLevel = 0;
+static BOOLEAN g_ConnType = TRUE;//DUT is initiating connection
+static BOOLEAN g_Fcr_Present = FALSE;
+static UINT8 g_Fcr_Mode = L2CAP_FCR_BASIC_MODE;
+static UINT8 g_Ertm_AllowedMode = (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | L2CAP_FCR_CHAN_OPT_STREAM);
+
+
+/* Default mtu */
+static int g_imtu = 672;
+static int g_omtu = 0;
+
+enum {
+L2CAP_NOT_CONNECTED,
+L2CAP_CONN_SETUP,
+L2CAP_CONNECTED
+};
+
+//static int L2cap_conn_state = L2CAP_NOT_CONNECTED;
+static tL2CAP_CFG_INFO tl2cap_cfg_info;
+static long data_size = -1;
+static UINT16 g_PSM = 0;
+static UINT16 g_lcid = 0;
+
+
+enum {
+ SEND,
+ RECEIVE,
+ WAITANDSEND,
+ PAIR,
+ PING,
+ CONNECT,
+};
+
+
+/* Control channel eL2CAP default options */
+tL2CAP_FCR_OPTS ertm_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE,
+ 3, /* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ 2000, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ 100 /* MPS segment size */
+};
+
+tL2CAP_FCR_OPTS stream_fcr_opts_def = {
+ L2CAP_FCR_STREAM_MODE,
+ 3,/* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ 2000, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ 100 /* MPS segment size */
+};
+static tL2CAP_ERTM_INFO t_ertm_info = {0, 0, 0, 0, 0, 0};
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+static void process_cmd(char *p, unsigned char is_job);
+//static void job_handler(void *param);
+static void bdt_log(const char *fmt_str, ...);
+static void l2c_connect(bt_bdaddr_t *bd_addr);
+static UINT16 do_l2cap_connect(bt_bdaddr_t * bd_addr);
+
+
+
+int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr);
+
+/* LE L2CAP functions */
+static t_le_chnl_info *le_allocate_conn_info(UINT16 psm, BOOLEAN is_server);
+static t_le_chnl_info *le_get_conn_info(UINT16 psm, BOOLEAN is_server);
+static t_le_chnl_info *le_get_conn_info_by_lcid(UINT16 lcid);
+static BOOLEAN le_release_conn_info(t_le_chnl_info *le_conn_info);
+UINT8 do_l2cap_DataWrite(UINT16 chnl_id, char *p , UINT32 len);
+static int Send_Data();
+static int send_file(char *p);
+static void le_l2cap_coc_connect(char *svr);
+UINT16 do_le_l2cap_coc_connect(char *p);
+static void le_l2cap_coc_flow_ctrl(char *p);
+UINT16 do_le_l2cap_coc_flow_ctrl(char *p);
+static void do_le_coc_disconnect(char *p);
+int GetFileName(char *p, char *filename);
+
+/************************************************************************************
+** GATT Client Callbacks
+************************************************************************************/
+static void register_client_cb(int status, int client_if, bt_uuid_t *app_uuid)
+{
+ printf("%s:: status=%d, client_if=%d, uuid=%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x \n", __FUNCTION__, status, client_if,
+ app_uuid->uu[0], app_uuid->uu[1], app_uuid->uu[2], app_uuid->uu[3],
+ app_uuid->uu[4], app_uuid->uu[5], app_uuid->uu[6], app_uuid->uu[7],
+ app_uuid->uu[8], app_uuid->uu[9], app_uuid->uu[10], app_uuid->uu[11],
+ app_uuid->uu[12], app_uuid->uu[13], app_uuid->uu[14], app_uuid->uu[15]);
+ if(0 == status) g_client_if_scan = client_if;
+}
+
+static void scan_result_cb(bt_bdaddr_t* remote_bd_addr, int rssi, uint8_t* adv_data)
+{
+ printf("%s:: remote_bd_addr= %02X%02X%02X%02X%02X%02X , adv_data=0x%x \n", __FUNCTION__,
+ remote_bd_addr->address[0], remote_bd_addr->address[1], remote_bd_addr->address[2],
+ remote_bd_addr->address[3], remote_bd_addr->address[4], remote_bd_addr->address[5], *adv_data);
+}
+
+static void connect_cb(int conn_id, int status, int client_if, bt_bdaddr_t* remote_bd_addr)
+{
+ printf("%s:: remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, conn_id=0x%x, status=%d, client_if=%d\n", __FUNCTION__,
+ remote_bd_addr->address[0], remote_bd_addr->address[1], remote_bd_addr->address[2],
+ remote_bd_addr->address[3], remote_bd_addr->address[4], remote_bd_addr->address[5], conn_id, status, client_if);
+
+ g_conn_id = conn_id;
+ sGapInterface->Gap_BleAttrDBUpdate(remote_bd_addr->address, 50, 70, 0, 1000);
+
+}
+
+/*
+static void register_for_notification_cb(int conn_id, int registered, int status, btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id)
+{
+ printf("%s:: conn_id=%d, registered=%d, status=%d \n", __FUNCTION__, conn_id, registered, status);
+}
+*/
+
+static void listen_cb(int status, int server_if)
+{
+ printf("%s:: status=%d, server_if=%d \n", __FUNCTION__, status, server_if);
+ if(0 == status) g_server_if = server_if;
+}
+
+static btgatt_client_callbacks_t sGattClient_cb =
+{
+ register_client_cb,
+ scan_result_cb,
+ connect_cb,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //register_for_notification_cb,
+ NULL,
+ NULL,
+ NULL,
+ listen_cb,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+/************************************************************************************
+** GATT Server Callbacks
+************************************************************************************/
+static void register_server_cb(int status, int server_if, bt_uuid_t *app_uuid)
+{
+ printf("%s:: status=%d, server_if=%d \n", __FUNCTION__, status, server_if);
+ if(0 == status) g_server_if_scan = server_if;
+}
+
+static void server_connection_cb(int conn_id, int server_if, int connected, bt_bdaddr_t *bda)
+{
+ printf("%s:: conn_id=%d, server_if=%d \n", __FUNCTION__, conn_id, server_if);
+ g_conn_id = conn_id;
+}
+
+static btgatt_server_callbacks_t sGattServer_cb =
+{
+ register_server_cb,
+ server_connection_cb, //connection_callback connection_cb;
+ NULL, //service_added_callback service_added_cb;
+ NULL, //included_service_added_callback included_service_added_cb;
+ NULL, //characteristic_added_callback characteristic_added_cb;
+ NULL, //descriptor_added_callback descriptor_added_cb;
+ NULL, //service_started_callback service_started_cb;
+ NULL, //service_stopped_callback service_stopped_cb;
+ NULL, //service_deleted_callback service_deleted_cb;
+ NULL, //request_read_callback request_read_cb;
+ NULL, //request_write_callback request_write_cb;
+ NULL, //request_exec_write_callback request_exec_write_cb;
+ NULL, //response_confirmation_callback response_confirmation_cb;
+ NULL,
+ NULL,
+ NULL
+};
+
+
+/************************************************************************************
+** GATT Callbacks
+************************************************************************************/
+static void DiscoverRes_cb (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data)
+{
+ printf("%s:: conn_id=%d, disc_type=%d\n", __FUNCTION__, conn_id, disc_type);
+}
+
+static void DiscoverCmpl_cb (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
+{
+ printf("%s:: conn_id=%d, disc_type=%d, status=%d\n", __FUNCTION__, conn_id, disc_type, status);
+}
+
+static void OperationCmpl_cb(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+{
+ printf("%s:: conn_id=%d, op=%d, status=%d\n", __FUNCTION__, conn_id, op, status);
+}
+
+static void Connection_cb (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason,tBT_TRANSPORT transport)
+{
+ printf("%s:: remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, conn_id=0x%x, connected=%d, reason=%d, gatt_if=%d \n", __FUNCTION__,
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5],
+ conn_id, connected, reason, gatt_if);
+ g_conn_id = conn_id;
+}
+
+static void AttributeReq_cb(UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
+{
+ printf("%s:: conn_id=%d, trans_id=%d, type=%u\n", __FUNCTION__, conn_id, trans_id, type);
+}
+
+
+static tGATT_CBACK sGattCB =
+{
+ Connection_cb,
+ OperationCmpl_cb,
+ DiscoverRes_cb,
+ DiscoverCmpl_cb,
+ AttributeReq_cb,
+ NULL,
+ NULL
+};
+
+/************************************************************************************
+** GAP Callbacks
+************************************************************************************/
+/*
+static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data)
+{
+ printf("%s:: conn_id=%d, trans_id=%d, op_code=%u\n", __FUNCTION__, conn_id, trans_id, op_code);
+}
+
+// client connection callback
+
+static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason,tBT_TRANSPORT transport)
+{
+ printf("%s:: gatt_if=%d, remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, conn_id=%d, connected=%d, reason=%d\n", __FUNCTION__,
+ gatt_if, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], conn_id, connected, reason);
+ g_conn_id = conn_id;
+}
+
+static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+{
+ printf("%s:: conn_id=%d, op=%d, status=%d\n", __FUNCTION__, conn_id, op, status);
+}
+
+
+static tGATT_CBACK gap_cback =
+{
+ gap_ble_c_connect_cback,
+ gap_ble_c_cmpl_cback,
+ NULL,
+ NULL,
+ gap_ble_s_attr_request_cback,
+ NULL,
+ NULL
+};
+*/
+
+
+/************************************************************************************
+** SMP Callbacks
+************************************************************************************/
+static UINT8 SMP_cb (tSMP_EVT event, BD_ADDR bda, tSMP_EVT_DATA *p_data)
+{
+ printf("%s:: event=%d(1-SMP_IO_CAP_REQ_EVT, 2-SMP_SEC_REQUEST_EVT, \
+ 3-SMP_PASSKEY_NOTIF_EVT, 4-SMP_PASSKEY_REQ_EVT, 6-SMP_COMPLT_EVT), \
+ \nremote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, PassKey=%u \n", __FUNCTION__, event,
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], p_data->passkey);
+ switch(event)
+ {
+ case SMP_IO_CAP_REQ_EVT:
+ printf("Io_Caps=%d, auth_req=%d, max_key_size=%d, init_keys=%d, resp_keys=%d \n", p_data->io_req.io_cap, p_data->io_req.auth_req, p_data->io_req.max_key_size, p_data->io_req.init_keys, p_data->io_req.resp_keys);
+ break;
+
+ case SMP_PASSKEY_REQ_EVT:
+ case SMP_PASSKEY_NOTIF_EVT:
+ printf("passkey value=%u\n", p_data->passkey);
+ sSmpIface->PasskeyReply(bda, SMP_SUCCESS, p_data->passkey);
+ break;
+ case SMP_OOB_REQ_EVT:
+ //p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ break;
+ case SMP_SEC_REQUEST_EVT:
+ case SMP_COMPLT_EVT:
+ printf("SMP Complete Event:: Reason=%d \n", p_data->cmplt.reason);
+ if(p_data->cmplt.reason == SMP_SUCCESS)
+ {
+ sSmpIface->SecurityGrant(bda, p_data->cmplt.reason);
+ printf("Granting Security \n");
+ }
+ break;
+ }
+ return 0;
+}
+
+
+
+
+/************************************************************************************
+** Shutdown helper functions
+************************************************************************************/
+
+static void bdt_shutdown(void)
+{
+ bdt_log("shutdown bdroid test app\n");
+ main_done = 1;
+}
+
+
+/*****************************************************************************
+** Android's init.rc does not yet support applying linux capabilities
+*****************************************************************************/
+
+static void config_permissions(void)
+{
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap[2];
+
+ bdt_log("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
+
+ header.pid = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setuid(AID_BLUETOOTH);
+ setgid(AID_BLUETOOTH);
+
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ capset(&header, &cap[0]);
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+}
+
+
+
+/*****************************************************************************
+** Logger API
+*****************************************************************************/
+
+void bdt_log(const char *fmt_str, ...)
+{
+ static char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt_str);
+ vsnprintf(buffer, 1024, fmt_str, ap);
+ va_end(ap);
+
+ fprintf(stdout, "%s\n", buffer);
+}
+
+/*******************************************************************************
+ ** Misc helper functions
+ *******************************************************************************/
+static const char* dump_bt_status(bt_status_t status)
+{
+ switch(status)
+ {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown status code";
+ }
+}
+
+/*
+static void hex_dump(char *msg, void *data, int size, int trunc)
+{
+ unsigned char *p = data;
+ unsigned char c;
+ int n;
+ char bytestr[4] = {0};
+ char addrstr[10] = {0};
+ char hexstr[ 16*3 + 5] = {0};
+ char charstr[16*1 + 5] = {0};
+
+ bdt_log("%s \n", msg);
+
+ // truncate
+ if(trunc && (size>32))
+ size = 32;
+
+ for(n=1;n<=size;n++) {
+ if (n%16 == 1) {
+ // store address for this line
+ snprintf(addrstr, sizeof(addrstr), "%.4x",
+ ((intptr_t)p-(intptr_t)data) );
+ }
+
+ c = *p;
+ if (isalnum(c) == 0) {
+ c = '.';
+ }
+
+ // store hex str (for left side)
+ snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
+ strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
+
+ // store char str (for right side)
+ snprintf(bytestr, sizeof(bytestr), "%c", c);
+ strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
+
+ if(n%16 == 0) {
+ // line completed
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ } else if(n%8 == 0) {
+ // half line: add whitespaces
+ strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
+ strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
+ }
+ p++; // next byte
+ }
+
+ if (strlen(hexstr) > 0) {
+ // print rest of buffer if not empty
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ }
+}
+*/
+
+/*******************************************************************************
+ ** Console helper functions
+ *******************************************************************************/
+
+void skip_blanks(char **p)
+{
+ while (**p == ' ')
+ (*p)++;
+}
+
+uint32_t get_int(char **p, int DefaultValue)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+int get_signed_int(char **p, int DefaultValue)
+{
+ int Value = 0;
+ unsigned char UseDefault;
+ unsigned char NegativeNum = 0;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ if ((**p) == '-')
+ {
+ NegativeNum = 1;
+ (*p)++;
+ }
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return ((NegativeNum == 0)? Value : -Value);
+}
+
+void get_str(char **p, char *Buffer)
+{
+ skip_blanks(p);
+ while (**p != 0 && **p != ' ')
+ {
+ *Buffer = **p;
+ (*p)++;
+ Buffer++;
+ }
+
+ *Buffer = 0;
+}
+
+uint32_t get_hex_any(char **p, int DefaultValue, unsigned int NumOfNibble)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ((NumOfNibble) && (((**p)<= '9' && (**p)>= '0') ||
+ ((**p)<= 'f' && (**p)>= 'a') ||
+ ((**p)<= 'F' && (**p)>= 'A')) )
+ {
+ if (**p >= 'a')
+ Value = Value * 16 + (**p) - 'a' + 10;
+ else if (**p >= 'A')
+ Value = Value * 16 + (**p) - 'A' + 10;
+ else
+ Value = Value * 16 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ NumOfNibble--;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+uint32_t get_hex(char **p, int DefaultValue)
+{
+ return (get_hex_any(p, DefaultValue, 8));
+}
+uint32_t get_hex_byte(char **p, int DefaultValue)
+{
+ return (get_hex_any(p, DefaultValue, 2));
+}
+
+void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
+ char *d = ((char *)bd), *endp;
+ int i;
+ for(i = 0; i < 6; i++) {
+ *d++ = strtol(str, &endp, 16);
+ if (*endp != ':' && i != 5) {
+ memset(bd, 0, sizeof(bt_bdaddr_t));
+ return;
+ }
+ str = endp + 1;
+ }
+}
+
+#define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
+#define if_cmd(str) if (is_cmd(str))
+
+typedef void (t_console_cmd_handler) (char *p);
+
+typedef struct {
+ const char *name;
+ t_console_cmd_handler *handler;
+ const char *help;
+ unsigned char is_job;
+} t_cmd;
+
+
+const t_cmd console_cmd_list[];
+static int console_cmd_maxlen = 0;
+
+static void cmdjob_handler(void *param)
+{
+ char *job_cmd = (char*)param;
+
+ bdt_log("cmdjob starting (%s)", job_cmd);
+
+ process_cmd(job_cmd, 1);
+
+ bdt_log("cmdjob terminating");
+
+ free(job_cmd);
+}
+
+static int create_cmdjob(char *cmd)
+{
+ pthread_t thread_id;
+ char *job_cmd;
+
+ job_cmd = (char*)calloc(1, strlen(cmd)+1); /* freed in job handler */
+ if (job_cmd) {
+ strlcpy(job_cmd, cmd,(strlen(cmd)+1));
+ if (pthread_create(&thread_id, NULL,
+ (void*)cmdjob_handler, (void*)job_cmd)!=0)
+ perror("pthread_create");
+ return 0;
+ }
+ else
+ perror("create_Cmdjob malloc failed ");
+ return -1;
+}
+
+/*******************************************************************************
+ ** Load stack lib
+ *******************************************************************************/
+
+int HAL_load(void)
+{
+ int err = 0;
+
+ hw_module_t* module;
+ hw_device_t* device;
+
+ bdt_log("Loading HAL lib + extensions");
+
+ err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0)
+ {
+
+ err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ bdt_log("HAL library open (%s)", strerror(err));
+ if (err == 0) {
+ bt_device = (bluetooth_device_t *)device;
+ sBtInterface = bt_device->get_bluetooth_interface();
+ }
+ }
+
+ bdt_log("HAL library loaded (%s) interface pointer =%x ", strerror(err), sBtInterface);
+
+ return err;
+}
+
+int HAL_unload(void)
+{
+ int err = 0;
+
+ bdt_log("Unloading HAL lib");
+
+ sBtInterface = NULL;
+
+ bdt_log("HAL library unloaded (%s)", strerror(err));
+
+ return err;
+}
+
+/*******************************************************************************
+ ** HAL test functions & callbacks
+ *******************************************************************************/
+
+void setup_test_env(void)
+{
+ int i = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
+ i++;
+ }
+}
+
+void check_return_status(bt_status_t status)
+{
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
+ }
+ else
+ {
+ bdt_log("HAL REQUEST SUCCESS");
+ }
+}
+/*
+static void do_set_adv_params(char *p)
+{
+ bt_bdaddr_t bd_addr = {{0}};
+ int int_min = 0x0, int_max = 0x0, addr_type = 0;
+ int_max = get_int(&p, -1);
+ int_min = get_int(&p, -1);
+ if(int_max < int_min)
+ return;
+// if(FALSE == GetBdAddr(p, &bd_addr)) return;
+// sBtInterface->le_set_adv_params(int_min, int_max, &bd_addr, addr_type);
+}
+*/
+
+static void do_set_localname(char *p)
+{
+ printf("set name in progress: %s\n", p);
+ bt_property_t property = {BT_PROPERTY_BDNAME, strlen(p), p};
+ status = sBtInterface->set_adapter_property(&property);
+}
+
+static void adapter_state_changed(bt_state_t state)
+{
+ int V1 = 1000, V2=2;
+ bt_property_t property = {9 /*BT_PROPERTY_DISCOVERY_TIMEOUT*/, 4, &V1};
+ bt_property_t property1 = {7 /*SCAN*/, 2, &V2};
+ bt_property_t property2 ={1,9,"GATTTOOL"};
+ printf("ADAPTER STATE UPDATED : %s\n", (state == BT_STATE_OFF)?"OFF":"ON");
+
+ g_AdapterState = state;
+
+ if (state == BT_STATE_ON) {
+ bt_enabled = 1;
+ status = sBtInterface->set_adapter_property(&property1);
+ status = sBtInterface->set_adapter_property(&property);
+ status = sBtInterface->set_adapter_property(&property2);
+ } else {
+ bt_enabled = 0;
+ }
+}
+
+static void adapter_properties_changed(bt_status_t status, int num_properties, bt_property_t *properties)
+{
+ char Bd_addr[15] = {0};
+ if(NULL == properties)
+ {
+ printf("properties is null\n");
+ return;
+ }
+ switch(properties->type)
+ {
+ case BT_PROPERTY_BDADDR:
+ memcpy(Bd_addr, properties->val, properties->len);
+ break;
+// case BT_PROPERTY_ADAPTER_BLE_ADV_MODE:
+ // printf("Set in advertisement mode\n");
+ // break;
+ default:
+ printf("property type not used\n");
+ }
+ return;
+}
+
+static void discovery_state_changed(bt_discovery_state_t state)
+{
+ printf("Discovery State Updated : %s\n", (state == BT_DISCOVERY_STOPPED)?"STOPPED":"STARTED");
+}
+
+
+static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name, uint32_t cod, bool min_16_digit )
+{
+ remote_bd_address = remote_bd_addr;
+ //bt_pin_code_t pincode = {{0x31, 0x32, 0x33, 0x34}};
+ printf("Enter the pin key displayed in the remote device and terminate the key entry with .\n");
+
+ /*if(BT_STATUS_SUCCESS != sBtInterface->pin_reply(remote_bd_addr, TRUE, 4, &pincode))
+ {
+ printf("Pin Reply failed\n");
+ }*/
+}
+static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant, uint32_t pass_key)
+{
+ printf("ssp_request_cb : name=%s variant=%d passkey=%u\n", bd_name->name, pairing_variant, pass_key);
+ if(BT_STATUS_SUCCESS != sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, TRUE, pass_key))
+ {
+ printf("SSP Reply failed\n");
+ }
+}
+
+static void bond_state_changed_cb(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_bond_state_t state)
+{
+ g_PairState = state;
+}
+
+static void acl_state_changed(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_acl_state_t state)
+{
+ printf("acl_state_changed : remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, acl status=%s \n",
+ remote_bd_addr->address[0], remote_bd_addr->address[1], remote_bd_addr->address[2],
+ remote_bd_addr->address[3], remote_bd_addr->address[4], remote_bd_addr->address[5],
+ (state == BT_ACL_STATE_CONNECTED)?"ACL Connected" :"ACL Disconnected"
+ );
+}
+static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+ bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
+}
+
+static void le_test_mode(bt_status_t status, uint16_t packet_count)
+{
+ bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
+}
+
+extern int timer_create (clockid_t, struct sigevent *__restrict, timer_t *__restrict);
+extern int timer_settime (timer_t, int, const struct itimerspec *__restrict, struct itimerspec *__restrict);
+
+static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data)
+{
+
+ static timer_t timer;
+ static bool timer_created;
+
+ if (!timer_created) {
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))cb;
+ sigevent.sigev_value.sival_ptr = data;
+ timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
+ timer_created = true;
+ }
+
+ struct itimerspec new_value;
+ new_value.it_value.tv_sec = delay_millis / 1000;
+ new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
+ new_value.it_interval.tv_sec = 0;
+ new_value.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &new_value, NULL);
+ return true;
+}
+
+static int acquire_wake_lock(const char *lock_name)
+{
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock(const char *lock_name)
+{
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed,
+ adapter_properties_changed, /*adapter_properties_cb */
+ NULL, /* remote_device_properties_cb */
+ NULL, /* device_found_cb */
+ discovery_state_changed, /* discovery_state_changed_cb */
+ pin_request_cb, /* pin_request_cb */
+ ssp_request_cb, /* ssp_request_cb */
+ bond_state_changed_cb, /*bond_state_changed_cb */
+ acl_state_changed, /* acl_state_changed_cb */
+ NULL, /* thread_evt_cb */
+ dut_mode_recv, /*dut_mode_recv_cb */
+ le_test_mode, /* le_test_mode_cb */
+ NULL, /*energy_info_cb*/
+ NULL /* hci_event_recv_cb */
+};
+
+static bt_os_callouts_t bt_os_callbacks = {
+ sizeof(bt_os_callouts_t),
+ set_wake_alarm,
+ acquire_wake_lock,
+ release_wake_lock
+};
+
+static void l2test_l2c_connect_ind_cb(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+
+ UINT16 result;
+
+ local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
+ local_coc_cfg.mtu = L2CAP_LE_DEFAULT_MTU;
+ local_coc_cfg.mps = L2CAP_LE_DEFAULT_MPS;
+ /* Verify if LE PSM */
+ if (L2C_IS_VALID_LE_PSM(psm))
+ {
+ if (psm == 200)
+ {
+ printf("No Resources Available\n");
+ result = L2CAP_LE_NO_RESOURCES;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_CONN_OK,&local_coc_cfg);
+ }
+ else if(psm == 201)
+ {
+ printf("L2CAP_LE_CONN_INSUFFI_AUTHORIZATION \n");
+ result = L2CAP_LE_INSUFFICIENT_AUTHORIZATION;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_CONN_OK,&local_coc_cfg);
+ }
+ else
+ {
+
+ result = L2CAP_LE_CONN_OK;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid, result,L2CAP_LE_CONN_OK,&local_coc_cfg);
+ }
+ return;
+ }
+ if((L2CAP_FCR_ERTM_MODE == g_Fcr_Mode) || (L2CAP_FCR_STREAM_MODE == g_Fcr_Mode)) {
+ sL2capInterface->ErtmConnectRsp(bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, &t_ertm_info);
+ } else {
+ sL2capInterface->ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+ }
+ {
+ tL2CAP_CFG_INFO cfg;
+ memcpy (&cfg ,&tl2cap_cfg_info,sizeof(tl2cap_cfg_info));
+ if ((!sL2capInterface->ConfigReq (lcid, &cfg)) && cfg.fcr_present
+ && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcr_present = FALSE;
+ sL2capInterface->ConfigReq (lcid, &cfg);
+ }
+ }
+ g_ConnectionState = CONNECT;
+ g_lcid = lcid;
+}
+
+static void l2test_l2c_connect_cfm_cb(UINT16 lcid, UINT16 result)
+{
+ t_le_chnl_info *le_conn_info = le_get_conn_info_by_lcid(lcid);
+ if (le_conn_info&&L2C_IS_VALID_LE_PSM(le_conn_info->psm))
+ {
+
+ if (result == L2CAP_LE_CONN_OK) {
+ g_ConnectionState = CONNECT;
+ }
+ else if(le_conn_info && !le_conn_info->is_server)
+ {
+ le_release_conn_info(le_conn_info);
+ }
+ return;
+ }
+#if 0
+ if (result == L2CAP_CONN_OK) {
+ L2cap_conn_state = L2CAP_CONN_SETUP;
+ tL2CAP_CFG_INFO cfg;
+ memcpy (&cfg ,&tl2cap_cfg_info,sizeof(tl2cap_cfg_info));
+ sL2capInterface->ConfigReq (lcid, &cfg);
+ g_imtu = cfg.mtu;
+ g_ConnectionState = CONNECT;
+ g_lcid = lcid;
+ }
+#endif
+}
+
+static void l2test_l2c_connect_pnd_cb(UINT16 lcid)
+{
+ g_ConnectionState = CONNECTING;
+}
+static void l2test_l2c_config_ind_cb(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ p_cfg->result = L2CAP_CFG_OK;
+ p_cfg->fcr_present = FALSE;
+ if(p_cfg->mtu_present) g_omtu = p_cfg->mtu;
+ else g_omtu = L2CAP_DEFAULT_MTU;
+ sL2capInterface->ConfigRsp (lcid, p_cfg);
+ return;
+}
+
+static void l2test_l2c_config_cfm_cb(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ printf("\nl2test_l2c_config_cfm_cb Success\n");
+ } else {
+
+ /* If peer has rejected FCR and suggested basic then try basic */
+ if (p_cfg->fcr_present) {
+ tL2CAP_CFG_INFO cfg;
+ memcpy (&cfg ,&tl2cap_cfg_info,sizeof(tl2cap_cfg_info));
+ cfg.fcr_present = FALSE;
+ sL2capInterface->ConfigReq (lcid, &cfg);
+ // Remain in configure state
+ return;
+ }
+ sL2capInterface->DisconnectReq(lcid);
+ }
+ if(0 == g_omtu) g_omtu = L2CAP_DEFAULT_MTU;
+}
+
+static void l2test_l2c_disconnect_ind_cb(UINT16 lcid, BOOLEAN ack_needed)
+{
+ t_le_chnl_info *le_conn_info = le_get_conn_info_by_lcid(lcid);
+ /* release the conn info entry if it'a client */
+ if(le_conn_info && !le_conn_info->is_server)
+ {
+ le_release_conn_info(le_conn_info);
+ }
+ printf("l2test_le_l2c_disconnect_ind_cb, cid=0x%x, acks=%d\n", lcid, ack_needed);
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ sL2capInterface->DisconnectRsp(lcid);
+ }
+ g_ConnectionState = DISCONNECTING;
+ g_lcid = 0;
+}
+static void l2test_l2c_disconnect_cfm_cb(UINT16 lcid, UINT16 result)
+{
+ t_le_chnl_info *le_conn_info = le_get_conn_info_by_lcid(lcid);
+ /* release the conn info entry if it'a client */
+ if(le_conn_info && !le_conn_info->is_server)
+ {
+ le_release_conn_info(le_conn_info);
+ }
+
+ printf("l2test_le_l2c_disconnect_cfm_cb, cid=0x%x, result=%d\n", lcid, result);
+ g_ConnectionState = DISCONNECT;
+ g_lcid = 0;
+}
+static void l2test_l2c_QoSViolationInd(BD_ADDR bd_addr)
+{
+ printf("l2test_l2c_QoSViolationInd\n");
+}
+static void l2test_l2c_data_ind_cb(UINT16 lcid, BT_HDR *p_buf)
+{
+ rcv_itration++;
+ printf("l2test_l2c_data_ind_cb:: itration=%d, event=%u, len=%u, "\
+ "offset=%u, layer_specific=%u\n",rcv_itration, p_buf->event,
+ p_buf->len, p_buf->offset, p_buf->layer_specific);
+ sL2capInterface->LeFreeBuf(p_buf);
+ printf("l2test_l2c_data_ind_cb:: event=%u, len=%u, offset=%u, layer_specific=%u\n",
+ p_buf->event, p_buf->len, p_buf->offset, p_buf->layer_specific);
+}
+static void l2test_l2c_congestion_ind_cb(UINT16 lcid, BOOLEAN is_congested)
+{
+ cong_status = is_congested;
+ printf("l2test_l2c_congestion_ind_cb is_congested %d\n ", is_congested);
+}
+
+static void l2test_l2c_tx_complete_cb (UINT16 lcid, UINT16 NoOfSDU)
+{
+ printf("l2test_l2c_tx_complete_cb, cid=0x%x, SDUs=%u\n", lcid, NoOfSDU);
+}
+
+/*
+static void l2c_echo_rsp_cb(UINT16 p)
+{
+ printf("Ping Response = %s\n", (L2CAP_PING_RESULT_OK==p) ?"Ping Reply OK" :(L2CAP_PING_RESULT_NO_LINK==p) ?"Link Could Not be setup" :"Remote L2cap did not reply");
+}
+*/
+/*LE-L2CAP Callback*/
+
+#if 0
+
+static void l2test_le_connect_ind_cb(BD_ADDR bd_addr, UINT16 lcid, UINT8 id,
+ tL2CAP_LE_CONN_INFO *conn_info)
+{
+ printf(" l2test_le_connect_ind_cb\n lcid=%u\n id=%u\n ls_psm %d\n "\
+ "le_mtu %d\n le_mps %d\n", lcid, id, conn_info->le_psm,
+ conn_info->le_mtu, conn_info->le_mps);
+ t_le_chnl_info *le_conn_info;
+ if (conn_info->le_psm == 200)
+ {
+ printf("No Resources Available\n");
+ conn_info->result = L2CAP_LE_NO_RESOURCES;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid, conn_info);
+ return;
+ }
+ else if(conn_info->le_psm == 201)
+ {
+ printf("L2CAP_LE_CONN_INSUFFI_AUTHORIZATION \n");
+ conn_info->result = L2CAP_LE_INSUFFICIENT_AUTHORIZATION;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid, conn_info);
+ return;
+ }
+
+ le_conn_info = le_get_conn_info(conn_info->le_psm, TRUE);
+
+ if(le_conn_info)
+ {
+ le_conn_info->loc_conn_info.result = L2CAP_LE_CONN_OK;
+ le_conn_info->lcid = lcid;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid,
+ &le_conn_info->loc_conn_info);
+ memcpy(&le_conn_info->rmt_conn_info, conn_info,
+ sizeof(tL2CAP_LE_CONN_INFO));
+ g_ConnectionState = CONNECT;
+ }
+ else
+ {
+ printf("No PSM registered \n");
+ conn_info->result = L2CAP_LE_NO_PSM;
+ sL2capInterface->LeConnectRsp (bd_addr, id, lcid, conn_info);
+ return;
+ }
+}
+
+static void l2test_le_connect_cfm_cb(UINT16 lcid,
+ tL2CAP_LE_CONN_INFO *conn_info)
+{
+ t_le_chnl_info *le_conn_info;
+
+ printf(" l2test_le_connect_cfm_cb\n lcid=%u\n ls_psm %d\n le_mtu %d\n "\
+ "le_mps %d\n result %d\n",lcid, conn_info->le_psm,
+ conn_info->le_mtu, conn_info->le_mps, conn_info->result);
+
+ le_conn_info = le_get_conn_info(conn_info->le_psm, FALSE);
+
+ if (conn_info->result == L2CAP_LE_CONN_OK) {
+ g_ConnectionState = CONNECT;
+ if(le_conn_info)
+ {
+ memcpy(&le_conn_info->rmt_conn_info, conn_info,
+ sizeof(tL2CAP_LE_CONN_INFO));
+ le_conn_info->lcid = lcid;
+ }
+ }
+ else if(le_conn_info && !le_conn_info->is_server)
+ {
+ le_release_conn_info(le_conn_info);
+ }
+}
+#endif
+
+/* L2CAP callback function structure */
+static tL2CAP_APPL_INFO l2test_l2c_appl = {
+ // sizeof(l2test_l2c_appl),
+ l2test_l2c_connect_ind_cb,
+ l2test_l2c_connect_cfm_cb,
+ l2test_l2c_connect_pnd_cb,
+ l2test_l2c_config_ind_cb,
+ l2test_l2c_config_cfm_cb,
+ l2test_l2c_disconnect_ind_cb,
+ l2test_l2c_disconnect_cfm_cb,
+ l2test_l2c_QoSViolationInd,
+ l2test_l2c_data_ind_cb,
+ l2test_l2c_congestion_ind_cb,
+ l2test_l2c_tx_complete_cb
+};
+
+
+
+
+void bdt_init(void)
+{
+ bdt_log("INIT BT ");
+ status = sBtInterface->init(&bt_callbacks);
+ status = sBtInterface->set_os_callouts(&bt_os_callbacks);
+ check_return_status(status);
+}
+
+void bdt_enable(void)
+{
+ bdt_log("ENABLE BT");
+ if (bt_enabled) {
+ bdt_log("Bluetooth is already enabled");
+ return;
+ }
+ status = sBtInterface->enable(false);
+
+ check_return_status(status);
+}
+
+void bdt_disable(void)
+{
+ bdt_log("DISABLE BT");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth is already disabled");
+ return;
+ }
+ status = sBtInterface->disable();
+
+ check_return_status(status);
+}
+
+void do_pairing(char *p)
+{
+ bt_bdaddr_t bd_addr = {{0}};
+ int transport = GATT_TRANSPORT_LE;
+ if(FALSE == GetBdAddr(p, &bd_addr)) return; // arg1
+ if(BT_STATUS_SUCCESS != sBtInterface->create_bond(&bd_addr, transport))
+ {
+ printf("Failed to Initiate Pairing \n");
+ return;
+ }
+}
+
+void bdt_dut_mode_configure(char *p)
+{
+ int32_t mode = -1;
+
+ bdt_log("BT DUT MODE CONFIGURE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for test_mode to work.");
+ return;
+ }
+ mode = get_signed_int(&p, mode);
+ if ((mode != 0) && (mode != 1)) {
+ bdt_log("Please specify mode: 1 to enter, 0 to exit");
+ return;
+ }
+ status = sBtInterface->dut_mode_configure(mode);
+
+ check_return_status(status);
+}
+
+#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
+#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
+#define HCI_LE_END_TEST_OPCODE 0x201F
+
+void bdt_le_test_mode(char *p)
+{
+ int cmd;
+ unsigned char buf[3];
+ int arg1, arg2, arg3;
+
+ bdt_log("BT LE TEST MODE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for le_test to work.");
+ return;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd = get_int(&p, 0);
+ switch (cmd)
+ {
+ case 0x1: /* RX TEST */
+ arg1 = get_int(&p, -1);
+ if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
+ break;
+ case 0x2: /* TX TEST */
+ arg1 = get_int(&p, -1);
+ arg2 = get_int(&p, -1);
+ arg3 = get_int(&p, -1);
+ if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
+ bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ buf[1] = arg2;
+ buf[2] = arg3;
+ status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
+ break;
+ case 0x3: /* END TEST */
+ status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
+ break;
+ default:
+ bdt_log("Unsupported command");
+ return;
+ break;
+ }
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
+ }
+ return;
+}
+
+void bdt_cleanup(void)
+{
+ bdt_log("CLEANUP");
+ sBtInterface->cleanup();
+}
+
+/*******************************************************************************
+ ** Console commands
+ *******************************************************************************/
+
+void do_help(char *p)
+{
+ int i = 0;
+ char line[128];
+// int pos = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ snprintf(line, 128,"%s", (char*)console_cmd_list[i].name);
+ bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
+ i++;
+ }
+}
+
+void do_quit(char *p)
+{
+ bdt_shutdown();
+}
+
+/*******************************************************************
+ *
+ * BT TEST CONSOLE COMMANDS
+ *
+ * Parses argument lists and passes to API test function
+ *
+*/
+
+void do_init(char *p)
+{
+ bdt_init();
+}
+
+void do_enable(char *p)
+{
+ bdt_enable();
+}
+
+void do_disable(char *p)
+{
+ bdt_disable();
+}
+void do_dut_mode_configure(char *p)
+{
+ bdt_dut_mode_configure(p);
+}
+
+void do_le_test_mode(char *p)
+{
+ bdt_le_test_mode(p);
+}
+
+void do_cleanup(char *p)
+{
+ bdt_cleanup();
+}
+
+
+void do_le_client_register(char *p)
+{
+ bt_status_t Ret;
+ int Idx;
+ tBT_UUID uuid;
+ bt_uuid_t bt_uuid;
+
+ skip_blanks(&p);
+ Idx = atoi(p);
+
+ switch(Idx)
+ {
+ case 1:
+ uuid.len = LEN_UUID_128;
+ memcpy(&uuid.uu.uuid128, "\x00\x00\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //0000A00C-0000-0000-0123-456789ABCDEF
+ memcpy(&bt_uuid.uu, "\x00\x00\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //0000A00C-0000-0000-0123-456789ABCDEF
+ break;
+ case 2:
+ uuid.len = LEN_UUID_128;
+ memcpy(&uuid.uu.uuid128, "\x11\x22\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //1122A00C-0000-0000-0123-456789ABCDEF
+ memcpy(&bt_uuid.uu, "\x11\x22\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //1122A00C-0000-0000-0123-456789ABCDEF
+ break;
+ default:
+ printf("%s:: ERROR: no matching uuid \n", __FUNCTION__);
+ return;
+ }
+ if(Btif_gatt_layer)
+ {
+ Ret = sGattIfaceScan->client->register_client(&bt_uuid);
+ printf("%s:: ret value %d\n", __FUNCTION__,Ret);
+ }
+ else
+ {
+ g_client_if = sGattInterface->Register(&uuid, &sGattCB);
+ sleep(2);
+ sGattInterface->StartIf(g_client_if);
+ }
+}
+
+void do_le_client_deregister(char *p)
+{
+ bt_status_t Ret;
+
+ if(Btif_gatt_layer)
+ {
+ if(0 == g_client_if_scan)
+ {
+ printf("%s:: ERROR: no application registered\n", __FUNCTION__);
+ return;
+ }
+ Ret = sGattIfaceScan->client->unregister_client(g_client_if_scan);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+ }
+ else
+ {
+ if(0 == g_client_if)
+ {
+ printf("%s:: ERROR: no application registered\n", __FUNCTION__);
+ return;
+ }
+ sGattInterface->Deregister(g_client_if);
+ }
+}
+
+void do_le_client_connect (char *p)
+{
+ BOOLEAN Ret = false;
+ bt_bdaddr_t bd_addr = {{0}};
+ int transport = BT_TRANSPORT_BR_EDR;
+ transport = get_int(&p, -1);
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+
+ if(transport == BT_TRANSPORT_BR_EDR)
+ {
+ //Outgoing Connection
+
+ // g_SecLevel |= BTM_SEC_OUT_AUTHENTICATE;
+ // g_SecLevel |= BTM_SEC_OUT_ENCRYPT ;
+ g_PSM= 1;
+ g_SecLevel = 0;
+ printf("g_SecLevel = %d \n", g_SecLevel);
+ sL2capInterface->RegisterPsm(g_PSM, g_ConnType, g_SecLevel /*BTM_SEC_IN_AUTHORIZE */);
+ sleep(3);
+
+ l2c_connect(&bd_addr);
+ }
+ else if(Btif_gatt_layer)
+ {
+ Ret = sGattIfaceScan->client->connect(g_client_if_scan, &bd_addr, TRUE, transport);
+ }
+ else
+ {
+ Ret = sGattInterface->Connect(g_client_if, bd_addr.address, TRUE, transport);
+ }
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void do_le_client_refresh (char *p)
+{
+ BOOLEAN Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+
+ if(Btif_gatt_layer)
+ {
+ Ret = sGattIfaceScan->client->refresh(g_client_if_scan, &bd_addr);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+ }
+}
+
+void do_le_conn_param_update(char *p)
+{
+ BOOLEAN Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ int min_interval = 24;
+ int max_interval = 40;
+ int latency = 0;
+ int timeout = 2000;
+ min_interval = get_int(&p, -1);
+ max_interval = get_int(&p, -1);
+ latency = get_int(&p, -1);
+ if(!min_interval)
+ min_interval = 24;
+ if(!max_interval)
+ max_interval = 40;
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ Ret = sGattIfaceScan->client->conn_parameter_update(&bd_addr,min_interval,max_interval,latency,timeout);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+
+}
+
+void do_le_client_connect_auto (char *p)
+{
+ BOOLEAN Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+
+ if(Btif_gatt_layer)
+ {
+ Ret = sGattIfaceScan->client->connect(g_client_if_scan, &bd_addr, FALSE,BT_TRANSPORT_LE);
+ }
+ else
+ {
+ Ret = sGattInterface->Connect(g_client_if, bd_addr.address, FALSE,BT_TRANSPORT_LE);
+ }
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+
+void do_le_client_disconnect (char *p)
+{
+ bt_status_t Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ int transport = BT_TRANSPORT_BR_EDR;
+ transport = get_int(&p, -1);
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+
+ if(transport == BT_TRANSPORT_BR_EDR)
+ {
+ Ret = sL2capInterface->DisconnectReq(g_lcid);
+ }
+ else if(Btif_gatt_layer)
+ {
+ Ret = sGattIfaceScan->client->disconnect(g_client_if_scan, &bd_addr, g_conn_id);
+ }
+ else
+ {
+ Ret = sGattInterface->Disconnect(g_conn_id);
+ }
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_scan_start (char *p)
+{
+ bt_status_t Ret;
+ Ret = sGattIfaceScan->client->scan(TRUE);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_scan_stop (char *p)
+{
+ bt_status_t Ret;
+ Ret = sGattIfaceScan->client->scan(FALSE);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_listen_start (char *p)
+{
+ bt_status_t Ret;
+ Ret = sGattIfaceScan->client->listen(g_client_if_scan,TRUE);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_listen_stop (char *p)
+{
+ bt_status_t Ret;
+ Ret = sGattIfaceScan->client->listen(g_client_if_scan,FALSE);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_set_adv_data(char *p)
+{
+ bt_status_t Ret;
+ bool SetScanRsp = FALSE;
+ bool IncludeName = TRUE;
+ bool IncludeTxPower = FALSE;
+ int min_conn_interval = 100;
+ int max_conn_interval = 1000;
+
+ SetScanRsp = get_int(&p, -1); // arg1 Other than zero will be considered as true.
+ IncludeName = get_int(&p, -1); // arg2 Other than zero will be considered as true.
+ IncludeTxPower = get_int(&p, -1); // arg3 Other than zero will be considered as true.
+ min_conn_interval = get_int(&p, -1); // arg3 Other than zero will be considered as true.
+ max_conn_interval = get_int(&p, -1); // arg3 Other than zero will be considered as true.
+
+ //To start with we are going with hard-code values.
+ Ret = sGattIfaceScan->client->set_adv_data(/*g_server_if*/ g_server_if_scan /*g_client_if_scan*/, SetScanRsp, IncludeName, IncludeTxPower, min_conn_interval, max_conn_interval, 0,8, "QUALCOMM", 0, NULL,0,NULL);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+void do_le_client_set_adv_mode(char *p)
+{
+ tBTA_DM_DISC disc_mode;
+ tBTA_DM_CONN conn_mode;
+
+ disc_mode = get_int(&p,-1);
+ conn_mode = get_int(&p,-1);
+ printf("%s:: discoverable mode=%d connectable _mode=%d \n", __FUNCTION__,disc_mode,conn_mode );
+ sGattInterface->cSetVisibility(disc_mode,conn_mode);
+
+}
+
+void do_le_client_multi_adv_set_inst_data(char *p)
+{
+ bt_status_t Ret;
+ bool SetScanRsp = FALSE;
+ bool IncludeName = TRUE;
+ bool IncludeTxPower = TRUE;
+
+ SetScanRsp = get_int(&p, -1); // arg1 Other than zero will be considered as true.
+ IncludeName = get_int(&p, -1); // arg2 Other than zero will be considered as true.
+ IncludeTxPower = get_int(&p, -1); // arg3 Other than zero will be considered as true.
+
+ //To start with we are going with hard-code values.
+ Ret = sGattIfaceScan->client->multi_adv_set_inst_data(g_client_if_scan /*g_client_if_scan*/, SetScanRsp, IncludeName, IncludeTxPower,0,8, "QUALCOMM", 0, NULL,0,NULL);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_adv_update(char *p)
+{
+ bt_status_t Ret;
+ int TxPower = 3;
+ int chnlMap = 7;
+ int min_interval = 160;
+ int max_interval = 240;
+ int adv_type = 3 ;//non-connectable undirect
+ int adv_if = g_server_if_scan;
+ int timeout_s = 30;
+
+ adv_if = get_int(&p, -1);
+ min_interval = get_int(&p, -1);
+ max_interval = get_int(&p, -1);
+ adv_type = get_int(&p, -1);
+ chnlMap = get_int(&p, -1);
+ TxPower = get_int(&p, -1);
+ timeout_s = get_int(&p, -1);
+ //To start with we are going with hard-code values.
+ Ret = sGattIfaceScan->client->multi_adv_update(adv_if, min_interval, max_interval,adv_type,chnlMap,TxPower, timeout_s);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_client_adv_enable(char *p)
+{
+ bt_status_t Ret;
+ int TxPower = 4;
+ int chnlMap = 7;
+ int min_interval = 30;
+ int max_interval = 60;
+ int adv_type = 0; //connectable undirect
+ int adv_if = g_server_if_scan;
+ int timeout_s = 30;
+
+ adv_if = get_int(&p, -1);
+ min_interval = get_int(&p, -1);
+ max_interval = get_int(&p, -1);
+ adv_type = get_int(&p, -1);
+ chnlMap = get_int(&p, -1);
+ TxPower = get_int(&p, -1);
+ timeout_s = get_int(&p, -1);
+ Ret = sGattIfaceScan->client->multi_adv_enable(adv_if,min_interval,max_interval,adv_type,chnlMap,TxPower, timeout_s);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void do_le_client_adv_disable(char *p)
+{
+ bt_status_t Ret;
+ int adv_if = g_server_if_scan;
+
+ adv_if = get_int(&p, -1);
+ Ret = sGattIfaceScan->client->multi_adv_disable(adv_if);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void do_le_client_configureMTU(char *p)
+{
+ tGATT_STATUS Ret =0;
+ UINT16 mtu = 23;
+
+ printf("%s:: mtu :%d\n", __FUNCTION__, mtu);
+ Ret = sGattInterface->cConfigureMTU(g_conn_id, mtu);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void do_le_client_discover(char *p)
+{
+ int uuid_len = 0;
+ tGATT_STATUS Ret =0;
+ tGATT_DISC_PARAM param;
+ tGATT_DISC_TYPE disc_type; //GATT_DISC_SRVC_ALL , GATT_DISC_SRVC_BY_UUID
+
+ disc_type = get_int(&p, -1); // arg1
+ param.s_handle = get_hex(&p, -1); // arg2
+ param.e_handle = get_hex(&p, -1); // arg3
+
+ uuid_len = get_int(&p, -1); // arg4 - Size in bits for the uuid (16, 32, or 128)
+ if((16==uuid_len) || (32==uuid_len) || (128==uuid_len))
+ {
+ param.service.len = uuid_len/8;
+ }
+ else
+ {
+ printf("%s::ERROR - Invalid Parameter. UUID Len should be either 16/32/128 \n",__FUNCTION__);
+ return;
+ }
+
+ switch(param.service.len)
+ {
+ case 2: //16 bit uuid
+ param.service.uu.uuid16 = get_hex(&p, -1); // arg5
+ break;
+
+ case 4: //32 bit uuid
+ param.service.uu.uuid32 = get_hex(&p, -1); // arg5
+ break;
+
+ case 16: //128 bit uuid
+ *((unsigned int*)¶m.service.uu.uuid128[12]) = get_hex(&p, -1);
+ *((unsigned int*)¶m.service.uu.uuid128[8]) = get_hex(&p, -1);
+ *((unsigned int*)¶m.service.uu.uuid128[4]) = get_hex(&p, -1);
+ *((unsigned int*)param.service.uu.uuid128) = get_hex(&p, -1); //arg5
+
+ break;
+ default:
+ printf("%s::ERROR - Invalid Parameter. UUID Len should \n",__FUNCTION__);
+ return;
+ }
+
+ printf("%s:: disc_type = %d, uuid=%04x \n", __FUNCTION__, disc_type, param.service.uu.uuid16);
+
+ //if(FALSE == GetDiscType(p, &disc_type)) return; //TODO - add the function if user input is needed
+ Ret = sGattInterface->cDiscover(g_conn_id, disc_type, ¶m);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+
+void do_le_client_read(char *p)
+{
+ int i =0;
+ int uuid_len = 0;
+ tGATT_STATUS Ret = 0;
+ tGATT_READ_TYPE read_type;
+ int auth_req;
+ tGATT_READ_PARAM readBuf;// = {GATT_AUTH_REQ_NONE, 0x201};
+
+ //Parse and copy command line arguments
+ read_type = get_int(&p, -1); // arg2
+ auth_req = get_int(&p, -1); // arg2
+
+ switch(read_type)
+ {
+ case GATT_READ_BY_TYPE:
+ case GATT_READ_CHAR_VALUE:
+
+ readBuf.service.auth_req = auth_req;
+ readBuf.service.s_handle = get_hex(&p, -1); // arg2
+ readBuf.service.e_handle = get_hex(&p, -1); // arg3
+
+ uuid_len = get_int(&p, -1); // arg4 - Size in bits for the uuid (16, 32, or 128)
+ if((16==uuid_len) || (32==uuid_len) || (128==uuid_len))
+ {
+ readBuf.service.uuid.len = uuid_len/8;
+ }
+ else
+ {
+ printf("%s::ERROR - Invalid Parameter. UUID Len should be either 16/32/128 \n",__FUNCTION__);
+ return;
+ }
+
+ switch(readBuf.service.uuid.len)
+ {
+ case 2: //16 bit uuid
+ readBuf.service.uuid.uu.uuid16 = get_hex(&p, -1); // arg5
+ break;
+
+ case 4: //32 bit uuid
+ readBuf.service.uuid.uu.uuid32 = get_hex(&p, -1); // arg5
+ break;
+
+ case 16: //128 bit uuid
+ *((unsigned int*)&readBuf.service.uuid.uu.uuid128[12]) = get_hex(&p, -1);
+ *((unsigned int*)&readBuf.service.uuid.uu.uuid128[8]) = get_hex(&p, -1);
+ *((unsigned int*)&readBuf.service.uuid.uu.uuid128[4]) = get_hex(&p, -1);
+ *((unsigned int*)readBuf.service.uuid.uu.uuid128) = get_hex(&p, -1); //arg5
+
+ break;
+ default:
+ printf("%s::ERROR - Invalid Parameter. UUID Len should be either 4/8/32characters, which corresponds <16/32/128> bits \n",__FUNCTION__);
+ return;
+ }
+ break;
+
+
+ case GATT_READ_BY_HANDLE:
+ readBuf.by_handle.handle = get_hex(&p, -1);
+ readBuf.by_handle.auth_req = auth_req;
+ break;
+
+ case GATT_READ_MULTIPLE:
+ readBuf.read_multiple.auth_req = auth_req;
+ readBuf.read_multiple.num_handles = get_hex(&p, -1); //arg 2
+ if(readBuf.read_multiple.num_handles > 10)
+ {
+ printf(":: ERROR - invalid param. Max handle value is 10. \n");
+ return;
+ }
+ for(i=0; i<readBuf.read_multiple.num_handles; i++)
+ {
+ readBuf.read_multiple.handles[i] = get_hex(&p, -1); //arg 3 ... N
+ }
+ printf("%s:: Read by MultipleHandle \t Number of handles=%04x \n", __FUNCTION__, readBuf.read_multiple.num_handles);
+ break;
+
+ case GATT_READ_PARTIAL:
+ readBuf.partial.auth_req = auth_req;
+ readBuf.partial.handle = get_hex(&p, -1); //arg 2
+ readBuf.partial.offset = get_hex(&p, -1); //arg 3
+ printf("%s:: Read by Descriptor \t handle=%04x \t offset=%04x \n", __FUNCTION__, readBuf.partial.handle, readBuf.partial.offset);
+ break;
+
+ }
+
+ Ret = sGattInterface->cRead(g_conn_id, read_type, &readBuf);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void copy_string(char *dest, char *source)
+{
+ int i = 2;
+ while(i)
+ {
+ *dest = *source;
+ source++;
+ dest++;
+ i--;
+ }
+ *dest = '\0';
+}
+
+void do_le_client_write(char *p)
+{
+ int i;
+ tGATT_STATUS Ret = 0;
+ tGATT_WRITE_TYPE write_type;
+ int auth_req = 0;
+ tGATT_VALUE writeBuf;// = {GATT_AUTH_REQ_NONE, 0x201};
+
+ write_type = get_int(&p, -1); // arg1
+ auth_req = get_int(&p, -1); // arg2
+
+ writeBuf.conn_id = g_conn_id;
+ writeBuf.auth_req = auth_req;
+ writeBuf.handle = get_hex(&p, -1); // arg3
+ writeBuf.offset = get_hex(&p, -1); //arg4
+ writeBuf.len = get_int(&p, -1); //arg5
+
+
+ if(writeBuf.len > GATT_MAX_ATTR_LEN )
+ {
+ printf("%s:: ERROR - invalid param. Max length for Write is 600 \n",__FUNCTION__);
+ return;
+ }
+ memset(&(writeBuf.value[0]), 0, GATT_MAX_ATTR_LEN);
+ for (i = 0; i < writeBuf.len; i++)
+ {
+ writeBuf.value[i] = get_hex_byte(&p, 0);
+ }
+
+ Ret = sGattInterface->cWrite(g_conn_id, write_type, &writeBuf);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+void do_le_execute_write(char *p)
+{
+ BOOLEAN is_execute;
+ tGATT_STATUS Ret = 0;
+
+ is_execute = get_int(&p, -1); // arg1
+
+ printf("%s:: is_execute=%d \n", __FUNCTION__, is_execute);
+ Ret = sGattInterface->cExecuteWrite(g_conn_id, is_execute);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+void do_le_set_idle_timeout(char *p)
+{
+ int idle_timeout;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ idle_timeout = get_int(&p, -1); //arg2
+ sGattInterface->cSetIdleTimeout(bd_addr.address, idle_timeout);
+
+}
+
+
+/*******************************************************************************
+ ** GATT SERVER API commands
+ *******************************************************************************/
+void do_le_server_register(char *p)
+{
+ bt_status_t Ret;
+ int Idx;
+ tBT_UUID uuid;
+ bt_uuid_t bt_uuid;
+ skip_blanks(&p);
+ Idx = atoi(p);
+ switch(Idx)
+ {
+ case 1:
+ uuid.len = LEN_UUID_128;
+ memcpy(&uuid.uu.uuid128, "\x00\x00\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //0000A00C-0000-0000-0123-456789ABCDEF
+ memcpy(&bt_uuid.uu, "\x00\x00\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //0000A00C-0000-0000-0123-456789ABCDEF
+ break;
+ case 2:
+ uuid.len = LEN_UUID_128;
+ memcpy(&uuid.uu.uuid128, "\x11\x22\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //1122A00C-0000-0000-0123-456789ABCDEF
+ memcpy(&bt_uuid.uu, "\x11\x22\xA0\x0C\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //1122A00C-0000-0000-0123-456789ABCDEF
+ break;
+ default:
+ printf("%s:: ERROR: no matching uuid \n", __FUNCTION__);
+ return;
+ }
+
+ if(Btif_gatt_layer)
+ {
+ Ret = sGattIfaceScan->server->register_server(&bt_uuid);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+ }
+ else
+ {
+ g_server_if = sGattInterface->Register(&uuid, &sGattCB);
+ printf("%s:: g_server_if=%d \n", __FUNCTION__, g_server_if);
+ }
+
+}
+
+void do_le_server_deregister(char *p)
+{
+ bt_status_t Ret;
+ if(0 == g_server_if)
+ {
+ printf("%s:: ERROR: no application registered\n", __FUNCTION__);
+ return;
+ }
+ sGattInterface->Deregister(g_server_if);
+ Ret = sGattIfaceScan->server->unregister_server(g_server_if_scan);
+ printf("%s::Ret = %d\n", __FUNCTION__,Ret);
+}
+
+void do_le_server_add_service(char *p)
+{
+ bt_status_t Ret = 0;
+
+ //Later take this value as cmd line
+ btgatt_srvc_id_t srvc_id;
+ memcpy(&srvc_id.id.uuid.uu, "\x00\x00\x18\x00\x00\x00\x10\x00\x80\x00\x00\x80\x5f\x9b\x34\xfb", 16); //00001800-0000-1000-8000-00805f9b34fb
+
+
+ srvc_id.id.inst_id = 1;//
+ srvc_id.is_primary = BTGATT_SERVICE_TYPE_PRIMARY; // BTGATT_SERVICE_TYPE_SECONDARY
+ Ret = sGattIfaceScan->server->add_service(g_server_if_scan, &srvc_id, 1/*num_handles*/);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_server_connect (char *p)
+{
+ BOOLEAN Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ Ret = sGattIfaceScan->server->connect(g_server_if_scan, &bd_addr, TRUE, BT_TRANSPORT_LE);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+void do_le_server_connect_auto (char *p)
+{
+ BOOLEAN Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ Ret = sGattIfaceScan->server->connect(g_server_if_scan, &bd_addr, FALSE, BT_TRANSPORT_LE);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+
+void do_le_server_disconnect (char *p)
+{
+ bt_status_t Ret;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ Ret = sGattIfaceScan->server->disconnect(g_server_if_scan, &bd_addr, g_conn_id);
+ printf("%s:: Ret=%d \n", __FUNCTION__,Ret );
+}
+
+/**************************************************
+**L2CAP for BR/EDR conn
+***************************************************/
+
+
+
+void do_l2cap_init(char *p)
+{
+
+ memset(&tl2cap_cfg_info, 0, sizeof(tl2cap_cfg_info));
+ memset(&le_conn_info, 0, sizeof(le_conn_info));
+ //Use macros for the constants
+ tl2cap_cfg_info.mtu_present = TRUE;
+ tl2cap_cfg_info.mtu = g_imtu;
+ tl2cap_cfg_info.flush_to_present = TRUE;
+ tl2cap_cfg_info.flush_to = 0xffff;
+ //use other param if needed
+ tl2cap_cfg_info.fcr_present = g_Fcr_Present;
+ tl2cap_cfg_info.fcr.mode = g_Fcr_Mode;
+ tl2cap_cfg_info.fcs = 0;
+ tl2cap_cfg_info.fcs_present = 1;
+ le_conn_info.init_credits = L2CAP_LE_MAX_CREDIT;
+ le_conn_info.le_mtu = L2CAP_LE_DEFAULT_MTU;
+ le_conn_info.le_mps = L2CAP_LE_DEFAULT_MPS;
+ le_conn_info.le_psm = 0x80; //dynamic le psm starts from 0x80
+ if(L2CAP_FCR_ERTM_MODE == tl2cap_cfg_info.fcr.mode)
+ {
+ tl2cap_cfg_info.fcr = ertm_fcr_opts_def;
+ }
+ else if(L2CAP_FCR_STREAM_MODE == tl2cap_cfg_info.fcr.mode)
+ {
+ tl2cap_cfg_info.fcr = stream_fcr_opts_def;
+ }
+ //Load L2cap Interface
+ else if(NULL == sL2capInterface)
+ {
+ printf("Get L2cap testapp interfaces\n");
+ sL2capInterface = sBtInterface->get_testapp_interface(TEST_APP_L2CAP);
+ }
+ tl2cap_cfg_info.fcr.tx_win_sz = 3;
+ //Initialize ERTM Parameters
+ t_ertm_info.preferred_mode = g_Fcr_Mode;
+ t_ertm_info.allowed_modes = g_Ertm_AllowedMode;
+ t_ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ t_ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ t_ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ t_ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ //Load L2cap Interface
+ sL2capInterface->Init(&l2test_l2c_appl);
+}
+
+
+/*
+static int l2c_pair(char *p)
+{
+ bt_bdaddr_t bd_addr = {{0}};
+ int transport = BT_TRANSPORT_BR_EDR;
+ transport = get_int(&p, -1);
+ GetBdAddr(p, &bd_addr);
+ if(BT_STATUS_SUCCESS != sBtInterface->create_bond(&bd_addr,transport))
+ {
+ printf("Failed to Initiate Pairing \n");
+ return FALSE;
+ }
+ sleep(20);
+ return TRUE;
+}
+*/
+
+static UINT16 do_l2cap_connect(bt_bdaddr_t * bd_addr)
+{
+
+ if((L2CAP_FCR_STREAM_MODE == g_Fcr_Mode) || (L2CAP_FCR_ERTM_MODE == g_Fcr_Mode)) {
+ return sL2capInterface->ErtmConnectReq(g_PSM, bd_addr->address, &t_ertm_info);
+ } else {
+ return sL2capInterface->Connect(g_PSM, bd_addr);
+ }
+}
+
+static void l2c_connect(bt_bdaddr_t *bd_addr)
+{
+ do_l2cap_connect(bd_addr);
+}
+
+
+BOOLEAN do_l2cap_disconnect(char *p)
+{
+ return sL2capInterface->DisconnectReq(g_lcid);
+}
+
+/* LE-L2CAP functionalities */
+static t_le_chnl_info *le_allocate_conn_info(UINT16 psm, BOOLEAN is_server)
+{
+ t_le_chnl_info *p_le_chnl_info = &le_chnl_conn_info[0];
+ UINT16 i;
+
+ for (i = 0; i < MAX_L2CAP_CLIENTS; i++, p_le_chnl_info++)
+ {
+ if (!p_le_chnl_info->in_use)
+ {
+ p_le_chnl_info->in_use = TRUE;
+ p_le_chnl_info->is_server = is_server;
+ p_le_chnl_info->psm = psm;
+ return p_le_chnl_info;
+ }
+ }
+ return (NULL);
+
+}
+
+static t_le_chnl_info *le_get_conn_info(UINT16 psm, BOOLEAN is_server)
+{
+ t_le_chnl_info *p_le_chnl_info = &le_chnl_conn_info[0];
+ UINT16 i;
+
+ for (i = 0; i < MAX_L2CAP_CLIENTS; i++, p_le_chnl_info++)
+ {
+ if ((p_le_chnl_info->in_use) && (p_le_chnl_info->psm == psm)
+ && (is_server == p_le_chnl_info->is_server))
+ {
+ return p_le_chnl_info;
+ }
+ }
+ return NULL;
+
+}
+
+static t_le_chnl_info *le_get_conn_info_by_lcid(UINT16 lcid)
+{
+ t_le_chnl_info *p_le_chnl_info = &le_chnl_conn_info[0];
+ UINT16 i;
+
+ for (i = 0; i < MAX_L2CAP_CLIENTS; i++, p_le_chnl_info++)
+ {
+ if ((p_le_chnl_info->in_use) && (p_le_chnl_info->lcid == lcid))
+ {
+ return p_le_chnl_info;
+ }
+ }
+ return NULL;
+
+}
+
+static BOOLEAN le_release_conn_info(t_le_chnl_info *le_conn_info)
+{
+ if (le_conn_info && (le_conn_info->in_use))
+ {
+ le_conn_info->in_use = FALSE;
+ le_conn_info->is_server = 0;
+ le_conn_info->psm = 0;
+ memset(le_conn_info, 0, sizeof(tL2CAP_LE_CONN_INFO));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void do_start_advertisment(char *p)
+{
+ tBT_UUID uuid;
+ int option = get_int(&p, -1);
+ int start = get_int(&p, -1);
+
+ uuid.len = LEN_UUID_128;
+ memcpy(&uuid.uu.uuid128, "\x11\x22\xA0\x0D\x00\x00\x00\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF", 16); //1122A00D-0000-0000-0123-456789ABCDEF
+
+ if ((g_le_coc_if == 0) && option)
+ g_le_coc_if = sGattInterface->Register(&uuid, &sGattCB);
+ printf("Gatt Registration Done\n");
+
+ if( option)
+ {
+ if (start == 1)
+ status = sGattInterface->Listen(g_le_coc_if, start, NULL);
+ else if (start == 0)
+ status = sGattInterface->Listen(g_le_coc_if, start, NULL);
+ else
+ {
+ printf("Unknown parameter\n");
+ return;
+ }
+ }
+ else
+ {
+ if (start == 1)
+ status = sGattInterface->Listen(g_server_if_scan, start, NULL);
+ else if (start == 0)
+ status = sGattInterface->Listen(g_server_if_scan, start, NULL);
+ else
+ {
+ printf("Unknown parameter\n");
+ return;
+ }
+ }
+ printf("Gatt Listen status is %d\n", status);
+}
+
+UINT16 do_le_l2cap_coc_flow_ctrl(char *p)
+{
+ UINT16 lcid = get_int(&p, -1);
+
+ UINT16 credits = get_int(&p, -1);
+
+ printf("\ndo_le_l2cap_coc_flow_ctrl lcid = %d, credits = %d\n", lcid, credits);
+ return sL2capInterface->LeFlowControl(lcid, credits);
+}
+static void le_l2cap_coc_flow_ctrl(char *p)
+{
+ printf("In le_l2cap_coc_flow_ctrl\n");
+ do_le_l2cap_coc_flow_ctrl(p);
+}
+
+UINT16 do_le_l2cap_coc_connect(char *p)
+{
+ int le_initiator_sec_level;
+ UINT16 le_coc_seclevel = 0;
+ bt_bdaddr_t bd_addr = {{0}};
+ UINT16 le_psm = get_int(&p, -1);
+
+
+ t_le_chnl_info *le_conn_info = le_allocate_conn_info(le_psm, FALSE);
+
+ if(le_conn_info)
+ {
+ le_conn_info->loc_conn_info.le_psm = le_psm;
+ le_conn_info->loc_conn_info.le_mtu = get_int(&p, -1);
+ le_conn_info->loc_conn_info.le_mps = get_int(&p, -1);
+ le_conn_info->loc_conn_info.init_credits = get_int(&p, -1);
+ le_initiator_sec_level = get_int(&p, -1);
+ if(FALSE == GetBdAddr(p, &bd_addr)) return FALSE;
+ }
+ else
+ return FALSE;
+
+ if (le_initiator_sec_level == 0)
+ {
+ le_coc_seclevel |= BTM_SEC_NONE;
+ }
+ else if (le_initiator_sec_level == 1)
+ {
+ le_coc_seclevel |= BTM_SEC_OUT_AUTHENTICATE;
+ }
+ else if (le_initiator_sec_level == 2)
+ {
+ le_coc_seclevel |= BTM_SEC_OUT_ENCRYPT;
+ le_coc_seclevel |= BTM_SEC_OUT_AUTHENTICATE;
+ }
+ else
+ {
+ printf("Security level not supported");
+ return FALSE;
+ }
+
+ printf("g_SecLevel = %d \n", le_coc_seclevel);
+ sL2capInterface->RegisterLePsm(le_conn_info->loc_conn_info.le_psm, TRUE,
+ le_coc_seclevel, g_BleEncKeySize);
+ sleep(3);
+ local_coc_cfg.credits = le_conn_info->loc_conn_info.init_credits;
+ local_coc_cfg.mtu = le_conn_info->loc_conn_info.le_mtu;
+ local_coc_cfg.mps = le_conn_info->loc_conn_info.le_mps;
+ printf("\ndo_l2cap_connect:::::::: psm %d mtu %d mps %d init_credit %d \n",
+ le_conn_info->loc_conn_info.le_psm, le_conn_info->loc_conn_info.le_mtu,
+ le_conn_info->loc_conn_info.le_mps, le_conn_info->loc_conn_info.init_credits);
+
+ return sL2capInterface->LeConnect(le_conn_info->loc_conn_info.le_psm, ( UINT8 * )&bd_addr.address, &local_coc_cfg);
+}
+
+static void le_l2cap_coc_connect(char *svr)
+{
+ do_le_l2cap_coc_connect(svr);
+}
+
+static void le_l2cap_listen(char *p)
+{
+ int le_rspndr_sec_level;
+ UINT16 le_coc_seclevel = 0;
+ UINT16 le_psm = get_int(&p, -1);
+ t_le_chnl_info *le_conn_info = le_get_conn_info(le_psm, TRUE);
+
+ if(!le_conn_info)
+ {
+ le_conn_info = le_allocate_conn_info(le_psm, TRUE);
+ }
+ else
+ {
+ printf("ALready listening on same channel");
+ return;
+ }
+
+ if(le_conn_info)
+ {
+ le_conn_info->loc_conn_info.le_psm = le_psm;
+ le_conn_info->loc_conn_info.le_mtu = get_int(&p, -1);
+ le_conn_info->loc_conn_info.le_mps = get_int(&p, -1);
+ le_conn_info->loc_conn_info.init_credits = get_int(&p, -1);
+ le_rspndr_sec_level = get_int(&p, -1);
+ }
+ else
+ return;
+
+ if (le_rspndr_sec_level == 0)
+ {
+ le_coc_seclevel |= BTM_SEC_NONE;
+ }
+ else if (le_rspndr_sec_level == 1)
+ {
+ le_coc_seclevel |= BTM_SEC_IN_AUTHENTICATE;
+ }
+ else if (le_rspndr_sec_level == 2)
+ {
+ le_coc_seclevel |= BTM_SEC_IN_ENCRYPT;
+ le_coc_seclevel |= BTM_SEC_IN_AUTHENTICATE;
+ }
+ else
+ {
+ printf("Security level not supported");
+ return ;
+ }
+ printf("g_SecLevel = %d \n", le_coc_seclevel);
+
+ sL2capInterface->RegisterLePsm(le_conn_info->loc_conn_info.le_psm, FALSE,
+ le_coc_seclevel, g_BleEncKeySize);
+
+ printf("Waiting for Incoming connection for LE PSM %d... \n",
+ le_conn_info->loc_conn_info.le_psm);
+}
+
+UINT8 do_l2cap_DataWrite(UINT16 chnl_id, char *p , UINT32 len)
+{
+ return sL2capInterface->DataWrite(chnl_id, p, len);
+}
+
+static int send_file(char *p)
+{
+ uint32_t seq = 0, itration = 1;
+ int fd, size;
+ char filename[] = {0};
+ char tmpBuf[LE_ACL_MAX_BUFF_SIZE];
+ UINT16 lcid;
+
+ lcid = get_int(&p, -1);
+ t_le_chnl_info *le_conn_info = le_get_conn_info_by_lcid(lcid);
+ GetFileName(p, filename);
+
+ if(!le_conn_info)
+ {
+ printf("No conn info, exit \n");
+ return FALSE;
+ }
+
+ g_omtu = le_conn_info->rmt_conn_info.le_mtu;
+
+ if(g_omtu < LE_ACL_MAX_BUFF_SIZE)
+ data_size = g_omtu;
+ else
+ data_size = LE_ACL_MAX_BUFF_SIZE;
+
+ printf("data_size(max patload size) = %ld, g_omtu(max ttansmission unit) = %d",
+ data_size, g_omtu);
+
+ printf("Filename for input data = %s \n", filename);
+
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ {
+ printf("Open failed: %s (%d)\n", strerror(errno), errno);
+ exit(1);
+ }
+ while (1)
+ {
+ while(cong_status)
+ {
+ usleep(50 * 1000);
+ }
+ if((size = read(fd, tmpBuf, data_size)) <= 0)
+ {
+ printf("\n File end ");
+ break;
+ }
+ printf("Sending data :: itration %d, omtu %d, writing data size %d\n",
+ itration, g_omtu, size);
+ do_l2cap_DataWrite(lcid, tmpBuf, size);
+ itration++;
+ }
+
+ if (num_frames && g_delay && count && !(seq % count))
+ usleep(g_delay);
+ return TRUE;
+}
+
+static int Send_Data(char *p)
+{
+ //uint32_t seq =0;
+ int send_mode;
+ UINT16 lcid;
+
+ lcid = get_int(&p, -1);
+ send_mode = get_int(&p, -1);
+
+ char tmpBuffer_1[] = {
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F
+ };
+ char tmpBuffer_2[] = {
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F
+ };
+
+ if(send_mode == 1) // segmented
+ {
+ printf("Sending Segmented data...\nData written len %d...\n",
+ sizeof(tmpBuffer_1) );
+ do_l2cap_DataWrite(lcid, tmpBuffer_1, sizeof(tmpBuffer_1));
+ }
+ else if( send_mode == 0) // unsegmented
+ {
+ printf("Sending Unsegmented data...\nData written len %d...\n",
+ sizeof(tmpBuffer_2) );
+ do_l2cap_DataWrite(lcid, tmpBuffer_2, sizeof(tmpBuffer_2));
+ }
+ return TRUE;
+}
+
+static void send_data_on_le_coc(char *svr)
+{
+ printf("Sending data on LE L2CAP CoC...\n");
+ Send_Data(svr);
+}
+static void do_send_file(char *svr)
+{
+ printf("Sending file on LE L2CAP CoC...\n");
+ send_file(svr);
+}
+
+BOOLEAN le_coc_disc(char *p)
+{
+ UINT16 cid = get_int(&p, -1);
+ return sL2capInterface->DisconnectReq(cid);
+}
+
+static void do_le_coc_disconnect(char *p)
+{
+ le_coc_disc(p);
+}
+
+/*******************************************************************************
+ ** SMP API commands
+ *******************************************************************************/
+void do_smp_init(char *p)
+{
+ sSmpIface->init();
+ sleep(1);
+ sSmpIface->Register(SMP_cb);
+ sleep(1);
+}
+
+void do_smp_pair(char *p)
+{
+ tSMP_STATUS Ret = 0;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ Ret = sSmpIface->Pair(bd_addr.address);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void do_smp_pair_cancel(char *p)
+{
+ BOOLEAN Ret = 0;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return;
+ Ret = sSmpIface->PairCancel(bd_addr.address);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+void do_smp_security_grant(char *p)
+{
+ UINT8 res;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return; //arg1
+ res = get_int(&p, -1); // arg2
+ sSmpIface->SecurityGrant(bd_addr.address, res);
+ printf("%s:: Ret=%d \n", __FUNCTION__,res);
+}
+
+void do_smp_passkey_reply(char *p)
+{
+ UINT32 passkey;
+ UINT8 res;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return; //arg1
+ printf("get res value\n");
+ res = get_int(&p, -1); // arg2
+ printf("res value=%d\n", res);
+ passkey = get_int(&p, -1); // arg3
+ printf("passkey value=%d\n", passkey);
+ sSmpIface->PasskeyReply(bd_addr.address, res, passkey);
+ printf("%s:: Ret=%d \n", __FUNCTION__,res);
+}
+
+void do_smp_encrypt(char *p)
+{
+ BOOLEAN Ret = 0;
+ UINT8 res;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return; //arg1
+ res = get_int(&p, -1); // arg2
+ printf("%s:: res =%d Ret=%d \n", __FUNCTION__,res, Ret);
+}
+
+void do_le_gap_conn_param_update(char *p)
+{
+ //attr_uuid = get_int(&p, -1);
+ tGAP_BLE_ATTR_VALUE attr_value;
+ attr_value.conn_param.int_min = 50;
+ attr_value.conn_param.int_max = 70;
+ attr_value.conn_param.latency = 0;
+ attr_value.conn_param.sp_tout = 10;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return; //arg1
+ //attr_uuid = get_hex(&p, -1);
+ //L2CA_UpdateBleConnParams(bd_addr.address, 50, 70, 0, 1000);
+ printf("stage 1\n");
+ sGapInterface->Gap_BleAttrDBUpdate(bd_addr.address, attr_value.conn_param.int_min, attr_value.conn_param.int_max,attr_value.conn_param.latency ,attr_value.conn_param.sp_tout);
+ printf("%s:: GAP connection parameter Update\n", __FUNCTION__);
+
+}
+void do_le_gap_attr_init(char *p)
+{
+ sGapInterface->Gap_AttrInit();
+ printf("%s:: GAP Initialization\n", __FUNCTION__);
+
+}
+/*
+void do_le_gap_set_disc(char *p)
+{
+ UINT16 Ret = 0;
+ UINT16 mode;
+ UINT16 duration;
+ UINT16 interval;
+
+ mode = get_int(&p, -1);
+ if(1 == mode) mode = GAP_NON_DISCOVERABLE;
+ else if(2 == mode) mode = GAP_LIMITED_DISCOVERABLE;
+ else mode = GAP_GENERAL_DISCOVERABLE;
+
+ duration = get_int(&p, -1);
+ if((12 > duration) || (duration > 1000)) duration = 0; //if 0 is passed, stack will take 12 as default
+
+ interval = get_int(&p, -1);
+ if((12 > interval) || (interval > 1000)) interval = 0; //if 0 is passed, stack will take 800 as default
+
+
+
+ sGapInterface->Gap_SetDiscoverableMode(mode, duration, interval);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+}
+
+void do_le_gap_set_conn(char *p)
+{
+ UINT16 Ret=0;
+ UINT16 mode;
+ UINT16 duration;
+ UINT16 interval;
+
+ mode = get_int(&p, -1);
+ if(1 == mode)
+ mode = GAP_NON_CONNECTABLE;
+ else
+ mode = GAP_CONNECTABLE;
+
+ duration = get_int(&p, -1);
+ if((12 > duration) || (duration > 1000)) duration = 0; //if 0 is passed, stack will take 12 as default
+
+ interval = get_int(&p, -1);
+ if((12 > interval) || (interval > 1000)) interval = 0; //if 0 is passed, stack will take 800 as default
+
+ sGapInterface->Gap_SetConnectableMode(mode, duration, interval);
+ printf("%s:: Ret=%d\n", __FUNCTION__, Ret);
+}
+*/
+void do_l2cap_send_data_cid(char *p)
+{
+ UINT16 cid = 0;
+ BT_HDR bt_hdr;
+ UINT16 Ret = 0;
+ bt_bdaddr_t bd_addr = {{0}};
+ if(FALSE == GetBdAddr(p, &bd_addr)) return; //arg1
+ cid = get_int(&p, -1); // arg2
+
+ bt_hdr.event = 0;
+ bt_hdr.len = 1;
+ bt_hdr.offset = 0;
+ bt_hdr.layer_specific = 0;
+
+
+ Ret = sL2capInterface->SendFixedChnlData(cid, bd_addr.address, &bt_hdr);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+
+}
+/*******************************************************************
+ *
+ * CONSOLE COMMAND TABLE
+ *
+*/
+
+const t_cmd console_cmd_list[] =
+{
+ /*
+ * INTERNAL
+ */
+
+ { "help", do_help, "lists all available console commands", 0 },
+ { "quit", do_quit, "", 0},
+
+ /*
+ * API CONSOLE COMMANDS
+ */
+
+ /* Init and Cleanup shall be called automatically */
+ { "enable", do_enable, ":: enables bluetooth", 0 },
+ { "disable", do_disable, ":: disables bluetooth", 0 },
+ { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
+ { "c_register", do_le_client_register, "::UUID: 1<1111..> 2<12323..> 3<321111..>", 0 },
+ { "c_deregister", do_le_client_deregister, "::UUID: 1<1111..> 2<12323..> 3<321111..>", 0 },
+ { "c_connect", do_le_client_connect, ":: transport-type<0,1...> , BdAddr<00112233445566>", 0 },
+ { "c_refresh", do_le_client_refresh, ":: BdAddr<00112233445566>", 0 },
+ { "c_conn_param_update", do_le_conn_param_update, ":: int min_interval, int max_interval,int latency, BdAddr<00112233445566>", 0 },
+ { "c_connect_auto", do_le_client_connect_auto, ":: BdAddr<00112233445566>", 0 },
+ { "c_disconnect", do_le_client_disconnect, ":: BdAddr<00112233445566>", 0 },
+ { "c_configureMTU", do_le_client_configureMTU, ":: 23", 0 },
+ { "c_discover", do_le_client_discover, "type(1-PrimaryService, 2-PrimaryService using UUID, 3-Included Service, 4-Characteristic, 5-Characteristic Descriptor) \
+ \n\t s.handle(hex) e.handle(hex) UUIDLen(16/32/128) UUID(hex)", 0 },
+ { "c_read", do_le_client_read, "Type(1-ByType, 2-ByHandle, 3-ByMultiple, 4-CharValue, 5-Partial (blob)) Auth_Req \
+ \n\t ByType :: s.handle(hex) e.handle(hex) UUIDLen(16/32/128) UUID(hex) \
+ \n\t ByHandle :: Handle(hex) \
+ \n\t ByMultiple :: NumOfHandle<1-10> Handle_1(hex) Handle_2(hex) ... Handle_N(hex) \
+ \n\t CharValue :: s.handle(hex) e.handle(hex) UUIDLen(16/32/128) UUID(hex) \
+ \n\t Partial/Blob :: Handle(hex) Offset(hex)", 0 },
+ { "c_write", do_le_client_write, "Type(1-No response, 2-write, 3-prepare write), Auth_req, Handle, Offset, Len(0-600), Value(hex)", 0 },
+ { "c_execute_write", do_le_execute_write, "is_execute", 0 },
+ { "c_scan_start", do_le_client_scan_start, "::", 0 },
+ { "c_scan_stop", do_le_client_scan_stop, "::", 0 },
+ { "c_listen_start", do_le_client_listen_start, "::", 0 },
+ { "c_listen_stop", do_le_client_listen_stop, "::", 0 },
+ { "c_set_adv_mode", do_le_client_set_adv_mode, ":: Discoverability mode,Connectable_mode,", 0 },
+ { "c_set_adv_data", do_le_client_set_adv_data, "::EnableScanrsp<0/1>, IncludeName<0/1> IncludeTxPower<0/1>,min_conn_interval,int max_conn_interval", 0 },
+ { "c_set_multi_adv_data", do_le_client_multi_adv_set_inst_data, "::EnableScanrsp<0/1>, IncludeName<0/1> IncludeTxPower<0/1>", 0 },
+ { "start_advertising", do_le_client_adv_enable, "::int client_if,int min_interval,int max_interval,int adv_type,int chnl_map, int tx_power timeout",0},
+ { "c_adv_update", do_le_client_adv_update, "::int client_if, int min_interval,int max_interval,int adv_type,int chnl_map, int tx_power, int timeout",0},
+ { "stop_advertising", do_le_client_adv_disable, "::int adv_if",0},
+ { "c_set_idle_timeout", do_le_set_idle_timeout, "bd_addr, time_out(int)", 0 },
+ { "c_gap_attr_init", do_le_gap_attr_init, "::", 0 },
+ { "c_gap_conn_param_update", do_le_gap_conn_param_update, "::", 0 },
+
+ { "s_register", do_le_server_register, "::UUID: 1<1111..> 2<12323..> 3<321111..>", 0 },
+ { "s_connect", do_le_server_connect, ":: BdAddr<00112233445566>", 0 },
+ { "s_connect_auto", do_le_server_connect_auto, ":: BdAddr<00112233445566>", 0 },
+ { "s_disconnect", do_le_server_disconnect, ":: BdAddr<00112233445566>", 0 },
+ { "s_add_service", do_le_server_add_service, "::", 0 },
+
+ { "pair", do_pairing, ":: BdAddr<00112233445566>", 0 },
+
+ { "smp_init", do_smp_init, "::", 0 }, //Here itself we will register.
+ { "smp_pair", do_smp_pair, ":: BdAddr<00112233445566>", 0 },
+ { "smp_pair_cancel", do_smp_pair_cancel, ":: BdAddr<00112233445566>", 0 },
+ { "smp_security_grant", do_smp_security_grant, ":: BdAddr<00112233445566>, res<>", 0 },
+ { "smp_passkey_reply", do_smp_passkey_reply, ":: BdAddr<00112233445566>, res<>, passkey<>", 0 },
+ //{ "smp_encrypt", do_smp_encrypt, "::", 0 },
+ { "l2cap_send_data_cid", do_l2cap_send_data_cid, ":: BdAddr<00112233445566>, CID<>", 0 },
+
+ { "set_local_name", do_set_localname, ":: setName<name>", 0 },
+ /* LE-L2CAP cmds */
+ { " ", NULL, "\n\t\t\033[0m\033[34mLE L2CAP CoC Commands\033[0m", 0 },
+ { " ", NULL, "\033[0m\033[34mCommands\t\t\tParameters\033[0m", 0 },
+
+ { "start_adv", do_start_advertisment, "\t\t::\tuuid [0 - register"\
+ "none (or) 1 - register uuid] , \n\t\t\t\tflag [0- stop adv (or) "\
+ "1 - start adv] \n " , 0},
+
+ { "le_l2cap_listen", le_l2cap_listen, "\t::\tle_psm [1 to 255], "\
+ "\n\t\t\t\tle_mtu [23 to 65535], \n\t\t\t\tle_mps [23 to 65533],"\
+ " \n\t\t\t\tinit_credits [0 to 65535], \n\t\t\t\tsec_level "\
+ "[0 - None, 1 - Authentication, 2 - Auth and Encryption]", 0},
+
+ { "le_l2cap_coc_connect", le_l2cap_coc_connect, "\t::\tle_psm [128 to 255],"\
+ "\n\t\t\t\tle_mtu [23 to 65535], \n\t\t\t\tle_mps [23 to 65533], "\
+ "\n\t\t\t\tinit_credits [0 to 65535], \n\t\t\t\tsec_level [0 - None,"\
+ " 1 - Authentication, 2 - Encryption], \n\t\t\t\tbd_addr [001122334455] ", 0},
+
+ { "le_l2cap_coc_flow_ctrl", le_l2cap_coc_flow_ctrl, "\t::\tchnl_id [chnl id"\
+ "info from conn_ind or conn_cnf], \n\t\t\t\tcredits [1 to 65535]", 0},
+
+ { "send_data_on_le_coc", send_data_on_le_coc, "\t::\tchnl_id [chnl id info "\
+ "from conn_ind or conn_cnf] , \n\t\t\t\tdata_type [0 - Unsegmented data ,"\
+ "1 - Segmented data]", 0},
+
+ { "send_file", do_send_file, "\t\t::\tchnl_id [chnl_id info from conn_ind"\
+ "or conn_cnf], \n\t\t\t\tfile_name", 0},
+
+ { "le_coc_disconnect", do_le_coc_disconnect, "\t::\tchnl_id [chnl_id info"\
+ "from conn_ind or conn_cnf]", 0},
+ /* add here */
+
+ /* last entry */
+ {NULL, NULL, "", 0},
+};
+
+/*
+ * Main console command handler
+*/
+
+static void process_cmd(char *p, unsigned char is_job)
+{
+ char cmd[2048];
+ int i = 0;
+ bt_pin_code_t pincode;
+ char *p_saved = p;
+
+ get_str(&p, cmd);
+
+ /* table commands */
+ while (console_cmd_list[i].name != NULL)
+ {
+ if (is_cmd(console_cmd_list[i].name))
+ {
+ if (!is_job && console_cmd_list[i].is_job)
+ create_cmdjob(p_saved);
+ else
+ {
+ console_cmd_list[i].handler(p);
+ }
+ return;
+ }
+ i++;
+ }
+ //pin key
+ if(cmd[6] == '.') {
+ for(i=0; i<6; i++) {
+ pincode.pin[i] = cmd[i];
+ }
+ pincode.pin[i] = '\0';
+ if(BT_STATUS_SUCCESS != sBtInterface->pin_reply(remote_bd_address, TRUE, strlen((const char*)pincode.pin), &pincode)) {
+ printf("Pin Reply failed\n");
+ }
+ else
+ printf("Pin Reply done and paired\n");
+ //flush the char for pinkey
+ cmd[6] = 0;
+ }
+ else {
+ bdt_log("%s : unknown command\n", p_saved);
+ do_help(NULL);
+ }
+}
+
+int main (int argc, char * argv[])
+{
+ static btgatt_callbacks_t sGatt_cb = {sizeof(btgatt_callbacks_t), &sGattClient_cb, &sGattServer_cb};
+
+ config_permissions();
+ bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
+ bdt_log(":: Bluedroid test app starting");
+
+ if ( HAL_load() < 0 ) {
+ perror("HAL failed to initialize, exit\n");
+ unlink(PID_FILE);
+ exit(0);
+ }
+
+ setup_test_env();
+
+ /* Automatically perform the init */
+ bdt_init();
+ sleep(5);
+ bdt_enable();
+ sleep(5);
+ bdt_log("Get SMP IF BT Interface = %x \n", sBtInterface);
+ sGattInterface = sBtInterface->get_testapp_interface(TEST_APP_GATT);
+ sSmpIface = sBtInterface->get_testapp_interface(TEST_APP_SMP);
+ bdt_log("Get GAP IF");
+ sGapInterface = sBtInterface->get_testapp_interface(TEST_APP_GAP);
+
+ bdt_log("Get GATT IF");
+ sGattIfaceScan = sBtInterface->get_profile_interface(BT_PROFILE_GATT_ID);
+
+ bdt_log("Get L2CAP IF");
+ sL2capInterface = sBtInterface->get_testapp_interface(TEST_APP_L2CAP);
+
+ sGattIfaceScan->init(&sGatt_cb);
+ bdt_log("GATT IF INIT Done");
+
+ printf("\n Before l2cap init\n");
+ do_l2cap_init(NULL);
+ printf("\n after l2cap init\n");
+
+ while(!main_done)
+ {
+ char line[2048];
+
+ /* command prompt */
+ printf( ">" );
+ fflush(stdout);
+
+ fgets (line, 2048, stdin);
+
+ if (line[0]!= '\0')
+ {
+ /* remove linefeed */
+ line[strlen(line)-1] = 0;
+
+ process_cmd(line, 0);
+ memset(line, '\0', 2048);
+ }
+ }
+
+ /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
+ //bdt_cleanup();
+
+ HAL_unload();
+
+ bdt_log(":: Bluedroid test app terminating");
+
+ return 0;
+}
+int GetFileName(char *p, char *filename)
+{
+// uint8_t i;
+ int len;
+
+ skip_blanks(&p);
+
+ printf("Input file name = %s\n", p);
+
+ if (p == NULL)
+ {
+ printf("\nInvalid File Name... Please enter file name\n");
+ return FALSE;
+ }
+ len = strlen(p);
+
+ memcpy(filename, p, len);
+ filename[len] = '\0';
+
+ return TRUE;
+}
+int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr)
+{
+ char Arr[13] = {0};
+ char *pszAddr = NULL;
+ uint8_t k1 = 0;
+ uint8_t k2 = 0;
+ uint8_t i;
+
+ skip_blanks(&p);
+
+ printf("Input=%s\n", p);
+
+ if(12 > strlen(p))
+ {
+ printf("\nInvalid Bd Address. Format[112233445566]\n");
+ return FALSE;
+ }
+ memcpy(Arr, p, 12);
+
+ for(i=0; i<12; i++)
+ {
+ Arr[i] = tolower(Arr[i]);
+ }
+ pszAddr = Arr;
+
+ for(i=0; i<6; i++)
+ {
+ k1 = (uint8_t) ( (*pszAddr >= 'a') ? ( 10 + (uint8_t)( *pszAddr - 'a' )) : (*pszAddr - '0') );
+ pszAddr++;
+ k2 = (uint8_t) ( (*pszAddr >= 'a') ? ( 10 + (uint8_t)( *pszAddr - 'a' )) : (*pszAddr - '0') );
+ pszAddr++;
+
+ if ( (k1>15)||(k2>15) )
+ {
+ return FALSE;
+ }
+ pbd_addr->address[i] = (k1<<4 | k2);
+ }
+ return TRUE;
+}
+#endif //TEST_APP_INTERFACE
diff --git a/test/bluedroidtest/Android.mk b/test/bluedroidtest/Android.mk
new file mode 100644
index 0000000..aeea6fa
--- /dev/null
+++ b/test/bluedroidtest/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ bluedroidtest.c
+
+LOCAL_C_INCLUDES :=
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+LOCAL_CFLAGS += -std=c99
+
+LOCAL_CFLAGS += -std=c99
+
+LOCAL_MODULE_TAGS := debug optional
+
+LOCAL_MODULE:= bdt
+
+LOCAL_SHARED_LIBRARIES += libcutils \
+ libhardware \
+ libhardware_legacy
+
+LOCAL_MULTILIB := 32
+
+include $(BUILD_EXECUTABLE)
diff --git a/test/bluedroidtest/README.txt b/test/bluedroidtest/README.txt
new file mode 100644
index 0000000..0a47050
--- /dev/null
+++ b/test/bluedroidtest/README.txt
@@ -0,0 +1,88 @@
+Bluedroid Test Application
+==========================
+The test application provides a small console shell interface that allows
+access to the Bluetooth HAL API library though ASCII commands. This is similar
+to how the real JNI service would operate. The primary objective of this
+application is to allow Bluetooth to be put in DUT Mode for RF/BB BQB test purposes.
+
+This application is mutually exclusive with the Java based Bluetooth.apk. Hence
+before launching the application, it should be ensured that the Settings->Bluetooth is OFF.
+
+This application is built as 'bdt' and shall be available in '/system/bin/bdt'
+
+Limitations
+===========
+1.) Settings->Bluetooth must be OFF for this application to work
+2.) Currently, only the SIG 'HCI Test Mode' commands are supported. The vendor
+specific HCI test mode commands to be added.
+
+Usage instructions
+==================
+The following section describes the various commands and their usage
+
+Launching the test application
+==============================
+$ adb shell
+root@android:/ # /system/bin/bdt
+set_aid_and_cap : pid 1183, uid 0 gid 0
+:::::::::::::::::::::::::::::::::::::::::::::::::::
+:: Bluedroid test app starting
+Loading HAL lib + extensions
+HAL library loaded (Success)
+INIT BT
+HAL REQUEST SUCCESS
+
+Enabling Bluetooth
+==================
+>enable
+ENABLE BT
+HAL REQUEST SUCCESS
+>ADAPTER STATE UPDATED : ON
+
+Enabling Test Mode (Bluetooth must be enabled for this command to work)
+======================================================================
+>dut_mode_configure 1
+BT DUT MODE CONFIGURE
+HAL REQUEST SUCCESS
+>
+
+Disabling Test Mode
+===================
+>dut_mode_configure 0
+BT DUT MODE CONFIGURE
+HAL REQUEST SUCCESS
+>
+
+Running BLE Test commands (Bluetooth must be enabled)
+=====================================================
+NOTE: Unlike BR/EDR, there is no explicit DUT mode to run these BLE tests.
+
+> le_test_mode 1 <rx_freq>
+
+> le_test_mode 2 <tx_freq> <test_data_len> <payload_pattern>
+
+> le_test_mode 3 <no_args>
+Please refer to the BT Core spec pages-1099 to 1102 for possible values for
+the above parameters. These values need to be provided in Decimal format.
+
+Exit the test application
+=========================
+>quit
+shutdown bdroid test app
+Unloading HAL lib
+HAL library unloaded (Success)
+:: Bluedroid test app terminating
+
+Help (Lists the available commands)
+===================================
+>help
+help lists all available console commands
+
+quit
+enable :: enables bluetooth
+disable :: disables bluetooth
+dut_mode_configure :: DUT mode - 1 to enter,0 to exit
+le_test_mode :: LE Test Mode - RxTest - 1 <rx_freq>,
+ TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>,
+ End Test - 3 <no_args>
+
diff --git a/test/bluedroidtest/bluedroidtest.c b/test/bluedroidtest/bluedroidtest.c
new file mode 100644
index 0000000..114ec0b
--- /dev/null
+++ b/test/bluedroidtest/bluedroidtest.c
@@ -0,0 +1,937 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: bluedroidtest.c
+ *
+ * Description: Bluedroid Test application
+ *
+ ***********************************************************************************/
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/bluetooth.h>
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define PID_FILE "/data/.bdt_pid"
+#define DEVICE_DISCOVERY_TIMEOUT 20
+
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+#define UNUSED __attribute__((unused))
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static unsigned char main_done = 0;
+static bt_status_t status;
+
+/* Main API */
+static bluetooth_device_t* bt_device;
+
+const bt_interface_t* sBtInterface = NULL;
+
+static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
+ AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
+ AID_NET_ADMIN, AID_VPN};
+
+/* Set to 1 when the Bluedroid stack is enabled */
+static unsigned char bt_enabled = 0;
+static int deviceCount;
+static int wantMore = 0;
+pthread_mutex_t deviceCount_mutex;
+pthread_cond_t deviceCount_cond;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+static void process_cmd(char *p, unsigned char is_job);
+static void job_handler(void *param);
+static void bdt_log(const char *fmt_str, ...);
+static void discover_device(void *arg);
+
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+
+/************************************************************************************
+** Shutdown helper functions
+************************************************************************************/
+
+static void bdt_shutdown(void)
+{
+ bdt_log("shutdown bdroid test app\n");
+ main_done = 1;
+}
+
+
+/*****************************************************************************
+** Android's init.rc does not yet support applying linux capabilities
+*****************************************************************************/
+
+static void config_permissions(void)
+{
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap[2];
+
+ bdt_log("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
+
+ header.pid = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setuid(AID_BLUETOOTH);
+ setgid(AID_BLUETOOTH);
+
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ capset(&header, &cap[0]);
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+}
+
+
+
+/*****************************************************************************
+** Logger API
+*****************************************************************************/
+
+void bdt_log(const char *fmt_str, ...)
+{
+ static char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt_str);
+ vsnprintf(buffer, 1024, fmt_str, ap);
+ va_end(ap);
+
+ fprintf(stdout, "%s\n", buffer);
+}
+
+/*******************************************************************************
+ ** Misc helper functions
+ *******************************************************************************/
+static const char* dump_bt_status(bt_status_t status)
+{
+ switch(status)
+ {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown status code";
+ }
+}
+
+static void hex_dump(char *msg, void *data, int size, int trunc)
+{
+ unsigned char *p = data;
+ unsigned char c;
+ int n;
+ char bytestr[4] = {0};
+ char addrstr[10] = {0};
+ char hexstr[ 16*3 + 5] = {0};
+ char charstr[16*1 + 5] = {0};
+
+ bdt_log("%s \n", msg);
+
+ /* truncate */
+ if(trunc && (size>32))
+ size = 32;
+
+ for(n=1;n<=size;n++) {
+ if (n%16 == 1) {
+ /* store address for this line */
+ snprintf(addrstr, sizeof(addrstr), "%.4x",
+ (unsigned int)((uintptr_t)p-(uintptr_t)data) );
+ }
+
+ c = *p;
+ if (isalnum(c) == 0) {
+ c = '.';
+ }
+
+ /* store hex str (for left side) */
+ snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
+ strlcat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
+
+ /* store char str (for right side) */
+ snprintf(bytestr, sizeof(bytestr), "%c", c);
+ strlcat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
+
+ if(n%16 == 0) {
+ /* line completed */
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ } else if(n%8 == 0) {
+ /* half line: add whitespaces */
+ strlcat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
+ strlcat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
+ }
+ p++; /* next byte */
+ }
+
+ if (strlen(hexstr) > 0) {
+ /* print rest of buffer if not empty */
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ }
+}
+
+/*******************************************************************************
+ ** Console helper functions
+ *******************************************************************************/
+
+void skip_blanks(char **p)
+{
+ while (**p == ' ')
+ (*p)++;
+}
+
+uint32_t get_int(char **p, int DefaultValue)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+int get_signed_int(char **p, int DefaultValue)
+{
+ int Value = 0;
+ unsigned char UseDefault;
+ unsigned char NegativeNum = 0;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ if ( (**p) == '-')
+ {
+ NegativeNum = 1;
+ (*p)++;
+ }
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return ((NegativeNum == 0)? Value : -Value);
+}
+
+void get_str(char **p, char *Buffer)
+{
+ skip_blanks(p);
+
+ while (**p != 0 && **p != ' ')
+ {
+ *Buffer = **p;
+ (*p)++;
+ Buffer++;
+ }
+
+ *Buffer = 0;
+}
+
+uint32_t get_hex(char **p, int DefaultValue)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ( ((**p)<= '9' && (**p)>= '0') ||
+ ((**p)<= 'f' && (**p)>= 'a') ||
+ ((**p)<= 'F' && (**p)>= 'A') )
+ {
+ if (**p >= 'a')
+ Value = Value * 16 + (**p) - 'a' + 10;
+ else if (**p >= 'A')
+ Value = Value * 16 + (**p) - 'A' + 10;
+ else
+ Value = Value * 16 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
+ char *d = ((char *)bd), *endp;
+ int i;
+ for(i = 0; i < 6; i++) {
+ *d++ = strtol(str, &endp, 16);
+ if (*endp != ':' && i != 5) {
+ memset(bd, 0, sizeof(bt_bdaddr_t));
+ return;
+ }
+ str = endp + 1;
+ }
+}
+
+#define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
+#define if_cmd(str) if (is_cmd(str))
+
+typedef void (t_console_cmd_handler) (char *p);
+
+typedef struct {
+ const char *name;
+ t_console_cmd_handler *handler;
+ const char *help;
+ unsigned char is_job;
+} t_cmd;
+
+
+const t_cmd console_cmd_list[];
+static int console_cmd_maxlen = 0;
+
+static void cmdjob_handler(void *param)
+{
+ char *job_cmd = (char*)param;
+
+ bdt_log("cmdjob starting (%s)", job_cmd);
+
+ process_cmd(job_cmd, 1);
+
+ bdt_log("cmdjob terminating");
+
+ free(job_cmd);
+}
+
+static int create_cmdjob(char *cmd)
+{
+ pthread_t thread_id;
+ char *job_cmd;
+
+ job_cmd = malloc(strlen(cmd)+1); /* freed in job handler */
+ if (job_cmd)
+ {
+ strlcpy(job_cmd, cmd, strlen(cmd)+1);
+
+ if (pthread_create(&thread_id, NULL,
+ (void*)cmdjob_handler, (void*)job_cmd)!=0)
+ perror("pthread_create");
+ }
+ else
+ {
+ perror("create_cmdjob(): Failed to allocate memory");
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ ** Load stack lib
+ *******************************************************************************/
+
+int HAL_load(void)
+{
+ int err = 0;
+
+ hw_module_t* module;
+ hw_device_t* device;
+
+ bdt_log("Loading HAL lib + extensions");
+
+ err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0)
+ {
+ err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (err == 0) {
+ bt_device = (bluetooth_device_t *)device;
+ sBtInterface = bt_device->get_bluetooth_interface();
+ }
+ }
+
+ bdt_log("HAL library loaded (%s)", strerror(err));
+
+ return err;
+}
+
+int HAL_unload(void)
+{
+ int err = 0;
+
+ bdt_log("Unloading HAL lib");
+
+ sBtInterface = NULL;
+
+ bdt_log("HAL library unloaded (%s)", strerror(err));
+
+ return err;
+}
+
+/*******************************************************************************
+ ** HAL test functions & callbacks
+ *******************************************************************************/
+
+void setup_test_env(void)
+{
+ int i = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
+ i++;
+ }
+}
+
+void check_return_status(bt_status_t status)
+{
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
+ }
+ else
+ {
+ bdt_log("HAL REQUEST SUCCESS");
+ }
+}
+
+static void adapter_state_changed(bt_state_t state)
+{
+ bdt_log("ADAPTER STATE UPDATED : %s", (state == BT_STATE_OFF)?"OFF":"ON");
+ if (state == BT_STATE_ON) {
+ bt_enabled = 1;
+ } else {
+ bt_enabled = 0;
+ }
+}
+
+static void dut_mode_recv(uint16_t UNUSED opcode, uint8_t UNUSED *buf, uint8_t UNUSED len)
+{
+ bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
+}
+
+static void le_test_mode(bt_status_t status, uint16_t packet_count)
+{
+ bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
+}
+
+static void device_found_cb(int num_properties, bt_property_t *properties)
+{
+ int i;
+ for (i = 0; i < num_properties; i++)
+ {
+ if (properties[i].type == BT_PROPERTY_BDNAME)
+ {
+ bdt_log("Device name is : %s\n",
+ (char*)properties[i].val);
+ }
+ if (properties[i].type == BT_PROPERTY_REMOTE_RSSI)
+ {
+ pthread_mutex_lock(&deviceCount_mutex);
+ deviceCount++;
+ bdt_log("Device RSSI VALUE is :%d\n",
+ *(signed char*)properties[i].val);
+ if (deviceCount > 0 && wantMore == 0)
+ {
+ pthread_cond_signal(&deviceCount_cond);
+ }
+ pthread_mutex_unlock(&deviceCount_mutex);
+ }
+ }
+}
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed,
+ NULL, /* adapter_properties_cb */
+ NULL, /* remote_device_properties_cb */
+ device_found_cb, /* device_found_cb */
+ NULL, /* discovery_state_changed_cb */
+ NULL, /* pin_request_cb */
+ NULL, /* ssp_request_cb */
+ NULL, /* bond_state_changed_cb */
+ NULL, /* acl_state_changed_cb */
+ NULL, /* thread_evt_cb */
+ dut_mode_recv, /* dut_mode_recv_cb */
+#if BLE_INCLUDED == TRUE
+ le_test_mode, /* le_test_mode_cb */
+#else
+ NULL, /* le_test_mode_cb */
+#endif
+ NULL, /* energy_info_cb */
+ NULL /* hci_event_recv_cb */
+};
+
+static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data) {
+ static timer_t timer;
+ static bool timer_created;
+
+ if (!timer_created) {
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))cb;
+ sigevent.sigev_value.sival_ptr = data;
+ timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
+ timer_created = true;
+ }
+
+ struct itimerspec new_value;
+ new_value.it_value.tv_sec = delay_millis / 1000;
+ new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
+ new_value.it_interval.tv_sec = 0;
+ new_value.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &new_value, NULL);
+
+ return true;
+}
+
+static int acquire_wake_lock(const char *lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock(const char *lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t callouts = {
+ sizeof(bt_os_callouts_t),
+ set_wake_alarm,
+ acquire_wake_lock,
+ release_wake_lock,
+};
+
+void bdt_init(void)
+{
+ bdt_log("INIT BT ");
+ status = sBtInterface->init(&bt_callbacks);
+
+ if (status == BT_STATUS_SUCCESS) {
+ status = sBtInterface->set_os_callouts(&callouts);
+ }
+
+ check_return_status(status);
+}
+
+void bdt_enable(void)
+{
+ bdt_log("ENABLE BT");
+ if (bt_enabled) {
+ bdt_log("Bluetooth is already enabled");
+ return;
+ }
+ status = sBtInterface->enable(false);
+
+ check_return_status(status);
+}
+
+void bdt_disable(void)
+{
+ bdt_log("DISABLE BT");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth is already disabled");
+ return;
+ }
+ status = sBtInterface->disable();
+
+ check_return_status(status);
+}
+void bdt_dut_mode_configure(char *p)
+{
+ int32_t mode = -1;
+
+ bdt_log("BT DUT MODE CONFIGURE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for test_mode to work.");
+ return;
+ }
+ mode = get_signed_int(&p, mode);
+ if ((mode != 0) && (mode != 1)) {
+ bdt_log("Please specify mode: 1 to enter, 0 to exit");
+ return;
+ }
+ status = sBtInterface->dut_mode_configure(mode);
+
+ check_return_status(status);
+}
+
+#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
+#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
+#define HCI_LE_END_TEST_OPCODE 0x201F
+
+void bdt_le_test_mode(char *p)
+{
+ int cmd;
+ unsigned char buf[3];
+ int arg1, arg2, arg3;
+
+ bdt_log("BT LE TEST MODE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for le_test to work.");
+ return;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd = get_int(&p, 0);
+ switch (cmd)
+ {
+ case 0x1: /* RX TEST */
+ arg1 = get_int(&p, -1);
+ if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
+ break;
+ case 0x2: /* TX TEST */
+ arg1 = get_int(&p, -1);
+ arg2 = get_int(&p, -1);
+ arg3 = get_int(&p, -1);
+ if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
+ bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ buf[1] = arg2;
+ buf[2] = arg3;
+ status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
+ break;
+ case 0x3: /* END TEST */
+ status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
+ break;
+ default:
+ bdt_log("Unsupported command");
+ return;
+ break;
+ }
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
+ }
+ return;
+}
+
+void bdt_cleanup(void)
+{
+ bdt_log("CLEANUP");
+ sBtInterface->cleanup();
+}
+
+/*******************************************************************************
+ ** Console commands
+ *******************************************************************************/
+
+void do_help(char UNUSED *p)
+{
+ int i = 0;
+ int max = 0;
+ char line[128];
+ int pos = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ pos = sprintf(line, "%s", (char*)console_cmd_list[i].name);
+ bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
+ i++;
+ }
+}
+
+void do_quit(char UNUSED *p)
+{
+ bdt_shutdown();
+}
+
+/*******************************************************************
+ *
+ * BT TEST CONSOLE COMMANDS
+ *
+ * Parses argument lists and passes to API test function
+ *
+*/
+
+void do_init(char UNUSED *p)
+{
+ bdt_init();
+}
+
+void do_enable(char UNUSED *p)
+{
+ bdt_enable();
+}
+
+void do_disable(char UNUSED *p)
+{
+ bdt_disable();
+}
+void do_dut_mode_configure(char *p)
+{
+ bdt_dut_mode_configure(p);
+}
+
+void do_le_test_mode(char *p)
+{
+ bdt_le_test_mode(p);
+}
+
+void do_cleanup(char UNUSED *p)
+{
+ bdt_cleanup();
+}
+
+/*******************************************************************
+ *
+ * CONSOLE COMMAND TABLE
+ *
+*/
+
+const t_cmd console_cmd_list[] =
+{
+ /*
+ * INTERNAL
+ */
+
+ { "help", do_help, "lists all available console commands", 0 },
+ { "quit", do_quit, "", 0},
+
+ /*
+ * API CONSOLE COMMANDS
+ */
+
+ /* Init and Cleanup shall be called automatically */
+ { "enable", do_enable, ":: enables bluetooth", 0 },
+ { "disable", do_disable, ":: disables bluetooth", 0 },
+ { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
+ { "le_test_mode", do_le_test_mode, ":: LE Test Mode - RxTest - 1 <rx_freq>, \n\t \
+ TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, \n\t \
+ End Test - 3 <no_args>", 0 },
+ /* add here */
+
+ /* last entry */
+ {NULL, NULL, "", 0},
+};
+
+/*
+ * Main console command handler
+*/
+
+static void process_cmd(char *p, unsigned char is_job)
+{
+ char cmd[64];
+ int i = 0;
+ char *p_saved = p;
+
+ get_str(&p, cmd);
+
+ /* table commands */
+ while (console_cmd_list[i].name != NULL)
+ {
+ if (is_cmd(console_cmd_list[i].name))
+ {
+ if (!is_job && console_cmd_list[i].is_job)
+ create_cmdjob(p_saved);
+ else
+ {
+ console_cmd_list[i].handler(p);
+ }
+ return;
+ }
+ i++;
+ }
+ bdt_log("%s : unknown command\n", p_saved);
+ do_help(NULL);
+}
+
+static void discover_device(void *arg)
+{
+ struct timespec ts = {0, 0};
+ ts.tv_sec = time(NULL) + DEVICE_DISCOVERY_TIMEOUT;
+
+ sBtInterface->start_discovery();
+ pthread_mutex_lock(&deviceCount_mutex);
+ pthread_cond_timedwait(&deviceCount_cond, &deviceCount_mutex, &ts);
+ if (deviceCount == 0)
+ {
+ bdt_log("No device found\n");
+ }
+ else
+ {
+ deviceCount = 0;
+ }
+ pthread_mutex_unlock(&deviceCount_mutex);
+ wantMore = 0;
+ bdt_log("Cancelling discovery\n");
+ sBtInterface->cancel_discovery();
+ pthread_exit(0);
+}
+
+int main (int UNUSED argc, char UNUSED *argv[])
+{
+ int opt;
+ char cmd[128];
+ int args_processed = 0;
+ int pid = -1;
+ int enable_wait_count = 0;
+ pthread_t discoveryThread;
+
+ config_permissions();
+ bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
+ bdt_log(":: Bluedroid test app starting");
+
+ if ( HAL_load() < 0 ) {
+ perror("HAL failed to initialize, exit\n");
+ unlink(PID_FILE);
+ exit(0);
+ }
+
+ setup_test_env();
+ pthread_mutex_init(&deviceCount_mutex, NULL);
+ pthread_cond_init (&deviceCount_cond, NULL);
+
+ /* Automatically perform the init */
+ bdt_init();
+ if (argc > 1)
+ {
+ bdt_log("Command line mode\n");
+ if (strncmp(argv[1],"get_ap_list",11) == 0) {
+ wantMore = 1;
+ } else if (strncmp(argv[1],"get_a_device",12) == 0) {
+ wantMore = 0;
+ } else {
+ bdt_log("Unrecognised command");
+ goto cleanup;
+ }
+ bdt_log("Enabling BT for 45 seconds\n");
+ bdt_enable();
+ do {
+ if (bt_enabled)
+ break;
+ bdt_log("Waiting for bt_enabled to become true\n");
+ sleep(2);
+ } while(enable_wait_count++ < 10);
+
+ if (bt_enabled) {
+ pthread_create(&discoveryThread, NULL, (void*)discover_device, NULL);
+ pthread_join(discoveryThread, NULL);
+ } else {
+ bdt_log("Failed to enable BT\n");
+ goto cleanup;
+ }
+ bdt_log("Disabling BT\n");
+ bdt_disable();
+ goto cleanup;
+ }
+ while(!main_done)
+ {
+ char line[128];
+
+ /* command prompt */
+ printf( ">" );
+ fflush(stdout);
+
+ fgets (line, 128, stdin);
+
+ if (line[0]!= '\0')
+ {
+ /* remove linefeed */
+ line[strlen(line)-1] = 0;
+
+ process_cmd(line, 0);
+ memset(line, '\0', 128);
+ }
+ }
+
+ /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
+ //bdt_cleanup();
+cleanup:
+ HAL_unload();
+
+ pthread_mutex_destroy(&deviceCount_mutex);
+ pthread_cond_destroy(&deviceCount_cond);
+
+ bdt_log(":: Bluedroid test app terminating");
+
+ return 0;
+}
diff --git a/test/l2test_ertm/Android.mk b/test/l2test_ertm/Android.mk
new file mode 100644
index 0000000..4355ab1
--- /dev/null
+++ b/test/l2test_ertm/Android.mk
@@ -0,0 +1,31 @@
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= l2test_ertm.c
+
+LOCAL_C_INCLUDES += . \
+ $(LOCAL_PATH)/../../stack/include \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../stack/l2cap \
+ $(LOCAL_PATH)/../../utils/include \
+ $(LOCAL_PATH)/../../ \
+ $(LOCAL_PATH)/btif/include \
+ $(bluetooth_C_INCLUDES)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug optional
+LOCAL_MODULE:= l2test_ertm
+
+LOCAL_SHARED_LIBRARIES += libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy
+
+LOCAL_MULTILIB := 32
+
+include $(BUILD_EXECUTABLE)
diff --git a/test/l2test_ertm/l2test_ertm.c b/test/l2test_ertm/l2test_ertm.c
new file mode 100644
index 0000000..123042d
--- /dev/null
+++ b/test/l2test_ertm/l2test_ertm.c
@@ -0,0 +1,1310 @@
+/******************************************************************************
+ ** Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: l2test_ertm.c
+ *
+ * Description: Bluedroid L2CAP TOOL application
+ *
+ ***********************************************************************************/
+
+#include "l2c_api.h"
+#include <bt_testapp.h>
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <signal.h>
+#include <time.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "bt_target.h"
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/bluetooth.h>
+
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define PID_FILE "/data/.bdt_pid"
+
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define TRANSPORT_BREDR 1 //Add tranport parameter to create bond
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+enum {
+ DISCONNECT,
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTING
+};
+
+static int g_ConnectionState = DISCONNECT;
+static int g_AdapterState = BT_STATE_OFF;
+static int g_PairState = BT_BOND_STATE_NONE;
+static UINT16 g_SecLevel = 0;
+static BOOLEAN g_SecOnlyMode = FALSE;
+static int g_secvalue = 0;
+static BOOLEAN g_ConnType = TRUE;//DUT is initiating connection
+static BOOLEAN g_Fcr_Present = FALSE;
+static bool g_Sar_Present = FALSE;
+static bool strict_mode = FALSE;
+static UINT8 g_Fcr_Mode = L2CAP_FCR_BASIC_MODE;
+static UINT8 g_Ertm_AllowedMode = (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | L2CAP_FCR_CHAN_OPT_STREAM);
+static int g_LocalBusy = 0;
+
+enum {
+ BT_TURNON_CMD,
+ BT_TURNOFF_CMD,
+ I_CONNECT_CMD,
+ O_CONNECT_CMD,
+ DISCONNECT_CMD,
+ SEND_DATA_CMD,
+ O_PAIR_CMD
+};
+
+enum {
+ SEND,
+ RECEIVE,
+ WAITANDSEND,
+ PAIR,
+ PING,
+ CONNECT,
+};
+
+static unsigned char *buf;
+/* Default mtu */
+static int g_imtu = 672;
+static int g_omtu = 0;
+
+
+/* Default data size */
+static long data_size = -1;
+static long buffer_size = 2048;
+
+static int master = 0;
+static int auth = 0;
+static int encrypt = 0;
+static int secure_m4_l4 = 0;
+/* Default number of frames */
+static int num_frames = 1;
+static int count = 1;
+
+/* Default delay before data transfer */
+static unsigned long g_delay = 1;
+
+static char *filename = NULL;
+
+
+/* Control channel eL2CAP default options */
+tL2CAP_FCR_OPTS ertm_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE,
+ 3, /* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ 2000, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ 100 /* MPS segment size */
+};
+
+tL2CAP_FCR_OPTS stream_fcr_opts_def = {
+ L2CAP_FCR_STREAM_MODE,
+ 3,/* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ 2000, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ 100 /* MPS segment size */
+};
+static tL2CAP_ERTM_INFO t_ertm_info = {0,0,0,0,0,0};
+
+UINT8 do_l2cap_DataWrite(char *p , UINT32 len);
+
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static unsigned char main_done = 0;
+static bt_status_t status;
+
+/* Main API */
+static bluetooth_device_t* bt_device;
+
+const bt_interface_t* sBtInterface = NULL;
+
+static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
+ AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
+ AID_NET_ADMIN, AID_VPN};
+
+
+const btl2cap_interface_t *sL2capInterface = NULL;
+
+enum {
+L2CAP_NOT_CONNECTED,
+L2CAP_CONN_SETUP,
+L2CAP_CONNECTED
+};
+
+static int L2cap_conn_state = L2CAP_NOT_CONNECTED;
+static tL2CAP_CFG_INFO tl2cap_cfg_info;
+static UINT16 g_PSM = 0;
+static UINT16 g_lcid = 0;
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+static int Send_Data();
+static int WaitForCompletion(int Cmd, int Timeout);
+
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+
+//--------------------l2test----------------------------------------------------
+btl2cap_interface_t* get_l2cap_interface(void);
+
+
+
+static void l2test_l2c_connect_ind_cb(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
+{
+
+ if((L2CAP_FCR_ERTM_MODE == g_Fcr_Mode) || (L2CAP_FCR_STREAM_MODE == g_Fcr_Mode)) {
+ sL2capInterface->ErtmConnectRsp(bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, &t_ertm_info);
+ } else {
+ sL2capInterface->ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+ }
+ {
+ tL2CAP_CFG_INFO cfg;
+ memcpy (&cfg ,&tl2cap_cfg_info,sizeof(tl2cap_cfg_info));
+ if ((!sL2capInterface->ConfigReq (lcid, &cfg)) && cfg.fcr_present
+ && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcr_present = FALSE;
+ sL2capInterface->ConfigReq (lcid, &cfg);
+ }
+ }
+ g_ConnectionState = CONNECT;
+ g_lcid = lcid;
+}
+
+static void l2test_l2c_connect_cfm_cb(UINT16 lcid, UINT16 result)
+{
+
+ if (result == L2CAP_CONN_OK) {
+ L2cap_conn_state = L2CAP_CONN_SETUP;
+ tL2CAP_CFG_INFO cfg;
+ memcpy (&cfg ,&tl2cap_cfg_info,sizeof(tl2cap_cfg_info));
+ sL2capInterface->ConfigReq (lcid, &cfg);
+ g_imtu = cfg.mtu;
+ g_ConnectionState = CONNECT;
+ g_lcid = lcid;
+ }
+}
+
+static void l2test_l2c_connect_pnd_cb(UINT16 lcid)
+{
+ g_ConnectionState = CONNECTING;
+}
+static void l2test_l2c_config_ind_cb(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+ p_cfg->result = L2CAP_CFG_OK;
+ p_cfg->fcr_present = FALSE;
+ if(p_cfg->mtu_present) g_omtu = p_cfg->mtu;
+ else g_omtu = L2CAP_DEFAULT_MTU;
+ sL2capInterface->ConfigRsp (lcid, p_cfg);
+ return;
+}
+
+static void l2test_l2c_config_cfm_cb(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ printf("\nl2test_l2c_config_cfm_cb Success\n");
+ } else {
+
+ /* If peer has rejected FCR and suggested basic then try basic */
+ if (p_cfg->fcr_present) {
+ tL2CAP_CFG_INFO cfg;
+ memcpy (&cfg ,&tl2cap_cfg_info,sizeof(tl2cap_cfg_info));
+ cfg.fcr_present = FALSE;
+ sL2capInterface->ConfigReq (lcid, &cfg);
+ // Remain in configure state
+ return;
+ }
+ sL2capInterface->DisconnectReq(lcid);
+ }
+ if(0 == g_omtu) g_omtu = L2CAP_DEFAULT_MTU;
+}
+
+static void l2test_l2c_disconnect_ind_cb(UINT16 lcid, BOOLEAN ack_needed)
+{
+ if (ack_needed)
+ {
+ /* send L2CAP disconnect response */
+ sL2capInterface->DisconnectRsp(lcid);
+ }
+ g_ConnectionState = DISCONNECTING;
+ g_lcid = 0;
+}
+static void l2test_l2c_disconnect_cfm_cb(UINT16 lcid, UINT16 result)
+{
+ g_ConnectionState = DISCONNECT;
+ g_lcid = 0;
+}
+static void l2test_l2c_QoSViolationInd(BD_ADDR bd_addr)
+{
+ printf("l2test_l2c_QoSViolationInd\n");
+}
+static void l2test_l2c_data_ind_cb(UINT16 lcid, BT_HDR *p_buf)
+{
+ printf("l2test_l2c_data_ind_cb:: event=%u, len=%u, offset=%u, layer_specific=%u\n", p_buf->event, p_buf->len, p_buf->offset, p_buf->layer_specific);
+}
+static void l2test_l2c_congestion_ind_cb(UINT16 lcid, BOOLEAN is_congested)
+{
+ printf("l2test_l2c_congestion_ind_cb\n");
+}
+
+static void l2test_l2c_tx_complete_cb (UINT16 lcid, UINT16 NoOfSDU)
+{
+ printf("l2test_l2c_tx_complete_cb, cid=0x%x, SDUs=%u\n", lcid, NoOfSDU);
+}
+
+static void l2c_echo_rsp_cb(UINT16 p)
+{
+ printf("Ping Response = %s\n", (L2CAP_PING_RESULT_OK==p) ?"Ping Reply OK" :(L2CAP_PING_RESULT_NO_LINK==p) ?"Link Could Not be setup" :"Remote L2cap did not reply");
+}
+
+/* L2CAP callback function structure */
+static tL2CAP_APPL_INFO l2test_l2c_appl = {
+ // sizeof(l2test_l2c_appl),
+ l2test_l2c_connect_ind_cb,
+ l2test_l2c_connect_cfm_cb,
+ l2test_l2c_connect_pnd_cb,
+ l2test_l2c_config_ind_cb,
+ l2test_l2c_config_cfm_cb,
+ l2test_l2c_disconnect_ind_cb,
+ l2test_l2c_disconnect_cfm_cb,
+ l2test_l2c_QoSViolationInd,
+ l2test_l2c_data_ind_cb,
+ l2test_l2c_congestion_ind_cb,
+ l2test_l2c_tx_complete_cb
+};
+
+
+/************************************************************************************
+** Shutdown helper functions
+************************************************************************************/
+
+static void bdt_shutdown(void)
+{
+ printf("shutdown bdroid test app\n");
+ main_done = 1;
+}
+
+
+/*****************************************************************************
+** Android's init.rc does not yet support applying linux capabilities
+*****************************************************************************/
+
+static void config_permissions(void)
+{
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap[2];
+
+ printf("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
+
+ header.pid = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setuid(AID_BLUETOOTH);
+ setgid(AID_BLUETOOTH);
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ capset(&header, &cap[0]);
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+}
+
+
+
+/*****************************************************************************
+** Logger API
+*****************************************************************************/
+
+
+/*******************************************************************************
+ ** Console helper functions
+ *******************************************************************************/
+
+void skip_blanks(char **p)
+{
+ while (**p == ' ')
+ (*p)++;
+}
+
+#define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
+#define if_cmd(str) if (is_cmd(str))
+
+typedef void (t_console_cmd_handler) (char *p);
+
+typedef struct {
+ const char *name;
+ t_console_cmd_handler *handler;
+ const char *help;
+ unsigned char is_job;
+} t_cmd;
+
+
+#if 0
+static void cmdjob_handler(void *param)
+{
+ char *job_cmd = (char*)param;
+
+ // process_cmd(job_cmd, 1);
+ free(job_cmd);
+}
+
+static int create_cmdjob(char *cmd)
+{
+ pthread_t thread_id;
+ char *job_cmd;
+
+ job_cmd = malloc(strlen(cmd)+1); /* freed in job handler */
+ if (job_cmd) {
+ strlcpy(job_cmd, cmd, sizeof(job_cmd));
+
+ if (pthread_create(&thread_id, NULL,
+ (void*)cmdjob_handler, (void*)job_cmd)!=0)
+ perror("pthread_create");
+ }
+
+ return 0;
+}
+#endif
+
+/*******************************************************************************
+ ** Load stack lib
+ *******************************************************************************/
+
+int HAL_load(void)
+{
+ int err = 0;
+
+ hw_module_t* module;
+ hw_device_t* device;
+
+ err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0)
+ {
+ err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (err == 0) {
+ bt_device = (bluetooth_device_t *)device;
+ sBtInterface = bt_device->get_bluetooth_interface();
+ }
+ }
+
+ return err;
+}
+
+int HAL_unload(void)
+{
+ int err = 0;
+
+ sBtInterface = NULL;
+
+ return err;
+}
+
+/*******************************************************************************
+ ** HAL test functions & callbacks
+ *******************************************************************************/
+#if 0
+void setup_test_env(void)
+{
+ int i = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
+ i++;
+ }
+}
+#endif
+
+void check_return_status(bt_status_t status)
+{
+ if (status != BT_STATUS_SUCCESS)
+ {
+ printf("HAL REQUEST FAILED\n");
+ }
+ else
+ {
+ printf("\nHAL REQUEST SUCCESS");
+ }
+}
+
+static void adapter_state_changed(bt_state_t state)
+{
+
+ int V1 = 1000, V2=2;
+ bt_property_t property = {9 /*BT_PROPERTY_DISCOVERY_TIMEOUT*/, 4, &V1};
+ bt_property_t property1 = {7 /*SCAN*/, 2, &V2};
+ bt_property_t property2 ={1,6,"Amith"};
+ g_AdapterState = state;
+
+ if (state == BT_STATE_ON) {
+ status = sBtInterface->set_adapter_property(&property1);
+ status = sBtInterface->set_adapter_property(&property);
+ status = sBtInterface->set_adapter_property(&property2);
+ }
+}
+
+static void adapter_properties_changed(bt_status_t status, int num_properties, bt_property_t *properties)
+{
+
+ char Bd_addr[15] = {0};
+ if(NULL == properties) {
+ return;
+ }
+ switch(properties->type)
+ {
+ case BT_PROPERTY_BDADDR:
+ memcpy(Bd_addr, properties->val, properties->len);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static void discovery_state_changed(bt_discovery_state_t state)
+{
+ printf("Discovery State Updated : %s\n", (state == BT_DISCOVERY_STOPPED)?"STOPPED":"STARTED");
+}
+
+#if 0
+static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name, uint32_t cod)
+{
+
+ int ret = 0;
+ bt_pin_code_t pincode = {{ 0x31, 0x32, 0x33, 0x34}};
+
+ if(BT_STATUS_SUCCESS != sBtInterface->pin_reply(remote_bd_addr, TRUE, 4, &pincode)) {
+ printf("Pin Reply failed\n");
+ }
+}
+#endif
+static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant, uint32_t pass_key)
+{
+ if(BT_STATUS_SUCCESS != sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, TRUE, pass_key)) {
+ printf("SSP Reply failed\n");
+ }
+}
+
+static void bond_state_changed_cb(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_bond_state_t state)
+{
+
+ g_PairState = state;
+}
+
+static void acl_state_changed(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_acl_state_t state)
+{
+}
+
+
+static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+ printf("DUT MODE RECEIVE : NOT IMPLEMENTED\n");
+}
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed,
+ adapter_properties_changed, /*adapter_properties_cb */
+ NULL, /* remote_device_properties_cb */
+ NULL, /* device_found_cb */
+ discovery_state_changed, /* discovery_state_changed_cb */
+ NULL, /* pin_request_cb */
+ ssp_request_cb, /* ssp_request_cb */
+ bond_state_changed_cb, /*bond_state_changed_cb */
+ acl_state_changed, /* acl_state_changed_cb */
+ NULL, /* thread_evt_cb */
+ dut_mode_recv, /*dut_mode_recv_cb */
+ NULL, /*le_test_mode_cb*/
+ NULL, /*energy_info_cb */
+ NULL, /*get_testapp_interface */
+};
+
+static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data) {
+ static timer_t timer;
+ static bool timer_created;
+
+ if (!timer_created) {
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))cb;
+ sigevent.sigev_value.sival_ptr = data;
+ timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
+ timer_created = true;
+ }
+
+ struct itimerspec new_value;
+ new_value.it_value.tv_sec = delay_millis / 1000;
+ new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
+ new_value.it_interval.tv_sec = 0;
+ new_value.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &new_value, NULL);
+
+ return true;
+}
+
+static int acquire_wake_lock(const char *lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock(const char *lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t callouts = {
+ sizeof(bt_os_callouts_t),
+ set_wake_alarm,
+ acquire_wake_lock,
+ release_wake_lock,
+};
+
+
+void bdt_init(void)
+{
+ printf("INIT BT \n");
+ status = sBtInterface->init(&bt_callbacks);
+ if (status == BT_STATUS_SUCCESS) {
+ status = sBtInterface->set_os_callouts(&callouts);
+ }
+ check_return_status(status);
+}
+
+void bdt_enable(void)
+{
+ //int status = 0;
+ printf("ENABLE BT\n");
+ if (BT_STATE_ON == g_AdapterState) {
+ printf("Bluetooth is already enabled\n");
+ return;
+ }
+ status = sBtInterface->enable(strict_mode);
+ return;
+}
+
+void bdt_disable(void)
+{
+ if (BT_STATE_ON != g_AdapterState)
+ {
+ return;
+ }
+ status = sBtInterface->disable();
+ check_return_status(status);
+ return;
+}
+
+void bdt_cleanup(void)
+{
+ sBtInterface->cleanup();
+}
+
+btl2cap_interface_t* get_l2cap_interface(void)
+{
+ if ((sBtInterface)&&(sBtInterface->get_testapp_interface)) {
+ return (btl2cap_interface_t *) sBtInterface->get_testapp_interface(TEST_APP_L2CAP);
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ ** Console commands
+ *******************************************************************************/
+
+void do_quit(char *p)
+{
+ bdt_shutdown();
+}
+
+/*******************************************************************
+ *
+ * BT TEST CONSOLE COMMANDS
+ *
+ * Parses argument lists and passes to API test function
+ *
+*/
+
+void do_init(char *p)
+{
+ bdt_init();
+}
+
+BOOLEAN do_enable(char *p)
+{
+ bdt_enable();
+ if(0 != WaitForCompletion(BT_TURNON_CMD, 10))
+ {
+ printf("BT Turn ON Failed... Exiting...\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN do_disable(char *p)
+{
+ bdt_disable();
+ if(0 != WaitForCompletion(BT_TURNOFF_CMD, 10))
+ {
+ printf("BT Turn OFF Failed... Exiting...\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void do_cleanup(char *p)
+{
+ // bdt_cleanup();
+}
+
+int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr)
+{
+ char Arr[13] = {0};
+ UINT8 k1 = 0;
+ UINT8 k2 = 0;
+ int i;
+
+ if(12 != strlen(p))
+ {
+ printf("\nInvalid Bd Address. Format[112233445566]\n");
+ return FALSE;
+ }
+ strlcpy(Arr, p, sizeof(Arr));
+ for(i=0; i<12; i++)
+ {
+ Arr[i] = tolower(Arr[i]);
+ }
+ for(i=0; i<6; i++)
+ {
+ k1 = (UINT8) ( (Arr[i*2] >= 'a') ? ( 10 + (UINT8)( Arr[i*2] - 'a' )) : (Arr[i*2] - '0') );
+ k2 = (UINT8) ( (Arr[i*2+1] >= 'a') ? ( 10 + (UINT8)( Arr[i*2+1] - 'a' )) : (Arr[i*2+1] - '0') );
+ if ( (k1>15)||(k2>15) )
+ {
+ return FALSE;
+ }
+ pbd_addr->address[i] = (k1<<4 | k2);
+ }
+ return TRUE;
+}
+
+void do_l2cap_init(char *p)
+{
+
+
+ memset(&tl2cap_cfg_info, 0, sizeof(tl2cap_cfg_info));
+ //Use macros for the constants
+ tl2cap_cfg_info.mtu_present = TRUE;
+ tl2cap_cfg_info.mtu = g_imtu;
+ tl2cap_cfg_info.flush_to_present = TRUE;
+ tl2cap_cfg_info.flush_to = 0xffff;
+ //use other param if needed
+ tl2cap_cfg_info.fcr_present = g_Fcr_Present;
+ tl2cap_cfg_info.fcr.mode = g_Fcr_Mode;
+ tl2cap_cfg_info.fcs = 0;
+ tl2cap_cfg_info.fcs_present = 1;
+
+ tl2cap_cfg_info.fcr.tx_win_sz = 3;
+ if(L2CAP_FCR_ERTM_MODE == tl2cap_cfg_info.fcr.mode)
+ {
+ tl2cap_cfg_info.fcr = ertm_fcr_opts_def;
+ }
+ else if(L2CAP_FCR_STREAM_MODE == tl2cap_cfg_info.fcr.mode)
+ {
+ tl2cap_cfg_info.fcr = stream_fcr_opts_def;
+ }
+ //Initialize ERTM Parameters
+ t_ertm_info.preferred_mode = g_Fcr_Mode;
+ t_ertm_info.allowed_modes = g_Ertm_AllowedMode;
+ t_ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ t_ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ t_ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ t_ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ //Load L2cap Interface
+ if(NULL == sL2capInterface)
+ {
+ sL2capInterface = get_l2cap_interface();
+ }
+ if (sL2capInterface)
+ sL2capInterface->Init(&l2test_l2c_appl);
+}
+
+void do_l2cap_deregister(char *p)
+{
+
+ sL2capInterface->Deregister(g_PSM);
+}
+
+UINT16 do_l2cap_connect(char *p)
+{
+
+ bt_bdaddr_t bd_addr = {{0}};
+ GetBdAddr(p, &bd_addr);
+
+ if((L2CAP_FCR_STREAM_MODE == g_Fcr_Mode) || (L2CAP_FCR_ERTM_MODE == g_Fcr_Mode)) {
+ return sL2capInterface->ErtmConnectReq(g_PSM,(uint8_t *)&bd_addr.address, &t_ertm_info);
+ } else {
+ return sL2capInterface->Connect(g_PSM, &bd_addr);
+ }
+}
+
+BOOLEAN do_l2cap_ping(char *p)
+{
+
+ bt_bdaddr_t bd_addr = {{0}};
+ GetBdAddr(p, &bd_addr);
+ if(FALSE == sL2capInterface->Ping(bd_addr.address, l2c_echo_rsp_cb)) {
+ printf("Failed to send Ping Request \n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+BOOLEAN do_l2cap_disconnect(char *p)
+{
+ return sL2capInterface->DisconnectReq(g_lcid);
+}
+
+UINT8 do_l2cap_DataWrite(char *p , UINT32 len)
+{
+ return sL2capInterface->DataWrite(g_lcid, p, len);
+}
+
+void do_l2cap_SetSecConnOnlyMode(BOOLEAN secvalue)
+{
+ sL2capInterface->SetSecConnOnlyMode(secvalue);
+}
+static int WaitForCompletion(int Cmd, int Timeout)
+{
+ int Status = 0xFF;
+ int *pState = NULL;
+ switch(Cmd)
+ {
+ case BT_TURNON_CMD:
+ Status = BT_STATE_ON;
+ pState = &g_AdapterState;
+ break;
+ case BT_TURNOFF_CMD:
+ Status = BT_STATE_OFF;
+ pState = &g_AdapterState;
+ break;
+ case I_CONNECT_CMD:
+ Status = CONNECT;
+ pState = &g_ConnectionState;
+ break;
+ case O_CONNECT_CMD:
+ Status = CONNECT;
+ pState = &g_ConnectionState;
+ break;
+ case DISCONNECT_CMD:
+ Status = DISCONNECT;
+ pState = &g_ConnectionState;
+ break;
+ case SEND_DATA_CMD:
+ //
+ break;
+ case O_PAIR_CMD:
+ Status = BT_BOND_STATE_BONDED;
+ pState = &g_PairState;
+ break;
+ }
+ if(NULL == pState)
+ return 0xFF;
+ while( (Status != *pState) && (Timeout--) )
+ {
+ sleep(1);
+ }
+ if(Status != *pState)
+ return 1; //Timeout
+ else
+ return 0; //Success
+}
+
+static void l2c_listen(int SendData)
+{
+ printf("Waiting for Incoming connection... \n");
+ if(0 != WaitForCompletion(I_CONNECT_CMD, 60))
+ {
+ printf("No incoming connection... Exiting...\n");
+ return;
+ }
+ if(TRUE == SendData)
+ {
+ printf(" going to send data...\n");
+ Send_Data();
+ }
+}
+
+static int Send_Data()
+{
+ int fd, size;
+ char *tmpBuf = NULL;
+
+ if (data_size < 0)
+ data_size = g_omtu;
+ printf("data_size = %ld, g_omtu=%d", data_size, g_omtu);
+
+ tmpBuf = malloc(data_size);
+ if(NULL == tmpBuf)
+ {
+ printf("Malloc failed \n");
+ return FALSE;
+ }
+ if (filename) {
+ fd = open(filename, O_RDONLY);
+ printf("Filename for input data = %s \n", filename);
+ if (fd < 0) {
+ printf("Open failed: %s (%d)\n", strerror(errno), errno);
+ exit(1);
+ }
+ while (1) {
+ size = read(fd, tmpBuf, data_size);
+ if(size <= 0) {
+ printf("\n File end ");
+ break;
+ }
+ do_l2cap_DataWrite(tmpBuf, size);
+ }
+ return TRUE;
+ } else {
+ memset(tmpBuf, '\x7f', data_size);
+ }
+ if (num_frames && g_delay && count) {
+ printf("Delay before first send ... %lu msec, size=%ld \n", g_delay/1000, data_size);
+ usleep(g_delay);
+ }
+ printf(" count %d...\n", count);
+ sleep(5);
+ while (count > 0) {
+ char tmpBuffer[] = {0x11,0x04,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F
+ };
+ count--;
+ printf("Before write count is %d...\n", count);
+ if( g_Sar_Present == TRUE)
+ {
+ sleep(5);
+ printf("SAR present..\n");
+ do_l2cap_DataWrite(tmpBuffer, 100);
+ sleep(5);
+ do_l2cap_DataWrite(tmpBuffer, 100);
+ }
+ else
+ do_l2cap_DataWrite(tmpBuffer, 5);
+ }
+ sleep(50);
+ free(tmpBuf);
+ return TRUE;
+}
+
+static void l2c_connect(char *svr)
+{
+
+ printf("In l2c_connect - %s \n", svr);
+ do_l2cap_connect(svr);
+}
+
+static void l2c_send(char *p)
+{
+
+ do_l2cap_connect(p);
+ if(0 != WaitForCompletion(I_CONNECT_CMD, 10)) {
+ printf("Connection didnot happen in 10sec... Returning Failure...\n");
+ return;
+ }
+ sleep(1); //Let Config to complete
+ Send_Data();
+}
+
+static int l2c_pair(char *p)
+{
+ bt_bdaddr_t bd_addr = {{0}};
+ GetBdAddr(p, &bd_addr);
+ if(BT_STATUS_SUCCESS != sBtInterface->create_bond(&bd_addr,TRANSPORT_BREDR))
+ {
+ printf("Failed to Initiate Pairing \n");
+ return FALSE;
+ }
+ if(0 != WaitForCompletion(O_PAIR_CMD, 15))
+ {
+ printf("Pairing didnot happen in 15sec... Returning Failure...\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void l2c_ping(char *svr)
+{
+
+ printf("In l2c_ping - %s \n", svr);
+ do_l2cap_ping(svr);
+}
+
+static void l2c_disconnect(char *p)
+{
+ printf("In l2c_disconnect\n");
+ do_l2cap_disconnect(p);
+}
+
+static void options(void)
+{
+ printf("Modes:\n"
+ "\t-c connect\n"
+ "\t-r receive\n"
+ "\t-s connect and send\n"
+ "\t-w wait and send\n"
+ "\t-p bonding\n"
+ "\t-a ping\n");
+ printf("Options:\n"
+ "\t[-b bytes] [-i device] [-P psm] [-J cid]\n"
+ "\t[-I imtu] [-O omtu]\n"
+ "\t[-L localBusy status] 1-localbusy, 0-otherwise (default=0)\n"
+ "\t[-N num] send num frames (default = infinite)\n"
+ "\t[-C num] Count(default = 1)\n"
+ "\t[-D milliseconds] delay after sending num frames (default = 0)\n"
+ "\t[-X mode] select retransmission/flow-control mode\n"
+ "\t(ertm, ertm-mandatory, streaming, streaming-mandatory)\n"
+ "\t[-Q num] retransmit each packet up to num times (default = 3)\n"
+ "\t[-A] authentication\n"
+ "\t[-E] encryption\n"
+ "\t[-S] secure connection\n"
+ "\t[-T] timestamps\n"
+ "\t[-H mode] 1-SecConnOnlyModeTrue 0-SecConnOnlyModeFalse\n");
+}
+
+static int len = 0;
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ int opt, mode = RECEIVE, addr_required = 0;
+ char temp[3] = {0};
+
+ while ((opt=getopt(argc,argv,"arswcpb:i:P:K:O:H:F:N:L:C:D:X:Q:I:W:Z:UGATMES")) != EOF) {
+ switch(opt) {
+ case 'a':
+ mode = PING;
+ addr_required = 1;
+ break;
+ case 'r':
+ mode = RECEIVE;
+ g_ConnType = FALSE;
+ break;
+
+ case 's':
+ mode = SEND;
+ g_ConnType = TRUE;
+ addr_required = 1;
+ break;
+
+ case 'w':
+ mode = WAITANDSEND;
+ g_ConnType = FALSE;
+ break;
+
+ case 'c':
+ mode = CONNECT;
+ g_ConnType = TRUE;
+ addr_required = 1;
+ break;
+
+ case 'p':
+ mode = PAIR;
+ addr_required = 1;
+ break;
+
+ case 'b':
+ data_size = atoi(optarg);
+ break;
+
+ case 'A':
+ auth = 1;
+ break;
+ case 'C':
+ count = atoi(optarg);
+ break;
+ case 'D':
+ g_delay = atoi(optarg) * 1000;
+ break;
+ case 'E':
+ encrypt = 1;
+ break;
+ case 'F':
+ filename = strdup(optarg);
+ break;
+ case 'H':
+ g_SecOnlyMode = TRUE;
+ g_secvalue = atoi(optarg);
+ break;
+ case 'I':
+ g_imtu = atoi(optarg);
+ break;
+
+ case 'L':
+ g_LocalBusy = atoi(optarg);
+ break;
+
+ case 'M':
+ master = 1;
+ break;
+
+ case 'N':
+ num_frames = atoi(optarg);
+ break;
+
+ case 'O':
+ g_omtu = atoi(optarg);
+ break;
+
+ case 'P':
+ g_PSM = atoi(optarg);
+ printf("PSM %d",g_PSM);
+ break;
+ case 'S':
+ secure_m4_l4 = 1;
+ break;
+
+ case 'Q':
+ ertm_fcr_opts_def.max_transmit = atoi(optarg);
+ stream_fcr_opts_def.max_transmit = ertm_fcr_opts_def.max_transmit;
+ break;
+
+ case 'X':
+ if (strcasecmp(optarg, "ertm-mandatory") == 0) {
+ g_Fcr_Present = TRUE;
+ g_Fcr_Mode = L2CAP_FCR_ERTM_MODE;
+ g_Ertm_AllowedMode = L2CAP_FCR_CHAN_OPT_ERTM;
+ printf("in ERTM Mandatory option - 1\n");
+ } else if (strcasecmp(optarg, "ertm") == 0) {
+ g_Fcr_Present = TRUE;
+ g_Fcr_Mode = L2CAP_FCR_ERTM_MODE;
+ printf("in ERTM option \n");
+ } else if (strcasecmp(optarg, "streaming-mandatory") == 0) {
+ printf("FCR Mode selected as Streaming Mandatory\n");
+ g_Fcr_Present = TRUE;
+ g_Fcr_Mode = L2CAP_FCR_STREAM_MODE;
+ g_Ertm_AllowedMode = L2CAP_FCR_CHAN_OPT_STREAM;
+ } else if (strcasecmp(optarg, "streaming") == 0) {
+ g_Fcr_Present = TRUE;
+ printf("FCR Mode selected as Streaming\n");
+ g_Fcr_Mode = L2CAP_FCR_STREAM_MODE;
+ } else {
+ g_Fcr_Mode = L2CAP_FCR_BASIC_MODE;
+ printf("FCR Mode selected as Basic. String passed matches none\n");
+ }
+ break;
+
+ case 'W':
+ ertm_fcr_opts_def.tx_win_sz = atoi(optarg);
+ stream_fcr_opts_def.tx_win_sz = ertm_fcr_opts_def.tx_win_sz;
+ tl2cap_cfg_info.fcr.tx_win_sz = ertm_fcr_opts_def.tx_win_sz;
+ break;
+ case 'Z':
+ g_Sar_Present = TRUE;
+ printf("g_Sar_Present = true \n");
+ break;
+ default:
+ options();
+ exit(1);
+ }
+ }
+ if (addr_required && !(argc - optind)) {
+ options();
+ exit(1);
+ }
+
+ if (data_size < 0)
+ buffer_size = (g_omtu > g_imtu) ? g_omtu : g_imtu;
+ else
+ buffer_size = data_size;
+
+ if (!(buf = malloc(buffer_size))) {
+ perror("Can't allocate data buffer");
+ exit(1);
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ config_permissions();
+ if ( HAL_load() < 0 ) {
+ perror("HAL failed to initialize, exit\n");
+ unlink(PID_FILE);
+ exit(0);
+ }
+
+ //setup_test_env();
+ bdt_init();
+ sleep(5);
+ if(FALSE == do_enable(NULL))
+ goto ERR;
+ printf("\n Before l2cap init\n");
+ do_l2cap_init(NULL);
+ printf("\n after l2cap init\n");
+ if (g_SecOnlyMode)
+ {
+ printf("\n Before Setting SecureConnectionsOnlyMode");
+ do_l2cap_SetSecConnOnlyMode(TRUE);
+ printf("\n After Setting SecureConnectionsOnlyMode");
+ }
+ //Outgoing Connection
+ if(TRUE == g_ConnType)
+ {
+ if(1 == auth) g_SecLevel |= BTM_SEC_OUT_AUTHENTICATE;
+ if(1 == encrypt) g_SecLevel |= BTM_SEC_OUT_ENCRYPT ;
+ if(1 == secure_m4_l4) g_SecLevel |= BTM_SEC_MODE4_LEVEL4;
+ } else {
+ if(1 == auth) g_SecLevel |= BTM_SEC_IN_AUTHENTICATE;
+ if(1 == encrypt) g_SecLevel |= BTM_SEC_IN_ENCRYPT ;
+ if(1 == secure_m4_l4) g_SecLevel |= BTM_SEC_MODE4_LEVEL4;
+ }
+
+ if(0 != g_PSM)
+ {
+ printf("g_SecLevel = %d \n", g_SecLevel);
+ sL2capInterface->RegisterPsm(g_PSM, g_ConnType, g_SecLevel /*BTM_SEC_IN_AUTHORIZE */);
+ sleep(3);
+ }
+
+ switch (mode) {
+ case RECEIVE:
+ l2c_listen(FALSE);
+ break;
+
+ case SEND:
+ l2c_send(argv[optind]);
+ break;
+
+ case WAITANDSEND:
+ l2c_listen(TRUE);
+ break;
+
+ case CONNECT:
+ l2c_connect(argv[optind]);
+ break;
+
+ case PING:
+ l2c_ping(argv[optind]);
+ break;
+
+ case PAIR:
+ l2c_pair(argv[optind]);
+ if(0 != g_PSM) {
+ sleep(2);
+ l2c_connect(argv[optind]);
+ }
+ break;
+ }
+
+ if(0 != g_LocalBusy) {
+ sleep(5);
+ printf("To Send Local BusyStatus.... Press any key\n");
+ read(0, &temp, 2);
+ sL2capInterface->FlowControl(g_lcid, 0); //second param is 'dataEnabled', making it false means localBusy
+ }
+
+ERR:
+ while(1) {
+ sleep(5);
+ printf("Enter Y/y to Exit... \n");
+ len = read(0, &temp, 2);
+ if((temp[0] == 'Y') || (temp[0] == 'y'))
+ break;
+ }
+ //bdt_cleanup();
+ if(g_ConnectionState == CONNECT) {
+ l2c_disconnect(NULL);
+ sleep(5);
+ }
+ do_disable(NULL);
+ HAL_unload();
+ return 0;
+}
diff --git a/test/mcap_tool/Android.mk b/test/mcap_tool/Android.mk
new file mode 100644
index 0000000..47785b4
--- /dev/null
+++ b/test/mcap_tool/Android.mk
@@ -0,0 +1,36 @@
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+
+LOCAL_SRC_FILES:= mcap_tool.c
+
+LOCAL_C_INCLUDES += . \
+ $(LOCAL_PATH)/../../stack/include \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../stack/l2cap \
+ $(LOCAL_PATH)/../../utils/include \
+ $(LOCAL_PATH)/../../ \
+ $(LOCAL_PATH)/btif/include \
+ $(bluetooth_C_INCLUDES)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug optional
+
+LOCAL_MODULE:= mcap_tool
+
+
+LOCAL_SHARED_LIBRARIES += libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy
+
+
+LOCAL_MULTILIB := 32
+
+
+include $(BUILD_EXECUTABLE)
diff --git a/test/mcap_tool/mcap_tool.c b/test/mcap_tool/mcap_tool.c
new file mode 100644
index 0000000..861aaf6
--- /dev/null
+++ b/test/mcap_tool/mcap_tool.c
@@ -0,0 +1,1178 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015, The linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: mcap_tool.c
+ *
+ * Description: Bluedroid MCAP TOOL application
+ *
+ ***********************************************************************************/
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include "l2c_api.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/bluetooth.h>
+#include "bt_testapp.h"
+#include "mca_defs.h"
+#include "mca_api.h"
+
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+//#define TRUE 1
+//#define FALSE 0
+
+#define PID_FILE "/data/.bdt_pid"
+
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define CASE_RETURN_STR(const) case const: return #const;
+#define TRANSPORT_BREDR 1 //Add tranport parameter to create bond
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static unsigned char main_done = 0;
+static bt_status_t status;
+static bool strict_mode = FALSE;
+
+/* Main API */
+static bluetooth_device_t* bt_device;
+
+const bt_interface_t* sBtInterface = NULL;
+
+static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
+ AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
+ AID_NET_ADMIN, AID_VPN};
+
+/* Set to 1 when the Bluedroid stack is enabled */
+static unsigned char bt_enabled = 0;
+
+
+
+
+enum {
+ DISCONNECT,
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTING
+};
+static int g_AdapterState = BT_STATE_OFF;
+static int g_PairState = BT_BOND_STATE_NONE;
+
+btmcap_interface_t *sMcapIface = NULL;
+tMCA_HANDLE g_Mcap_Handle = 0;
+tMCA_DEP g_Mcap_Dep = 0;
+tL2CAP_FCR_OPTS g_fcr_opts = {
+ L2CAP_FCR_ERTM_MODE,
+ MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
+};
+
+tMCA_CHNL_CFG g_chnl_cfg = {
+ {
+ L2CAP_FCR_ERTM_MODE,
+ MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
+ MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
+ },
+ BT_DEFAULT_BUFFER_SIZE,
+ BT_DEFAULT_BUFFER_SIZE,
+ BT_DEFAULT_BUFFER_SIZE,
+ BT_DEFAULT_BUFFER_SIZE,
+ MCA_FCS_NONE,
+ 572
+};
+
+UINT16 g_Peer_Mtu = 0;
+UINT16 g_Mdl_Id = 0;
+tMCA_DL g_Mdl = 0;
+tMCA_CL g_Mcl = 0;
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+static void process_cmd(char *p, unsigned char is_job);
+static void bdt_log(const char *fmt_str, ...);
+
+int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr);
+
+static int str2bd(char *str, bt_bdaddr_t *addr)
+{
+ int32_t i = 0;
+
+ for (i = 0; i < 6; i++)
+ {
+ addr->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
+ str++;
+ }
+ return 0;
+}
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** MCAP Callbacks
+************************************************************************************/
+static void mcap_ctrl_cb(tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event, tMCA_CTRL *p_data)
+{
+ tMCA_RESULT Ret;
+ //printf("%s:: handle=%d, mcl=%d, event=0x%x, g_Mdl=%d, g_Mdl_Id=%d \n", __FUNCTION__, handle, mcl, event, g_Mdl, g_Mdl_Id);
+ switch(event)
+ {
+ case MCA_CREATE_IND_EVT:
+ //printf("%s::Create_ind::Mdl_Id=%d, OpCode=%d, dep_id=%d, cfg=%d \n", __FUNCTION__, p_data->create_ind.mdl_id,
+ //p_data->create_ind.op_code, p_data->create_ind.dep_id, p_data->create_ind.cfg);
+ g_Mdl = p_data->create_ind.mdl_id;
+ Ret = sMcapIface->CreateMdlRsp(mcl, p_data->create_ind.dep_id,
+ g_Mdl, p_data->create_ind.cfg, MCA_SUCCESS, &g_chnl_cfg);
+ break;
+
+ case MCA_CONNECT_IND_EVT:
+ //printf("%s::Connect_Ind:: peer_mtu=%d \n", __FUNCTION__, p_data->connect_ind.mtu);
+ g_Mcl = mcl;
+ break;
+
+ case MCA_DISCONNECT_IND_EVT:
+ g_Mcl = 0;
+ break;
+
+ case MCA_OPEN_IND_EVT:
+ case MCA_OPEN_CFM_EVT:
+ g_Mdl_Id = p_data->open_ind.mdl_id;
+ g_Mdl = p_data->open_ind.mdl;
+ g_Peer_Mtu = p_data->open_ind.mtu;
+ break;
+
+ case MCA_RECONNECT_IND_EVT:
+ //printf("%s::Reconnect Ind:: Mdl_Id=%d, g_Mdl_Id=%d\n", __FUNCTION__, p_data->reconnect_ind.mdl_id, g_Mdl_Id);
+ Ret = sMcapIface->ReconnectMdlRsp(mcl, g_Mcap_Dep, p_data->reconnect_ind.mdl_id, (g_Mdl_Id==p_data->reconnect_ind.mdl_id) ?MCA_RSP_SUCCESS :MCA_RSP_BAD_MDL, &g_chnl_cfg);
+ break;
+
+ case MCA_DELETE_IND_EVT:
+ //printf("%s::Delete Ind:: Mdl_Id=%d\n", __FUNCTION__, p_data->delete_ind.mdl_id);
+ if((0xffff==p_data->delete_ind.mdl_id)||(g_Mdl_Id == p_data->delete_ind.mdl_id)) g_Mdl_Id = 0;
+ break;
+
+ case MCA_SYNC_CAP_IND_EVT:
+ //printf("%s::Sync Cap Ind::\n", __FUNCTION__);
+ break;
+
+ case MCA_ABORT_IND_EVT:
+ //printf("%s::Abort_Ind::Mdl_Id=%d, opCode=%d \n", __FUNCTION__, p_data->abort_ind.mdl_id, p_data->abort_ind.op_code);
+ break;
+ }
+}
+
+static void mcap_data_cb(tMCA_DL mdl, BT_HDR *p_pkt)
+{
+ //printf("%s:: mdl=%d, event=%d, len=%d, offset=%d, layer_specific=%d\n", __FUNCTION__, mdl, p_pkt->event, p_pkt->len, p_pkt->offset, p_pkt->layer_specific);
+}
+
+
+
+/************************************************************************************
+** Shutdown helper functions
+************************************************************************************/
+
+static void bdt_shutdown(void)
+{
+ bdt_log("shutdown bdroid test app\n");
+ main_done = 1;
+}
+
+
+/*****************************************************************************
+** Android's init.rc does not yet support applying linux capabilities
+*****************************************************************************/
+
+static void config_permissions(void)
+{
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap[2];
+
+ bdt_log("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
+
+ header.pid = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setuid(AID_BLUETOOTH);
+ setgid(AID_BLUETOOTH);
+
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ capset(&header, &cap[0]);
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+}
+
+
+
+/*****************************************************************************
+** Logger API
+*****************************************************************************/
+
+void bdt_log(const char *fmt_str, ...)
+{
+ static char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt_str);
+ vsnprintf(buffer, 1024, fmt_str, ap);
+ va_end(ap);
+
+ fprintf(stdout, "%s\n", buffer);
+}
+
+/*******************************************************************************
+ ** Misc helper functions
+ *******************************************************************************/
+static const char* dump_bt_status(bt_status_t status)
+{
+ switch(status)
+ {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown status code";
+ }
+}
+#if 0
+static void hex_dump(char *msg, void *data, int size, int trunc)
+{
+ unsigned char *p = data;
+ unsigned char c;
+ int n;
+ char bytestr[4] = {0};
+ char addrstr[10] = {0};
+ char hexstr[ 16*3 + 5] = {0};
+ char charstr[16*1 + 5] = {0};
+
+ bdt_log("%s \n", msg);
+
+ /* truncate */
+ if(trunc && (size>32))
+ size = 32;
+
+ for(n=1;n<=size;n++) {
+ if (n%16 == 1) {
+ /* store address for this line */
+ snprintf(addrstr, sizeof(addrstr), "%.4x",
+ ((unsigned int)p-(unsigned int)data) );
+ }
+
+ c = *p;
+ if (isalnum(c) == 0) {
+ c = '.';
+ }
+
+ /* store hex str (for left side) */
+ snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
+ strlcat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
+
+ /* store char str (for right side) */
+ snprintf(bytestr, sizeof(bytestr), "%c", c);
+ strlcat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
+
+ if(n%16 == 0) {
+ /* line completed */
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ } else if(n%8 == 0) {
+ /* half line: add whitespaces */
+ strlcat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
+ strlcat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
+ }
+ p++; /* next byte */
+ }
+
+ if (strlen(hexstr) > 0) {
+ /* print rest of buffer if not empty */
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ }
+}
+#endif
+
+/*******************************************************************************
+ ** Console helper functions
+ *******************************************************************************/
+
+void skip_blanks(char **p)
+{
+ while (**p == ' ')
+ (*p)++;
+}
+
+uint32_t get_int(char **p, int DefaultValue)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+int get_signed_int(char **p, int DefaultValue)
+{
+ int Value = 0;
+ unsigned char UseDefault;
+ unsigned char NegativeNum = 0;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ if ( (**p) == '-')
+ {
+ NegativeNum = 1;
+ (*p)++;
+ }
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return ((NegativeNum == 0)? Value : -Value);
+}
+
+void get_str(char **p, char *Buffer)
+{
+ skip_blanks(p);
+
+ while (**p != 0 && **p != ' ')
+ {
+ *Buffer = **p;
+ (*p)++;
+ Buffer++;
+ }
+
+ *Buffer = 0;
+}
+
+uint32_t get_hex_any(char **p, int DefaultValue, unsigned int NumOfNibble)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+ //unsigned char NumOfNibble = 8; //Since we are returning uint32, max allowed is 4 bytes(8 nibbles).
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ((NumOfNibble) && (((**p)<= '9' && (**p)>= '0') ||
+ ((**p)<= 'f' && (**p)>= 'a') ||
+ ((**p)<= 'F' && (**p)>= 'A')) )
+ {
+ if (**p >= 'a')
+ Value = Value * 16 + (**p) - 'a' + 10;
+ else if (**p >= 'A')
+ Value = Value * 16 + (**p) - 'A' + 10;
+ else
+ Value = Value * 16 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ NumOfNibble--;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+uint32_t get_hex(char **p, int DefaultValue)
+{
+ //unsigned char NumOfNibble = 8; //Since we are returning uint32, max allowed is 4 bytes(8 nibbles).
+ return (get_hex_any(p, DefaultValue, 8));
+}
+uint32_t get_hex_byte(char **p, int DefaultValue)
+{
+ return (get_hex_any(p, DefaultValue, 2));
+}
+
+void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
+ char *d = ((char *)bd), *endp;
+ int i;
+ for(i = 0; i < 6; i++) {
+ *d++ = strtol(str, &endp, 16);
+ if (*endp != ':' && i != 5) {
+ memset(bd, 0, sizeof(bt_bdaddr_t));
+ return;
+ }
+ str = endp + 1;
+ }
+}
+
+#define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
+#define if_cmd(str) if (is_cmd(str))
+
+typedef void (t_console_cmd_handler) (char *p);
+
+typedef struct {
+ const char *name;
+ t_console_cmd_handler *handler;
+ const char *help;
+ unsigned char is_job;
+} t_cmd;
+
+
+const t_cmd console_cmd_list[];
+static int console_cmd_maxlen = 0;
+
+static void cmdjob_handler(void *param)
+{
+ char *job_cmd = (char*)param;
+
+ bdt_log("cmdjob starting (%s)", job_cmd);
+
+ process_cmd(job_cmd, 1);
+
+ bdt_log("cmdjob terminating");
+
+ free(job_cmd);
+}
+
+static int create_cmdjob(char *cmd)
+{
+ pthread_t thread_id;
+ char *job_cmd;
+ job_cmd = (char*)calloc(1, strlen(cmd)+1); /* freed in job handler */
+ if(job_cmd)
+ {
+ strlcpy(job_cmd, cmd, strlen(job_cmd)+1);
+
+ if (pthread_create(&thread_id, NULL,
+ (void*)cmdjob_handler, (void*)job_cmd)!=0)
+ perror("pthread_create");
+ }
+ else
+ bdt_log("Mecap_test: Cannot Allocate memory for cmdjob");
+
+
+ return 0;
+}
+
+/*******************************************************************************
+ ** Load stack lib
+ *******************************************************************************/
+
+int HAL_load(void)
+{
+ int err = 0;
+
+ hw_module_t* module;
+ hw_device_t* device;
+
+ bdt_log("Loading HAL lib + extensions");
+
+ err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0)
+ {
+ err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (err == 0) {
+ bt_device = (bluetooth_device_t *)device;
+ sBtInterface = bt_device->get_bluetooth_interface();
+ }
+ }
+
+ bdt_log("HAL library loaded (%s)", strerror(err));
+
+ return err;
+}
+
+int HAL_unload(void)
+{
+ int err = 0;
+
+ bdt_log("Unloading HAL lib");
+
+ sBtInterface = NULL;
+
+ bdt_log("HAL library unloaded (%s)", strerror(err));
+
+ return err;
+}
+
+/*******************************************************************************
+ ** HAL test functions & callbacks
+ *******************************************************************************/
+
+void setup_test_env(void)
+{
+ int i = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
+ i++;
+ }
+}
+
+void check_return_status(bt_status_t status)
+{
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
+ }
+ else
+ {
+ bdt_log("HAL REQUEST SUCCESS");
+ }
+}
+
+static void adapter_state_changed(bt_state_t state)
+{
+ int V1 = 1000, V2=2;
+ bt_property_t property = {9 /*BT_PROPERTY_DISCOVERY_TIMEOUT*/, 4, &V1};
+ bt_property_t property1 = {7 /*SCAN*/, 2, &V2};
+ bt_property_t property2 ={1,6,"Bluedroid"};
+
+ g_AdapterState = state;
+
+ if (state == BT_STATE_ON) {
+ bt_enabled = 1;
+ status = sBtInterface->set_adapter_property(&property1);
+ status = sBtInterface->set_adapter_property(&property);
+ status = sBtInterface->set_adapter_property(&property2);
+ }
+ else {
+ bt_enabled = 0;
+ }
+}
+
+static void adapter_properties_changed(bt_status_t status, int num_properties, bt_property_t *properties)
+{
+ char Bd_addr[15] = {0};
+ if(NULL == properties)
+ {
+ printf("properties is null\n");
+ return;
+ }
+ switch(properties->type)
+ {
+ case BT_PROPERTY_BDADDR:
+ memcpy(Bd_addr, properties->val, properties->len);
+ printf("Local Bd Addr = %02x:%02x:%02x:%02x:%02x:%02x\n", Bd_addr[0], Bd_addr[1], Bd_addr[2], Bd_addr[3], Bd_addr[4], Bd_addr[5]);
+ break;
+ default :
+ break;
+ }
+ return;
+}
+
+static void discovery_state_changed(bt_discovery_state_t state)
+{
+ printf("Discovery State Updated : %s\n", (state == BT_DISCOVERY_STOPPED)?"STOPPED":"STARTED");
+}
+
+
+static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name, uint32_t cod, bool min_16_digit)
+{
+ bt_pin_code_t pincode = {{ 0x31, 0x32, 0x33, 0x34}};
+
+ if(BT_STATUS_SUCCESS != sBtInterface->pin_reply(remote_bd_addr, TRUE, 4, &pincode))
+ {
+ printf("Pin Reply failed\n");
+ }
+}
+
+static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant, uint32_t pass_key)
+{
+ printf("ssp_request_cb : %s %d %u\n", bd_name->name, pairing_variant, pass_key);
+ if(BT_STATUS_SUCCESS != sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, TRUE, pass_key))
+ {
+ printf("SSP Reply failed\n");
+ }
+}
+
+static void bond_state_changed_cb(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_bond_state_t state)
+{
+ printf("Bond State Changed = %d\n", state);
+ g_PairState = state;
+}
+
+static void acl_state_changed(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_acl_state_t state)
+{
+ printf("acl_state_changed : remote_bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, acl status=%s \n",
+ remote_bd_addr->address[0], remote_bd_addr->address[1], remote_bd_addr->address[2],
+ remote_bd_addr->address[3], remote_bd_addr->address[4], remote_bd_addr->address[5],
+ (state == BT_ACL_STATE_CONNECTED)?"ACL Connected" :"ACL Disconnected"
+ );
+}
+
+
+static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+ bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
+}
+
+static void le_test_mode(bt_status_t status, uint16_t packet_count)
+{
+ bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
+}
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed,
+ adapter_properties_changed, /*adapter_properties_cb */
+ NULL, /* remote_device_properties_cb */
+ NULL, /* device_found_cb */
+ discovery_state_changed, /* discovery_state_changed_cb */
+ pin_request_cb, /* pin_request_cb */
+ ssp_request_cb, /* ssp_request_cb */
+ bond_state_changed_cb, /*bond_state_changed_cb */
+ acl_state_changed, /* acl_state_changed_cb */
+ NULL, /* thread_evt_cb */
+ dut_mode_recv, /*dut_mode_recv_cb */
+
+ // NULL, /*authorize_request_cb */
+#if BLE_INCLUDED == TRUE
+ le_test_mode, /* le_test_mode_cb */
+#else
+ NULL,
+#endif
+ NULL,
+ NULL
+};
+
+static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data) {
+ static timer_t timer;
+ static bool timer_created;
+
+ if (!timer_created) {
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))cb;
+ sigevent.sigev_value.sival_ptr = data;
+ timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
+ timer_created = true;
+ }
+
+ struct itimerspec new_value;
+ new_value.it_value.tv_sec = delay_millis / 1000;
+ new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
+ new_value.it_interval.tv_sec = 0;
+ new_value.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &new_value, NULL);
+
+ return true;
+}
+
+static int acquire_wake_lock(const char *lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock(const char *lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t callouts = {
+ sizeof(bt_os_callouts_t),
+ set_wake_alarm,
+ acquire_wake_lock,
+ release_wake_lock,
+};
+
+void bdt_init(void)
+{
+ bdt_log("INIT BT ");
+ status = sBtInterface->init(&bt_callbacks);
+ if (status == BT_STATUS_SUCCESS) {
+ status = sBtInterface->set_os_callouts(&callouts);
+ }
+ check_return_status(status);
+}
+
+void bdt_enable(void)
+{
+ bdt_log("ENABLE BT");
+ if (bt_enabled) {
+ bdt_log("Bluetooth is already enabled");
+ return;
+ }
+ status = sBtInterface->enable(strict_mode);
+
+ check_return_status(status);
+}
+
+void bdt_disable(void)
+{
+ bdt_log("DISABLE BT");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth is already disabled");
+ return;
+ }
+ status = sBtInterface->disable();
+
+ check_return_status(status);
+}
+void bdt_dut_mode_configure(char *p)
+{
+ int32_t mode = -1;
+
+ bdt_log("BT DUT MODE CONFIGURE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for test_mode to work.");
+ return;
+ }
+ mode = get_signed_int(&p, mode);
+ if ((mode != 0) && (mode != 1)) {
+ bdt_log("Please specify mode: 1 to enter, 0 to exit");
+ return;
+ }
+ status = sBtInterface->dut_mode_configure(mode);
+
+ check_return_status(status);
+}
+
+#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
+#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
+#define HCI_LE_END_TEST_OPCODE 0x201F
+
+void bdt_le_test_mode(char *p)
+{
+ int cmd;
+ unsigned char buf[3];
+ int arg1, arg2, arg3;
+
+ bdt_log("BT LE TEST MODE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for le_test to work.");
+ return;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd = get_int(&p, 0);
+ switch (cmd)
+ {
+ case 0x1: /* RX TEST */
+ arg1 = get_int(&p, -1);
+ if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
+ break;
+ case 0x2: /* TX TEST */
+ arg1 = get_int(&p, -1);
+ arg2 = get_int(&p, -1);
+ arg3 = get_int(&p, -1);
+ if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
+ bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ buf[1] = arg2;
+ buf[2] = arg3;
+ status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
+ break;
+ case 0x3: /* END TEST */
+ status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
+ break;
+ default:
+ bdt_log("Unsupported command");
+ return;
+ break;
+ }
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
+ }
+ return;
+}
+
+void bdt_cleanup(void)
+{
+ bdt_log("CLEANUP");
+ sBtInterface->cleanup();
+}
+
+/*******************************************************************************
+ ** Console commands
+ *******************************************************************************/
+
+void do_help(char *p)
+{
+ int i = 0;
+ char line[128];
+ int pos = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ pos = snprintf(line, sizeof(line), "%s", (char*)console_cmd_list[i].name);
+ bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
+ i++;
+ }
+}
+
+void do_quit(char *p)
+{
+ bdt_shutdown();
+}
+
+/*******************************************************************
+ *
+ * BT TEST CONSOLE COMMANDS
+ *
+ * Parses argument lists and passes to API test function
+ *
+*/
+
+void do_init(char *p)
+{
+ bdt_init();
+}
+
+void do_enable(char *p)
+{
+ bdt_enable();
+}
+
+void do_disable(char *p)
+{
+ bdt_disable();
+}
+
+void do_cleanup(char *p)
+{
+ bdt_cleanup();
+}
+
+
+/*******************************************************************************
+ ** MCAP API commands
+ *******************************************************************************/
+void do_mcap_register(char *p)
+{
+ tMCA_REG Mca_Reg;
+ Mca_Reg.rsp_tout = 5000; //Need to check if we have to give in msec or seconds
+ Mca_Reg.ctrl_psm = get_hex(&p, -1); // arg1
+ Mca_Reg.data_psm = get_hex(&p, -1); // arg2
+ Mca_Reg.sec_mask = get_int(&p, -1); // arg3
+ g_Mcap_Handle = sMcapIface->Register(&Mca_Reg, mcap_ctrl_cb);
+ printf("%s:: Ret=%d \n", __FUNCTION__, g_Mcap_Handle);
+}
+
+void do_mcap_deregister(char *p)
+{
+ sMcapIface->Deregister(g_Mcap_Handle);
+ printf("%s:: Handle=%d \n", __FUNCTION__, g_Mcap_Handle);
+}
+
+void do_mcap_create_dep(char *p)
+{
+ tMCA_RESULT Ret = 0;
+ int type = 0;
+ tMCA_CS Mca_cs ;
+ type = get_int(&p, -1); // arg1
+
+ memset ((void*)&Mca_cs ,0 ,sizeof(tMCA_CS));
+ Mca_cs.type = (0 == type) ? MCA_TDEP_ECHO :MCA_TDEP_DATA;
+ Mca_cs.max_mdl = MCA_NUM_MDLS;
+ Mca_cs.p_data_cback = mcap_data_cb;
+
+ Ret = sMcapIface->CreateDep(g_Mcap_Handle, &g_Mcap_Dep, &Mca_cs);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+static void do_mcap_delete_dep(char *p)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = sMcapIface->DeleteDep(g_Mcap_Handle, g_Mcap_Dep);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+static void do_mcap_connect(char *p)
+{
+ tMCA_RESULT Ret = 0;
+ bt_bdaddr_t bd_addr = {{0}};
+ UINT16 ctrl_psm = 0;
+ UINT16 sec_mask = 0;
+ char buf[64];
+
+ get_str(&p, buf);
+ str2bd(buf, &bd_addr);
+ ctrl_psm = get_hex(&p, -1);// arg2
+ sec_mask = get_int(&p, -1);// arg3
+ printf("ctrl_psm=%d, secMask=%d \n", ctrl_psm, sec_mask);
+ Ret = sMcapIface->ConnectReq(g_Mcap_Handle, bd_addr.address, ctrl_psm, sec_mask);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+static void do_mcap_disconnect(char *p)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = sMcapIface->DisconnectReq(g_Mcl);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+static void do_mcap_create_mdl(char *p)
+{
+ tMCA_RESULT Ret = 0;
+ UINT16 data_psm = 0;
+ data_psm = get_hex(&p, -1); // arg1
+ Ret = sMcapIface->CreateMdl(g_Mcl, g_Mcap_Dep, data_psm, 1, 1, 1, &g_chnl_cfg);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+static void do_mcap_close(char *p)
+{
+ tMCA_RESULT Ret = 0;
+ Ret = sMcapIface->CloseReq(g_Mdl);
+ printf("%s:: Ret=%d \n", __FUNCTION__, Ret);
+}
+
+static void do_pairing(char *p)
+{
+ bt_bdaddr_t bd_addr = {{0}};
+
+ if(FALSE == GetBdAddr(p, &bd_addr))
+ return; // arg1
+ if(BT_STATUS_SUCCESS != sBtInterface->create_bond(&bd_addr, TRANSPORT_BREDR))
+ {
+ printf("Failed to Initiate Pairing \n");
+ return;
+ }
+}
+
+/*******************************************************************
+ *
+ * CONSOLE COMMAND TABLE
+ *
+*/
+
+const t_cmd console_cmd_list[] =
+{
+ /*
+ * INTERNAL
+ */
+
+ { "help", do_help, "lists all available console commands", 0 },
+ { "quit", do_quit, "", 0},
+
+ /*
+ * API CONSOLE COMMANDS
+ */
+
+ /* Init and Cleanup shall be called automatically */
+ { "enable", do_enable, ":: enables bluetooth", 0 },
+ { "disable", do_disable, ":: disables bluetooth", 0 },
+ { "pair", do_pairing, ":: BdAddr<00112233445566>", 0 },
+ { "register", do_mcap_register, "::Ctrl_Psm<hex>, Data_Psm<hex>, Security<0-10>", 0 },
+ { "deregister", do_mcap_deregister, "::", 0 },
+ { "create_data_endpoint", do_mcap_create_dep, "::Type<0-Echo, 1-NormalData>", 0 },
+ { "delete_data_endpoint", do_mcap_delete_dep, "::", 0 },
+ { "connect", do_mcap_connect, ":: BdAddr<00112233445566>, Ctrl_Psm<hex>, SecMask<int>", 0 },
+ { "disconnect", do_mcap_disconnect, ":: BdAddr<00112233445566>", 0 },
+ { "create_mdl", do_mcap_create_mdl, ":: Data_Psm<hex>", 0 },
+ { "close_data_channel", do_mcap_close, "::", 0 },
+ /* last entry */
+ {NULL, NULL, "", 0},
+};
+
+/*
+ * Main console command handler
+*/
+
+static void process_cmd(char *p, unsigned char is_job)
+{
+ char cmd[2048];
+ int i = 0;
+ char *p_saved = p;
+
+ get_str(&p, cmd);
+
+ /* table commands */
+ while (console_cmd_list[i].name != NULL)
+ {
+ if (is_cmd(console_cmd_list[i].name))
+ {
+ if (!is_job && console_cmd_list[i].is_job)
+ create_cmdjob(p_saved);
+ else
+ {
+ console_cmd_list[i].handler(p);
+ }
+ return;
+ }
+ i++;
+ }
+ bdt_log("%s : unknown command\n", p_saved);
+ do_help(NULL);
+}
+
+int main (int argc, char * argv[])
+{
+
+ config_permissions();
+ bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
+ bdt_log(":: Bluedroid test app starting");
+
+ if ( HAL_load() < 0 ) {
+ perror("HAL failed to initialize, exit\n");
+ unlink(PID_FILE);
+ exit(0);
+ }
+
+ setup_test_env();
+
+ /* Automatically perform the init */
+ bdt_init();
+ sleep(5);
+ bdt_enable();
+ sleep(5);
+
+ sMcapIface = (btmcap_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_MCAP);
+ //sSmpIface = sBtInterface->get_testapp_interface(TEST_APP_SMP);
+ sleep(1);
+ sMcapIface->Init();
+
+ while(!main_done)
+ {
+ char line[2048];
+
+ /* command prompt */
+ printf( ">" );
+ fflush(stdout);
+
+ fgets (line, 2048, stdin);
+
+ if (line[0]!= '\0')
+ {
+ /* remove linefeed */
+ line[strlen(line)-1] = 0;
+
+ process_cmd(line, 0);
+ memset(line, '\0', 2048);
+ }
+ }
+
+ /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
+ //bdt_cleanup();
+
+ HAL_unload();
+
+ bdt_log(":: Bluedroid test app terminating");
+
+ return 0;
+}
+
+
+int GetBdAddr(char *p, bt_bdaddr_t *pbd_addr)
+{
+ char Arr[13] = {0};
+ UINT8 k1 = 0;
+ UINT8 k2 = 0;
+ int i;
+
+ if(12 != strlen(p))
+ {
+ printf("\nInvalid Bd Address. Format[112233445566]\n");
+ return FALSE;
+ }
+ strlcpy(Arr, p, sizeof(Arr));
+ for(i=0; i<12; i++)
+ {
+ Arr[i] = tolower(Arr[i]);
+ }
+ for(i=0; i<6; i++)
+ {
+ k1 = (UINT8) ( (Arr[i*2] >= 'a') ? ( 10 + (UINT8)( Arr[i*2] - 'a' )) : (Arr[i*2] - '0') );
+ k2 = (UINT8) ( (Arr[(i*2)+1] >= 'a') ? ( 10 + (UINT8)( Arr[(i*2)+1] - 'a' )) : (Arr[(i*2)+1] - '0') );
+ if ( (k1>15)||(k2>15) )
+ {
+ return FALSE;
+ }
+ pbd_addr->address[i] = (k1<<4 | k2);
+ }
+ return TRUE;
+}
diff --git a/test/rfcommtest/Android.mk b/test/rfcommtest/Android.mk
new file mode 100644
index 0000000..f4ae2ca
--- /dev/null
+++ b/test/rfcommtest/Android.mk
@@ -0,0 +1,33 @@
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ rfcommtest.c
+
+LOCAL_C_INCLUDES += . \
+ $(LOCAL_PATH)/../../stack/include \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../stack/l2cap \
+ $(LOCAL_PATH)/../../utils/include \
+ $(LOCAL_PATH)/../../ \
+ $(LOCAL_PATH)/btif/include \
+ $(bluetooth_C_INCLUDES)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug optional
+LOCAL_MODULE:= rfc
+
+LOCAL_SHARED_LIBRARIES += libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy
+
+LOCAL_MULTILIB := 32
+
+include $(BUILD_EXECUTABLE)
diff --git a/test/rfcommtest/rfcommtest.c b/test/rfcommtest/rfcommtest.c
new file mode 100644
index 0000000..2159daf
--- /dev/null
+++ b/test/rfcommtest/rfcommtest.c
@@ -0,0 +1,1100 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014, The linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: rfcommtest.c
+ *
+ * Description: RFCOMM Test application
+ *
+ ***********************************************************************************/
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/bluetooth.h>
+#include "bt_target.h"
+#include "bt_testapp.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define PID_FILE "/data/.bdt_pid"
+
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define CASE_RETURN_STR(const) case const: return #const;
+#define DISCONNECT 3
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+static unsigned char main_done = 0;
+static bt_status_t status;
+
+/* Main API */
+static bluetooth_device_t* bt_device;
+
+const bt_interface_t* sBtInterface = NULL;
+const btrfcomm_interface_t *sRfcInterface = NULL;
+
+static gid_t groups[] = { AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
+ AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
+ AID_NET_ADMIN, AID_VPN};
+
+/* Set to 1 when the Bluedroid stack is enabled */
+static unsigned char bt_enabled = 0;
+static bool strict_mode = FALSE;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+static void process_cmd(char *p, unsigned char is_job);
+static void bdt_log(const char *fmt_str, ...);
+
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+
+/************************************************************************************
+** Shutdown helper functions
+************************************************************************************/
+
+static void bdt_shutdown(void)
+{
+ bdt_log("shutdown bdroid test app\n");
+ main_done = 1;
+}
+
+
+/*****************************************************************************
+** Android's init.rc does not yet support applying linux capabilities
+*****************************************************************************/
+
+static int str2bd(char *str, bt_bdaddr_t *addr)
+{
+ int32_t i = 0;
+
+ for (i = 0; i < 6; i++)
+ {
+ addr->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
+ str++;
+ }
+ return 0;
+}
+static void config_permissions(void)
+{
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap[2];
+
+ bdt_log("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(), getgid());
+
+ header.pid = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setuid(AID_BLUETOOTH);
+ setgid(AID_BLUETOOTH);
+
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ capset(&header, &cap[0]);
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+}
+#if 0
+/*Pin_Request_cb */
+static void pin_remote_request_callback (bt_bdaddr_t *remote_bd_addr,
+ bt_bdname_t *bd_name, uint32_t cod)
+{
+ bt_pin_code_t pin_code;
+ /* Default 1234 is the Pin code */
+ pin_code.pin[0] = 0x31;
+ pin_code.pin[1] = 0x32;
+ pin_code.pin[2] = 0x33;
+ pin_code.pin[3] = 0x34;
+
+ bdt_log("bdt PIN Remote Request");
+ sBtInterface->pin_reply(remote_bd_addr ,1 , 4 , &pin_code);
+}
+#endif
+
+/* Pairing in Case of SSP */
+static void ssp_remote_requst_callback(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant, uint32_t pass_key)
+{
+ if (pairing_variant == BT_SSP_VARIANT_PASSKEY_ENTRY)
+ {
+ bdt_log("bdt ssp remote request not supported");
+ return;
+ }
+ bdt_log("bdt accept SSP pairing");
+ sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, 1, pass_key);
+}
+
+
+
+
+/*****************************************************************************
+** Logger API
+*****************************************************************************/
+
+void bdt_log(const char *fmt_str, ...)
+{
+ static char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt_str);
+ vsnprintf(buffer, 1024, fmt_str, ap);
+ va_end(ap);
+
+ fprintf(stdout, "%s\n", buffer);
+}
+
+/*******************************************************************************
+ ** Misc helper functions
+ *******************************************************************************/
+static const char* dump_bt_status(bt_status_t status)
+{
+ switch(status)
+ {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown status code";
+ }
+}
+#if 0
+static void hex_dump(char *msg, void *data, int size, int trunc)
+{
+ unsigned char *p = data;
+ unsigned char c;
+ int n;
+ char bytestr[4] = {0};
+ char addrstr[10] = {0};
+ char hexstr[ 16*3 + 5] = {0};
+ char charstr[16*1 + 5] = {0};
+
+ bdt_log("%s \n", msg);
+
+ /* truncate */
+ if(trunc && (size>32))
+ size = 32;
+
+ for(n=1;n<=size;n++) {
+ if (n%16 == 1) {
+ /* store address for this line */
+ snprintf(addrstr, sizeof(addrstr), "%.4x",
+ (unsigned int)((uintptr_t)p-(uintptr_t)data) );
+ }
+
+ c = *p;
+ if (isalnum(c) == 0) {
+ c = '.';
+ }
+
+ /* store hex str (for left side) */
+ snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
+ strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
+
+ /* store char str (for right side) */
+ snprintf(bytestr, sizeof(bytestr), "%c", c);
+ strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
+
+ if(n%16 == 0) {
+ /* line completed */
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ } else if(n%8 == 0) {
+ /* half line: add whitespaces */
+ strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
+ strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
+ }
+ p++; /* next byte */
+ }
+
+ if (strlen(hexstr) > 0) {
+ /* print rest of buffer if not empty */
+ bdt_log("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ }
+}
+#endif
+/*******************************************************************************
+ ** Console helper functions
+ *******************************************************************************/
+
+void skip_blanks(char **p)
+{
+ while (**p == ' ')
+ (*p)++;
+}
+
+uint32_t get_int(char **p, int DefaultValue)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+int get_signed_int(char **p, int DefaultValue)
+{
+ int Value = 0;
+ unsigned char UseDefault;
+ unsigned char NegativeNum = 0;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ if ( (**p) == '-')
+ {
+ NegativeNum = 1;
+ (*p)++;
+ }
+ while ( ((**p)<= '9' && (**p)>= '0') )
+ {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return ((NegativeNum == 0)? Value : -Value);
+}
+
+void get_str(char **p, char *Buffer)
+{
+ skip_blanks(p);
+
+ while (**p != 0 && **p != ' ')
+ {
+ *Buffer = **p;
+ (*p)++;
+ Buffer++;
+ }
+
+ *Buffer = 0;
+}
+
+uint32_t get_hex(char **p, int DefaultValue)
+{
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ( ((**p)<= '9' && (**p)>= '0') ||
+ ((**p)<= 'f' && (**p)>= 'a') ||
+ ((**p)<= 'F' && (**p)>= 'A') )
+ {
+ if (**p >= 'a')
+ Value = Value * 16 + (**p) - 'a' + 10;
+ else if (**p >= 'A')
+ Value = Value * 16 + (**p) - 'A' + 10;
+ else
+ Value = Value * 16 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+void get_bdaddr(const char *str, bt_bdaddr_t *bd) {
+ char *d = ((char *)bd), *endp;
+ int i;
+ for(i = 0; i < 6; i++) {
+ *d++ = strtol(str, &endp, 16);
+ if (*endp != ':' && i != 5) {
+ memset(bd, 0, sizeof(bt_bdaddr_t));
+ return;
+ }
+ str = endp + 1;
+ }
+}
+
+#define is_cmd(str) ((strlen(str) == strlen(cmd)) && strncmp((const char *)&cmd, str, strlen(str)) == 0)
+#define if_cmd(str) if (is_cmd(str))
+
+typedef void (t_console_cmd_handler) (char *p);
+
+typedef struct {
+ const char *name;
+ t_console_cmd_handler *handler;
+ const char *help;
+ unsigned char is_job;
+} t_cmd;
+
+
+const t_cmd console_cmd_list[];
+static int console_cmd_maxlen = 0;
+
+static void cmdjob_handler(void *param)
+{
+ char *job_cmd = (char*)param;
+
+ bdt_log("cmdjob starting (%s)", job_cmd);
+
+ process_cmd(job_cmd, 1);
+
+ bdt_log("cmdjob terminating");
+
+ free(job_cmd);
+}
+
+static int create_cmdjob(char *cmd)
+{
+ pthread_t thread_id;
+ char *job_cmd;
+
+ job_cmd = (char*)calloc(1, strlen(cmd)+1); /* freed in job handler */
+ if (job_cmd)
+ {
+ strlcpy(job_cmd, cmd, sizeof(job_cmd));
+ if (pthread_create(&thread_id, NULL,
+ (void*)cmdjob_handler, (void*)job_cmd)!=0)
+ perror("pthread_create");
+ }
+ else
+ bdt_log("Rfcomm_test: Cannot allocate memory for cmdjob");
+ return 0;
+}
+
+/*******************************************************************************
+ ** Load stack lib
+ *******************************************************************************/
+
+int HAL_load(void)
+{
+ int err = 0;
+
+ hw_module_t* module;
+ hw_device_t* device;
+
+ bdt_log("Loading HAL lib + extensions");
+
+ err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0)
+ {
+ err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (err == 0) {
+ bt_device = (bluetooth_device_t *)device;
+ sBtInterface = bt_device->get_bluetooth_interface();
+ }
+ }
+
+ bdt_log("HAL library loaded (%s)", strerror(err));
+
+ return err;
+}
+
+int HAL_unload(void)
+{
+ int err = 0;
+
+ bdt_log("Unloading HAL lib");
+
+ sBtInterface = NULL;
+ sRfcInterface = NULL;
+
+ bdt_log("HAL library unloaded (%s)", strerror(err));
+
+ return err;
+}
+
+/*******************************************************************************
+ ** HAL test functions & callbacks
+ *******************************************************************************/
+
+void setup_test_env(void)
+{
+ int i = 0;
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ console_cmd_maxlen = MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
+ i++;
+ }
+}
+
+void check_return_status(bt_status_t status)
+{
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("HAL REQUEST FAILED status : %d (%s)", status, dump_bt_status(status));
+ }
+ else
+ {
+ bdt_log("HAL REQUEST SUCCESS");
+ }
+}
+
+static void adapter_state_changed(bt_state_t state)
+{
+ bdt_log("ADAPTER STATE UPDATED : %s", (state == BT_STATE_OFF)?"OFF":"ON");
+ if (state == BT_STATE_ON) {
+ bt_enabled = 1;
+ } else {
+ bt_enabled = 0;
+ }
+}
+
+static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+ bdt_log("DUT MODE RECV : NOT IMPLEMENTED");
+}
+
+static void le_test_mode(bt_status_t status, uint16_t packet_count)
+{
+ bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count);
+}
+
+static void device_found_cb(int num_properties, bt_property_t *properties)
+{
+ int i;
+ for (i = 0; i < num_properties; i++)
+ {
+ if (properties[i].type == BT_PROPERTY_BDNAME)
+ {
+ bdt_log("AP name is : %s\n",
+ (char*)properties[i].val);
+ }
+ }
+}
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed,
+ NULL, /*adapter_properties_cb */
+ NULL, /* remote_device_properties_cb */
+ device_found_cb, /* device_found_cb */
+ NULL, /* discovery_state_changed_cb */
+ NULL, /* pin_request_cb */
+ ssp_remote_requst_callback, /* ssp_request_cb */
+ NULL, /*bond_state_changed_cb */
+ NULL, /* acl_state_changed_cb */
+ NULL, /* thread_evt_cb */
+ dut_mode_recv, /*dut_mode_recv_cb */
+// NULL, /*authorize_request_cb */
+#if BLE_INCLUDED == TRUE
+ le_test_mode, /* le_test_mode_cb */
+#else
+ NULL,
+#endif
+ NULL, /* energy_info_cb */
+ NULL /* get_testapp_interface */
+};
+
+static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data)
+{
+ static timer_t timer;
+ static bool timer_created;
+
+ if (!timer_created)
+ {
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))cb;
+ sigevent.sigev_value.sival_ptr = data;
+ timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
+ timer_created = true;
+ }
+
+ struct itimerspec new_value;
+ new_value.it_value.tv_sec = delay_millis / 1000;
+ new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
+ new_value.it_interval.tv_sec = 0;
+ new_value.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &new_value, NULL);
+
+ return true;
+}
+
+static int acquire_wake_lock(const char *lock_name)
+{
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock(const char *lock_name)
+{
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t callouts = {
+ sizeof(bt_os_callouts_t),
+ set_wake_alarm,
+ acquire_wake_lock,
+ release_wake_lock,
+};
+
+/* Rfcomm Client */
+void bdt_rfcomm(void)
+{
+ bdt_log("rfcomm client");
+
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm(0);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+}
+
+/* Rfcomm Server */
+void bdt_rfcomm_server (void)
+{
+ bdt_log("rfcomm server");
+
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm(1);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+}
+
+/* Rfcomm disconnect */
+void bdt_rfcomm_disc_from_server(void)
+{
+ bdt_log("rfcomm disc from Server");
+
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm(3);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+}
+
+void bdt_init(void)
+{
+ bdt_log("INIT BT ");
+ status = sBtInterface->init(&bt_callbacks);
+ if (status == BT_STATUS_SUCCESS) {
+ status = sBtInterface->set_os_callouts(&callouts);
+ }
+ check_return_status(status);
+}
+
+void bdt_enable(void)
+{
+ bdt_log("ENABLE BT");
+ if (bt_enabled) {
+ bdt_log("Bluetooth is already enabled");
+ return;
+ }
+ status = sBtInterface->enable(strict_mode);
+
+ check_return_status(status);
+}
+
+void bdt_disable(void)
+{
+ bdt_log("DISABLE BT");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth is already disabled");
+ return;
+ }
+ status = sBtInterface->disable();
+
+ check_return_status(status);
+}
+void bdt_dut_mode_configure(char *p)
+{
+ int32_t mode = -1;
+
+ bdt_log("BT DUT MODE CONFIGURE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for test_mode to work.");
+ return;
+ }
+ mode = get_signed_int(&p, mode);
+ if ((mode != 0) && (mode != 1)) {
+ bdt_log("Please specify mode: 1 to enter, 0 to exit");
+ return;
+ }
+ status = sBtInterface->dut_mode_configure(mode);
+
+ check_return_status(status);
+}
+
+#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D
+#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E
+#define HCI_LE_END_TEST_OPCODE 0x201F
+
+void bdt_le_test_mode(char *p)
+{
+ int cmd;
+ unsigned char buf[3];
+ int arg1, arg2, arg3;
+
+ bdt_log("BT LE TEST MODE");
+ if (!bt_enabled) {
+ bdt_log("Bluetooth must be enabled for le_test to work.");
+ return;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd = get_int(&p, 0);
+ switch (cmd)
+ {
+ case 0x1: /* RX TEST */
+ arg1 = get_int(&p, -1);
+ if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1);
+ break;
+ case 0x2: /* TX TEST */
+ arg1 = get_int(&p, -1);
+ arg2 = get_int(&p, -1);
+ arg3 = get_int(&p, -1);
+ if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0))
+ bdt_log("%s Invalid arguments", __FUNCTION__);
+ buf[0] = arg1;
+ buf[1] = arg2;
+ buf[2] = arg3;
+ status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3);
+ break;
+ case 0x3: /* END TEST */
+ status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0);
+ break;
+ default:
+ bdt_log("Unsupported command");
+ return;
+ break;
+ }
+ if (status != BT_STATUS_SUCCESS)
+ {
+ bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status);
+ }
+ return;
+}
+
+void bdt_cleanup(void)
+{
+ bdt_log("CLEANUP");
+ sBtInterface->cleanup();
+}
+
+/*******************************************************************************
+ ** Console commands
+ *******************************************************************************/
+
+static int pos = 0;
+
+void do_help(char *p)
+{
+ int i = 0;
+ char line[128];
+
+ while (console_cmd_list[i].name != NULL)
+ {
+ pos = snprintf(line, sizeof(line), "%s", (char*)console_cmd_list[i].name);
+ bdt_log("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
+ i++;
+ }
+}
+
+void do_quit(char *p)
+{
+ bdt_shutdown();
+}
+
+/*******************************************************************
+ *
+ * BT TEST CONSOLE COMMANDS
+ *
+ * Parses argument lists and passes to API test function
+ *
+*/
+
+void do_init(char *p)
+{
+ bdt_init();
+}
+
+void do_enable(char *p)
+{
+ bdt_enable();
+}
+
+void do_disable(char *p)
+{
+ bdt_disable();
+}
+void do_dut_mode_configure(char *p)
+{
+ bdt_dut_mode_configure(p);
+}
+
+void do_le_test_mode(char *p)
+{
+ bdt_le_test_mode(p);
+}
+
+void do_cleanup(char *p)
+{
+ bdt_cleanup();
+}
+
+/********* Rfcomm Test toot ***************/
+void do_rfcomm(char *p)
+{
+ bdt_rfcomm();
+}
+
+
+/**********************************************
+ Rfcomm connection to remote device
+************************************************/
+void do_rfc_con( char *p)
+{
+ char buf[64];
+ tRFC conn_param;
+
+ bdt_log("bdt do_rfc_con");
+ memset(buf, 0, 64);
+ /*Enter BD address */
+ get_str(&p, buf);
+ str2bd(buf, &conn_param.data.conn.bdadd);
+ memset(buf ,0 , 64);
+ get_str(&p, buf);
+ conn_param.data.conn.scn = atoi(buf);
+ bdt_log("SCN =%d",conn_param.data.conn.scn);
+ /* Connection */
+ conn_param.param = RFC_TEST_CLIENT;
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm_test_interface(&conn_param);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+}
+
+
+/* For PTS test case BV21 and BV22 */
+
+void do_rfc_con_for_test_msc_data(char *p)
+{
+ char buf[64];
+ tRFC conn_param;
+
+ bdt_log("bdt do_rfc_con_for_test_msc_data");
+ memset(buf, 0, 64);
+ /*Enter BD address */
+ get_str(&p, buf);
+ str2bd(buf, &conn_param.data.conn.bdadd);
+ memset(buf ,0 , 64);
+ get_str(&p, buf);
+ conn_param.data.conn.scn = atoi(buf);
+ bdt_log("SCN =%d",conn_param.data.conn.scn);
+ /* Connection */
+ conn_param.param = RFC_TEST_CLIENT_TEST_MSC_DATA;
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->
+ get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm_test_interface(&conn_param);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+}
+
+
+
+/* Role Switch */
+void do_role_switch(char *p)
+{
+ char buf[64];
+ tRFC conn_param ;
+
+ bdt_log("bdt do_role_switch");
+ memset(buf ,0 , 64);
+ /* Bluetooth Device address */
+ get_str(&p, buf);
+ str2bd(buf, &conn_param.data.role_switch.bdadd);
+ memset(buf ,0 , 64);
+ get_str(&p, buf);
+ conn_param.data.role_switch.role = atoi(buf);
+ /* Role Switch */
+ conn_param.param = RFC_TEST_ROLE_SWITCH; //role switch
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm_test_interface(&conn_param);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+}
+
+void do_rfc_rls (char *p)
+{
+ tRFC conn_param;
+
+ bdt_log("bdt rfc_rls");
+ conn_param.param = RFC_TEST_FRAME_ERROR;
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm_test_interface(&conn_param);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+
+}
+
+void do_rfc_send_data (char *p)
+{
+ tRFC conn_param;
+
+ bdt_log("bdt rfc_send_data");
+ conn_param.param = RFC_TEST_WRITE_DATA;
+ sRfcInterface = (btrfcomm_interface_t *)sBtInterface->get_testapp_interface(TEST_APP_RFCOMM);
+ if (sRfcInterface)
+ {
+ sRfcInterface->rdut_rfcomm_test_interface(&conn_param);
+ }
+ else
+ {
+ bdt_log("interface not loaded");
+ }
+
+}
+
+
+void do_rfcomm_server(char *p)
+{
+ bdt_rfcomm_server();
+}
+
+void do_rfcomm_disc_frm_server(char *p)
+{
+ bdt_rfcomm_disc_from_server();
+}
+/*******************************************************************
+ *
+ * CONSOLE COMMAND TABLE
+ *
+*/
+
+const t_cmd console_cmd_list[] =
+{
+ /*
+ * INTERNAL
+ */
+
+ { "help", do_help, "lists all available console commands", 0 },
+ { "quit", do_quit, "", 0},
+
+ /*
+ * API CONSOLE COMMANDS
+ */
+
+ /* Init and Cleanup shall be called automatically */
+ { "enable", do_enable, ":: enables bluetooth", 0 },
+ { "disable", do_disable, ":: disables bluetooth", 0 },
+ { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 },
+ { "le_test_mode", do_le_test_mode, ":: LE Test Mode - RxTest - 1 <rx_freq>, \n\t \
+ TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, \n\t \
+ End Test - 3 <no_args>", 0 },
+ /* add here */
+ { "rfcomm", do_rfcomm, "rfcomm test", 0},
+ { "server_rfcomm", do_rfcomm_server ,"rfcomm server test", 0},
+ { "dis_client", do_rfcomm_disc_frm_server, "disc from Server", 0},
+ { "rfc_con", do_rfc_con, "rfc_con", 0 },
+ { "rfc_msccon", do_rfc_con_for_test_msc_data, "rfc_msccon", 0 },
+ { "rfc_rls", do_rfc_rls, "rls", 0 },
+ { "rfc_senddata", do_rfc_send_data, "rfc_senddata", 0 },
+ { "role_sw", do_role_switch, "role_sw", 0},
+ /* last entry */
+ {NULL, NULL, "", 0},
+};
+
+/*
+ * Main console command handler
+*/
+
+static void process_cmd(char *p, unsigned char is_job)
+{
+ char cmd[128];
+ int i = 0;
+ char *p_saved = p;
+
+ get_str(&p, cmd);
+
+ /* table commands */
+ while (console_cmd_list[i].name != NULL)
+ {
+ if (is_cmd(console_cmd_list[i].name))
+ {
+ if (!is_job && console_cmd_list[i].is_job)
+ create_cmdjob(p_saved);
+ else
+ {
+ console_cmd_list[i].handler(p);
+ }
+ return;
+ }
+ i++;
+ }
+ bdt_log("%s : unknown command\n", p_saved);
+ do_help(NULL);
+}
+
+int main (int argc, char * argv[])
+{
+
+ config_permissions();
+ bdt_log("\n:::::::::::::::::::::::::::::::::::::::::::::::::::");
+ bdt_log(":: Bluedroid test app starting");
+
+ if ( HAL_load() < 0 ) {
+ perror("HAL failed to initialize, exit\n");
+ unlink(PID_FILE);
+ exit(0);
+ }
+
+ setup_test_env();
+
+ /* Automatically perform the init */
+ bdt_init();
+
+ while(!main_done)
+ {
+ char line[128];
+
+ /* command prompt */
+ printf( ">" );
+ fflush(stdout);
+
+ fgets (line, 128, stdin);
+
+ if (line[0]!= '\0')
+ {
+ /* remove linefeed */
+ line[strlen(line)-1] = 0;
+
+ process_cmd(line, 0);
+ memset(line, '\0', 128);
+ }
+ }
+
+ /* FIXME: Commenting this out as for some reason, the application does not exit otherwise*/
+ //bdt_cleanup();
+//cleanup:
+ HAL_unload();
+
+ bdt_log(":: Bluedroid test app terminating");
+
+ return 0;
+}
diff --git a/udrv/ulinux/uipc.c b/udrv/ulinux/uipc.c
index abb747d..c5cf905 100644
--- a/udrv/ulinux/uipc.c
+++ b/udrv/ulinux/uipc.c
@@ -67,6 +67,9 @@
#define UIPC_FLUSH_BUFFER_SIZE 1024
+#define CHAN_CREATE_WAIT_TIME_MS 30
+#define CHAN_CREATE_RETRY_COUNT 10
+
/*****************************************************************************
** Local type definitions
******************************************************************************/
@@ -143,6 +146,7 @@
static inline int create_server_socket(const char* name)
{
+ int ret;
int s = socket(AF_LOCAL, SOCK_STREAM, 0);
if (s < 0)
return -1;
@@ -151,9 +155,10 @@
if(osi_socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0)
{
+ ret = (errno == EADDRINUSE ? -EADDRINUSE : -1);
BTIF_TRACE_EVENT("socket failed to create (%s)", strerror(errno));
close(s);
- return -1;
+ return ret;
}
if(listen(s, 5) < 0)
@@ -350,6 +355,7 @@
static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, char *name, tUIPC_RCV_CBACK *cback)
{
int fd;
+ int i;
BTIF_TRACE_EVENT("SETUP CHANNEL SERVER %d", ch_id);
@@ -358,7 +364,19 @@
UIPC_LOCK();
- fd = create_server_socket(name);
+ for (i = 0; i < CHAN_CREATE_RETRY_COUNT; i++)
+ {
+ fd = create_server_socket(name);
+ if (fd == -EADDRINUSE)
+ {
+ BTIF_TRACE_ERROR("Address already in use, retry: %d", i);
+ usleep(CHAN_CREATE_WAIT_TIME_MS * 1000);
+ }
+ else
+ {
+ break;
+ }
+ }
if (fd < 0)
{
@@ -436,7 +454,6 @@
case UIPC_CH_ID_AV_CTRL:
uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL);
break;
-
case UIPC_CH_ID_AV_AUDIO:
uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO);
break;
@@ -644,6 +661,7 @@
case UIPC_CH_ID_AV_AUDIO:
uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback);
break;
+
}
UIPC_UNLOCK();
diff --git a/utils/Android.mk b/utils/Android.mk
index e28d5fa..4a83236 100644
--- a/utils/Android.mk
+++ b/utils/Android.mk
@@ -8,11 +8,16 @@
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/../btcore/include \
$(LOCAL_PATH)/../stack/include \
+ $(LOCAL_PATH)/../gki/common \
+ $(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../ \
$(bluetooth_C_INCLUDES)
LOCAL_SRC_FILES := \
- ./src/bt_utils.c
+ ./src/bt_utils.c
+
+LOCAL_STATIC_LIBRARIES := \
+ libosi
LOCAL_MODULE := libbt-utils
LOCAL_MODULE_TAGS := optional
diff --git a/utils/include/bt_utils.h b/utils/include/bt_utils.h
index fa397f9..960a283 100644
--- a/utils/include/bt_utils.h
+++ b/utils/include/bt_utils.h
@@ -21,6 +21,7 @@
static const char BT_UTILS_MODULE[] = "bt_utils_module";
+#include <stdbool.h>
/*******************************************************************************
** Type definitions
********************************************************************************/
@@ -36,11 +37,46 @@
TASK_HIGH_MAX
} tHIGH_PRIORITY_TASK;
+/* Run-time configuration file to store AVRCP version info*/
+#ifndef AVRC_PEER_VERSION_CONF_FILE
+#define AVRC_PEER_VERSION_CONF_FILE "/data/misc/bluedroid/avrc_peer_entries.conf"
+#endif
+
/*******************************************************************************
** Functions
********************************************************************************/
+typedef enum {
+ METHOD_BD = 0,
+ METHOD_NAME
+} tBLACKLIST_METHOD;
+
+typedef enum {
+ BT_SOC_DEFAULT = 0,
+ BT_SOC_SMD = BT_SOC_DEFAULT,
+ BT_SOC_AR3K,
+ BT_SOC_ROME,
+ BT_SOC_CHEROKEE,
+ /* Add chipset type here */
+ BT_SOC_RESERVED
+} bt_soc_type;
+
+#define MAX_NAME_LEN (50)
+#define IOT_DEV_BASE_CONF_FILE "/etc/bluetooth/iot_devlist.conf"
+#define IOT_DEV_CONF_FILE "/data/misc/bluedroid/iot_devlist.conf"
+#define IOT_DEV_CONF_BKP_FILE "/data/misc/bluedroid/iot_devlist_bkp.conf"
+#define IOT_ROLE_CHANGE_BLACKLIST "RoleChangeBlacklistAddr"
+#define IOT_HFP_1_7_BLACKLIST "Hfp1_7BlacklistAddr"
+#define COD_AUDIO_DEVICE (0x200400)
void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task);
void adjust_priority_a2dp(int start);
+void load_iot_devlist(const char *filename);
+void unload_iot_devlist();
+bool is_device_present(char* header, unsigned char* device_details);
+bool add_iot_device(const char *filename, char* header,
+ unsigned char* device_details, tBLACKLIST_METHOD method_type);
+bool remove_iot_device(const char *filename, char* header,
+ unsigned char* device_details, tBLACKLIST_METHOD method_type);
+bt_soc_type get_soc_type();
#define UNUSED(x) (void)(x)
#endif /* BT_UTILS_H */
diff --git a/utils/src/bt_utils.c b/utils/src/bt_utils.c
index 2c3422a..6f0f205 100644
--- a/utils/src/bt_utils.c
+++ b/utils/src/bt_utils.c
@@ -42,10 +42,53 @@
#include "bt_types.h"
#include "btcore/include/module.h"
#include "osi/include/compat.h"
+#include "osi/include/allocator.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"
+#include "osi/include/list.h"
+#include <string.h>
/*******************************************************************************
+** Local type definitions
+*******************************************************************************/
+typedef struct {
+ char header_name[MAX_NAME_LEN]; // name of header in iot_devlist_conf file
+ list_t *devlist; // list of BD addresses
+ tBLACKLIST_METHOD method_type;
+} iot_header_node_t;
+
+typedef struct {
+ char dev_bd[3]; // BD address of blacklisted device
+} iot_devlist_bd_node_t;
+
+typedef struct {
+ char dev_name[MAX_NAME_LEN]; // Name of blacklisted device
+} iot_devlist_name_node_t;
+
+typedef struct {
+ char *header; // header name
+ unsigned char *dev_details; // details of blacklisted device
+ bool device_found;
+} iot_input_param;
+
+typedef struct {
+ bt_soc_type soc_type;
+ char* soc_name;
+} soc_type_node;
+
+static soc_type_node soc_type_entries[] = {
+ { BT_SOC_SMD , "smd" },
+ { BT_SOC_AR3K , "ath3k" },
+ { BT_SOC_ROME , "rome" },
+ { BT_SOC_CHEROKEE , "cherokee" },
+ { BT_SOC_RESERVED , "" }
+ };
+
+static list_t *iot_header_queue = NULL;
+#define MAX_LINE 2048
+#define MAX_ADDR_STR_LEN 9
+static pthread_mutex_t iot_mutex_lock;
+/*******************************************************************************
** Type definitions for callback functions
********************************************************************************/
static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
@@ -53,8 +96,11 @@
static pthread_mutex_t gIdxLock;
static int g_TaskIdx;
static int g_TaskIDs[TASK_HIGH_MAX];
+static bt_soc_type soc_type;
#define INVALID_TASK_ID (-1)
+static void init_soc_type();
+
static future_t *init(void) {
int i;
pthread_mutexattr_t lock_attr;
@@ -67,11 +113,14 @@
pthread_mutexattr_init(&lock_attr);
pthread_mutex_init(&gIdxLock, &lock_attr);
+ pthread_mutex_init(&iot_mutex_lock, NULL);
+ init_soc_type();
return NULL;
}
static future_t *clean_up(void) {
pthread_mutex_destroy(&gIdxLock);
+ pthread_mutex_destroy(&iot_mutex_lock);
return NULL;
}
@@ -129,7 +178,7 @@
rc = -1;
#else // !defined(OS_GENERIC)
pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
- if (g_DoSchedulingGroup[g_TaskIdx]) {
+ if (g_TaskIdx < TASK_HIGH_MAX && g_DoSchedulingGroup[g_TaskIdx]) {
// set_sched_policy does not support tid == 0
rc = set_sched_policy(tid, SP_AUDIO_SYS);
}
@@ -181,3 +230,900 @@
}
}
}
+
+/*****************************************************************************
+**
+** Function check_bd_cb
+**
+** Description Compares the BD address.
+**
+** Returns returns true if the BD address matches otherwise false
+**
+*******************************************************************************/
+static bool check_bd_cb(void* node, void* cb_data)
+{
+ iot_devlist_bd_node_t *bd_node = (iot_devlist_bd_node_t*)node;
+ iot_input_param *input_param = (iot_input_param*)cb_data;
+
+ if (input_param->device_found == true)
+ return true;
+
+ if ((bd_node->dev_bd[0] == input_param->dev_details[0]) &&
+ (bd_node->dev_bd[1] == input_param->dev_details[1]) &&
+ (bd_node->dev_bd[2] == input_param->dev_details[2])) {
+ input_param->device_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function check_name_cb
+**
+** Description Compares the Device name.
+**
+** Returns returns true if the name matches otherwise false
+**
+*******************************************************************************/
+static bool check_name_cb(void* node, void* cb_data)
+{
+ iot_devlist_name_node_t *name_node = (iot_devlist_name_node_t*)node;
+ iot_input_param *input_param = (iot_input_param*)cb_data;
+
+ if (input_param->device_found == true)
+ return true;
+
+ if (!strncmp(name_node->dev_name, (const char*)input_param->dev_details,
+ strlen((char *)input_param->dev_details))) {
+ input_param->device_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function check_header_cb
+**
+** Description Iterates through the each entry in the header list and
+** calls the callback associated to each entry.
+**
+** Returns boolean
+**
+*******************************************************************************/
+static bool check_header_cb(void* node, void* cb_data)
+{
+ iot_header_node_t *header_node = (iot_header_node_t*)node;
+ iot_input_param *input_param = (iot_input_param*)cb_data;
+ if (!strcmp(header_node->header_name, input_param->header)) {
+ if(header_node->devlist) {
+ if (header_node->method_type == METHOD_BD)
+ list_foreach_ext(header_node->devlist, check_bd_cb, cb_data);
+ else if (header_node->method_type == METHOD_NAME)
+ list_foreach_ext(header_node->devlist, check_name_cb, cb_data);
+ }
+ }
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function is_device_present
+**
+** Description Checks if the device is already present in the blacklisted
+** device list or not.The input can be address based or name
+** based.
+**
+** Returns true incase device is present false otherwise.
+**
+*******************************************************************************/
+bool is_device_present(char* header, unsigned char* device_details)
+{
+ iot_input_param input_param;
+ input_param.dev_details = device_details;
+ input_param.header = header;
+ input_param.device_found = false;
+
+ pthread_mutex_lock(&iot_mutex_lock);
+ if (!iot_header_queue) {
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+ list_foreach_ext(iot_header_queue, check_header_cb, &input_param);
+ pthread_mutex_unlock(&iot_mutex_lock);
+
+ if (input_param.device_found)
+ return true;
+ else
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function parse_bd
+**
+** Description It will read 3 bytes and copy them into node. It also
+** increments header pointer.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void parse_bd(char **start_ptr, iot_devlist_bd_node_t *bd)
+{
+ char *p_end;
+ bd->dev_bd[0] = (unsigned char)strtol(*start_ptr, &p_end, 16);
+ (*start_ptr) = p_end + 1;
+ bd->dev_bd[1] = (unsigned char)strtol(*start_ptr, &p_end, 16);
+ (*start_ptr) = p_end + 1;
+ bd->dev_bd[2] = (unsigned char)strtol(*start_ptr, &p_end, 16);
+ (*start_ptr) = p_end;
+}
+
+/*****************************************************************************
+**
+** Function parse_name
+**
+** Description It will read name and copy them into node. It also
+** increments header pointer.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void parse_name(char **start_ptr, iot_devlist_name_node_t *name)
+{
+ char *split = strchr(*start_ptr, ','); // split point to first occurrence of ,
+ int len = 0;
+ if (split == NULL) {
+ // check once for end of line, for the last name in list
+ split = strchr(*start_ptr, '\n');
+ if (split == NULL)
+ return;
+ }
+ len = (((split - (*start_ptr)) >= MAX_NAME_LEN) ? MAX_NAME_LEN - 1 :
+ (split - (*start_ptr)));
+ memcpy(name->dev_name, *start_ptr, len);
+ name->dev_name[len] = '\0';
+ *start_ptr = split;
+}
+
+/*****************************************************************************
+**
+** Function is_device_node_exist
+**
+** Description Checks if the device node is already present in the queue
+** or not.The input can be address based or name based.
+**
+** Returns true if the entry found else false.
+**
+*******************************************************************************/
+static bool is_device_node_exist(iot_header_node_t *header_entry, char* device_details,
+ tBLACKLIST_METHOD method_type)
+{
+ if(!header_entry || !header_entry->devlist)
+ return false;
+
+ for (const list_node_t *device_node = list_begin(header_entry->devlist);
+ device_node != list_end(header_entry->devlist);
+ device_node = list_next(device_node)) {
+ if(method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd_addr_entry = list_node(device_node);
+ if(!memcmp(device_details, bd_addr_entry->dev_bd, 3)) {
+ return true;
+ }
+ }
+ else if(method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *bd_name_entry = list_node(device_node);
+ if(!strcmp((char *)device_details, bd_name_entry->dev_name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function populate_list
+**
+** Description It goes through the input buffer and add device node to the
+** header list if the valid entry is found.It ignores the
+** duplicated entries.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void populate_list(char *header_end, iot_header_node_t *node)
+{
+ if(node->devlist == NULL)
+ node->devlist = list_new(osi_free);
+ while(header_end && (*header_end != '\n')&&(*header_end != '\0')) // till end of line reached
+ {
+ // read from line buffer and copy to list
+ if (node->method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd = (iot_devlist_bd_node_t *)osi_malloc(sizeof(iot_devlist_bd_node_t));
+ if(bd == NULL) {
+ ALOGE(" Unable to allocate memory for addr entry");
+ return;
+ }
+ header_end++;
+ parse_bd(&header_end, bd);
+ if(is_device_node_exist(node, (char *) bd, node->method_type)) {
+ osi_free(bd);
+ }
+ else {
+ list_append(node->devlist, bd);
+ }
+ }
+ else if (node->method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *name = (iot_devlist_name_node_t *)osi_malloc(sizeof(iot_devlist_name_node_t));
+ if(name == NULL) {
+ ALOGE(" Unable to allocate memory for name entry");
+ return;
+ }
+ header_end++;
+ parse_name(&header_end, name);
+ if(is_device_node_exist(node, (char *)name, node->method_type)) {
+ osi_free(name);
+ }
+ else {
+ list_append(node->devlist, name);
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+**
+** Function create_header_node
+**
+** Description This function is used to create the header node.
+**
+** Returns valid pointer incase the node is created otherwise NULL.
+**
+*******************************************************************************/
+static iot_header_node_t *create_header_node(char* name, unsigned int len,
+ tBLACKLIST_METHOD method_type)
+{
+ iot_header_node_t *node = NULL;
+ if(len >= MAX_NAME_LEN) {
+ return NULL;
+ }
+ node =(iot_header_node_t *) osi_malloc(sizeof(iot_header_node_t));
+ if (node == NULL) {
+ ALOGE(" Not enough memory to create the header node");
+ return NULL;
+ }
+ memcpy(node->header_name, name, len);
+ node->header_name[len] = '\0'; // header copied
+ node->method_type = method_type;
+ node->devlist = NULL;
+ return node;
+}
+
+/*****************************************************************************
+**
+** Function get_existing_header_node
+**
+** Description This function is used to get exisiting header node if present.
+**
+** Returns valid pointer incase the node is already prsent otherwise NULL.
+**
+*******************************************************************************/
+static iot_header_node_t *get_existing_header_node(char* name, unsigned int len)
+{
+ for (const list_node_t *node = list_begin(iot_header_queue);
+ node != list_end(iot_header_queue); node = list_next(node)) {
+ iot_header_node_t *entry = list_node(node);
+ if (!strncmp(entry->header_name, name, len)) {
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+/*****************************************************************************
+**
+** Function populate_header
+**
+** Description It goes through the input buffer and add header node to the
+** main queue if the valid entry is found.It ignores the
+** duplicated entries.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void populate_header(char* line_start, char *header_end)
+{
+ tBLACKLIST_METHOD method_type;
+ iot_header_node_t *node = NULL;
+
+ if (*(header_end + 3) == ':')
+ method_type = METHOD_BD;
+ else
+ method_type = METHOD_NAME;
+
+ if (!iot_header_queue) {
+ iot_header_queue = list_new(osi_free);
+ if (iot_header_queue == NULL) {
+ ALOGE(" Not enough memory to create the queue");
+ return;
+ }
+ }
+
+ if( (node = get_existing_header_node(line_start, header_end - line_start)) == NULL) {
+ node = create_header_node(line_start, header_end - line_start, method_type);
+ if(node)
+ list_append(iot_header_queue, node);
+ }
+ if(node)
+ populate_list(header_end, node);
+}
+
+/*****************************************************************************
+**
+** Function free_header_list
+**
+** Description This function is used to free all entries under blacklist
+** queue.
+**
+** Returns boolean
+**
+*******************************************************************************/
+static bool free_header_list(void* node, void *context)
+{
+ iot_header_node_t *header_node = (iot_header_node_t*)node;
+ list_free(header_node->devlist);
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function unload_iot_devlist
+**
+** Description This function is used to free the IOT blacklist queue.
+**
+** Returns void
+**
+*******************************************************************************/
+void unload_iot_devlist()
+{
+ pthread_mutex_lock(&iot_mutex_lock);
+ if (!iot_header_queue) {
+ ALOGV(" Blacklist queue is not initialized ");
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return;
+ }
+ list_foreach(iot_header_queue, free_header_list, NULL);
+ list_free(iot_header_queue);
+ iot_header_queue = NULL;
+ pthread_mutex_unlock(&iot_mutex_lock);
+}
+
+/*****************************************************************************
+**
+** Function copy_file
+**
+** Description This function is used to copy one file to other.
+**
+** Returns true incase copy is successful otherwise false.
+**
+*******************************************************************************/
+static bool copy_file(const char *src, const char *dst)
+{
+ FILE *src_fp = NULL, *dst_fp = NULL;
+ int ch;
+
+ if( !src || !dst) {
+ return false;
+ }
+ src_fp = fopen(src, "rt");
+ if(src_fp)
+ dst_fp = fopen(dst, "wt");
+ if(src_fp && dst_fp) {
+ while( ( ch = fgetc(src_fp) ) != EOF ) {
+ fputc(ch, dst_fp);
+ }
+ fclose(dst_fp);
+ fclose(src_fp);
+ return true;
+ }
+ else {
+ if(src_fp)
+ fclose(src_fp);
+ if(dst_fp)
+ fclose(dst_fp);
+ return false;
+ }
+}
+
+/*****************************************************************************
+**
+** Function dump_all_iot_devices
+**
+** Description This function is used to print all blacklisted devices
+** which are loaded from iot_devlist.conf file..
+**
+** Returns void.
+**
+*******************************************************************************/
+static void dump_all_iot_devices(void)
+{
+ tBLACKLIST_METHOD method_type;
+
+ if(!iot_header_queue)
+ return;
+
+ for (const list_node_t *header_node = list_begin(iot_header_queue);
+ header_node != list_end(iot_header_queue);
+ header_node = list_next(header_node)) {
+ iot_header_node_t *header_entry = list_node(header_node);
+ method_type = header_entry->method_type;
+
+ if(!header_entry->devlist)
+ continue;
+
+ ALOGW(" ########### Blacklisted Device summary ##############");
+ for (const list_node_t *device_node = list_begin(header_entry->devlist);
+ device_node != list_end(header_entry->devlist);
+ device_node = list_next(device_node)) {
+ if(method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd_addr_entry = list_node(device_node);
+ ALOGW(" Device %02X:%02X:%02X Blacklisted under %s",
+ bd_addr_entry->dev_bd[0], bd_addr_entry->dev_bd[1],
+ bd_addr_entry->dev_bd[2], header_entry->header_name);
+ }
+ else if(method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *bd_name_entry = list_node(device_node);
+ ALOGW(" Device %s Blacklisted under %s", bd_name_entry->dev_name,
+ header_entry->header_name);
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+**
+** Function load_iot_devlist_from_file
+**
+** Description This function is used to initialize the queue and load the
+** load the devices from file.
+**
+** Returns void.
+**
+*******************************************************************************/
+void load_iot_devlist_from_file(const char *filename)
+{
+ if (!filename) {
+ ALOGE(" Invalid IOT blacklist filename");
+ return;
+ }
+ char line_start[MAX_LINE];
+ int line_number = 0;
+ char *header_end = NULL;
+ FILE *iot_devlist_fp = fopen(filename, "rt");
+ if (iot_devlist_fp == NULL) {
+ if(!strcmp(filename, IOT_DEV_CONF_FILE)) {
+ //load it from system partition
+ if(copy_file(IOT_DEV_BASE_CONF_FILE, IOT_DEV_CONF_FILE) == false) {
+ ALOGE(" Can't copy it from Base file %s", IOT_DEV_BASE_CONF_FILE);
+ return;
+ }
+ else {
+ if((iot_devlist_fp = fopen(filename, "rt")) == NULL)
+ return;
+ }
+ }
+ else {
+ ALOGE(" File %s does not exist ",filename);
+ return;
+ }
+ }
+ while(fgets(line_start, MAX_LINE, iot_devlist_fp)) {
+ line_number++;
+ if((*line_start == '\n') ||(*line_start == '#')) {
+ ALOGV("line %d is empty",line_number);
+ continue;
+ }
+ header_end = strchr(line_start, '=');
+ if (header_end == NULL) {
+ ALOGV(" NOT A valid line %d", line_number);
+ continue;
+ }
+ populate_header(line_start, header_end);
+ }
+ dump_all_iot_devices();
+ fclose(iot_devlist_fp);
+}
+
+/*****************************************************************************
+**
+** Function load_iot_devlist
+**
+** Description This function is used to initialize the queue.
+**
+** Returns void.
+**
+*******************************************************************************/
+void load_iot_devlist(const char *filename)
+{
+ pthread_mutex_lock(&iot_mutex_lock);
+ load_iot_devlist_from_file(filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+}
+
+/*****************************************************************************
+**
+** Function add_iot_device
+**
+** Description This function is used to add the device to the blacklist file
+** as well as queue.
+**
+** Returns true incase the device is blacklisted otherwise fasle.
+**
+*******************************************************************************/
+bool add_iot_device(const char *filename, char* header,
+ unsigned char* device_details, tBLACKLIST_METHOD method_type)
+{
+ char line_start[MAX_LINE];
+ FILE *iot_devlist_fp;
+ char *header_end = NULL;
+ int index = 0, i, len = 0;
+
+ if((header == NULL) || (device_details == NULL)) {
+ ALOGE("Error adding device to the list: Invalid input data");
+ return false;
+ }
+ if (is_device_present (header , device_details)) {
+ ALOGW("Device already present in the blacklist");
+ return true;
+ }
+
+ pthread_mutex_lock(&iot_mutex_lock);
+ iot_devlist_fp = fopen(filename, "a");
+
+ if (iot_devlist_fp == NULL) {
+ ALOGE(" File %s does not exist ", filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+ /* first copy the header */
+ len = strlcpy(&line_start[index], header, strlen(header)+ 1);
+ index += len;
+
+ line_start[index++] = '=';
+ /* then copy the device addr/device name */
+ if(method_type == METHOD_BD) {
+ /* for addr take first 3 bytes */
+ for(i = 0; i < 3; i++) {
+ if(i < 2) {
+ len = snprintf(&line_start[index], MAX_LINE - index, "%02X:",
+ *(device_details + i));
+ }
+ else {
+ len = snprintf(&line_start[index], MAX_LINE - index, "%02X",
+ *(device_details + i));
+ }
+ index += len;
+ }
+ }
+ else if(method_type == METHOD_NAME) {
+ len = strlcpy(&line_start[index], (const char*) device_details,
+ strlen((const char*)device_details) + 1);
+ index += len;
+ }
+ /* append the new line characer at the end */
+ line_start[index++] = '\n';
+ line_start[index++] = '\0';
+
+ header_end = strchr(line_start,'=');
+ if(header_end) {
+ populate_header(line_start, header_end);
+ }
+ if(fputs(line_start, iot_devlist_fp)) {
+ fclose(iot_devlist_fp);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return true;
+ }
+ else {
+ fclose(iot_devlist_fp);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+}
+
+/*****************************************************************************
+**
+** Function form_bd_addr
+**
+** Description Adds the colon after 2 bytes to form valid BD address to
+** compare the entry prsent in file.
+**
+** Returns void
+**
+*******************************************************************************/
+static void form_bd_addr(char *addr, char *new_addr, int max_len)
+{
+ int i = 0, index = 0, len =0;
+ /* for addr take first 3 bytes */
+ for(i = 0; i < 3; i++) {
+ if(i < 2) {
+ len = snprintf(&new_addr[index], max_len - index, "%02X:",
+ *(addr + i));
+ }
+ else {
+ len = snprintf(&new_addr[index], max_len - index, "%02X",
+ *(addr + i));
+ }
+ index += len;
+ }
+ new_addr[max_len - 1]= '\0';
+}
+
+/*****************************************************************************
+**
+** Function remove_iot_device_from_queue
+**
+** Description This function is used remove the entry from internal queue.
+**
+** Returns true if the entry removed from queue else false.
+**
+*******************************************************************************/
+bool remove_iot_device_from_queue(unsigned char* device_details, char* header,
+ tBLACKLIST_METHOD method_type)
+{
+ if(!iot_header_queue)
+ return false;
+ for (const list_node_t *header_node = list_begin(iot_header_queue);
+ header_node != list_end(iot_header_queue);
+ header_node = list_next(header_node)) {
+ iot_header_node_t *header_entry = list_node(header_node);
+
+ if(!header_entry->devlist)
+ continue;
+
+ if((!strcmp(header, header_entry->header_name)) &&
+ method_type == header_entry->method_type) {
+
+ for (const list_node_t *device_node = list_begin(header_entry->devlist);
+ device_node != list_end(header_entry->devlist);
+ device_node = list_next(device_node)) {
+ if(method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd_addr_entry = list_node(device_node);
+ if(!memcmp(device_details, bd_addr_entry->dev_bd, 3)) {
+ list_remove(header_entry->devlist, bd_addr_entry);
+ return true;
+ }
+ }
+ else if(method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *bd_name_entry = list_node(device_node);
+ if(!strcmp((char *)device_details, bd_name_entry->dev_name)) {
+ list_remove(header_entry->devlist, bd_name_entry);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function edit_line
+**
+** Description This function is used to remove the device entry from the
+** inputted line buffer if the entry present.
+**
+** Returns true if the entry removed from line else false.
+**
+*******************************************************************************/
+static void edit_line(char *line_start, char *dev_info, int line_len)
+{
+ char *dev_ptr = strstr(line_start, dev_info);
+ char *comma_ptr = NULL;
+ int len_to_copy = 0;
+ if(dev_ptr) {
+ comma_ptr = strchr(dev_ptr, ',');
+ if(comma_ptr) {
+ len_to_copy = line_len - (comma_ptr - line_start + 1);
+ }
+ else {
+ *(dev_ptr - 1) = '\n';
+ *(dev_ptr) = '\0';
+ }
+ }
+ if(len_to_copy) {
+ memmove(dev_ptr, comma_ptr + 1, len_to_copy);
+ }
+}
+
+/*****************************************************************************
+**
+** Function is_single_entry_line
+**
+** Description This function is used to check the line consists of single
+** input line if the entry present.
+**
+** Returns true if the single entry present else false.
+**
+*******************************************************************************/
+static bool is_single_entry_line(char *line_start)
+{
+ char *comma_ptr = strchr(line_start, ',');
+ // check the char next to ,
+ if( !comma_ptr || (*(comma_ptr + 1) == '\n')) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/*****************************************************************************
+**
+** Function get_header_from_line
+**
+** Description This function is used to get the header from line buffer.
+**
+** Returns true if the header found else false.
+**
+*******************************************************************************/
+bool get_header_from_line(char *line_start, char* header)
+{
+ int i = 0;
+ if(!line_start || !header || !strchr(line_start, '=')) {
+ return false;
+ }
+ while (line_start[i] != '=') {
+ header[i] = line_start[i];
+ i++;
+ }
+ header[i] = '\0';
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function remove_iot_device
+**
+** Description This function is used to remove the device from internal
+** blacklisted queue as well as black list file.
+**
+** Returns true if the device is removed else false.
+**
+*******************************************************************************/
+bool remove_iot_device(const char *filename, char* header,
+ unsigned char* device_details, tBLACKLIST_METHOD method_type)
+{
+ char line_start[MAX_LINE];
+ FILE *iot_devlist_fp, *iot_devlist_new_fp;
+ char bd_addr[MAX_ADDR_STR_LEN];
+ char header_name[MAX_NAME_LEN] = { 0 };
+ char *dev = NULL;
+ int len = 0;
+
+ if((header == NULL) || (device_details == NULL)) {
+ ALOGE("Invalid input data to add the device");
+ return false;
+ }
+ if (!is_device_present (header , device_details)) {
+ ALOGW("Device doesn't exist in the list");
+ return false;
+ }
+ pthread_mutex_lock(&iot_mutex_lock);
+ iot_devlist_fp = fopen(filename, "rt");
+
+ if (iot_devlist_fp == NULL) {
+ ALOGE(" File %s does not exist ", filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+ iot_devlist_new_fp = fopen(IOT_DEV_CONF_BKP_FILE, "wt");
+
+ if (iot_devlist_new_fp == NULL) {
+ ALOGE(" Unable to create backup file %s", IOT_DEV_CONF_BKP_FILE);
+ fclose(iot_devlist_fp);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+
+ /* then copy the device addr/device name */
+ while (fgets(line_start, sizeof line_start, iot_devlist_fp)) {
+ len = strlen(line_start);
+
+ if (len) {
+ get_header_from_line(line_start, header_name);
+ if(method_type == METHOD_BD) {
+ form_bd_addr((char*)device_details, bd_addr, MAX_ADDR_STR_LEN);
+ dev = bd_addr;
+ }
+ else if(method_type == METHOD_NAME) {
+ dev = (char *) device_details;
+ }
+ // copy as it is if the line consists comments
+ if( (line_start[0] == '#') || (line_start[0] == '/') ||
+ (line_start[0] == ' ') || (line_start[0] == '\n')) {
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ else if((!strcmp(header_name, header)) && (strstr(line_start, dev))) {
+ if(is_single_entry_line(line_start)) {
+ if(!remove_iot_device_from_queue(device_details, header, method_type)) {
+ // if unable to remove from queue put the same line as it is
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ else
+ ALOGE(" Removed %s device from blacklist file %s", dev, IOT_DEV_CONF_FILE);
+ }
+ else {
+ // multi line entry
+ if(remove_iot_device_from_queue(device_details, header, method_type)) {
+ edit_line(line_start, dev, len + 1);
+ fputs(line_start, iot_devlist_new_fp);
+ ALOGE(" Removed %s device from blacklist file %s", dev, IOT_DEV_CONF_FILE);
+ }
+ else {
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ }
+ }
+ else {
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ }
+ }
+
+ fclose(iot_devlist_fp);
+ fclose(iot_devlist_new_fp);
+ remove(filename);
+ rename(IOT_DEV_CONF_BKP_FILE, filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function init_soc_type
+**
+** Description Get Bluetooth SoC type from system setting and stores it
+** in soc_type.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void init_soc_type()
+{
+ int ret = 0;
+ char bt_soc_type[PROPERTY_VALUE_MAX];
+
+ ALOGI("init_soc_type");
+
+ soc_type = BT_SOC_DEFAULT;
+ ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL);
+ if (ret != 0) {
+ int i;
+ ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type);
+ for ( i = BT_SOC_AR3K ; i < BT_SOC_RESERVED ; i++ )
+ {
+ char* soc_name = soc_type_entries[i].soc_name;
+ if (!strcmp(bt_soc_type, soc_name)) {
+ soc_type = soc_type_entries[i].soc_type;
+ break;
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+**
+** Function get_soc_type
+**
+** Description This function is used to get the Bluetooth SoC type.
+**
+** Returns bt_soc_type.
+**
+*******************************************************************************/
+bt_soc_type get_soc_type()
+{
+ return soc_type;
+}