From f7dd9f5779680da37dc89e5df2b26d436487818c Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Thu, 24 Oct 2013 15:37:17 +0530 Subject: [PATCH] Add A2DP Sink Support Change-Id: I9affefdd2d00597545e49c593ef3bddb110d4c9c --- Android.mk | 1 + bta/av/bta_av_aact.c | 240 ++++++++++-- bta/av/bta_av_act.c | 5 + bta/av/bta_av_api.c | 32 +- bta/av/bta_av_ci.c | 3 +- bta/av/bta_av_int.h | 27 +- bta/av/bta_av_main.c | 84 +++++ bta/av/bta_av_sbc.c | 73 ++++ bta/av/bta_av_ssm.c | 2 +- bta/include/bta_av_api.h | 29 +- bta/include/bta_av_ci.h | 2 +- bta/include/bta_av_co.h | 4 +- bta/include/bta_av_sbc.h | 12 + btif/co/bta_av_co.c | 372 ++++++++++++++++++- btif/include/bluetoothTrack.h | 32 ++ btif/include/btif_av.h | 2 + btif/include/btif_av_co.h | 1 + btif/include/btif_media.h | 41 ++- btif/include/btif_profile_queue.h | 2 +- btif/src/bluetoothTrack.cpp | 122 +++++++ btif/src/btif_av.c | 310 ++++++++++++++-- btif/src/btif_hf.c | 2 +- btif/src/btif_hf_client.c | 2 +- btif/src/btif_media_task.c | 749 +++++++++++++++++++++++++++++++++++++- btif/src/btif_profile_queue.c | 2 +- include/bt_target.h | 2 + main/Android.mk | 4 +- stack/avdt/avdt_ad.c | 3 + stack/avdt/avdt_api.c | 62 ++++ stack/avdt/avdt_int.h | 1 + stack/avdt/avdt_scb.c | 7 + stack/avdt/avdt_scb_act.c | 13 +- stack/include/avdt_api.h | 29 ++ 33 files changed, 2151 insertions(+), 121 deletions(-) create mode 100644 btif/include/bluetoothTrack.h create mode 100644 btif/src/bluetoothTrack.cpp diff --git a/Android.mk b/Android.mk index 83e6bbff0..dbe1b1fa3 100644 --- a/Android.mk +++ b/Android.mk @@ -12,6 +12,7 @@ else endif bdroid_CFLAGS += -Wall -Werror +bdroid_CFLAGS += -DBTA_AVK_INCLUDED include $(call all-subdir-makefiles) diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c index 6b1a35279..25de516b5 100644 --- a/bta/av/bta_av_aact.c +++ b/bta/av/bta_av_aact.c @@ -193,6 +193,7 @@ static const UINT16 bta_av_stream_evt_fail[] = { 0 /* AVDT_DELAY_REPORT_CFM_EVT */ }; +void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt); static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); #if BTA_AV_NUM_STRS > 2 @@ -225,6 +226,48 @@ tAVDT_CTRL_CBACK * const bta_av_dt_cback[] = ,bta_av_stream5_cback #endif }; +/*********************************************** +** +** Function bta_get_scb_handle +** +** Description gives the registered AVDT handle.by checking with sep_type. +** +** +** Returns void +***********************************************/ +UINT8 bta_av_get_scb_handle ( tBTA_AV_SCB *p_scb, UINT8 local_sep ) +{ + UINT8 xx =0; + for (xx = 0; xxseps[xx].tsep == local_sep) && + (p_scb->seps[xx].codec_type == p_scb->codec_type)) + return (p_scb->seps[xx].av_handle); + } + APPL_TRACE_DEBUG0(" bta_av_get_scb_handle appropiate sep_type not found") + return 0; /* return invalid handle */ +} + +/*********************************************** +** +** Function bta_av_get_scb_sep_type +** +** Description gives the sep type by cross-checking with AVDT handle +** +** +** Returns void +***********************************************/ +UINT8 bta_av_get_scb_sep_type ( tBTA_AV_SCB *p_scb, UINT8 tavdt_handle) +{ + UINT8 xx =0; + for (xx = 0; xxseps[xx].av_handle == tavdt_handle) + return (p_scb->seps[xx].tsep); + } + APPL_TRACE_DEBUG0(" bta_av_get_scb_sep_type appropiate handle not found") + return 3; /* return invalid sep type */ +} /******************************************************************************* ** @@ -320,12 +363,19 @@ static BOOLEAN bta_av_next_getcap(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) int i; tAVDT_GETCAP_REQ *p_req; BOOLEAN sent_cmd = FALSE; + UINT16 uuid_int = p_scb->uuid_int; + UINT8 sep_requested = 0; + + if(uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) + sep_requested = AVDT_TSEP_SNK; + else if(uuid_int == UUID_SERVCLASS_AUDIO_SINK) + sep_requested = AVDT_TSEP_SRC; for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++) { /* steam not in use, is a sink, and is the right media type (audio/video) */ if ((p_scb->sep_info[i].in_use == FALSE) && - (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (p_scb->sep_info[i].tsep == sep_requested) && (p_scb->sep_info[i].media_type == p_scb->media_type)) { p_scb->sep_info_idx = i; @@ -509,6 +559,39 @@ void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CT /******************************************************************************* ** +** Function bta_av_stream_data_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) +{ + int index = 0; + tBTA_AV_SCB *p_scb ; + APPL_TRACE_DEBUG3("bta_av_stream_data_cback avdt_handle: %d pkt_len=0x%x ofst = 0x%x", handle,p_pkt->len,p_pkt->offset); + APPL_TRACE_DEBUG1(" Number of frames 0x%x",*((UINT8*)(p_pkt + 1) + p_pkt->offset)); + APPL_TRACE_DEBUG1("Sequence Number 0x%x",p_pkt->layer_specific); + /* Get SCB and correct sep type*/ + for(index = 0; index < BTA_AV_NUM_STRS;index ++ ) + { + p_scb = bta_av_cb.p_scb[index]; + if((p_scb->avdt_handle == handle)&&(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) + break; + } + if(index == BTA_AV_NUM_STRS) /* cannot find correct handler */ + { + GKI_freebuf(p_pkt); + return; + } + p_pkt->event = BTA_AV_MEDIA_DATA_EVT; + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_DATA_EVT, (tBTA_AV_MEDIA*)p_pkt); + GKI_freebuf(p_pkt); /* a copy of packet had been delivered, we free this buffer */ +} + +/******************************************************************************* +** ** Function bta_av_stream0_cback ** ** Description This is the AVDTP callback function for stream events. @@ -650,16 +733,16 @@ static void bta_av_a2d_sdp_cback(BOOLEAN found, tA2D_Service *p_service) ** Returns ** *******************************************************************************/ -static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb) +static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb, UINT8 avdt_handle) { - int xx; - + int xx; APPL_TRACE_DEBUG1("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type); for(xx=0; xxseps[xx].av_handle, p_scb->seps[xx].codec_type); - if(p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type) + if((p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type) + && (p_scb->seps[xx].av_handle == avdt_handle)) { p_scb->sep_idx = xx; p_scb->avdt_handle = p_scb->seps[xx].av_handle; @@ -781,6 +864,10 @@ void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) av_open.chnl = p_scb->chnl; av_open.hndl = p_scb->hndl; start.status = BTA_AV_FAIL_ROLE; + if(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) + av_open.sep = AVDT_TSEP_SNK; + else if(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) + av_open.sep = AVDT_TSEP_SRC; (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *)&av_open); } else @@ -830,6 +917,7 @@ void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_PROTOCOL_DESC_LIST, ATTR_ID_BT_PROFILE_DESC_LIST}; + UINT16 sdp_uuid = 0; /* UUID for which SDP has to be done */ APPL_TRACE_DEBUG3("bta_av_do_disc_a2d use_rc: %d rs:%d, oc:%d", p_data->api_open.use_rc, p_data->api_open.switch_res, bta_av_cb.audio_open_cnt); @@ -922,8 +1010,14 @@ void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) db_params.num_attr = 3; db_params.p_db = p_scb->p_disc_db; db_params.p_attrs = attr_list; - - if(A2D_FindService(UUID_SERVCLASS_AUDIO_SINK, p_scb->peer_addr, &db_params, + p_scb->uuid_int = p_data->api_open.uuid; + if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK) + sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE; + else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) + sdp_uuid = UUID_SERVCLASS_AUDIO_SINK; + + APPL_TRACE_DEBUG2("uuid_int 0x%x, Doing SDP For 0x%x", p_scb->uuid_int, sdp_uuid); + if(A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params, bta_av_a2d_sdp_cback) == A2D_SUCCESS) { return; @@ -1021,8 +1115,12 @@ void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) tAVDT_SEP_INFO *p_info; tAVDT_CFG *p_evt_cfg = &p_data->str_msg.cfg; UINT8 psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask); + UINT8 local_sep; /* sep type of local handle on which connection was received */ + UINT8 count = 0; + tBTA_AV_STR_MSG *p_msg = (tBTA_AV_STR_MSG *)p_data; UNUSED(p_data); + local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle); p_scb->avdt_label = p_data->str_msg.msg.hdr.label; memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE); p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX]; @@ -1048,7 +1146,13 @@ void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) p_info->in_use = 0; p_info->media_type = p_scb->media_type; p_info->seid = p_data->str_msg.msg.config_ind.int_seid; - p_info->tsep = AVDT_TSEP_SNK; + + /* Sep type of Peer will be oppsite role to our local sep */ + if (local_sep == AVDT_TSEP_SRC) + p_info->tsep = AVDT_TSEP_SNK; + else if (local_sep == AVDT_TSEP_SNK) + p_info->tsep = AVDT_TSEP_SRC; + p_scb->role |= BTA_AV_ROLE_AD_ACP; p_scb->cur_psc_mask = p_evt_cfg->psc_mask; if (bta_av_cb.features & BTA_AV_FEAT_RCTG) @@ -1059,13 +1163,29 @@ void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) p_scb->num_seps = 1; p_scb->sep_info_idx = 0; APPL_TRACE_DEBUG3("bta_av_config_ind: SEID: %d use_rc: %d cur_psc_mask:0x%x", p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask); - - p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type, + /* in case of A2DP SINK this is the first time peer data is being sent to co functions */ + if (local_sep == AVDT_TSEP_SNK) + { + p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type, + p_evt_cfg->codec_info, + p_info->seid, + p_scb->peer_addr, + p_evt_cfg->num_protect, + p_evt_cfg->protect_info, + AVDT_TSEP_SNK, + p_msg->handle); + } + else + { + p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type, p_evt_cfg->codec_info, p_info->seid, p_scb->peer_addr, p_evt_cfg->num_protect, - p_evt_cfg->protect_info); + p_evt_cfg->protect_info, + AVDT_TSEP_SRC, + p_msg->handle); + } } } @@ -1153,12 +1273,21 @@ void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { UINT8 num = p_data->ci_setconfig.num_seid + 1; + UINT8 avdt_handle = p_data->ci_setconfig.avdt_handle; UINT8 *p_seid = p_data->ci_setconfig.p_seid; int i; + UINT8 local_sep; /* we like this codec_type. find the sep_idx */ - bta_av_adjust_seps_idx(p_scb); + local_sep = bta_av_get_scb_sep_type(p_scb,avdt_handle); + bta_av_adjust_seps_idx(p_scb, avdt_handle); APPL_TRACE_DEBUG2("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask); + if ((AVDT_TSEP_SNK == local_sep) && (p_data->ci_setconfig.err_code == AVDT_SUCCESS) && + (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT, + (tBTA_AV_MEDIA*)p_scb->cfg.codec_info); + + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code, p_data->ci_setconfig.category); @@ -1182,8 +1311,11 @@ void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) if (p_scb->codec_type == BTA_AV_CODEC_SBC || num > 1) { /* if SBC is used by the SNK as INT, discover req is not sent in bta_av_config_ind. - * call disc_res now */ - p_scb->p_cos->disc_res(p_scb->hndl, num, num, p_scb->peer_addr); + * call disc_res now */ + /* this is called in A2DP SRC path only, In case of SINK we don't need it */ + if (local_sep == AVDT_TSEP_SRC) + p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr, + UUID_SERVCLASS_AUDIO_SOURCE); } else { @@ -1202,7 +1334,9 @@ void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) p_scb->sep_info[i].media_type = p_scb->media_type; p_scb->sep_info[i].seid = p_seid[i-1]; } - bta_av_next_getcap(p_scb, p_data); + /* only in case of local sep as SRC we need to look for other SEPs, In case of SINK we don't */ + if (local_sep == AVDT_TSEP_SRC) + bta_av_next_getcap(p_scb, p_data); } } @@ -1275,6 +1409,11 @@ void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr); #endif + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) + open.sep = AVDT_TSEP_SNK; + else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) + open.sep = AVDT_TSEP_SRC; + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open); if(open.starting) { @@ -1436,8 +1575,11 @@ void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) *******************************************************************************/ void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { - UINT8 num_snks = 0, i; + UINT8 num_snks = 0, num_srcs =0, i; + /* our uuid in case we initiate connection */ + UINT16 uuid_int = p_scb->uuid_int; + APPL_TRACE_DEBUG1(" initiator UUID 0x%x", uuid_int); /* store number of stream endpoints returned */ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; @@ -1445,15 +1587,23 @@ void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { /* steam not in use, is a sink, and is audio */ if ((p_scb->sep_info[i].in_use == FALSE) && - (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && (p_scb->sep_info[i].media_type == p_scb->media_type)) { - num_snks++; + if((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)) + num_snks++; + + if((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) && + (uuid_int == UUID_SERVCLASS_AUDIO_SINK)) + num_srcs++; + } } - p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr); + p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, num_srcs, p_scb->peer_addr, + uuid_int); p_scb->num_disc_snks = num_snks; + p_scb->num_disc_srcs = num_srcs; /* if we got any */ if (p_scb->num_seps > 0) @@ -1501,9 +1651,10 @@ void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) num_snks++; } } - - p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr); + p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0, p_scb->peer_addr, + UUID_SERVCLASS_AUDIO_SOURCE); p_scb->num_disc_snks = num_snks; + p_scb->num_disc_srcs = 0; /* if we got any */ if (p_scb->num_seps > 0) @@ -1648,6 +1799,11 @@ void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) /* set the state back to initial state */ bta_av_set_scb_sst_init(p_scb); + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) + open.sep = AVDT_TSEP_SNK; + else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) + open.sep = AVDT_TSEP_SRC; + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open); } @@ -1674,6 +1830,7 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) tAVDT_CFG cfg; UINT8 media_type; tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx]; + UINT16 uuid_int; /* UUID for which connection was initiatied */ memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG)); cfg.num_codec = 1; @@ -1702,11 +1859,26 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) /* save copy of codec type and configuration */ p_scb->codec_type = cfg.codec_info[BTA_AV_CODEC_TYPE_IDX]; memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG)); - bta_av_adjust_seps_idx(p_scb); + + uuid_int = p_scb->uuid_int; + APPL_TRACE_DEBUG1(" initiator UUID = 0x%x ", uuid_int); + if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) + bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC)); + else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK) + bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SNK)); + /* use only the services peer supports */ cfg.psc_mask &= p_scb->p_cap->psc_mask; p_scb->cur_psc_mask = cfg.psc_mask; + if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) && + (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) + { + APPL_TRACE_DEBUG0(" Configure Deoder for Sink Connection "); + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT, + (tBTA_AV_MEDIA*)p_scb->cfg.codec_info); + } + /* open the stream */ AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr, p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg); @@ -1738,9 +1910,12 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { tBTA_AV_REJECT reject; + UINT8 avdt_handle = p_data->ci_setconfig.avdt_handle; + + bta_av_adjust_seps_idx(p_scb, avdt_handle); + APPL_TRACE_DEBUG1("bta_av_setconfig_rej: sep_idx: %d",p_scb->sep_idx); + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0); - APPL_TRACE_DEBUG0("bta_av_setconfig_rej"); - AVDT_ConfigRsp(p_data->str_msg.handle, p_data->str_msg.msg.hdr.label, AVDT_ERR_BAD_STATE, 0); bdcpy(reject.bd_addr, p_data->str_msg.bd_addr); reject.hndl = p_scb->hndl; (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject); @@ -2129,6 +2304,13 @@ void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) if (new_role & BTA_AV_ROLE_START_INT) initiator = TRUE; + /* for A2DP SINK we do not send get_caps */ + if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle) + &&(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) + { + p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON); + APPL_TRACE_DEBUG1(" Local SEP type is SNK new wait is 0x%x",p_scb->wait); + } if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) { /* role switch has failed */ @@ -2322,6 +2504,12 @@ void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) data.open.status = p_scb->open_status; data.open.chnl = p_scb->chnl; data.open.hndl = p_scb->hndl; + + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) + data.open.sep = AVDT_TSEP_SNK; + else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) + data.open.sep = AVDT_TSEP_SRC; + event = BTA_AV_OPEN_EVT; p_scb->open_status = BTA_AV_SUCCESS; @@ -2683,7 +2871,7 @@ void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { UNUSED(p_data); - APPL_TRACE_DEBUG1("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks); + APPL_TRACE_DEBUG1("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks); if (p_scb->num_disc_snks == 0) { @@ -2699,7 +2887,7 @@ void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE); /* we may choose to use a different SEP at reconfig. * adjust the sep_idx now */ - bta_av_adjust_seps_idx(p_scb); + bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC)); /* open the stream with the new config */ p_scb->sep_info_idx = p_scb->rcfg_idx; diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c index 1637adcac..54e7aba28 100644 --- a/bta/av/bta_av_act.c +++ b/bta/av/bta_av_act.c @@ -1996,6 +1996,11 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data) #endif bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle); bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE); + +#ifdef BTA_AVK_INCLUDED + bta_av_del_sdp_rec(&p_cb->sdp_a2d_snk_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK); +#endif } } else diff --git a/bta/av/bta_av_api.c b/bta/av/bta_av_api.c index 9b07399e4..47cc2aadf 100644 --- a/bta/av/bta_av_api.c +++ b/bta/av/bta_av_api.c @@ -109,7 +109,7 @@ void BTA_AvDisable(void) ** Returns void ** *******************************************************************************/ -void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id) +void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback) { tBTA_AV_API_REG *p_buf; @@ -128,6 +128,7 @@ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id) p_buf->p_service_name[0] = 0; } p_buf->app_id = app_id; + p_buf->p_app_data_cback = p_data_cback; bta_sys_sendmsg(p_buf); } } @@ -164,7 +165,8 @@ void BTA_AvDeregister(tBTA_AV_HNDL hndl) ** Returns void ** *******************************************************************************/ -void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC sec_mask) +void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC sec_mask, + UINT16 uuid) { tBTA_AV_API_OPEN *p_buf; @@ -176,6 +178,7 @@ void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC s p_buf->use_rc = use_rc; p_buf->sec_mask = sec_mask; p_buf->switch_res = BTA_AV_RS_NONE; + p_buf->uuid = uuid; bta_sys_sendmsg(p_buf); } } @@ -244,6 +247,31 @@ void BTA_AvStart(void) /******************************************************************************* ** +** Function BTA_AvEnable_Sink +** +** Description Enable/Disable A2DP Sink.. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable_Sink(int enable) +{ + BT_HDR *p_buf; + +#ifdef BTA_AVK_INCLUDED + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AV_API_SINK_ENABLE_EVT; + p_buf->layer_specific = enable; + bta_sys_sendmsg(p_buf); + } +#else + return; +#endif +} + +/******************************************************************************* +** ** Function BTA_AvStop ** ** Description Stop audio/video stream data transfer. diff --git a/bta/av/bta_av_ci.c b/bta/av/bta_av_ci.c index a1c2ac0b1..2da1d9767 100644 --- a/bta/av/bta_av_ci.c +++ b/bta/av/bta_av_ci.c @@ -68,7 +68,7 @@ void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl) ** *******************************************************************************/ void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category, - UINT8 num_seid, UINT8 *p_seid, BOOLEAN recfg_needed) + UINT8 num_seid, UINT8 *p_seid, BOOLEAN recfg_needed, UINT8 avdt_handle) { tBTA_AV_CI_SETCONFIG *p_buf; @@ -81,6 +81,7 @@ void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category, p_buf->category = category; p_buf->recfg_needed = recfg_needed; p_buf->num_seid = num_seid; + p_buf->avdt_handle= avdt_handle; if(p_seid && num_seid) { p_buf->p_seid = (UINT8 *)(p_buf + 1); diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h index cd22bcb2d..bbef8c5f8 100644 --- a/bta/av/bta_av_int.h +++ b/bta/av/bta_av_int.h @@ -96,6 +96,9 @@ enum BTA_AV_AVRC_CLOSE_EVT, BTA_AV_CONN_CHG_EVT, BTA_AV_DEREG_COMP_EVT, +#ifdef BTA_AVK_INCLUDED + BTA_AV_API_SINK_ENABLE_EVT, +#endif #if (AVDT_REPORTING == TRUE) BTA_AV_AVDT_RPT_CONN_EVT, #endif @@ -156,16 +159,15 @@ enum /* function types for call-out functions */ typedef BOOLEAN (*tBTA_AV_CO_INIT) (UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index); - typedef void (*tBTA_AV_CO_DISC_RES) (tBTA_AV_HNDL hndl, UINT8 num_seps, - UINT8 num_snk, BD_ADDR addr); - + UINT8 num_snk, UINT8 num_src, BD_ADDR addr, UINT16 uuid_local); typedef UINT8 (*tBTA_AV_CO_GETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, UINT8 *p_protect_info); typedef void (*tBTA_AV_CO_SETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, - UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, - UINT8 num_protect, UINT8 *p_protect_info); + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, + UINT8 num_protect, UINT8 *p_protect_info, + UINT8 t_local_sep, UINT8 avdt_handle); typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT16 mtu); @@ -206,6 +208,7 @@ typedef struct BT_HDR hdr; char p_service_name[BTA_SERVICE_NAME_LEN+1]; UINT8 app_id; + tBTA_AV_DATA_CBACK *p_app_data_cback; } tBTA_AV_API_REG; @@ -225,6 +228,7 @@ typedef struct BOOLEAN use_rc; tBTA_SEC sec_mask; tBTA_AV_RS_RES switch_res; + UINT16 uuid; /* uuid of initiator */ } tBTA_AV_API_OPEN; /* data type for BTA_AV_API_STOP_EVT */ @@ -319,6 +323,7 @@ typedef struct UINT8 num_seid; UINT8 *p_seid; BOOLEAN recfg_needed; + UINT8 avdt_handle; /* local sep type for which this stream will be set up */ } tBTA_AV_CI_SETCONFIG; /* data type for all stream events from AVDTP */ @@ -376,8 +381,10 @@ typedef struct /* type for SEP control block */ typedef struct { - UINT8 av_handle; /* AVDTP handle */ - tBTA_AV_CODEC codec_type; /* codec type */ + UINT8 av_handle; /* AVDTP handle */ + tBTA_AV_CODEC codec_type; /* codec type */ + UINT8 tsep; /* SEP type of local SEP */ + tBTA_AV_DATA_CBACK *p_app_data_cback; /* Application callback for media packets */ } tBTA_AV_SEP; @@ -483,6 +490,7 @@ typedef struct UINT8 hdi; /* the index to SCB[] */ UINT8 num_seps; /* number of seps returned by stream discovery */ UINT8 num_disc_snks; /* number of discovered snks */ + UINT8 num_disc_srcs; /* number of discovered srcs */ UINT8 sep_info_idx; /* current index into sep_info */ UINT8 sep_idx; /* current index into local seps[] */ UINT8 rcfg_idx; /* reconfig requested index into sep_info */ @@ -505,6 +513,7 @@ typedef struct UINT8 wait; /* set 0x1, when getting Caps as ACP, set 0x2, when started */ 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 */ } tBTA_AV_SCB; #define BTA_AV_RC_ROLE_MASK 0x10 @@ -554,6 +563,9 @@ typedef struct TIMER_LIST_ENT sig_tmr; /* link timer */ TIMER_LIST_ENT acp_sig_tmr; /* timer to monitor signalling when accepting */ UINT32 sdp_a2d_handle; /* SDP record handle for audio src */ +#ifdef BTA_AVK_INCLUDED + UINT32 sdp_a2d_snk_handle; /* SDP record handle for audio snk */ +#endif UINT32 sdp_vdp_handle; /* SDP record handle for video src */ tBTA_AV_FEAT features; /* features mask */ tBTA_SEC sec_mask; /* security mask */ @@ -601,6 +613,7 @@ extern const tBTA_AV_SACT bta_av_a2d_action[]; extern const tBTA_AV_CO_FUNCTS bta_av_a2d_cos; extern const tBTA_AV_SACT bta_av_vdp_action[]; extern tAVDT_CTRL_CBACK * const bta_av_dt_cback[]; +extern void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt); /***************************************************************************** ** Function prototypes diff --git a/bta/av/bta_av_main.c b/bta/av/bta_av_main.c index 25c40a5ef..20ed1614d 100644 --- a/bta/av/bta_av_main.c +++ b/bta/av/bta_av_main.c @@ -41,6 +41,8 @@ *****************************************************************************/ /* AVDTP protocol timeout values */ +#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink" + #ifndef BTA_AV_RET_TOUT #define BTA_AV_RET_TOUT 4 #endif @@ -150,6 +152,9 @@ static const tBTA_AV_ST_TBL bta_av_st_tbl[] = typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA *p_data); static void bta_av_api_enable(tBTA_AV_DATA *p_data); static void bta_av_api_register(tBTA_AV_DATA *p_data); +#ifdef BTA_AVK_INCLUDED +static void bta_av_api_sink_enable(tBTA_AV_DATA *p_data); +#endif static void bta_av_ci_data(tBTA_AV_DATA *p_data); #if (AVDT_REPORTING == TRUE) static void bta_av_rpc_conn(tBTA_AV_DATA *p_data); @@ -175,6 +180,9 @@ const tBTA_AV_NSM_ACT bta_av_nsm_act[] = bta_av_rc_closed, /* BTA_AV_AVRC_CLOSE_EVT */ bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */ bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */ +#ifdef BTA_AVK_INCLUDED + bta_av_api_sink_enable, /* BTA_AV_API_SINK_ENABLE_EVT */ +#endif #if (AVDT_REPORTING == TRUE) bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */ #endif @@ -459,6 +467,49 @@ static void bta_av_a2dp_report_cback(UINT8 handle, AVDT_REPORT_TYPE type, } #endif +#ifdef BTA_AVK_INCLUDED +/******************************************************************************* +** +** Function bta_av_api_sink_enable +** +** Description activate, deactive A2DP Sink, +** +** Returns void +** +*******************************************************************************/ + +static void bta_av_api_sink_enable(tBTA_AV_DATA *p_data) +{ + UINT16 activate_sink = 0; + activate_sink = p_data->hdr.layer_specific; + APPL_TRACE_DEBUG1("bta_av_api_sink_enable %d ", activate_sink) + char p_service_name[BTA_SERVICE_NAME_LEN+1]; + BCM_STRNCPY_S(p_service_name, sizeof(p_service_name), + BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN); + + if(activate_sink) + { + AVDT_SINK_Activate(); + if (bta_av_cb.sdp_a2d_snk_handle == 0) + { + bta_av_cb.sdp_a2d_snk_handle = SDP_CreateRecord(); + A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL, + A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_snk_handle); + bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK); + } + } + else + { + AVDT_SINK_Deactivate(); + if (bta_av_cb.sdp_a2d_snk_handle != 0) + { + SDP_DeleteRecord(bta_av_cb.sdp_a2d_snk_handle); + bta_av_cb.sdp_a2d_snk_handle = 0; + bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK); + } + } +} +#endif /******************************************************************************* ** ** Function bta_av_api_register @@ -480,6 +531,8 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data) tBTA_AV_CODEC codec_type; tBTA_UTL_COD cod; UINT8 index = 0; + char p_avk_service_name[BTA_SERVICE_NAME_LEN+1]; + BCM_STRNCPY_S(p_avk_service_name, sizeof(p_avk_service_name), BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN); memset(&cs,0,sizeof(tAVDT_CS)); @@ -534,7 +587,11 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data) } /* Set the Capturing service class bit */ +#ifdef BTA_AVK_INCLUDED + cod.service = BTM_COD_SERVICE_CAPTURING | BTM_COD_SERVICE_RENDERING; +#else cod.service = BTM_COD_SERVICE_CAPTURING; +#endif utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); } /* if 1st channel */ @@ -594,9 +651,27 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data) (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info, &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE) { + +#ifdef BTA_AVK_INCLUDED + if(index == 1) + { + cs.tsep = AVDT_TSEP_SNK; + cs.p_data_cback = bta_av_stream_data_cback; + } + APPL_TRACE_DEBUG1(" SEP Type = %d",cs.tsep); +#endif if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS) { p_scb->seps[index].codec_type = codec_type; + +#ifdef BTA_AVK_INCLUDED + p_scb->seps[index].tsep = cs.tsep; + if(cs.tsep == AVDT_TSEP_SNK) + p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback; + else + p_scb->seps[index].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */ +#endif + APPL_TRACE_DEBUG3("audio[%d] av_handle: %d codec_type: %d", index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type); index++; @@ -613,6 +688,12 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data) A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle); bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE); +#ifdef BTA_AVK_INCLUDED + bta_av_cb.sdp_a2d_snk_handle = SDP_CreateRecord(); + A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_avk_service_name, NULL, + A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_snk_handle); + bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK); +#endif /* start listening when A2DP is registered */ if (bta_av_cb.features & BTA_AV_FEAT_RCTG) bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); @@ -1318,6 +1399,9 @@ char *bta_av_evt_code(UINT16 evt_code) case BTA_AV_AVRC_CLOSE_EVT: return "AVRC_CLOSE"; case BTA_AV_CONN_CHG_EVT: return "CONN_CHG"; case BTA_AV_DEREG_COMP_EVT: return "DEREG_COMP"; +#ifdef BTA_AVK_INCLUDED + case BTA_AV_API_SINK_ENABLE_EVT: return "SINK_ENABLE"; +#endif #if (AVDT_REPORTING == TRUE) case BTA_AV_AVDT_RPT_CONN_EVT: return "RPT_CONN"; #endif diff --git a/bta/av/bta_av_sbc.c b/bta/av/bta_av_sbc.c index a5703756b..af1b3ec89 100644 --- a/bta/av/bta_av_sbc.c +++ b/bta/av/bta_av_sbc.c @@ -511,6 +511,78 @@ UINT8 bta_av_sbc_cfg_for_cap(UINT8 *p_peer, tA2D_SBC_CIE *p_cap, tA2D_SBC_CIE *p /******************************************************************************* ** +** Function bta_av_sbc_cfg_matches_cap +** +** Description This function checks whether an SBC codec configuration +** matched with capabilities. Here we check subset. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +UINT8 bta_av_sbc_cfg_matches_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap) +{ + UINT8 status = 0; + tA2D_SBC_CIE cfg_cie; + + /* parse configuration */ + if ((status = A2D_ParsSbcInfo(&cfg_cie, p_cfg, TRUE)) != 0) + { + APPL_TRACE_ERROR1(" bta_av_sbc_cfg_matches_cap Parsing Failed %d", status); + return status; + } + + /* verify that each parameter is in range */ + + APPL_TRACE_DEBUG2(" FREQ peer: 0%x, capability 0%x", cfg_cie.samp_freq, p_cap->samp_freq); + APPL_TRACE_DEBUG2(" CH_MODE peer: 0%x, capability 0%x", cfg_cie.ch_mode, p_cap->ch_mode); + APPL_TRACE_DEBUG2(" BLOCK_LEN peer: 0%x, capability 0%x", cfg_cie.block_len, p_cap->block_len); + APPL_TRACE_DEBUG2(" SUB_BAND peer: 0%x, capability 0%x", cfg_cie.num_subbands, p_cap->num_subbands); + APPL_TRACE_DEBUG2(" ALLOC_MTHD peer: 0%x, capability 0%x", cfg_cie.alloc_mthd, p_cap->alloc_mthd); + APPL_TRACE_DEBUG2(" MAX_BitPool peer: 0%x, capability 0%x", cfg_cie.max_bitpool, p_cap->max_bitpool); + APPL_TRACE_DEBUG2(" Min_bitpool peer: 0%x, capability 0%x", cfg_cie.min_bitpool, p_cap->min_bitpool); + + /* sampling frequency */ + if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) + { + status = A2D_NS_SAMP_FREQ; + } + /* channel mode */ + else if ((cfg_cie.ch_mode & p_cap->ch_mode) == 0) + { + status = A2D_NS_CH_MODE; + } + /* block length */ + else if ((cfg_cie.block_len & p_cap->block_len) == 0) + { + status = A2D_BAD_BLOCK_LEN; + } + /* subbands */ + else if ((cfg_cie.num_subbands & p_cap->num_subbands) == 0) + { + status = A2D_NS_SUBBANDS; + } + /* allocation method */ + else if ((cfg_cie.alloc_mthd & p_cap->alloc_mthd) == 0) + { + status = A2D_NS_ALLOC_MTHD; + } + /* max bitpool */ + else if (cfg_cie.max_bitpool > p_cap->max_bitpool) + { + status = A2D_NS_MAX_BITPOOL; + } + /* min bitpool */ + else if (cfg_cie.min_bitpool < p_cap->min_bitpool) + { + status = A2D_NS_MIN_BITPOOL; + } + + return status; +} + + +/******************************************************************************* +** ** Function bta_av_sbc_cfg_in_cap ** ** Description This function checks whether an SBC codec configuration @@ -532,6 +604,7 @@ UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap) /* verify that each parameter is in range */ + /* sampling frequency */ if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) { diff --git a/bta/av/bta_av_ssm.c b/bta/av/bta_av_ssm.c index 407146efd..5756c886a 100644 --- a/bta/av/bta_av_ssm.c +++ b/bta/av/bta_av_ssm.c @@ -162,7 +162,7 @@ static const UINT8 bta_av_sst_incoming[][BTA_AV_NUM_COLS] = /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER, BTA_AV_INCOMING_SST }, -/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP,BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h index 1ea570c64..22ee91cd8 100644 --- a/bta/include/bta_av_api.h +++ b/bta/include/bta_av_api.h @@ -249,8 +249,11 @@ typedef UINT8 tBTA_AV_ERR; #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_DATA_EVT 21 /* sending data to Media Task */ /* Max BTA event */ -#define BTA_AV_MAX_EVT 20 +#define BTA_AV_MAX_EVT 22 + typedef UINT8 tBTA_AV_EVT; @@ -282,6 +285,7 @@ typedef struct tBTA_AV_STATUS status; BOOLEAN starting; tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */ + UINT8 sep; /* sep type of peer device */ } tBTA_AV_OPEN; /* data associated with BTA_AV_CLOSE_EVT */ @@ -446,6 +450,13 @@ typedef union tBTA_AV_RC_FEAT rc_feat; } tBTA_AV; +/* union of data associated with AV Media callback */ +typedef union +{ + BT_HDR *p_data; + UINT8 *codec_info; +} tBTA_AV_MEDIA; + #define BTA_AVC_PACKET_LEN AVRC_PACKET_LEN #define BTA_VENDOR_DATA_OFFSET 6 @@ -464,6 +475,7 @@ typedef union /* AV callback */ typedef void (tBTA_AV_CBACK)(tBTA_AV_EVT event, tBTA_AV *p_data); +typedef void (tBTA_AV_DATA_CBACK)(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data); /* type for stream state machine action functions */ typedef void (*tBTA_AV_ACT)(void *p_cb, void *p_data); @@ -548,7 +560,7 @@ BTA_API void BTA_AvDisable(void); ** *******************************************************************************/ BTA_API void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, - UINT8 app_id); + UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback); /******************************************************************************* ** @@ -573,7 +585,7 @@ BTA_API void BTA_AvDeregister(tBTA_AV_HNDL hndl); ** *******************************************************************************/ BTA_API void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, - BOOLEAN use_rc, tBTA_SEC sec_mask); + BOOLEAN use_rc, tBTA_SEC sec_mask, UINT16 uuid); /******************************************************************************* ** @@ -599,6 +611,17 @@ BTA_API void BTA_AvDisconnect(BD_ADDR bd_addr); /******************************************************************************* ** +** Function BTA_AvEnable_Sink +** +** Description Enable/Disable A2DP Sink. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable_Sink(int enable); + +/******************************************************************************* +** ** Function BTA_AvStart ** ** Description Start audio/video stream data transfer. diff --git a/bta/include/bta_av_ci.h b/bta/include/bta_av_ci.h index 63668a907..faad260dc 100644 --- a/bta/include/bta_av_ci.h +++ b/bta/include/bta_av_ci.h @@ -63,7 +63,7 @@ BTA_API extern void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl); *******************************************************************************/ BTA_API extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category, UINT8 num_seid, UINT8 *p_seid, - BOOLEAN recfg_needed); + BOOLEAN recfg_needed, UINT8 avdt_handle); #ifdef __cplusplus diff --git a/bta/include/bta_av_co.h b/bta/include/bta_av_co.h index 862ac5ef2..ed11c5030 100644 --- a/bta/include/bta_av_co.h +++ b/bta/include/bta_av_co.h @@ -100,7 +100,7 @@ BTA_API extern BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_ ** *******************************************************************************/ BTA_API extern void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, - UINT8 num_snk, BD_ADDR addr); + UINT8 num_snk, UINT8 num_src, BD_ADDR addr, UINT16 uuid_local); /******************************************************************************* ** @@ -162,7 +162,7 @@ BTA_API extern UINT8 bta_av_co_video_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC *******************************************************************************/ BTA_API extern void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, - UINT8 num_protect, UINT8 *p_protect_info); + UINT8 num_protect, UINT8 *p_protect_info,UINT8 t_local_sep, UINT8 avdt_handle); /******************************************************************************* ** diff --git a/bta/include/bta_av_sbc.h b/bta/include/bta_av_sbc.h index 98eb6ae79..d7cfa8950 100644 --- a/bta/include/bta_av_sbc.h +++ b/bta/include/bta_av_sbc.h @@ -194,6 +194,18 @@ extern UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap); /******************************************************************************* ** +** Function bta_av_sbc_cfg_matches_cap +** +** Description This function checks whether an SBC codec configuration +** matched with capabilities. Here we check subset. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +extern UINT8 bta_av_sbc_cfg_matches_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap); + +/******************************************************************************* +** ** Function bta_av_sbc_bld_hdr ** ** Description This function builds the packet header for MPF1. diff --git a/btif/co/bta_av_co.c b/btif/co/bta_av_co.c index fecf6216b..a0cc3448e 100644 --- a/btif/co/bta_av_co.c +++ b/btif/co/bta_av_co.c @@ -67,7 +67,7 @@ /* SCMS-T protect info */ const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00"; -/* SBC codec capabilities */ +/* SBC SRC codec capabilities */ const tA2D_SBC_CIE bta_av_co_sbc_caps = { (A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ @@ -79,6 +79,18 @@ const tA2D_SBC_CIE bta_av_co_sbc_caps = A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ }; +/* SBC SINK codec capabilities */ +const tA2D_SBC_CIE bta_av_co_sbc_sink_caps = +{ + (A2D_SBC_IE_SAMP_FREQ_48 | A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ + (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ + (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ + (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ + (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */ + A2D_SBC_IE_MAX_BITPOOL, /* max_bitpool */ + A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ +}; + #if !defined(BTIF_AV_SBC_DEFAULT_SAMP_FREQ) #define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44 #endif @@ -113,17 +125,23 @@ typedef struct { BD_ADDR addr; /* address of audio/video peer */ tBTA_AV_CO_SINK snks[BTIF_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */ + tBTA_AV_CO_SINK srcs[BTIF_SV_AV_AA_SEP_INDEX]; /* array of supported srcs */ UINT8 num_snks; /* total number of sinks at peer */ + UINT8 num_srcs; /* total number of srcs at peer */ UINT8 num_seps; /* total number of seids at peer */ UINT8 num_rx_snks; /* number of received sinks */ + UINT8 num_rx_srcs; /* number of received srcs */ UINT8 num_sup_snks; /* number of supported sinks in the snks array */ + UINT8 num_sup_srcs; /* number of supported srcs in the srcs array */ tBTA_AV_CO_SINK *p_snk; /* currently selected sink */ + tBTA_AV_CO_SINK *p_src; /* currently selected src */ UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */ BOOLEAN cp_active; /* current CP configuration */ BOOLEAN acp; /* acceptor */ BOOLEAN recfg_needed; /* reconfiguration is needed */ BOOLEAN opened; /* opened */ UINT16 mtu; /* maximum transmit unit size */ + UINT16 uuid_to_connect; /* uuid of peer device */ } tBTA_AV_CO_PEER; typedef struct @@ -152,7 +170,8 @@ static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo); static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink); static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index); static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); - +static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); +static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index); @@ -284,7 +303,7 @@ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_ switch (index) { case BTIF_SV_AV_AA_SBC_INDEX: - /* Set up for SBC codec */ + /* Set up for SBC codec for SRC*/ *p_codec_type = BTA_AV_CODEC_SBC; /* This should not fail because we are using constants for parameters */ @@ -292,8 +311,16 @@ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_ /* Codec is valid */ return TRUE; +#ifdef BTA_AVK_INCLUDED + case BTIF_SV_AV_AA_SBC_SINK_INDEX: + *p_codec_type = BTA_AV_CODEC_SBC; + /* This should not fail because we are using constants for parameters */ + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_sink_caps, p_codec_info); + /* Codec is valid */ + return TRUE; +#endif default: /* Not valid */ return FALSE; @@ -313,14 +340,14 @@ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_ ** *******************************************************************************/ BTA_API void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk, - BD_ADDR addr) + UINT8 num_src, BD_ADDR addr, UINT16 uuid_local) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); - APPL_TRACE_DEBUG3("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d", - hndl, num_seps, num_snk); + APPL_TRACE_DEBUG4("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d num_src:%d", + hndl, num_seps, num_snk, num_src); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); @@ -339,13 +366,220 @@ BTA_API void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 n /* Copy the discovery results */ bdcpy(p_peer->addr, addr); p_peer->num_snks = num_snk; + p_peer->num_srcs = num_src; p_peer->num_seps = num_seps; p_peer->num_rx_snks = 0; + p_peer->num_rx_srcs = 0; p_peer->num_sup_snks = 0; + if (uuid_local == UUID_SERVCLASS_AUDIO_SINK) + p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE; + else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE) + p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK; } /******************************************************************************* ** + ** Function bta_av_build_src_cfg + ** + ** Description This function will build preferred config from src capabilities + ** + ** + ** Returns Pass or Fail for current getconfig. + ** + *******************************************************************************/ +void bta_av_build_src_cfg (UINT8 *p_pref_cfg, UINT8 *p_src_cap) +{ + tA2D_SBC_CIE src_cap; + tA2D_SBC_CIE pref_cap; + UINT8 status = 0; + + /* initialize it to default SBC configuration */ + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &btif_av_sbc_default_config, p_pref_cfg); + /* now try to build a preferred one */ + /* parse configuration */ + if ((status = A2D_ParsSbcInfo(&src_cap, p_src_cap, TRUE)) != 0) + { + APPL_TRACE_DEBUG1(" Cant parse src cap ret = %d", status); + return ; + } + + if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_48) + pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_48; + else if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_44) + pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_44; + + if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_JOINT) + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_JOINT; + else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_STEREO) + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_STEREO; + else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_DUAL) + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_DUAL; + else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_MONO) + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_MONO; + + if (src_cap.block_len & A2D_SBC_IE_BLOCKS_16) + pref_cap.block_len = A2D_SBC_IE_BLOCKS_16; + else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_12) + pref_cap.block_len = A2D_SBC_IE_BLOCKS_12; + else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_8) + pref_cap.block_len = A2D_SBC_IE_BLOCKS_8; + else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_4) + pref_cap.block_len = A2D_SBC_IE_BLOCKS_4; + + if (src_cap.num_subbands & A2D_SBC_IE_SUBBAND_8) + pref_cap.num_subbands = A2D_SBC_IE_SUBBAND_8; + else if(src_cap.num_subbands & A2D_SBC_IE_SUBBAND_4) + pref_cap.num_subbands = A2D_SBC_IE_SUBBAND_4; + + if (src_cap.alloc_mthd & A2D_SBC_IE_ALLOC_MD_L) + pref_cap.alloc_mthd = A2D_SBC_IE_ALLOC_MD_L; + else if(src_cap.alloc_mthd & A2D_SBC_IE_ALLOC_MD_S) + pref_cap.alloc_mthd = A2D_SBC_IE_ALLOC_MD_S; + + pref_cap.max_bitpool = src_cap.max_bitpool; + pref_cap.min_bitpool = src_cap.min_bitpool; + + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &pref_cap, p_pref_cfg); +} + +/******************************************************************************* + ** + ** Function bta_av_audio_sink_getconfig + ** + ** Description This callout function is executed by AV to retrieve the + ** desired codec and content protection configuration for the + ** A2DP Sink audio stream in Initiator. + ** + ** + ** Returns Pass or Fail for current getconfig. + ** + *******************************************************************************/ +UINT8 bta_av_audio_sink_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, + UINT8 *p_protect_info) +{ + + UINT8 result = A2D_FAIL; + BOOLEAN supported; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_src; + UINT8 codec_cfg[AVDT_CODEC_SIZE]; + UINT8 pref_cfg[AVDT_CODEC_SIZE]; + UINT8 index; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG3("bta_av_audio_sink_getconfig handle:0x%x codec_type:%d seid:%d", + hndl, codec_type, seid); + APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x", + *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_audio_sink_getconfig could not find peer entry"); + return A2D_FAIL; + } + + APPL_TRACE_DEBUG4("bta_av_audio_sink_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", + p_peer->opened, p_peer->num_srcs, p_peer->num_rx_srcs, p_peer->num_sup_srcs); + + p_peer->num_rx_srcs++; + + /* Check if this is a supported configuration */ + supported = FALSE; + switch (codec_type) + { + case BTA_AV_CODEC_SBC: + supported = TRUE; + break; + + default: + break; + } + + if (supported) + { + /* If there is room for a new one */ + if (p_peer->num_sup_srcs < BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs)) + { + p_src = &p_peer->srcs[p_peer->num_sup_srcs++]; + + APPL_TRACE_DEBUG6("bta_av_audio_sink_getconfig saved caps[%x:%x:%x:%x:%x:%x]", + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); + + memcpy(p_src->codec_caps, p_codec_info, AVDT_CODEC_SIZE); + p_src->codec_type = codec_type; + p_src->sep_info_idx = *p_sep_info_idx; + p_src->seid = seid; + p_src->num_protect = *p_num_protect; + memcpy(p_src->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN); + } + else + { + APPL_TRACE_ERROR0("bta_av_audio_sink_getconfig no more room for SRC info"); + } + } + + /* If last SNK get capabilities or all supported codec caps retrieved */ + if ((p_peer->num_rx_srcs == p_peer->num_srcs) || + (p_peer->num_sup_srcs == BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs))) + { + APPL_TRACE_DEBUG0("bta_av_audio_sink_getconfig last SRC reached"); + + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_disable(); + + /* Find a src that matches the codec config */ + if (bta_av_co_audio_peer_src_supports_codec(p_peer, &index)) + { + APPL_TRACE_DEBUG0(" Codec Supported "); + p_src = &p_peer->srcs[index]; + + /* Build the codec configuration for this sink */ + { + /* Save the new configuration */ + p_peer->p_src = p_src; + /* get preferred config from src_caps */ + bta_av_build_src_cfg(pref_cfg, p_src->codec_caps); + memcpy(p_peer->codec_cfg, pref_cfg, AVDT_CODEC_SIZE); + + APPL_TRACE_DEBUG6("bta_av_audio_sink_getconfig p_codec_info[%x:%x:%x:%x:%x:%x]", + p_peer->codec_cfg[1], p_peer->codec_cfg[2], p_peer->codec_cfg[3], + p_peer->codec_cfg[4], p_peer->codec_cfg[5], p_peer->codec_cfg[6]); + /* By default, no content protection */ + *p_num_protect = 0; + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + /* Check if this sink supports SCMS */ + if (bta_av_co_audio_sink_has_scmst(p_sink)) + { + p_peer->cp_active = TRUE; + bta_av_co_cb.cp.active = TRUE; + *p_num_protect = BTA_AV_CP_INFO_LEN; + memcpy(p_protect_info, bta_av_co_cp_scmst, BTA_AV_CP_INFO_LEN); + } + else + { + p_peer->cp_active = FALSE; + bta_av_co_cb.cp.active = FALSE; + } +#endif + + *p_sep_info_idx = p_src->sep_info_idx; + memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE); + result = A2D_SUCCESS; + } + } + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_enable(); + } + return result; +} +/******************************************************************************* + ** ** Function bta_av_co_audio_getconfig ** ** Description This callout function is executed by AV to retrieve the @@ -370,10 +604,6 @@ BTA_API UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_t FUNC_TRACE(); - APPL_TRACE_DEBUG3("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", hndl, codec_type, seid); - APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x", - *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); - /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) @@ -382,10 +612,20 @@ BTA_API UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_t return A2D_FAIL; } + if (p_peer->uuid_to_connect == UUID_SERVCLASS_AUDIO_SOURCE) + { + result = bta_av_audio_sink_getconfig(hndl, codec_type, p_codec_info, p_sep_info_idx, + seid, p_num_protect, p_protect_info); + return result; + } + APPL_TRACE_DEBUG3("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", + hndl, codec_type, seid); + APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x", + *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + APPL_TRACE_DEBUG4("bta_av_co_audio_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); - /* Increment the number of received sinks capabilities */ p_peer->num_rx_snks++; /* Check if this is a supported configuration */ @@ -510,13 +750,15 @@ BTA_API UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_t ** *******************************************************************************/ BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, - UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, UINT8 num_protect, UINT8 *p_protect_info) + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, UINT8 num_protect, UINT8 *p_protect_info, + UINT8 t_local_sep, UINT8 avdt_handle) { tBTA_AV_CO_PEER *p_peer; UINT8 status = A2D_SUCCESS; UINT8 category = A2D_SUCCESS; BOOLEAN recfg_needed = FALSE; + BOOLEAN codec_cfg_supported = FALSE; UNUSED(seid); UNUSED(addr); @@ -535,9 +777,11 @@ BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_ty APPL_TRACE_ERROR0("bta_av_co_audio_setconfig could not find peer entry"); /* Call call-in rejecting the configuration */ - bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE); + bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE, avdt_handle); return; } + APPL_TRACE_DEBUG4("bta_av_co_audio_setconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", + p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); /* Sanity check: should not be opened at this point */ if (p_peer->opened) @@ -568,9 +812,20 @@ BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_ty #endif if (status == A2D_SUCCESS) { + if(AVDT_TSEP_SNK == t_local_sep) + { + codec_cfg_supported = bta_av_co_audio_sink_supports_config(codec_type, p_codec_info); + APPL_TRACE_DEBUG0(" Peer is A2DP SRC "); + } + if(AVDT_TSEP_SRC == t_local_sep) + { + codec_cfg_supported = bta_av_co_audio_media_supports_config(codec_type, p_codec_info); + APPL_TRACE_DEBUG0(" Peer is A2DP SINK "); + } /* Check if codec configuration is supported */ - if (bta_av_co_audio_media_supports_config(codec_type, p_codec_info)) + if (codec_cfg_supported) { + /* Protect access to bta_av_co_cb.codec_cfg */ GKI_disable(); @@ -595,6 +850,13 @@ BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_ty bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_SBC; memcpy(bta_av_co_cb.codec_cfg_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); + if(AVDT_TSEP_SNK == t_local_sep) + { + /* If Peer is SRC, and our cfg subset matches with what is requested by peer, then + just accept what peer wants */ + memcpy(bta_av_co_cb.codec_cfg.info, p_codec_info, AVDT_CODEC_SIZE); + recfg_needed = FALSE; + } break; @@ -618,7 +880,7 @@ BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_ty APPL_TRACE_DEBUG2("bta_av_co_audio_setconfig reject s=%d c=%d", status, category); /* Call call-in rejecting the configuration */ - bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE); + bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE, avdt_handle); } else { @@ -629,7 +891,7 @@ BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_ty APPL_TRACE_DEBUG1("bta_av_co_audio_setconfig accept reconf=%d", recfg_needed); /* Call call-in accepting the configuration */ - bta_av_ci_setconfig(hndl, A2D_SUCCESS, A2D_SUCCESS, 0, NULL, recfg_needed); + bta_av_ci_setconfig(hndl, A2D_SUCCESS, A2D_SUCCESS, 0, NULL, recfg_needed, avdt_handle); } } @@ -1094,13 +1356,89 @@ static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT /******************************************************************************* ** - ** Function bta_av_co_audio_media_supports_config + ** Function bta_av_co_audio_peer_src_supports_codec + ** + ** Description Check if a peer acting as src supports codec config + ** + ** Returns TRUE if the connection supports this codec, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index) +{ + int index; + UINT8 codec_type; + FUNC_TRACE(); + + /* Configure the codec type to look for */ + codec_type = bta_av_co_cb.codec_cfg.id; + + + for (index = 0; index < p_peer->num_sup_srcs; index++) + { + if (p_peer->srcs[index].codec_type == codec_type) + { + switch (bta_av_co_cb.codec_cfg.id) + { + case BTIF_AV_CODEC_SBC: + if (p_src_index) *p_src_index = index; + if (0 == bta_av_sbc_cfg_matches_cap((UINT8 *)p_peer->srcs[index].codec_caps, + (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) + { + return TRUE; + } + break; + + default: + APPL_TRACE_ERROR1("peer_src_supports_codec: unsupported codec id %d", + bta_av_co_cb.codec_cfg.id); + return FALSE; + break; + } + } + } + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_sink_supports_config ** ** Description Check if the media source supports a given configuration ** ** Returns TRUE if the media source supports this config, FALSE otherwise ** *******************************************************************************/ +static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + switch (codec_type) + { + case BTA_AV_CODEC_SBC: + if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) + { + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR1("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); + return FALSE; + break; + } + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_media_supports_config + ** + ** Description Check if the media sink supports a given configuration + ** + ** Returns TRUE if the media source supports this config, FALSE otherwise + ** + *******************************************************************************/ static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) { FUNC_TRACE(); diff --git a/btif/include/bluetoothTrack.h b/btif/include/bluetoothTrack.h new file mode 100644 index 000000000..e4e1660ab --- /dev/null +++ b/btif/include/bluetoothTrack.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * + * 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. + * + ******************************************************************************/ + +#if defined (__cplusplus) || (cplusplus) +extern "C" { +#endif + +int btCreateTrack(int trackFreq, int channelType); +void btDeleteTrack(); +void btStopTrack(); +void btStartTrack(); +void btPauseTrack(); +int btWriteData(void *audioBuffer, int bufferlen); + +#if defined (__cplusplus) || (cplusplus) +} +#endif diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h index 9e537cdfc..eda9c1822 100644 --- a/btif/include/btif_av.h +++ b/btif/include/btif_av.h @@ -45,6 +45,8 @@ typedef enum { BTIF_AV_STOP_STREAM_REQ_EVT, BTIF_AV_SUSPEND_STREAM_REQ_EVT, BTIF_AV_RECONFIGURE_REQ_EVT, + BTIF_AV_REQUEST_AUDIO_FOCUS_EVT, + BTIF_AV_REQUEST_ACTIVATE_SINK_EVT, } btif_av_sm_event_t; diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h index 20e9a1e8a..a6a5bfaba 100644 --- a/btif/include/btif_av_co.h +++ b/btif/include/btif_av_co.h @@ -28,6 +28,7 @@ enum { BTIF_SV_AV_AA_SBC_INDEX = 0, + BTIF_SV_AV_AA_SBC_SINK_INDEX, BTIF_SV_AV_AA_SEP_INDEX /* Last index */ }; diff --git a/btif/include/btif_media.h b/btif/include/btif_media.h index 4cdbb8c96..a785d340b 100644 --- a/btif/include/btif_media.h +++ b/btif/include/btif_media.h @@ -90,8 +90,20 @@ typedef struct tBTIF_AV_FEEDING_MODE feeding_mode; tBTIF_AV_MEDIA_FEEDINGS feeding; } tBTIF_MEDIA_INIT_AUDIO_FEEDING; + +typedef struct +{ + BT_HDR hdr; + UINT8 codec_info[AVDT_CODEC_SIZE]; +} tBTIF_MEDIA_SINK_CFG_UPDATE; #endif +typedef enum { + BTIF_MEDIA_AUDIOFOCUS_LOSS = 0, + BTIF_MEDIA_AUDIOFOCUS_GAIN, + BTIF_MEDIA_AUDIOFOCUS_LOSS_TRANSIENT +} btif_media_AudioFocus_state; + /******************************************************************************* ** Public functions @@ -154,7 +166,16 @@ extern BOOLEAN btif_media_task_start_aa_req(void); *******************************************************************************/ extern BOOLEAN btif_media_task_stop_aa_req(void); - +/******************************************************************************* + ** + ** Function btif_media_task_aa_rx_flush_req + ** + ** Description Request to flush audio decoding pipe + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btif_media_task_aa_rx_flush_req(void); /******************************************************************************* ** ** Function btif_media_task_aa_tx_flush_req @@ -179,6 +200,19 @@ extern BT_HDR *btif_media_aa_readbuf(void); /******************************************************************************* ** + ** Function btif_media_sink_enque_buf + ** + ** Description This function is called by the av_co to fill A2DP Sink Queue + ** + ** + ** Returns size of the queue + *******************************************************************************/ + UINT8 btif_media_sink_enque_buf(BT_HDR *p_buf); + + + +/******************************************************************************* + ** ** Function btif_media_aa_writebuf ** ** Description Enqueue a Advance Audio media GKI buffer to be processed by btif media task. @@ -243,5 +277,10 @@ void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av); void btif_a2dp_on_suspend(void); void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av); void btif_a2dp_set_tx_flush(BOOLEAN enable); +void btif_a2dp_set_rx_flush(BOOLEAN enable); +void btif_media_check_iop_exceptions(UINT8 *peer_bda); +void btif_reset_decoder(UINT8 *p_av); +BOOLEAN btif_media_task_start_decoding_req(void); +void btif_a2dp_set_audio_focus_state(btif_media_AudioFocus_state state); #endif diff --git a/btif/include/btif_profile_queue.h b/btif/include/btif_profile_queue.h index e05c97aa9..b58657556 100644 --- a/btif/include/btif_profile_queue.h +++ b/btif/include/btif_profile_queue.h @@ -27,7 +27,7 @@ #ifndef BTIF_PROFILE_QUEUE_H #define BTIF_PROFILE_QUEUE_H -typedef bt_status_t (*btif_connect_cb_t)(bt_bdaddr_t *bda); +typedef bt_status_t (*btif_connect_cb_t) (bt_bdaddr_t *bda, uint16_t uuid); bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda, btif_connect_cb_t connect_cb); void btif_queue_advance(); diff --git a/btif/src/bluetoothTrack.cpp b/btif/src/bluetoothTrack.cpp new file mode 100644 index 000000000..685780e85 --- /dev/null +++ b/btif/src/bluetoothTrack.cpp @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * + * 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 "bluetoothTrack.h" +#include + +//#define DUMP_PCM_DATA TRUE +#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) +FILE *outputPcmSampleFile; +char outputFilename [50] = "/data/misc/bluedroid/output_sample.pcm"; +#endif + +struct BluetoothTrack { + android::sp mTrack; +}; + +typedef struct BluetoothTrack BluetoothTrack; + +BluetoothTrack *track = NULL; + +int btCreateTrack(int trackFreq, int channelType) +{ + int ret = -1; + if (track == NULL) + track = new BluetoothTrack; + track->mTrack = NULL; + track->mTrack = new android::AudioTrack(AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT, + channelType, (int)0, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST, NULL, NULL, 0, 0, android::AudioTrack::TRANSFER_SYNC); + if (track->mTrack == NULL) + { + delete track; + track = NULL; + return ret; + } + if (track->mTrack->initCheck() != 0) + { + delete track; + track = NULL; + return ret; + } +#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) + outputPcmSampleFile = fopen(outputFilename, "ab"); +#endif + ret = 0; + track->mTrack->setVolume(1, 1); + return ret; +} + +void btStartTrack() +{ + if ((track != NULL) && (track->mTrack.get() != NULL)) + { + track->mTrack->start(); + } +} + + +void btDeleteTrack() +{ + if ((track != NULL) && (track->mTrack.get() != NULL)) + { + track->mTrack.clear(); + delete track; + track = NULL; + } +#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) + if (outputPcmSampleFile) + { + fclose(outputPcmSampleFile); + } + outputPcmSampleFile = NULL; +#endif +} + +void btPauseTrack() +{ + if ((track != NULL) && (track->mTrack.get() != NULL)) + { + track->mTrack->pause(); + track->mTrack->flush(); + } +} + +void btStopTrack() +{ + if ((track != NULL) && (track->mTrack.get() != NULL)) + { + track->mTrack->stop(); + } +} + +int btWriteData(void *audioBuffer, int bufferlen) +{ + int retval = -1; + if ((track != NULL) && (track->mTrack.get() != NULL)) + { +#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE)) + if (outputPcmSampleFile) + { + fwrite ((audioBuffer), 1, (size_t)bufferlen, outputPcmSampleFile); + } +#endif + retval = track->mTrack->write(audioBuffer, (size_t)bufferlen); + } + return retval; +} + diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c index f893c9e31..0b7b9d714 100644 --- a/btif/src/btif_av.c +++ b/btif/src/btif_av.c @@ -69,6 +69,12 @@ typedef enum { /***************************************************************************** ** Local type definitions ******************************************************************************/ +typedef enum +{ + SEP_SRC = 0x0, + SEP_SNK, + SEP_NOT_OPENED +}tbtif_AV_SEP_TYPE; typedef struct { @@ -77,8 +83,14 @@ typedef struct btif_sm_handle_t sm_handle; UINT8 flags; tBTA_AV_EDR edr; + tbtif_AV_SEP_TYPE sep; /* sep type of peer device */ } btif_av_cb_t; +typedef struct +{ + bt_bdaddr_t *target_bda; + uint16_t uuid; +} btif_av_connect_req_t; /***************************************************************************** ** Static variables ******************************************************************************/ @@ -180,11 +192,38 @@ const char *dump_av_sm_event_name(btif_av_sm_event_t event) CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT) CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT) CASE_RETURN_STR(BTIF_AV_RECONFIGURE_REQ_EVT) - + CASE_RETURN_STR(BTIF_AV_REQUEST_AUDIO_FOCUS_EVT) + CASE_RETURN_STR(BTIF_AV_REQUEST_ACTIVATE_SINK_EVT) default: return "UNKNOWN_EVENT"; } } +/******************************************************************************* +** +** Function btif_av_request_audio_focus +** +** Description send request to gain audio focus +** +** Returns void +** +*******************************************************************************/ +void btif_av_request_audio_focus( BOOLEAN enable) +{ + btif_sm_state_t state; + state= btif_sm_get_state(btif_av_cb.sm_handle); + /* We shld be in started state */ + if (state != BTIF_AV_STATE_STARTED) + return; + /* If we are in started state, suspend shld not have been initiated */ + if ((btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND )|| + (btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING)) + return; + if(enable) + { + btif_dispatch_sm_event(BTIF_AV_REQUEST_AUDIO_FOCUS_EVT, NULL, 0); + } +} + /**************************************************************************** ** Local helper functions *****************************************************************************/ @@ -203,11 +242,15 @@ static void btif_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle) { BD_ADDR peer_addr; UNUSED(tle); - + btif_av_connect_req_t connect_req; + UNUSED(tle); /* is there at least one RC connection - There should be */ if (btif_rc_get_connected_peer(peer_addr)) { BTIF_TRACE_DEBUG1("%s Issuing connect to the remote RC peer", __FUNCTION__); - btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (void*)&peer_addr); + /* In case of AVRCP connection request, we will initiate SRC connection */ + connect_req.target_bda = (bt_bdaddr_t*)&peer_addr; + connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE; + btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req); } else { @@ -221,7 +264,7 @@ static void btif_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle) /***************************************************************************** ** -** Function btif_av_state_idle_handler +** Function btif_av_state_idle_handler ** ** Description State managing disconnected AV link ** @@ -241,6 +284,7 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); btif_av_cb.flags = 0; btif_av_cb.edr = 0; + btif_av_cb.sep = SEP_NOT_OPENED; btif_a2dp_on_idle(); break; @@ -250,6 +294,14 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) case BTA_AV_ENABLE_EVT: break; + case BTIF_AV_REQUEST_ACTIVATE_SINK_EVT: + { + int enable = *((int*)p_data); + BTIF_TRACE_DEBUG1(" Active_Sink enable %d", enable) + BTA_AvEnable_Sink(enable); + } + break; + case BTA_AV_REGISTER_EVT: btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl; break; @@ -259,14 +311,17 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) { if (event == BTIF_AV_CONNECT_REQ_EVT) { - memcpy(&btif_av_cb.peer_bda, (bt_bdaddr_t*)p_data, sizeof(bt_bdaddr_t)); + memcpy(&btif_av_cb.peer_bda, ((btif_av_connect_req_t*)p_data)->target_bda, + sizeof(bt_bdaddr_t)); + BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, + TRUE, BTA_SEC_NONE, ((btif_av_connect_req_t*)p_data)->uuid); } else if (event == BTA_AV_PENDING_EVT) { bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr); + BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, + TRUE, BTA_SEC_NONE, UUID_SERVCLASS_AUDIO_SOURCE); } - BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, - TRUE, BTA_SEC_NONE); btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING); } break; @@ -339,6 +394,13 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data case BTIF_SM_EXIT_EVT: break; + case BTA_AV_REJECT_EVT: + BTIF_TRACE_DEBUG0(" Received BTA_AV_REJECT_EVT "); + HAL_CBACK(bt_av_callbacks, connection_state_cb, + BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE); + break; + case BTA_AV_OPEN_EVT: { tBTA_AV *p_bta_data = (tBTA_AV*)p_data; @@ -352,6 +414,11 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data state = BTAV_CONNECTION_STATE_CONNECTED; av_state = BTIF_AV_STATE_OPENED; btif_av_cb.edr = p_bta_data->open.edr; + + if (p_bta_data->open.sep == AVDT_TSEP_SRC) + btif_av_cb.sep = SEP_SRC; + else if (p_bta_data->open.sep == AVDT_TSEP_SNK) + btif_av_cb.sep = SEP_SNK; } else { @@ -366,9 +433,17 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data state, &(btif_av_cb.peer_bda)); /* change state to open/idle based on the status */ btif_sm_change_state(btif_av_cb.sm_handle, av_state); - /* if queued PLAY command, send it now */ - btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, + if (btif_av_cb.sep == SEP_SNK) + { + /* if queued PLAY command, send it now */ + btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, (p_bta_data->open.status == BTA_AV_SUCCESS)); + } + else if (btif_av_cb.sep == SEP_SRC) + { + /* if queued PLAY command, send it now */ + btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE); + } btif_queue_advance(); } break; @@ -403,19 +478,31 @@ static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data switch (event) { case BTIF_SM_ENTER_EVT: - - /* immediately stop transmission of frames */ - btif_a2dp_set_tx_flush(TRUE); - /* wait for audioflinger to stop a2dp */ + if (btif_av_cb.sep == SEP_SNK) + { + /* immediately stop transmission of frames */ + btif_a2dp_set_tx_flush(TRUE); + /* wait for audioflinger to stop a2dp */ + } + if (btif_av_cb.sep == SEP_SRC) + { + btif_a2dp_set_rx_flush(TRUE); + } break; case BTA_AV_STOP_EVT: case BTIF_AV_STOP_STREAM_REQ_EVT: + if (btif_av_cb.sep == SEP_SNK) + { /* immediately flush any pending tx frames while suspend is pending */ btif_a2dp_set_tx_flush(TRUE); + } + if (btif_av_cb.sep == SEP_SRC) + { + btif_a2dp_set_rx_flush(TRUE); + } - btif_a2dp_on_stopped(NULL); - + btif_a2dp_on_stopped(NULL); break; case BTIF_SM_EXIT_EVT: @@ -480,6 +567,12 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) break; case BTIF_AV_START_STREAM_REQ_EVT: + if (btif_av_cb.sep == SEP_SRC) + { + BTA_AvStart(); + btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START; + break; + } btif_a2dp_setup_codec(); BTA_AvStart(); btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START; @@ -493,19 +586,30 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE)) return TRUE; - if (btif_a2dp_on_started(&p_av->start, - ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0))) { - /* only clear pending flag after acknowledgement */ - btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START; + /* In case peer is A2DP SRC we do not want to ack commands on UIPC*/ + if (btif_av_cb.sep == SEP_SNK) + { + if (btif_a2dp_on_started(&p_av->start, + ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0))) + { + /* only clear pending flag after acknowledgement */ + btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START; + } } /* remain in open state if status failed */ if (p_av->start.status != BTA_AV_SUCCESS) return FALSE; + if (btif_av_cb.sep == SEP_SRC) + { + btif_a2dp_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/ + } + /* change state to started, send acknowledgement if start is pending */ if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) { - btif_a2dp_on_started(NULL, TRUE); + if (btif_av_cb.sep == SEP_SNK) + btif_a2dp_on_started(NULL, TRUE); /* pending start flag will be cleared when exit current state */ } btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED); @@ -521,8 +625,7 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) break; case BTA_AV_CLOSE_EVT: - - /* avdtp link is closed */ + /* avdtp link is closed */ btif_a2dp_on_stopped(NULL); /* inform the application that we are disconnected */ @@ -603,7 +706,8 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data case BTIF_AV_START_STREAM_REQ_EVT: /* we were remotely started, just ack back the local request */ - btif_a2dp_on_started(NULL, TRUE); + if (btif_av_cb.sep == SEP_SNK) + btif_a2dp_on_started(NULL, TRUE); break; /* fixme -- use suspend = true always to work around issue with BTA AV */ @@ -618,8 +722,14 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data always overrides */ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND; + if (btif_av_cb.sep == SEP_SNK) + { /* immediately stop transmission of frames while suspend is pending */ - btif_a2dp_set_tx_flush(TRUE); + btif_a2dp_set_tx_flush(TRUE); + } + + if (btif_av_cb.sep == SEP_SRC) + btif_a2dp_set_rx_flush(TRUE); BTA_AvStop(TRUE); break; @@ -650,8 +760,11 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data { btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING; + if (btif_av_cb.sep == SEP_SNK) + { /* suspend failed, reset back tx flush state */ - btif_a2dp_set_tx_flush(FALSE); + btif_a2dp_set_tx_flush(FALSE); + } return FALSE; } @@ -683,7 +796,6 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data case BTA_AV_STOP_EVT: btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP; - btif_a2dp_on_stopped(&p_av->suspend); HAL_CBACK(bt_av_callbacks, audio_state_cb, @@ -695,12 +807,16 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data break; + case BTIF_AV_REQUEST_AUDIO_FOCUS_EVT: + HAL_CBACK(bt_av_callbacks, audio_focus_request_cb, + 1, &(btif_av_cb.peer_bda)); + break; + case BTA_AV_CLOSE_EVT: btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP; /* avdtp link is closed */ - btif_a2dp_on_stopped(NULL); /* inform the application that we are disconnected */ @@ -737,6 +853,27 @@ static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data) (char*)p_data, sizeof(tBTA_AV), NULL); } +static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data) +{ + btif_sm_state_t state; + UINT8 que_len; + + if (event == BTA_AV_MEDIA_DATA_EVT)/* Switch to BTIF_MEDIA context */ + { + state= btif_sm_get_state(btif_av_cb.sm_handle); + if ( (state == BTIF_AV_STATE_STARTED) || /* send SBC packets only in Started State */ + (state == BTIF_AV_STATE_OPENED) ) + { + que_len = btif_media_sink_enque_buf((BT_HDR *)p_data); + BTIF_TRACE_DEBUG1(" Packets in Que %d",que_len); + } + else + return; + } + + if (event == BTA_AV_MEDIA_SINK_CFG_EVT) /* send a command to BT Media Task */ + btif_reset_decoder((UINT8*)p_data); +} /******************************************************************************* ** ** Function btif_av_init @@ -802,16 +939,27 @@ static bt_status_t init(btav_callbacks_t* callbacks ) ** *******************************************************************************/ -static bt_status_t connect_int(bt_bdaddr_t *bd_addr) +static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid) { + btif_av_connect_req_t connect_req; + connect_req.target_bda = bd_addr; + connect_req.uuid = uuid; BTIF_TRACE_EVENT1("%s", __FUNCTION__); - btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)bd_addr); + btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req); return BT_STATUS_SUCCESS; } -static bt_status_t connect(bt_bdaddr_t *bd_addr) +static bt_status_t connect_sink(bt_bdaddr_t *bd_addr) +{ + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + CHECK_BTAV_INIT(); + return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, bd_addr, + connect_int); +} + +static bt_status_t connect_src(bt_bdaddr_t *bd_addr) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); CHECK_BTAV_INIT(); @@ -866,12 +1014,110 @@ static void cleanup(void) return; } +/******************************************************************************* +** +** Function is_src +** +** Description Checks if peer device is A2DP SRC +** +** Returns Success in case peer is A2DP Src, FAIL otherwise +** +*******************************************************************************/ +bt_status_t is_src( bt_bdaddr_t *bd_addr ) +{ + BTIF_TRACE_DEBUG0(" isSrc: Check if peer device with bd_addr is audio src or sink"); + if (btif_av_cb.sep == SEP_SRC) + { + BTIF_TRACE_DEBUG0(" Current Peer is SRC"); + return BT_STATUS_SUCCESS; + } + else if (btif_av_cb.sep == SEP_SNK) + { + BTIF_TRACE_DEBUG0(" Current Peer is SNK"); + return BT_STATUS_FAIL; + } + else + { + BTIF_TRACE_DEBUG0(" Stream not opened till now"); + return BT_STATUS_NOT_READY; + } +} + +/******************************************************************************* +** +** Function activate_sink +** +** Description Activates/Deactivates A2DP Sink +** +** Returns None +** +*******************************************************************************/ +void activate_sink(int enable) +{ + BTIF_TRACE_DEBUG1(" Activate Sink %d", enable); + btif_dispatch_sm_event(BTIF_AV_REQUEST_ACTIVATE_SINK_EVT, (char*)&enable, sizeof(int)); +} + +/******************************************************************************* +** +** Function suspend_sink +** +** Description Suspends stream in case of A2DP Sink +** +** Returns None +** +*******************************************************************************/ +void suspend_sink() +{ + BTIF_TRACE_DEBUG0(" suspend Stream Suspend called"); + if (btif_av_cb.sep == SEP_SRC) + btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0); +} + +/******************************************************************************* +** +** Function resume_sink +** +** Description Resumes stream in case of A2DP Sink +** +** Returns None +** +*******************************************************************************/ +void resume_sink() +{ + BTIF_TRACE_DEBUG0(" resume Stream called"); + if (btif_av_cb.sep == SEP_SRC) + btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0); +} + +/******************************************************************************* +** +** Function audio_focus_status +** +** Description Updates audio focus state +** +** Returns None +** +*******************************************************************************/ +static void audio_focus_status(int state) +{ + BTIF_TRACE_DEBUG1(" Audio Focus granted %d",state); + + btif_a2dp_set_audio_focus_state(state); +} + static const btav_interface_t bt_av_interface = { sizeof(btav_interface_t), init, - connect, + connect_src, + connect_sink, disconnect, cleanup, + is_src, + suspend_sink, + resume_sink, + audio_focus_status, + activate_sink, }; /******************************************************************************* @@ -995,7 +1241,7 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable) BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD), bte_av_callback); #endif - BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0); + BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback); } else { BTA_AvDeregister(btif_av_cb.bta_handle); diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c index d2e835499..1b826ae53 100644 --- a/btif/src/btif_hf.c +++ b/btif/src/btif_hf.c @@ -675,7 +675,7 @@ static bt_status_t init( bthf_callbacks_t* callbacks, int max_hf_clients) ** Returns bt_status_t ** *******************************************************************************/ -static bt_status_t connect_int( bt_bdaddr_t *bd_addr ) +static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid) { CHECK_BTHF_INIT(); int i; diff --git a/btif/src/btif_hf_client.c b/btif/src/btif_hf_client.c index f1eb374ba..98a73d8ad 100644 --- a/btif/src/btif_hf_client.c +++ b/btif/src/btif_hf_client.c @@ -211,7 +211,7 @@ static bt_status_t init( bthf_client_callbacks_t* callbacks ) ** Returns bt_status_t ** *******************************************************************************/ -static bt_status_t connect_int( bt_bdaddr_t *bd_addr ) +static bt_status_t connect_int( bt_bdaddr_t *bd_addr, uint16_t uuid ) { if (is_connected(bd_addr)) return BT_STATUS_BUSY; diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c index 26bda41eb..aa2d3c8b0 100644 --- a/btif/src/btif_media_task.c +++ b/btif/src/btif_media_task.c @@ -66,12 +66,35 @@ #include "btif_av.h" #include "btif_sm.h" #include "btif_util.h" +#ifdef BTA_AVK_INCLUDED +#include "oi_codec_sbc.h" +#include "oi_status.h" +#endif +#include "stdio.h" +#include +#include "bluetoothTrack.h" + +//#define DEBUG_MEDIA_AV_FLOW TRUE + +#ifdef BTA_AVK_INCLUDED +OI_CODEC_SBC_DECODER_CONTEXT context; +OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)]; +OI_INT16 pcmData[15*SBC_MAX_SAMPLES_PER_FRAME*SBC_MAX_CHANNELS]; +void *dlhandle = NULL; +oi_sbc_decoder_vendor_interface_t *oi_sbc_decode_vnd_if = NULL; +#endif /***************************************************************************** ** Constants *****************************************************************************/ -//#define DEBUG_MEDIA_AV_FLOW TRUE +#ifndef AUDIO_CHANNEL_OUT_MONO +#define AUDIO_CHANNEL_OUT_MONO 0x01 +#endif + +#ifndef AUDIO_CHANNEL_OUT_STEREO +#define AUDIO_CHANNEL_OUT_STEREO 0x03 +#endif /* BTIF media task gki event definition */ #define BTIF_MEDIA_TASK_CMD TASK_MBOX_0_EVT_MASK @@ -81,8 +104,12 @@ #define BTIF_MEDIA_AA_TASK_TIMER_ID TIMER_0 #define BTIF_MEDIA_AV_TASK_TIMER_ID TIMER_1 +#define BTIF_MEDIA_AVK_TASK_TIMER_ID TIMER_2 + #define BTIF_MEDIA_AA_TASK_TIMER TIMER_0_EVT_MASK #define BTIF_MEDIA_AV_TASK_TIMER TIMER_1_EVT_MASK +#define BTIF_MEDIA_AVK_TASK_TIMER TIMER_2_EVT_MASK + #define BTIF_MEDIA_TASK_CMD_MBOX TASK_MBOX_0 /* cmd mailbox */ #define BTIF_MEDIA_TASK_DATA_MBOX TASK_MBOX_1 /* data mailbox */ @@ -102,7 +129,11 @@ enum BTIF_MEDIA_FLUSH_AA_TX, BTIF_MEDIA_FLUSH_AA_RX, BTIF_MEDIA_AUDIO_FEEDING_INIT, - BTIF_MEDIA_AUDIO_RECEIVING_INIT + BTIF_MEDIA_AUDIO_RECEIVING_INIT, + BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE, + BTIF_MEDIA_AUDIO_SINK_START_DECODING, + BTIF_MEDIA_AUDIO_SINK_STOP_DECODING, + BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK }; enum { @@ -121,6 +152,8 @@ enum { #define BTIF_MEDIA_TIME_TICK (20 * BTIF_MEDIA_NUM_TICK) #define A2DP_DATA_READ_POLL_MS (BTIF_MEDIA_TIME_TICK / 2) +#define BTIF_SINK_MEDIA_TIME_TICK (20 * BTIF_MEDIA_NUM_TICK) + /* buffer pool */ #define BTIF_MEDIA_AA_POOL_ID GKI_POOL_ID_3 @@ -183,6 +216,13 @@ static UINT32 a2dp_media_task_stack[(A2DP_MEDIA_TASK_STACK_SIZE + 3) / 4]; #define RESET_RATE_COUNTER_THRESHOLD_MS 2000 //#define BTIF_MEDIA_VERBOSE_ENABLED +/* In case of A2DP SINK, we will delay start by 5 AVDTP Packets*/ +#define MAX_A2DP_DELAYED_START_FRAME_COUNT 5 +#define PACKET_PLAYED_PER_TICK_48 8 +#define PACKET_PLAYED_PER_TICK_44 7 +#define PACKET_PLAYED_PER_TICK_32 5 +#define PACKET_PLAYED_PER_TICK_16 3 + #ifdef BTIF_MEDIA_VERBOSE_ENABLED #define VERBOSE(fmt, ...) \ @@ -195,6 +235,13 @@ static UINT32 a2dp_media_task_stack[(A2DP_MEDIA_TASK_STACK_SIZE + 3) / 4]; /***************************************************************************** ** Data types *****************************************************************************/ +typedef struct +{ + UINT16 num_frames_to_be_processed; + UINT16 len; + UINT16 offset; + UINT16 layer_specific; +} tBT_SBC_HDR; typedef struct { @@ -219,7 +266,9 @@ typedef struct { #if (BTA_AV_INCLUDED == TRUE) BUFFER_Q TxAaQ; + BUFFER_Q RxSbcQ; BOOLEAN is_tx_timer; + BOOLEAN is_rx_timer; UINT16 TxAaMtuSize; UINT32 timestamp; UINT8 TxTranscoding; @@ -231,6 +280,10 @@ typedef struct void* av_sm_hdl; UINT8 a2dp_cmd_pending; /* we can have max one command pending */ BOOLEAN tx_flush; /* discards any outgoing data when true */ + BOOLEAN rx_flush; /* discards any incoming data when true */ + BOOLEAN is_source; + UINT8 frames_to_process; + BOOLEAN rx_audio_focus_gained; #endif } tBTIF_MEDIA_CB; @@ -259,13 +312,24 @@ static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event); static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event); static void btif_a2dp_encoder_update(void); const char* dump_media_event(UINT16 event); +#ifdef BTA_AVK_INCLUDED +void btif_load_decoder_library(); +#endif +static void btif_media_flush_q(BUFFER_Q *p_q); +static void btif_media_task_aa_handle_stop_decoding(void ); +static void btif_media_task_aa_rx_flush(void); +static BOOLEAN btif_media_task_stop_decoding_req(void); /***************************************************************************** ** Externs *****************************************************************************/ static void btif_media_task_handle_cmd(BT_HDR *p_msg); -static void btif_media_task_handle_media(BT_HDR *p_msg); +static void btif_media_task_handle_media(BT_HDR*p_msg); +/* Handle incoming media packets A2DP SINK streaming*/ +#ifdef BTA_AVK_INCLUDED +static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg); +#endif #if (BTA_AV_INCLUDED == TRUE) static void btif_media_send_aa_frame(void); @@ -277,9 +341,15 @@ static void btif_media_task_enc_update(BT_HDR *p_msg); static void btif_media_task_audio_feeding_init(BT_HDR *p_msg); static void btif_media_task_aa_tx_flush(BT_HDR *p_msg); static void btif_media_aa_prep_2_send(UINT8 nb_frame); +#ifdef BTA_AVK_INCLUDED +static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg); +static void btif_media_task_aa_handle_clear_track(void); #endif - - +static void btif_media_task_aa_handle_start_decoding(void ); +#endif +extern void btif_av_request_audio_focus(BOOLEAN enable); +BOOLEAN btif_media_task_start_decoding_req(void); +BOOLEAN btif_media_task_clear_track(void); /***************************************************************************** ** Misc helper functions *****************************************************************************/ @@ -318,6 +388,10 @@ const char* dump_media_event(UINT16 event) CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_RX) CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_INIT) CASE_RETURN_STR(BTIF_MEDIA_AUDIO_RECEIVING_INIT) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_START_DECODING) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_STOP_DECODING) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK) default: return "UNKNOWN MEDIA EVENT"; @@ -381,7 +455,6 @@ static void btif_recv_ctrl_data(void) { UINT8 cmd = 0; int n; - n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &cmd, 1); /* detach on ctrl channel means audioflinger process was terminated */ @@ -779,11 +852,26 @@ void btif_a2dp_setup_codec(void) void btif_a2dp_on_idle(void) { APPL_TRACE_EVENT0("## ON A2DP IDLE ##"); - - /* Make sure media task is stopped */ - btif_media_task_stop_aa_req(); + if(btif_media_cb.is_source) + { + /* Make sure media task is stopped */ + btif_media_task_stop_aa_req(); + } bta_av_co_init(); +#ifdef BTA_AVK_INCLUDED + if (!btif_media_cb.is_source) + { + btif_media_cb.rx_flush = TRUE; + btif_media_task_aa_rx_flush_req(); + btif_media_task_stop_decoding_req(); + btif_media_task_clear_track(); + APPL_TRACE_DEBUG0("Stopped BT track"); + APPL_TRACE_DEBUG0("Reset to Source role"); + btif_media_cb.is_source = TRUE; + btif_media_cb.rx_audio_focus_gained = BTIF_MEDIA_AUDIOFOCUS_LOSS; + } +#endif } /***************************************************************************** @@ -804,6 +892,113 @@ void btif_a2dp_on_open(void) UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb); } +/******************************************************************************* + ** + ** Function btif_media_task_clear_track + ** + ** Description + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +BOOLEAN btif_media_task_clear_track(void) +{ + BT_HDR *p_buf; + + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + return FALSE; + } + + p_buf->event = BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK; + + GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); + return TRUE; +} +/******************************************************************************* + ** + ** Function btif_media_task_stop_decoding_req + ** + ** Description + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +BOOLEAN btif_media_task_stop_decoding_req(void) +{ + BT_HDR *p_buf; + + if (!btif_media_cb.is_rx_timer) + return TRUE; /* if timer is not running no need to send message */ + + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + return FALSE; + } + + p_buf->event = BTIF_MEDIA_AUDIO_SINK_STOP_DECODING; + + GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); + return TRUE; +} + +/******************************************************************************* + ** + ** Function btif_media_task_start_decoding_req + ** + ** Description + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +BOOLEAN btif_media_task_start_decoding_req(void) +{ + BT_HDR *p_buf; + + if(btif_media_cb.is_rx_timer) + return FALSE; /* if timer is already running no need to send message */ + + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + return FALSE; + } + + p_buf->event = BTIF_MEDIA_AUDIO_SINK_START_DECODING; + + GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); + return TRUE; +} + +/***************************************************************************** +** +** Function btif_reset_decoder +** +** Description +** +** Returns +** +*******************************************************************************/ + +void btif_reset_decoder(UINT8 *p_av) +{ + APPL_TRACE_EVENT0("btif_reset_decoder"); + APPL_TRACE_DEBUG6("btif_reset_decoder p_codec_info[%x:%x:%x:%x:%x:%x]", + p_av[1], p_av[2], p_av[3], + p_av[4], p_av[5], p_av[6]); + + tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf; + if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_SINK_CFG_UPDATE)))) + { + APPL_TRACE_EVENT0("btif_reset_decoder No Buffer "); + return; + } + + memcpy(p_buf->codec_info,p_av, AVDT_CODEC_SIZE); + p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE; + + GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); +} + /***************************************************************************** ** ** Function btif_a2dp_on_started @@ -889,7 +1084,13 @@ void btif_a2dp_ack_fail(void) void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av) { APPL_TRACE_EVENT0("## ON A2DP STOPPED ##"); - + if ((!btif_media_cb.is_source)) /* Handling for A2DP SINK cases*/ + { + btif_media_cb.rx_flush = TRUE; + btif_media_task_aa_rx_flush_req(); + btif_media_task_stop_decoding_req(); + return; + } /* allow using this api for other than suspend */ if (p_av != NULL) { @@ -927,6 +1128,13 @@ void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av) void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av) { APPL_TRACE_EVENT0("## ON A2DP SUSPENDED ##"); + if ((!btif_media_cb.is_source)) + { + btif_media_cb.rx_flush = TRUE; + btif_media_task_aa_rx_flush_req(); + btif_media_task_stop_decoding_req(); + return; + } /* check for status failures */ if (p_av->status != BTA_AV_SUCCESS) @@ -944,6 +1152,13 @@ void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av) btif_media_task_stop_aa_req(); } +/* when true media task discards any rx frames */ +void btif_a2dp_set_rx_flush(BOOLEAN enable) +{ + APPL_TRACE_EVENT1("## DROP RX %d ##", enable); + btif_media_cb.rx_flush = enable; +} + /* when true media task discards any tx frames */ void btif_a2dp_set_tx_flush(BOOLEAN enable) { @@ -951,6 +1166,94 @@ void btif_a2dp_set_tx_flush(BOOLEAN enable) btif_media_cb.tx_flush = enable; } +/* when true media task discards any rx frames */ +void btif_a2dp_set_audio_focus_state(btif_media_AudioFocus_state state) +{ + APPL_TRACE_EVENT1("## Audio_focus_state Rx %d ##", state); + btif_media_cb.rx_audio_focus_gained = state; +} + +#ifdef BTA_AVK_INCLUDED +/******************************************************************************* + ** + ** Function btif_media_task_avk_handle_timer + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btif_media_task_avk_handle_timer ( void ) +{ + UINT8 count; + tBT_SBC_HDR *p_msg; + int num_sbc_frames; + int num_frames_to_process; + + count = btif_media_cb.RxSbcQ.count; + if (0 == count) + { + APPL_TRACE_DEBUG0(" QUE EMPTY "); + } + else + { + if (btif_media_cb.rx_flush == TRUE) + { + btif_media_flush_q(&(btif_media_cb.RxSbcQ)); + return; + } + if (btif_media_cb.rx_audio_focus_gained == BTIF_MEDIA_AUDIOFOCUS_LOSS_TRANSIENT) + { + APPL_TRACE_DEBUG0("Received Transient Focus Loss, Ignoring"); + return; + } + + if (btif_media_cb.rx_audio_focus_gained == BTIF_MEDIA_AUDIOFOCUS_LOSS) + { + /* Send a Audio Focus Request */ + btif_av_request_audio_focus(TRUE); + return; + } + num_frames_to_process = btif_media_cb.frames_to_process; + APPL_TRACE_DEBUG0(" Process Frames + "); + + do + { + p_msg = (tBT_SBC_HDR *)GKI_getfirst(&(btif_media_cb.RxSbcQ)); + if (p_msg == NULL) + return; + num_sbc_frames = p_msg->num_frames_to_be_processed; /* num of frames in Que Packets */ + APPL_TRACE_DEBUG1(" Frames left in topmost packet %d", num_sbc_frames); + APPL_TRACE_DEBUG1(" Remaining frames to process in tick %d", num_frames_to_process); + APPL_TRACE_DEBUG1(" Num of Packets in Que %d", btif_media_cb.RxSbcQ.count); + + if ( num_sbc_frames > num_frames_to_process) /* Que Packet has more frames*/ + { + p_msg->num_frames_to_be_processed= num_frames_to_process; + btif_media_task_handle_inc_media(p_msg); + p_msg->num_frames_to_be_processed = num_sbc_frames - num_frames_to_process; + num_frames_to_process = 0; + break; + } + else /* Que packet has less frames */ + { + btif_media_task_handle_inc_media(p_msg); + p_msg = (tBT_SBC_HDR *)GKI_dequeue(&(btif_media_cb.RxSbcQ)); + if( p_msg == NULL ) + { + APPL_TRACE_ERROR0("Insufficient data in que "); + break; + } + num_frames_to_process = num_frames_to_process - p_msg->num_frames_to_be_processed; + GKI_freebuf(p_msg); + } + }while(num_frames_to_process > 0); + + APPL_TRACE_DEBUG0(" Process Frames - "); + } +} +#endif + /******************************************************************************* ** ** Function btif_media_task_aa_handle_timer @@ -1027,8 +1330,8 @@ void btif_media_task_init(void) #if (BTA_AV_INCLUDED == TRUE) UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb); #endif - - + btif_media_cb.is_source = TRUE; + APPL_TRACE_DEBUG0("Reset to Source role"); } /******************************************************************************* ** @@ -1075,6 +1378,7 @@ int btif_media_task(void *p) if (event & BTIF_MEDIA_TASK_DATA) { + VERBOSE("================= Received Media Packets %d ===============", event); /* Process all messages in the queue */ while ((p_msg = (BT_HDR *) GKI_read_mbox(BTIF_MEDIA_TASK_DATA_MBOX)) != NULL) { @@ -1088,6 +1392,15 @@ int btif_media_task(void *p) btif_media_task_aa_handle_timer(); } + if (event & BTIF_MEDIA_AVK_TASK_TIMER) + { +#ifdef BTA_AVK_INCLUDED + /* advance audio timer expiration for a2dp sink */ + btif_media_task_avk_handle_timer(); +#endif + } + + VERBOSE("=============== MEDIA TASK EVENT %d DONE ============", event); @@ -1146,7 +1459,7 @@ BOOLEAN btif_media_task_send_cmd_evt(UINT16 Evt) *******************************************************************************/ static void btif_media_flush_q(BUFFER_Q *p_q) { - while (GKI_IS_QUEUE_EMPTY(p_q) == FALSE) + while (GKI_queue_is_empty(p_q) == FALSE) { GKI_freebuf(GKI_dequeue(p_q)); } @@ -1191,6 +1504,25 @@ static void btif_media_task_handle_cmd(BT_HDR *p_msg) case BTIF_MEDIA_UIPC_RX_RDY: btif_media_task_aa_handle_uipc_rx_rdy(); break; + case BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE: +#ifdef BTA_AVK_INCLUDED + btif_media_task_aa_handle_decoder_reset(p_msg); +#endif + break; + case BTIF_MEDIA_AUDIO_SINK_START_DECODING: + btif_media_task_aa_handle_start_decoding(); + break; + case BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK: +#ifdef BTA_AVK_INCLUDED + btif_media_task_aa_handle_clear_track(); +#endif + break; + case BTIF_MEDIA_AUDIO_SINK_STOP_DECODING: + btif_media_task_aa_handle_stop_decoding(); + break; + case BTIF_MEDIA_FLUSH_AA_RX: + btif_media_task_aa_rx_flush(); + break; #endif default: APPL_TRACE_ERROR1("ERROR in btif_media_task_handle_cmd unknown event %d", p_msg->event); @@ -1199,25 +1531,68 @@ static void btif_media_task_handle_cmd(BT_HDR *p_msg) VERBOSE("btif_media_task_handle_cmd : %s DONE", dump_media_event(p_msg->event)); } +#ifdef BTA_AVK_INCLUDED /******************************************************************************* ** - ** Function btif_media_task_handle_media + ** Function btif_media_task_handle_inc_media ** ** Description ** ** Returns void ** *******************************************************************************/ -static void btif_media_task_handle_media(BT_HDR *p_msg) +static void btif_media_task_handle_inc_media(tBT_SBC_HDR*p_msg) { - APPL_TRACE_ERROR0("ERROR btif_media_task_handle_media: not in use"); - - GKI_freebuf(p_msg); -} - + UINT8 *sbc_start_frame = ((UINT8*)(p_msg + 1) + p_msg->offset + 1); + int count; + UINT32 pcmBytes, availPcmBytes; + OI_INT16 *pcmDataPointer = pcmData; /*Will be overwritten on next packet receipt*/ + OI_STATUS status; + int num_sbc_frames = p_msg->num_frames_to_be_processed; + UINT32 sbc_frame_len = p_msg->len - 1; + int retwriteAudioTrack = 0; + availPcmBytes = 2*sizeof(pcmData); + + if ((btif_media_cb.is_source) || (btif_media_cb.rx_flush)) + { + APPL_TRACE_DEBUG0(" State Changed happened in this tick "); + return; + } + APPL_TRACE_DEBUG2("Number of sbc frames %d, frame_len %d", num_sbc_frames, sbc_frame_len); + for(count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) + { + pcmBytes = availPcmBytes; + status = oi_sbc_decode_vnd_if->OI_CODEC_SBC_DecodeFrame(&context, (const OI_BYTE**)&sbc_start_frame, + &sbc_frame_len, pcmDataPointer, &pcmBytes); + if (!OI_SUCCESS(status)) { + APPL_TRACE_ERROR1("Decoding failure: %d\n", status); + break; + } + availPcmBytes -= pcmBytes; + pcmDataPointer += pcmBytes/2; + p_msg->offset += (p_msg->len - 1) - sbc_frame_len; + p_msg->len = sbc_frame_len + 1; + } + retwriteAudioTrack = btWriteData((void*)pcmData, (2*sizeof(pcmData) - availPcmBytes)); +} +#endif +/******************************************************************************* + ** + ** Function btif_media_task_handle_media + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btif_media_task_handle_media(BT_HDR*p_msg) +{ + APPL_TRACE_DEBUG0(" btif_media_task_handle_media "); + GKI_freebuf(p_msg); +} #if (BTA_AV_INCLUDED == TRUE) /******************************************************************************* ** @@ -1337,6 +1712,32 @@ BOOLEAN btif_media_task_stop_aa_req(void) GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); return TRUE; } +/******************************************************************************* + ** + ** Function btif_media_task_aa_rx_flush_req + ** + ** Description + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +BOOLEAN btif_media_task_aa_rx_flush_req(void) +{ + BT_HDR *p_buf; + + if (GKI_queue_is_empty(&(btif_media_cb.RxSbcQ))== TRUE) /* Que is already empty */ + return TRUE; + + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) + { + return FALSE; + } + + p_buf->event = BTIF_MEDIA_FLUSH_AA_RX; + + GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); + return TRUE; +} /******************************************************************************* ** @@ -1360,6 +1761,23 @@ BOOLEAN btif_media_task_aa_tx_flush_req(void) GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf); return TRUE; } +/******************************************************************************* + ** + ** Function btif_media_task_aa_rx_flush + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btif_media_task_aa_rx_flush(void) +{ + /* Flush all enqueued GKI SBC buffers (encoded) */ + APPL_TRACE_DEBUG0("btif_media_task_aa_rx_flush"); + + btif_media_flush_q(&(btif_media_cb.RxSbcQ)); +} + /******************************************************************************* ** @@ -1679,6 +2097,234 @@ static void btif_media_task_audio_feeding_init(BT_HDR *p_msg) } } +int a2dp_get_track_frequency(UINT8 frequency) { + int freq = 48000; + switch (frequency) { + case A2D_SBC_IE_SAMP_FREQ_16: + freq = 16000; + break; + case A2D_SBC_IE_SAMP_FREQ_32: + freq = 32000; + break; + case A2D_SBC_IE_SAMP_FREQ_44: + freq = 44100; + break; + case A2D_SBC_IE_SAMP_FREQ_48: + freq = 48000; + break; + } + return freq; +} + +int a2dp_get_track_channel_type(UINT8 channeltype) { + int channel = AUDIO_CHANNEL_OUT_MONO; + switch (channeltype) { + case A2D_SBC_IE_CH_MD_MONO: + channel = AUDIO_CHANNEL_OUT_MONO; + break; + case A2D_SBC_IE_CH_MD_DUAL: + case A2D_SBC_IE_CH_MD_STEREO: + case A2D_SBC_IE_CH_MD_JOINT: + channel = AUDIO_CHANNEL_OUT_STEREO; + break; + } + return channel; +} + +/******************************************************************************* + ** + ** Function btif_media_task_aa_handle_stop_decoding + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btif_media_task_aa_handle_stop_decoding(void ) +{ + btif_media_cb.is_rx_timer = FALSE; + GKI_stop_timer(BTIF_MEDIA_AVK_TASK_TIMER_ID); + btPauseTrack(); +} + +/******************************************************************************* + ** + ** Function btif_media_task_aa_handle_start_decoding + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btif_media_task_aa_handle_start_decoding(void ) +{ + if(btif_media_cb.is_rx_timer == TRUE) + return; + btStartTrack(); + btif_media_cb.is_rx_timer = TRUE; + GKI_start_timer(BTIF_MEDIA_AVK_TASK_TIMER_ID, GKI_MS_TO_TICKS(BTIF_SINK_MEDIA_TIME_TICK), TRUE); +} + +#ifdef BTA_AVK_INCLUDED + +static void btif_media_task_aa_handle_clear_track (void) +{ + APPL_TRACE_DEBUG0("btif_media_task_aa_handle_clear_track"); + btStopTrack(); + btDeleteTrack(); + if (dlhandle) + { + APPL_TRACE_DEBUG0("Unload Decoder lib"); + dlclose(dlhandle); + dlhandle = NULL; + oi_sbc_decode_vnd_if = NULL; + } +} + +/******************************************************************************* + ** + ** Function btif_media_task_aa_handle_decoder_reset + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg) +{ + tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf = (tBTIF_MEDIA_SINK_CFG_UPDATE*) p_msg; + tA2D_STATUS a2d_status; + tA2D_SBC_CIE sbc_cie; + OI_STATUS status; + UINT32 freq_multiple; /* frequency multiple for 20ms of data */ + UINT32 num_blocks; + UINT32 num_subbands; + UINT32 num_channel; + + APPL_TRACE_DEBUG6("btif_media_task_aa_handle_decoder_reset p_codec_info[%x:%x:%x:%x:%x:%x]", + p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3], + p_buf->codec_info[4], p_buf->codec_info[5], p_buf->codec_info[6]); + + a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_buf->codec_info, FALSE); + if (a2d_status != A2D_SUCCESS) + { + APPL_TRACE_ERROR1("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d", a2d_status); + return; + } + btif_media_cb.is_source = FALSE; + btif_media_cb.rx_flush = FALSE; + APPL_TRACE_DEBUG0("Reset to sink role"); + btif_load_decoder_library(); + status = oi_sbc_decode_vnd_if->OI_CODEC_SBC_DecoderReset(&context, contextData, sizeof(contextData), 2, 2, FALSE); + if (!OI_SUCCESS(status)) { + APPL_TRACE_ERROR1("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status); + } + APPL_TRACE_DEBUG0("A2dpSink: Crate Track"); + if (btCreateTrack(a2dp_get_track_frequency(sbc_cie.samp_freq), a2dp_get_track_channel_type(sbc_cie.ch_mode)) == -1) { + APPL_TRACE_ERROR0("A2dpSink: Track creation fails!!!"); + return; + } + + switch(sbc_cie.samp_freq) + { + case A2D_SBC_IE_SAMP_FREQ_16: + APPL_TRACE_DEBUG1("\tsamp_freq:%d (16000)", sbc_cie.samp_freq); + freq_multiple = 16*20; + break; + case A2D_SBC_IE_SAMP_FREQ_32: + APPL_TRACE_DEBUG1("\tsamp_freq:%d (32000)", sbc_cie.samp_freq); + freq_multiple = 32*20; + break; + case A2D_SBC_IE_SAMP_FREQ_44: + APPL_TRACE_DEBUG1("\tsamp_freq:%d (44100)", sbc_cie.samp_freq); + freq_multiple = 441*2; + break; + case A2D_SBC_IE_SAMP_FREQ_48: + APPL_TRACE_DEBUG1("\tsamp_freq:%d (48000)", sbc_cie.samp_freq); + freq_multiple = 48*20; + break; + default: + APPL_TRACE_DEBUG0(" Unknown Frequency "); + break; + } + + switch(sbc_cie.ch_mode) + { + case A2D_SBC_IE_CH_MD_MONO: + APPL_TRACE_DEBUG1("\tch_mode:%d (Mono)", sbc_cie.ch_mode); + break; + case A2D_SBC_IE_CH_MD_DUAL: + APPL_TRACE_DEBUG1("\tch_mode:%d (DUAL)", sbc_cie.ch_mode); + break; + case A2D_SBC_IE_CH_MD_STEREO: + APPL_TRACE_DEBUG1("\tch_mode:%d (STEREO)", sbc_cie.ch_mode); + break; + case A2D_SBC_IE_CH_MD_JOINT: + APPL_TRACE_DEBUG1("\tch_mode:%d (JOINT)", sbc_cie.ch_mode); + break; + default: + APPL_TRACE_DEBUG0(" Unknown Mode "); + break; + } + + switch(sbc_cie.block_len) + { + case A2D_SBC_IE_BLOCKS_4: + APPL_TRACE_DEBUG1("\tblock_len:%d (4)", sbc_cie.block_len); + num_blocks = 4; + break; + case A2D_SBC_IE_BLOCKS_8: + APPL_TRACE_DEBUG1("\tblock_len:%d (8)", sbc_cie.block_len); + num_blocks = 8; + break; + case A2D_SBC_IE_BLOCKS_12: + APPL_TRACE_DEBUG1("\tblock_len:%d (12)", sbc_cie.block_len); + num_blocks = 12; + break; + case A2D_SBC_IE_BLOCKS_16: + APPL_TRACE_DEBUG1("\tblock_len:%d (16)", sbc_cie.block_len); + num_blocks = 16; + break; + default: + APPL_TRACE_DEBUG0(" Unknown BlockLen "); + break; + } + + switch(sbc_cie.num_subbands) + { + case A2D_SBC_IE_SUBBAND_4: + APPL_TRACE_DEBUG1("\tnum_subbands:%d (4)", sbc_cie.num_subbands); + num_subbands = 4; + break; + case A2D_SBC_IE_SUBBAND_8: + APPL_TRACE_DEBUG1("\tnum_subbands:%d (8)", sbc_cie.num_subbands); + num_subbands = 8; + break; + default: + APPL_TRACE_DEBUG0(" Unknown SubBands "); + break; + } + + switch(sbc_cie.alloc_mthd) + { + case A2D_SBC_IE_ALLOC_MD_S: + APPL_TRACE_DEBUG1("\talloc_mthd:%d (SNR)", sbc_cie.alloc_mthd); + break; + case A2D_SBC_IE_ALLOC_MD_L: + APPL_TRACE_DEBUG1("\talloc_mthd:%d (Loudness)", sbc_cie.alloc_mthd); + break; + default: + APPL_TRACE_DEBUG0(" Unknown Allocation Method"); + break; + } + + APPL_TRACE_DEBUG2("\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool, sbc_cie.max_bitpool); + + btif_media_cb.frames_to_process = ((freq_multiple)/(num_blocks*num_subbands)) + 1; + APPL_TRACE_DEBUG1(" Frames to be processed in 20 ms %d",btif_media_cb.frames_to_process); +} +#endif + /******************************************************************************* ** ** Function btif_media_task_feeding_state_reset @@ -1826,6 +2472,49 @@ static UINT8 btif_get_num_aa_frame(void) /******************************************************************************* ** + ** Function btif_media_sink_enque_buf + ** + ** Description This function is called by the av_co to fill A2DP Sink Queue + ** + ** + ** Returns size of the queue + *******************************************************************************/ +UINT8 btif_media_sink_enque_buf(BT_HDR *p_pkt) +{ + tBT_SBC_HDR *p_msg; + + if(btif_media_cb.rx_flush == TRUE) /* Flush enabled, do not enque*/ + return btif_media_cb.RxSbcQ.count; + if(btif_media_cb.RxSbcQ.count == MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) + { + GKI_freebuf(GKI_dequeue(&(btif_media_cb.RxSbcQ))); + } + + BTIF_TRACE_VERBOSE0("btif_media_sink_enque_buf + "); + /* allocate and Queue this buffer */ + if ((p_msg = (tBT_SBC_HDR *) GKI_getbuf(sizeof(tBT_SBC_HDR) + + p_pkt->offset+ p_pkt->len)) != NULL) + { + memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len)); + p_msg->num_frames_to_be_processed = (*((UINT8*)(p_msg + 1) + p_msg->offset)) & 0x0f; + BTIF_TRACE_VERBOSE1("btif_media_sink_enque_buf + ", p_msg->num_frames_to_be_processed); + GKI_enqueue(&(btif_media_cb.RxSbcQ), p_msg); + if(btif_media_cb.RxSbcQ.count == MAX_A2DP_DELAYED_START_FRAME_COUNT) + { + BTIF_TRACE_DEBUG0(" Initiate Decoding "); + btif_media_task_start_decoding_req(); + } + } + else + { + /* let caller deal with a failed allocation */ + BTIF_TRACE_VERBOSE0("btif_media_sink_enque_buf No Buffer left - "); + } + return btif_media_cb.RxSbcQ.count; +} + +/******************************************************************************* + ** ** Function btif_media_aa_readbuf ** ** Description This function is called by the av_co to get the next buffer to send @@ -2280,3 +2969,23 @@ void dump_codec_info(unsigned char *p_codec) APPL_TRACE_DEBUG2("\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool, sbc_cie.max_bitpool); } + +#ifdef BTA_AVK_INCLUDED +void btif_load_decoder_library() +{ + dlhandle = dlopen("liboi_sbc_decoder.so", RTLD_NOW); + APPL_TRACE_DEBUG0("Load decoder library"); + if (!dlhandle) + { + APPL_TRACE_ERROR0("!!! Failed to load oi_sbc_decoder.so !!!"); + return; + } + + oi_sbc_decode_vnd_if = (oi_sbc_decoder_vendor_interface_t *) dlsym(dlhandle, "OI_SBC_DECODER_VENDOR_LIB_INTERFACE"); + if (!oi_sbc_decode_vnd_if) + { + APPL_TRACE_ERROR0("!!! Failed to get oi sbc decode vendor interface !!!"); + return; + } +} +#endif diff --git a/btif/src/btif_profile_queue.c b/btif/src/btif_profile_queue.c index b9bbe1708..12cec2e00 100644 --- a/btif/src/btif_profile_queue.c +++ b/btif/src/btif_profile_queue.c @@ -89,7 +89,7 @@ static bt_status_t queue_int_connect_next() { return BT_STATUS_SUCCESS; p_head->busy = true; - return p_head->connect_cb(&p_head->bda); + return p_head->connect_cb(&p_head->bda, p_head->uuid); } static void queue_int_handle_evt(UINT16 event, char *p_param) { diff --git a/include/bt_target.h b/include/bt_target.h index 7cccf3683..39bdd9fa8 100644 --- a/include/bt_target.h +++ b/include/bt_target.h @@ -167,6 +167,8 @@ #define BTA_GATT_INCLUDED TRUE #endif +/* defined BTA_AVK_INCLUDED in Android.mk file based on target selected*/ + #ifndef BTA_DISABLE_DELAY #define BTA_DISABLE_DELAY 200 /* in milliseconds */ #endif diff --git a/main/Android.mk b/main/Android.mk index 07afe1b38..7add8f73a 100644 --- a/main/Android.mk +++ b/main/Android.mk @@ -46,7 +46,8 @@ LOCAL_SRC_FILES += \ ../btif/src/btif_gatt_test.c \ ../btif/src/btif_config.c \ ../btif/src/btif_config_util.cpp \ - ../btif/src/btif_profile_queue.c + ../btif/src/btif_profile_queue.c \ + ../btif/src/bluetoothTrack.cpp # callouts LOCAL_SRC_FILES+= \ @@ -100,6 +101,7 @@ LOCAL_C_INCLUDES+= . \ $(LOCAL_PATH)/../audio_a2dp_hw \ $(LOCAL_PATH)/../utils/include \ $(bdroid_C_INCLUDES) \ + $(TOP)/frameworks/av/include/media \ external/tinyxml2 LOCAL_CFLAGS += -DBUILDCFG $(bdroid_CFLAGS) -Werror -Wno-error=maybe-uninitialized -Wno-error=uninitialized -Wno-error=unused-parameter diff --git a/stack/avdt/avdt_ad.c b/stack/avdt/avdt_ad.c index 7fe665cbf..5f9e60a85 100644 --- a/stack/avdt/avdt_ad.c +++ b/stack/avdt/avdt_ad.c @@ -482,7 +482,10 @@ void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf) avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf); } else + { GKI_freebuf(p_buf); + AVDT_TRACE_ERROR0(" avdt_ad_tc_data_ind buffer freed"); + } } } diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c index 855f17e4d..5e5ea2bd6 100644 --- a/stack/avdt/avdt_api.c +++ b/stack/avdt/avdt_api.c @@ -176,6 +176,68 @@ void AVDT_Deregister(void) /******************************************************************************* ** +** Function AVDT_SINK_Activate +** +** Description Activate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made false in case of activation. A2DP SRC +** will receive in_use as false and can open A2DP Sink +** connection +** +** Returns void. +** +*******************************************************************************/ +void AVDT_SINK_Activate() +{ + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + int i; + AVDT_TRACE_DEBUG0("AVDT_SINK_Activate"); + /* for all allocated scbs */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) + { + if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) + { + AVDT_TRACE_DEBUG0("AVDT_SINK_Activate found scb"); + p_scb->sink_activated = TRUE; + /* update in_use */ + p_scb->in_use = FALSE; + break; + } + } +} + +/******************************************************************************* +** +** Function AVDT_SINK_Deactivate +** +** Description Deactivate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made TRUE in case of activation. A2DP SRC +** will receive in_use as true and will not open A2DP Sink +** connection +** +** Returns void. +** +*******************************************************************************/ +void AVDT_SINK_Deactivate() +{ + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + int i; + AVDT_TRACE_DEBUG0("AVDT_SINK_Deactivate"); + /* for all allocated scbs */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) + { + if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) + { + AVDT_TRACE_DEBUG0("AVDT_SINK_Deactivate, found scb"); + p_scb->sink_activated = FALSE; + /* update in_use */ + p_scb->in_use = TRUE; + break; + } + } +} + +/******************************************************************************* +** ** Function AVDT_CreateStream ** ** Description Create a stream endpoint. After a stream endpoint is diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h index 04968a6d5..e9752c2c2 100644 --- a/stack/avdt/avdt_int.h +++ b/stack/avdt/avdt_int.h @@ -491,6 +491,7 @@ typedef struct { UINT16 media_seq; /* media packet sequence number */ BOOLEAN allocated; /* whether scb is allocated or unused */ BOOLEAN in_use; /* whether stream being used by peer */ + BOOLEAN sink_activated; /* A2DP Sink activated/de-activated from Application */ UINT8 role; /* initiator/acceptor role in current procedure */ BOOLEAN remove; /* whether CB is marked for removal */ UINT8 state; /* state machine state */ diff --git a/stack/avdt/avdt_scb.c b/stack/avdt/avdt_scb.c index d0c9e0fe2..f509240ca 100644 --- a/stack/avdt/avdt_scb.c +++ b/stack/avdt/avdt_scb.c @@ -601,6 +601,13 @@ tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs) memset(p_scb,0,sizeof(tAVDT_SCB)); p_scb->allocated = TRUE; p_scb->p_ccb = NULL; + + /* initialize sink as activated */ + if (p_cs->tsep == AVDT_TSEP_SNK) + { + p_scb->sink_activated = TRUE; + } + memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS)); #if AVDT_MULTIPLEXING == TRUE /* initialize fragments gueue */ diff --git a/stack/avdt/avdt_scb_act.c b/stack/avdt/avdt_scb_act.c index 8175b96aa..87cc61f4b 100644 --- a/stack/avdt/avdt_scb_act.c +++ b/stack/avdt/avdt_scb_act.c @@ -678,7 +678,7 @@ void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) UNUSED(p_scb); GKI_freebuf(p_data->p_pkt); - AVDT_TRACE_WARNING0("Dropped incoming media packet"); + AVDT_TRACE_ERROR0(" avdt_scb_drop_pkt Dropped incoming media packet"); } /******************************************************************************* @@ -826,7 +826,7 @@ void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) p_scb->peer_seid = p_data->msg.config_cmd.int_seid; memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG)); /* call app callback */ - (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, AVDT_CONFIG_IND_EVT, (tAVDT_CTRL *) &p_data->msg.config_cmd); @@ -2054,7 +2054,14 @@ void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) { UNUSED(p_data); - p_scb->in_use = FALSE; + if ((p_scb->cs.tsep == AVDT_TSEP_SNK) && (!p_scb->sink_activated)) + { + p_scb->in_use = TRUE; + } + else + { + p_scb->in_use = FALSE; + } p_scb->p_ccb = NULL; p_scb->peer_seid = 0; } diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h index beaecf61e..93ed6aebc 100644 --- a/stack/include/avdt_api.h +++ b/stack/include/avdt_api.h @@ -454,6 +454,35 @@ AVDT_API extern void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback); *******************************************************************************/ AVDT_API extern void AVDT_Deregister(void); + +/******************************************************************************* +** +** Function AVDT_SINK_Activate +** +** Description Activate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made false in case of activation. A2DP SRC +** will receive in_use as false and can open A2DP Sink +** connection +** +** Returns void +** +*******************************************************************************/ +AVDT_API extern void AVDT_SINK_Activate(void); + +/******************************************************************************* +** +** Function AVDT_SINK_Deactivate +** +** Description Deactivate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made TRUE in case of activation. A2DP SRC +** will receive in_use as true and will not open A2DP Sink +** connection +** +** Returns void. +** +*******************************************************************************/ +AVDT_API extern void AVDT_SINK_Deactivate(void); + /******************************************************************************* ** ** Function AVDT_CreateStream -- 2.11.0