A2DP_CTRL_CMD_STOP,
A2DP_CTRL_CMD_SUSPEND,
A2DP_CTRL_GET_AUDIO_CONFIG,
+ A2DP_CTRL_CMD_OFFLOAD_START,
} 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_INCALL_FAILURE, /* Failure when in Call*/
+ A2DP_CTRL_ACK_UNSUPPORTED
} tA2DP_CTRL_ACK;
include $(CLEAR_VARS)
-ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
-LOCAL_CFLAGS += \
- -DBOARD_HAVE_BLUETOOTH_BCM
-endif
LOCAL_CFLAGS += -DBUILDCFG $(bdroid_CFLAGS) -std=c99
LOCAL_CLANG_CFLAGS += -Wno-error=gnu-variable-sized-type-not-at-end
#include "utl.h"
#include "l2c_api.h"
#include "l2cdefs.h"
+#include "bt_utils.h"
+#include "vendor.h"
+
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
#define BTA_AV_RECONFIG_RETRY 6
#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);
/* state machine states */
bta_av_role_res, /* BTA_AV_ROLE_RES */
bta_av_delay_co, /* BTA_AV_DELAY_CO */
bta_av_open_at_inc, /* BTA_AV_OPEN_AT_INC */
+ bta_av_offload_req, /* BTA_AV_OFFLOAD_REQ */
+ bta_av_offload_rsp, /* BTA_AV_OFFLOAD_RSP */
NULL
};
p_scb->wait = 0;
p_scb->num_disc_snks = 0;
bta_sys_stop_timer(&p_scb->timer);
+
+ vendor_get_interface()->send_command(BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+ if (p_scb->offload_start_pending) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
+ }
+ p_scb->offload_start_pending = FALSE;
+
if (p_scb->deregistring)
{
/* remove stream */
bta_av_conn_chg((tBTA_AV_DATA *) &msg);
/* 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->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
if (p_scb->co_started)
{
+ vendor_get_interface()->send_command(BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+ if (p_scb->offload_start_pending) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
+ }
+ p_scb->offload_start_pending = FALSE;
+
bta_av_stream_chg(p_scb, FALSE);
p_scb->co_started = FALSE;
/* in case that we received suspend_ind, we may need to call co_stop here */
if(p_scb->co_started)
{
+ vendor_get_interface()->send_command(BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+ if (p_scb->offload_start_pending) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
+ }
+ p_scb->offload_start_pending = FALSE;
+
bta_av_stream_chg(p_scb, FALSE);
{
}
}
+/*******************************************************************************
+**
+** Function bta_av_offload_req
+**
+** Description This function is called if application requests offload of
+** a2dp audio.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_offload_req(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES;
+ UINT16 mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+
+ APPL_TRACE_DEBUG("%s stream %s, audio channels open %d", __func__,
+ p_scb->started ? "STARTED" : "STOPPED", bta_av_cb.audio_open_cnt);
+
+ /* Check if stream has already been started. */
+ /* Support offload if only one audio source stream is open. */
+ if (p_scb->started != TRUE) {
+ status = BTA_AV_FAIL_STREAM;
+
+ } else if (bta_av_cb.audio_open_cnt == 1 &&
+ p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC &&
+ p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+
+ bt_vendor_op_a2dp_offload_t a2dp_offload_start;
+
+ if (L2CA_GetConnectionConfig(p_scb->l2c_cid, &a2dp_offload_start.acl_data_size,
+ &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) {
+
+ APPL_TRACE_DEBUG("%s l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle 0x%02X", __func__,
+ a2dp_offload_start.acl_data_size, p_scb->l2c_cid,
+ a2dp_offload_start.remote_cid, a2dp_offload_start.lm_handle);
+
+ a2dp_offload_start.bta_av_handle = p_scb->hndl;
+ a2dp_offload_start.xmit_quota = BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA;
+ a2dp_offload_start.stream_mtu = (mtu < p_scb->stream_mtu) ? mtu : p_scb->stream_mtu;
+ a2dp_offload_start.local_cid = p_scb->l2c_cid;
+ a2dp_offload_start.is_flushable = TRUE;
+ a2dp_offload_start.stream_source = ((UINT32)(p_scb->cfg.codec_info[1] | p_scb->cfg.codec_info[2]));
+
+ memcpy(a2dp_offload_start.codec_info, p_scb->cfg.codec_info,
+ sizeof(a2dp_offload_start.codec_info));
+
+ if (!vendor_get_interface()->send_command(BT_VND_OP_A2DP_OFFLOAD_START, &a2dp_offload_start)) {
+ status = BTA_AV_SUCCESS;
+ p_scb->offload_start_pending = TRUE;
+ }
+ }
+ }
+
+ if (status != BTA_AV_SUCCESS)
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
+}
+
+/*******************************************************************************
+**
+** Function bta_av_offload_rsp
+**
+** Description This function is called when the vendor lib responds to
+** BT_VND_OP_A2DP_OFFLOAD_START.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_av_offload_rsp(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
+{
+ tBTA_AV_STATUS status = p_data->api_status_rsp.status;
+
+ APPL_TRACE_DEBUG("%s stream %s status %s", __func__,
+ p_scb->started ? "STARTED" : "STOPPED",
+ status ? "FAIL" : "SUCCESS");
+
+ /* Check if stream has already been started. */
+ if (status == BTA_AV_SUCCESS && p_scb->started != TRUE) {
+ status = BTA_AV_FAIL_STREAM;
+ }
+
+ p_scb->offload_start_pending = FALSE;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV *)&status);
+}
+
#endif /* BTA_AV_INCLUDED */
{
mask = 1 << xx;
APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
-
+ tBTA_AV_SCB *p_scb = p_cb->p_scb[xx];
+ if (p_scb != NULL)
+ {
+ UINT8 avdt_tsep_type = p_scb->seps[p_scb->sep_idx].tsep;
+ /* If the device is a A2DP source, disconnect the AVDT connection */
+ if ((avdt_tsep_type == AVDT_TSEP_SRC) && (p_data->hdr.offset == AVDT_ACP))
+ {
+ LOG_INFO("%s disconnecting invalid A2DP source to A2DP source connection.", __func__);
+ AVDT_DisconnectReq(p_data->str_msg.bd_addr, NULL);
+ return;
+ }
+ }
/* look for a p_lcb with its p_scb registered */
if((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
{
/*******************************************************************************
**
+** Function BTA_AvOffloadStart
+**
+** Description Start a2dp audio offloading.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvOffloadStart(tBTA_AV_HNDL hndl)
+{
+ BT_HDR *p_buf;
+ if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AV_API_OFFLOAD_START_EVT;
+ p_buf->layer_specific = hndl;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AvOffloadStartRsp
+**
+** Description Response from vendor lib for A2DP Offload Start request.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status)
+{
+ tBTA_AV_API_STATUS_RSP *p_buf;
+ if ((p_buf = (tBTA_AV_API_STATUS_RSP *) GKI_getbuf(sizeof(tBTA_AV_API_STATUS_RSP))) != NULL)
+ {
+ p_buf->hdr.event = BTA_AV_API_OFFLOAD_START_RSP_EVT;
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->status = status;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
** Function BTA_AvEnable_Sink
**
** Description Enable/Disable A2DP Sink..
BTA_AV_ROLE_CHANGE_EVT,
BTA_AV_AVDT_DELAY_RPT_EVT,
BTA_AV_ACP_CONNECT_EVT,
+ BTA_AV_API_OFFLOAD_START_EVT,
+ BTA_AV_API_OFFLOAD_START_RSP_EVT,
/* these events are handled outside of the state machine */
BTA_AV_API_ENABLE_EVT,
UINT16 avdt_version; /* AVDTP protocol version */
} tBTA_AV_SDP_RES;
+/* data type for BTA_AV_API_OFFLOAD_RSP_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AV_STATUS status;
+} tBTA_AV_API_STATUS_RSP;
+
+
/* type for SEP control block */
typedef struct
{
tBTA_AV_ROLE_RES role_res;
tBTA_AV_SDP_RES sdp_res;
tBTA_AV_API_META_RSP api_meta_rsp;
+ tBTA_AV_API_STATUS_RSP api_status_rsp;
} tBTA_AV_DATA;
typedef void (tBTA_AV_VDP_DATA_ACT)(void *p_scb);
UINT8 q_tag; /* identify the associated q_info union member */
BOOLEAN no_rtp_hdr; /* TRUE if add no RTP header*/
UINT16 uuid_int; /*intended UUID of Initiator to connect to */
+ BOOLEAN offload_start_pending;
} tBTA_AV_SCB;
#define BTA_AV_RC_ROLE_MASK 0x10
extern void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
extern void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
extern void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_offload_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+extern void bta_av_offload_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
+
/* ssm action functions - vdp specific */
extern void bta_av_do_disc_vdp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
BTA_AV_ROLE_RES,
BTA_AV_DELAY_CO,
BTA_AV_OPEN_AT_INC,
+ BTA_AV_OFFLOAD_REQ,
+ BTA_AV_OFFLOAD_RSP,
BTA_AV_NUM_SACTIONS
};
/* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
/* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
-/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_OFFLOAD_START_EVT */{BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
+/* API_OFFLOAD_START_RSP_EVT */{BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_INIT_SST }
};
/* state table for incoming state */
/* 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 }
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_OFFLOAD_START_EVT */{BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST },
+/* API_OFFLOAD_START_RSP_EVT */{BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }
};
/* state table for opening state */
/* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
/* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
-/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* API_OFFLOAD_START_EVT */{BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST },
+/* API_OFFLOAD_START_RSP_EVT */{BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }
};
/* state table for open state */
/* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
/* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
-/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* API_OFFLOAD_START_EVT */{BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST },
+/* API_OFFLOAD_START_RSP_EVT */{BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }
};
/* state table for reconfig state */
/* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
-/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CONT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SUSPEND_CONT, BTA_AV_RCFG_SST },
/* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
-/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_OFFLOAD_START_EVT */{BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_RCFG_SST },
+/* API_OFFLOAD_START_RSP_EVT */{BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }
};
/* state table for closing state */
/* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST },
/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
/* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
-/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }
+/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* API_OFFLOAD_START_EVT */{BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST },
+/* API_OFFLOAD_START_RSP_EVT */{BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }
};
/* type for state table */
* limitations under the License.
*
******************************************************************************/
+
+#define LOG_TAG "bt_hf_client"
+
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "bta_hf_client_api.h"
#include "bta_hf_client_int.h"
+#include "osi/include/log.h"
#include "port_api.h"
/* Uncomment to enable AT traffic dumping */
{
bta_hf_client_cb.scb.at_cb.resp_timer_on = FALSE;
- APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting");
-
- bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+ if (bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_CNUM) {
+ LOG_INFO("%s timed out waiting for AT+CNUM response; spoofing OK.", __func__);
+ bta_hf_client_handle_ok();
+ } else {
+ APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting");
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+ }
}
}
/* spec forces 16 chars max, plus \0 here */
char opstr[17];
int res;
- int offset;
+ int offset = 0;
AT_CHECK_EVENT(buffer, "+COPS:");
break;
case BTA_HF_CLIENT_AT_BRSF:
- if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_CODEC)
+ if ((bta_hf_client_cb.scb.features & BTA_HF_CLIENT_FEAT_CODEC)
+ && (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_CODEC))
{
bta_hf_client_send_at_bac();
break;
break;
case BTA_HF_CLIENT_AT_CMER:
- if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY)
+ if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY
+ && bta_hf_client_cb.scb.features & BTA_HF_CLIENT_FEAT_3WAY)
{
bta_hf_client_send_at_chld('?', 0);
}
#include "bt_target.h"
#include "bt_types.h"
#include "btm_api.h"
-#include "uipc_msg.h"
#if BLE_INCLUDED == TRUE
#include "btm_ble_api.h"
#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */
#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */
-#define BTA_AV_MEDIA_SINK_CFG_EVT 20 /* command to configure codec */
+#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 22
+#define BTA_AV_MAX_EVT 23
typedef UINT8 tBTA_AV_EVT;
tBTA_AV_META_MSG meta_msg;
tBTA_AV_REJECT reject;
tBTA_AV_RC_FEAT rc_feat;
+ tBTA_AV_STATUS status;
} tBTA_AV;
/* union of data associated with AV Media callback */
*******************************************************************************/
void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt);
+/*******************************************************************************
+**
+** Function BTA_AvOffloadStart
+**
+** Description Request Starting of A2DP Offload.
+** This function is used to start A2DP offload if vendor lib has
+** the feature enabled.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvOffloadStart(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+**
+** Function BTA_AvOffloadStartRsp
+**
+** Description Response from vendor library indicating response for
+** OffloadStart.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status);
+
+
#ifdef __cplusplus
}
#endif
BTIF_AV_STOP_STREAM_REQ_EVT,
BTIF_AV_SUSPEND_STREAM_REQ_EVT,
BTIF_AV_SINK_CONFIG_REQ_EVT,
+ BTIF_AV_OFFLOAD_START_REQ_EVT,
} btif_av_sm_event_t;
void btif_config_save(void);
void btif_config_flush(void);
-int btif_config_clear(void);
+bool btif_config_clear(void);
// TODO(zachoverflow): Eww...we need to move these out. These are peer specific, not config general.
bool btif_get_address_type(const BD_ADDR bd_addr, int *p_addr_type);
#include <stdint.h>
-#define BTSNOOZ_CURRENT_VERSION 0x01
+#define BTSNOOZ_CURRENT_VERSION 0x02
// The preamble is stored un-encrypted as the first part
// of the file.
// One header for each HCI packet
typedef struct btsnooz_header_t {
uint16_t length;
+ uint16_t packet_length;
uint32_t delta_time_ms;
uint8_t type;
} __attribute__((__packed__)) btsnooz_header_t;
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);
static int config_clear(void) {
LOG_INFO("%s", __func__);
- return btif_config_clear();
+ return btif_config_clear() ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
static const bt_interface_t bluetoothInterface = {
CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
CASE_RETURN_STR(BTA_AV_REJECT_EVT)
CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+ CASE_RETURN_STR(BTA_AV_OFFLOAD_START_RSP_EVT)
CASE_RETURN_STR(BTIF_SM_ENTER_EVT)
CASE_RETURN_STR(BTIF_SM_EXIT_EVT)
CASE_RETURN_STR(BTIF_AV_CONNECT_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_SINK_CONFIG_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
default: return "UNKNOWN_EVENT";
}
}
btif_rc_handler(event, p_data);
break;
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTIF_TRACE_ERROR("BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started IDLE");
+ btif_a2dp_on_offload_started(BTA_AV_FAIL);
+ break;
+
default:
BTIF_TRACE_WARNING("%s : unhandled event:%s", __FUNCTION__,
dump_av_sm_event_name(event));
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 OPENING");
+ break;
+
CHECK_RC_EVENT(event, p_data);
default:
btif_rc_handler(event, (tBTA_AV*)p_data);
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");
+ break;
+
default:
BTIF_TRACE_WARNING("%s : unhandled event:%s", __FUNCTION__,
dump_av_sm_event_name(event));
btif_queue_advance();
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 Opened");
+ break;
+
CHECK_RC_EVENT(event, p_data);
default:
btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
break;
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTA_AvOffloadStart(btif_av_cb.bta_handle);
+ break;
+
+ case BTA_AV_OFFLOAD_START_RSP_EVT:
+
+ btif_a2dp_on_offload_started(p_av->status);
+ break;
+
CHECK_RC_EVENT(event, p_data);
default:
#include <pthread.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "bt_types.h"
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+static const char *CONFIG_FILE_PATH = "bt_config.conf";
+static const char *CONFIG_BACKUP_PATH = "bt_config.bak";
+#else // !defined(OS_GENERIC)
static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
-static const char *LEGACY_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.xml";
+static const char *CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
+#endif // defined(OS_GENERIC)
static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
static void timer_config_save_cb(void *data);
pthread_mutex_init(&lock, NULL);
config = config_new(CONFIG_FILE_PATH);
if (!config) {
- LOG_WARN("%s unable to load config file; attempting to transcode legacy file.", __func__);
- config = btif_config_transcode(LEGACY_CONFIG_FILE_PATH);
+ LOG_WARN("%s unable to load config file: %s; using backup.",
+ __func__, CONFIG_FILE_PATH);
+ config = config_new(CONFIG_BACKUP_PATH);
if (!config) {
- LOG_WARN("%s unable to transcode legacy file, starting unconfigured.", __func__);
+ LOG_ERROR("%s unable to load backup; creating empty config.", __func__);
config = config_new_empty();
if (!config) {
LOG_ERROR("%s unable to allocate a config object.", __func__);
goto error;
}
}
-
- if (config_save(config, CONFIG_FILE_PATH))
- unlink(LEGACY_CONFIG_FILE_PATH);
}
btif_config_devcache_cleanup();
btif_config_write();
}
-int btif_config_clear(void){
+bool btif_config_clear(void){
assert(config != NULL);
assert(alarm_timer != NULL);
return false;
}
- int ret = config_save(config, CONFIG_FILE_PATH);
+ bool ret = config_save(config, CONFIG_FILE_PATH);
pthread_mutex_unlock(&lock);
return ret;
}
btif_config_devcache_cleanup();
pthread_mutex_lock(&lock);
+ rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
+ sync();
config_save(config, CONFIG_FILE_PATH);
pthread_mutex_unlock(&lock);
}
// Total btsnoop memory log buffer size
#ifndef BTSNOOP_MEM_BUFFER_SIZE
-static const size_t BTSNOOP_MEM_BUFFER_SIZE = (128 * 1024);
+static const size_t BTSNOOP_MEM_BUFFER_SIZE = (172 * 1024);
#endif
// Block size for copying buffers (for compression/encoding etc.)
static void btsnoop_cb(const uint16_t type, const uint8_t *data, const size_t length) {
btsnooz_header_t header;
+ // Only log packet content for HCI commands and events (privacy).
+ size_t included_length = 0;
+ switch (type) {
+ case BT_EVT_TO_LM_HCI_CMD:
+ included_length = length;
+ break;
+ case BT_EVT_TO_BTU_HCI_EVT:
+ included_length = length;
+ break;
+ case BT_EVT_TO_LM_HCI_ACL:
+ case BT_EVT_TO_BTU_HCI_ACL:
+ included_length = 4;
+ break;
+ case BT_EVT_TO_LM_HCI_SCO:
+ case BT_EVT_TO_BTU_HCI_SCO:
+ included_length = 2;
+ break;
+ }
+
// Make room in the ring buffer
- while (ringbuffer_available(buffer) < (length + sizeof(btsnooz_header_t))) {
+ while (ringbuffer_available(buffer) < (included_length + sizeof(btsnooz_header_t))) {
ringbuffer_pop(buffer, (uint8_t *)&header, sizeof(btsnooz_header_t));
ringbuffer_delete(buffer, header.length - 1);
}
const uint64_t now = btif_debug_ts();
header.type = REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type);
- header.length = length;
+ header.length = included_length + 1; // +1 for type byte.
+ header.packet_length = length + 1; // +1 for type byte.
header.delta_time_ms = last_timestamp_ms ? now - last_timestamp_ms : 0;
last_timestamp_ms = now;
ringbuffer_insert(buffer, (uint8_t *)&header, sizeof(btsnooz_header_t));
- ringbuffer_insert(buffer, data, length - 1);
+ ringbuffer_insert(buffer, data, included_length);
}
static bool btsnoop_compress(ringbuffer_t *rb_dst, ringbuffer_t *rb_src) {
}
}
+ // 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 (!bdaddr_equals(p_auth_cmpl->bd_addr, pairing_cb.bd_addr)) {
+ char address[32];
+ bdaddr_to_string(&p_auth_cmpl->bd_addr, address, sizeof(address));
+ LOG_INFO("%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)
{
tBTA_AG_RES_DATA ag_res;
/* Format the response */
- sprintf (ag_res.str, "0,0,\"%s\"", cops);
+ sprintf (ag_res.str, "0,0,\"%.16s\"", cops);
ag_res.ok_flag = BTA_AG_OK_DONE;
BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_COPS_RES, &ag_res);
#include <sys/time.h>
#include <errno.h>
+#define LOG_TAG "BTIF-MEDIA"
+
#include "bt_target.h"
#include "osi/include/fixed_queue.h"
#include "gki.h"
#define BTIF_MEDIA_BITRATE_STEP 5
#endif
-/* Middle quality quality setting @ 44.1 khz */
-#define DEFAULT_SBC_BITRATE 328
+#ifndef BTIF_A2DP_DEFAULT_BITRATE
+/* High quality quality setting @ 44.1 khz */
+#define BTIF_A2DP_DEFAULT_BITRATE 328
+#endif
#ifndef BTIF_A2DP_NON_EDR_MAX_RATE
#define BTIF_A2DP_NON_EDR_MAX_RATE 229
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_START)
+
default:
return "UNKNOWN MSG ID";
}
break;
}
+ case A2DP_CTRL_CMD_OFFLOAD_START:
+ btif_dispatch_sm_event(BTIF_AV_OFFLOAD_START_REQ_EVT, NULL, 0);
+ break;
+
default:
APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
static UINT16 btif_media_task_get_sbc_rate(void)
{
- UINT16 rate = DEFAULT_SBC_BITRATE;
+ UINT16 rate = BTIF_A2DP_DEFAULT_BITRATE;
/* restrict bitrate if a2dp link is non-edr */
if (!btif_av_is_peer_edr())
GKI_disable();
/* for now hardcode 44.1 khz 16 bit stereo PCM format */
- media_feeding.cfg.pcm.sampling_freq = 44100;
- media_feeding.cfg.pcm.bit_per_sample = 16;
- media_feeding.cfg.pcm.num_channel = 2;
+ media_feeding.cfg.pcm.sampling_freq = BTIF_A2DP_SRC_SAMPLING_RATE;
+ 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;
if (bta_av_co_audio_set_codec(&media_feeding, &status))
btif_media_task_stop_aa_req();
}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_offload_started
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+void btif_a2dp_on_offload_started(tBTA_AV_STATUS status)
+{
+ tA2DP_CTRL_ACK ack;
+ APPL_TRACE_EVENT("%s status %d", __func__, status);
+
+ switch (status) {
+ case BTA_AV_SUCCESS:
+ ack = A2DP_CTRL_ACK_SUCCESS;
+ break;
+
+ case BTA_AV_FAIL_RESOURCES:
+ APPL_TRACE_ERROR("%s FAILED UNSUPPORTED", __func__);
+ ack = A2DP_CTRL_ACK_UNSUPPORTED;
+ break;
+ default:
+ APPL_TRACE_ERROR("%s FAILED", __func__);
+ ack = A2DP_CTRL_ACK_FAILURE;
+ break;
+ }
+ a2dp_cmd_acknowledge(ack);
+}
+
/* when true media task discards any rx frames */
void btif_a2dp_set_rx_flush(BOOLEAN enable)
{
rc_features |= BTRC_FEAT_BROWSE;
}
+#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)
{
*******************************************************************************/
void GKI_freebuf (void *p_buf)
{
- osi_free((BUFFER_HDR_T *)p_buf - 1);
+ if (p_buf)
+ osi_free((BUFFER_HDR_T *)p_buf - 1);
}
src/hci_packet_parser.c \
src/low_power_manager.c \
src/packet_fragmenter.c \
- src/vendor.c
+ src/vendor.c \
+ EventLogTags.logtags
ifeq ($(BLUETOOTH_HCI_USE_MCT),true)
LOCAL_CFLAGS += -DHCI_USE_MCT
$(LOCAL_PATH)/../osi/include \
$(LOCAL_PATH)/../stack/include \
$(LOCAL_PATH)/../utils/include \
+ $(LOCAL_PATH)/../bta/include \
$(bdroid_C_INCLUDES)
LOCAL_MODULE := libbt-hci
LOCAL_CFLAGS := -Wall -Werror $(bdroid_CFLAGS)
LOCAL_MODULE := net_test_hci
LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_SHARED_LIBRARIES := liblog libdl libpower
LOCAL_STATIC_LIBRARIES := libbt-hci libosi libcutils libbtcore
include $(BUILD_NATIVE_TEST)
--- /dev/null
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1010000 bt_hci_timeout (opcode|1)
* specific epilog process once it has been done.
*/
BT_VND_OP_EPILOG,
+
+/* [operation]
+ * Call to the vendor module so that it can perform all vendor-specific
+ * operations to start offloading a2dp media encode & tx.
+ * [input param]
+ * pointer to bt_vendor_op_a2dp_offload_start_t containing elements
+ * required for VND FW to setup a2dp offload.
+ * [return]
+ * 0 - default, dont care.
+ * [callback]
+ * Must call a2dp_offload_start_cb to notify the stack of the
+ * completion of vendor specific setup process once it has been done.
+ */
+ BT_VND_OP_A2DP_OFFLOAD_START,
+
+/* [operation]
+ * Call to the vendor module so that it can perform all vendor-specific
+ * operations to suspend offloading a2dp media encode & tx.
+ * [input param]
+ * pointer to bt_vendor_op_a2dp_offload_t containing elements
+ * required for VND FW to setup a2dp offload.
+ * [return]
+ * 0 - default, dont care.
+ * [callback]
+ * Must call a2dp_offload_cb to notify the stack of the
+ * completion of vendor specific setup process once it has been done.
+ */
+ BT_VND_OP_A2DP_OFFLOAD_STOP,
+
} bt_vendor_opcode_t;
/** Power on/off control states */
*/
typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback);
+typedef void (*cfg_a2dp_cb)(bt_vendor_op_result_t result, bt_vendor_opcode_t op, uint8_t bta_av_handle);
+
typedef struct {
/** set to sizeof(bt_vendor_callbacks_t) */
size_t size;
/* notifies caller completion of epilog process */
cfg_result_cb epilog_cb;
+
+ /* notifies status of a2dp offload cmd's */
+ cfg_a2dp_cb a2dp_offload_cb;
} bt_vendor_callbacks_t;
+/** A2DP offload request */
+typedef struct {
+ uint8_t bta_av_handle; /* BTA_AV Handle for callbacks */
+ uint16_t xmit_quota; /* Total ACL quota for light stack */
+ uint16_t acl_data_size; /* Max ACL data size across HCI transport */
+ uint16_t stream_mtu;
+ uint16_t local_cid;
+ uint16_t remote_cid;
+ uint16_t lm_handle;
+ uint8_t is_flushable; /* TRUE if flushable channel */
+ uint32_t stream_source;
+ uint8_t codec_info[10]; /* Codec capabilities array */
+} bt_vendor_op_a2dp_offload_t;
+
/*
* Bluetooth Host/Controller VENDOR Interface
*/
VENDOR_CONFIGURE_FIRMWARE = BT_VND_OP_FW_CFG,
VENDOR_CONFIGURE_SCO = BT_VND_OP_SCO_CFG,
VENDOR_SET_LPM_MODE = BT_VND_OP_LPM_SET_MODE,
- VENDOR_DO_EPILOG = BT_VND_OP_EPILOG
+ VENDOR_DO_EPILOG = BT_VND_OP_EPILOG,
+ VENDOR_A2DP_OFFLOAD_START = BT_VND_OP_A2DP_OFFLOAD_START,
+ VENDOR_A2DP_OFFLOAD_STOP = BT_VND_OP_A2DP_OFFLOAD_STOP,
+ VENDOR_LAST_OP
} vendor_async_opcode_t;
typedef void (*vendor_cb)(bool success);
switch (type) {
case BT_EVT_TO_LM_HCI_CMD:
if (packet->len > 2)
- length = data[2] + 4;
+ length = data[2] + 3;
break;
case BT_EVT_TO_BTU_HCI_EVT:
if (packet->len > 1)
- length = data[1] + 3;
+ length = data[1] + 2;
break;
- // Ignore data for privacy
case BT_EVT_TO_LM_HCI_ACL:
- case BT_EVT_TO_LM_HCI_SCO:
case BT_EVT_TO_BTU_HCI_ACL:
+ if (packet->len > 3)
+ length = (data[2] | (data[3] << 8)) + 4;
+ break;
+
+ case BT_EVT_TO_LM_HCI_SCO:
case BT_EVT_TO_BTU_HCI_SCO:
+ if (packet->len > 2)
+ length = data[2] + 3;
break;
}
#include <assert.h>
#include <cutils/properties.h>
+#include <hardware_legacy/power.h>
#include <string.h>
#include <signal.h>
#include <string.h>
#define PREAMBLE_BUFFER_SIZE 4 // max preamble size, ACL
#define RETRIEVE_ACL_LENGTH(preamble) ((((preamble)[3]) << 8) | (preamble)[2])
+#define BT_HCI_TIMEOUT_TAG_NUM 1010000
+
static const uint8_t preamble_sizes[] = {
HCI_COMMAND_PREAMBLE_SIZE,
HCI_ACL_PREAMBLE_SIZE,
// The hand-off point for data going to a higher layer, set by the higher layer
static fixed_queue_t *upwards_data_queue;
+// Wake lock to prevent sleep mode during bt adapter initialization.
+static const char *WAKE_LOCK_ID = "bt_adapter_init_wakelock";
+
static future_t *shut_down();
static void event_finish_startup(void *context);
goto error;
}
+ // Prevent system from entering suspend mode during bt adapter initialization.
+ int status = acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+ if (status != (int) strlen(WAKE_LOCK_ID)) {
+ LOG_ERROR("%s unable to acquire wake lock: %d", __func__, status);
+ goto error;
+ }
// Make sure we run in a bounded amount of time
non_repeating_timer_restart(startup_timer);
static future_t *shut_down() {
LOG_INFO("%s", __func__);
+ release_wake_lock(WAKE_LOCK_ID);
+
hci_inject->close();
if (thread) {
firmware_is_configured = true;
non_repeating_timer_cancel(startup_timer);
+ release_wake_lock(WAKE_LOCK_ID);
+
future_ready(startup_future, FUTURE_SUCCESS);
startup_future = NULL;
}
static void startup_timer_expired(UNUSED_ATTR void *context) {
LOG_ERROR("%s", __func__);
+
+ release_wake_lock(WAKE_LOCK_ID);
+
future_ready(startup_future, FUTURE_FAIL);
startup_future = NULL;
}
// We shouldn't try to recover the stack from this command timeout.
// If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
LOG_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode);
+ LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
}
LOG_ERROR("%s restarting the bluetooth process.", __func__);
#include "buffer_allocator.h"
#include "bt_vendor_lib.h"
+#include "bta_av_api.h"
#include "osi/include/osi.h"
#include "osi/include/log.h"
#include "vendor.h"
-#define LAST_VENDOR_OPCODE_VALUE VENDOR_DO_EPILOG
static const char *VENDOR_LIBRARY_NAME = "libbt-vendor.so";
static const char *VENDOR_LIBRARY_SYMBOL_NAME = "BLUETOOTH_VENDOR_LIB_INTERFACE";
static const vendor_t interface;
static const allocator_t *buffer_allocator;
static const hci_t *hci;
-static vendor_cb callbacks[LAST_VENDOR_OPCODE_VALUE + 1];
+static vendor_cb callbacks[VENDOR_LAST_OP];
static void *lib_handle;
static bt_vendor_interface_t *lib_interface;
callback(result == BT_VND_OP_RESULT_SUCCESS);
}
+// Called back from vendor library when the a2dp offload machine has to report status of
+// an a2dp offload command.
+static void a2dp_offload_cb(bt_vendor_op_result_t result, bt_vendor_opcode_t op, uint8_t bta_av_handle) {
+ tBTA_AV_STATUS status = (result == BT_VND_OP_RESULT_SUCCESS) ? BTA_AV_SUCCESS : BTA_AV_FAIL_RESOURCES;
+
+ if (op == BT_VND_OP_A2DP_OFFLOAD_START) {
+ BTA_AvOffloadStartRsp(bta_av_handle, status);
+ }
+}
+
static const bt_vendor_callbacks_t lib_callbacks = {
sizeof(lib_callbacks),
firmware_config_cb,
buffer_alloc_cb,
buffer_free_cb,
transmit_cb,
- epilog_cb
+ epilog_cb,
+ a2dp_offload_cb
};
static const vendor_t interface = {
#define BTA_AV_CO_CP_SCMS_T FALSE
#endif
+#ifndef BTIF_A2DP_SRC_SAMPLING_RATE
+#define BTIF_A2DP_SRC_SAMPLING_RATE 44100
+#endif
+
+#ifndef BTIF_A2DP_SRC_BIT_DEPTH
+#define BTIF_A2DP_SRC_BIT_DEPTH 16
+#endif
+
+#ifndef BTIF_A2DP_SRC_NUM_CHANNELS
+#define BTIF_A2DP_SRC_NUM_CHANNELS 2
+#endif
+
/* This feature is used to eanble interleaved scan*/
#ifndef BTA_HOST_INTERLEAVE_SEARCH
#define BTA_HOST_INTERLEAVE_SEARCH FALSE
LOCAL_CFLAGS := -Wall -UNDEBUG
LOCAL_MODULE := net_test_osi
LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libpower
LOCAL_STATIC_LIBRARIES := libosi
include $(BUILD_NATIVE_TEST)
#include <assert.h>
#include <errno.h>
#include <hardware/bluetooth.h>
+#include <hardware_legacy/power.h>
#include <inttypes.h>
#include <malloc.h>
#include <string.h>
// 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;
+static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
static const char *WAKE_LOCK_ID = "bluedroid_timer";
// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
static pthread_mutex_t monitor;
static list_t *alarms;
static timer_t timer;
+static timer_t wakeup_timer;
static bool timer_set;
// All alarm callbacks are dispatched from |callback_thread|
static void reschedule_root_alarm(void);
static void timer_callback(void *data);
static void callback_dispatch(void *context);
+static bool timer_create_internal(const clockid_t clock_id, timer_t *timer);
alarm_t *alarm_new(void) {
// Make sure we have a list we can insert alarms into.
static bool lazy_initialize(void) {
assert(alarms == NULL);
+ // timer_t doesn't have an invalid value so we must track whether
+ // the |timer| variable is valid ourselves.
+ bool timer_initialized = false;
+ bool wakeup_timer_initialized = false;
+
pthread_mutex_init(&monitor, NULL);
alarms = list_new(NULL);
if (!alarms) {
LOG_ERROR("%s unable to allocate alarm list.", __func__);
- return false;
+ goto error;
}
- struct sigevent sigevent;
- memset(&sigevent, 0, sizeof(sigevent));
- sigevent.sigev_notify = SIGEV_THREAD;
- sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
- if (timer_create(CLOCK_ID, &sigevent, &timer) == -1) {
- LOG_ERROR("%s unable to create timer: %s", __func__, strerror(errno));
- return false;
- }
+ if (!timer_create_internal(CLOCK_ID, &timer))
+ goto error;
+ timer_initialized = true;
+
+ if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer))
+ goto error;
+ wakeup_timer_initialized = true;
alarm_expired = semaphore_new(0);
if (!alarm_expired) {
LOG_ERROR("%s unable to create alarm expired semaphore", __func__);
- return false;
+ goto error;
}
callback_thread_active = true;
callback_thread = thread_new("alarm_callbacks");
if (!callback_thread) {
LOG_ERROR("%s unable to create alarm callback thread.", __func__);
- return false;
+ goto error;
}
thread_set_priority(callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
thread_post(callback_thread, callback_dispatch, NULL);
return true;
+
+error:
+ thread_free(callback_thread);
+ callback_thread = NULL;
+
+ callback_thread_active = false;
+
+ semaphore_free(alarm_expired);
+ alarm_expired = NULL;
+
+ if (wakeup_timer_initialized)
+ timer_delete(wakeup_timer);
+
+ if (timer_initialized)
+ timer_delete(timer);
+
+ list_free(alarms);
+ alarms = NULL;
+
+ pthread_mutex_destroy(&monitor);
+
+ return false;
}
static period_ms_t now(void) {
// NOTE: must be called with monitor lock.
static void reschedule_root_alarm(void) {
- bool timer_was_set = timer_set;
assert(alarms != NULL);
- // If used in a zeroed state, disarms the timer
- struct itimerspec wakeup_time;
- memset(&wakeup_time, 0, sizeof(wakeup_time));
+ const bool timer_was_set = timer_set;
+
+ // If used in a zeroed state, disarms the timer.
+ struct itimerspec timer_time;
+ memset(&timer_time, 0, sizeof(timer_time));
if (list_is_empty(alarms))
goto done;
- alarm_t *next = list_front(alarms);
- int64_t next_expiration = next->deadline - now();
+ const alarm_t *next = list_front(alarms);
+ const int64_t next_expiration = next->deadline - now();
if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
if (!timer_set) {
- int status = bt_os_callouts->acquire_wake_lock(WAKE_LOCK_ID);
- if (status != BT_STATUS_SUCCESS) {
+ int status = acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+ if (status != (int) strlen(WAKE_LOCK_ID)) {
LOG_ERROR("%s unable to acquire wake lock: %d", __func__, status);
goto done;
}
}
+ timer_time.it_value.tv_sec = (next->deadline / 1000);
+ timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+
+ // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec for
+ // timers with *_ALARM clock IDs. Although the man page states that the timer
+ // would be canceled, the current behavior (as of Linux kernel 3.17) is that
+ // the callback is issued immediately. The only way to cancel an *_ALARM timer
+ // is to delete the timer. But unfortunately, deleting and re-creating a timer
+ // is rather expensive; every timer_create(2) spawns a new thread. So we simply
+ // set the timer to fire at the largest possible time.
+ //
+ // If we've reached this code path, we're going to grab a wake lock and wait for
+ // the next timer to fire. In that case, there's no reason to have a pending wakeup
+ // timer so we simply cancel it.
+ struct itimerspec end_of_time;
+ memset(&end_of_time, 0, sizeof(end_of_time));
+ end_of_time.it_value.tv_sec = (time_t)((1LL << (sizeof(time_t) * 8 - 1)) - 1);
+ timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
+ } else {
+ // WARNING: do not attempt to use relative timers with *_ALARM clock IDs
+ // in kernels before 3.17 unless you have the following patch:
+ // https://lkml.org/lkml/2014/7/7/576
+ struct itimerspec wakeup_time;
+ memset(&wakeup_time, 0, sizeof(wakeup_time));
wakeup_time.it_value.tv_sec = (next->deadline / 1000);
wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
- } else {
- if (!bt_os_callouts->set_wake_alarm(next_expiration, true, timer_callback, NULL))
- LOG_ERROR("%s unable to set wake alarm for %" PRId64 "ms.", __func__, next_expiration);
+ if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
+ LOG_ERROR("%s unable to set wakeup timer: %s", __func__, strerror(errno));
}
done:
- timer_set = wakeup_time.it_value.tv_sec != 0 || wakeup_time.it_value.tv_nsec != 0;
+ timer_set = timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0;
if (timer_was_set && !timer_set) {
- bt_os_callouts->release_wake_lock(WAKE_LOCK_ID);
+ release_wake_lock(WAKE_LOCK_ID);
}
- if (timer_settime(timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
+ if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
LOG_ERROR("%s unable to set timer: %s", __func__, strerror(errno));
// If next expiration was in the past (e.g. short timer that got context switched)
LOG_DEBUG("%s Callback thread exited", __func__);
}
+
+static bool timer_create_internal(const clockid_t clock_id, timer_t *timer) {
+ assert(timer != NULL);
+
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
+ if (timer_create(clock_id, &sigevent, timer) == -1) {
+ LOG_ERROR("%s unable to create timer with clock %d: %s", __func__, clock_id, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
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);
- fprintf(fp, "[%s]\n", section->name);
+ if (fprintf(fp, "[%s]\n", section->name) < 0) {
+ LOG_ERROR("%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
+ goto error;
+ }
for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) {
const entry_t *entry = (const entry_t *)list_node(enode);
- fprintf(fp, "%s = %s\n", entry->key, entry->value);
+ if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) {
+ LOG_ERROR("%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
+ goto error;
+ }
}
// Only add a separating newline if there are more sections.
- if (list_next(node) != list_end(config->sections))
- fputc('\n', fp);
+ if (list_next(node) != list_end(config->sections)) {
+ if (fputc('\n', fp) == EOF) {
+ LOG_ERROR("%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno));
+ goto error;
+ }
+ }
}
- fflush(fp);
- fclose(fp);
+ if (fclose(fp) == EOF) {
+ LOG_ERROR("%s unable to close file '%s': %s", __func__, temp_filename, strerror(errno));
+ fp = NULL;
+ goto error;
+ }
+ fp = NULL;
// Change the file's permissions to Read/Write by User and Group
if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
return true;
error:;
+ if (fp != NULL)
+ fclose(fp);
unlink(temp_filename);
osi_free(temp_filename);
return false;
LOCAL_CFLAGS += $(bdroid_CFLAGS) -std=c99
-ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
-LOCAL_CFLAGS += \
- -DBOARD_HAVE_BLUETOOTH_BCM
-endif
-
LOCAL_SRC_FILES:= \
./a2dp/a2d_api.c \
./a2dp/a2d_sbc.c \
UINT16 result;
tL2CAP_CFG_INFO cfg;
tBTM_STATUS rc;
+#if defined(AVDT_DISABLE_3DH) && (AVDT_DISABLE_3DH == TRUE)
+ tACL_CONN *p_acl_cb;
+#endif
UNUSED(psm);
/* do we already have a control channel for this peer? */
p_tbl->state = AVDT_AD_ST_SEC_ACP;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
+#if defined(AVDT_DISABLE_3DH) && (AVDT_DISABLE_3DH == TRUE)
+ 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 |
+ HCI_PKT_TYPES_MASK_NO_3_DH1 |
+ HCI_PKT_TYPES_MASK_NO_3_DH3 |
+ HCI_PKT_TYPES_MASK_NO_3_DH5));
+#endif
+
/* Check the security */
rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
FALSE, BTM_SEC_PROTO_AVDT,
tAVDT_TC_TBL *p_tbl;
tL2CAP_CFG_INFO cfg;
tAVDT_CCB *p_ccb;
+#if defined(AVDT_DISABLE_3DH) && (AVDT_DISABLE_3DH == TRUE)
+ tACL_CONN *p_acl_cb;
+#endif
AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
lcid, result);
p_tbl->lcid = lcid;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
+#if defined(AVDT_DISABLE_3DH) && (AVDT_DISABLE_3DH == TRUE)
+ 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 |
+ HCI_PKT_TYPES_MASK_NO_3_DH1 |
+ HCI_PKT_TYPES_MASK_NO_3_DH3 |
+ HCI_PKT_TYPES_MASK_NO_3_DH5));
+#endif
+
/* Check the security */
btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
TRUE, BTM_SEC_PROTO_AVDT,
STREAM_TO_BDADDR (peer_rpa, p);
}
- /* possiblly receive connection complete with resolvable random on
- slave role while the device has been paired */
- if (!match && role == HCI_ROLE_SLAVE && BTM_BLE_IS_RESOLVE_BDA(bda))
+ /* possiblly receive connection complete with resolvable random while
+ 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);
}
if (pin_length >= 16 ||
key_type == BTM_LKEY_TYPE_AUTH_COMB ||
key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
- // Set the fiag if the link key was made by using either a 16 digit
+ // Set the flag if the link key was made by using either a 16 digit
// pin or MITM.
- p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED | BTM_SEC_LINK_KEY_AUTHED;
}
}
tL2CAP_CFG_INFO **pp_our_cfg, tL2CAP_CH_CFG_BITS *p_our_cfg_bits,
tL2CAP_CFG_INFO **pp_peer_cfg, tL2CAP_CH_CFG_BITS *p_peer_cfg_bits);
+/*******************************************************************************
+**
+** Function L2CA_GetConnectionConfig
+**
+** Description This function polulates the mtu, remote cid & lm_handle for
+** a given local L2CAP channel
+**
+** Returns TRUE if successful
+**
+*******************************************************************************/
+extern BOOLEAN L2CA_GetConnectionConfig(UINT16 lcid, UINT16 *mtu, UINT16 *rcid, UINT16 *handle);
+
#if (BLE_INCLUDED == TRUE)
/*******************************************************************************
**
+++ /dev/null
-/******************************************************************************
- *
- * Copyright (C) 1999-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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This file contains sync message over UIPC
- *
- ******************************************************************************/
-
-#ifndef UIPC_MSG_H
-#define UIPC_MSG_H
-
-#include "bt_types.h"
-
-/****************************************************************************/
-/* UIPC version number: 1.0 */
-/****************************************************************************/
-#define UIPC_VERSION_MAJOR 0x0001
-#define UIPC_VERSION_MINOR 0x0000
-
-
-/********************************
-
- UIPC Management Messages
-
-********************************/
-
-/* tUIPC_STATUS codes*/
-enum
-{
- UIPC_STATUS_SUCCESS,
- UIPC_STATUS_FAIL
-};
-typedef UINT8 tUIPC_STATUS;
-
-/* op_code */
-#define UIPC_OPEN_REQ 0x00
-#define UIPC_OPEN_RSP 0x01
-#define UIPC_CLOSE_REQ 0x02
-#define UIPC_CLOSE_RSP 0x03
-
-/* Structure of UIPC_OPEN_REQ message */
-typedef struct
-{
- UINT8 opcode; /* UIPC_OPEN_REQ */
-} tUIPC_OPEN_REQ;
-#define UIPC_OPEN_REQ_MSGLEN (1)
-
-/* Structure of UIPC_OPEN_RSP message */
-typedef struct
-{
- UINT8 opcode; /* UIPC_OPEN_RESP */
- tUIPC_STATUS status; /* UIPC_STATUS */
- UINT16 version_major; /* UIPC_VERSION_MAJOR */
- UINT16 version_minor; /* UIPC_VERSION_MINOR */
- UINT8 num_streams; /* Number of simultaneous streams supported by the light stack */
-} tUIPC_OPEN_RSP;
-#define UIPC_OPEN_RSP_MSGLEN (7)
-
-/* Structure of UIPC_CLOSE_REQ message */
-typedef struct t_uipc_close_req
-{
- UINT8 opcode; /* UIPC_CLOSE_REQ */
-} tUIPC_CLOSE_REQ;
-#define UIPC_CLOSE_REQ_MSGLEN (1)
-
-/* Structure of UIPC_CLOSE_RSP message, only for BTC, full stack may ignore it */
-typedef struct t_uipc_close_rsp
-{
- UINT8 opcode; /* UIPC_CLOSE_RSP */
-} tUIPC_CLOSE_RSP;
-#define UIPC_CLOSE_RSP_MSGLEN (1)
-
-/* UIPC management message structures */
-typedef union
-{
- UINT8 opcode;
- tUIPC_OPEN_REQ open_req;
- tUIPC_OPEN_RSP open_resp;
- tUIPC_CLOSE_REQ close_req;
-} tUIPC_MSG;
-
-#define UIPC_MGMT_MSG_MAXLEN (sizeof(tUIPC_MSG))
-
-#define IPC_LOG_MSG_LEN 100
-typedef struct t_uipc_log_msg
-{
- UINT32 trace_set_mask;
- UINT8 msg[IPC_LOG_MSG_LEN];
-} tUIPC_LOG_MSG;
-#define UIPC_LOG_MSGLEN (IPC_LOG_MSG_LEN + 4)
-
-typedef struct
-{
- UINT8 opcode; /* A2DP_START_REQ */
- UINT16 lcid;
- UINT16 curr_mtu;
-}tA2DP_START_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* A2DP_STOP_REQ */
- UINT16 lcid;
-}tA2DP_STOP_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* A2DP_SUSPEND_REQ */
- UINT16 lcid;
-}tA2DP_SUSPEND_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* A2DP_CLEANUP_REQ */
- UINT16 lcid;
- UINT16 curr_mtu;
-} tA2DP_CLEANUP_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* A2DP_START_RESP, A2DP_STOP_RESP, A2DP_CLEANUP_RESP, A2DP_SUSPEND_RESP */
- UINT16 lcid;
-}tA2DP_GENERIC_RESP;
-
-#define AUDIO_CODEC_NONE 0x0000
-#define AUDIO_CODEC_SBC_ENC 0x0001
-#define AUDIO_CODEC_SBC_DEC 0x0002
-#define AUDIO_CODEC_MP3_ENC 0x0004
-#define AUDIO_CODEC_MP3_DEC 0x0008
-#define AUDIO_CODEC_AAC_ENC 0x0010
-#define AUDIO_CODEC_AAC_DEC 0x0020
-#define AUDIO_CODEC_AAC_PLUS_ENC 0x0040
-#define AUDIO_CODEC_AAC_PLUS_DEC 0x0080
-#define AUDIO_CODEC_MP2_ENC 0x0100
-#define AUDIO_CODEC_MP2_DEC 0x0200
-#define AUDIO_CODEC_MP2_5_ENC 0x0400
-#define AUDIO_CODEC_MP2_5_DEC 0x0800
-
-typedef UINT16 tAUDIO_CODEC_TYPE;
-
-/* SBC CODEC Parameters */
-
-#define CODEC_INFO_SBC_SF_16K 0x00
-#define CODEC_INFO_SBC_SF_32K 0x01
-#define CODEC_INFO_SBC_SF_44K 0x02
-#define CODEC_INFO_SBC_SF_48K 0x03
-
-#define CODEC_INFO_SBC_BLOCK_4 0x00
-#define CODEC_INFO_SBC_BLOCK_8 0x01
-#define CODEC_INFO_SBC_BLOCK_12 0x02
-#define CODEC_INFO_SBC_BLOCK_16 0x03
-
-#define CODEC_INFO_SBC_CH_MONO 0x00
-#define CODEC_INFO_SBC_CH_DUAL 0x01
-#define CODEC_INFO_SBC_CH_STEREO 0x02
-#define CODEC_INFO_SBC_CH_JS 0x03
-
-#define CODEC_INFO_SBC_ALLOC_LOUDNESS 0x00
-#define CODEC_INFO_SBC_ALLOC_SNR 0x01
-
-#define CODEC_INFO_SBC_SUBBAND_4 0x00
-#define CODEC_INFO_SBC_SUBBAND_8 0x01
-
-/* MPEG audio version ID */
-#define CODEC_INFO_MP25_ID 0x00
-#define CODEC_INFO_RESERVE 0x01
-#define CODEC_INFO_MP2_ID 0x02
-#define CODEC_INFO_MP3_ID 0x03
-
-#define CODEC_INFO_MP3_PROTECTION_ON 0x00
-#define CODEC_INFO_MP3_PROTECTION_OFF 0x01
-
-#define CODEC_INFO_MP3_BR_IDX_FREE 0x00
-#define CODEC_INFO_MP3_BR_IDX_32K 0x01
-#define CODEC_INFO_MP3_BR_IDX_40K 0x02
-#define CODEC_INFO_MP3_BR_IDX_48K 0x03
-#define CODEC_INFO_MP3_BR_IDX_56K 0x04
-#define CODEC_INFO_MP3_BR_IDX_64K 0x05
-#define CODEC_INFO_MP3_BR_IDX_80K 0x06
-#define CODEC_INFO_MP3_BR_IDX_96K 0x07
-#define CODEC_INFO_MP3_BR_IDX_112K 0x08
-#define CODEC_INFO_MP3_BR_IDX_128K 0x09
-#define CODEC_INFO_MP3_BR_IDX_160K 0x0A
-#define CODEC_INFO_MP3_BR_IDX_192K 0x0B
-#define CODEC_INFO_MP3_BR_IDX_224K 0x0C
-#define CODEC_INFO_MP3_BR_IDX_256K 0x0D
-#define CODEC_INFO_MP3_BR_IDX_320K 0x0E
-
-#define CODEC_INFO_MP3_SF_44K 0x00
-#define CODEC_INFO_MP3_SF_48K 0x01
-#define CODEC_INFO_MP3_SF_32K 0x02
-
-#define CODEC_INFO_MP3_MODE_STEREO 0x00
-#define CODEC_INFO_MP3_MODE_JS 0x01
-#define CODEC_INFO_MP3_MODE_DUAL 0x02
-#define CODEC_INFO_MP3_MODE_SINGLE 0x03
-
-/* layer 3, type of joint stereo coding method (intensity and ms) */
-#define CODEC_INFO_MP3_MODE_EXT_OFF_OFF 0x00
-#define CODEC_INFO_MP3_MODE_EXT_ON_OFF 0x01
-#define CODEC_INFO_MP3_MODE_EXT_OFF_ON 0x02
-#define CODEC_INFO_MP3_MODE_EXT_ON_ON 0x03
-
-
-#define CODEC_INFO_MP2_PROTECTION_ON 0x00
-#define CODEC_INFO_MP2_PROTECTION_OFF 0x01
-
-#define CODEC_INFO_MP2_BR_IDX_FREE 0x00
-#define CODEC_INFO_MP2_BR_IDX_8K 0x01
-#define CODEC_INFO_MP2_BR_IDX_16K 0x02
-#define CODEC_INFO_MP2_BR_IDX_24K 0x03
-#define CODEC_INFO_MP2_BR_IDX_32K 0x04
-#define CODEC_INFO_MP2_BR_IDX_40K 0x05
-#define CODEC_INFO_MP2_BR_IDX_48K 0x06
-#define CODEC_INFO_MP2_BR_IDX_56K 0x07
-#define CODEC_INFO_MP2_BR_IDX_64K 0x08
-#define CODEC_INFO_MP2_BR_IDX_80K 0x09
-#define CODEC_INFO_MP2_BR_IDX_96K 0x0A
-#define CODEC_INFO_MP2_BR_IDX_112K 0x0B
-#define CODEC_INFO_MP2_BR_IDX_128K 0x0C
-#define CODEC_INFO_MP2_BR_IDX_144K 0x0D
-#define CODEC_INFO_MP2_BR_IDX_160K 0x0E
-
-#define CODEC_INFO_MP2_SF_22K 0x00
-#define CODEC_INFO_MP2_SF_24K 0x01
-#define CODEC_INFO_MP2_SF_16K 0x02
-
-#define CODEC_INFO_MP2_MODE_STEREO 0x00
-#define CODEC_INFO_MP2_MODE_JS 0x01
-#define CODEC_INFO_MP2_MODE_DUAL 0x02
-#define CODEC_INFO_MP2_MODE_SINGLE 0x03
-
-/* layer 3, type of joint stereo coding method (intensity and ms) */
-#define CODEC_INFO_MP2_MODE_EXT_OFF_OFF 0x00
-#define CODEC_INFO_MP2_MODE_EXT_ON_OFF 0x01
-#define CODEC_INFO_MP2_MODE_EXT_OFF_ON 0x02
-#define CODEC_INFO_MP2_MODE_EXT_ON_ON 0x03
-
-#define CODEC_INFO_MP2_SAMPLE_PER_FRAME 576
-
-/* mpeg 2.5 layer 3 decoder */
-
-#define CODEC_INFO_MP25_PROTECTION_ON 0x00
-#define CODEC_INFO_MP25_PROTECTION_OFF 0x01
-
-#define CODEC_INFO_MP25_BR_IDX_FREE 0x00
-#define CODEC_INFO_MP25_BR_IDX_8K 0x01
-#define CODEC_INFO_MP25_BR_IDX_16K 0x02
-#define CODEC_INFO_MP25_BR_IDX_24K 0x03
-#define CODEC_INFO_MP25_BR_IDX_32K 0x04
-#define CODEC_INFO_MP25_BR_IDX_40K 0x05
-#define CODEC_INFO_MP25_BR_IDX_48K 0x06
-#define CODEC_INFO_MP25_BR_IDX_56K 0x07
-#define CODEC_INFO_MP25_BR_IDX_64K 0x08
-#define CODEC_INFO_MP25_BR_IDX_80K 0x09
-#define CODEC_INFO_MP25_BR_IDX_96K 0x0A
-#define CODEC_INFO_MP25_BR_IDX_112K 0x0B
-#define CODEC_INFO_MP25_BR_IDX_128K 0x0C
-#define CODEC_INFO_MP25_BR_IDX_144K 0x0D
-#define CODEC_INFO_MP25_BR_IDX_160K 0x0E
-
-#define CODEC_INFO_MP25_SF_11K 0x00
-#define CODEC_INFO_MP25_SF_12K 0x01
-#define CODEC_INFO_MP25_SF_8K 0x02
-
-#define CODEC_INFO_MP25_MODE_STEREO 0x00
-#define CODEC_INFO_MP25_MODE_JS 0x01
-#define CODEC_INFO_MP25_MODE_DUAL 0x02
-#define CODEC_INFO_MP25_MODE_SINGLE 0x03
-
-/* layer 3, type of joint stereo coding method (intensity and ms) */
-#define CODEC_INFO_MP25_MODE_EXT_OFF_OFF 0x00
-#define CODEC_INFO_MP25_MODE_EXT_ON_OFF 0x01
-#define CODEC_INFO_MP25_MODE_EXT_OFF_ON 0x02
-#define CODEC_INFO_MP25_MODE_EXT_ON_ON 0x03
-
-#define CODEC_INFO_MP25_SAMPLE_PER_FRAME 576
-
-/* AAC/AAC+ CODEC Parameters */
-#define CODEC_INFO_AAC_SF_IDX_96K 0x0
-#define CODEC_INFO_AAC_SF_IDX_88K 0x1
-#define CODEC_INFO_AAC_SF_IDX_64K 0x2
-#define CODEC_INFO_AAC_SF_IDX_48K 0x3
-#define CODEC_INFO_AAC_SF_IDX_44K 0x4
-#define CODEC_INFO_AAC_SF_IDX_32K 0x5
-#define CODEC_INFO_AAC_SF_IDX_24K 0x6
-#define CODEC_INFO_AAC_SF_IDX_22K 0x7
-#define CODEC_INFO_AAC_SF_IDX_16K 0x8
-#define CODEC_INFO_AAC_SF_IDX_12K 0x9
-#define CODEC_INFO_AAC_SF_IDX_11K 0xA
-#define CODEC_INFO_AAC_SF_IDX_08K 0xB
-#define CODEC_INFO_AAC_SF_IDX_RESERVE 0xC
-
-#define CODEC_INFO_AAC_BR_RATE_48K 288000
-#define CODEC_INFO_AAC_BR_RATE_44K 264600
-#define CODEC_INFO_AAC_BR_RATE_32K 192000
-
-
-#define CODEC_INFO_AAC_1_CH 1 /*center front speaker */
-#define CODEC_INFO_AAC_2_CH 2 /*left, right front speaker */
-#define CODEC_INFO_AAC_3_CH 3 /*center front speaker, left right front speaker */
-#define CODEC_INFO_AAC_4_CH 4 /*center/rear front speaker, left/right front speaker */
-#define CODEC_INFO_AAC_5_CH 5 /*center, left, right front speaker, left/right surround */
-#define CODEC_INFO_AAC_6_CH 6 /*center, left, right front speaker, left/right surround, LFE */
-#define CODEC_INFO_AAC_7_CH 7 /*(left, right)center/left,right front speaker, left/right surround, LFE */
-
-
-typedef struct
-{
- UINT8 sampling_freq;
- UINT8 channel_mode;
- UINT8 block_length;
- UINT8 num_subbands;
- UINT8 alloc_method;
- UINT8 bitpool_size; /* 2 - 250 */
-} tCODEC_INFO_SBC;
-
-typedef struct
-{
- UINT8 ch_mode;
- UINT8 sampling_freq;
- UINT8 bitrate_index; /* 0 - 14 */
-} tCODEC_INFO_MP3;
-
-typedef struct
-{
- UINT8 ch_mode;
- UINT8 sampling_freq;
- UINT8 bitrate_index; /* 0 - 14 */
-} tCODEC_INFO_MP2;
-
-
-typedef struct
-{
- UINT8 ch_mode;
- UINT8 sampling_freq;
- UINT8 bitrate_index; /* 0 - 14 */
-} tCODEC_INFO_MP2_5;
-
-typedef struct
-{
- UINT16 sampling_freq;
- UINT8 channel_mode; /* 0x02:mono, 0x01:dual */
- UINT32 bitrate; /* 0 - 320K */
- UINT32 sbr_profile; /* 1: ON, 0: OFF */
-} tCODEC_INFO_AAC;
-
-typedef union
-{
- tCODEC_INFO_SBC sbc;
- tCODEC_INFO_MP3 mp3;
- tCODEC_INFO_MP2 mp2;
- tCODEC_INFO_MP2_5 mp2_5;
- tCODEC_INFO_AAC aac;
-} tCODEC_INFO;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_CODEC_CONFIG_REQ */
- tAUDIO_CODEC_TYPE codec_type;
- tCODEC_INFO codec_info;
-} tAUDIO_CODEC_CONFIG_REQ;
-
-#define AUDIO_CONFIG_SUCCESS 0x00
-#define AUDIO_CONFIG_NOT_SUPPORTED 0x01
-#define AUDIO_CONFIG_FAIL_OUT_OF_MEMORY 0x02
-#define AUDIO_CONFIG_FAIL_CODEC_USED 0x03
-#define AUDIO_CONFIG_FAIL_ROUTE 0x04
-typedef UINT8 tAUDIO_CONFIG_STATUS;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_CODEC_CONFIG_RESP */
- tAUDIO_CONFIG_STATUS status;
-} tAUDIO_CODEC_CONFIG_RESP;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_CODEC_SET_BITRATE_REQ */
- tAUDIO_CODEC_TYPE codec_type;
- union
- {
- UINT8 sbc;
- UINT8 mp3;
- UINT32 aac;
- } codec_bitrate;
-} tAUDIO_CODEC_SET_BITRATE_REQ;
-
-#define AUDIO_ROUTE_SRC_FMRX 0x00
-#define AUDIO_ROUTE_SRC_I2S 0x01
-#define AUDIO_ROUTE_SRC_ADC 0x02
-#define AUDIO_ROUTE_SRC_HOST 0x03
-#define AUDIO_ROUTE_SRC_PTU 0x04
-#define AUDIO_ROUTE_SRC_BTSNK 0x05
-#define AUDIO_ROUTE_SRC_NONE 0x80
-#define MAX_AUDIO_ROUTE_SRC 6
-typedef UINT8 tAUDIO_ROUTE_SRC;
-
-#define AUDIO_ROUTE_MIX_NONE 0x00
-#define AUDIO_ROUTE_MIX_HOST 0x01
-#define AUDIO_ROUTE_MIX_PCM 0x02
-#define AUDIO_ROUTE_MIX_CHIRP 0x03
-#define AUDIO_ROUTE_MIX_I2S 0x04
-#define AUDIO_ROUTE_MIX_ADC 0x05
-#define AUDIO_ROUTE_MIX_RESERVED 0x06
-#define MAX_AUDIO_ROUTE_MIX 7
-typedef UINT8 tAUDIO_ROUTE_MIX;
-
-#define AUDIO_ROUTE_OUT_NONE 0x0000
-#define AUDIO_ROUTE_OUT_BTA2DP 0x0001
-#define AUDIO_ROUTE_OUT_FMTX 0x0002
-#define AUDIO_ROUTE_OUT_BTSCO 0x0004
-#define AUDIO_ROUTE_OUT_HOST 0x0008
-#define AUDIO_ROUTE_OUT_DAC 0x0010
-#define AUDIO_ROUTE_OUT_I2S 0x0020
-#define AUDIO_ROUTE_OUT_BTA2DP_DAC 0x0040
-#define AUDIO_ROUTE_OUT_BTA2DP_I2S 0x0080
-#define AUDIO_ROUTE_OUT_BTSCO_DAC 0x0100
-#define AUDIO_ROUTE_OUT_BTSCO_I2S 0x0200
-#define AUDIO_ROUTE_OUT_HOST_BTA2DP 0x0400
-#define AUDIO_ROUTE_OUT_HOST_BTSCO 0x0800
-#define AUDIO_ROUTE_OUT_HOST_DAC 0x1000
-#define AUDIO_ROUTE_OUT_HOST_I2S 0x2000
-#define AUDIO_ROUTE_OUT_DAC_I2S 0x4000
-#define AUDIO_ROUTE_OUT_RESERVED_2 0x8000
-
-#define MAX_AUDIO_SINGLE_ROUTE_OUT 6
-#define MAX_AUDIO_MULTI_ROUTE_OUT 16
-typedef UINT16 tAUDIO_MULTI_ROUTE_OUT;
-typedef UINT8 tAUDIO_ROUTE_OUT;
-
-#define AUDIO_ROUTE_SF_8K 0x00
-#define AUDIO_ROUTE_SF_16K 0x01
-#define AUDIO_ROUTE_SF_32K 0x02
-#define AUDIO_ROUTE_SF_44_1K 0x03
-#define AUDIO_ROUTE_SF_48K 0x04
-#define AUDIO_ROUTE_SF_11K 0x05
-#define AUDIO_ROUTE_SF_12K 0x06
-#define AUDIO_ROUTE_SF_22K 0x07
-#define AUDIO_ROUTE_SF_24K 0x08
-#define AUDIO_ROUTE_SF_NA 0xFF
-typedef UINT8 tAUDIO_ROUTE_SF;
-
-#define AUDIO_ROUTE_EQ_BASS_BOOST 0x00
-#define AUDIO_ROUTE_EQ_CLASSIC 0x01
-#define AUDIO_ROUTE_EQ_JAZZ 0x02
-#define AUDIO_ROUTE_EQ_LIVE 0x03
-#define AUDIO_ROUTE_EQ_NORMAL 0x04
-#define AUDIO_ROUTE_EQ_ROCK 0x05
-#define AUDIO_ROUTE_EQ_BYPASS 0x06
-
-#define AUDIO_ROUTE_DIGITAL_VOLUME_CONTROL 0x07
-
-#define AUDIO_ROUTE_EQ_CONFIG_GAIN 0xFF /* Custion Gain Config */
-typedef UINT8 tAUDIO_ROUTE_EQ;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_ROUTE_CONFIG_REQ */
- tAUDIO_ROUTE_SRC src;
- tAUDIO_ROUTE_SF src_sf;
- tAUDIO_ROUTE_OUT out;
- tAUDIO_ROUTE_SF out_codec_sf;
- tAUDIO_ROUTE_SF out_i2s_sf;
- tAUDIO_ROUTE_EQ eq_mode;
-} tAUDIO_ROUTE_CONFIG_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_ROUTE_CONFIG_RESP */
- tAUDIO_CONFIG_STATUS status;
-} tAUDIO_ROUTE_CONFIG_RESP;
-
-typedef struct
-{
- UINT16 amp[2]; /* left/right 15 bit amplitude value */
- UINT16 tone[2]; /* left/right 12 bit frequency 0 - 4096Hz */
- UINT16 mark[2]; /* left/right 16 bit mark time 0 - 65535ms */
- UINT16 space[2]; /* left/right 16 bit space time 0 - 65535ms */
-} tCHIRP_CONFIG;
-
-typedef struct
-{
- UINT8 pri_l; /* Primary Left scale : 0 ~ 255 */
- UINT8 mix_l; /* Mixing Left scale : 0 ~ 255 */
- UINT8 pri_r; /* Primary Right scale : 0 ~ 255 */
- UINT8 mix_r; /* Mixing Right scale : 0 ~ 255 */
-} tMIX_SCALE_CONFIG;
-
-/* For custon equalizer gain configuration */
-typedef struct
-{
- UINT32 audio_l_g0; /* IIR biquad filter left ch gain 0 */
- UINT32 audio_l_g1; /* IIR biquad filter left ch gain 1 */
- UINT32 audio_l_g2; /* IIR biquad filter left ch gain 2 */
- UINT32 audio_l_g3; /* IIR biquad filter left ch gain 3 */
- UINT32 audio_l_g4; /* IIR biquad filter left ch gain 4 */
- UINT32 audio_l_gl; /* IIR biquad filter left ch global gain */
- UINT32 audio_r_g0; /* IIR biquad filter left ch gain 0 */
- UINT32 audio_r_g1; /* IIR biquad filter left ch gain 1 */
- UINT32 audio_r_g2; /* IIR biquad filter left ch gain 2 */
- UINT32 audio_r_g3; /* IIR biquad filter left ch gain 3 */
- UINT32 audio_r_g4; /* IIR biquad filter left ch gain 4 */
- UINT32 audio_r_gl; /* IIR biquad filter left ch global gain */
-} tEQ_GAIN_CONFIG;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_MIX_CONFIG_REQ */
- tAUDIO_ROUTE_MIX mix_src;
- tAUDIO_ROUTE_SF mix_src_sf;
- tMIX_SCALE_CONFIG mix_scale;
- tCHIRP_CONFIG chirp_config;
-} tAUDIO_MIX_CONFIG_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_MIX_CONFIG_RESP */
- tAUDIO_CONFIG_STATUS status;
-} tAUDIO_MIX_CONFIG_RESP;
-
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_BURST_FRAMES_IND */
- UINT32 burst_size; /* in bytes */
-} tAUDIO_BURST_FRAMES_IND;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_BURST_END_IND */
-} tAUDIO_BURST_END_IND;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_CODEC_FLUSH_REQ */
-} tAUDIO_CODEC_FLUSH_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_EQ_MODE_CONFIG_REQ */
- tAUDIO_ROUTE_EQ eq_mode;
- tEQ_GAIN_CONFIG filter_gain; /* Valid only when eq_mode is 0xFF */
-} tAUDIO_EQ_MODE_CONFIG_REQ;
-
-typedef struct
-{
- UINT8 opcode; /* AUDIO_SCALE_CONFIG_REQ */
- tMIX_SCALE_CONFIG mix_scale;
-} tAUDIO_SCALE_CONFIG_REQ;
-
-#endif /* UIPC_MSG_H */
-
/*******************************************************************************
**
+** Function L2CA_GetConnectionConfig
+**
+** Description This function returns configurations of L2CAP channel
+** pp_l2c_ccb : pointer to this channels L2CAP ccb data.
+**
+** Returns TRUE if successful
+**
+*******************************************************************************/
+BOOLEAN L2CA_GetConnectionConfig(UINT16 lcid, UINT16 *mtu, UINT16 *rcid, UINT16 *handle)
+{
+ tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);;
+
+ L2CAP_TRACE_API ("%s CID: 0x%04x", __func__, lcid);
+
+ if (p_ccb)
+ {
+ *mtu = L2CAP_MTU_SIZE;
+ if (p_ccb->our_cfg.mtu_present)
+ *mtu = p_ccb->our_cfg.mtu;
+
+ *rcid = p_ccb->remote_cid;
+ *handle= p_ccb->p_lcb->handle;
+ return TRUE;
+ }
+
+ L2CAP_TRACE_ERROR ("%s No CCB for CID:0x%04x", __func__, lcid);
+ return FALSE;
+}
+
+/*******************************************************************************
+**
** Function L2CA_RegForNoCPEvt
**
** Description Register callback for Number of Completed Packets event.
btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type);
- }
- else
+ } else {
btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE);
+
+ // If we have a current RPA, use that instead.
+ if (!bdaddr_is_empty((const bt_bdaddr_t *)p_dev_rec->ble.cur_rand_addr)) {
+ memcpy(peer_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN);
+ }
+ }
#endif
if (!btm_ble_topology_check(BTM_BLE_STATE_INIT))
p_mcb->state = RFC_MX_STATE_CONNECTED;
p_mcb->peer_ready = TRUE;
+ PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
}
return;
#
-# Copyright (C) 2014 Google, Inc.
+# Copyright (C) 2015 Google, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := net_test_bluedroid
+LOCAL_MODULE := net_test_bluetooth
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/../../
support/hal.c \
support/pan.c \
support/rfcomm.c \
- main.c
+ main.cpp
LOCAL_SHARED_LIBRARIES += \
liblog \
libbtcore \
libosi
-LOCAL_CFLAGS += -std=c99 -Wall -Wno-unused-parameter -Wno-missing-field-initializers -Werror
+LOCAL_CFLAGS += -Wall -Wno-unused-parameter -Wno-missing-field-initializers -Werror
LOCAL_MULTILIB := 32
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
--- /dev/null
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# 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.
+#
+
+executable("net_test_bluetooth") {
+ testonly = true
+ sources = [
+ "cases/adapter.c",
+ "cases/cases.c",
+ "cases/gatt.c",
+ "cases/pan.c",
+ "cases/rfcomm.c",
+ "support/adapter.c",
+ "support/callbacks.c",
+ "support/gatt.c",
+ "support/hal.c",
+ "support/pan.c",
+ "support/rfcomm.c",
+ "main.cpp",
+ ]
+
+ include_dirs = [
+ "//",
+ "//test/suite",
+ ]
+
+ deps = [
+ "//btcore",
+ "//main:bluetooth.default",
+ "//osi",
+ "//third_party/gtest:gtest_main",
+ ]
+
+ libs = [ "-lpthread", "-lrt", "-ldl" ]
+
+}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
bool adapter_repeated_enable_disable() {
- for (int i = 0; i < 10; ++i) {
+ int i;
+ for (i = 0; i < 10; ++i) {
if (!adapter_enable_disable()) {
return false;
}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
static void create_random_uuid(bt_uuid_t *uuid, int seed) {
srand(seed < 0 ? time(NULL) : seed);
- for (int i = 0; i < 16; ++i) {
+ int i;
+ for (i = 0; i < 16; ++i) {
uuid->uu[i] = (uint8_t) (rand() % 256);
}
}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
bool rfcomm_repeated_connect() {
static const int max_iterations = 128;
- for (int i = 0; i < max_iterations; ++i) {
+ int i;
+ for (i = 0; i < max_iterations; ++i) {
TASSERT(rfcomm_connect(), "Connection failed on attempt %d/%d", i, max_iterations);
}
+++ /dev/null
-/******************************************************************************
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * 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.
- *
- ******************************************************************************/
-
-#include <cutils/properties.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "base.h"
-#include "btcore/include/bdaddr.h"
-#include "cases/cases.h"
-#include "osi/include/config.h"
-#include "support/callbacks.h"
-#include "support/hal.h"
-#include "support/gatt.h"
-#include "support/pan.h"
-#include "support/rfcomm.h"
-
-// How long the watchdog thread should wait before checking if a test has completed.
-// Any individual test will have at least WATCHDOG_PERIOD_SEC and at most
-// 2 * WATCHDOG_PERIOD_SEC seconds to complete.
-static const int WATCHDOG_PERIOD_SEC = 1 * 60;
-static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
-
-const bt_interface_t *bt_interface;
-bt_bdaddr_t bt_remote_bdaddr;
-
-static pthread_t watchdog_thread;
-static int watchdog_id;
-static bool watchdog_running;
-
-static void *watchdog_fn(void *arg) {
- int current_id = 0;
- for (;;) {
- // Check every second whether this thread should exit and check
- // every WATCHDOG_PERIOD_SEC whether we should terminate the process.
- for (int i = 0; watchdog_running && i < WATCHDOG_PERIOD_SEC; ++i) {
- sleep(1);
- }
-
- if (!watchdog_running)
- break;
-
- if (current_id == watchdog_id) {
- printf("Watchdog detected hanging test suite, aborting...\n");
- exit(-1);
- }
- current_id = watchdog_id;
- }
- return NULL;
-}
-
-static bool is_shell_running(void) {
- char property_str[100];
- property_get("init.svc.zygote", property_str, NULL);
- if (!strcmp("running", property_str)) {
- return true;
- }
- return false;
-}
-
-static void print_usage(const char *program_name) {
- printf("Usage: %s [options] [test name]\n", program_name);
- printf("\n");
- printf("Options:\n");
- printf(" %-20sdisplay this help text.\n", "--help");
- printf(" %-20sdo not run sanity suite.\n", "--insanity");
- printf("\n");
- printf("Valid test names are:\n");
- for (size_t i = 0; i < sanity_suite_size; ++i) {
- printf(" %s\n", sanity_suite[i].function_name);
- }
- for (size_t i = 0; i < test_suite_size; ++i) {
- printf(" %s\n", test_suite[i].function_name);
- }
-}
-
-static bool is_valid(const char *test_name) {
- for (size_t i = 0; i < sanity_suite_size; ++i) {
- if (!strcmp(test_name, sanity_suite[i].function_name)) {
- return true;
- }
- }
- for (size_t i = 0; i < test_suite_size; ++i) {
- if (!strcmp(test_name, test_suite[i].function_name)) {
- return true;
- }
- }
- return false;
-}
-
-int main(int argc, char **argv) {
- const char *test_name = NULL;
- bool skip_sanity_suite = false;
-
- for (int i = 1; i < argc; ++i) {
- if (!strcmp("--help", argv[i])) {
- print_usage(argv[0]);
- return 0;
- }
-
- if (!strcmp("--insanity", argv[i])) {
- skip_sanity_suite = true;
- continue;
- }
-
- if (!is_valid(argv[i])) {
- printf("Error: invalid test name.\n");
- print_usage(argv[0]);
- return -1;
- }
-
- if (test_name != NULL) {
- printf("Error: invalid arguments.\n");
- print_usage(argv[0]);
- return -1;
- }
-
- test_name = argv[i];
- }
-
- if (is_shell_running()) {
- printf("Run 'adb shell stop' before running %s.\n", argv[0]);
- return -1;
- }
-
- config_t *config = config_new(CONFIG_FILE_PATH);
- if (!config) {
- printf("Error: unable to open stack config file.\n");
- print_usage(argv[0]);
- return -1;
- }
-
- for (const config_section_node_t *node = config_section_begin(config); node != config_section_end(config); node = config_section_next(node)) {
- const char *name = config_section_name(node);
- if (config_has_key(config, name, "LinkKey") && string_to_bdaddr(name, &bt_remote_bdaddr)) {
- break;
- }
- }
-
- config_free(config);
-
- if (bdaddr_is_empty(&bt_remote_bdaddr)) {
- printf("Error: unable to find paired device in config file.\n");
- print_usage(argv[0]);
- return -1;
- }
-
- if (!hal_open(callbacks_get_adapter_struct())) {
- printf("Unable to open Bluetooth HAL.\n");
- return 1;
- }
-
- if (!btsocket_init()) {
- printf("Unable to initialize Bluetooth sockets.\n");
- return 2;
- }
-
- if (!pan_init()) {
- printf("Unable to initialize PAN.\n");
- return 3;
- }
-
- if (!gatt_init()) {
- printf("Unable to initialize GATT.\n");
- return 4;
- }
-
- watchdog_running = true;
- pthread_create(&watchdog_thread, NULL, watchdog_fn, NULL);
-
- static const char *DEFAULT = "\x1b[0m";
- static const char *GREEN = "\x1b[0;32m";
- static const char *RED = "\x1b[0;31m";
-
- // If the output is not a TTY device, don't colorize output.
- if (!isatty(fileno(stdout))) {
- DEFAULT = GREEN = RED = "";
- }
-
- int pass = 0;
- int fail = 0;
- int case_num = 0;
-
- // If test name is specified, run that specific test.
- // Otherwise run through the sanity suite.
- if (!skip_sanity_suite) {
- for (size_t i = 0; i < sanity_suite_size; ++i) {
- if (!test_name || !strcmp(test_name, sanity_suite[i].function_name)) {
- callbacks_init();
- if (sanity_suite[i].function()) {
- printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, sanity_suite[i].function_name, GREEN, DEFAULT);
- ++pass;
- } else {
- printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, sanity_suite[i].function_name, RED, DEFAULT);
- ++fail;
- }
- callbacks_cleanup();
- ++watchdog_id;
- }
- }
- }
-
- // If there was a failure in the sanity suite, don't bother running the rest of the tests.
- if (fail) {
- printf("\n%sSanity suite failed with %d errors.%s\n", RED, fail, DEFAULT);
- hal_close();
- return 4;
- }
-
- // If test name is specified, run that specific test.
- // Otherwise run through the full test suite.
- for (size_t i = 0; i < test_suite_size; ++i) {
- if (!test_name || !strcmp(test_name, test_suite[i].function_name)) {
- callbacks_init();
- CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
- if (test_suite[i].function()) {
- printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, test_suite[i].function_name, GREEN, DEFAULT);
- ++pass;
- } else {
- printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, test_suite[i].function_name, RED, DEFAULT);
- ++fail;
- }
- CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
- callbacks_cleanup();
- ++watchdog_id;
- }
- }
-
- printf("\n");
-
- if (fail) {
- printf("%d/%d tests failed. See above for failed test cases.\n", fail, sanity_suite_size + test_suite_size);
- } else {
- printf("All tests passed!\n");
- }
-
- watchdog_running = false;
- pthread_join(watchdog_thread, NULL);
-
- hal_close();
-
- return 0;
-}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern "C" {
+ #include "base.h"
+ #include "btcore/include/bdaddr.h"
+ #include "cases/cases.h"
+ #include "osi/include/config.h"
+ #include "support/callbacks.h"
+ #include "support/hal.h"
+ #include "support/gatt.h"
+ #include "support/pan.h"
+ #include "support/rfcomm.h"
+}
+
+static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
+
+const bt_interface_t *bt_interface;
+bt_bdaddr_t bt_remote_bdaddr;
+
+class CommsTest : public ::testing::Test {
+ protected : CommsTest() { }
+ ~CommsTest() { }
+ virtual void SetUp() {
+ callbacks_init();
+ }
+ virtual void TearDown() {
+ callbacks_cleanup();
+ }
+};
+
+void first_time_setup() {
+ config_t *config = config_new(CONFIG_FILE_PATH);
+ if (!config) {
+ printf("Error: unable to open stack config file.\n");
+ FAIL();
+ }
+ for (const config_section_node_t *node = config_section_begin(config); node != config_section_end(config); node = config_section_next(node)) {
+ const char *name = config_section_name(node);
+ if (config_has_key(config, name, "LinkKey") && string_to_bdaddr(name, &bt_remote_bdaddr)) {
+ break;
+ }
+ }
+ config_free(config);
+ if (bdaddr_is_empty(&bt_remote_bdaddr)) {
+ printf("Error: unable to find paired device in config file.\n");
+ FAIL();
+ } else if (!hal_open(callbacks_get_adapter_struct())) {
+ printf("Unable to open Bluetooth HAL.\n");
+ FAIL();
+ } else if (!btsocket_init()) {
+ printf("Unable to initialize Bluetooth sockets.\n");
+ FAIL();
+ } else if (!pan_init()) {
+ printf("Unable to initialize PAN.\n");
+ FAIL();
+ } else if (!gatt_init()) {
+ printf("Unable to initialize GATT.\n");
+ FAIL();
+ }
+}
+
+void setup() {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+}
+
+void cleanup() {
+ CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
+}
+
+TEST_F(CommsTest, initial_setup) {
+ first_time_setup();
+}
+
+TEST_F(CommsTest, adapter_enable_disable) {
+ EXPECT_TRUE(sanity_suite[0].function());
+}
+
+TEST_F(CommsTest, adapter_repeated_enable_disable) {
+ EXPECT_TRUE(sanity_suite[1].function());
+}
+
+TEST_F(CommsTest, adapter_set_name) {
+ setup();
+ EXPECT_TRUE(test_suite[0].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, adapter_get_name) {
+ setup();
+ EXPECT_TRUE(test_suite[1].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, adapter_start_discovery) {
+ setup();
+ EXPECT_TRUE(test_suite[2].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, adapter_cancel_discovery) {
+ setup();
+ EXPECT_TRUE(test_suite[3].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, rfcomm_connect) {
+ setup();
+ EXPECT_TRUE(test_suite[4].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, rfcomm_repeated_connect) {
+ setup();
+ EXPECT_TRUE(test_suite[5].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, pan_enable) {
+ setup();
+ EXPECT_TRUE(test_suite[6].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, pan_connect) {
+ setup();
+ EXPECT_TRUE(test_suite[7].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, pan_disconnect) {
+ setup();
+ EXPECT_TRUE(test_suite[8].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, gatt_client_register) {
+ setup();
+ EXPECT_TRUE(test_suite[9].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, gatt_client_scan) {
+ setup();
+ EXPECT_TRUE(test_suite[10].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, gatt_client_advertise) {
+ setup();
+ EXPECT_TRUE(test_suite[11].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, gatt_server_register) {
+ setup();
+ EXPECT_TRUE(test_suite[12].function());
+ cleanup();
+}
+
+TEST_F(CommsTest, gatt_server_build) {
+ setup();
+ EXPECT_TRUE(test_suite[13].function());
+ cleanup();
+}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
bt_property_t *adapter_get_property(bt_property_type_t type) {
- for (int i = 0; i < property_count; ++i) {
+ int i;
+ for (i = 0; i < property_count; ++i) {
if (properties[i].type == type) {
return &properties[i];
}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
};
void callbacks_init() {
- for (size_t i = 0; i < ARRAY_SIZE(callback_data); ++i) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(callback_data); ++i) {
sem_init(&callback_data[i].semaphore, 0, 0);
}
}
void callbacks_cleanup() {
- for (size_t i = 0; i < ARRAY_SIZE(callback_data); ++i) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(callback_data); ++i) {
sem_destroy(&callback_data[i].semaphore);
}
}
}
sem_t *callbacks_get_semaphore(const char *name) {
- for (size_t i = 0; i < ARRAY_SIZE(callback_data); ++i) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(callback_data); ++i) {
if (callback_data[i].name && !strcmp(name, callback_data[i].name)) {
return &callback_data[i].semaphore;
}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void btgatts_connection_cb(int conn_id, int server_if, int connected, bt_bdaddr_t *bda) {
gatt_connection_id = conn_id;
- for (int i = 0; i < 6; ++i) {
+ int i;
+ for (i = 0; i < 6; ++i) {
remote_bd_addr.address[i] = bda->address[i];
}
CALLBACK_RET();
void btgatts_response_confirmation_cb(int status, int handle) {
CALLBACK_RET();
-}
\ No newline at end of file
+}
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
// callback
-void pan_control_state_changed(btpan_control_state_t state, bt_status_t error, int local_role, const char *ifname) {
+void pan_control_state_changed(btpan_control_state_t state, int local_role, bt_status_t error, const char *ifname) {
free(pan_ifname);
pan_control_state = state;
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/******************************************************************************
*
- * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2015 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static int set_discoverable(int argc, char **argv);
static int set_name(int argc, char **argv);
static int set_pcm_loopback(int argc, char **argv);
+static int set_sco_route(int argc, char **argv);
static bool write_hci_command(hci_packet_t type, const void *packet, size_t length);
static const command_t *find_command(const char *name);
{ "setDiscoverable", "(true|false) - whether the controller should be discoverable.", set_discoverable },
{ "setName", "<name> - sets the device's Bluetooth name to <name>.", set_name },
{ "setPcmLoopback", "(true|false) - enables or disables PCM loopback on the controller.", set_pcm_loopback },
+ { "setScoRoute", "(pcm|i2s|uart) - sets the SCO packet route to one of the specified buses.", set_sco_route },
};
static int help(int argc, char **argv) {
return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
}
+static int set_sco_route(int argc, char **argv) {
+ if (argc != 1) {
+ printf("SCO route parameter must be specified.\n");
+ return 1;
+ }
+
+ uint8_t route = 0xFF;
+ if (!strcmp(argv[0], "pcm"))
+ route = 0;
+ else if (!strcmp(argv[0], "i2s"))
+ route = 3;
+ else if (!strcmp(argv[0], "uart"))
+ route = 1;
+
+ if (route == 0xFF) {
+ printf("Invalid SCO route specified: %s\n", argv[0]);
+ return 2;
+ }
+
+ uint8_t packet[] = { 0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00 };
+ packet[3] = route;
+
+ return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
int main(int argc, char **argv) {
if (argc < 2) {
usage(argv[0]);
--- /dev/null
+#!/usr/bin/env python
+"""
+This script extracts btsnooz content from bugreports and generates
+a valid btsnoop log file which can be viewed using standard tools
+like Wireshark.
+
+btsnooz is a custom format designed to be included in bugreports.
+It can be described as:
+
+base64 {
+ file_header
+ deflate {
+ repeated {
+ record_header
+ record_data
+ }
+ }
+}
+
+where the file_header and record_header are modified versions of
+the btsnoop headers.
+"""
+
+
+import base64
+import fileinput
+import struct
+import sys
+import zlib
+
+
+# Enumeration of the values the 'type' field can take in a btsnooz
+# header. These values come from the Bluetooth stack's internal
+# representation of packet types.
+TYPE_IN_EVT = 0x10
+TYPE_IN_ACL = 0x11
+TYPE_IN_SCO = 0x12
+TYPE_OUT_CMD = 0x20
+TYPE_OUT_ACL = 0x21
+TYPE_OUT_SCO = 0x22
+
+
+def type_to_direction(type):
+ """
+ Returns the inbound/outbound direction of a packet given its type.
+ 0 = sent packet
+ 1 = received packet
+ """
+ if type in [TYPE_IN_EVT, TYPE_IN_ACL, TYPE_IN_SCO]:
+ return 1
+ return 0
+
+
+def type_to_hci(type):
+ """
+ Returns the HCI type of a packet given its btsnooz type.
+ """
+ if type == TYPE_OUT_CMD:
+ return '\x01'
+ if type == TYPE_IN_ACL or type == TYPE_OUT_ACL:
+ return '\x02'
+ if type == TYPE_IN_SCO or type == TYPE_OUT_SCO:
+ return '\x03'
+ if type == TYPE_IN_EVT:
+ return '\x04'
+
+
+def decode_snooz(snooz):
+ """
+ Decodes all known versions of a btsnooz file into a btsnoop file.
+ """
+ version, last_timestamp_ms = struct.unpack_from('=bQ', snooz)
+
+ if version != 1 and version != 2:
+ sys.stderr.write('Unsupported btsnooz version: %s\n' % version)
+ exit(1)
+
+ # Oddly, the file header (9 bytes) is not compressed, but the rest is.
+ decompressed = zlib.decompress(snooz[9:])
+
+ sys.stdout.write('btsnoop\x00\x00\x00\x00\x01\x00\x00\x03\xea')
+
+ if version == 1:
+ decode_snooz_v1(decompressed, last_timestamp_ms)
+ elif version == 2:
+ decode_snooz_v2(decompressed, last_timestamp_ms)
+
+
+def decode_snooz_v1(decompressed, last_timestamp_ms):
+ """
+ Decodes btsnooz v1 files into a btsnoop file.
+ """
+ # An unfortunate consequence of the file format design: we have to do a
+ # pass of the entire file to determine the timestamp of the first packet.
+ first_timestamp_ms = last_timestamp_ms + 0x00dcddb30f2f8000
+ offset = 0
+ while offset < len(decompressed):
+ length, delta_time_ms, type = struct.unpack_from('=HIb', decompressed, offset)
+ offset += 7 + length - 1
+ first_timestamp_ms -= delta_time_ms
+
+ # Second pass does the actual writing out to stdout.
+ offset = 0
+ while offset < len(decompressed):
+ length, delta_time_ms, type = struct.unpack_from('=HIb', decompressed, offset)
+ first_timestamp_ms += delta_time_ms
+ offset += 7
+ sys.stdout.write(struct.pack('>II', length, length))
+ sys.stdout.write(struct.pack('>II', type_to_direction(type), 0))
+ sys.stdout.write(struct.pack('>II', (first_timestamp_ms >> 32), (first_timestamp_ms & 0xFFFFFFFF)))
+ sys.stdout.write(type_to_hci(type))
+ sys.stdout.write(decompressed[offset : offset + length - 1])
+ offset += length - 1
+
+
+def decode_snooz_v2(decompressed, last_timestamp_ms):
+ """
+ Decodes btsnooz v2 files into a btsnoop file.
+ """
+ # An unfortunate consequence of the file format design: we have to do a
+ # pass of the entire file to determine the timestamp of the first packet.
+ first_timestamp_ms = last_timestamp_ms + 0x00dcddb30f2f8000
+ offset = 0
+ while offset < len(decompressed):
+ length, packet_length, delta_time_ms, snooz_type = struct.unpack_from('=HHIb', decompressed, offset)
+ offset += 9 + length - 1
+ first_timestamp_ms -= delta_time_ms
+
+ # Second pass does the actual writing out to stdout.
+ offset = 0
+ while offset < len(decompressed):
+ length, packet_length, delta_time_ms, snooz_type = struct.unpack_from('=HHIb', decompressed, offset)
+ first_timestamp_ms += delta_time_ms
+ offset += 9
+ sys.stdout.write(struct.pack('>II', packet_length, length))
+ sys.stdout.write(struct.pack('>II', type_to_direction(snooz_type), 0))
+ sys.stdout.write(struct.pack('>II', (first_timestamp_ms >> 32), (first_timestamp_ms & 0xFFFFFFFF)))
+ sys.stdout.write(type_to_hci(snooz_type))
+ sys.stdout.write(decompressed[offset : offset + length - 1])
+ offset += length - 1
+
+
+def main():
+ if len(sys.argv) > 2:
+ sys.stderr.write('Usage: %s [bugreport]\n' % sys.argv[0])
+ exit(1)
+
+ iterator = fileinput.input()
+ for line in iterator:
+ if line.startswith('--- BEGIN:BTSNOOP_LOG_SUMMARY'):
+ decode_snooz(base64.standard_b64decode(iterator.next()))
+ sys.exit(0)
+ sys.stderr.write('No btsnooz section found in bugreport.\n');
+
+
+if __name__ == '__main__':
+ main()