diff options
author | Ayan Ghosh <abghosh@codeaurora.org> | 2015-10-07 18:34:50 +0530 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2015-12-01 04:19:55 -0800 |
commit | cc034991d31c3ad1cf9b9d44655dc256c6b68228 (patch) | |
tree | a800674f064d564f31b55c0d761bc6f1e991fd99 | |
parent | f80b682e088ea0c49b5b4d1371eedda63bc5d96b (diff) | |
download | android_system_bt-cc034991d31c3ad1cf9b9d44655dc256c6b68228.tar.gz android_system_bt-cc034991d31c3ad1cf9b9d44655dc256c6b68228.tar.bz2 android_system_bt-cc034991d31c3ad1cf9b9d44655dc256c6b68228.zip |
Split A2dp implementation
Implement Split A2dp to process AVDTP Signalling commands
from host and media packet handling from Controller.
Host uses vendor specific commands to let controller know
the media channel configurations for controller to form
the media packets accordingly.
Change-Id: I7a98177a8125fd70b057bb514f0d870971a45bcf
-rw-r--r-- | Android.mk | 5 | ||||
-rw-r--r-- | audio_a2dp_hw/audio_a2dp_hw.c | 58 | ||||
-rw-r--r-- | audio_a2dp_hw/audio_a2dp_hw.h | 4 | ||||
-rw-r--r-- | bta/av/bta_av_aact.c | 10 | ||||
-rw-r--r-- | bta/dm/bta_dm_act.c | 19 | ||||
-rw-r--r-- | bta/dm/bta_dm_api.c | 52 | ||||
-rw-r--r-- | bta/dm/bta_dm_int.h | 15 | ||||
-rw-r--r-- | bta/dm/bta_dm_main.c | 3 | ||||
-rw-r--r-- | bta/include/bta_api.h | 17 | ||||
-rw-r--r-- | bta/include/bta_av_api.h | 3 | ||||
-rw-r--r-- | btif/co/bta_av_co.c | 12 | ||||
-rw-r--r-- | btif/include/btif_av.h | 22 | ||||
-rw-r--r-- | btif/include/btif_media.h | 1 | ||||
-rw-r--r-- | btif/src/btif_av.c | 77 | ||||
-rw-r--r-- | btif/src/btif_media_task.c | 514 | ||||
-rw-r--r-- | stack/avdt/avdt_api.c | 16 | ||||
-rw-r--r-- | stack/include/avdt_api.h | 14 | ||||
-rw-r--r-- | stack/include/l2c_api.h | 13 | ||||
-rw-r--r-- | stack/l2cap/l2c_api.c | 24 | ||||
-rw-r--r-- | udrv/ulinux/uipc.c | 10 |
20 files changed, 877 insertions, 12 deletions
diff --git a/Android.mk b/Android.mk index 520d51f50..7b6c036df 100644 --- a/Android.mk +++ b/Android.mk @@ -28,6 +28,11 @@ ifeq ($(BOARD_USES_WIPOWER), true) bdroid_CFLAGS += -DWIPOWER_SUPPORTED endif +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPLIT_A2DP)),true) + bdroid_CFLAGS += -DBTA_AV_SPLIT_A2DP_ENABLED + bdroid_CFLAGS += -DBTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ +endif + bdroid_CFLAGS += \ -Wall \ -Wno-unused-parameter \ diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c index 5b93992a8..3e2bc2dde 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.c +++ b/audio_a2dp_hw/audio_a2dp_hw.c @@ -543,6 +543,7 @@ static int start_audio_datapath(struct a2dp_stream_common *common) return -1; } +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* connect socket if not yet connected */ if (common->audio_fd == AUDIO_SKT_DISCONNECTED) { @@ -555,6 +556,9 @@ static int start_audio_datapath(struct a2dp_stream_common *common) common->state = AUDIO_A2DP_STATE_STARTED; } +#else + common->state = AUDIO_A2DP_STATE_STARTED; +#endif return 0; } @@ -581,9 +585,11 @@ static int stop_audio_datapath(struct a2dp_stream_common *common) common->state = AUDIO_A2DP_STATE_STOPPED; +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* disconnect audio path */ skt_disconnect(common->audio_fd); common->audio_fd = AUDIO_SKT_DISCONNECTED; +#endif return 0; } @@ -606,10 +612,12 @@ static int suspend_audio_datapath(struct a2dp_stream_common *common, bool standb else common->state = AUDIO_A2DP_STATE_SUSPENDED; +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* disconnect audio path */ skt_disconnect(common->audio_fd); common->audio_fd = AUDIO_SKT_DISCONNECTED; +#endif return 0; } @@ -715,6 +723,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, } DEBUG("wrote %d bytes out of %zu bytes", sent, bytes); + return sent; } @@ -815,13 +824,60 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int retval; int status = 0; - INFO("state %d", out->common.state); + INFO("out_set_parameters: state %d", out->common.state); parms = str_parms_create_str(kvpairs); /* dump params */ str_parms_dump(parms); +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + retval = str_parms_get_str(parms, "A2dpStarted", keyval, sizeof(keyval)); + if (retval >= 0) + { + INFO("out_set_parameters, param: A2dpStarted"); + if (strcmp(keyval, "true") == 0) + { + INFO("out_set_parameters, value: true"); + pthread_mutex_lock(&out->common.lock); + if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) + { + INFO("stream suspended"); + status = -1; + } + else if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) || + (out->common.state == AUDIO_A2DP_STATE_STANDBY)) + { + if (start_audio_datapath(&out->common) < 0) + { + INFO("stream start failed"); + status = -1; + } + } + else if (out->common.state != AUDIO_A2DP_STATE_STARTED) + { + ERROR("stream not in stopped or standby"); + status = -1; + } + pthread_mutex_unlock(&out->common.lock); + INFO("stream start completes with status: %d", status); + } + else if (strcmp(keyval, "false") == 0) + { + INFO("out_set_parameters, value: false"); + pthread_mutex_lock(&out->common.lock); + if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED) + status = suspend_audio_datapath(&out->common, true); + else + { + ERROR("stream alreday suspended"); + } + pthread_mutex_unlock(&out->common.lock); + INFO("stream stop completes with status: %d", status); + } + } +#endif + retval = str_parms_get_str(parms, "closing", keyval, sizeof(keyval)); if (retval >= 0) diff --git a/audio_a2dp_hw/audio_a2dp_hw.h b/audio_a2dp_hw/audio_a2dp_hw.h index e49cbdb32..a97b4c855 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.h +++ b/audio_a2dp_hw/audio_a2dp_hw.h @@ -35,7 +35,11 @@ #define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl" #define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data" +#ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ #define AUDIO_STREAM_DEFAULT_RATE 44100 +#else +#define AUDIO_STREAM_DEFAULT_RATE 48000 +#endif #define AUDIO_STREAM_DEFAULT_FORMAT AUDIO_FORMAT_PCM_16_BIT #define AUDIO_STREAM_DEFAULT_CHANNEL_FLAG AUDIO_CHANNEL_OUT_STEREO #define AUDIO_STREAM_OUTPUT_BUFFER_SZ (20*512) diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c index 41c3fe293..94ca7d981 100644 --- a/bta/av/bta_av_aact.c +++ b/bta/av/bta_av_aact.c @@ -64,7 +64,11 @@ static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); static const size_t SBC_MAX_BITPOOL_OFFSET = 6; +#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ +static const size_t SBC_MAX_BITPOOL = 51; +#else static const size_t SBC_MAX_BITPOOL = 53; +#endif /* state machine states */ enum @@ -1489,6 +1493,9 @@ void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) open.status = BTA_AV_SUCCESS; open.starting = bta_av_chk_start(p_scb); open.edr = 0; +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + open.stream_chnl_id = AVDT_GetStreamingDestChannelId(p_scb->l2c_cid); +#endif // update Master/Slave Role for start if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) { @@ -1912,6 +1919,9 @@ void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) open.status = BTA_AV_FAIL_GET_CAP; open.starting = bta_av_chk_start(p_scb); open.edr = 0; +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + open.stream_chnl_id = 0; +#endif // update Master/Slave Role for open event if (BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) { diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c index 0ef7ff279..d81fb32dc 100644 --- a/bta/dm/bta_dm_act.c +++ b/bta/dm/bta_dm_act.c @@ -630,6 +630,25 @@ void bta_dm_hci_raw_command (tBTA_DM_MSG *p_data) /******************************************************************************* ** +** Function bta_dm_vendor_spec_command +** +** Description Send a vendor specific command to the controller +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_vendor_spec_command (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_API("bta_dm_vendor_spec_command"); + BTM_VendorSpecificCommand(p_data->vendor_command.opcode, + p_data->vendor_command.param_len, + p_data->vendor_command.p_param_buf, + p_data->vendor_command.p_cback); +} + +/******************************************************************************* +** ** Function bta_dm_process_remove_deviced ** ** diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c index 21d8b07b7..674cd21ef 100644 --- a/bta/dm/bta_dm_api.c +++ b/bta/dm/bta_dm_api.c @@ -261,6 +261,58 @@ tBTA_STATUS BTA_DmHciRawCommand (UINT16 opcode, UINT8 param_len, /******************************************************************************* ** +** Function BTA_DmVendorSpecificCommand +** +** Description This function sends the vendor specific command +** to the controller +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, UINT8 param_len, + UINT8 *p_param_buf, + tBTA_VENDOR_CMPL_CBACK *p_cback) +{ + + tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *p_msg; + UINT16 size; + + /* If p_cback is NULL, Notify application */ + if (p_cback == NULL) + { + return (BTA_FAILURE); + } + else + { + size = sizeof (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND) + param_len; + if ((p_msg = (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *) GKI_getbuf(size)) != NULL) + { + p_msg->hdr.event = BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT; + p_msg->opcode = opcode; + p_msg->p_param_buf = (UINT8 *)(p_msg + 1); + p_msg->p_cback = p_cback; + + if (p_param_buf && param_len) + { + memcpy (p_msg->p_param_buf, p_param_buf, param_len); + p_msg->param_len = param_len; + } + else + { + p_msg->param_len = 0; + p_msg->p_param_buf = NULL; + + } + + bta_sys_sendmsg(p_msg); + } + return (BTA_SUCCESS); + } +} + +/******************************************************************************* +** ** Function BTA_DmSearch ** ** Description This function searches for peer Bluetooth devices. It performs diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h index 42efe1b32..57733ead1 100644 --- a/bta/dm/bta_dm_int.h +++ b/bta/dm/bta_dm_int.h @@ -125,6 +125,7 @@ enum BTA_DM_API_REMOVE_ALL_ACL_EVT, BTA_DM_API_REMOVE_DEVICE_EVT, BTA_DM_API_HCI_RAW_COMMAND_EVT, + BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT, BTA_DM_MAX_EVT }; @@ -180,6 +181,16 @@ typedef struct tBTA_RAW_CMPL_CBACK *p_cback; } tBTA_DM_API_RAW_COMMAND; +/* data type for BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 opcode; + UINT8 param_len; + UINT8 *p_param_buf; + tBTA_VENDOR_CMPL_CBACK *p_cback; +} tBTA_DM_API_VENDOR_SPECIFIC_COMMAND; + enum { BTA_DM_RS_NONE, /* straight API call */ @@ -753,8 +764,8 @@ typedef union tBTA_DM_API_REMOVE_ACL remove_acl; tBTA_DM_API_REMOVE_ALL_ACL remove_all_acl; - tBTA_DM_API_RAW_COMMAND btc_command; - + tBTA_DM_API_RAW_COMMAND btc_command; + tBTA_DM_API_VENDOR_SPECIFIC_COMMAND vendor_command; } tBTA_DM_MSG; #ifndef MAX_ACL_CONNECTIONS diff --git a/bta/dm/bta_dm_main.c b/bta/dm/bta_dm_main.c index 4645760e3..93cd90fe8 100644 --- a/bta/dm/bta_dm_main.c +++ b/bta/dm/bta_dm_main.c @@ -120,7 +120,8 @@ const tBTA_DM_ACTION bta_dm_action[] = bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */ bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */ - bta_dm_hci_raw_command /* BTA_DM_API_HCI_RAW_COMMAND_EVT */ + bta_dm_hci_raw_command, /* BTA_DM_API_HCI_RAW_COMMAND_EVT */ + bta_dm_vendor_spec_command,/* BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */ }; diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h index 64b4a3664..b6446eecc 100644 --- a/bta/include/bta_api.h +++ b/bta/include/bta_api.h @@ -1027,6 +1027,9 @@ typedef struct /* HCI RAW Command Callback */ typedef tBTM_RAW_CMPL_CB tBTA_RAW_CMPL_CBACK; +/* Vendor Specific Command Callback */ +typedef tBTM_VSC_CMPL_CB tBTA_VENDOR_CMPL_CBACK; + /* Search callback events */ #define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */ #define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */ @@ -1470,6 +1473,20 @@ extern void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, *******************************************************************************/ extern tBTA_STATUS BTA_DmHciRawCommand (UINT16 opcode, UINT8 param_len,UINT8 *p_param_buf, tBTA_RAW_CMPL_CBACK *p_cback); +/******************************************************************************* +** +** Function BTA_DmVendorSpecificCommand +** +** Description This function sends the vendor specific command +** to the controller +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +extern tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, + UINT8 param_len,UINT8 *p_param_buf, tBTA_VENDOR_CMPL_CBACK *p_cback); + /******************************************************************************* ** diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h index 8fc43dbcd..94818b6ad 100644 --- a/bta/include/bta_av_api.h +++ b/bta/include/bta_av_api.h @@ -290,6 +290,9 @@ typedef struct tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */ UINT8 sep; /* sep type of peer device */ UINT8 role; /* 0x00 master, 0x01 slave , 0xFF unkown*/ +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + UINT16 stream_chnl_id; +#endif } tBTA_AV_OPEN; /* data associated with BTA_AV_CLOSE_EVT */ diff --git a/btif/co/bta_av_co.c b/btif/co/bta_av_co.c index 8a9004c61..7d73db0c7 100644 --- a/btif/co/bta_av_co.c +++ b/btif/co/bta_av_co.c @@ -62,7 +62,11 @@ #define BTA_AV_CO_SBC_MIN_BITPOOL_OFF 5 #define BTA_AV_CO_SBC_MAX_BITPOOL_OFF 6 +#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ +#define BTA_AV_CO_SBC_MAX_BITPOOL 51 +#else #define BTA_AV_CO_SBC_MAX_BITPOOL 53 +#endif /* SCMS-T protect info */ const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00"; @@ -70,7 +74,11 @@ const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00"; /* SBC SRC codec capabilities */ const tA2D_SBC_CIE bta_av_co_sbc_caps = { +#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ + (A2D_SBC_IE_SAMP_FREQ_48), /* samp_freq */ +#else (A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ +#endif (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ @@ -92,8 +100,12 @@ const tA2D_SBC_CIE bta_av_co_sbc_sink_caps = }; #if !defined(BTIF_AV_SBC_DEFAULT_SAMP_FREQ) +#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ +#define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_48 +#else #define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44 #endif +#endif /* Default SBC codec configuration */ const tA2D_SBC_CIE btif_av_sbc_default_config = diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h index 37caf6610..5d7ac0107 100644 --- a/btif/include/btif_av.h +++ b/btif/include/btif_av.h @@ -207,5 +207,27 @@ BOOLEAN btif_av_any_br_peer(void); *******************************************************************************/ BOOLEAN btif_av_peer_supports_3mbps(void); +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/****************************************************************************** +** +** Function btif_av_get_streaming_channel_id +** +** Description Returns streaming channel id +** +** Returns channel id +********************************************************************************/ +UINT16 btif_av_get_streaming_channel_id(void); + +/****************************************************************************** +** +** Function btif_av_get_peer_addr +** +** Description Returns peer device address +** +** Returns peer address +********************************************************************************/ +void btif_av_get_peer_addr(bt_bdaddr_t *peer_bda); + +#endif #endif /* BTIF_AV_H */ diff --git a/btif/include/btif_media.h b/btif/include/btif_media.h index 023e03cde..a9323f066 100644 --- a/btif/include/btif_media.h +++ b/btif/include/btif_media.h @@ -280,6 +280,7 @@ tBTIF_STATUS btif_a2dp_setup_codec(void); void btif_a2dp_on_idle(void); void btif_a2dp_on_open(void); BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start); +void btif_media_on_stop_vendor_command(); void btif_a2dp_ack_fail(void); void btif_a2dp_on_stop_req(void); void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av); diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c index ef9ee51a2..9c1cad76a 100644 --- a/btif/src/btif_av.c +++ b/btif/src/btif_av.c @@ -101,6 +101,9 @@ typedef struct int service; BOOLEAN is_slave; BOOLEAN is_device_playing; +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + UINT16 channel_id; +#endif } btif_av_cb_t; typedef struct @@ -382,6 +385,9 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data, i { btif_av_cb[i].dual_handoff = FALSE; } +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + btif_av_cb[index].channel_id = 0; +#endif /* This API will be called twice at initialization ** Idle can be moved when device is disconnected too. ** Take care of other connected device here.*/ @@ -535,6 +541,11 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data, i } bdcpy(btif_av_cb[index].peer_bda.address, ((tBTA_AV*)p_data)->open.bd_addr); +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + btif_av_cb[index].channel_id = p_bta_data->open.stream_chnl_id; + BTIF_TRACE_DEBUG("streaming channel id updated as : 0x%x", + btif_av_cb[index].channel_id); +#endif } else { @@ -663,6 +674,11 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data BTIF_TRACE_DEBUG("remote supports 3 mbps"); btif_av_cb[index].edr_3mbps = TRUE; } +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + btif_av_cb[index].channel_id = p_bta_data->open.stream_chnl_id; + BTIF_TRACE_DEBUG("streaming channel id updated as : 0x%x", + btif_av_cb[index].channel_id); +#endif } else { @@ -1086,7 +1102,7 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data, else { BTIF_TRACE_DEBUG("%s: trigger suspend as remote initiated!!", - __FUNCTION__); + __FUNCTION__); btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0); } } @@ -1616,6 +1632,9 @@ static void btif_av_handle_event(UINT16 event, char* p_param) case BTIF_AV_STOP_STREAM_REQ_EVT: case BTIF_AV_SUSPEND_STREAM_REQ_EVT: /*Should be handled by current STARTED*/ +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + btif_media_on_stop_vendor_command(); +#endif index = btif_get_latest_playing_device_idx(); break; /*Events from the stack, BTA*/ @@ -3178,3 +3197,59 @@ BOOLEAN btif_av_get_ongoing_multicast() return FALSE; } } + +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/****************************************************************************** +** +** Function btif_av_get_streaming_channel_id +** +** Description Returns streaming channel id +** +** Returns channel id +********************************************************************************/ +UINT16 btif_av_get_streaming_channel_id(void) +{ + btif_sm_state_t state = BTIF_AV_STATE_IDLE; + int i; + for (i = 0; i < btif_max_av_clients; i++) + { + state = btif_sm_get_state(btif_av_cb[i].sm_handle); + if ((state == BTIF_AV_STATE_OPENED) || + (state == BTIF_AV_STATE_STARTED)) + { + BTIF_TRACE_DEBUG("btif_av_get_streaming_channel_id: %u", + btif_av_cb[i].channel_id); + return btif_av_cb[i].channel_id; + } + } + return 0; +} + +/****************************************************************************** +** +** Function btif_av_get_peer_addr +** +** Description Returns peer device address +** +** Returns peer address +********************************************************************************/ +void btif_av_get_peer_addr(bt_bdaddr_t *peer_bda) +{ + btif_sm_state_t state = BTIF_AV_STATE_IDLE; + int i; + memset(peer_bda, 0, sizeof(bt_bdaddr_t)); + for (i = 0; i < btif_max_av_clients; i++) + { + state = btif_sm_get_state(btif_av_cb[i].sm_handle); + if ((state == BTIF_AV_STATE_OPENED) || + (state == BTIF_AV_STATE_STARTED)) + { + BTIF_TRACE_DEBUG("btif_av_get_peer_addr: %u", + btif_av_cb[i].peer_bda); + memcpy(peer_bda, &btif_av_cb[i].peer_bda, + sizeof(bt_bdaddr_t)); + } + } +} +#endif + diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c index d68811982..55fef3a1f 100644 --- a/btif/src/btif_media_task.c +++ b/btif/src/btif_media_task.c @@ -97,6 +97,11 @@ OI_INT16 pcmData[15*SBC_MAX_SAMPLES_PER_FRAME*SBC_MAX_CHANNELS]; #define PERF_SYSTRACE 1 #endif +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +#include "bta_api.h" +#endif + + /***************************************************************************** ** Constants *****************************************************************************/ @@ -129,6 +134,18 @@ enum #ifdef USE_AUDIO_TRACK ,BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE #endif +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + ,BTIF_MEDIA_START_VS_CMD, + BTIF_MEDIA_STOP_VS_CMD, + BTIF_MEDIA_RESET_VS_STATE, + BTIF_MEDIA_VS_A2DP_START_SUCCESS, + BTIF_MEDIA_VS_A2DP_STOP_SUCCESS, + BTIF_MEDIA_VS_A2DP_MEDIA_CHNL_CFG_SUCCESS, + BTIF_MEDIA_VS_A2DP_WRITE_SBC_CFG_SUCCESS, + BTIF_MEDIA_VS_A2DP_PREF_BIT_RATE_SUCCESS, + BTIF_MEDIA_VS_A2DP_SET_SCMST_HDR_SUCCESS, + BTIF_MEDIA_VS_A2DP_STOP_FAILURE +#endif }; enum { @@ -166,12 +183,19 @@ enum { #define BTIF_MEDIA_BITRATE_STEP 5 #endif -/* Middle quality quality setting @ 44.1 khz */ +#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ +#define DEFAULT_SBC_BITRATE 345 + +#ifndef BTIF_A2DP_NON_EDR_MAX_RATE +#define BTIF_A2DP_NON_EDR_MAX_RATE 237 +#endif +#else #define DEFAULT_SBC_BITRATE 328 #ifndef BTIF_A2DP_NON_EDR_MAX_RATE #define BTIF_A2DP_NON_EDR_MAX_RATE 229 #endif +#endif #if (BTA_AV_CO_CP_SCMS_T == TRUE) /* A2DP header will contain a CP header of size 1 */ @@ -273,6 +297,14 @@ typedef struct alarm_t *media_alarm; alarm_t *decode_alarm; UINT8 TxNumSBCFrames; +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + UINT8 max_bitpool; + UINT8 min_bitpool; + BOOLEAN vs_configs_exchanged; + BOOLEAN tx_started; + BOOLEAN tx_stop_initiated; +#endif + #endif } tBTIF_MEDIA_CB; @@ -340,6 +372,19 @@ static void btif_media_task_aa_handle_timer(UNUSED_ATTR void *context); static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context); extern BOOLEAN btif_hf_is_call_idle(); +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +void btif_media_send_reset_vendor_state(); +void btif_media_on_start_vendor_command(); +void btif_media_start_vendor_command(); +void btif_media_on_stop_vendor_command(); +BOOLEAN btif_media_send_vendor_pref_bit_rate(); +BOOLEAN btif_media_send_vendor_write_sbc_cfg(); +BOOLEAN btif_media_send_vendor_media_chn_cfg(); +BOOLEAN btif_media_send_vendor_stop(); +BOOLEAN btif_media_send_vendor_start(); +#endif + + static tBTIF_MEDIA_CB btif_media_cb; static int media_task_running = MEDIA_TASK_STATE_OFF; @@ -524,17 +569,27 @@ static void btif_recv_ctrl_data(void) * and ACK the audio HAL.*/ if (btif_av_stream_started_ready()) { +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* already started, setup audio data channel listener * and ack back immediately */ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb); - +#else + APPL_TRACE_DEBUG("Av stream alreday started"); + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) + btif_a2dp_encoder_update(); +#endif a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); } else if (btif_av_stream_ready() == TRUE) { /* setup audio data channel listener */ +#ifndef BTA_AV_SPLIT_A2DP_ENABLED + /* already started, setup audio data channel listener + * and ack back immediately */ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb); - +#else + APPL_TRACE_DEBUG("Av stream ready"); +#endif /* post start event and wait for audio path to open */ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0); @@ -551,14 +606,20 @@ static void btif_recv_ctrl_data(void) break; case A2DP_CTRL_CMD_STOP: +#ifndef BTA_AV_SPLIT_A2DP_ENABLED if (btif_media_cb.peer_sep == AVDT_TSEP_SNK && btif_media_cb.is_tx_timer == FALSE) +#else + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK && btif_media_cb.tx_started == FALSE) +#endif { /* we are already stopped, just ack back */ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); break; } + APPL_TRACE_DEBUG("Stop stream request to Av"); btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); break; @@ -566,6 +627,7 @@ static void btif_recv_ctrl_data(void) /* local suspend */ if (btif_av_stream_started_ready()) { + APPL_TRACE_DEBUG("Suspend stream request to Av"); btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0); } else @@ -768,6 +830,13 @@ static void btif_a2dp_encoder_update(void) msg.MinMtuSize = minmtu; +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + btif_media_cb.max_bitpool = msg.MaxBitPool; + btif_media_cb.min_bitpool = msg.MinBitPool; + APPL_TRACE_DEBUG("Updated min_bitpool: 0x%x max_bitpool: 0x%x", + btif_media_cb.min_bitpool, btif_media_cb.max_bitpool); +#endif + /* Update the media task to encode SBC properly */ btif_media_task_enc_update_req(&msg); } @@ -858,8 +927,14 @@ tBTIF_STATUS btif_a2dp_setup_codec(void) GKI_disable(); + +#ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ + /* for now hardcode 48 khz 16 bit stereo PCM format */ + media_feeding.cfg.pcm.sampling_freq = 48000; +#else /* for now hardcode 44.1 khz 16 bit stereo PCM format */ media_feeding.cfg.pcm.sampling_freq = 44100; +#endif media_feeding.cfg.pcm.bit_per_sample = 16; media_feeding.cfg.pcm.num_channel = 2; media_feeding.format = BTIF_AV_CODEC_PCM; @@ -904,6 +979,9 @@ void btif_a2dp_on_idle(void) /* Make sure media task is stopped */ btif_media_task_stop_aa_req(); } +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + btif_media_send_reset_vendor_state(); +#endif bta_av_co_init(); #if (BTA_AV_SINK_INCLUDED == TRUE) @@ -935,8 +1013,10 @@ void btif_a2dp_on_open(void) { APPL_TRACE_EVENT("## ON A2DP OPEN ##"); +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* always use callback to notify socket events */ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb); +#endif } /******************************************************************************* @@ -1011,8 +1091,15 @@ BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start) if (p_av == NULL) { +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) + { + btif_media_on_start_vendor_command(); + } +#else /* ack back a local start request */ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); +#endif return TRUE; } @@ -1023,7 +1110,14 @@ BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start) if (p_av->initiator) { if (pending_start) { +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) + { + btif_media_on_start_vendor_command(); + } +#else a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); +#endif ack = TRUE; } } @@ -1031,7 +1125,15 @@ BOOLEAN btif_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start) { /* we were remotely started, make sure codec is setup before datapath is started */ +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + if (btif_media_cb.peer_sep == AVDT_TSEP_SNK) + { + APPL_TRACE_IMP("start VS command exchange on remote start"); + btif_media_on_start_vendor_command(); + } +#else btif_a2dp_setup_codec(); +#endif } /* media task is autostarted upon a2dp audiopath connection */ @@ -1103,7 +1205,9 @@ void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av) btif_media_cb.tx_flush = 1; /* request to stop media task */ +#ifndef BTA_AV_SPLIT_A2DP_ENABLED btif_media_task_aa_tx_flush_req(); +#endif btif_media_task_stop_aa_req(); /* once stream is fully stopped we will ack back */ @@ -1403,6 +1507,55 @@ static void btif_media_thread_handle_cmd(fixed_queue_t *queue, UNUSED_ATTR void case BTIF_MEDIA_FLUSH_AA_RX: btif_media_task_aa_rx_flush(); break; +#ifdef BTA_AV_SPLIT_A2DP_ENABLED + case BTIF_MEDIA_RESET_VS_STATE: + btif_media_cb.tx_started = FALSE; + btif_media_cb.tx_stop_initiated = FALSE; + btif_media_cb.vs_configs_exchanged = FALSE; + break; + case BTIF_MEDIA_START_VS_CMD: + btif_a2dp_encoder_update(); + btif_media_start_vendor_command(); + break; + case BTIF_MEDIA_STOP_VS_CMD: + btif_media_send_vendor_stop(); + break; + case BTIF_MEDIA_VS_A2DP_START_SUCCESS: + btif_media_cb.tx_started = TRUE; + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); + break; + case BTIF_MEDIA_VS_A2DP_STOP_SUCCESS: + btif_media_cb.tx_started = FALSE; + btif_media_cb.tx_stop_initiated = FALSE; + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); + break; + case BTIF_MEDIA_VS_A2DP_STOP_FAILURE: + btif_media_cb.tx_stop_initiated = FALSE; + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + break; + case BTIF_MEDIA_VS_A2DP_MEDIA_CHNL_CFG_SUCCESS: + btif_media_send_vendor_pref_bit_rate(); + break; + case BTIF_MEDIA_VS_A2DP_WRITE_SBC_CFG_SUCCESS: + btif_media_send_vendor_media_chn_cfg(); + break; + case BTIF_MEDIA_VS_A2DP_PREF_BIT_RATE_SUCCESS: +#if (BTA_AV_CO_CP_SCMS_T == TRUE) + btif_media_send_vendor_scmst_hdr(); +#else + if (!btif_media_cb.vs_configs_exchanged) + btif_media_cb.vs_configs_exchanged = TRUE; + btif_media_send_vendor_start(); +#endif + break; +#if (BTA_AV_CO_CP_SCMS_T == TRUE) + case BTIF_MEDIA_VS_A2DP_SET_SCMST_HDR_SUCCESS: + if (!btif_media_cb.vs_configs_exchanged) + btif_media_cb.vs_configs_exchanged = TRUE; + btif_media_send_vendor_start(); + break; +#endif +#endif #endif default: APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event); @@ -1749,8 +1902,10 @@ static void btif_media_task_enc_init(BT_HDR *p_msg) btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate, btif_media_cb.encoder.s16SamplingFreq); +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* Reset entirely the SBC encoder */ SBC_Encoder_Init(&(btif_media_cb.encoder)); +#endif btif_media_cb.TxNumSBCFrames = check_for_max_number_of_frames_per_packet(); APPL_TRACE_DEBUG("btif_media_task_enc_init bit pool %d", btif_media_cb.encoder.s16BitPool); } @@ -1915,8 +2070,10 @@ static void btif_media_task_enc_update(BT_HDR *p_msg) APPL_TRACE_DEBUG("btif_media_task_enc_update final bit rate %d, final bit pool %d", btif_media_cb.encoder.u16BitRate, btif_media_cb.encoder.s16BitPool); +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* make sure we reinitialize encoder with new settings */ SBC_Encoder_Init(&(btif_media_cb.encoder)); +#endif btif_media_cb.TxNumSBCFrames = check_for_max_number_of_frames_per_packet(); } } @@ -1991,8 +2148,9 @@ static void btif_media_task_pcm2sbc_init(tBTIF_MEDIA_INIT_AUDIO_FEEDING * p_feed btif_media_cb.encoder.s16NumOfSubBands, btif_media_cb.encoder.s16NumOfBlocks, btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate, btif_media_cb.encoder.s16SamplingFreq); - +#ifndef BTA_AV_SPLIT_A2DP_ENABLED SBC_Encoder_Init(&(btif_media_cb.encoder)); +#endif } else { @@ -2331,6 +2489,8 @@ static void btif_media_task_aa_start_tx(void) /* Reset the media feeding state */ btif_media_task_feeding_state_reset(); +#ifndef BTA_AV_SPLIT_A2DP_ENABLED + APPL_TRACE_EVENT("starting timer %dms", BTIF_MEDIA_TIME_TICK); assert(btif_media_cb.media_alarm == NULL); @@ -2342,6 +2502,7 @@ static void btif_media_task_aa_start_tx(void) } alarm_set_periodic(btif_media_cb.media_alarm, BTIF_MEDIA_TIME_TICK, btif_media_task_alarm_cb, NULL); +#endif } /******************************************************************************* @@ -2355,9 +2516,9 @@ static void btif_media_task_aa_start_tx(void) *******************************************************************************/ static void btif_media_task_aa_stop_tx(void) { - APPL_TRACE_DEBUG("%s is_tx_timer: %d", __func__, btif_media_cb.is_tx_timer); - +#ifndef BTA_AV_SPLIT_A2DP_ENABLED const bool send_ack = (btif_media_cb.is_tx_timer != FALSE); + APPL_TRACE_DEBUG("%s is_tx_timer: %d", __func__, btif_media_cb.is_tx_timer); /* Stop the timer first */ alarm_free(btif_media_cb.media_alarm); @@ -2386,6 +2547,14 @@ static void btif_media_task_aa_stop_tx(void) /* Reset the media feeding state */ btif_media_task_feeding_state_reset(); +#else + APPL_TRACE_IMP("%s tx_started: %d, tx_stop_initiated: %d", + __func__, btif_media_cb.tx_started, btif_media_cb.tx_stop_initiated); + if (btif_media_cb.tx_started && !btif_media_cb.tx_stop_initiated) + btif_media_send_vendor_stop(); + else + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS); +#endif } static UINT32 get_frame_length() @@ -3074,6 +3243,339 @@ static void btif_media_send_aa_frame(void) bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO); } +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/******************************************************************************* + ** + ** Function bta_av_co_send_vendor_start + ** + ** Description Send Vendor Specific A2dp START command to controller + ** + ** Returns TRUE if command succeeds, FALSE otherwize + ** + *******************************************************************************/ + +#define HCI_VSQC_CONTROLLER_A2DP_OPCODE 0x000A + +#define VS_QHCI_READ_A2DP_CFG 0x01 +#define VS_QHCI_WRITE_SBC_CFG 0x02 +#define VS_QHCI_WRITE_A2DP_MEDIA_CHANNEL_CFG 0x03 +#define VS_QHCI_START_A2DP_MEDIA 0x04 +#define VS_QHCI_STOP_A2DP_MEDIA 0x05 +#define VS_QHCI_A2DP_WRITE_SUGGESTED_BITRATE 0x06 +#define VS_QHCI_A2DP_TRANSPORT_CONFIGURATION 0x07 +#define VS_QHCI_A2DP_WRITE_SCMS_T_CP 0x08 + +void btif_media_send_reset_vendor_state() +{ + BT_HDR *p_buf; + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + APPL_TRACE_EVENT("GKI alloc failed"); + return; + } + p_buf->event = BTIF_MEDIA_RESET_VS_STATE; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); +} + +void btif_media_start_vendor_command() +{ + APPL_TRACE_IMP("btif_media_start_vendor_command_exchange:\ + vs_configs_exchanged:%u", btif_media_cb.vs_configs_exchanged); + if(btif_media_cb.vs_configs_exchanged) + { + btif_media_send_vendor_start(); + } + else + { + btif_media_send_vendor_write_sbc_cfg(); + } +} + +void btif_media_on_start_vendor_command() +{ + BT_HDR *p_buf; + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + APPL_TRACE_EVENT("GKI alloc failed: ACK failure"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + return; + } + p_buf->event = BTIF_MEDIA_START_VS_CMD; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); +} + +void btif_media_on_stop_vendor_command() +{ + BT_HDR *p_buf; + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + APPL_TRACE_EVENT("GKI alloc failed: ACK failure"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + return; + } + APPL_TRACE_IMP("btif_media_on_stop_vendor_command"); + p_buf->event = BTIF_MEDIA_STOP_VS_CMD; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); +} + +void btif_media_a2dp_start_cb(tBTM_VSC_CMPL *param) +{ + unsigned char status = 0; + BT_HDR *p_buf; + + if (param->param_len) + { + status = param->p_param_buf[0]; + } + APPL_TRACE_IMP("VS_QHCI_START_A2DP_MEDIA sent with error code: %u", status); + + if ((!status) && (NULL != (p_buf = GKI_getbuf(sizeof(BT_HDR))))) + { + p_buf->event = BTIF_MEDIA_VS_A2DP_START_SUCCESS; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); + } + else + { + APPL_TRACE_ERROR("Error in processing Vendor command response"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + } +} + +BOOLEAN btif_media_send_vendor_start() +{ + UINT8 param[2]; + + APPL_TRACE_IMP("btif_media_send_vendor_start"); + + param[0] = VS_QHCI_START_A2DP_MEDIA; + param[1] = 0; /*needs to send index for multi A2dp*/ + + return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 2, + param, btif_media_a2dp_start_cb); +} + +void btif_media_a2dp_stop_cb(tBTM_VSC_CMPL *param) +{ + unsigned char status = 0; + BT_HDR *p_buf; + + if (param->param_len) + { + status = param->p_param_buf[0]; + } + APPL_TRACE_IMP("VS_QHCI_STOP_A2DP_MEDIA sent with error code: %u", status); + + if ((!status) && (NULL != (p_buf = GKI_getbuf(sizeof(BT_HDR))))) + p_buf->event = BTIF_MEDIA_VS_A2DP_STOP_SUCCESS; + else + p_buf->event = BTIF_MEDIA_VS_A2DP_STOP_FAILURE; + + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); +} + +BOOLEAN btif_media_send_vendor_stop() +{ + UINT8 param[2]; + + APPL_TRACE_IMP("btif_media_send_vendor_stop"); + + btif_media_cb.tx_stop_initiated = TRUE; + + param[0] = VS_QHCI_STOP_A2DP_MEDIA; + param[1] = 0; /*needs to send index for multi A2dp*/ + + return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 2, + param, btif_media_a2dp_stop_cb); +} + +void btif_media_a2dp_media_chn_cfg_cb(tBTM_VSC_CMPL *param) +{ + unsigned char status = 0; + BT_HDR *p_buf; + + if (param->param_len) + { + status = param->p_param_buf[0]; + } + APPL_TRACE_IMP("VS_QHCI_WRITE_A2DP_MEDIA_CHANNEL_CFG sent with error code: %u", + status); + + if ((!status) && (NULL != (p_buf = GKI_getbuf(sizeof(BT_HDR))))) + { + p_buf->event = BTIF_MEDIA_VS_A2DP_MEDIA_CHNL_CFG_SUCCESS; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); + } + else + { + APPL_TRACE_ERROR("Error in processing Vendor command response"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + } +} + +BOOLEAN btif_media_send_vendor_media_chn_cfg() +{ + UINT8 param[8]; + bt_bdaddr_t bd_addr; + BD_ADDR addr; + btif_av_get_peer_addr(&bd_addr); + memcpy(addr, bd_addr.address, sizeof(BD_ADDR)); + UINT16 acl_hdl = BTM_GetHCIConnHandle(addr, BT_TRANSPORT_BR_EDR); + APPL_TRACE_IMP("btif_media_send_vendor_media_chn_cfg"); + APPL_TRACE_IMP("AVDTP mtu: %u, hdl: %u", btif_media_cb.TxAaMtuSize, acl_hdl); + + param[0] = VS_QHCI_WRITE_A2DP_MEDIA_CHANNEL_CFG; + param[1] = 0; /*needs to send index for multi A2dp*/ + param[2] = (UINT8)(acl_hdl & 0x00ff); + param[3] = (UINT8)(((acl_hdl & 0xff00) >> 8) & 0x00ff); + param[4] = (UINT8)(btif_av_get_streaming_channel_id()& 0x00ff); + param[5] = (UINT8)(((btif_av_get_streaming_channel_id() & 0xff00) + >> 8) & 0x00ff); + param[6] = (UINT8)(btif_media_cb.TxAaMtuSize & 0x00ff); + param[7] = (UINT8)(((btif_media_cb.TxAaMtuSize & 0xff00) >> 8) & 0x00ff); + return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 8, + param, btif_media_a2dp_media_chn_cfg_cb); +} + +void btif_media_a2dp_write_sbc_cfg_cb(tBTM_VSC_CMPL *param) +{ + unsigned char status = 0; + BT_HDR *p_buf; + + if (param->param_len) + { + status = param->p_param_buf[0]; + } + APPL_TRACE_IMP("VS_QHCI_WRITE_SBC_CFG sent with error code: %u", status); + + if ((!status) && (NULL != (p_buf = GKI_getbuf(sizeof(BT_HDR))))) + { + p_buf->event = BTIF_MEDIA_VS_A2DP_WRITE_SBC_CFG_SUCCESS; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); + } + else + { + APPL_TRACE_ERROR("Error in processing Vendor command response"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + } +} + +BOOLEAN btif_media_send_vendor_write_sbc_cfg() +{ + UINT8 param[12]; + bt_bdaddr_t bd_addr; + BD_ADDR addr; + btif_av_get_peer_addr(&bd_addr); + memcpy(addr, bd_addr.address, sizeof(BD_ADDR)); + UINT16 acl_hdl = BTM_GetHCIConnHandle(addr, BT_TRANSPORT_BR_EDR); + APPL_TRACE_IMP("btif_media_send_vendor_write_sbc_cfg"); + APPL_TRACE_IMP("acl hdl: %u", acl_hdl); + APPL_TRACE_IMP("channel mode: %u", btif_media_cb.encoder.s16ChannelMode); + APPL_TRACE_IMP("sampling frequency: %u", btif_media_cb.encoder.s16SamplingFreq); + APPL_TRACE_IMP("allocation method: %u", btif_media_cb.encoder.s16AllocationMethod); + APPL_TRACE_IMP("subbands: %u", btif_media_cb.encoder.s16NumOfSubBands); + APPL_TRACE_IMP("num of blocks: %u", btif_media_cb.encoder.s16NumOfBlocks); + APPL_TRACE_IMP("bitpool: <%u>,<%u>", btif_media_cb.min_bitpool, btif_media_cb.max_bitpool); + APPL_TRACE_IMP("Scmst flag: %u", bta_av_co_cp_get_flag()); + + param[0] = VS_QHCI_WRITE_SBC_CFG; + param[1] = (UINT8)((1 << (3 - btif_media_cb.encoder.s16ChannelMode)) | + (1 << (7 - btif_media_cb.encoder.s16SamplingFreq))); + param[2] = (UINT8)((1 << btif_media_cb.encoder.s16AllocationMethod) | + (1 << (3 - (btif_media_cb.encoder.s16NumOfSubBands >> 3))) | + (1 << (7 - ((btif_media_cb.encoder.s16NumOfBlocks - 4) >> 2)))); + param[3] = btif_media_cb.min_bitpool; + param[4] = btif_media_cb.max_bitpool; + param[5] = 0; // Not in use as latency calculation will now be taken care of in SOC + param[6] = 0; // Not in use as latency calculation will now be taken care of in SOC + param[7] = 0; // Not in use as latency calculation will now be taken care of in SOC + param[8] = 0; // Not in use as latency calculation will now be taken care of in SOC + param[9] = 0; // 0 as delayed report not supported +#if (BTA_AV_CO_CP_SCMS_T == TRUE) + param[10] = 1; +#else + param[10] = 0; +#endif + param[11] = bta_av_co_cp_get_flag(); + + return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 12, + param, btif_media_a2dp_write_sbc_cfg_cb); +} + +void btif_media_pref_bit_rate_cb(tBTM_VSC_CMPL *param) +{ + unsigned char status = 0; + BT_HDR *p_buf; + + if (param->param_len) + { + status = param->p_param_buf[0]; + } + APPL_TRACE_IMP("VS_QHCI_A2DP_WRITE_SUGGESTED_BITRATE sent with error code: %u", status); + + if ((!status) && (NULL != (p_buf = GKI_getbuf(sizeof(BT_HDR))))) + { + p_buf->event = BTIF_MEDIA_VS_A2DP_PREF_BIT_RATE_SUCCESS; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); + } + else + { + APPL_TRACE_ERROR("Error in processing Vendor command response"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + } +} + +BOOLEAN btif_media_send_vendor_pref_bit_rate() +{ + UINT8 param[3]; + + APPL_TRACE_IMP("btif_media_send_vendor_pref_bit_rate: bitrate: %d", btif_media_cb.encoder.u16BitRate); + + param[0] = VS_QHCI_A2DP_WRITE_SUGGESTED_BITRATE; + param[1] = (UINT8)(btif_media_cb.encoder.u16BitRate & 0x00ff); + param[2] = (UINT8)((btif_media_cb.encoder.u16BitRate & 0xff00) >> 8); + + return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 3, + param, btif_media_pref_bit_rate_cb); +} + +void btif_media_scmst_cb(tBTM_VSC_CMPL *param) +{ + unsigned char status = 0; + BT_HDR *p_buf; + + if (param->param_len) + { + status = param->p_param_buf[0]; + } + APPL_TRACE_IMP("VS_QHCI_A2DP_WRITE_SCMS_T_CP sent with error code: %u", status); + + if ((!status) && (NULL != (p_buf = GKI_getbuf(sizeof(BT_HDR))))) + { + p_buf->event = BTIF_MEDIA_VS_A2DP_SET_SCMST_HDR_SUCCESS; + fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf); + } + else + { + APPL_TRACE_ERROR("Error in processing Vendor command response"); + a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE); + } +} + +BOOLEAN btif_media_send_vendor_scmst_hdr() +{ + UINT8 param[3]; + + APPL_TRACE_IMP("btif_media_send_vendor_pref_bit_rate"); + + param[0] = VS_QHCI_A2DP_WRITE_SCMS_T_CP; + param[1] = bta_av_co_cp_get_flag(); + + return BTA_DmVendorSpecificCommand(HCI_VSQC_CONTROLLER_A2DP_OPCODE, 2, + param, btif_media_pref_bit_rate_cb); +} + +#endif + #endif /* BTA_AV_INCLUDED == TRUE */ /******************************************************************************* diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c index df980416e..0d7d33a5d 100644 --- a/stack/avdt/avdt_api.c +++ b/stack/avdt/avdt_api.c @@ -1207,6 +1207,22 @@ UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr) return (lcid); } +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/******************************************************************************* +** +** Function AVDT_GetStreamingDestChannel +** +** Description Get the Dest L2CAP CID used by the stream channel. +** +** Returns Destination CID. +** +*******************************************************************************/ +UINT16 AVDT_GetStreamingDestChannelId(UINT16 lcid) +{ + return L2CA_GetDestChannelID(lcid); +} +#endif + #if AVDT_MULTIPLEXING == TRUE /******************************************************************************* ** diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h index 74ee63411..ab28227d5 100644 --- a/stack/include/avdt_api.h +++ b/stack/include/avdt_api.h @@ -939,6 +939,20 @@ extern UINT16 AVDT_GetL2CapChannel(UINT8 handle); *******************************************************************************/ extern UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr); +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/******************************************************************************* +** +** Function AVDT_GetStreamingDestChannel +** +** Description Get the Dest L2CAP CID used by the stream channel. +** +** Returns Destination CID. +** +*******************************************************************************/ +UINT16 AVDT_GetStreamingDestChannelId(UINT16 lcid); +#endif + + /******************************************************************************* ** ** Function AVDT_WriteDataReq diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h index f2b648de7..e73d30c9c 100644 --- a/stack/include/l2c_api.h +++ b/stack/include/l2c_api.h @@ -540,6 +540,19 @@ extern BOOLEAN L2CA_DisconnectRsp (UINT16 cid); *******************************************************************************/ extern UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data); +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/******************************************************************************* +** +** Function L2CA_GetDestChannelID +** +** Description Higher layers call this function to fetch destination channel id. +** +** Returns Destination Channel ID +** +*******************************************************************************/ +UINT16 L2CA_GetDestChannelID (UINT16 cid); +#endif + /******************************************************************************* ** ** Function L2CA_Ping diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c index 437ef9e42..e8e1e3f4a 100644 --- a/stack/l2cap/l2c_api.c +++ b/stack/l2cap/l2c_api.c @@ -1859,6 +1859,30 @@ UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data) return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED); } +#ifdef BTA_AV_SPLIT_A2DP_ENABLED +/******************************************************************************* +** +** Function L2CA_GetDestChannelID +** +** Description Higher layers call this function to fetch destination channel id. +** +** Returns Destination Channel ID +** +*******************************************************************************/ +UINT16 L2CA_GetDestChannelID (UINT16 cid) +{ + tL2C_CCB *p_ccb; + L2CAP_TRACE_API ("L2CA_GetDestChannelID: local cid: %d", cid); + + /* Find the channel control block. We don't know the link it is on. */ + p_ccb = l2cu_find_ccb_by_cid (NULL, cid); + L2CAP_TRACE_DEBUG("local cid: %d, dest cid: %d", + p_ccb->local_cid, p_ccb->remote_cid); + + return p_ccb->remote_cid; +} +#endif + /******************************************************************************* ** ** Function L2CA_SetChnlFlushability diff --git a/udrv/ulinux/uipc.c b/udrv/ulinux/uipc.c index f3c746e09..8e3d4513e 100644 --- a/udrv/ulinux/uipc.c +++ b/udrv/ulinux/uipc.c @@ -427,10 +427,11 @@ static void uipc_flush_locked(tUIPC_CH_ID ch_id) case UIPC_CH_ID_AV_CTRL: uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL); break; - +#ifndef BTA_AV_SPLIT_A2DP_ENABLED case UIPC_CH_ID_AV_AUDIO: uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO); break; +#endif } } @@ -523,13 +524,17 @@ static void uipc_read_task(void *arg) /* check pending task events */ uipc_check_task_flags_locked(); +#ifndef BTA_AV_SPLIT_A2DP_ENABLED /* make sure we service audio channel first */ uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO); +#endif /* check for other connections */ for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) { +#ifndef BTA_AV_SPLIT_A2DP_ENABLED if (ch_id != UIPC_CH_ID_AV_AUDIO) +#endif uipc_check_fd_locked(ch_id); } @@ -633,9 +638,12 @@ BOOLEAN UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK *p_cback) uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback); break; +#ifndef BTA_AV_SPLIT_A2DP_ENABLED case UIPC_CH_ID_AV_AUDIO: uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback); break; +#endif + } UIPC_UNLOCK(); |