Support for A2DP Sink and Proper initialization of profiles
- Register SDP and SEP (Stream End Point) for the profile
whose init is called. We achieve this by making registration
api aware of profile id being called.
- Register A2DP Src + Avrcp Target + Avrcp Controller. We need
to support Absolute Volume as well, so Avrcp Controller is
required here.
- Register A2DP Sink + Avrcp Controller. In this case we do not
support absolute volume. Support would be added in AVRCP
controller change
- Adapter property is updated with profile ID for which init is
called.This is required to make changes in btService for Profile
initialization
- Start listening for incoming AVRCP connection if we have
only AVRCP Controller
- Update default peer_features based on feature mask. In case
of incoming AVRCP connection, SDP will be done later.
In such a scenario default peer features sent to btif should
be based on features-set selected during initialization.
- Drop Control, Meta and Browse commands when TG is not up.
- Not to call AVRCP app callbacks when mentioned service is down.
- Close audio socket on suspend
A2DP Sink: Support for AudioTrack
- implemetation for audiotrack to take care of audio rendering
- support for audio focus state in bluedroid
Bluetooth: Support for Avrcp 1.3 Controller
- support for SDP registration
- support for sending vendor dependant commands
- support for abs vol
- support for receiving vendor dependant response
- serialization of connection and rc_features callback
Avrcp_Ctrl: handling of commands and events for AVRCP Controller
- support of parsing cmd and event pdus
- timeout handling
Change-Id: I1e8d49b087eff6301373e1e90e8d868f15847c34
diff --git a/bta/ar/bta_ar.c b/bta/ar/bta_ar.c
index d58fe7b..5b16b8f 100644
--- a/bta/ar/bta_ar.c
+++ b/bta/ar/bta_ar.c
@@ -243,7 +243,7 @@
**
******************************************************************************/
void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_name,
- UINT16 categories, tBTA_SYS_ID sys_id)
+ UINT16 categories, tBTA_SYS_ID sys_id, BOOLEAN browse_supported)
{
UINT8 mask = bta_ar_id (sys_id);
UINT8 temp[8], *p;
@@ -257,20 +257,23 @@
{
bta_ar_cb.tg_registered = mask;
bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
- AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle);
+ AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+ bta_ar_cb.sdp_tg_handle, browse_supported);
bta_sys_add_uuid(service_uuid);
}
/* only one TG is allowed (first-come, first-served).
* If sdp_tg_handle is non-0, ignore this request */
}
- else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL))
+ else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)||
+ (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL))
{
bta_ar_cb.ct_categories [mask - 1] = categories;
categories = bta_ar_cb.ct_categories[0]|bta_ar_cb.ct_categories[1];
if (bta_ar_cb.sdp_ct_handle == 0)
{
bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
- AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle);
+ AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+ bta_ar_cb.sdp_ct_handle, browse_supported);
bta_sys_add_uuid(service_uuid);
}
else
diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c
index d4e2e57..137767e 100644
--- a/bta/av/bta_av_aact.c
+++ b/bta/av/bta_av_aact.c
@@ -1311,9 +1311,13 @@
APPL_TRACE_DEBUG("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 != NULL)) {
+ tBTA_AV_MEDIA av_sink_codec_info;
+ memcpy(av_sink_codec_info.avk_config.bd_addr,p_scb->peer_addr,sizeof(BD_ADDR));
+ av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
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);
+ &av_sink_codec_info);
+ }
AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code,
@@ -1696,7 +1700,7 @@
}
}
p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0, p_scb->peer_addr,
- UUID_SERVCLASS_AUDIO_SOURCE);
+ UUID_SERVCLASS_AUDIO_SOURCE);
p_scb->num_disc_snks = num_snks;
p_scb->num_disc_srcs = 0;
@@ -1918,9 +1922,12 @@
if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) &&
(p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL))
{
- APPL_TRACE_DEBUG(" Configure Deoder for Sink Connection ");
+ APPL_TRACE_DEBUG("%s Configure Decoder for Sink Connection.", __func__);
+ tBTA_AV_MEDIA av_sink_codec_info;
+ memcpy(av_sink_codec_info.avk_config.bd_addr,p_scb->peer_addr,sizeof(BD_ADDR));
+ av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
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);
+ &av_sink_codec_info);
}
/* open the stream */
diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c
index 06e1de0..fad6e23 100644
--- a/bta/av/bta_av_act.c
+++ b/bta/av/bta_av_act.c
@@ -39,12 +39,16 @@
#include "osi/include/osi.h"
#include "utl.h"
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
#include "osi/include/log.h"
+#if (AVRC_CTLR_INCLUDED == TRUE)
+#include <cutils/properties.h>
+#endif
+
/*****************************************************************************
** Constants
*****************************************************************************/
@@ -102,23 +106,23 @@
UINT8 rc_handle; /* connected AVRCP handle */
p_scb = NULL;
- if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
{
- if(p_rcb->shdl)
+ if (p_rcb->shdl)
{
/* Validate array index*/
if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS)
{
p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
}
- if(p_scb)
+ if (p_scb)
{
APPL_TRACE_DEBUG("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d", p_rcb->shdl,
p_scb->rc_handle, p_rcb->handle);
- if(p_scb->rc_handle == p_rcb->handle)
+ if (p_scb->rc_handle == p_rcb->handle)
p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
/* just in case the RC timer is active
- if(bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+ if (bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */
bta_sys_stop_timer(&p_scb->timer);
}
}
@@ -126,7 +130,7 @@
APPL_TRACE_EVENT("bta_av_del_rc handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx);
rc_handle = p_rcb->handle;
- if(!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
+ if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) )
{
p_rcb->status = 0;
@@ -174,7 +178,7 @@
*******************************************************************************/
static void bta_av_del_sdp_rec(UINT32 *p_sdp_handle)
{
- if(*p_sdp_handle != 0)
+ if (*p_sdp_handle != 0)
{
SDP_DeleteRecord(*p_sdp_handle);
*p_sdp_handle = 0;
@@ -240,7 +244,7 @@
{
p_msg->hdr.event = msg_event;
p_msg->handle = handle;
- if(peer_addr)
+ if (peer_addr)
bdcpy(p_msg->peer_addr, peer_addr);
bta_sys_sendmsg(p_msg);
}
@@ -313,7 +317,7 @@
UINT8 rc_handle;
tBTA_AV_RCB *p_rcb;
- if(role == AVCT_INT)
+ if (role == AVCT_INT)
{
bda = p_scb->peer_addr;
status = BTA_AV_RC_ROLE_INT;
@@ -350,7 +354,7 @@
p_rcb->shdl = shdl;
p_rcb->lidx = lidx;
p_rcb->peer_features = 0;
- if(lidx == (BTA_AV_NUM_LINKS + 1))
+ if (lidx == (BTA_AV_NUM_LINKS + 1))
{
/* this LIDX is reserved for the AVRCP ACP connection */
p_cb->rc_acp_handle = p_rcb->handle;
@@ -464,10 +468,10 @@
for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
{
mask = 1 << xx; /* the used mask for this lcb */
- if((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr)))
+ if ((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr)))
{
p_lcb = &p_cb->lcb[xx];
- if(op == BTA_AV_LCB_FREE)
+ if (op == BTA_AV_LCB_FREE)
{
p_cb->conn_lcb &= ~mask; /* clear the connect mask */
APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
@@ -502,7 +506,7 @@
for(i=0; i<BTA_AV_NUM_STRS; i++)
{
p_scb = p_cb->p_scb[i];
- if(p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0)
+ if (p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0)
{
p_scb->rc_handle = p_data->rc_conn_chg.handle;
APPL_TRACE_DEBUG("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle);
@@ -545,7 +549,7 @@
i, shdl, p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
- if(!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx)
+ if (!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx)
{
/* no associated SCB -> connected to an RC only device
* update the index to the extra LCB */
@@ -568,11 +572,15 @@
rc_open.status = BTA_AV_SUCCESS;
APPL_TRACE_DEBUG("local features:x%x peer_features:x%x", p_cb->features,
rc_open.peer_features);
- if(rc_open.peer_features == 0)
+ if (rc_open.peer_features == 0)
{
/* we have not done SDP on peer RC capabilities.
- * peer must have initiated the RC connection */
- rc_open.peer_features = BTA_AV_FEAT_RCCT;
+ * peer must have initiated the RC connection
+ * We Don't have SDP records of Peer, so we by
+ * default will take values depending upon registered
+ * features */
+ if (p_cb->features & BTA_AV_FEAT_RCTG)
+ rc_open.peer_features |= BTA_AV_FEAT_RCCT;
bta_av_rc_disc(disc);
}
(*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open);
@@ -593,10 +601,10 @@
tBTA_AV_RCB *p_rcb;
if (p_cb->features & BTA_AV_FEAT_RCCT)
{
- if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+ if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
{
p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
- if(p_rcb->status & BTA_AV_RC_CONN_MASK)
+ if (p_rcb->status & BTA_AV_RC_CONN_MASK)
{
AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label,
&p_data->api_remote_cmd.msg);
@@ -620,7 +628,7 @@
if ( (p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) ==
(BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR))
{
- if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+ if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
{
p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
@@ -643,7 +651,7 @@
if ( (p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) ==
(BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR))
{
- if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
+ if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)
{
p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg);
@@ -868,7 +876,9 @@
tBTA_AV av;
BT_HDR *p_pkt = NULL;
tAVRC_MSG_VENDOR *p_vendor = &p_data->rc_msg.msg.vendor;
- BOOLEAN is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) || p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
+ BOOLEAN is_inquiry =
+ ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
+ p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
#if (AVRC_METADATA_INCLUDED == TRUE)
UINT8 ctype = 0;
tAVRC_RESPONSE rc_rsp;
@@ -878,13 +888,15 @@
if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU)
{
- /* if this is a pass thru command */
+ /* if this is a pass thru command */
if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) ||
(p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
(p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ)
)
{
- /* check if operation is supported */
+ /* check if operation is supported */
+ char avrcp_ct_support[PROPERTY_VALUE_MAX];
+ property_get("bluetooth.pts.avrcp_ct.support", avrcp_ct_support, "false");
if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR)
{
p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
@@ -895,9 +907,18 @@
p_data->rc_msg.msg.pass.p_pass_data, is_inquiry);
#endif
}
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ else if (((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_UP)||
+ (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_DOWN)) &&
+ !strcmp(avrcp_ct_support, "true"))
+ {
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_ACCEPT;
+ }
+#endif
else
{
- p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
+ p_data->rc_msg.msg.hdr.ctype =
+ bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
}
APPL_TRACE_DEBUG("ctype %d",p_data->rc_msg.msg.hdr.ctype)
@@ -919,7 +940,8 @@
}
}
/* else if this is a pass thru response */
- else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+ /* id response type is not impl, we have to release label */
+ else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL)
{
/* set up for callback */
evt = BTA_AV_REMOTE_RSP_EVT;
@@ -927,6 +949,19 @@
av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;
av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;
av.remote_rsp.label = p_data->rc_msg.label;
+
+ /* If this response is for vendor unique command */
+ if ((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) &&
+ (p_data->rc_msg.msg.pass.pass_len > 0))
+ {
+ av.remote_rsp.p_data = (UINT8*)osi_getbuf(p_data->rc_msg.msg.pass.pass_len);
+ if (av.remote_rsp.p_data != NULL)
+ {
+ APPL_TRACE_DEBUG("Vendor Unique data len = %d",p_data->rc_msg.msg.pass.pass_len);
+ memcpy(av.remote_rsp.p_data,p_data->rc_msg.msg.pass.p_pass_data,
+ p_data->rc_msg.msg.pass.pass_len);
+ }
+ }
}
/* must be a bad ctype -> reject*/
else
@@ -962,7 +997,7 @@
}
/* else if configured to support vendor specific and it's a response */
else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
- p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT)
+ p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL)
{
#if (AVRC_METADATA_INCLUDED == TRUE)
if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
@@ -980,7 +1015,7 @@
else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&
p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ)
{
- if(p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID)
+ if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID)
{
/* reject it */
p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
@@ -1027,20 +1062,20 @@
tBTA_AV_SCB *p_scb;
tBTA_AV_RCB *p_rcb;
- if(handle < BTA_AV_NUM_RCB)
+ if (handle < BTA_AV_NUM_RCB)
{
p_rcb = &p_cb->rcb[handle];
APPL_TRACE_DEBUG("bta_av_rc_close handle: %d, status=0x%x", p_rcb->handle, p_rcb->status);
- if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE)
{
- if(p_rcb->shdl)
+ if (p_rcb->shdl)
{
p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
- if(p_scb)
+ if (p_scb)
{
/* just in case the RC timer is active
- if(bta_av_cb.features & BTA_AV_FEAT_RCCT &&
+ if (bta_av_cb.features & BTA_AV_FEAT_RCCT &&
p_scb->chnl == BTA_AV_CHNL_AUDIO) */
bta_sys_stop_timer(&p_scb->timer);
}
@@ -1065,7 +1100,7 @@
/* find the SCB & stop the timer */
for(i=0; i<BTA_AV_NUM_STRS; i++)
{
- if(p_scb == bta_av_cb.p_scb[i])
+ if (p_scb == bta_av_cb.p_scb[i])
{
shdl = i+1;
break;
@@ -1181,12 +1216,12 @@
mask = BTA_AV_HNDL_TO_MSK(index);
p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND);
conn_msk = 1 << (index + 1);
- if(p_data->conn_chg.is_up)
+ if (p_data->conn_chg.is_up)
{
/* set the conned mask for this channel */
- if(p_scb)
+ if (p_scb)
{
- if(p_lcb)
+ if (p_lcb)
{
p_lcb->conn_msk |= conn_msk;
for (i=0; i<BTA_AV_NUM_RCB; i++)
@@ -1220,7 +1255,7 @@
APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
/* check if the AVRCP ACP channel is already connected */
- if(p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
+ if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
{
p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
APPL_TRACE_DEBUG("rc_acp is connected && conn_chg on same addr p_lcb_rc->conn_msk:x%x",
@@ -1276,20 +1311,20 @@
/* clear the conned mask for this channel */
p_cb->conn_audio &= ~mask;
p_cb->conn_video &= ~mask;
- if(p_scb)
+ if (p_scb)
{
/* the stream is closed.
* clear the peer address, so it would not mess up the AVRCP for the next round of operation */
bdcpy(p_scb->peer_addr, bd_addr_null);
- if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO)
{
- if(p_lcb)
+ if (p_lcb)
{
p_lcb->conn_msk &= ~conn_msk;
}
/* audio channel is down. make sure the INT channel is down */
/* just in case the RC timer is active
- if(p_cb->features & BTA_AV_FEAT_RCCT) */
+ if (p_cb->features & BTA_AV_FEAT_RCCT) */
{
bta_sys_stop_timer(&p_scb->timer);
}
@@ -1304,14 +1339,14 @@
APPL_TRACE_DEBUG("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
- if(bta_av_cb.rcb[i].shdl == index + 1)
+ if (bta_av_cb.rcb[i].shdl == index + 1)
{
bta_av_del_rc(&bta_av_cb.rcb[i]);
break;
}
}
- if(p_cb->conn_audio == 0 && p_cb->conn_video == 0)
+ if (p_cb->conn_audio == 0 && p_cb->conn_video == 0)
{
/* if both channels are not connected,
* close all RC channels */
@@ -1419,10 +1454,10 @@
tBTA_AV_LCB *p_lcb = NULL;
APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event);
- if(event == AVDT_CONNECT_IND_EVT)
+ if (event == AVDT_CONNECT_IND_EVT)
{
p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
- if(!p_lcb)
+ if (!p_lcb)
{
/* if the address does not have an LCB yet, alloc one */
for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
@@ -1431,7 +1466,7 @@
APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
/* look for a p_lcb with its p_scb registered */
- if((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
+ if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL))
{
p_lcb = &p_cb->lcb[xx];
p_lcb->lidx = xx + 1;
@@ -1486,7 +1521,7 @@
}
}
}
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
else if (event == BTA_AR_AVDT_CONN_EVT)
{
bta_sys_stop_timer(&bta_av_cb.sig_tmr);
@@ -1496,7 +1531,7 @@
{
/* disconnected. */
p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
- if(p_lcb && p_lcb->conn_msk)
+ if (p_lcb && p_lcb->conn_msk)
{
APPL_TRACE_DEBUG("conn_msk: 0x%x", p_lcb->conn_msk);
/* clean up ssm */
@@ -1538,11 +1573,11 @@
for(xx=0; xx<BTA_AV_NUM_LINKS; xx++)
{
mask = 1 << xx;
- if(mask & p_cb->conn_lcb)
+ if (mask & p_cb->conn_lcb)
{
/* this entry is used. check if it is connected */
p_lcb = &p_cb->lcb[xx];
- if(!p_lcb->conn_msk)
+ if (!p_lcb->conn_msk)
{
bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL);
bdcpy(pend.bd_addr, p_lcb->addr);
@@ -1664,7 +1699,8 @@
if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
{
/* get profile version (if failure, version parameter is not updated) */
- SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+ SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ &peer_rc_version);
APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version);
if (peer_rc_version >= AVRC_REV_1_3)
@@ -1690,6 +1726,80 @@
/*******************************************************************************
**
+** Function bta_avk_check_peer_features
+**
+** Description check supported features on the peer device from the SDP record
+** and return the feature mask
+**
+** Returns tBTA_AV_FEAT peer device feature mask
+**
+*******************************************************************************/
+tBTA_AV_FEAT bta_avk_check_peer_features (UINT16 service_uuid)
+{
+ tBTA_AV_FEAT peer_features = 0;
+ tBTA_AV_CB *p_cb = &bta_av_cb;
+
+ APPL_TRACE_DEBUG("%s service_uuid:x%x", __FUNCTION__, service_uuid);
+
+ /* loop through all records we found */
+ tSDP_DISC_REC *p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL);
+ while (p_rec)
+ {
+ APPL_TRACE_DEBUG("%s found Service record for x%x", __FUNCTION__, service_uuid);
+
+ if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL)
+ {
+ /* find peer features */
+ if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL))
+ {
+ peer_features |= BTA_AV_FEAT_RCCT;
+ }
+ if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL))
+ {
+ peer_features |= BTA_AV_FEAT_RCTG;
+ }
+ }
+
+ if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL)
+ {
+ /* get profile version (if failure, version parameter is not updated) */
+ UINT16 peer_rc_version = 0;
+ BOOLEAN val = SDP_FindProfileVersionInRec(
+ p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+ APPL_TRACE_DEBUG("%s peer_rc_version for TG 0x%x, profile_found %d",
+ __FUNCTION__, peer_rc_version, val);
+
+ if (peer_rc_version >= AVRC_REV_1_3)
+ peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+ /*
+ * Though Absolute Volume came after in 1.4 and above, but there are few devices
+ * in market which supports absolute Volume and they are still 1.3
+ * TO avoid IOT issuses with those devices, we check for 1.3 as minimum version
+ */
+ if (peer_rc_version >= AVRC_REV_1_3)
+ {
+ /* get supported categories */
+ tSDP_DISC_ATTR *p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr != NULL)
+ {
+ UINT16 categories = p_attr->attr_value.v.u16;
+ if (categories & AVRC_SUPF_CT_CAT2)
+ peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+ if (categories & AVRC_SUPF_CT_APP_SETTINGS)
+ peer_features |= (BTA_AV_FEAT_APP_SETTING);
+ }
+ }
+ }
+ /* get next record; if none found, we're done */
+ p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
+ }
+ APPL_TRACE_DEBUG("%s peer_features:x%x", __FUNCTION__, peer_features);
+ return peer_features;
+}
+
+/*******************************************************************************
+**
** Function bta_av_rc_disc_done
**
** Description Handle AVRCP service discovery results. If matching
@@ -1706,10 +1816,10 @@
tBTA_AV_RC_OPEN rc_open;
tBTA_AV_RC_FEAT rc_feat;
UINT8 rc_handle;
- tBTA_AV_FEAT peer_features; /* peer features mask */
+ tBTA_AV_FEAT peer_features = 0; /* peer features mask */
UNUSED(p_data);
- APPL_TRACE_DEBUG("bta_av_rc_disc_done disc:x%x", p_cb->disc);
+ APPL_TRACE_DEBUG("%s bta_av_rc_disc_done disc:x%x", __FUNCTION__, p_cb->disc);
if (!p_cb->disc)
{
return;
@@ -1728,7 +1838,9 @@
p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
}
if (p_scb)
+ {
rc_handle = p_scb->rc_handle;
+ }
else
{
p_cb->disc = 0;
@@ -1736,14 +1848,25 @@
}
}
- APPL_TRACE_DEBUG("rc_handle %d", rc_handle);
- /* check peer version and whether support CT and TG role */
- peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL);
- if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features&BTA_AV_FEAT_ADV_CTRL) == 0))
+ APPL_TRACE_DEBUG("%s rc_handle %d", __FUNCTION__, rc_handle);
+ if (p_cb->sdp_a2d_snk_handle)
{
- /* if we support advance control and peer does not, check their support on TG role
- * some implementation uses 1.3 on CT ans 1.4 on TG */
- peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ /* This is Sink + CT + TG(Abs Vol) */
+ peer_features = bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ if (BTA_AV_FEAT_ADV_CTRL & bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
+ peer_features |= (BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCCT);
+ }
+ else if (p_cb->sdp_a2d_handle)
+ {
+ /* check peer version and whether support CT and TG role */
+ peer_features = bta_av_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL);
+ if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) &&
+ ((peer_features & BTA_AV_FEAT_ADV_CTRL) == 0))
+ {
+ /* if we support advance control and peer does not, check their support on TG role
+ * some implementation uses 1.3 on CT ans 1.4 on TG */
+ peer_features |= bta_av_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ }
}
p_cb->disc = 0;
@@ -1761,7 +1884,7 @@
((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) )
{
p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
- if(p_lcb)
+ if (p_lcb)
{
rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
p_cb->rcb[rc_handle].peer_features = peer_features;
@@ -1773,7 +1896,7 @@
}
#endif
}
- else if(p_scb->use_rc)
+ else if (p_scb->use_rc)
{
/* can not find AVRC on peer device. report failure */
p_scb->use_rc = FALSE;
@@ -1789,6 +1912,17 @@
p_cb->rcb[rc_handle].peer_features = peer_features;
rc_feat.rc_handle = rc_handle;
rc_feat.peer_features = peer_features;
+ if (p_scb == NULL)
+ {
+ /*
+ * In case scb is not created by the time we are done with SDP
+ * we still need to send RC feature event. So we need to get BD
+ * from Message
+ */
+ bdcpy(rc_feat.peer_addr, p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr);
+ }
+ else
+ bdcpy(rc_feat.peer_addr, p_scb->peer_addr);
(*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat);
}
}
@@ -1820,28 +1954,28 @@
{
p_rcb = &p_cb->rcb[i];
APPL_TRACE_DEBUG("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i, p_rcb->handle, p_rcb->status);
- if(p_rcb->handle == p_msg->handle)
+ if (p_rcb->handle == p_msg->handle)
{
rc_close.rc_handle = i;
p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
p_rcb->peer_features = 0;
APPL_TRACE_DEBUG(" shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
- if(p_rcb->shdl)
+ if (p_rcb->shdl)
{
if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS)
{
p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
}
- if(p_scb)
+ if (p_scb)
{
bdcpy(rc_close.peer_addr, p_scb->peer_addr);
- if(p_scb->rc_handle == p_rcb->handle)
+ if (p_scb->rc_handle == p_rcb->handle)
p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
APPL_TRACE_DEBUG("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
}
p_rcb->shdl = 0;
}
- else if(p_rcb->lidx == (BTA_AV_NUM_LINKS + 1) )
+ else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1))
{
/* if the RCB uses the extra LCB, use the addr for event and clean it */
p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
@@ -1855,7 +1989,7 @@
}
p_rcb->lidx = 0;
- if((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)
+ if ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)
{
/* AVCT CCB is deallocated */
p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
@@ -1871,14 +2005,14 @@
bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
}
}
- else if((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
+ else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK))
{
/* at least one channel is still connected */
conn = TRUE;
}
}
- if(!conn)
+ if (!conn)
{
/* no AVRC channels are connected, go back to INIT state */
bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL);
@@ -1985,11 +2119,11 @@
/* find the stream control block */
p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
- if(p_scb)
+ if (p_scb)
{
APPL_TRACE_DEBUG("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
- if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO)
{
p_cb->reg_audio &= ~mask;
if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt)
@@ -2009,17 +2143,25 @@
}
/* remove the A2DP SDP record, if no more audio stream is left */
- if(!p_cb->reg_audio)
+ if (!p_cb->reg_audio)
{
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
#endif
- bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle);
- bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+ if (p_cb->sdp_a2d_handle)
+ {
+ bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle);
+ p_cb->sdp_a2d_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+ }
#if (BTA_AV_SINK_INCLUDED == TRUE)
- bta_av_del_sdp_rec(&p_cb->sdp_a2d_snk_handle);
- bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+ if (p_cb->sdp_a2d_snk_handle)
+ {
+ bta_av_del_sdp_rec(&p_cb->sdp_a2d_snk_handle);
+ p_cb->sdp_a2d_snk_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+ }
#endif
}
}
@@ -2041,9 +2183,9 @@
APPL_TRACE_DEBUG("audio 0x%x, video: 0x%x, disable:%d",
p_cb->reg_audio, p_cb->reg_video, p_cb->disabling);
/* if no stream control block is active */
- if((p_cb->reg_audio + p_cb->reg_video) == 0)
+ if ((p_cb->reg_audio + p_cb->reg_video) == 0)
{
-#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
+#if ( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
/* deregister from AVDT */
bta_ar_dereg_avdt(BTA_ID_AV);
@@ -2052,7 +2194,7 @@
bta_ar_dereg_avct(BTA_ID_AV);
#endif
- if(p_cb->disabling)
+ if (p_cb->disabling)
{
p_cb->disabling = FALSE;
bta_av_cb.features = 0;
diff --git a/bta/av/bta_av_api.c b/bta/av/bta_av_api.c
index 8686a90..932ee33 100644
--- a/bta/av/bta_av_api.c
+++ b/bta/av/bta_av_api.c
@@ -24,6 +24,8 @@
*
******************************************************************************/
+#include <assert.h>
+
#include "bt_target.h"
#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
@@ -110,7 +112,8 @@
** Returns void
**
*******************************************************************************/
-void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback)
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
+ tBTA_AV_DATA_CBACK *p_data_cback, UINT16 service_uuid)
{
tBTA_AV_API_REG *p_buf;
@@ -121,7 +124,9 @@
p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
if(p_service_name)
{
- BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN);
+ BCM_STRNCPY_S(
+ p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name,
+ BTA_SERVICE_NAME_LEN);
p_buf->p_service_name[BTA_SERVICE_NAME_LEN-1] = 0;
}
else
@@ -130,6 +135,7 @@
}
p_buf->app_id = app_id;
p_buf->p_app_data_cback = p_data_cback;
+ p_buf->service_uuid = service_uuid;
bta_sys_sendmsg(p_buf);
}
}
@@ -463,6 +469,32 @@
/*******************************************************************************
**
+** Function BTA_AvRemoteVendorUniqueCmd
+**
+** Description Send a remote control command with Vendor Unique rc_id. This function can only
+** be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_STATE key_state,
+ UINT8* p_msg, UINT8 buf_len)
+{
+ tBTA_AV_API_REMOTE_CMD *p_buf =
+ (tBTA_AV_API_REMOTE_CMD *) osi_getbuf(sizeof(tBTA_AV_API_REMOTE_CMD));
+ assert(p_buf);
+ p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.op_id = AVRC_ID_VENDOR;
+ p_buf->msg.state = key_state;
+ p_buf->msg.p_pass_data = p_msg;
+ p_buf->msg.pass_len = buf_len;
+ p_buf->label = label;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+**
** Function BTA_AvVendorCmd
**
** Description Send a vendor dependent remote control command. This
diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c
index 285e078..47b8795 100644
--- a/bta/av/bta_av_cfg.c
+++ b/bta/av/bta_av_cfg.c
@@ -40,7 +40,16 @@
};
/* AVRCP cupported categories */
+#if (AVRC_CTLR_INCLUDED == TRUE)
+#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_CAT2)
+#else
#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2)
+#endif
+
+#if (AVRC_CTLR_INCLUDED == TRUE)
+#define BTA_AVK_RC_SUPF_CT (AVRC_SUPF_CT_CAT1)
+#define BTA_AVK_RC_SUPF_TG (AVRC_SUPF_TG_CAT2)
+#endif
/* Added to modify
** 1. flush timeout
@@ -81,11 +90,22 @@
#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
#endif /* BTA_AV_NUM_RC_EVT_IDS */
+const UINT8 bta_avk_meta_caps_evt_ids[] = {
+#if AVRC_ADV_CTRL_INCLUDED == TRUE
+ AVRC_EVT_VOLUME_CHANGE,
+#endif
+};
+#ifndef BTA_AVK_NUM_RC_EVT_IDS
+#define BTA_AVK_NUM_RC_EVT_IDS (sizeof(bta_avk_meta_caps_evt_ids) / sizeof(bta_avk_meta_caps_evt_ids[0]))
+#endif /* BTA_AVK_NUM_RC_EVT_IDS */
+
+
/* the MTU for the AVRCP browsing channel */
#ifndef BTA_AV_MAX_RC_BR_MTU
#define BTA_AV_MAX_RC_BR_MTU 1008
#endif
+/* This configuration to be used when we are Src + TG + CT( only for abs vol) */
const tBTA_AV_CFG bta_av_cfg =
{
AVRC_CO_BROADCOM, /* AVRCP Company ID */
@@ -115,7 +135,37 @@
{0}, /* Default AVRCP target name */
};
-tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg;
+/* This configuration to be used when we are Sink + CT + TG( only for abs vol) */
+const tBTA_AV_CFG bta_avk_cfg =
+{
+ AVRC_CO_METADATA, /* AVRCP Company ID */
+#if AVRC_METADATA_INCLUDED == TRUE
+ 512, /* AVRCP MTU at L2CAP for control channel */
+#else
+ 48, /* AVRCP MTU at L2CAP for control channel */
+#endif
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+ BTA_AVK_RC_SUPF_CT, /* AVRCP controller categories */
+ BTA_AVK_RC_SUPF_TG, /* AVRCP target categories */
+ 672, /* AVDTP signaling channel MTU at L2CAP */
+ BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
+ bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
+ 6, /* AVDTP audio channel max data queue size */
+ BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */
+ 600, /* AVDTP video transport channel flush timeout */
+ FALSE, /* TRUE, to accept AVRC 1.3 group nevigation command */
+ 2, /* company id count in p_meta_co_ids */
+ BTA_AVK_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
+ BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */
+ bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */
+ bta_avk_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */
+ NULL, /* the action function table for VDP stream */
+ NULL, /* action function to register VDP */
+ {0}, /* Default AVRCP controller name */
+ {0}, /* Default AVRCP target name */
+};
+
+tBTA_AV_CFG *p_bta_av_cfg = NULL;
const UINT16 bta_av_rc_id[] =
{
diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h
index 2151209..d2c3cc1 100644
--- a/bta/av/bta_av_int.h
+++ b/bta/av/bta_av_int.h
@@ -212,6 +212,7 @@
char p_service_name[BTA_SERVICE_NAME_LEN+1];
UINT8 app_id;
tBTA_AV_DATA_CBACK *p_app_data_cback;
+ UINT16 service_uuid;
} tBTA_AV_API_REG;
@@ -617,6 +618,8 @@
/* config struct */
extern tBTA_AV_CFG *p_bta_av_cfg;
+extern const tBTA_AV_CFG bta_avk_cfg;
+extern const tBTA_AV_CFG bta_av_cfg;
/* rc id config struct */
extern UINT16 *p_bta_av_rc_id;
diff --git a/bta/av/bta_av_main.c b/bta/av/bta_av_main.c
index 7706252..8f6a5df 100644
--- a/bta/av/bta_av_main.c
+++ b/bta/av/bta_av_main.c
@@ -536,14 +536,23 @@
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));
registr.status = BTA_AV_FAIL_RESOURCES;
registr.app_id = p_data->api_reg.app_id;
registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
+
+ UINT16 profile_initialized = p_data->api_reg.service_uuid;
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ {
+ p_bta_av_cfg = (tBTA_AV_CFG *) &bta_avk_cfg;
+ }
+ else if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+ {
+ p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg;
+ }
+
do
{
p_scb = bta_av_alloc_scb(registr.chnl);
@@ -587,23 +596,23 @@
#endif
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL,
- p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV);
+ p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE));
#endif
}
/* Set the Capturing service class bit */
-#if (BTA_AV_SINK_INCLUDED == TRUE)
- cod.service = BTM_COD_SERVICE_CAPTURING | BTM_COD_SERVICE_RENDERING;
-#else
- cod.service = BTM_COD_SERVICE_CAPTURING;
-#endif
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+ cod.service = BTM_COD_SERVICE_CAPTURING;
+ else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ cod.service = BTM_COD_SERVICE_RENDERING;
utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
} /* if 1st channel */
/* get stream configuration and create stream */
/* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */
cs.cfg.num_codec = 1;
- cs.tsep = AVDT_TSEP_SRC;
+
/*
* memset of cs takes care setting call back pointers to null.
@@ -650,55 +659,64 @@
if(bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
- /* keep the configuration in the stream control block */
- memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
- while(index < BTA_AV_MAX_SEPS &&
- (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
- &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
{
-
-#if (BTA_AV_SINK_INCLUDED == TRUE)
- if(index == 1)
+ cs.tsep = AVDT_TSEP_SRC;
+ index = 0;
+ }
+ else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
{
cs.tsep = AVDT_TSEP_SNK;
cs.p_data_cback = bta_av_stream_data_cback;
+ index = 1;
}
- APPL_TRACE_DEBUG(" SEP Type = %d",cs.tsep);
-#endif
+
+ /* Initialize Handles to zero */
+ for (int xx=0; xx < BTA_AV_MAX_SEPS; xx++)
+ {
+ p_scb->seps[xx].av_handle = 0;
+ }
+
+ /* keep the configuration in the stream control block */
+ memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
+ if ((*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
+ &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
+ {
if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)
{
p_scb->seps[index].codec_type = codec_type;
-
-#if (BTA_AV_SINK_INCLUDED == TRUE)
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_DEBUG("audio[%d] av_handle: %d codec_type: %d",
- index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type);
- index++;
}
- else
- break;
}
if(!bta_av_cb.reg_audio)
{
- /* create the SDP records on the 1st audio channel */
- bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
- A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
- A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle);
- bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
-
+ bta_av_cb.sdp_a2d_handle = 0;
#if (BTA_AV_SINK_INCLUDED == TRUE)
- 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);
+ bta_av_cb.sdp_a2d_snk_handle = 0;
#endif
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+ {
+ /* create the SDP records on the 1st audio channel */
+ bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
+ A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
+ A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle);
+ bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ {
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+ 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);
+#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);
@@ -718,11 +736,12 @@
(UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
#endif
#endif
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
}
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
/* create an SDP record as AVRC CT. */
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
- p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV);
+ p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,(bta_av_cb.features & BTA_AV_FEAT_BROWSE));
#endif
}
}
diff --git a/bta/include/bta_ar_api.h b/bta/include/bta_ar_api.h
index b451cb4..f9c35ff 100644
--- a/bta/include/bta_ar_api.h
+++ b/bta/include/bta_ar_api.h
@@ -119,7 +119,8 @@
**
******************************************************************************/
extern void bta_ar_reg_avrc(UINT16 service_uuid, char *p_service_name,
- char *p_provider_name, UINT16 categories, tBTA_SYS_ID sys_id);
+ char *p_provider_name, UINT16 categories, tBTA_SYS_ID sys_id,
+ BOOLEAN browse_supported);
/******************************************************************************
**
diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h
index 8b92d30..04ba603 100644
--- a/bta/include/bta_av_api.h
+++ b/bta/include/bta_av_api.h
@@ -64,6 +64,7 @@
#define BTA_AV_FEAT_ADV_CTRL 0x0200 /* remote control Advanced Control command/response */
#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */
#define BTA_AV_FEAT_ACP_START 0x0800 /* start stream when 2nd SNK was accepted */
+#define BTA_AV_FEAT_APP_SETTING 0x2000 /* Player app setting support */
/* Internal features */
#define BTA_AV_FEAT_NO_SCO_SSPD 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */
@@ -363,6 +364,7 @@
{
UINT8 rc_handle;
tBTA_AV_FEAT peer_features;
+ BD_ADDR peer_addr;
} tBTA_AV_RC_FEAT;
/* data associated with BTA_AV_REMOTE_CMD_EVT */
@@ -452,11 +454,17 @@
tBTA_AV_STATUS status;
} tBTA_AV;
+typedef struct
+{
+ UINT8 *codec_info;
+ BD_ADDR bd_addr;;
+} tBTA_AVK_CONFIG;
+
/* union of data associated with AV Media callback */
typedef union
{
BT_HDR *p_data;
- UINT8 *codec_info;
+ tBTA_AVK_CONFIG avk_config;
} tBTA_AV_MEDIA;
@@ -562,7 +570,7 @@
**
*******************************************************************************/
void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name,
- UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback);
+ UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback, UINT16 service_uuid);
/*******************************************************************************
**
@@ -704,6 +712,20 @@
/*******************************************************************************
**
+** Function BTA_AvRemoteVendorUniqueCmd
+**
+** Description Send a remote control command with Vendor Unique rc_id.
+** This function can only be used if AV is enabled with
+** feature BTA_AV_FEAT_RCCT.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_STATE key_state,
+ UINT8* p_msg, UINT8 buf_len);
+
+/*******************************************************************************
+**
** Function BTA_AvVendorCmd
**
** Description Send a vendor dependent remote control command. This
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
index 75bfebf..273fb2f 100644
--- a/btif/include/btif_api.h
+++ b/btif/include/btif_api.h
@@ -30,6 +30,8 @@
#ifndef BTIF_API_H
#define BTIF_API_H
+#include <hardware/bluetooth.h>
+
#include "btif_common.h"
#include "btif_dm.h"
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
index 4b116ee..2f245ed 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -46,6 +46,8 @@
BTIF_AV_SUSPEND_STREAM_REQ_EVT,
BTIF_AV_SINK_CONFIG_REQ_EVT,
BTIF_AV_OFFLOAD_START_REQ_EVT,
+ BTIF_AV_SINK_FOCUS_REQ_EVT,
+ BTIF_AV_CLEANUP_REQ_EVT,
} btif_av_sm_event_t;
@@ -112,7 +114,7 @@
**
*******************************************************************************/
-bt_status_t btif_av_init(void);
+bt_status_t btif_av_init(int service_id);
/*******************************************************************************
**
@@ -142,6 +144,31 @@
BOOLEAN btif_av_is_peer_edr(void);
+#ifdef USE_AUDIO_TRACK
+/*******************************************************************************
+**
+** Function audio_focus_status
+**
+** Description Update Audio Focus State
+**
+** Returns None
+**
+*******************************************************************************/
+void audio_focus_status(int state);
+
+/*******************************************************************************
+**
+** Function btif_queue_focus_request
+**
+** Description This is used to move context to btif and
+** queue audio_focus_request
+**
+** Returns none
+**
+*******************************************************************************/
+void btif_queue_focus_request(void);
+#endif
+
/******************************************************************************
**
** Function btif_av_clear_remote_suspend_flag
diff --git a/btif/include/btif_avrcp_audio_track.h b/btif/include/btif_avrcp_audio_track.h
new file mode 100644
index 0000000..407732a
--- /dev/null
+++ b/btif/include/btif_avrcp_audio_track.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 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
+
+/**
+ * Implements an API to be used by A2DP to do streaming of music over a media
+ * stream. This API provides mechanism to create and control playback of the
+ * media stream depending on the data bits coming from the remote device. The
+ * media stream is played over the default audio media stream type and hence
+ * volume control is handled entirely by the Audio Manager (which is also the
+ * original motivation for this solution.
+ *
+ * TODO: Once the AudioManager provides support for patching audio sources with
+ * volume control we should deprecate this file.
+ */
+
+/**
+ * Creates an audio track object and returns a void handle. Use this handle to the
+ * following functions.
+ *
+ * The ownership of the handle is maintained by the caller of this API and it should eventually be
+ * deleted using BtifAvrcpAudioTrackDelete (see below).
+ */
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType);
+
+/**
+ * Starts the audio track.
+ */
+void BtifAvrcpAudioTrackStart(void *handle);
+
+/**
+ * Pauses the audio track.
+ */
+void BtifAvrcpAudioTrackPause(void *handle);
+
+/**
+ * Stop / Delete the audio track.
+ * Delete should usually be called stop.
+ */
+void BtifAvrcpAudioTrackStop(void *handle);
+void BtifAvrcpAudioTrackDelete(void *handle);
+
+/**
+ * Writes the audio track data to file.
+ *
+ * Used only for debugging.
+ */
+int BtifAvrcpAudioTrackWriteData(void *handle, void *audioBuffer, int bufferlen);
+
+#if defined (__cplusplus) || (cplusplus)
+}
+#endif
diff --git a/btif/include/btif_media.h b/btif/include/btif_media.h
index 9602d6a..2bf0e8d 100644
--- a/btif/include/btif_media.h
+++ b/btif/include/btif_media.h
@@ -99,6 +99,21 @@
} tBTIF_MEDIA_SINK_CFG_UPDATE;
#endif
+#ifdef USE_AUDIO_TRACK
+typedef enum {
+ BTIF_MEDIA_FOCUS_IDLE = 0,
+ BTIF_MEDIA_FOCUS_READY,
+ BTIF_MEDIA_FOCUS_REQUESTED,
+ BTIF_MEDIA_FOCUS_GRANTED
+} btif_media_audio_focus_state;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 focus_state;
+} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
+#endif
+
/*******************************************************************************
** Public functions
*******************************************************************************/
@@ -280,5 +295,7 @@
int btif_a2dp_get_track_frequency(UINT8 frequency);
int btif_a2dp_get_track_channel_count(UINT8 channeltype);
void btif_a2dp_set_peer_sep(UINT8 sep);
-
+#ifdef USE_AUDIO_TRACK
+void btif_a2dp_set_audio_focus_state(btif_media_audio_focus_state state);
+#endif
#endif
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c
index f8e7771..ff3c8c2 100644
--- a/btif/src/btif_av.c
+++ b/btif/src/btif_av.c
@@ -38,6 +38,7 @@
** Constants & Macros
******************************************************************************/
#define BTIF_AV_SERVICE_NAME "Advanced Audio"
+#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink"
#define BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS 2
@@ -83,6 +84,7 @@
{
int sample_rate;
int channel_count;
+ bt_bdaddr_t peer_bd;
} btif_av_sink_config_req_t;
/*****************************************************************************
@@ -140,6 +142,7 @@
*************************************************************************/
extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
+extern UINT8 btif_rc_get_connected_peer_handle(void);
extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp);
/*****************************************************************************
@@ -193,6 +196,9 @@
CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT)
CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
+#ifdef USE_AUDIO_TRACK
+ CASE_RETURN_STR(BTIF_AV_SINK_FOCUS_REQ_EVT)
+#endif
default: return "UNKNOWN_EVENT";
}
}
@@ -221,7 +227,10 @@
BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
/* In case of AVRCP connection request, we will initiate SRC connection */
connect_req.target_bda = (bt_bdaddr_t*)&peer_addr;
- connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+ if(bt_av_sink_callbacks != NULL)
+ connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
+ else if(bt_av_src_callbacks != NULL)
+ connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req);
}
else
@@ -300,8 +309,16 @@
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_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+ if (bt_av_src_callbacks != NULL)
+ {
+ BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
+ TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ if (bt_av_sink_callbacks != NULL)
+ {
+ BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
+ TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
+ }
}
btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
} break;
@@ -325,6 +342,72 @@
btif_rc_handler(event, p_data);
break;
+ /*
+ * In case Signalling channel is not down
+ * and remote started Streaming Procedure
+ * we have to handle config and open event in
+ * idle_state. We hit these scenarios while running
+ * PTS test case for AVRCP Controller
+ */
+ case BTIF_AV_SINK_CONFIG_REQ_EVT:
+ {
+ btif_av_sink_config_req_t req;
+ // copy to avoid alignment problems
+ memcpy(&req, p_data, sizeof(req));
+
+ BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
+ req.channel_count);
+ if (bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(req.peer_bd),
+ req.sample_rate, req.channel_count);
+ }
+ } break;
+
+ case BTA_AV_OPEN_EVT:
+ {
+ tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
+ btav_connection_state_t state;
+ btif_sm_state_t av_state;
+ BTIF_TRACE_DEBUG("status:%d, edr 0x%x",p_bta_data->open.status,
+ p_bta_data->open.edr);
+
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
+ {
+ state = BTAV_CONNECTION_STATE_CONNECTED;
+ av_state = BTIF_AV_STATE_OPENED;
+ btif_av_cb.edr = p_bta_data->open.edr;
+
+ btif_av_cb.peer_sep = p_bta_data->open.sep;
+ btif_a2dp_set_peer_sep(p_bta_data->open.sep);
+ }
+ else
+ {
+ BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
+ p_bta_data->open.status );
+ state = BTAV_CONNECTION_STATE_DISCONNECTED;
+ av_state = BTIF_AV_STATE_IDLE;
+ }
+
+ /* inform the application of the event */
+ btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+ /* change state to open/idle based on the status */
+ btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
+ (p_bta_data->open.status == BTA_AV_SUCCESS));
+ }
+ else if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
+ {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
+ /* Bring up AVRCP connection too */
+ BTA_AvOpenRc(btif_av_cb.bta_handle);
+ }
+ btif_queue_advance();
+ } break;
+
case BTA_AV_REMOTE_CMD_EVT:
case BTA_AV_VENDOR_CMD_EVT:
case BTA_AV_META_MSG_EVT:
@@ -408,6 +491,17 @@
{
BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
p_bta_data->open.status );
+ BD_ADDR peer_addr;
+ if ((btif_rc_get_connected_peer(peer_addr))
+ &&(!bdcmp(btif_av_cb.peer_bda.address, peer_addr)))
+ {
+ /*
+ * Disconnect AVRCP connection, if
+ * A2DP conneciton failed, for any reason
+ */
+ BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
+ BTA_AvCloseRc(btif_rc_get_connected_peer_handle());
+ }
state = BTAV_CONNECTION_STATE_DISCONNECTED;
av_state = BTIF_AV_STATE_IDLE;
}
@@ -650,6 +744,9 @@
if (btif_av_cb.peer_sep == AVDT_TSEP_SRC)
{
btif_a2dp_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/
+#ifdef USE_AUDIO_TRACK
+ audio_focus_status(BTIF_MEDIA_FOCUS_READY);
+#endif
}
/* change state to started, send acknowledgement if start is pending */
@@ -861,6 +958,13 @@
btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
break;
+#ifdef USE_AUDIO_TRACK
+ case BTIF_AV_SINK_FOCUS_REQ_EVT:
+ HAL_CBACK(bt_av_sink_callbacks, audio_focus_request_cb,
+ &(btif_av_cb.peer_bda));
+ break;
+#endif
+
case BTA_AV_STOP_EVT:
btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
@@ -913,8 +1017,17 @@
static void btif_av_handle_event(UINT16 event, char* p_param)
{
- btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
- btif_av_event_free_data(event, p_param);
+ switch(event)
+ {
+ case BTIF_AV_CLEANUP_REQ_EVT:
+ BTIF_TRACE_EVENT("%s: BTIF_AV_CLEANUP_REQ_EVT", __FUNCTION__);
+ btif_a2dp_stop_media_task();
+ break;
+
+ default:
+ btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
+ btif_av_event_free_data(event, p_param);
+ }
}
void btif_av_event_deep_copy(UINT16 event, char *p_dest, char *p_src)
@@ -1012,13 +1125,14 @@
if (event == BTA_AV_MEDIA_SINK_CFG_EVT) {
/* send a command to BT Media Task */
- btif_reset_decoder((UINT8*)p_data);
-
- a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE);
+ btif_reset_decoder((UINT8*)(p_data->avk_config.codec_info));
+ a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)(p_data->avk_config.codec_info), FALSE);
if (a2d_status == A2D_SUCCESS) {
/* Switch to BTIF context */
config_req.sample_rate = btif_a2dp_get_track_frequency(sbc_cie.samp_freq);
config_req.channel_count = btif_a2dp_get_track_channel_count(sbc_cie.ch_mode);
+ memcpy(&config_req.peer_bd,(UINT8*)(p_data->avk_config.bd_addr),
+ sizeof(config_req.peer_bd));
btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT,
(char*)&config_req, sizeof(config_req), NULL);
} else {
@@ -1036,22 +1150,19 @@
**
*******************************************************************************/
-bt_status_t btif_av_init()
+bt_status_t btif_av_init(int service_id)
{
if (btif_av_cb.sm_handle == NULL)
{
if (!btif_a2dp_start_media_task())
return BT_STATUS_FAIL;
+ btif_enable_service(service_id);
+
/* Also initialize the AV state machine */
btif_av_cb.sm_handle =
btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
- btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
-#if (BTA_AV_SINK_INCLUDED == TRUE)
- btif_enable_service(BTA_A2DP_SINK_SERVICE_ID);
-#endif
-
btif_a2dp_on_init();
}
@@ -1072,7 +1183,7 @@
{
BTIF_TRACE_EVENT("%s()", __func__);
- bt_status_t status = btif_av_init();
+ bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
if (status == BT_STATUS_SUCCESS)
bt_av_src_callbacks = callbacks;
@@ -1093,13 +1204,44 @@
{
BTIF_TRACE_EVENT("%s()", __func__);
- bt_status_t status = btif_av_init();
+ bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
if (status == BT_STATUS_SUCCESS)
bt_av_sink_callbacks = callbacks;
return status;
}
+#ifdef USE_AUDIO_TRACK
+/*******************************************************************************
+**
+** Function audio_focus_status
+**
+** Description Update Audio Focus State
+**
+** Returns None
+**
+*******************************************************************************/
+void audio_focus_status(int state)
+{
+ BTIF_TRACE_DEBUG("%s state %d ",__func__, state);
+ btif_a2dp_set_audio_focus_state(state);
+}
+
+/*******************************************************************************
+**
+** Function btif_queue_focus_request
+**
+** Description This is used to move context to btif and queue audio_focus_request
+**
+** Returns none
+**
+*******************************************************************************/
+void btif_queue_focus_request(void)
+{
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_FOCUS_REQ_EVT, NULL, 0, NULL);
+}
+#endif
+
/*******************************************************************************
**
** Function connect
@@ -1167,16 +1309,13 @@
** Returns None
**
*******************************************************************************/
-static void cleanup(void)
+static void cleanup(int service_uuid)
{
BTIF_TRACE_EVENT("%s", __FUNCTION__);
- btif_a2dp_stop_media_task();
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0, NULL);
- btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
-#if (BTA_AV_SINK_INCLUDED == TRUE)
- btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
-#endif
+ btif_disable_service(service_uuid);
/* Also shut down the AV state machine */
btif_sm_shutdown(btif_av_cb.sm_handle);
@@ -1190,7 +1329,7 @@
{
bt_av_src_callbacks = NULL;
if (bt_av_sink_callbacks == NULL)
- cleanup();
+ cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
}
}
@@ -1201,7 +1340,7 @@
{
bt_av_sink_callbacks = NULL;
if (bt_av_src_callbacks == NULL)
- cleanup();
+ cleanup(BTA_A2DP_SINK_SERVICE_ID);
}
}
@@ -1211,6 +1350,7 @@
src_connect_sink,
disconnect,
cleanup_src,
+ NULL,
};
static const btav_interface_t bt_av_sink_interface = {
@@ -1219,6 +1359,11 @@
sink_connect_src,
disconnect,
cleanup_sink,
+#ifdef USE_AUDIO_TRACK
+ audio_focus_status,
+#else
+ NULL,
+#endif
};
/*******************************************************************************
@@ -1330,19 +1475,23 @@
/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
* auto-suspend av streaming on AG events(SCO or Call). The suspend shall
* be initiated by the app/audioflinger layers */
+ /* Support for browsing for SDP record should work only if we enable BROWSE
+ * while registering. */
#if (AVRC_METADATA_INCLUDED == TRUE)
BTA_AvEnable(BTA_SEC_AUTHENTICATE,
BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
|BTA_AV_FEAT_RCCT
|BTA_AV_FEAT_ADV_CTRL
+ |BTA_AV_FEAT_BROWSE
#endif
,bte_av_callback);
#else
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, bte_av_media_callback);
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
+ UUID_SERVCLASS_AUDIO_SOURCE);
}
else {
BTA_AvDeregister(btif_av_cb.bta_handle);
@@ -1362,10 +1511,23 @@
*******************************************************************************/
bt_status_t btif_av_sink_execute_service(BOOLEAN b_enable)
{
-#if (BTA_AV_SINK_INCLUDED == TRUE)
- BTA_AvEnable_Sink(b_enable);
-#endif
- return BT_STATUS_SUCCESS;
+ if (b_enable)
+ {
+ /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_NO_SCO_SSPD|BTA_AV_FEAT_RCCT|
+ BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|
+ BTA_AV_FEAT_ADV_CTRL|BTA_AV_FEAT_RCTG,
+ bte_av_callback);
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0, bte_av_media_callback,
+ UUID_SERVCLASS_AUDIO_SINK);
+ }
+ else {
+ BTA_AvDeregister(btif_av_cb.bta_handle);
+ BTA_AvDisable();
+ }
+ return BT_STATUS_SUCCESS;
}
/*******************************************************************************
diff --git a/btif/src/btif_avrcp_audio_track.cpp b/btif/src/btif_avrcp_audio_track.cpp
new file mode 100644
index 0000000..222b6c9
--- /dev/null
+++ b/btif/src/btif_avrcp_audio_track.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+//#define LOG_NDEBUG 0
+#include "btif_avrcp_audio_track.h"
+
+#include <media/AudioTrack.h>
+#include <utils/StrongPointer.h>
+
+#include "osi/include/log.h"
+
+using namespace android;
+
+typedef struct {
+ android::sp<android::AudioTrack> track;
+} BtifAvrcpAudioTrack;
+
+//#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
+
+void *BtifAvrcpAudioTrackCreate(int trackFreq, int channelType)
+{
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d channel %d ",
+ __func__, trackFreq, channelType);
+ int ret = -1;
+ sp<android::AudioTrack> track =
+ 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);
+ assert(track != NULL);
+
+ BtifAvrcpAudioTrack *trackHolder = new BtifAvrcpAudioTrack;
+ assert(trackHolder);
+ trackHolder->track = track;
+
+ if (trackHolder->track->initCheck() != 0)
+ {
+ return nullptr;
+ }
+
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+ outputPcmSampleFile = fopen(outputFilename, "ab");
+#endif
+ trackHolder->track->setVolume(1, 1);
+ return (void *)trackHolder;
+}
+
+void BtifAvrcpAudioTrackStart(void *handle)
+{
+ BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ assert(trackHolder);
+ assert(trackHolder->track != NULL);
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ trackHolder->track->start();
+}
+
+void BtifAvrcpAudioTrackStop(void *handle)
+{
+ BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ trackHolder->track->stop();
+ }
+}
+
+void BtifAvrcpAudioTrackDelete(void *handle)
+{
+ BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ delete trackHolder;
+ }
+
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+ if (outputPcmSampleFile)
+ {
+ fclose(outputPcmSampleFile);
+ }
+ outputPcmSampleFile = NULL;
+#endif
+}
+
+void BtifAvrcpAudioTrackPause(void *handle)
+{
+ BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ trackHolder->track->pause();
+ trackHolder->track->flush();
+ }
+}
+
+int BtifAvrcpAudioTrackWriteData(void *handle, void *audioBuffer, int bufferlen)
+{
+ BtifAvrcpAudioTrack *trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ assert(trackHolder);
+ assert(trackHolder->track != NULL);
+ int retval = -1;
+#if (defined(DUMP_PCM_DATA) && (DUMP_PCM_DATA == TRUE))
+ if (outputPcmSampleFile)
+ {
+ fwrite ((audioBuffer), 1, (size_t)bufferlen, outputPcmSampleFile);
+ }
+#endif
+ retval = trackHolder->track->write(audioBuffer, (size_t)bufferlen);
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btWriteData len = %d ret = %d",
+ __func__, bufferlen, retval);
+ return retval;
+}
diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c
index 772bdce..2eefcb1 100644
--- a/btif/src/btif_media_task.c
+++ b/btif/src/btif_media_task.c
@@ -29,8 +29,6 @@
#define LOG_TAG "bt_btif_media"
#include <assert.h>
-#include <dlfcn.h>
-#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdint.h>
@@ -79,6 +77,10 @@
#include "oi_status.h"
#endif
+#ifdef USE_AUDIO_TRACK
+#include "btif_avrcp_audio_track.h"
+#endif
+
#if (BTA_AV_SINK_INCLUDED == TRUE)
OI_CODEC_SBC_DECODER_CONTEXT context;
OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
@@ -113,7 +115,8 @@
BTIF_MEDIA_AUDIO_FEEDING_INIT,
BTIF_MEDIA_AUDIO_RECEIVING_INIT,
BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE,
- BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK
+ BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK,
+ BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE
};
enum {
@@ -240,6 +243,10 @@
UINT32 sample_rate;
UINT8 channel_count;
+#ifdef USE_AUDIO_TRACK
+ btif_media_audio_focus_state rx_audio_focus_state;
+ void *audio_track;
+#endif
alarm_t *media_alarm;
alarm_t *decode_alarm;
#endif
@@ -352,6 +359,7 @@
CASE_RETURN_STR(BTIF_MEDIA_AUDIO_RECEIVING_INIT)
CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE)
CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK)
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE)
default:
return "UNKNOWN MEDIA EVENT";
@@ -855,6 +863,9 @@
btif_media_task_aa_rx_flush_req();
btif_media_task_aa_handle_stop_decoding();
btif_media_task_clear_track();
+#ifdef USE_AUDIO_TRACK
+ btif_media_cb.rx_audio_focus_state = BTIF_MEDIA_FOCUS_IDLE;
+#endif
APPL_TRACE_DEBUG("Stopped BT track");
}
#endif
@@ -1019,7 +1030,9 @@
btif_media_cb.rx_flush = TRUE;
btif_media_task_aa_rx_flush_req();
btif_media_task_aa_handle_stop_decoding();
+#ifndef USE_AUDIO_TRACK
UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+#endif
btif_media_cb.data_channel_open = FALSE;
return;
}
@@ -1065,6 +1078,9 @@
btif_media_cb.rx_flush = TRUE;
btif_media_task_aa_rx_flush_req();
btif_media_task_aa_handle_stop_decoding();
+#ifndef USE_AUDIO_TRACK
+ UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+#endif
return;
}
@@ -1130,6 +1146,23 @@
btif_media_cb.tx_flush = enable;
}
+#ifdef USE_AUDIO_TRACK
+void btif_a2dp_set_audio_focus_state(btif_media_audio_focus_state state)
+{
+ APPL_TRACE_EVENT("btif_a2dp_set_audio_focus_state");
+ tBTIF_MEDIA_SINK_FOCUS_UPDATE *p_buf;
+ if (NULL == (p_buf = osi_getbuf(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE))))
+ {
+ APPL_TRACE_EVENT("btif_a2dp_set_audio_focus_state No Buffer ");
+ return;
+ }
+
+ p_buf->focus_state = state;
+ p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE;
+ fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
+}
+#endif
+
#if (BTA_AV_SINK_INCLUDED == TRUE)
static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context)
{
@@ -1143,6 +1176,24 @@
}
else
{
+
+#ifdef USE_AUDIO_TRACK
+ switch(btif_media_cb.rx_audio_focus_state)
+ {
+ /* Don't Do anything in case of Idle, Requested */
+ case BTIF_MEDIA_FOCUS_REQUESTED:
+ case BTIF_MEDIA_FOCUS_IDLE:
+ return;
+ /* In case of Ready, request for focus and wait to move in granted */
+ case BTIF_MEDIA_FOCUS_READY:
+ btif_queue_focus_request();
+ btif_media_cb.rx_audio_focus_state = BTIF_MEDIA_FOCUS_REQUESTED;
+ return;
+ /* play only in this case */
+ case BTIF_MEDIA_FOCUS_GRANTED:
+ break;
+ }
+#endif
if (btif_media_cb.rx_flush == TRUE)
{
btif_media_flush_q(btif_media_cb.RxSbcQ);
@@ -1320,6 +1371,14 @@
case BTIF_MEDIA_UIPC_RX_RDY:
btif_media_task_aa_handle_uipc_rx_rdy();
break;
+#ifdef USE_AUDIO_TRACK
+ case BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE:
+ if(!btif_av_is_connected())
+ break;
+ btif_media_cb.rx_audio_focus_state = ((tBTIF_MEDIA_SINK_FOCUS_UPDATE *)p_msg)->focus_state;
+ APPL_TRACE_DEBUG("Setting focus state to %d ",btif_media_cb.rx_audio_focus_state);
+ break;
+#endif
case BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE:
#if (BTA_AV_SINK_INCLUDED == TRUE)
btif_media_task_aa_handle_decoder_reset(p_msg);
@@ -1360,19 +1419,23 @@
OI_STATUS status;
int num_sbc_frames = p_msg->num_frames_to_be_processed;
UINT32 sbc_frame_len = p_msg->len - 1;
- availPcmBytes = 2*sizeof(pcmData);
+ availPcmBytes = sizeof(pcmData);
if ((btif_media_cb.peer_sep == AVDT_TSEP_SNK) || (btif_media_cb.rx_flush))
{
APPL_TRACE_DEBUG(" State Changed happened in this tick ");
return;
}
-
+#ifndef USE_AUDIO_TRACK
// ignore data if no one is listening
if (!btif_media_cb.data_channel_open)
+ {
+ APPL_TRACE_ERROR("%s Channel not open, returning", __func__);
return;
-
- APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d", num_sbc_frames, sbc_frame_len);
+ }
+#endif
+ APPL_TRACE_DEBUG("%s Number of sbc frames %d, frame_len %d",
+ __func__, num_sbc_frames, sbc_frame_len);
for(count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++)
{
@@ -1391,7 +1454,12 @@
p_msg->len = sbc_frame_len + 1;
}
- UIPC_Send(UIPC_CH_ID_AV_AUDIO, 0, (UINT8 *)pcmData, (2*sizeof(pcmData) - availPcmBytes));
+#ifdef USE_AUDIO_TRACK
+ BtifAvrcpAudioTrackWriteData(
+ btif_media_cb.audio_track, (void*)pcmData, (sizeof(pcmData) - availPcmBytes));
+#else
+ UIPC_Send(UIPC_CH_ID_AV_AUDIO, 0, (UINT8 *)pcmData, (sizeof(pcmData) - availPcmBytes));
+#endif
}
#endif
@@ -1971,23 +2039,46 @@
return count;
}
+#ifdef USE_AUDIO_TRACK
+int a2dp_get_track_channel_type(UINT8 channeltype) {
+ int count = 1;
+ switch (channeltype) {
+ case A2D_SBC_IE_CH_MD_MONO:
+ count = 1;
+ break;
+ case A2D_SBC_IE_CH_MD_DUAL:
+ case A2D_SBC_IE_CH_MD_STEREO:
+ case A2D_SBC_IE_CH_MD_JOINT:
+ count = 3;
+ break;
+ }
+ return count;
+}
+#endif
+
void btif_a2dp_set_peer_sep(UINT8 sep) {
btif_media_cb.peer_sep = sep;
}
static void btif_decode_alarm_cb(UNUSED_ATTR void *context) {
- thread_post(worker_thread, btif_media_task_avk_handle_timer, NULL);
+ if(worker_thread != NULL)
+ thread_post(worker_thread, btif_media_task_avk_handle_timer, NULL);
}
static void btif_media_task_aa_handle_stop_decoding(void) {
alarm_free(btif_media_cb.decode_alarm);
btif_media_cb.decode_alarm = NULL;
+#ifdef USE_AUDIO_TRACK
+ BtifAvrcpAudioTrackPause(btif_media_cb.audio_track);
+#endif
}
static void btif_media_task_aa_handle_start_decoding(void) {
if (btif_media_cb.decode_alarm)
return;
-
+#ifdef USE_AUDIO_TRACK
+ BtifAvrcpAudioTrackStart(btif_media_cb.audio_track);
+#endif
btif_media_cb.decode_alarm = alarm_new();
if (!btif_media_cb.decode_alarm) {
LOG_ERROR(LOG_TAG, "%s unable to allocate decode alarm.", __func__);
@@ -2002,6 +2093,10 @@
static void btif_media_task_aa_handle_clear_track (void)
{
APPL_TRACE_DEBUG("btif_media_task_aa_handle_clear_track");
+#ifdef USE_AUDIO_TRACK
+ BtifAvrcpAudioTrackStop(btif_media_cb.audio_track);
+ BtifAvrcpAudioTrackDelete(btif_media_cb.audio_track);
+#endif
}
/*******************************************************************************
@@ -2044,7 +2139,18 @@
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
}
+#ifdef USE_AUDIO_TRACK
+ APPL_TRACE_DEBUG("%s A2dpSink: sbc Create Track", __func__);
+ btif_media_cb.audio_track =
+ BtifAvrcpAudioTrackCreate(btif_a2dp_get_track_frequency(sbc_cie.samp_freq),
+ a2dp_get_track_channel_type(sbc_cie.ch_mode));
+ if (btif_media_cb.audio_track == NULL) {
+ APPL_TRACE_ERROR("%s A2dpSink: Track creation fails!!!", __func__);
+ return;
+ }
+#else
UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+#endif
switch(sbc_cie.samp_freq)
{
@@ -2336,19 +2442,25 @@
return fixed_queue_length(btif_media_cb.RxSbcQ);
if (fixed_queue_length(btif_media_cb.RxSbcQ) == MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ)
{
+ UINT8 ret = fixed_queue_length(btif_media_cb.RxSbcQ);
osi_freebuf(fixed_queue_try_dequeue(btif_media_cb.RxSbcQ));
+ return ret;
}
- BTIF_TRACE_VERBOSE("btif_media_sink_enque_buf + ");
+ BTIF_TRACE_VERBOSE("%s +", __func__);
/* allocate and Queue this buffer */
if ((p_msg = (tBT_SBC_HDR *) osi_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_VERBOSE("btif_media_sink_enque_buf + ", p_msg->num_frames_to_be_processed);
+ memcpy((UINT8*)(p_msg + 1), (UINT8*)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+ p_msg->num_frames_to_be_processed = (*((UINT8*)(p_pkt + 1) + p_pkt->offset))& 0x0f;
+ p_msg->len = p_pkt->len;
+ p_msg->offset = 0;
+ p_msg->layer_specific = p_pkt->layer_specific;
+ BTIF_TRACE_VERBOSE("%s frames to process %d, len %d ",
+ __func__, p_msg->num_frames_to_be_processed,p_msg->len);
fixed_queue_enqueue(btif_media_cb.RxSbcQ, p_msg);
- if (fixed_queue_length(btif_media_cb.RxSbcQ) == MAX_A2DP_DELAYED_START_FRAME_COUNT)
+ if(fixed_queue_length(btif_media_cb.RxSbcQ) == MAX_A2DP_DELAYED_START_FRAME_COUNT)
{
BTIF_TRACE_DEBUG(" Initiate Decoding ");
btif_media_task_aa_handle_start_decoding();
diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
index 7462561..301bd11 100644
--- a/btif/src/btif_rc.c
+++ b/btif/src/btif_rc.c
@@ -1,20 +1,18 @@
-/******************************************************************************
+/*
+ * Copyright (C) 2015 The Android Open Source Project
*
- * Copyright (C) 2009-2012 Broadcom Corporation
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * 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
*
- * 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.
- *
- ******************************************************************************/
+ * 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.
+ */
/*****************************************************************************
*
@@ -45,7 +43,9 @@
#include "bt_common.h"
#include "device/include/interop.h"
#include "uinput.h"
-
+#include "osi/include/list.h"
+#include "btu.h"
+#define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL)
/*****************************************************************************
** Constants & Macros
******************************************************************************/
@@ -53,7 +53,7 @@
/* cod value for Headsets */
#define COD_AV_HEADSETS 0x0404
/* for AVRC 1.4 need to change this */
-#define MAX_RC_NOTIFICATIONS AVRC_EVT_APP_SETTING_CHANGE
+#define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
#define IDX_GET_PLAY_STATUS_RSP 0
#define IDX_LIST_APP_ATTR_RSP 1
@@ -71,7 +71,7 @@
#define CHECK_RC_CONNECTED \
BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__); \
- if(btif_rc_cb.rc_connected == FALSE) \
+ if (btif_rc_cb.rc_connected == FALSE) \
{ \
BTIF_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \
return BT_STATUS_NOT_READY; \
@@ -86,7 +86,7 @@
#define SEND_METAMSG_RSP(index, avrc_rsp) \
{ \
- if(btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \
+ if (btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \
{ \
BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \
return BT_STATUS_UNHANDLED; \
@@ -113,6 +113,61 @@
BOOLEAN is_rsp_pending;
} btif_rc_cmd_ctxt_t;
+/* 2 second timeout to get interim response */
+#define BTIF_TIMEOUT_RC_INTERIM_RSP 2
+#define BTIF_TIMEOUT_RC_STATUS_CMD 2
+#define BTIF_TIMEOUT_RC_CONTROL_CMD 2
+
+
+typedef enum
+{
+ eNOT_REGISTERED,
+ eREGISTERED,
+ eINTERIM
+} btif_rc_nfn_reg_status_t;
+
+typedef struct {
+ UINT8 event_id;
+ UINT8 label;
+ btif_rc_nfn_reg_status_t status;
+} btif_rc_supported_event_t;
+
+#define RC_TIMER_STATUS_CMD 0
+#define RC_TIMER_CONTROL_CMD 1
+#define RC_TIMER_PLAY_STATUS 2
+
+#define BTIF_RC_STS_TIMEOUT 0xFE
+typedef struct {
+ UINT8 label;
+ UINT8 pdu_id;
+} btif_rc_status_cmd_timer_t;
+
+typedef struct {
+ UINT8 label;
+ UINT8 pdu_id;
+} btif_rc_control_cmd_timer_t;
+
+typedef struct {
+ UINT8 timer_id;
+ union {
+ btif_rc_status_cmd_timer_t rc_status_cmd;
+ btif_rc_control_cmd_timer_t rc_control_cmd;
+ };
+ timer_entry_t tle;
+} btif_rc_timer_context_t;
+
+typedef struct {
+ BOOLEAN query_started;
+ UINT8 num_attrs;
+ UINT8 num_ext_attrs;
+
+ UINT8 attr_index;
+ UINT8 ext_attr_index;
+ UINT8 ext_val_index;
+ btrc_player_app_attr_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+ btrc_player_app_ext_attr_t ext_attrs[AVRC_MAX_APP_ATTR_SIZE];
+} btif_rc_player_app_settings_t;
+
/* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single struct */
typedef struct {
BOOLEAN rc_connected;
@@ -124,12 +179,19 @@
btif_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS];
unsigned int rc_volume;
uint8_t rc_vol_label;
+ list_t *rc_supported_event_list;
+ btif_rc_player_app_settings_t rc_app_settings;
+ timer_entry_t tle_rc_play_status;
+ BOOLEAN rc_features_processed;
+ UINT64 rc_playing_uid;
+ BOOLEAN rc_procedure_complete;
} btif_rc_cb_t;
typedef struct {
BOOLEAN in_use;
UINT8 lbl;
UINT8 handle;
+ timer_entry_t tle_txn;
} rc_transaction_t;
typedef struct
@@ -182,6 +244,36 @@
static void release_transaction(UINT8 label);
static rc_transaction_t* get_transaction_by_lbl(UINT8 label);
static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg);
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg);
+static void btif_rc_ctrl_upstreams_rsp_cmd(
+ UINT8 event, tAVRC_COMMAND *pavrc_cmd, UINT8 label);
+static void btif_rc_ctrl_upstreams_rsp_evt(
+ UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8* p_buf, UINT16 buf_len, UINT8 rsp_type);
+static void rc_ctrl_procedure_complete();
+static void rc_stop_play_status_timer ();
+static void register_for_event_notification (btif_rc_supported_event_t *p_event);
+static void rc_timeout_handler (UINT16 event, char* p_data);
+static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CAPS_RSP *p_rsp);
+static void handle_app_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_ATTR_RSP *p_rsp);
+static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_VALUES_RSP *p_rsp);
+static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp);
+static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp);
+static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp);
+static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_PLAY_STATUS_RSP *p_rsp);
+static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ELEM_ATTRS_RSP *p_rsp);
+static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_RSP *p_rsp);
+static bt_status_t get_play_status_cmd(void);
+static bt_status_t get_player_app_setting_attr_text_cmd (UINT8 *attrs, UINT8 num_attrs);
+static bt_status_t get_player_app_setting_value_text_cmd (UINT8 *vals, UINT8 num_vals);
+static bt_status_t register_notification_cmd (UINT8 label, UINT8 event_id, UINT32 event_value);
+static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids);
+static bt_status_t getcapabilities_cmd (uint8_t cap_id);
+static bt_status_t list_player_app_setting_attrib_cmd(void);
+static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id);
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids);
+#endif
static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label);
static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label);
@@ -324,8 +416,50 @@
}
}
-void handle_rc_features()
+#if (AVRC_CTLR_INCLUDED == TRUE)
+void rc_cleanup_sent_cmd (void *p_data)
{
+ BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+
+}
+
+void handle_rc_ctrl_features(BD_ADDR bd_addr)
+{
+ if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
+ ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
+ (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+ {
+ bt_bdaddr_t rc_addr;
+ int rc_features = 0;
+ bdcpy(rc_addr.address,bd_addr);
+
+ if ((btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)&&
+ (btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT))
+ {
+ rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+ }
+ if ((btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA)&&
+ (btif_rc_cb.rc_features & BTA_AV_FEAT_VENDOR)&&
+ (btif_rc_cb.rc_features_processed != TRUE))
+ {
+ rc_features |= BTRC_FEAT_METADATA;
+ /* Mark rc features processed to avoid repeating
+ * the AVRCP procedure every time on receiving this
+ * update.
+ */
+ btif_rc_cb.rc_features_processed = TRUE;
+ getcapabilities_cmd (AVRC_CAP_COMPANY_ID);
+ }
+ BTIF_TRACE_DEBUG("%s Update rc features to CTRL %d", __FUNCTION__, rc_features);
+ HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+ }
+}
+#endif
+
+void handle_rc_features(BD_ADDR bd_addr)
+{
+ if (bt_rc_callbacks != NULL)
+ {
btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
bt_bdaddr_t rc_addr;
bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
@@ -355,38 +489,39 @@
HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features)
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- BTIF_TRACE_DEBUG("Checking for feature flags in btif_rc_handler with label %d",
- btif_rc_cb.rc_vol_label);
+ BTIF_TRACE_DEBUG("%s Checking for feature flags in btif_rc_handler with label %d",
+ __FUNCTION__, btif_rc_cb.rc_vol_label);
// Register for volume change on connect
- if(btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL &&
+ if (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL &&
btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
{
rc_transaction_t *p_transaction=NULL;
bt_status_t status = BT_STATUS_NOT_READY;
- if(MAX_LABEL==btif_rc_cb.rc_vol_label)
+ if (MAX_LABEL==btif_rc_cb.rc_vol_label)
{
status=get_transaction(&p_transaction);
}
else
{
p_transaction=get_transaction_by_lbl(btif_rc_cb.rc_vol_label);
- if(NULL!=p_transaction)
+ if (NULL!=p_transaction)
{
- BTIF_TRACE_DEBUG("register_volumechange already in progress for label %d",
- btif_rc_cb.rc_vol_label);
+ BTIF_TRACE_DEBUG("%s register_volumechange already in progress for label %d",
+ __FUNCTION__, btif_rc_cb.rc_vol_label);
return;
}
else
status=get_transaction(&p_transaction);
}
- if(BT_STATUS_SUCCESS == status && NULL!=p_transaction)
+ if (BT_STATUS_SUCCESS == status && NULL!=p_transaction)
{
btif_rc_cb.rc_vol_label=p_transaction->lbl;
register_volumechange(btif_rc_cb.rc_vol_label);
}
}
#endif
+ }
}
/***************************************************************************
@@ -405,17 +540,17 @@
bt_bdaddr_t rc_addr;
#endif
- if(p_rc_open->status == BTA_AV_SUCCESS)
+ if (p_rc_open->status == BTA_AV_SUCCESS)
{
//check if already some RC is connected
if (btif_rc_cb.rc_connected)
{
- BTIF_TRACE_ERROR("Got RC OPEN in connected state, Connected RC: %d \
- and Current RC: %d", btif_rc_cb.rc_handle,p_rc_open->rc_handle );
+ BTIF_TRACE_ERROR("%s Got RC OPEN in connected state, Connected RC: %d \
+ and Current RC: %d", __FUNCTION__, btif_rc_cb.rc_handle,p_rc_open->rc_handle );
if ((btif_rc_cb.rc_handle != p_rc_open->rc_handle)
&& (bdcmp(btif_rc_cb.rc_addr, p_rc_open->peer_addr)))
{
- BTIF_TRACE_DEBUG("Got RC connected for some other handle");
+ BTIF_TRACE_DEBUG("%s Got RC connected for some other handle", __FUNCTION__);
BTA_AvCloseRc(p_rc_open->rc_handle);
return;
}
@@ -430,21 +565,35 @@
/* on locally initiated connection we will get remote features as part of connect */
if (btif_rc_cb.rc_features != 0)
- handle_rc_features();
-
- result = uinput_driver_check();
- if(result == BT_STATUS_SUCCESS)
+ handle_rc_features(btif_rc_cb.rc_addr);
+ if (bt_rc_callbacks)
{
- init_uinput();
- }
-#if (AVRC_CTLR_INCLUDED == TRUE)
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
- /* report connection state if device is AVRCP target */
- if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) {
- if (bt_rc_ctrl_callbacks != NULL) {
- HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &rc_addr);
+ result = uinput_driver_check();
+ if (result == BT_STATUS_SUCCESS)
+ {
+ init_uinput();
}
}
+ else
+ {
+ BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not initializing UInput",
+ __FUNCTION__);
+ }
+ BTIF_TRACE_DEBUG("%s handle_rc_connect features %d ",__FUNCTION__, btif_rc_cb.rc_features);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ btif_rc_cb.rc_playing_uid = RC_INVALID_TRACK_ID;
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ if (bt_rc_ctrl_callbacks != NULL)
+ {
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &rc_addr);
+ }
+ /* report connection state if remote device is AVRCP target */
+ if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)||
+ ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCCT)&&
+ (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)))
+ {
+ handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+ }
#endif
}
else
@@ -476,30 +625,51 @@
BTIF_TRACE_ERROR("Got disconnect of unknown device");
return;
}
-
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ features = btif_rc_cb.rc_features;
+ /* Clean up AVRCP procedure flags */
+ memset(&btif_rc_cb.rc_app_settings, 0,
+ sizeof(btif_rc_player_app_settings_t));
+ btif_rc_cb.rc_features_processed = FALSE;
+ btif_rc_cb.rc_procedure_complete = FALSE;
+ /* Check and stop play status timer */
+ if (btif_rc_cb.tle_rc_play_status.in_use == TRUE)
+ {
+ rc_stop_play_status_timer();
+ }
+ /* Check and clear the notification event list */
+ if (btif_rc_cb.rc_supported_event_list != NULL)
+ {
+ list_clear(btif_rc_cb.rc_supported_event_list);
+ btif_rc_cb.rc_supported_event_list = NULL;
+ }
+#endif
btif_rc_cb.rc_handle = 0;
btif_rc_cb.rc_connected = FALSE;
memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
memset(btif_rc_cb.rc_notif, 0, sizeof(btif_rc_cb.rc_notif));
-#if (AVRC_CTLR_INCLUDED == TRUE)
- features = btif_rc_cb.rc_features;
-#endif
+
btif_rc_cb.rc_features = 0;
btif_rc_cb.rc_vol_label=MAX_LABEL;
btif_rc_cb.rc_volume=MAX_VOLUME;
init_all_transactions();
- close_uinput();
-#if (AVRC_CTLR_INCLUDED == TRUE)
- bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
-#endif
+ if (bt_rc_callbacks != NULL)
+ {
+ close_uinput();
+ }
+ else
+ {
+ BTIF_TRACE_WARNING("%s Avrcp TG role not enabled, not closing UInput", __FUNCTION__);
+ }
+
memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
#if (AVRC_CTLR_INCLUDED == TRUE)
/* report connection state if device is AVRCP target */
- if (features & BTA_AV_FEAT_RCTG) {
- if (bt_rc_ctrl_callbacks != NULL) {
- HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr);
- }
- }
+ if (bt_rc_ctrl_callbacks != NULL)
+ {
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr);
+ }
#endif
}
@@ -539,6 +709,8 @@
btif_rc_cb.rc_pending_play = FALSE;
return;
}
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_VOL_UP)||(p_remote_cmd->rc_id == BTA_AV_RC_VOL_DOWN))
+ return; // this command is not to be sent to UINPUT, only needed for PTS
}
if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) && (!btif_av_stream_started_ready()))
@@ -562,7 +734,7 @@
* This fix is to interop with certain carkits which sends an automatic PLAY or PAUSE
* commands right after call ends
*/
- if((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&&
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&&
(btif_hf_call_terminated_recently() == TRUE) &&
(check_cod( (const bt_bdaddr_t*)&(btif_rc_cb.rc_addr), COD_AV_HEADSETS) != TRUE))
{
@@ -652,6 +824,53 @@
#endif
}
+/***************************************************************************
+ * Function handle_rc_vendorunique_rsp
+ *
+ * - Argument: tBTA_AV_REMOTE_RSP command response
+ *
+ * - Description: Remote control vendor unique response handler
+ *
+ ***************************************************************************/
+void handle_rc_vendorunique_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp)
+{
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ const char *status;
+ UINT8 vendor_id = 0;
+ if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ {
+ int key_state;
+ if (p_remote_rsp->key_state == AVRC_STATE_RELEASE)
+ {
+ status = "released";
+ key_state = 1;
+ }
+ else
+ {
+ status = "pressed";
+ key_state = 0;
+ }
+
+ if (p_remote_rsp->len > 0)
+ {
+ if (p_remote_rsp->len >= AVRC_PASS_THRU_GROUP_LEN)
+ vendor_id = p_remote_rsp->p_data[AVRC_PASS_THRU_GROUP_LEN -1];
+ osi_freebuf(p_remote_rsp->p_data);
+ }
+ BTIF_TRACE_DEBUG("%s: vendor_id=%d status=%s", __FUNCTION__, vendor_id, status);
+
+ release_transaction(p_remote_rsp->label);
+ HAL_CBACK(bt_rc_ctrl_callbacks, groupnavigation_rsp_cb, vendor_id, key_state);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s Remote does not support AVRCP TG role", __FUNCTION__);
+ }
+#else
+ BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __FUNCTION__);
+#endif
+}
+
void handle_uid_changed_notification(tBTA_AV_META_MSG *pmeta_msg, tAVRC_COMMAND *pavrc_command)
{
tAVRC_RESPONSE avrc_rsp = {0};
@@ -703,7 +922,7 @@
{
rc_transaction_t *transaction=NULL;
transaction=get_transaction_by_lbl(pmeta_msg->label);
- if(NULL!=transaction)
+ if (NULL!=transaction)
{
handle_rc_metamsg_rsp(pmeta_msg);
}
@@ -724,8 +943,8 @@
}
status=AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf));
- BTIF_TRACE_DEBUG("Received vendor command.code,PDU and label: %d, %d,%d",pmeta_msg->code,
- avrc_command.cmd.pdu, pmeta_msg->label);
+ BTIF_TRACE_DEBUG("%s Received vendor command.code,PDU and label: %d, %d,%d",
+ __FUNCTION__, pmeta_msg->code, avrc_command.cmd.pdu, pmeta_msg->label);
if (status != AVRC_STS_NO_ERROR)
{
@@ -746,7 +965,7 @@
btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE;
btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label;
- if(event_id == AVRC_EVT_UIDS_CHANGE)
+ if (event_id == AVRC_EVT_UIDS_CHANGE)
{
handle_uid_changed_notification(pmeta_msg, &avrc_command);
return;
@@ -779,7 +998,7 @@
{
case BTA_AV_RC_OPEN_EVT:
{
- BTIF_TRACE_DEBUG("Peer_features:%x", p_data->rc_open.peer_features);
+ BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_open.peer_features);
handle_rc_connect( &(p_data->rc_open) );
}break;
@@ -790,39 +1009,115 @@
case BTA_AV_REMOTE_CMD_EVT:
{
- BTIF_TRACE_DEBUG("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
+ if (bt_rc_callbacks != NULL)
+ {
+ BTIF_TRACE_DEBUG("%s rc_id:0x%x key_state:%d",
+ __FUNCTION__, p_data->remote_cmd.rc_id,
p_data->remote_cmd.key_state);
- handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
+ /** In race conditions just after 2nd AVRCP is connected
+ * remote might send pass through commands, so check for
+ * Rc handle before processing pass through commands
+ **/
+ if (btif_rc_cb.rc_handle == p_data->remote_cmd.rc_handle)
+ {
+ handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s Pass-through command for Invalid rc handle", __FUNCTION__);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("AVRCP TG role not up, drop passthrough commands");
+ }
}
break;
+
#if (AVRC_CTLR_INCLUDED == TRUE)
case BTA_AV_REMOTE_RSP_EVT:
{
- BTIF_TRACE_DEBUG("RSP: rc_id:0x%x key_state:%d", p_data->remote_rsp.rc_id,
- p_data->remote_rsp.key_state);
- handle_rc_passthrough_rsp( (&p_data->remote_rsp) );
+ BTIF_TRACE_DEBUG("%s %s RSP: rc_id:0x%x key_state:%d",
+ __FUNCTION__, p_data->remote_rsp.rc_id, p_data->remote_rsp.key_state);
+ if (p_data->remote_rsp.rc_id == AVRC_ID_VENDOR)
+ {
+ handle_rc_vendorunique_rsp(&p_data->remote_rsp);
+ }
+ else
+ {
+ handle_rc_passthrough_rsp(&p_data->remote_rsp);
+ }
}
break;
+
#endif
case BTA_AV_RC_FEAT_EVT:
{
- BTIF_TRACE_DEBUG("Peer_features:%x", p_data->rc_feat.peer_features);
+ BTIF_TRACE_DEBUG("%s Peer_features:%x", __FUNCTION__, p_data->rc_feat.peer_features);
btif_rc_cb.rc_features = p_data->rc_feat.peer_features;
- handle_rc_features();
+ handle_rc_features(p_data->rc_feat.peer_addr);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ if ((btif_rc_cb.rc_connected) && (bt_rc_ctrl_callbacks != NULL))
+ {
+ handle_rc_ctrl_features(btif_rc_cb.rc_addr);
+ }
+#endif
}
break;
+
case BTA_AV_META_MSG_EVT:
{
- BTIF_TRACE_DEBUG("BTA_AV_META_MSG_EVT code:%d label:%d", p_data->meta_msg.code,
- p_data->meta_msg.label);
- BTIF_TRACE_DEBUG(" company_id:0x%x len:%d handle:%d", p_data->meta_msg.company_id,
- p_data->meta_msg.len, p_data->meta_msg.rc_handle);
- /* handle the metamsg command */
- handle_rc_metamsg_cmd(&(p_data->meta_msg));
+ if (bt_rc_callbacks != NULL)
+ {
+ BTIF_TRACE_DEBUG("%s BTA_AV_META_MSG_EVT code:%d label:%d",
+ __FUNCTION__,
+ p_data->meta_msg.code,
+ p_data->meta_msg.label);
+ BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d",
+ __FUNCTION__,
+ p_data->meta_msg.company_id,
+ p_data->meta_msg.len,
+ p_data->meta_msg.rc_handle);
+ /* handle the metamsg command */
+ handle_rc_metamsg_cmd(&(p_data->meta_msg));
+ /* Free the Memory allocated for tAVRC_MSG */
+ }
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ else if ((bt_rc_callbacks == NULL)&&(bt_rc_ctrl_callbacks != NULL))
+ {
+ /* This is case of Sink + CT + TG(for abs vol)) */
+ BTIF_TRACE_DEBUG("%s BTA_AV_META_MSG_EVT code:%d label:%d",
+ __FUNCTION__,
+ p_data->meta_msg.code,
+ p_data->meta_msg.label);
+ BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d",
+ __FUNCTION__,
+ p_data->meta_msg.company_id,
+ p_data->meta_msg.len,
+ p_data->meta_msg.rc_handle);
+ if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL)&&
+ (p_data->meta_msg.code <= AVRC_RSP_INTERIM))
+ {
+ /* Its a response */
+ handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+ }
+ else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ)
+ {
+ /* Its a command */
+ handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+ }
+
+ }
+#endif
+ else
+ {
+ BTIF_TRACE_ERROR("Neither CTRL, nor TG is up, drop meta commands");
+ }
}
break;
+
default:
- BTIF_TRACE_DEBUG("Unhandled RC event : 0x%x", event);
+ BTIF_TRACE_DEBUG("%s Unhandled RC event : 0x%x", __FUNCTION__, event);
}
}
@@ -844,6 +1139,18 @@
/***************************************************************************
**
+ ** Function btif_rc_get_connected_peer_handle
+ **
+ ** Description Fetches the connected headset's handle if any
+ **
+ ***************************************************************************/
+UINT8 btif_rc_get_connected_peer_handle(void)
+{
+ return btif_rc_cb.rc_handle;
+}
+
+/***************************************************************************
+ **
** Function btif_rc_check_handle_pending_play
**
** Description Clears the queued PLAY command. if bSend is TRUE, forwards to app
@@ -961,7 +1268,7 @@
}
/* if response is for register_notification, make sure the rc has
actually registered for this */
- if((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && (code == AVRC_RSP_CHANGED))
+ if ((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && (code == AVRC_RSP_CHANGED))
{
BOOLEAN bSent = FALSE;
UINT8 event_id = pmetamsg_resp->reg_notif.event_id;
@@ -1130,7 +1437,7 @@
break;
case AVRC_PDU_REGISTER_NOTIFICATION:
{
- if(pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
+ if (pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
pavrc_cmd->reg_notif.param == 0)
{
BTIF_TRACE_WARNING("%s Device registering position changed with illegal param 0.",
@@ -1148,7 +1455,7 @@
{
tAVRC_RESPONSE avrc_rsp;
BTIF_TRACE_EVENT("%s() AVRC_PDU_INFORM_DISPLAY_CHARSET", __FUNCTION__);
- if(btif_rc_cb.rc_connected == TRUE)
+ if (btif_rc_cb.rc_connected == TRUE)
{
memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
avrc_rsp.inform_charset.opcode=opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
@@ -1166,9 +1473,49 @@
}
break;
}
-
}
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btif_rc_ctrl_upstreams_rsp_cmd
+**
+** Description Executes AVRC UPSTREAMS response events in btif context.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_rc_ctrl_upstreams_rsp_cmd(UINT8 event, tAVRC_COMMAND *pavrc_cmd,
+ UINT8 label)
+{
+ BTIF_TRACE_DEBUG("%s pdu: %s handle: 0x%x", __FUNCTION__,
+ dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ switch (event)
+ {
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+ HAL_CBACK(bt_rc_ctrl_callbacks,setabsvol_cmd_cb, &rc_addr,
+ pavrc_cmd->volume.volume, label);
+ break;
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ if (pavrc_cmd->reg_notif.event_id == AVRC_EVT_VOLUME_CHANGE)
+ {
+ HAL_CBACK(bt_rc_ctrl_callbacks, registernotification_absvol_cb,
+ &rc_addr, label);
+ }
+ break;
+ }
+#endif
+}
+
+static void rc_supported_event_free(void* p_data)
+{
+ osi_freebuf (p_data);
+}
+#endif
+
/*******************************************************************************
**
** Function btif_rc_upstreams_rsp_evt
@@ -1188,7 +1535,7 @@
{
case AVRC_PDU_REGISTER_NOTIFICATION:
{
- if(AVRC_RSP_CHANGED==ctype)
+ if (AVRC_RSP_CHANGED==ctype)
btif_rc_cb.rc_volume=pavrc_resp->reg_notif.param.volume;
HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype)
}
@@ -1196,9 +1543,9 @@
case AVRC_PDU_SET_ABSOLUTE_VOLUME:
{
- BTIF_TRACE_DEBUG("Set absolute volume change event received: volume %d,ctype %d",
- pavrc_resp->volume.volume,ctype);
- if(AVRC_RSP_ACCEPT==ctype)
+ BTIF_TRACE_DEBUG("%s Set absolute volume change event received: volume %d,ctype %d",
+ __FUNCTION__, pavrc_resp->volume.volume,ctype);
+ if (AVRC_RSP_ACCEPT==ctype)
btif_rc_cb.rc_volume=pavrc_resp->volume.volume;
HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype)
}
@@ -1266,6 +1613,25 @@
return result;
}
+static void rc_ctrl_procedure_complete ()
+{
+ if (btif_rc_cb.rc_procedure_complete == TRUE)
+ {
+ return;
+ }
+ btif_rc_cb.rc_procedure_complete = TRUE;
+ UINT32 attr_list[] = {
+ AVRC_MEDIA_ATTR_ID_TITLE,
+ AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM,
+ AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+ AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+ AVRC_MEDIA_ATTR_ID_GENRE,
+ AVRC_MEDIA_ATTR_ID_PLAYING_TIME
+ };
+ get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+}
+
/***************************************************************************
**
** Function get_play_status_rsp
@@ -1325,9 +1691,9 @@
element_attrs[i].name.str_len = (UINT16)strlen((char *)p_attrs[i].text);
element_attrs[i].name.p_str = p_attrs[i].text;
BTIF_TRACE_DEBUG("%s attr_id:0x%x, charset_id:0x%x, str_len:%d, str:%s",
- __FUNCTION__, (unsigned int)element_attrs[i].attr_id,
- element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
- element_attrs[i].name.p_str);
+ __FUNCTION__, (unsigned int)element_attrs[i].attr_id,
+ element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
+ element_attrs[i].name.p_str);
}
avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
}
@@ -1413,7 +1779,7 @@
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
rc_transaction_t *p_transaction=NULL;
- if(btif_rc_cb.rc_volume==volume)
+ if (btif_rc_cb.rc_volume==volume)
{
status=BT_STATUS_DONE;
BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__FUNCTION__, volume);
@@ -1435,7 +1801,7 @@
if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR)
{
bt_status_t tran_status=get_transaction(&p_transaction);
- if(BT_STATUS_SUCCESS == tran_status && NULL!=p_transaction)
+ if (BT_STATUS_SUCCESS == tran_status && NULL!=p_transaction)
{
BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
__FUNCTION__,p_transaction->lbl);
@@ -1444,7 +1810,7 @@
}
else
{
- if(NULL!=p_msg)
+ if (NULL!=p_msg)
osi_freebuf(p_msg);
BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
__FUNCTION__, tran_status);
@@ -1486,19 +1852,20 @@
avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
avrc_cmd.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.reg_notif.param = 0;
BldResp=AVRC_BldCommand(&avrc_cmd, &p_msg);
- if(AVRC_STS_NO_ERROR==BldResp && p_msg)
+ if (AVRC_STS_NO_ERROR==BldResp && p_msg)
{
p_transaction=get_transaction_by_lbl(lbl);
- if(NULL!=p_transaction)
+ if (NULL!=p_transaction)
{
BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_NOTIF, p_msg);
BTIF_TRACE_DEBUG("%s:BTA_AvMetaCmd called",__FUNCTION__);
}
else
{
- if(NULL!=p_msg)
+ if (NULL!=p_msg)
osi_freebuf(p_msg);
BTIF_TRACE_ERROR("%s transaction not obtained with label: %d",__FUNCTION__,lbl);
}
@@ -1522,7 +1889,7 @@
UINT8 scratch_buf[512] = {0};
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
- if(AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
+ if (AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code
|| AVRC_RSP_INTERIM==pmeta_msg->code || AVRC_RSP_ACCEPT==pmeta_msg->code
|| AVRC_RSP_REJ==pmeta_msg->code || AVRC_RSP_NOT_IMPL==pmeta_msg->code))
{
@@ -1533,20 +1900,20 @@
if (status != AVRC_STS_NO_ERROR)
{
- if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
+ if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
&& btif_rc_cb.rc_vol_label==pmeta_msg->label)
{
btif_rc_cb.rc_vol_label=MAX_LABEL;
release_transaction(btif_rc_cb.rc_vol_label);
}
- else if(AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
+ else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
{
release_transaction(pmeta_msg->label);
}
return;
}
- else if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
+ else if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
&& btif_rc_cb.rc_vol_label!=pmeta_msg->label)
{
@@ -1563,7 +1930,7 @@
return;
}
- if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
+ if (AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu
&& AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id
&& AVRC_RSP_CHANGED==pmeta_msg->code)
{
@@ -1571,7 +1938,7 @@
// Do not re-register for rejected case, as it might get into endless loop
register_volumechange(btif_rc_cb.rc_vol_label);
}
- else if(AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
+ else if (AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu)
{
/* free up the label here */
release_transaction(pmeta_msg->label);
@@ -1583,6 +1950,1305 @@
pmeta_msg->label);
}
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/***************************************************************************
+**
+** Function iterate_supported_event_list_for_interim_rsp
+**
+** Description iterator callback function to match the event and handle
+** timer cleanup
+** Returns true if matches with the event, flase to stop
+**
+***************************************************************************/
+bool iterate_supported_event_list_for_interim_rsp(void *data, void *cb_data)
+{
+ UINT8 *p_event_id;
+ btif_rc_supported_event_t *p_event = (btif_rc_supported_event_t *)data;
+
+ p_event_id = (UINT8*)cb_data;
+
+ if (p_event->event_id == *p_event_id)
+ {
+ p_event->status = eINTERIM;
+ return true;
+ }
+ return false;
+}
+
+/***************************************************************************
+**
+** Function iterate_supported_event_list_for_timeout
+**
+** Description Iterator callback function for timeout handling.
+** As part of the failure handling, it releases the
+** transaction label and removes the event from list,
+** this event will not be requested again during
+** the lifetime of the connection.
+** Returns false to stop iterating, true to continue
+**
+***************************************************************************/
+bool iterate_supported_event_list_for_timeout(void *data, void *cb_data)
+{
+ UINT8 label;
+ UINT32 cb_value;
+ btif_rc_supported_event_t *p_event = (btif_rc_supported_event_t *)data;
+
+ cb_value = (UINT32)cb_data;
+
+ label = cb_value & 0xFF;
+
+ if (p_event->label == label)
+ {
+ list_remove(btif_rc_cb.rc_supported_event_list, p_event);
+ return true;
+ }
+ return false;
+}
+
+/***************************************************************************
+**
+** Function rc_notification_interim_timout
+**
+** Description Interim response timeout handler.
+** Runs the iterator to check and clear the timed out event.
+** Proceeds to register for the unregistered events.
+** Returns None
+**
+***************************************************************************/
+static void rc_notification_interim_timout (UINT8 label)
+{
+ list_node_t *node;
+
+ list_foreach(btif_rc_cb.rc_supported_event_list,
+ iterate_supported_event_list_for_timeout, &label);
+ /* Timeout happened for interim response for the registered event,
+ * check if there are any pending for registration
+ */
+ node = list_begin(btif_rc_cb.rc_supported_event_list);
+ while (node != NULL)
+ {
+ btif_rc_supported_event_t *p_event;
+
+ p_event = (btif_rc_supported_event_t *)list_node(node);
+ if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED))
+ {
+ register_for_event_notification(p_event);
+ break;
+ }
+ node = list_next (node);
+ }
+ /* Todo. Need to initiate application settings query if this
+ * is the last event registration.
+ */
+}
+
+/***************************************************************************
+**
+** Function rc_timeout_callback
+**
+** Description RC timeout callback.
+** This is called from BTU context and switches to BTIF
+** context to handle the timeout events
+** Returns None
+**
+***************************************************************************/
+static void rc_timeout_callback (timer_entry_t *tle)
+{
+ char *p_data = (char*)tle->data;
+
+ tle->data = NULL;
+ btif_transfer_context(rc_timeout_handler, 0,
+ p_data, sizeof(btif_rc_timer_context_t), NULL);
+ osi_freebuf (p_data);
+}
+
+/***************************************************************************
+**
+** Function rc_start_play_status_timer
+**
+** Description Helper function to start the timer to fetch play status.
+** Returns None
+**
+***************************************************************************/
+void rc_start_play_status_timer ()
+{
+ btif_rc_timer_context_t *p_rc_timer_context;
+ /* Start the Play status timer only if it is not started */
+ if (btif_rc_cb.tle_rc_play_status.data == NULL)
+ {
+ p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+ if (p_rc_timer_context != NULL)
+ {
+ p_rc_timer_context->timer_id = RC_TIMER_PLAY_STATUS;
+ memset(&btif_rc_cb.tle_rc_play_status, 0, sizeof(timer_entry_t));
+ btif_rc_cb.tle_rc_play_status.param = rc_timeout_callback;
+ btif_rc_cb.tle_rc_play_status.data = p_rc_timer_context;
+ btu_start_timer(&btif_rc_cb.tle_rc_play_status, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_RC_INTERIM_RSP);
+ }
+ }
+}
+
+/***************************************************************************
+**
+** Function rc_stop_play_status_timer
+**
+** Description Helper function to stop the play status timer.
+** Returns None
+**
+***************************************************************************/
+void rc_stop_play_status_timer ()
+{
+ if (btif_rc_cb.tle_rc_play_status.data != NULL)
+ {
+ btu_stop_timer (&btif_rc_cb.tle_rc_play_status);
+ osi_freebuf(btif_rc_cb.tle_rc_play_status.data);
+ btif_rc_cb.tle_rc_play_status.data = NULL;
+ }
+}
+
+/***************************************************************************
+**
+** Function rc_timeout_handler
+**
+** Description RC timeout handler (Runs in BTIF context).
+** main handler for all the timers created from RC module
+** Returns None
+**
+***************************************************************************/
+static void rc_timeout_handler (UINT16 event, char* p_data)
+{
+ btif_rc_timer_context_t *p_rc_timer_context;
+ tAVRC_RESPONSE avrc_response = {0};
+ tBTA_AV_META_MSG meta_msg;
+
+ p_rc_timer_context = (btif_rc_timer_context_t *)p_data;
+ memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
+ meta_msg.rc_handle = btif_rc_cb.rc_handle;
+
+ switch (p_rc_timer_context->timer_id)
+ {
+ case RC_TIMER_STATUS_CMD:
+ switch (p_rc_timer_context->rc_status_cmd.pdu_id)
+ {
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ rc_notification_interim_timout(
+ p_rc_timer_context->rc_status_cmd.label);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ avrc_response.get_caps.status = BTIF_RC_STS_TIMEOUT;
+ handle_get_capability_response(&meta_msg, &avrc_response.get_caps);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ avrc_response.list_app_attr.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_attr_response(&meta_msg, &avrc_response.list_app_attr);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ avrc_response.list_app_values.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_val_response(&meta_msg, &avrc_response.list_app_values);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ avrc_response.get_cur_app_val.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_cur_val_response(&meta_msg, &avrc_response.get_cur_app_val);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ avrc_response.get_app_attr_txt.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_attr_txt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ avrc_response.get_app_val_txt.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_val_txt);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ avrc_response.get_elem_attrs.status = BTIF_RC_STS_TIMEOUT;
+ handle_get_elem_attr_response(&meta_msg, &avrc_response.get_elem_attrs);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ avrc_response.get_caps.status = BTIF_RC_STS_TIMEOUT;
+ handle_get_capability_response(&meta_msg, &avrc_response.get_caps);
+ break;
+ }
+ release_transaction (p_rc_timer_context->rc_status_cmd.label);
+ break;
+
+ case RC_TIMER_CONTROL_CMD:
+ switch (p_rc_timer_context->rc_control_cmd.pdu_id)
+ {
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ avrc_response.set_app_val.status = BTIF_RC_STS_TIMEOUT;
+ handle_set_app_attr_val_response(&meta_msg, &avrc_response.set_app_val);
+ break;
+ }
+ release_transaction (p_rc_timer_context->rc_control_cmd.label);
+ break;
+
+ case RC_TIMER_PLAY_STATUS:
+ get_play_status_cmd();
+ rc_start_play_status_timer();
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("%s Error unknown timer id %d",
+ __FUNCTION__, p_rc_timer_context->timer_id);
+ break;
+ }
+}
+
+/***************************************************************************
+**
+** Function register_for_event_notification
+**
+** Description Helper function registering notification events
+** sets an interim response timeout to handle if the remote
+** does not respond.
+** Returns None
+**
+***************************************************************************/
+static void register_for_event_notification (btif_rc_supported_event_t *p_event)
+{
+ bt_status_t status;
+ rc_transaction_t *p_transaction;
+
+ status = get_transaction(&p_transaction);
+ if (status == BT_STATUS_SUCCESS)
+ {
+ btif_rc_timer_context_t *p_rc_timer_context;
+
+ status = register_notification_cmd (p_transaction->lbl, p_event->event_id, 0);
+ if (status != BT_STATUS_SUCCESS)
+ {
+ BTIF_TRACE_ERROR("%s Error in Notification registration %d",
+ __FUNCTION__, status);
+ release_transaction (p_transaction->lbl);
+ return;
+ }
+ p_event->label = p_transaction->lbl;
+ p_event->status = eREGISTERED;
+ p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+ if (p_rc_timer_context != NULL)
+ {
+ p_rc_timer_context->timer_id = RC_TIMER_STATUS_CMD;
+ p_rc_timer_context->rc_status_cmd.label = p_transaction->lbl;
+ p_rc_timer_context->rc_status_cmd.pdu_id = AVRC_PDU_REGISTER_NOTIFICATION;
+ memset(&p_transaction->tle_txn, 0, sizeof(timer_entry_t));
+ p_transaction->tle_txn.param = rc_timeout_callback;
+ p_transaction->tle_txn.data = p_rc_timer_context;
+ btu_start_timer(&p_transaction->tle_txn, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_RC_INTERIM_RSP);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s Error No more Transaction label %d",
+ __FUNCTION__, status);
+ }
+}
+
+static void start_status_command_timer (UINT8 pdu_id, rc_transaction_t *p_txn)
+{
+ bt_status_t status;
+ btif_rc_timer_context_t *p_rc_timer_context;
+
+ p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+ if (p_rc_timer_context != NULL)
+ {
+ p_rc_timer_context->timer_id = RC_TIMER_STATUS_CMD;
+ p_rc_timer_context->rc_status_cmd.label = p_txn->lbl;
+ p_rc_timer_context->rc_status_cmd.pdu_id = pdu_id;
+
+ memset(&p_txn->tle_txn, 0, sizeof(timer_entry_t));
+ p_txn->tle_txn.param = rc_timeout_callback;
+ p_txn->tle_txn.data = p_rc_timer_context;
+ btu_start_timer(&p_txn->tle_txn, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_RC_STATUS_CMD);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s Getbuf failed while starting command timer",
+ __FUNCTION__);
+ }
+}
+
+static void start_control_command_timer (UINT8 pdu_id, rc_transaction_t *p_txn)
+{
+ bt_status_t status;
+ btif_rc_timer_context_t *p_rc_timer_context;
+
+ p_rc_timer_context = (btif_rc_timer_context_t*) osi_getbuf(sizeof(btif_rc_timer_context_t));
+ if (p_rc_timer_context != NULL)
+ {
+ p_rc_timer_context->timer_id = RC_TIMER_CONTROL_CMD;
+ p_rc_timer_context->rc_control_cmd.label = p_txn->lbl;
+ p_rc_timer_context->rc_control_cmd.pdu_id = pdu_id;
+
+ memset(&p_txn->tle_txn, 0, sizeof(timer_entry_t));
+ p_txn->tle_txn.param = rc_timeout_callback;
+ p_txn->tle_txn.data = p_rc_timer_context;
+ btu_start_timer(&p_txn->tle_txn, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_RC_CONTROL_CMD);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s Getbuf failed while starting command timer",
+ __FUNCTION__);
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_get_capability_response
+**
+** Description Handles the get_cap_response to populate company id info
+** and query the supported events.
+** Initiates Notification registration for events supported
+** Returns None
+**
+***************************************************************************/
+static void handle_get_capability_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CAPS_RSP *p_rsp)
+{
+ int xx = 0;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_ERROR("%s Error capability response 0x%02X",
+ __FUNCTION__, p_rsp->status);
+ return;
+ }
+
+ if (p_rsp->capability_id == AVRC_CAP_EVENTS_SUPPORTED)
+ {
+ btif_rc_supported_event_t *p_event;
+
+ /* Todo: Check if list can be active when we hit here */
+ btif_rc_cb.rc_supported_event_list = list_new(rc_supported_event_free);
+ for (xx = 0; xx < p_rsp->count; xx++)
+ {
+ /* Skip registering for Play position change notification */
+ if ((p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_STATUS_CHANGE)||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_TRACK_CHANGE)||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_APP_SETTING_CHANGE))
+ {
+ p_event = (btif_rc_supported_event_t*) osi_getbuf(sizeof(btif_rc_supported_event_t));
+ p_event->event_id = p_rsp->param.event_id[xx];
+ p_event->status = eNOT_REGISTERED;
+ list_append(btif_rc_cb.rc_supported_event_list, p_event);
+ }
+ }
+ p_event = list_front(btif_rc_cb.rc_supported_event_list);
+ if (p_event != NULL)
+ {
+ register_for_event_notification(p_event);
+ }
+ }
+ else if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID)
+ {
+ getcapabilities_cmd (AVRC_CAP_EVENTS_SUPPORTED);
+ BTIF_TRACE_EVENT("%s AVRC_CAP_COMPANY_ID: ", __FUNCTION__);
+ for (xx = 0; xx < p_rsp->count; xx++)
+ {
+ BTIF_TRACE_EVENT("%s : %d", __FUNCTION__, p_rsp->param.company_id[xx]);
+ }
+ }
+}
+
+bool rc_is_track_id_valid (tAVRC_UID uid)
+{
+ tAVRC_UID invalid_uid = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ if (memcmp(uid, invalid_uid, sizeof(tAVRC_UID)) == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_notification_response
+**
+** Description Main handler for notification responses to registered events
+** 1. Register for unregistered event(in interim response path)
+** 2. After registering for all supported events, start
+** retrieving application settings and values
+** 3. Reregister for events on getting changed response
+** 4. Run play status timer for getting position when the
+** status changes to playing
+** 5. Get the Media details when the track change happens
+** or track change interim response is received with
+** valid track id
+** 6. HAL callback for play status change and application
+** setting change
+** Returns None
+**
+***************************************************************************/
+static void handle_notification_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_REG_NOTIF_RSP *p_rsp)
+{
+ bt_bdaddr_t rc_addr;
+ UINT32 attr_list[] = {
+ AVRC_MEDIA_ATTR_ID_TITLE,
+ AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM,
+ AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+ AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+ AVRC_MEDIA_ATTR_ID_GENRE,
+ AVRC_MEDIA_ATTR_ID_PLAYING_TIME
+ };
+
+
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ if (pmeta_msg->code == AVRC_RSP_INTERIM)
+ {
+ btif_rc_supported_event_t *p_event;
+ list_node_t *node;
+
+ BTIF_TRACE_DEBUG("%s Interim response : 0x%2X ", __FUNCTION__, p_rsp->event_id);
+ switch (p_rsp->event_id)
+ {
+ case AVRC_EVT_PLAY_STATUS_CHANGE:
+ /* Start timer to get play status periodically
+ * if the play state is playing.
+ */
+ if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING)
+ {
+ rc_start_play_status_timer();
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb,
+ &rc_addr, p_rsp->param.play_status);
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE:
+ if (rc_is_track_id_valid (p_rsp->param.track) != true)
+ {
+ break;
+ }
+ else
+ {
+ UINT8 *p_data = p_rsp->param.track;
+ /* Update the UID for current track
+ * Attributes will be fetched after the AVRCP procedure
+ */
+ BE_STREAM_TO_UINT64(btif_rc_cb.rc_playing_uid, p_data);
+ }
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE:
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ break;
+
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE:
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END:
+ case AVRC_EVT_TRACK_REACHED_START:
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+ default:
+ BTIF_TRACE_ERROR("%s Unhandled interim response 0x%2X", __FUNCTION__,
+ p_rsp->event_id);
+ return;
+ }
+ list_foreach(btif_rc_cb.rc_supported_event_list,
+ iterate_supported_event_list_for_interim_rsp,
+ &p_rsp->event_id);
+
+ node = list_begin(btif_rc_cb.rc_supported_event_list);
+ while (node != NULL)
+ {
+ p_event = (btif_rc_supported_event_t *)list_node(node);
+ if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED))
+ {
+ register_for_event_notification(p_event);
+ break;
+ }
+ node = list_next (node);
+ p_event = NULL;
+ }
+ /* Registered for all events, we can request application settings */
+ if ((p_event == NULL) && (btif_rc_cb.rc_app_settings.query_started == false))
+ {
+ /* we need to do this only if remote TG supports
+ * player application settings
+ */
+ btif_rc_cb.rc_app_settings.query_started = TRUE;
+ if (btif_rc_cb.rc_features & BTA_AV_FEAT_APP_SETTING)
+ {
+ list_player_app_setting_attrib_cmd();
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s App setting not supported, complete procedure", __FUNCTION__);
+ rc_ctrl_procedure_complete();
+ }
+ }
+ }
+ else if (pmeta_msg->code == AVRC_RSP_CHANGED)
+ {
+ btif_rc_supported_event_t *p_event;
+ list_node_t *node;
+
+ BTIF_TRACE_DEBUG("%s Notification completed : 0x%2X ", __FUNCTION__,
+ p_rsp->event_id);
+
+ node = list_begin(btif_rc_cb.rc_supported_event_list);
+ while (node != NULL)
+ {
+ p_event = (btif_rc_supported_event_t *)list_node(node);
+ if ((p_event != NULL) && (p_event->event_id == p_rsp->event_id))
+ {
+ p_event->status = eNOT_REGISTERED;
+ register_for_event_notification(p_event);
+ break;
+ }
+ node = list_next (node);
+ }
+
+ switch (p_rsp->event_id)
+ {
+ case AVRC_EVT_PLAY_STATUS_CHANGE:
+ /* Start timer to get play status periodically
+ * if the play state is playing.
+ */
+ if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING)
+ {
+ rc_start_play_status_timer();
+ }
+ else
+ {
+ rc_stop_play_status_timer();
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb,
+ &rc_addr, p_rsp->param.play_status);
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE:
+ if (rc_is_track_id_valid (p_rsp->param.track) != true)
+ {
+ break;
+ }
+ get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE:
+ {
+ btrc_player_settings_t app_settings;
+ UINT16 xx;
+
+ app_settings.num_attr = p_rsp->param.player_setting.num_attr;
+ for (xx = 0; xx < app_settings.num_attr; xx++)
+ {
+ app_settings.attr_ids[xx] = p_rsp->param.player_setting.attr_id[xx];
+ app_settings.attr_values[xx] = p_rsp->param.player_setting.attr_value[xx];
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
+ &rc_addr, &app_settings);
+ }
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ break;
+
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE:
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END:
+ case AVRC_EVT_TRACK_REACHED_START:
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+ default:
+ BTIF_TRACE_ERROR("%s Unhandled completion response 0x%2X",
+ __FUNCTION__, p_rsp->event_id);
+ return;
+ }
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_app_attr_response
+**
+** Description handles the the application attributes response and
+** initiates procedure to fetch the attribute values
+** Returns None
+**
+***************************************************************************/
+static void handle_app_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_ATTR_RSP *p_rsp)
+{
+ UINT8 xx;
+
+ if (p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_ERROR("%s Error getting Player application settings: 0x%2X",
+ __FUNCTION__, p_rsp->status);
+ rc_ctrl_procedure_complete();
+ return;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++)
+ {
+ UINT8 st_index;
+
+ if (p_rsp->attrs[xx] > AVRC_PLAYER_SETTING_LOW_MENU_EXT)
+ {
+ st_index = btif_rc_cb.rc_app_settings.num_ext_attrs;
+ btif_rc_cb.rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
+ btif_rc_cb.rc_app_settings.num_ext_attrs++;
+ }
+ else
+ {
+ st_index = btif_rc_cb.rc_app_settings.num_attrs;
+ btif_rc_cb.rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
+ btif_rc_cb.rc_app_settings.num_attrs++;
+ }
+ }
+ btif_rc_cb.rc_app_settings.attr_index = 0;
+ btif_rc_cb.rc_app_settings.ext_attr_index = 0;
+ btif_rc_cb.rc_app_settings.ext_val_index = 0;
+ if (p_rsp->num_attr)
+ {
+ list_player_app_setting_value_cmd (btif_rc_cb.rc_app_settings.attrs[0].attr_id);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s No Player application settings found",
+ __FUNCTION__);
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_app_val_response
+**
+** Description handles the the attributes value response and if extended
+** menu is available, it initiates query for the attribute
+** text. If not, it initiates procedure to get the current
+** attribute values and calls the HAL callback for provding
+** application settings information.
+** Returns None
+**
+***************************************************************************/
+static void handle_app_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_LIST_APP_VALUES_RSP *p_rsp)
+{
+ UINT8 xx, attr_index;
+ int i,j;
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+ btif_rc_player_app_settings_t *p_app_settings;
+ bt_bdaddr_t rc_addr;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_ERROR("%s Error fetching attribute values 0x%02X",
+ __FUNCTION__, p_rsp->status);
+ return;
+ }
+
+ p_app_settings = &btif_rc_cb.rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ if (p_app_settings->attr_index < p_app_settings->num_attrs)
+ {
+ attr_index = p_app_settings->attr_index;
+ p_app_settings->attrs[attr_index].num_val = p_rsp->num_val;
+ for (xx = 0; xx < p_rsp->num_val; xx++)
+ {
+ p_app_settings->attrs[attr_index].attr_val[xx] = p_rsp->vals[xx];
+ }
+ attr_index++;
+ p_app_settings->attr_index++;
+ if (attr_index < p_app_settings->num_attrs)
+ {
+ list_player_app_setting_value_cmd (p_app_settings->attrs[p_app_settings->attr_index].attr_id);
+ }
+ else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs)
+ {
+ attr_index = 0;
+ p_app_settings->ext_attr_index = 0;
+ list_player_app_setting_value_cmd (p_app_settings->ext_attrs[attr_index].attr_id);
+ }
+ else
+ {
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ get_player_app_setting_cmd (p_app_settings->num_attrs, attrs);
+ HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, &p_app_settings->attrs, 0, NULL);
+ }
+ }
+ else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs)
+ {
+ attr_index = p_app_settings->ext_attr_index;
+ p_app_settings->ext_attrs[attr_index].num_val = p_rsp->num_val;
+ for (xx = 0; xx < p_rsp->num_val; xx++)
+ {
+ p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val = p_rsp->vals[xx];
+ }
+ attr_index++;
+ p_app_settings->ext_attr_index++;
+ if (attr_index < p_app_settings->num_ext_attrs)
+ {
+ list_player_app_setting_value_cmd (p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id);
+ }
+ else
+ {
+ UINT8 attr[AVRC_MAX_APP_ATTR_SIZE];
+ UINT8 xx;
+
+ for (xx = 0; xx < p_app_settings->num_ext_attrs; xx++)
+ {
+ attr[xx] = p_app_settings->ext_attrs[xx].attr_id;
+ }
+ get_player_app_setting_attr_text_cmd(attr, xx);
+ }
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_app_cur_val_response
+**
+** Description handles the the get attributes value response.
+**
+** Returns None
+**
+***************************************************************************/
+static void handle_app_cur_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp)
+{
+ btrc_player_settings_t app_settings;
+ bt_bdaddr_t rc_addr;
+ UINT16 xx;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_ERROR("%s Error fetching current settings: 0x%02X",
+ __FUNCTION__, p_rsp->status);
+ return;
+ }
+
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ app_settings.num_attr = p_rsp->num_val;
+ for (xx = 0; xx < app_settings.num_attr; xx++)
+ {
+ app_settings.attr_ids[xx] = p_rsp->p_vals[xx].attr_id;
+ app_settings.attr_values[xx] = p_rsp->p_vals[xx].attr_val;
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
+ &rc_addr, &app_settings);
+ /* Application settings are fetched only once for initial values
+ * initiate anything that follows after RC procedure.
+ * Defer it if browsing is supported till players query
+ */
+ rc_ctrl_procedure_complete ();
+ osi_freebuf(p_rsp->p_vals);
+}
+
+/***************************************************************************
+**
+** Function handle_app_attr_txt_response
+**
+** Description handles the the get attributes text response, if fails
+** calls HAL callback with just normal settings and initiates
+** query for current settings else initiates query for value text
+** Returns None
+**
+***************************************************************************/
+static void handle_app_attr_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
+{
+ UINT8 xx, attr_index;
+ UINT8 vals[AVRC_MAX_APP_ATTR_SIZE];
+ btif_rc_player_app_settings_t *p_app_settings;
+ bt_bdaddr_t rc_addr;
+
+ p_app_settings = &btif_rc_cb.rc_app_settings;
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+ BTIF_TRACE_ERROR("%s Error fetching attribute text: 0x%02X",
+ __FUNCTION__, p_rsp->status);
+ /* Not able to fetch Text for extended Menu, skip the process
+ * and cleanup used memory. Proceed to get the current settings
+ * for standard attributes.
+ */
+ p_app_settings->num_ext_attrs = 0;
+ for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+ {
+ osi_freebuf (p_app_settings->ext_attrs[xx].p_str);
+ }
+ p_app_settings->ext_attr_index = 0;
+
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, &p_app_settings->attrs, 0, NULL);
+
+ get_player_app_setting_cmd (xx, attrs);
+ return;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++)
+ {
+ UINT8 x;
+ for (x = 0; x < p_app_settings->num_ext_attrs; x++)
+ {
+ if (p_app_settings->ext_attrs[x].attr_id == p_rsp->p_attrs[xx].attr_id)
+ {
+ p_app_settings->ext_attrs[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+ p_app_settings->ext_attrs[x].str_len = p_rsp->p_attrs[xx].str_len;
+ p_app_settings->ext_attrs[x].p_str = p_rsp->p_attrs[xx].p_str;
+ break;
+ }
+ }
+ }
+
+ for (xx = 0; xx < p_app_settings->ext_attrs[0].num_val; xx++)
+ {
+ vals[xx] = p_app_settings->ext_attrs[0].ext_attr_val[xx].val;
+ }
+ get_player_app_setting_value_text_cmd(vals, xx);
+}
+
+
+/***************************************************************************
+**
+** Function handle_app_attr_val_txt_response
+**
+** Description handles the the get attributes value text response, if fails
+** calls HAL callback with just normal settings and initiates
+** query for current settings
+** Returns None
+**
+***************************************************************************/
+static void handle_app_attr_val_txt_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp)
+{
+ UINT8 xx, attr_index;
+ UINT8 vals[AVRC_MAX_APP_ATTR_SIZE];
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+ btif_rc_player_app_settings_t *p_app_settings;
+ bt_bdaddr_t rc_addr;
+
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+ p_app_settings = &btif_rc_cb.rc_app_settings;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR)
+ {
+ UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+ BTIF_TRACE_ERROR("%s Error fetching attribute value text: 0x%02X",
+ __FUNCTION__, p_rsp->status);
+
+ /* Not able to fetch Text for extended Menu, skip the process
+ * and cleanup used memory. Proceed to get the current settings
+ * for standard attributes.
+ */
+ p_app_settings->num_ext_attrs = 0;
+ for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+ {
+ int x;
+ btrc_player_app_ext_attr_t *p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+ for (x = 0; x < p_ext_attr->num_val; x++)
+ {
+ osi_freebuf (p_ext_attr->ext_attr_val[x].p_str);
+ }
+ p_ext_attr->num_val = 0;
+ osi_freebuf (p_app_settings->ext_attrs[xx].p_str);
+ }
+ p_app_settings->ext_attr_index = 0;
+
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, &p_app_settings->attrs, 0, NULL);
+
+ get_player_app_setting_cmd (xx, attrs);
+ return;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++)
+ {
+ UINT8 x;
+ btrc_player_app_ext_attr_t *p_ext_attr;
+ p_ext_attr = &p_app_settings->ext_attrs[p_app_settings->ext_val_index];
+ for (x = 0; x < p_rsp->num_attr; x++)
+ {
+ if (p_ext_attr->ext_attr_val[x].val == p_rsp->p_attrs[xx].attr_id)
+ {
+ p_ext_attr->ext_attr_val[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+ p_ext_attr->ext_attr_val[x].str_len = p_rsp->p_attrs[xx].str_len;
+ p_ext_attr->ext_attr_val[x].p_str = p_rsp->p_attrs[xx].p_str;
+ break;
+ }
+ }
+ }
+ p_app_settings->ext_val_index++;
+
+ if (p_app_settings->ext_val_index < p_app_settings->num_ext_attrs)
+ {
+ attr_index = p_app_settings->ext_val_index;
+ for (xx = 0; xx < p_app_settings->ext_attrs[attr_index].num_val; xx++)
+ {
+ vals[xx] = p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val;
+ }
+ get_player_app_setting_value_text_cmd(vals, xx);
+ }
+ else
+ {
+ UINT8 x;
+
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++)
+ {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ for (x = 0; x < p_app_settings->num_ext_attrs; x++)
+ {
+ attrs[xx+x] = p_app_settings->ext_attrs[x].attr_id;
+ }
+ HAL_CBACK (bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, &p_app_settings->attrs,
+ p_app_settings->num_ext_attrs, &p_app_settings->ext_attrs);
+ get_player_app_setting_cmd (xx + x, attrs);
+
+ /* Free the application settings information after sending to
+ * application.
+ */
+ for (xx = 0; xx < p_app_settings->ext_attr_index; xx++)
+ {
+ int x;
+ btrc_player_app_ext_attr_t *p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+ for (x = 0; x < p_ext_attr->num_val; x++)
+ {
+ osi_freebuf (p_ext_attr->ext_attr_val[x].p_str);
+ }
+ p_ext_attr->num_val = 0;
+ osi_freebuf (p_app_settings->ext_attrs[xx].p_str);
+ }
+ p_app_settings->num_attrs = 0;
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_set_app_attr_val_response
+**
+** Description handles the the set attributes value response, if fails
+** calls HAL callback to indicate the failure
+** Returns None
+**
+***************************************************************************/
+static void handle_set_app_attr_val_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_RSP *p_rsp)
+{
+ uint8_t accepted = 0;
+ bt_bdaddr_t rc_addr;
+
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ /* For timeout pmeta_msg will be NULL, else we need to
+ * check if this is accepted by TG
+ */
+ if (pmeta_msg && (pmeta_msg->code == AVRC_RSP_ACCEPT))
+ {
+ accepted = 1;
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, setplayerappsetting_rsp_cb, &rc_addr, accepted);
+}
+
+/***************************************************************************
+**
+** Function handle_get_elem_attr_response
+**
+** Description handles the the element attributes response, calls
+** HAL callback to update track change information.
+** Returns None
+**
+***************************************************************************/
+static void handle_get_elem_attr_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_ELEM_ATTRS_RSP *p_rsp)
+{
+ btrc_element_attr_val_t *p_attr;
+ bt_bdaddr_t rc_addr;
+ UINT16 xx;
+
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR)
+ {
+ p_attr = (btrc_element_attr_val_t*)osi_getbuf (p_rsp->num_attr * sizeof(btrc_element_attr_val_t));
+ if (p_attr != NULL)
+ {
+ memset(p_attr, 0, osi_get_buf_size (p_attr));
+ for (xx = 0; xx < p_rsp->num_attr; xx++)
+ {
+ p_attr[xx].attr_id = p_rsp->p_attrs[xx].attr_id;
+ /* Todo. Legth limit check to include null */
+ if (p_rsp->p_attrs[xx].name.str_len && p_rsp->p_attrs[xx].name.p_str)
+ {
+ memcpy(p_attr[xx].text, p_rsp->p_attrs[xx].name.p_str,
+ p_rsp->p_attrs[xx].name.str_len);
+ osi_freebuf (p_rsp->p_attrs[xx].name.p_str);
+ }
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, track_changed_cb,
+ &rc_addr, p_rsp->num_attr, p_attr);
+ osi_freebuf (p_attr);
+ }
+ }
+ else if (p_rsp->status == BTIF_RC_STS_TIMEOUT)
+ {
+ /* Retry for timeout case, this covers error handling
+ * for continuation failure also.
+ */
+ UINT32 attr_list[] = {
+ AVRC_MEDIA_ATTR_ID_TITLE,
+ AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM,
+ AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+ AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+ AVRC_MEDIA_ATTR_ID_GENRE,
+ AVRC_MEDIA_ATTR_ID_PLAYING_TIME
+ };
+ get_element_attribute_cmd (AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: Error in get element attr procedure %d",
+ __FUNCTION__, p_rsp->status);
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_get_playstatus_response
+**
+** Description handles the the play status response, calls
+** HAL callback to update play position.
+** Returns None
+**
+***************************************************************************/
+static void handle_get_playstatus_response (tBTA_AV_META_MSG *pmeta_msg, tAVRC_GET_PLAY_STATUS_RSP *p_rsp)
+{
+ bt_bdaddr_t rc_addr;
+
+ bdcpy(rc_addr.address, btif_rc_cb.rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR)
+ {
+ HAL_CBACK(bt_rc_ctrl_callbacks, play_position_changed_cb,
+ &rc_addr, p_rsp->song_len, p_rsp->song_pos);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: Error in get play status procedure %d",
+ __FUNCTION__, p_rsp->status);
+ }
+}
+
+/***************************************************************************
+**
+** Function clear_cmd_timeout
+**
+** Description helper function to stop the command timeout timer
+** Returns None
+**
+***************************************************************************/
+static void clear_cmd_timeout (UINT8 label)
+{
+ rc_transaction_t *p_txn;
+
+ p_txn = get_transaction_by_lbl (label);
+ if (p_txn == NULL)
+ {
+ BTIF_TRACE_ERROR("%s: Error in transaction label lookup", __FUNCTION__);
+ return;
+ }
+
+ btu_stop_timer (&p_txn->tle_txn);
+ if (p_txn->tle_txn.data != NULL)
+ {
+ osi_freebuf (p_txn->tle_txn.data);
+ p_txn->tle_txn.data = NULL;
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_avk_rc_metamsg_rsp
+**
+** Description Handle RC metamessage response
+**
+** Returns void
+**
+***************************************************************************/
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg)
+{
+ tAVRC_RESPONSE avrc_response = {0};
+ UINT8 scratch_buf[512] = {0};// this variable is unused
+ UINT16 buf_len;
+ tAVRC_STS status;
+
+ BTIF_TRACE_DEBUG("%s opcode = %d rsp_code = %d ", __FUNCTION__,
+ pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+
+ if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode)&&
+ (pmeta_msg->code >= AVRC_RSP_NOT_IMPL)&&
+ (pmeta_msg->code <= AVRC_RSP_INTERIM))
+ {
+ status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, &buf_len);
+ BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d",
+ __FUNCTION__, status, avrc_response.pdu,
+ pmeta_msg->p_msg->vendor.hdr.ctype);
+
+ switch (avrc_response.pdu)
+ {
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ handle_notification_response(pmeta_msg, &avrc_response.reg_notif);
+ if (pmeta_msg->code == AVRC_RSP_INTERIM)
+ {
+ /* Don't free the transaction Id */
+ clear_cmd_timeout (pmeta_msg->label);
+ return;
+ }
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ handle_get_capability_response(pmeta_msg, &avrc_response.get_caps);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ handle_app_attr_response(pmeta_msg, &avrc_response.list_app_attr);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ handle_app_val_response(pmeta_msg, &avrc_response.list_app_values);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ handle_app_cur_val_response(pmeta_msg, &avrc_response.get_cur_app_val);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ handle_app_attr_txt_response(pmeta_msg, &avrc_response.get_app_attr_txt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ handle_app_attr_val_txt_response(pmeta_msg, &avrc_response.get_app_val_txt);
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ handle_set_app_attr_val_response(pmeta_msg, &avrc_response.set_app_val);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ handle_get_elem_attr_response(pmeta_msg, &avrc_response.get_elem_attrs);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ handle_get_playstatus_response(pmeta_msg, &avrc_response.get_play_status);
+ break;
+ }
+ release_transaction(pmeta_msg->label);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s:Invalid Vendor Command code: %d len: %d. Not processing it.",
+ __FUNCTION__, pmeta_msg->code, pmeta_msg->len);
+ return;
+ }
+}
+
+/***************************************************************************
+**
+** Function handle_avk_rc_metamsg_cmd
+**
+** Description Handle RC metamessage response
+**
+** Returns void
+**
+***************************************************************************/
+static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG *pmeta_msg)
+{
+ tAVRC_COMMAND avrc_cmd = {0};
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ BTIF_TRACE_DEBUG("%s opcode = %d rsp_code = %d ",__FUNCTION__,
+ pmeta_msg->p_msg->hdr.opcode,pmeta_msg->code);
+ if ((AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode)&&
+ (pmeta_msg->code <= AVRC_CMD_GEN_INQ))
+ {
+ status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
+ BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d",
+ __FUNCTION__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
+
+ if (status != AVRC_STS_NO_ERROR)
+ {
+ /* return error */
+ BTIF_TRACE_WARNING("%s: Error in parsing received metamsg command. status: 0x%02x",
+ __FUNCTION__, status);
+ send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu, status);
+ }
+ else
+ {
+ if (avrc_cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION)
+ {
+ UINT8 event_id = avrc_cmd.reg_notif.event_id;
+ BTIF_TRACE_EVENT("%s:Register notification event_id: %s",
+ __FUNCTION__, dump_rc_notification_event_id(event_id));
+ }
+ else if (avrc_cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME)
+ {
+ BTIF_TRACE_EVENT("%s: Abs Volume Cmd Recvd", __FUNCTION__);
+ }
+ btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG("%s:Invalid Vendor Command code: %d len: %d. Not processing it.",
+ __FUNCTION__, pmeta_msg->code, pmeta_msg->len);
+ return;
+ }
+}
+#endif
+
/***************************************************************************
**
** Function cleanup
@@ -1627,6 +3293,729 @@
BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__);
}
+/***************************************************************************
+**
+** Function getcapabilities_cmd
+**
+** Description GetCapabilties from Remote(Company_ID, Events_Supported)
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t getcapabilities_cmd (uint8_t cap_id)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s: cap_id %d", __FUNCTION__, cap_id);
+ CHECK_RC_CONNECTED
+ bt_status_t tran_status=get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ avrc_cmd.get_caps.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_caps.capability_id = cap_id;
+ avrc_cmd.get_caps.pdu = AVRC_PDU_GET_CAPABILITIES;
+ avrc_cmd.get_caps.status = AVRC_STS_NO_ERROR;
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if ((status == AVRC_STS_NO_ERROR)&&(p_msg != NULL))
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,p_transaction->lbl);
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_GET_CAPABILITIES, p_transaction);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function list_player_app_setting_attrib_cmd
+**
+** Description Get supported List Player Attributes
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t list_player_app_setting_attrib_cmd(void)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s: ", __FUNCTION__);
+ CHECK_RC_CONNECTED
+ bt_status_t tran_status=get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ avrc_cmd.list_app_attr.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.list_app_attr.pdu = AVRC_PDU_LIST_PLAYER_APP_ATTR;
+ avrc_cmd.list_app_attr.status = AVRC_STS_NO_ERROR;
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if ((status == AVRC_STS_NO_ERROR)&&(p_msg != NULL))
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,p_transaction->lbl);
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_ATTR, p_transaction);
+ }
+ else
+ {
+
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (NULL!=p_msg)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function list_player_app_setting_value_cmd
+**
+** Description Get values of supported Player Attributes
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t list_player_app_setting_value_cmd(uint8_t attrib_id)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction=NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s: attrib_id %d", __FUNCTION__, attrib_id);
+ CHECK_RC_CONNECTED
+ bt_status_t tran_status=get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ avrc_cmd.list_app_values.attr_id = attrib_id;
+ avrc_cmd.list_app_values.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.list_app_values.pdu = AVRC_PDU_LIST_PLAYER_APP_VALUES;
+ avrc_cmd.list_app_values.status = AVRC_STS_NO_ERROR;
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,p_transaction->lbl);
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_LIST_PLAYER_APP_VALUES, p_transaction);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __FUNCTION__, status);
+ }
+ if (NULL!=p_msg)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function get_player_app_setting_cmd
+**
+** Description Get current values of Player Attributes
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib, uint8_t* attrib_ids)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+ int count = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s: num attrib_id %d", __FUNCTION__, num_attrib);
+ CHECK_RC_CONNECTED
+ bt_status_t tran_status=get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ avrc_cmd.get_cur_app_val.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_cur_app_val.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.get_cur_app_val.num_attr = num_attrib;
+ avrc_cmd.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
+
+ for (count = 0; count < num_attrib; count++)
+ {
+ avrc_cmd.get_cur_app_val.attrs[count] = attrib_ids[count];
+ }
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,p_transaction->lbl);
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_STATUS,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_GET_CUR_PLAYER_APP_VALUE, p_transaction);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function change_player_app_setting
+**
+** Description Set current values of Player Attributes
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t change_player_app_setting(bt_bdaddr_t *bd_addr, uint8_t num_attrib, uint8_t* attrib_ids, uint8_t* attrib_vals)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+ int count = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s: num attrib_id %d", __FUNCTION__, num_attrib);
+ CHECK_RC_CONNECTED
+ bt_status_t tran_status=get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ avrc_cmd.set_app_val.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.set_app_val.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.set_app_val.num_val = num_attrib;
+ avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
+ avrc_cmd.set_app_val.p_vals =
+ (tAVRC_APP_SETTING*)osi_getbuf(sizeof(tAVRC_APP_SETTING)*num_attrib);
+ if (avrc_cmd.set_app_val.p_vals == NULL)
+ {
+ BTIF_TRACE_ERROR("%s: alloc failed", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ for (count = 0; count < num_attrib; count++)
+ {
+ avrc_cmd.set_app_val.p_vals[count].attr_id = attrib_ids[count];
+ avrc_cmd.set_app_val.p_vals[count].attr_val = attrib_vals[count];
+ }
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL))
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,p_transaction->lbl);
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,AVRC_CMD_CTRL,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_control_command_timer (AVRC_PDU_SET_PLAYER_APP_VALUE, p_transaction);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+ osi_freebuf(avrc_cmd.set_app_val.p_vals);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function get_player_app_setting_attr_text_cmd
+**
+** Description Get text description for app attribute
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t get_player_app_setting_attr_text_cmd (UINT8 *attrs, UINT8 num_attrs)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+ int count = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ bt_status_t tran_status;
+ CHECK_RC_CONNECTED
+
+ BTIF_TRACE_DEBUG("%s: num attrs %d", __FUNCTION__, num_attrs);
+
+ tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
+ avrc_cmd.get_app_attr_txt.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_app_attr_txt.num_attr = num_attrs;
+
+ for (count = 0; count < num_attrs; count++)
+ {
+ avrc_cmd.get_app_attr_txt.attrs[count] = attrs[count];
+ }
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__, p_transaction->lbl);
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ AVRC_CMD_STATUS, data_start, p_msg->len);
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT, p_transaction);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __FUNCTION__, status);
+ }
+ if (NULL != p_msg)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function get_player_app_setting_val_text_cmd
+**
+** Description Get text description for app attribute values
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t get_player_app_setting_value_text_cmd (UINT8 *vals, UINT8 num_vals)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+ int count = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ bt_status_t tran_status;
+ CHECK_RC_CONNECTED
+
+ BTIF_TRACE_DEBUG("%s: num_vals %d", __FUNCTION__, num_vals);
+
+ tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT;
+ avrc_cmd.get_app_val_txt.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_app_val_txt.num_val = num_vals;
+
+ for (count = 0; count < num_vals; count++)
+ {
+ avrc_cmd.get_app_val_txt.vals[count] = vals[count];
+ }
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__, p_transaction->lbl);
+ if (p_msg != NULL)
+ {
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ AVRC_CMD_STATUS, data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT, p_transaction);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (NULL != p_msg)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function register_notification_cmd
+**
+** Description Send Command to register for a Notification ID
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t register_notification_cmd (UINT8 label, UINT8 event_id, UINT32 event_value)
+{
+
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ CHECK_RC_CONNECTED
+
+
+ BTIF_TRACE_DEBUG("%s: event_id %d event_value", __FUNCTION__, event_id, event_value);
+
+ avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.reg_notif.event_id = event_id;
+ avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_cmd.reg_notif.param = event_value;
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__, label);
+ if (p_msg != NULL)
+ {
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle, label, AVRC_CMD_NOTIF,
+ data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function get_element_attribute_cmd
+**
+** Description Get Element Attribute for attributeIds
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t get_element_attribute_cmd (uint8_t num_attribute, uint32_t *p_attr_ids)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction=NULL;
+ int count = 0;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ bt_status_t tran_status;
+ CHECK_RC_CONNECTED
+
+ BTIF_TRACE_DEBUG("%s: num_attribute %d attribute_id %d",
+ __FUNCTION__, num_attribute, p_attr_ids[0]);
+
+ tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_elem_attrs.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.get_elem_attrs.num_attr = num_attribute;
+ avrc_cmd.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+ for (count = 0; count < num_attribute; count++)
+ {
+ avrc_cmd.get_elem_attrs.attrs[count] = p_attr_ids[count];
+ }
+
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__, p_transaction->lbl);
+ if (p_msg != NULL)
+ {
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ AVRC_CMD_STATUS, data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_GET_ELEMENT_ATTR,
+ p_transaction);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function get_play_status_cmd
+**
+** Description Get Element Attribute for attributeIds
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t get_play_status_cmd(void)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t *p_transaction = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR *p_msg = NULL;
+ bt_status_t tran_status;
+ CHECK_RC_CONNECTED
+
+ BTIF_TRACE_DEBUG("%s: ", __FUNCTION__);
+ tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status)
+ return BT_STATUS_FAIL;
+
+ avrc_cmd.get_play_status.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+ avrc_cmd.get_play_status.status = AVRC_STS_NO_ERROR;
+ status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__, p_transaction->lbl);
+ if (p_msg != NULL)
+ {
+ BTA_AvVendorCmd(btif_rc_cb.rc_handle,p_transaction->lbl,
+ AVRC_CMD_STATUS, data_start, p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ start_status_command_timer (AVRC_PDU_GET_PLAY_STATUS, p_transaction);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+
+}
+
+/***************************************************************************
+**
+** Function set_volume_rsp
+**
+** Description Rsp for SetAbsoluteVolume Command
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t set_volume_rsp(bt_bdaddr_t *bd_addr, uint8_t abs_vol, uint8_t label)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ tAVRC_RESPONSE avrc_rsp;
+ BT_HDR *p_msg = NULL;
+ CHECK_RC_CONNECTED
+
+ BTIF_TRACE_DEBUG("%s: abs_vol %d", __FUNCTION__, abs_vol);
+
+ avrc_rsp.volume.opcode = AVRC_OP_VENDOR;
+ avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
+ avrc_rsp.volume.status = AVRC_STS_NO_ERROR;
+ avrc_rsp.volume.volume = abs_vol;
+ status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__, btif_rc_cb.rc_vol_label);
+ if (p_msg != NULL)
+ {
+ BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+ BTA_AV_RSP_ACCEPT, data_start, p_msg->len, 0);
+ status = BT_STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function send_register_abs_vol_rsp
+**
+** Description Rsp for Notification of Absolute Volume
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t volume_change_notification_rsp(bt_bdaddr_t *bd_addr, btrc_notification_type_t rsp_type,
+ uint8_t abs_vol, uint8_t label)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ tAVRC_RESPONSE avrc_rsp;
+ BT_HDR *p_msg = NULL;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s: rsp_type %d abs_vol %d", __FUNCTION__, rsp_type, abs_vol);
+ CHECK_RC_CONNECTED
+
+ avrc_rsp.reg_notif.opcode = AVRC_OP_VENDOR;
+ avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_rsp.reg_notif.status = AVRC_STS_NO_ERROR;
+ avrc_rsp.reg_notif.param.volume = abs_vol;
+ avrc_rsp.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
+
+ status = AVRC_BldResponse(btif_rc_cb.rc_handle, &avrc_rsp, &p_msg);
+ if (status == AVRC_STS_NO_ERROR)
+ {
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+ __FUNCTION__,label);
+ UINT8* data_start = (UINT8*)(p_msg + 1) + p_msg->offset;
+ BTA_AvVendorRsp(btif_rc_cb.rc_handle, label,
+ (rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM) ? AVRC_RSP_INTERIM : AVRC_RSP_CHANGED,
+ data_start, p_msg->len, 0);
+ if (p_msg != NULL)
+ osi_freebuf(p_msg);
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ if (NULL!=p_msg)
+ osi_freebuf(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+ __FUNCTION__, status);
+ }
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function send_groupnavigation_cmd
+**
+** Description Send Pass-Through command
+**
+** Returns void
+**
+***************************************************************************/
+static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code,
+ uint8_t key_state)
+{
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTLR_INCLUDED == TRUE)
+ rc_transaction_t *p_transaction=NULL;
+ BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
+ key_code, key_state);
+ CHECK_RC_CONNECTED
+ if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
+ {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction))
+ {
+ UINT8* p_buf = (UINT8*)osi_getbuf(AVRC_PASS_THRU_GROUP_LEN);
+ if (p_buf != NULL)
+ {
+ UINT8* start = p_buf;
+ UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
+ *(start)++ = 0;
+ UINT8_TO_BE_STREAM(start, key_code);
+ BTA_AvRemoteVendorUniqueCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+ (tBTA_AV_STATE)key_state, p_buf, AVRC_PASS_THRU_GROUP_LEN);
+ status = BT_STATUS_SUCCESS;
+ BTIF_TRACE_DEBUG("%s: succesfully sent group_navigation command to BTA",
+ __FUNCTION__);
+ }
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s: error in fetching transaction", __FUNCTION__);
+ }
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
+ }
+#else
+ BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+ return status;
+}
+
+/***************************************************************************
+**
+** Function send_passthrough_cmd
+**
+** Description Send Pass-Through command
+**
+** Returns void
+**
+***************************************************************************/
static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
@@ -1638,7 +4027,7 @@
if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)
{
bt_status_t tran_status = get_transaction(&p_transaction);
- if(BT_STATUS_SUCCESS == tran_status && NULL != p_transaction)
+ if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction)
{
BTA_AvRemoteCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
(tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
@@ -1682,6 +4071,10 @@
sizeof(bt_rc_ctrl_interface),
init_ctrl,
send_passthrough_cmd,
+ send_groupnavigation_cmd,
+ change_player_app_setting,
+ set_volume_rsp,
+ volume_change_notification_rsp,
cleanup_ctrl,
};
@@ -1725,8 +4118,12 @@
static void initialize_transaction(int lbl)
{
pthread_mutex_lock(&device.lbllock);
- if(lbl < MAX_TRANSACTIONS_PER_SESSION)
+ if (lbl < MAX_TRANSACTIONS_PER_SESSION)
{
+ if (device.transaction[lbl].tle_txn.in_use == TRUE)
+ {
+ clear_cmd_timeout (lbl);
+ }
device.transaction[lbl].lbl = lbl;
device.transaction[lbl].in_use=FALSE;
device.transaction[lbl].handle=0;
@@ -1746,6 +4143,7 @@
memset(&device,0,sizeof(rc_device_t));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&(device.lbllock), &attr);
pthread_mutexattr_destroy(&attr);
init_all_transactions();
diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
index fc8f166..6da4514 100644
--- a/btif/src/btif_storage.c
+++ b/btif/src/btif_storage.c
@@ -670,6 +670,12 @@
p_uuid+num_uuids);
num_uuids++;
}break;
+ case BTA_A2DP_SINK_SERVICE_ID:
+ {
+ uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SINK,
+ p_uuid+num_uuids);
+ num_uuids++;
+ }break;
case BTA_HFP_HS_SERVICE_ID:
{
uuid16_to_uuid128(UUID_SERVCLASS_HF_HANDSFREE,
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
index fffd61d..45aa1b8 100644
--- a/btif/src/btif_util.c
+++ b/btif/src/btif_util.c
@@ -525,6 +525,9 @@
CASE_RETURN_STR(AVRC_PDU_REQUEST_CONTINUATION_RSP)
CASE_RETURN_STR(AVRC_PDU_ABORT_CONTINUATION_RSP)
CASE_RETURN_STR(AVRC_PDU_SET_ABSOLUTE_VOLUME)
+ CASE_RETURN_STR(AVRC_PDU_SET_ADDRESSED_PLAYER)
+ CASE_RETURN_STR(AVRC_PDU_CHANGE_PATH)
+ CASE_RETURN_STR(AVRC_PDU_GET_CAPABILITIES)
default:
return "Unknown PDU";
}
diff --git a/include/bt_target.h b/include/bt_target.h
index eff6485..e41f036 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -87,7 +87,7 @@
#endif
#ifndef BTA_AV_SINK_INCLUDED
-#define BTA_AV_SINK_INCLUDED FALSE
+#define BTA_AV_SINK_INCLUDED TRUE
#endif
#ifndef BTA_DISABLE_DELAY
diff --git a/main/Android.mk b/main/Android.mk
index 2ae5783..c68c17f 100644
--- a/main/Android.mk
+++ b/main/Android.mk
@@ -21,6 +21,7 @@
# BTIF
LOCAL_SRC_FILES += \
../btif/src/btif_av.c \
+ ../btif/src/btif_avrcp_audio_track.cpp \
../btif/src/btif_config.c \
../btif/src/btif_config_transcode.cpp \
../btif/src/btif_core.c \
@@ -127,7 +128,10 @@
libcutils \
libdl \
liblog \
- libz
+ libz \
+ libpower \
+ libmedia \
+ libutils
LOCAL_STATIC_LIBRARIES := \
libtinyxml2 \
diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c
index fa9f9cc..ea754c7 100644
--- a/stack/avdt/avdt_api.c
+++ b/stack/avdt/avdt_api.c
@@ -183,7 +183,6 @@
if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
{
AVDT_TRACE_DEBUG("AVDT_SINK_Activate found scb");
- p_scb->sink_activated = TRUE;
/* update in_use */
p_scb->in_use = FALSE;
break;
@@ -214,7 +213,6 @@
if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
{
AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate, found scb");
- p_scb->sink_activated = FALSE;
/* update in_use */
p_scb->in_use = TRUE;
break;
diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h
index e3c9f3f..f87fcfa 100644
--- a/stack/avdt/avdt_int.h
+++ b/stack/avdt/avdt_int.h
@@ -489,7 +489,6 @@
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 6e73c2e..f7d3c9c 100644
--- a/stack/avdt/avdt_scb.c
+++ b/stack/avdt/avdt_scb.c
@@ -599,12 +599,6 @@
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 de072b3..8e74520 100644
--- a/stack/avdt/avdt_scb_act.c
+++ b/stack/avdt/avdt_scb_act.c
@@ -2073,15 +2073,7 @@
void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
{
UNUSED(p_data);
-
- 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->in_use = FALSE;
p_scb->p_ccb = NULL;
p_scb->peer_seid = 0;
}
diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
old mode 100755
new mode 100644
index a4357cf..88758cf
--- a/stack/avrc/avrc_api.c
+++ b/stack/avrc/avrc_api.c
@@ -375,6 +375,7 @@
BT_HDR *p_pkt = *pp_pkt;
UINT8 *p_data;
UINT8 drop_code = 0;
+ BOOLEAN buf_overflow = FALSE;
BT_HDR *p_rsp = NULL;
BT_HDR *p_cmd = NULL;
BOOLEAN req_continue = FALSE;
@@ -466,6 +467,7 @@
AVRC_TRACE_WARNING("Fragmented message too big! - report the partial message");
p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
pkt_type = AVRC_PKT_END;
+ buf_overflow = true;
}
/* copy contents of p_pkt to p_rx_msg */
@@ -529,6 +531,20 @@
AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
}
}
+ /*
+ * Drop it if we are out of buffer
+ */
+ else if (cr == AVCT_RSP && req_continue == FALSE && buf_overflow == TRUE)
+ {
+ avrc_cmd.pdu = AVRC_PDU_ABORT_CONTINUATION_RSP;
+ avrc_cmd.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.target_pdu = p_rcb->rasm_pdu;
+ if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
+ {
+ drop_code = 4;
+ AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
+ }
+ }
}
return drop_code;
@@ -856,6 +872,7 @@
{
memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
p_data += p_msg->pass_len;
+ osi_freebuf(p_msg->p_pass_data);
}
}
else /* set msg len to 0 for other op_id */
diff --git a/stack/avrc/avrc_bld_ct.c b/stack/avrc/avrc_bld_ct.c
index 2e4f89a..f09d9a5 100644
--- a/stack/avrc/avrc_bld_ct.c
+++ b/stack/avrc/avrc_bld_ct.c
@@ -88,27 +88,263 @@
/*******************************************************************************
**
-** Function avrc_bld_vol_change_notfn
+** Function avrc_bld_register_notifn
**
-** Description This function builds the register notification for volume change.
+** Description This function builds the register notification.
**
** Returns AVRC_STS_NO_ERROR, if the command is built successfully
** Otherwise, the error code.
**
*******************************************************************************/
-static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR * p_pkt)
+static tAVRC_STS avrc_bld_register_notifn(BT_HDR * p_pkt, UINT8 event_id, UINT32 event_param)
{
UINT8 *p_data, *p_start;
- AVRC_TRACE_API("avrc_bld_vol_change");
+ AVRC_TRACE_API("avrc_bld_register_notifn");
/* get the existing length, if any, and also the num attributes */
// Set the notify value
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_start + 2; /* pdu + rsvd */
/* add fixed length 5 -*/
UINT16_TO_BE_STREAM(p_data, 5);
- UINT8_TO_BE_STREAM(p_data,AVRC_EVT_VOLUME_CHANGE);
- UINT32_TO_BE_STREAM(p_data, 0);
+ UINT8_TO_BE_STREAM(p_data,event_id);
+ UINT32_TO_BE_STREAM(p_data, event_param);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_capability_cmd
+**
+** Description This function builds the get capability command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR * p_pkt, UINT8 cap_id)
+{
+ AVRC_TRACE_API("avrc_bld_get_capability_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data,cap_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_list_player_app_attr_cmd
+**
+** Description This function builds the list player app attrib command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR * p_pkt)
+{
+ AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 0);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_list_player_app_values_cmd
+**
+** Description This function builds the list player app values command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR * p_pkt, UINT8 attrib_id)
+{
+ AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data,attrib_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_current_player_app_values_cmd
+**
+** Description This function builds the get current player app setting values command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(
+ BT_HDR * p_pkt, UINT8 num_attrib_id, UINT8* attrib_ids)
+{
+ AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ UINT8 param_len = num_attrib_id + 1; // 1 additional to hold num attributes feild
+ /* add length -*/
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data,num_attrib_id);
+ for(int count = 0; count < num_attrib_id; count ++)
+ {
+ UINT8_TO_BE_STREAM(p_data,attrib_ids[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_set_current_player_app_values_cmd
+**
+** Description This function builds the set current player app setting values command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt, UINT8 num_attrib_id, tAVRC_APP_SETTING* p_val)
+{
+ AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ /* we have to store attrib- value pair
+ * 1 additional to store num elements
+ */
+ UINT8 param_len = (2*num_attrib_id) + 1;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data,num_attrib_id);
+ for(int count = 0; count < num_attrib_id; count ++)
+ {
+ UINT8_TO_BE_STREAM(p_data,p_val[count].attr_id);
+ UINT8_TO_BE_STREAM(p_data,p_val[count].attr_val);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_player_app_setting_attr_text_cmd
+**
+** Description This function builds the get player app setting attribute text command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD *p_cmd)
+{
+ AVRC_TRACE_API("%s", __FUNCTION__);
+
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+
+ UINT8 param_len = p_cmd->num_attr + 1;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
+ for(int count = 0; count < p_cmd->num_attr; count++)
+ {
+ UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_player_app_setting_value_text_cmd
+**
+** Description This function builds the get player app setting value text command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_VAL_TXT_CMD *p_cmd)
+{
+ AVRC_TRACE_API("%s", __FUNCTION__);
+
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+
+ UINT8 param_len = p_cmd->num_val + 1;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
+ for(int count = 0; count < p_cmd->num_val; count++)
+ {
+ UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_element_attr_cmd
+**
+** Description This function builds the get element attribute command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt, UINT8 num_attrib, UINT32* attrib_ids)
+{
+ AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ /* we have to store attrib- value pair
+ * 1 additional to store num elements
+ */
+ UINT8 param_len = (4*num_attrib) + 9;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ /* 8 bytes of identifier as 0 (playing)*/
+ UINT32_TO_BE_STREAM(p_data,0);
+ UINT32_TO_BE_STREAM(p_data,0);
+ UINT8_TO_BE_STREAM(p_data,num_attrib);
+ for(int count = 0; count < num_attrib; count ++)
+ {
+ UINT32_TO_BE_STREAM(p_data,attrib_ids[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function avrc_bld_get_play_status_cmd
+**
+** Description This function builds the get play status command.
+**
+** Returns AVRC_STS_NO_ERROR, if the command is built successfully
+** Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)
+{
+ AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 0);
p_pkt->len = (p_data - p_start);
return AVRC_STS_NO_ERROR;
}
@@ -126,14 +362,10 @@
*******************************************************************************/
static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
{
- UINT16 offset = 0;
- UINT16 chnl = AVCT_DATA_CTRL;
- UINT16 len = AVRC_META_CMD_BUF_SIZE;
- BT_HDR *p_pkt = NULL;
UINT8 opcode = avrc_opcode_from_pdu(p_cmd->pdu);
-
AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
+ UINT16 offset = 0;
switch (opcode)
{
case AVRC_OP_PASS_THRU:
@@ -146,12 +378,12 @@
}
/* allocate and initialize the buffer */
- p_pkt = (BT_HDR *)osi_getbuf(len);
+ BT_HDR *p_pkt = (BT_HDR *)osi_getbuf(AVRC_META_CMD_BUF_SIZE);
if (p_pkt)
{
UINT8 *p_data, *p_start;
- p_pkt->layer_specific = chnl;
+ p_pkt->layer_specific = AVCT_DATA_CTRL;
p_pkt->event = opcode;
p_pkt->offset = offset;
p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
@@ -192,9 +424,7 @@
tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
{
tAVRC_STS status = AVRC_STS_BAD_PARAM;
- BT_HDR *p_pkt;
BOOLEAN alloc = FALSE;
-
AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status);
if (!p_cmd || !pp_pkt)
{
@@ -213,7 +443,7 @@
alloc = TRUE;
}
status = AVRC_STS_NO_ERROR;
- p_pkt = *pp_pkt;
+ BT_HDR* p_pkt = *pp_pkt;
switch (p_cmd->pdu)
{
@@ -229,14 +459,41 @@
status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
break;
#endif
-
- case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
- if(AVRC_EVT_VOLUME_CHANGE==p_cmd->reg_notif.event_id)
- status=avrc_bld_vol_change_notfn(p_pkt);
-#endif
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ status=avrc_bld_register_notifn(p_pkt,p_cmd->reg_notif.event_id,p_cmd->reg_notif.param);
break;
-
+ case AVRC_PDU_GET_CAPABILITIES:
+ status = avrc_bld_get_capability_cmd(p_pkt, p_cmd->get_caps.capability_id);
+ break;
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ status = avrc_bld_list_player_app_attr_cmd(p_pkt);
+ break;
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ status = avrc_bld_list_player_app_values_cmd(p_pkt,p_cmd->list_app_values.attr_id);
+ break;
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ status = avrc_bld_get_current_player_app_values_cmd(p_pkt,
+ p_cmd->get_cur_app_val.num_attr,p_cmd->get_cur_app_val.attrs);
+ break;
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ status = avrc_bld_set_current_player_app_values_cmd(p_pkt,
+ p_cmd->set_app_val.num_val,p_cmd->set_app_val.p_vals);
+ break;
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt, &p_cmd->get_app_attr_txt);
+ break;
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ avrc_bld_get_player_app_setting_value_text_cmd(p_pkt, &p_cmd->get_app_val_txt);
+ break;
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ status = avrc_bld_get_element_attr_cmd(p_pkt,
+ p_cmd->get_elem_attrs.num_attr,p_cmd->get_elem_attrs.attrs);
+ break;
+ case AVRC_PDU_GET_PLAY_STATUS:
+ status = avrc_bld_get_play_status_cmd(p_pkt);
+ break;
+#endif
}
if (alloc && (status != AVRC_STS_NO_ERROR) )
@@ -248,4 +505,3 @@
return status;
}
#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
-
diff --git a/stack/avrc/avrc_bld_tg.c b/stack/avrc/avrc_bld_tg.c
index 90f2769..e06f711 100644
--- a/stack/avrc/avrc_bld_tg.c
+++ b/stack/avrc/avrc_bld_tg.c
@@ -49,12 +49,12 @@
if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id)))
{
- AVRC_TRACE_ERROR("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp);
+ AVRC_TRACE_ERROR("%s bad parameter. p_rsp: %x", __func__, p_rsp);
status = AVRC_STS_BAD_PARAM;
return status;
}
- AVRC_TRACE_API("avrc_bld_get_capability_rsp");
+ AVRC_TRACE_API("%s", __func__);
/* get the existing length, if any, and also the num attributes */
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -122,7 +122,7 @@
UINT16 len = 0;
UINT8 xx;
- AVRC_TRACE_API("avrc_bld_list_app_settings_attr_rsp");
+ AVRC_TRACE_API("%s", __func__);
/* get the existing length, if any, and also the num attributes */
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -174,7 +174,7 @@
UINT8 xx;
UINT16 len;
- AVRC_TRACE_API("avrc_bld_list_app_settings_values_rsp");
+ AVRC_TRACE_API("%s", __func__);
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -226,11 +226,11 @@
if (!p_rsp->p_vals)
{
- AVRC_TRACE_ERROR("avrc_bld_get_cur_app_setting_value_rsp NULL parameter");
+ AVRC_TRACE_ERROR("%s NULL parameter", __func__);
return AVRC_STS_BAD_PARAM;
}
- AVRC_TRACE_API("avrc_bld_get_cur_app_setting_value_rsp");
+ AVRC_TRACE_API("%s", __func__);
/* get the existing length, if any, and also the num attributes */
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -281,7 +281,7 @@
UNUSED(p_pkt);
/* nothing to be added. */
- AVRC_TRACE_API("avrc_bld_set_app_setting_value_rsp");
+ AVRC_TRACE_API("%s", __func__);
return AVRC_STS_NO_ERROR;
}
@@ -306,7 +306,7 @@
if (!p_rsp->p_attrs)
{
- AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp NULL parameter");
+ AVRC_TRACE_ERROR("%s NULL parameter", __func__);
return AVRC_STS_BAD_PARAM;
}
/* get the existing length, if any, and also the num attributes */
@@ -331,15 +331,15 @@
{
if (len_left < (p_rsp->p_attrs[xx].str_len + 4))
{
- AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)",
- xx, p_rsp->p_attrs[xx].str_len, len_left);
+ AVRC_TRACE_ERROR("%s out of room (str_len:%d, left:%d)",
+ __func__, xx, p_rsp->p_attrs[xx].str_len, len_left);
p_rsp->num_attr = num_added;
sts = AVRC_STS_INTERNAL_ERR;
break;
}
if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str )
{
- AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx);
+ AVRC_TRACE_ERROR("%s NULL attr text[%d]", __func__, xx);
continue;
}
UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
@@ -370,7 +370,7 @@
static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
BT_HDR *p_pkt)
{
- AVRC_TRACE_API("avrc_bld_get_app_setting_attr_text_rsp");
+ AVRC_TRACE_API("%s", __func__);
return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
}
@@ -388,7 +388,7 @@
static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
BT_HDR *p_pkt)
{
- AVRC_TRACE_API("avrc_bld_get_app_setting_value_text_rsp");
+ AVRC_TRACE_API("%s", __func__);
return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
}
@@ -409,7 +409,7 @@
UNUSED(p_pkt);
/* nothing to be added. */
- AVRC_TRACE_API("avrc_bld_inform_charset_rsp");
+ AVRC_TRACE_API("%s", __func__);
return AVRC_STS_NO_ERROR;
}
@@ -430,7 +430,7 @@
UNUSED(p_pkt);
/* nothing to be added. */
- AVRC_TRACE_API("avrc_bld_inform_battery_status_rsp");
+ AVRC_TRACE_API("%s", __func__);
return AVRC_STS_NO_ERROR;
}
@@ -451,10 +451,10 @@
UINT16 len;
UINT8 xx;
- AVRC_TRACE_API("avrc_bld_get_elem_attrs_rsp");
+ AVRC_TRACE_API("%s", __func__);
if (!p_rsp->p_attrs)
{
- AVRC_TRACE_ERROR("avrc_bld_get_elem_attrs_rsp NULL parameter");
+ AVRC_TRACE_ERROR("%s NULL parameter", __func__);
return AVRC_STS_BAD_PARAM;
}
@@ -479,7 +479,8 @@
{
if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id))
{
- AVRC_TRACE_ERROR("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, p_rsp->p_attrs[xx].attr_id);
+ AVRC_TRACE_ERROR("%s invalid attr id[%d]: %d",
+ __func__, xx, p_rsp->p_attrs[xx].attr_id);
continue;
}
if ( !p_rsp->p_attrs[xx].name.p_str )
@@ -545,7 +546,7 @@
UINT8 xx;
tAVRC_STS status = AVRC_STS_NO_ERROR;
- AVRC_TRACE_API("avrc_bld_notify_rsp");
+ AVRC_TRACE_API("%s event_id %d", __func__, p_rsp->event_id);
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_len = p_start + 2; /* pdu + rsvd */
@@ -564,7 +565,7 @@
}
else
{
- AVRC_TRACE_ERROR("bad play state");
+ AVRC_TRACE_ERROR("%s bad play state", __func__);
status = AVRC_STS_BAD_PARAM;
}
break;
@@ -592,7 +593,7 @@
}
else
{
- AVRC_TRACE_ERROR("bad battery status");
+ AVRC_TRACE_ERROR("%s bad battery status", __func__);
status = AVRC_STS_BAD_PARAM;
}
break;
@@ -605,7 +606,7 @@
}
else
{
- AVRC_TRACE_ERROR("bad system status");
+ AVRC_TRACE_ERROR("%s bad system status", __func__);
status = AVRC_STS_BAD_PARAM;
}
break;
@@ -628,7 +629,7 @@
}
else
{
- AVRC_TRACE_ERROR("bad player app seeting attribute or value");
+ AVRC_TRACE_ERROR("%s bad player app seeting attribute or value", __func__);
status = AVRC_STS_BAD_PARAM;
break;
}
@@ -639,9 +640,14 @@
status = AVRC_STS_BAD_PARAM;
break;
+ case AVRC_EVT_VOLUME_CHANGE:
+ len = 2;
+ UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_rsp->param.volume));
+ break;
+
default:
status = AVRC_STS_BAD_PARAM;
- AVRC_TRACE_ERROR("unknown event_id");
+ AVRC_TRACE_ERROR("%s unknown event_id", __func__);
}
UINT16_TO_BE_STREAM(p_len, len);
@@ -667,7 +673,73 @@
UNUSED(p_pkt);
/* nothing to be added. */
- AVRC_TRACE_API("avrc_bld_next_rsp");
+ AVRC_TRACE_API("%s", __func__);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**
+** Function avrc_bld_set_address_player_rsp
+**
+** Description This function builds the set address player response
+**
+** Returns AVRC_STS_NO_ERROR
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_set_address_player_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API("%s", __func__);
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* To calculate length */
+ UINT8 *p_data = p_start + 2;
+ /* add fixed lenth status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**
+** Function avrc_bld_play_item_rsp
+**
+** Description This function builds the play item response
+**
+** Returns AVRC_STS_NO_ERROR, if the response is build successfully
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API("%s", __func__);
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* To calculate length */
+ UINT8 *p_data = p_start + 2;
+ /* add fixed lenth status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**
+** Function avrc_bld_set_absolute_volume_rsp
+**
+** Description This function builds the set absolute volume response
+**
+** Returns AVRC_STS_NO_ERROR, if the response is build successfully
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR *p_pkt)
+{
+ AVRC_TRACE_API("%s", __func__);
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* To calculate length */
+ UINT8 *p_data = p_start + 2;
+ /* add fixed lenth status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, abs_vol);
+ p_pkt->len = (p_data - p_start);
return AVRC_STS_NO_ERROR;
}
@@ -684,16 +756,13 @@
*******************************************************************************/
tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt)
{
- UINT8 *p_data;
-
if (!AVRC_IS_VALID_GROUP(navi_id))
{
- AVRC_TRACE_ERROR("avrc_bld_group_navigation_rsp bad navigation op id: %d", navi_id);
+ AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id);
return AVRC_STS_BAD_PARAM;
}
-
- AVRC_TRACE_API("avrc_bld_group_navigation_rsp");
- p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ AVRC_TRACE_API("%s", __func__);
+ UINT8 *p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
UINT16_TO_BE_STREAM(p_data, navi_id);
p_pkt->len = 2;
return AVRC_STS_NO_ERROR;
@@ -706,18 +775,15 @@
** Description This function builds the General Response response.
**
** Returns AVRC_STS_NO_ERROR, if the response is built successfully
-** Otherwise, the error code.
**
*******************************************************************************/
static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
{
- UINT8 *p_data, *p_start;
+ AVRC_TRACE_API("%s: status=%d, pdu:x%x", __func__, p_rsp->status, p_rsp->pdu);
- AVRC_TRACE_API("avrc_bld_rejected_rsp: status=%d, pdu:x%x", p_rsp->status, p_rsp->pdu);
-
- p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
- p_data = p_start + 2;
- AVRC_TRACE_DEBUG("pdu:x%x", *p_start);
+ UINT8 *p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ UINT8 *p_data = p_start + 2;
+ AVRC_TRACE_DEBUG("%s pdu:x%x", __func__, *p_start);
UINT16_TO_BE_STREAM(p_data, 1);
UINT8_TO_BE_STREAM(p_data, p_rsp->status);
@@ -744,13 +810,12 @@
BT_HDR *p_pkt = NULL;
UINT8 opcode = avrc_opcode_from_pdu(p_rsp->pdu);
- AVRC_TRACE_API("avrc_bld_init_rsp_buffer: pdu=%x, opcode=%x/%x", p_rsp->pdu, opcode,
- p_rsp->rsp.opcode);
+ AVRC_TRACE_API("%s: pdu=%x, opcode=%x/%x", __func__, p_rsp->pdu, opcode, p_rsp->rsp.opcode);
if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR &&
avrc_is_valid_opcode(p_rsp->rsp.opcode))
{
opcode = p_rsp->rsp.opcode;
- AVRC_TRACE_API("opcode=%x", opcode);
+ AVRC_TRACE_API("%s opcode=%x", __func__, opcode);
}
switch (opcode)
@@ -819,8 +884,8 @@
if (!p_rsp || !pp_pkt)
{
- AVRC_TRACE_API("AVRC_BldResponse. Invalid parameters passed. p_rsp=%p, pp_pkt=%p",
- p_rsp, pp_pkt);
+ AVRC_TRACE_API("%s Invalid parameters passed. p_rsp=%p, pp_pkt=%p",
+ __func__, p_rsp, pp_pkt);
return AVRC_STS_BAD_PARAM;
}
@@ -828,7 +893,7 @@
{
if ((*pp_pkt = avrc_bld_init_rsp_buffer(p_rsp)) == NULL)
{
- AVRC_TRACE_API("AVRC_BldResponse: Failed to initialize response buffer");
+ AVRC_TRACE_API("%s Failed to initialize response buffer", __func__);
return AVRC_STS_INTERNAL_ERR;
}
alloc = TRUE;
@@ -836,7 +901,7 @@
status = AVRC_STS_NO_ERROR;
p_pkt = *pp_pkt;
- AVRC_TRACE_API("AVRC_BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status);
+ AVRC_TRACE_API("%s pdu=%x status=%x", __func__, p_rsp->rsp.pdu, p_rsp->rsp.status);
if (p_rsp->rsp.status != AVRC_STS_NO_ERROR)
{
return( avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt) );
@@ -904,6 +969,18 @@
case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt);
break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /*PDU 0x60*/
+ status = avrc_bld_set_address_player_rsp(&p_rsp->addr_player, p_pkt);
+ break;
+
+ case AVRC_PDU_PLAY_ITEM:
+ status = avrc_bld_play_item_rsp(&p_rsp->play_item, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+ status = avrc_bld_set_absolute_volume_rsp(p_rsp->volume.volume, p_pkt);
+ break;
}
if (alloc && (status != AVRC_STS_NO_ERROR) )
@@ -911,7 +988,7 @@
osi_freebuf(p_pkt);
*pp_pkt = NULL;
}
- AVRC_TRACE_API("AVRC_BldResponse: returning %d", status);
+ AVRC_TRACE_API("%s returning %d", __func__, status);
return status;
}
diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c
index a1f5c37..d6b2d14 100644
--- a/stack/avrc/avrc_pars_ct.c
+++ b/stack/avrc/avrc_pars_ct.c
@@ -57,7 +57,8 @@
BE_STREAM_TO_UINT8 (p_result->pdu, p);
p++; /* skip the reserved/packe_type byte */
BE_STREAM_TO_UINT16 (len, p);
- AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len);
+ AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x",
+ __func__, p_msg->hdr.ctype, p_result->pdu, len, len);
if (p_msg->hdr.ctype == AVRC_RSP_REJ)
{
p_result->rsp.status = *p;
@@ -91,8 +92,8 @@
p_result->reg_notif.event_id=eventid;
BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
}
- AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid,
- p_result->reg_notif.param.volume);
+ AVRC_TRACE_DEBUG("%s PDU reg notif response:event %x, volume %x",
+ __func__, eventid, p_result->reg_notif.param.volume);
#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
break;
default:
@@ -102,6 +103,357 @@
return status;
}
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+void avrc_parse_notification_rsp (UINT8 *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
+{
+ BE_STREAM_TO_UINT8(p_rsp->event_id, p_stream);
+ switch (p_rsp->event_id)
+ {
+ case AVRC_EVT_PLAY_STATUS_CHANGE:
+ BE_STREAM_TO_UINT8(p_rsp->param.play_status, p_stream);
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE:
+ BE_STREAM_TO_ARRAY(p_stream, p_rsp->param.track, 8);
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE:
+ BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
+ for (int index = 0; index < p_rsp->param.player_setting.num_attr; index++)
+ {
+ BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index], p_stream);
+ BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_value[index], p_stream);
+ }
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ break;
+
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE:
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END:
+ case AVRC_EVT_TRACK_REACHED_START:
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avrc_ctrl_pars_vendor_rsp
+**
+** Description This function parses the vendor specific commands defined by
+** Bluetooth SIG
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
+ tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result, UINT8* p_buf, UINT16* buf_len)
+{
+ UINT8 *p = p_msg->p_vendor_data;
+ BE_STREAM_TO_UINT8 (p_result->pdu, p);
+ p++; /* skip the reserved/packe_type byte */
+
+ UINT16 len;
+ BE_STREAM_TO_UINT16 (len, p);
+ AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d",
+ __func__, p_msg->hdr.ctype, p_result->pdu, len);
+ /* Todo: Issue in handling reject, check */
+ if (p_msg->hdr.ctype == AVRC_RSP_REJ)
+ {
+ p_result->rsp.status = *p;
+ return p_result->rsp.status;
+ }
+
+ /* TODO: Break the big switch into functions. */
+ switch (p_result->pdu)
+ {
+ /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ avrc_parse_notification_rsp(p, &p_result->reg_notif);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ if (len == 0)
+ {
+ p_result->get_caps.count = 0;
+ p_result->get_caps.capability_id = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->get_caps.capability_id, p);
+ BE_STREAM_TO_UINT8(p_result->get_caps.count, p);
+ AVRC_TRACE_DEBUG("%s cap id = %d, cap_count = %d ",
+ __func__, p_result->get_caps.capability_id, p_result->get_caps.count);
+ if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID)
+ {
+ for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_COMP_ID));
+ xx++)
+ {
+ BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[xx], p);
+ }
+ }
+ else if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED)
+ {
+ for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_EVT_ID));
+ xx++)
+ {
+ BE_STREAM_TO_UINT8(p_result->get_caps.param.event_id[xx], p);
+ }
+ }
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ if (len == 0)
+ {
+ p_result->list_app_attr.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p);
+ AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->list_app_attr.num_attr);
+ for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
+ {
+ BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
+ }
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ if (len == 0)
+ {
+ p_result->list_app_values.num_val = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
+ AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
+ for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
+ {
+ BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
+ }
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ {
+ tAVRC_APP_SETTING *app_sett;
+ if (len == 0)
+ {
+ p_result->get_cur_app_val.num_val = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_val, p);
+ app_sett =
+ (tAVRC_APP_SETTING*)osi_getbuf(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
+ AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
+ for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
+ {
+ BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
+ BE_STREAM_TO_UINT8(app_sett[xx].attr_val, p);
+ }
+ p_result->get_cur_app_val.p_vals = app_sett;
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ {
+ tAVRC_APP_SETTING_TEXT *p_setting_text;
+ UINT8 num_attrs;
+
+ if (len == 0)
+ {
+ p_result->get_app_attr_txt.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(num_attrs, p);
+ AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_app_attr_txt.num_attr);
+ p_result->get_app_attr_txt.num_attr = num_attrs;
+ p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_getbuf(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
+ if (p_setting_text == NULL)
+ {
+ p_result->get_app_attr_txt.num_attr = 0;
+ AVRC_TRACE_ERROR("%s alloc fail", __FUNCTION__);
+ break;
+ }
+ for (int xx = 0; xx < num_attrs; xx++)
+ {
+ UINT8 *p_str;
+
+ BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
+ BE_STREAM_TO_UINT16(p_result->get_app_attr_txt.p_attrs[xx].charset_id, p);
+ BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].str_len, p);
+ if (p_result->get_app_attr_txt.p_attrs[xx].str_len != 0)
+ {
+ p_str = (UINT8*)osi_getbuf(p_result->get_app_attr_txt.p_attrs[xx].str_len);
+ if (p_str != NULL)
+ {
+ BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_attr_txt.p_attrs[xx].str_len);
+ p_result->get_app_attr_txt.p_attrs[xx].p_str = p_str;
+ }
+ else
+ {
+ p_result->get_app_attr_txt.p_attrs[xx].str_len = 0;
+ AVRC_TRACE_ERROR("%s alloc failed for text", __FUNCTION__);
+ }
+ }
+ else
+ {
+ p_result->get_app_attr_txt.p_attrs[xx].p_str = NULL;
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ {
+ tAVRC_APP_SETTING_TEXT *p_setting_text;
+ UINT8 num_vals;
+
+ if (len == 0)
+ {
+ p_result->get_app_val_txt.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(num_vals, p);
+ p_result->get_app_val_txt.num_attr = num_vals;
+ AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->get_app_val_txt.num_attr);
+
+ p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_getbuf(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
+ if (p_setting_text == NULL)
+ {
+ p_result->get_app_attr_txt.num_attr = 0;
+ AVRC_TRACE_ERROR("%s alloc fail", __FUNCTION__);
+ break;
+ }
+ for (int xx = 0; xx < num_vals; xx++)
+ {
+ UINT8 *p_str;
+
+ BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[xx].attr_id, p);
+ BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[xx].charset_id, p);
+ BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[xx].str_len, p);
+ if (p_result->get_app_val_txt.p_attrs[xx].str_len != 0)
+ {
+ p_str = (UINT8*)osi_getbuf(p_result->get_app_val_txt.p_attrs[xx].str_len);
+ if (p_str != NULL)
+ {
+ BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_val_txt.p_attrs[xx].str_len);
+ p_result->get_app_val_txt.p_attrs[xx].p_str = p_str;
+ }
+ else
+ {
+ p_result->get_app_val_txt.p_attrs[xx].str_len = 0;
+ AVRC_TRACE_ERROR("%s alloc failed for value text", __FUNCTION__);
+ }
+ }
+ else
+ {
+ p_result->get_app_val_txt.p_attrs[xx].p_str = NULL;
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ /* nothing comes as part of this rsp */
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ {
+ tAVRC_ATTR_ENTRY *p_attrs;
+ UINT8 num_attrs;
+
+ if (len <= 0)
+ {
+ p_result->get_elem_attrs.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(num_attrs, p);
+ p_result->get_elem_attrs.num_attr = num_attrs;
+ if (num_attrs)
+ {
+ p_attrs = (tAVRC_ATTR_ENTRY*)osi_getbuf(num_attrs * sizeof(tAVRC_ATTR_ENTRY));
+ for (int xx = 0; xx < num_attrs; xx++)
+ {
+ BE_STREAM_TO_UINT32(p_attrs[xx].attr_id, p);
+ BE_STREAM_TO_UINT16(p_attrs[xx].name.charset_id, p);
+ BE_STREAM_TO_UINT16(p_attrs[xx].name.str_len, p);
+ if (p_attrs[xx].name.str_len > 0)
+ {
+ p_attrs[xx].name.p_str = (UINT8*)osi_getbuf(p_attrs[xx].name.str_len);
+ if (p_attrs[xx].name.p_str != NULL)
+ {
+ BE_STREAM_TO_ARRAY(p, p_attrs[xx].name.p_str, p_attrs[xx].name.str_len);
+ }
+ else
+ {
+ p_attrs[xx].name.str_len = 0;
+ AVRC_TRACE_ERROR("%s : alloc failed for attribute", __FUNCTION__);
+ }
+ }
+ }
+ p_result->get_elem_attrs.p_attrs = p_attrs;
+ }
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ if (len == 0)
+ {
+ break;
+ }
+ BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
+ BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
+ BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+ break;
+
+ default:
+ return AVRC_STS_BAD_CMD;
+ }
+ return AVRC_STS_NO_ERROR;
+}
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function AVRC_Ctrl_ParsResponse
+**
+** Description This function is a parse response for AVRCP Controller.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16* buf_len)
+{
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+ if (p_msg && p_result)
+ {
+ switch (p_msg->hdr.opcode)
+ {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf,buf_len);
+ break;
+
+ default:
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+ break;
+ }
+ p_result->rsp.opcode = p_msg->hdr.opcode;
+ p_result->rsp.status = status;
+ }
+ return status;
+}
/*******************************************************************************
**
@@ -137,7 +489,7 @@
break;
default:
- AVRC_TRACE_ERROR("AVRC_ParsResponse() unknown opcode:0x%x", p_msg->hdr.opcode);
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
break;
}
p_result->rsp.opcode = p_msg->hdr.opcode;
@@ -145,6 +497,4 @@
}
return status;
}
-
-
#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c
index 60503c9..3f3fe93 100644
--- a/stack/avrc/avrc_pars_tg.c
+++ b/stack/avrc/avrc_pars_tg.c
@@ -27,6 +27,67 @@
*****************************************************************************/
#if (AVRC_METADATA_INCLUDED == TRUE)
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function avrc_ctrl_pars_vendor_cmd
+**
+** Description This function parses the vendor specific commands defined by
+** Bluetooth SIG for AVRCP Conroller.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result)
+{
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ UINT8 *p = p_msg->p_vendor_data;
+ p_result->pdu = *p++;
+ AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
+ if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
+ {
+ AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
+ status = AVRC_STS_BAD_CMD;
+ }
+
+ p++; /* skip the reserved byte */
+ UINT16 len;
+ BE_STREAM_TO_UINT16 (len, p);
+ if ((len+4) != (p_msg->vendor_len))
+ {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+
+ if (status != AVRC_STS_NO_ERROR)
+ return status;
+
+ switch (p_result->pdu)
+ {
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+ {
+ if(len!=1)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ {
+ BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
+ p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
+ }
+ break;
+ }
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
+ BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
+ break;
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+ return status;
+}
+#endif
+
/*******************************************************************************
**
** Function avrc_pars_vendor_cmd
@@ -59,10 +120,10 @@
p = p_msg->p_vendor_data;
p_result->pdu = *p++;
- AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
+ AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
{
- AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!");
+ AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
status = AVRC_STS_BAD_CMD;
}
@@ -139,14 +200,16 @@
}
if (xx != p_result->set_app_val.num_val)
{
- AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
- xx, p_result->set_app_val.num_val);
+ AVRC_TRACE_ERROR(
+ "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
+ __func__, xx, p_result->set_app_val.num_val);
p_result->set_app_val.num_val = xx;
}
}
else
{
- AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
+ AVRC_TRACE_ERROR("%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
+ __func__);
status = AVRC_STS_INTERNAL_ERR;
}
break;
@@ -276,6 +339,42 @@
return status;
}
+#if (AVRC_CTLR_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function AVRC_Ctrl_ParsCommand
+**
+** Description This function is used to parse cmds received for CTRL
+** Currently it is for SetAbsVolume and Volume Change Notification..
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result)
+{
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+
+ if (p_msg && p_result)
+ {
+ switch (p_msg->hdr.opcode)
+ {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
+ break;
+
+ default:
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+ break;
+ }
+ p_result->cmd.opcode = p_msg->hdr.opcode;
+ p_result->cmd.status = status;
+ }
+ AVRC_TRACE_DEBUG("%s return status:0x%x", __FUNCTION__, status);
+ return status;
+}
+#endif
+
/*******************************************************************************
**
** Function AVRC_ParsCommand
@@ -308,13 +407,13 @@
break;
default:
- AVRC_TRACE_ERROR("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
break;
}
p_result->cmd.opcode = p_msg->hdr.opcode;
p_result->cmd.status = status;
}
- AVRC_TRACE_DEBUG("AVRC_ParsCommand() return status:0x%x", status);
+ AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
return status;
}
diff --git a/stack/avrc/avrc_sdp.c b/stack/avrc/avrc_sdp.c
index c005788..4b668c4 100644
--- a/stack/avrc/avrc_sdp.c
+++ b/stack/avrc/avrc_sdp.c
@@ -28,7 +28,7 @@
#include "avrc_int.h"
#ifndef SDP_AVRCP_1_4
-#define SDP_AVRCP_1_4 FALSE
+#define SDP_AVRCP_1_4 TRUE
#endif
#ifndef SDP_AVCTP_1_4
@@ -218,7 +218,8 @@
**
******************************************************************************/
UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
- char *p_provider_name, UINT16 categories, UINT32 sdp_handle)
+ char *p_provider_name, UINT16 categories, UINT32 sdp_handle,
+ BOOLEAN browse_supported)
{
UINT16 browse_list[1];
BOOLEAN result = TRUE;
@@ -257,9 +258,11 @@
/* add profile descriptor list */
#if SDP_AVRCP_1_4 == TRUE
- /* additional protocol list to include browsing channel */
- result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list);
-
+ if (browse_supported)
+ {
+ /* additional protocol list to include browsing channel */
+ result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list);
+ }
result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_4);
#else
#if AVRC_METADATA_INCLUDED == TRUE
diff --git a/stack/avrc/avrc_utils.c b/stack/avrc/avrc_utils.c
index 18373c4..b381e84 100644
--- a/stack/avrc/avrc_utils.c
+++ b/stack/avrc/avrc_utils.c
@@ -59,6 +59,9 @@
case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ case AVRC_PDU_PLAY_ITEM:
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME:
if (avc_type == AVRC_CMD_CTRL)
result=TRUE;
break;
diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h
index 2198074..f1681d5 100644
--- a/stack/include/avrc_api.h
+++ b/stack/include/avrc_api.h
@@ -98,6 +98,7 @@
#define AVRC_SUPF_CT_CAT3 0x0004 /* Category 3 */
#define AVRC_SUPF_CT_CAT4 0x0008 /* Category 4 */
#define AVRC_SUPF_CT_BROWSE 0x0040 /* Browsing */
+#define AVRC_SUPF_CT_APP_SETTINGS 0x0010 /* Player Application Settings */
#define AVRC_SUPF_TG_CAT1 0x0001 /* Category 1 */
#define AVRC_SUPF_TG_CAT2 0x0002 /* Category 2 */
@@ -204,7 +205,7 @@
**
******************************************************************************/
extern UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
- char *p_provider_name, UINT16 categories, UINT32 sdp_handle);
+ char *p_provider_name, UINT16 categories, UINT32 sdp_handle, BOOLEAN browse_supported);
/******************************************************************************
**
@@ -558,6 +559,19 @@
/*******************************************************************************
**
+** Function AVRC_Ctrl_ParsCommand
+**
+** Description This function is used to parse cmds received for CTRL
+** Currently it is for SetAbsVolume and Volume Change Notification..
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result);
+
+/*******************************************************************************
+**
** Function AVRC_ParsCommand
**
** Description This function is used to parse the received command.
@@ -584,6 +598,19 @@
/*******************************************************************************
**
+** Function AVRC_Ctrl_ParsResponse
+**
+** Description This function is a parse response for AVRCP Controller.
+**
+** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+** Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
+ UINT8 *p_buf, UINT16* buf_len);
+
+/*******************************************************************************
+**
** Function AVRC_BldCommand
**
** Description This function builds the given AVRCP command to the given
diff --git a/stack/include/avrc_defs.h b/stack/include/avrc_defs.h
index e3e7f6e..cb6178c 100644
--- a/stack/include/avrc_defs.h
+++ b/stack/include/avrc_defs.h
@@ -840,7 +840,7 @@
#define AVRC_IS_VALID_CAP_ID(a) (((a == AVRC_CAP_COMPANY_ID) || (a == AVRC_CAP_EVENTS_SUPPORTED)) ? TRUE : FALSE)
#define AVRC_IS_VALID_EVENT_ID(a) (((a >= AVRC_EVT_PLAY_STATUS_CHANGE) && \
- (a <= AVRC_EVT_APP_SETTING_CHANGE)) ? TRUE : FALSE)
+ (a <= AVRC_EVT_VOLUME_CHANGE)) ? TRUE : FALSE)
#define AVRC_IS_VALID_ATTRIBUTE(a) (((((a > 0) && a <= AVRC_PLAYER_SETTING_SCAN)) || \
(a >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? TRUE : FALSE)
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 8d76143..688ffb4 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -238,6 +238,8 @@
/********************************************************************************
** Macros to get and put bytes to and from a stream (Little Endian format).
*/
+#define UINT64_TO_BE_STREAM(p, u64) {*(p)++ = (UINT8)((u64) >> 56); *(p)++ = (UINT8)((u64) >> 48); *(p)++ = (UINT8)((u64) >> 40); *(p)++ = (UINT8)((u64) >> 32); \
+ *(p)++ = (UINT8)((u64) >> 24); *(p)++ = (UINT8)((u64) >> 16); *(p)++ = (UINT8)((u64) >> 8); *(p)++ = (UINT8)(u64); }
#define UINT32_TO_STREAM(p, u32) {*(p)++ = (UINT8)(u32); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 24);}
#define UINT24_TO_STREAM(p, u24) {*(p)++ = (UINT8)(u24); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)((u24) >> 16);}
#define UINT16_TO_STREAM(p, u16) {*(p)++ = (UINT8)(u16); *(p)++ = (UINT8)((u16) >> 8);}
@@ -292,6 +294,11 @@
#define BE_STREAM_TO_UINT16(u16, p) {u16 = (UINT16)(((UINT16)(*(p)) << 8) + (UINT16)(*((p) + 1))); (p) += 2;}
#define BE_STREAM_TO_UINT24(u32, p) {u32 = (((UINT32)(*((p) + 2))) + ((UINT32)(*((p) + 1)) << 8) + ((UINT32)(*(p)) << 16)); (p) += 3;}
#define BE_STREAM_TO_UINT32(u32, p) {u32 = ((UINT32)(*((p) + 3)) + ((UINT32)(*((p) + 2)) << 8) + ((UINT32)(*((p) + 1)) << 16) + ((UINT32)(*(p)) << 24)); (p) += 4;}
+#define BE_STREAM_TO_UINT64(u64, p) {u64 = ((UINT64)(*((p) + 7)) + ((UINT64)(*((p) + 6)) << 8) + \
+ ((UINT64)(*((p) + 5)) << 16) + ((UINT64)(*((p) + 4)) << 24) + \
+ ((UINT64)(*((p) + 3)) << 32) + ((UINT64)(*((p) + 2)) << 40) + \
+ ((UINT64)(*((p) + 1)) << 48) + ((UINT64)(*(p)) << 56)); \
+ (p) += 8;}
#define BE_STREAM_TO_ARRAY(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;}