From 247c68fe6eee3660cbdcf4509195fe735ae25573 Mon Sep 17 00:00:00 2001 From: Satya Calloji Date: Thu, 1 Aug 2013 02:14:43 -0700 Subject: [PATCH] Add support for AbsoluteVolume Add support for AbsoluteVolume in BTIF bug 9595622 Change-Id: I11b707f6ab50d31bd11e879b0ebe5ad5bac54ad9 Conflicts: btif/src/btif_rc.c --- btif/src/btif_av.c | 8 +- btif/src/btif_rc.c | 526 +++++++++++++++++++++++++++++++++++++++++++++- btif/src/btif_util.c | 4 +- include/bt_target.h | 4 + stack/Android.mk | 2 + stack/avrc/avrc_api.c | 79 ++++++- stack/avrc/avrc_bld_ct.c | 250 ++++++++++++++++++++++ stack/avrc/avrc_pars_ct.c | 148 +++++++++++++ stack/avrc/avrc_pars_tg.c | 14 +- stack/avrc/avrc_sdp.c | 28 ++- 10 files changed, 1042 insertions(+), 21 deletions(-) create mode 100644 stack/avrc/avrc_bld_ct.c create mode 100755 stack/avrc/avrc_pars_ct.c diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c index 6bb6bfb..934c937 100755 --- a/btif/src/btif_av.c +++ b/btif/src/btif_av.c @@ -960,8 +960,12 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable) * be initiated by the app/audioflinger layers */ #if (AVRC_METADATA_INCLUDED == TRUE) BTA_AvEnable(BTA_SEC_AUTHENTICATE, - BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD, - bte_av_callback); + 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 +#endif + ,bte_av_callback); #else BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD), bte_av_callback); diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c index a37dc63..0289692 100755 --- a/btif/src/btif_rc.c +++ b/btif/src/btif_rc.c @@ -56,7 +56,9 @@ #define IDX_GET_APP_ATTR_TXT_RSP 5 #define IDX_GET_APP_VAL_TXT_RSP 6 #define IDX_GET_ELEMENT_ATTR_RSP 7 - +#define MAX_VOLUME 128 +#define MAX_LABEL 16 +#define MAX_TRANSACTIONS_PER_SESSION 16 #define MAX_CMD_QUEUE_LEN 8 #define CHECK_RC_CONNECTED \ @@ -112,8 +114,25 @@ typedef struct { UINT16 rc_pending_play; btif_rc_cmd_ctxt_t rc_pdu_info[MAX_CMD_QUEUE_LEN]; btif_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS]; + unsigned int rc_volume; + uint8_t rc_vol_label; } btif_rc_cb_t; +typedef struct { + BOOLEAN in_use; + UINT8 lbl; + UINT8 handle; +} rc_transaction_t; + +typedef struct +{ + pthread_mutex_t lbllock; + rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION]; +} rc_device_t; + + +rc_device_t device; + #define MAX_UINPUT_PATHS 3 static const char* uinput_dev_path[] = {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput" }; @@ -147,7 +166,16 @@ static void send_reject_response (UINT8 rc_handle, UINT8 label, static UINT8 opcode_from_pdu(UINT8 pdu); static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label, tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp); +static void register_volumechange(UINT8 label); +static void lbl_init(); +static void lbl_destroy(); +static void init_all_transactions(); +static bt_status_t get_transaction(rc_transaction_t **ptransaction); +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); 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); /***************************************************************************** ** Static variables @@ -291,7 +319,62 @@ void close_uinput (void) } } +void handle_rc_features() +{ + btrc_remote_features_t rc_features = BTRC_FEAT_NONE; + bt_bdaddr_t rc_addr; + bdcpy(rc_addr.address, btif_rc_cb.rc_addr); + if (btif_rc_cb.rc_features & BTA_AV_FEAT_BROWSE) + { + rc_features |= BTRC_FEAT_BROWSE; + } + if ( (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL) && + (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)) + { + rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME; + } + if (btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA) + { + rc_features |= BTRC_FEAT_METADATA; + } + BTIF_TRACE_DEBUG2("%s: rc_features=0x%x", __FUNCTION__, rc_features); + HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features) + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + BTIF_TRACE_DEBUG1("Checking for feature flags in btif_rc_handler with label %d", + btif_rc_cb.rc_vol_label); + // Register for volume change on connect + if(btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL && + btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) + { + rc_transaction_t *p_transaction=NULL; + bt_status_t status = BT_STATUS_NOT_READY; + if(MAX_LABEL==btif_rc_cb.rc_vol_label) + { + status=get_transaction(&p_transaction); + } + else + { + p_transaction=get_transaction_by_lbl(btif_rc_cb.rc_vol_label); + if(NULL!=p_transaction) + { + BTIF_TRACE_DEBUG1("register_volumechange already in progress for label %d", + btif_rc_cb.rc_vol_label); + return; + } + else + status=get_transaction(&p_transaction); + } + + if(BT_STATUS_SUCCESS == status && NULL!=p_transaction) + { + btif_rc_cb.rc_vol_label=p_transaction->lbl; + register_volumechange(btif_rc_cb.rc_vol_label); + } + } +#endif +} /*************************************************************************** @@ -313,10 +396,16 @@ void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open) { memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR)); btif_rc_cb.rc_features = p_rc_open->peer_features; + btif_rc_cb.rc_vol_label=MAX_LABEL; + btif_rc_cb.rc_volume=MAX_VOLUME; btif_rc_cb.rc_connected = TRUE; btif_rc_cb.rc_handle = p_rc_open->rc_handle; + /* on locally initiated connection we will get remote features as part of connect */ + if (btif_rc_cb.rc_features != 0) + handle_rc_features(); + result = uinput_driver_check(); if(result == BT_STATUS_SUCCESS) { @@ -347,6 +436,9 @@ void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close) btif_rc_cb.rc_connected = FALSE; memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR)); 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(); } @@ -499,16 +591,38 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg) if (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) { +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) +{ + rc_transaction_t *transaction=NULL; + transaction=get_transaction_by_lbl(pmeta_msg->label); + if(NULL!=transaction) + { + handle_rc_metamsg_rsp(pmeta_msg); + } + else + { + BTIF_TRACE_DEBUG3("%s:Discard vendor dependent rsp. code: %d label:%d.", + __FUNCTION__, pmeta_msg->code, pmeta_msg->label); + } + return; +} +#else +{ BTIF_TRACE_DEBUG3("%s:Received vendor dependent rsp. code: %d len: %d. Not processing it.", __FUNCTION__, pmeta_msg->code, pmeta_msg->len); return; - } - status = AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf)); +} +#endif + } + + status=AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf)); + BTIF_TRACE_DEBUG3("Received vendor command.code,PDU and label: %d, %d,%d",pmeta_msg->code, + avrc_command.cmd.pdu, pmeta_msg->label); if (status != AVRC_STS_NO_ERROR) { /* return error */ - BTIF_TRACE_WARNING2("%s: Error in parsing received metamsg command. status: 0x%02x", + BTIF_TRACE_WARNING2("%s: Error in parsing received metamsg command. status: 0x%02x", __FUNCTION__, status); send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_command.pdu, status); } @@ -520,8 +634,8 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg) { UINT8 event_id = avrc_command.reg_notif.event_id; param_len = sizeof(tAVRC_REG_NOTIF_CMD); - BTIF_TRACE_EVENT3("%s: New register notification received. event_id:%s, label:0x%x", - __FUNCTION__, dump_rc_notification_event_id(event_id), pmeta_msg->label); + BTIF_TRACE_EVENT4("%s:New register notification received.event_id:%s,label:0x%x,code:%x", + __FUNCTION__,dump_rc_notification_event_id(event_id), pmeta_msg->label,pmeta_msg->code); btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE; btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label; @@ -540,7 +654,7 @@ void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg) *btif context, no context switching is required. Invoke * btif_rc_upstreams_evt directly from here. */ btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command, pmeta_msg->code, - pmeta_msg->label); + pmeta_msg->label); } } @@ -578,7 +692,7 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data) { BTIF_TRACE_DEBUG1("Peer_features:%x", p_data->rc_feat.peer_features); btif_rc_cb.rc_features = p_data->rc_feat.peer_features; - /* TODO Handle RC_FEAT_EVT*/ + handle_rc_features(); } break; case BTA_AV_META_MSG_EVT: @@ -914,6 +1028,48 @@ static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 } + +/******************************************************************************* +** +** Function btif_rc_upstreams_rsp_evt +** +** Description Executes AVRC UPSTREAMS response events in btif context. +** +** Returns void +** +*******************************************************************************/ +static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label) +{ + BTIF_TRACE_EVENT5("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__, + dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb.rc_handle, ctype, label); + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + switch (event) + { + case AVRC_PDU_REGISTER_NOTIFICATION: + { + if(AVRC_RSP_CHANGED==ctype) + btif_rc_cb.rc_volume=pavrc_resp->reg_notif.param.volume; + HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype) + } + break; + + case AVRC_PDU_SET_ABSOLUTE_VOLUME: + { + BTIF_TRACE_DEBUG2("Set absolute volume change event received: volume %d,ctype %d", + 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) + } + break; + + default: + return; + } +#endif +} + /************************************************************************************ ** AVRCP API Functions ************************************************************************************/ @@ -937,6 +1093,9 @@ static bt_status_t init(btrc_callbacks_t* callbacks ) bt_rc_callbacks = callbacks; memset (&btif_rc_cb, 0, sizeof(btif_rc_cb)); + btif_rc_cb.rc_vol_label=MAX_LABEL; + btif_rc_cb.rc_volume=MAX_VOLUME; + lbl_init(); return result; } @@ -1064,6 +1223,202 @@ static bt_status_t register_notification_rsp(btrc_event_id_t event_id, /*************************************************************************** ** +** Function set_volume +** +** Description Send current volume setting to remote side. +** Support limited to SetAbsoluteVolume +** This can be enhanced to support Relative Volume (AVRCP 1.0). +** With RelateVolume, we will send VOLUME_UP/VOLUME_DOWN +** as opposed to absolute volume level +** volume: Should be in the range 0-127. bit7 is reseved and cannot be set +** +** Returns bt_status_t +** +***************************************************************************/ +static bt_status_t set_volume(uint8_t volume) +{ + BTIF_TRACE_DEBUG1("%s", __FUNCTION__); + CHECK_RC_CONNECTED + tAVRC_STS status = BT_STATUS_UNSUPPORTED; + rc_transaction_t *p_transaction=NULL; + + if(btif_rc_cb.rc_volume==volume) + { + status=BT_STATUS_DONE; + BTIF_TRACE_ERROR2("%s: volume value already set earlier: 0x%02x",__FUNCTION__, volume); + return status; + } + + if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) && + (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)) + { + tAVRC_COMMAND avrc_cmd = {0}; + BT_HDR *p_msg = NULL; + + BTIF_TRACE_DEBUG2("%s: Peer supports absolute volume. newVolume=%d", __FUNCTION__, volume); + avrc_cmd.volume.opcode = AVRC_OP_VENDOR; + avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME; + avrc_cmd.volume.status = AVRC_STS_NO_ERROR; + avrc_cmd.volume.volume = volume; + + 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) + { + BTIF_TRACE_DEBUG2("%s msgreq being sent out with label %d", + __FUNCTION__,p_transaction->lbl); + BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg); + status = BT_STATUS_SUCCESS; + } + else + { + if(NULL!=p_msg) + GKI_freebuf(p_msg); + BTIF_TRACE_ERROR2("%s: failed to obtain transaction details. status: 0x%02x", + __FUNCTION__, tran_status); + status = BT_STATUS_FAIL; + } + } + else + { + BTIF_TRACE_ERROR2("%s: failed to build absolute volume command. status: 0x%02x", + __FUNCTION__, status); + status = BT_STATUS_FAIL; + } + } + else + status=BT_STATUS_NOT_READY; + return status; +} + + +/*************************************************************************** +** +** Function register_volumechange +** +** Description Register for volume change notification from remote side. +** +** Returns void +** +***************************************************************************/ + +static void register_volumechange (UINT8 lbl) +{ + tAVRC_COMMAND avrc_cmd = {0}; + BT_HDR *p_msg = NULL; + tAVRC_STS BldResp=AVRC_STS_BAD_CMD; + UINT16 rv = 0; + bt_status_t tran_status; + rc_transaction_t *p_transaction=NULL; + + BTIF_TRACE_DEBUG2("%s called with label:%d",__FUNCTION__,lbl); + + avrc_cmd.cmd.opcode=0x00; + 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; + + BldResp=AVRC_BldCommand(&avrc_cmd, &p_msg); + if(AVRC_STS_NO_ERROR==BldResp && p_msg) + { + p_transaction=get_transaction_by_lbl(lbl); + if(NULL!=p_transaction) + { + BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_NOTIF, p_msg); + BTIF_TRACE_DEBUG1("%s:BTA_AvMetaCmd called",__FUNCTION__); + } + else + { + if(NULL!=p_msg) + GKI_freebuf(p_msg); + BTIF_TRACE_ERROR2("%s transaction not obtained with label: %d",__FUNCTION__,lbl); + } + } + else + BTIF_TRACE_ERROR2("%s failed to build command:%d",__FUNCTION__,BldResp); +} + + +/*************************************************************************** +** +** Function handle_rc_metamsg_rsp +** +** Description Handle RC metamessage response +** +** Returns void +** +***************************************************************************/ +static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg) +{ + tAVRC_RESPONSE avrc_response = {0}; + UINT8 scratch_buf[512] = {0}; + tAVRC_STS status = BT_STATUS_UNSUPPORTED; + + if(AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code + || 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)) + { + status=AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, sizeof(scratch_buf)); + BTIF_TRACE_DEBUG6("%s: code %d,event ID %d,PDU %x,parsing status %d, label:%d", + __FUNCTION__,pmeta_msg->code,avrc_response.reg_notif.event_id,avrc_response.reg_notif.pdu, + status, pmeta_msg->label); + + if (status != AVRC_STS_NO_ERROR) + { + 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) + { + release_transaction(pmeta_msg->label); + } + return; + } + 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) + { + // Just discard the message, if the device sends back with an incorrect label + BTIF_TRACE_DEBUG3("%s:Discarding register notfn in rsp.code: %d and label %d", + __FUNCTION__, pmeta_msg->code, pmeta_msg->label); + return; + } + } + else + { + BTIF_TRACE_DEBUG3("%s:Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not processing it.", + __FUNCTION__, pmeta_msg->code, pmeta_msg->len); + return; + } + + 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) + { + /* re-register for volume change notification */ + // Do not re-register for rejected case, as it might get into endless loop + register_volumechange(btif_rc_cb.rc_vol_label); + } + else if(AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu) + { + /* free up the label here */ + release_transaction(pmeta_msg->label); + } + + BTIF_TRACE_EVENT2("%s: Passing received metamsg response to app. pdu: %s", + __FUNCTION__, dump_rc_pdu(avrc_response.pdu)); + btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response, pmeta_msg->code, + pmeta_msg->label); +} + + +/*************************************************************************** +** ** Function cleanup ** ** Description Closes the AVRC interface @@ -1080,6 +1435,7 @@ static void cleanup() bt_rc_callbacks = NULL; } memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t)); + lbl_destroy(); } @@ -1095,6 +1451,7 @@ static const btrc_interface_t bt_rc_interface = { get_element_attr_rsp, NULL, /* set_player_app_value_rsp */ register_notification_rsp, + set_volume, cleanup, }; @@ -1111,4 +1468,155 @@ const btrc_interface_t *btif_rc_get_interface(void) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); return &bt_rc_interface; -} \ No newline at end of file +} + +/******************************************************************************* +** Function initialize_transaction +** +** Description Initializes fields of the transaction structure +** +** Returns void +*******************************************************************************/ +static void initialize_transaction(int lbl) +{ + pthread_mutex_lock(&device.lbllock); + if(lbl < MAX_TRANSACTIONS_PER_SESSION) + { + device.transaction[lbl].lbl = lbl; + device.transaction[lbl].in_use=FALSE; + device.transaction[lbl].handle=0; + } + pthread_mutex_unlock(&device.lbllock); +} + +/******************************************************************************* +** Function lbl_init +** +** Description Initializes label structures and mutexes. +** +** Returns void +*******************************************************************************/ +void lbl_init() +{ + memset(&device,0,sizeof(rc_device_t)); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutex_init(&(device.lbllock), &attr); + pthread_mutexattr_destroy(&attr); + init_all_transactions(); +} + +/******************************************************************************* +** +** Function init_all_transactions +** +** Description Initializes all transactions +** +** Returns void +*******************************************************************************/ +void init_all_transactions() +{ + UINT8 txn_indx=0; + for(txn_indx=0; txn_indx < MAX_TRANSACTIONS_PER_SESSION; txn_indx++) + { + initialize_transaction(txn_indx); + } +} + +/******************************************************************************* +** +** Function get_transaction_by_lbl +** +** Description Will return a transaction based on the label. If not inuse +** will return an error. +** +** Returns bt_status_t +*******************************************************************************/ +rc_transaction_t *get_transaction_by_lbl(UINT8 lbl) +{ + rc_transaction_t *transaction = NULL; + pthread_mutex_lock(&device.lbllock); + + /* Determine if this is a valid label */ + if (lbl < MAX_TRANSACTIONS_PER_SESSION) + { + if (FALSE==device.transaction[lbl].in_use) + { + transaction = NULL; + } + else + { + transaction = &(device.transaction[lbl]); + BTIF_TRACE_DEBUG2("%s: Got transaction.label: %d",__FUNCTION__,lbl); + } + } + + pthread_mutex_unlock(&device.lbllock); + return transaction; +} + +/******************************************************************************* +** +** Function get_transaction +** +** Description Obtains the transaction details. +** +** Returns bt_status_t +*******************************************************************************/ + +bt_status_t get_transaction(rc_transaction_t **ptransaction) +{ + bt_status_t result = BT_STATUS_NOMEM; + UINT8 i=0; + pthread_mutex_lock(&device.lbllock); + + // Check for unused transactions + for (i=0; ip_fmsg + 1) + p_fcb->p_fmsg->offset); rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK); @@ -146,6 +147,7 @@ static void avrc_prep_end_frag(UINT8 handle) AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA); *p_data++ = p_fcb->frag_pdu; *p_data++ = AVRC_PKT_END; + /* 4=pdu, pkt_type & len */ UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE)); } @@ -337,7 +339,7 @@ static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label, ** ** Function avrc_proc_far_msg ** -** Description This function processes vendor command/response fragmetation +** Description This function processes metadata fragmenation ** and reassembly ** ** Returns 0, to report the message with msg_cback . @@ -359,6 +361,10 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_ tAVRC_NEXT_CMD avrc_cmd; p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + + /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */ + p_data += AVRC_VENDOR_HDR_SIZE; + pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK; AVRC_TRACE_DEBUG1 ("pkt_type %d", pkt_type ); p_rcb = &avrc_cb.rcb[handle]; @@ -381,13 +387,48 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_ /* not a single response packet - need to re-assemble metadata messages */ if (pkt_type == AVRC_PKT_START) { - p_rcb->rasm_offset = p_pkt->offset; - p_rcb->p_rmsg = p_pkt; + /* Allocate buffer for re-assembly */ + p_rcb->rasm_pdu = *p_data; + if ((p_rcb->p_rmsg = (BT_HDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL) + { + /* Copy START packet to buffer for re-assembling fragments*/ + memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */ + + /* Copy metadata message */ + memcpy((UINT8 *)(p_rcb->p_rmsg + 1), + (UINT8 *)(p_pkt+1) + p_pkt->offset, p_pkt->len); + + /* offset of start of metadata response in reassembly buffer */ + p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0; + + /* Free original START packet, replace with pointer to reassembly buffer */ + GKI_freebuf(p_pkt); + *pp_pkt = p_rcb->p_rmsg; + } + else + { + /* Unable to allocate buffer for fragmented avrc message. Reuse START + buffer for reassembly (re-assembled message may fit into ACL buf) */ + AVRC_TRACE_DEBUG0 ("Unable to allocate buffer for fragmented avrc message, \ + reusing START buffer for reassembly"); + p_rcb->rasm_offset = p_pkt->offset; + p_rcb->p_rmsg = p_pkt; + } + /* set offset to point to where to copy next - use the same re-asm logic as AVCT */ p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len; - p_rcb->rasm_pdu = *p_data; req_continue = TRUE; } + else if (p_rcb->p_rmsg == NULL) + { + /* Received a CONTINUE/END, but no corresponding START + (or previous fragmented response was dropped) */ + AVRC_TRACE_DEBUG0 ("Received a CONTINUE/END without no corresponding START \ + (or previous fragmented response was dropped)"); + drop = 5; + GKI_freebuf(p_pkt); + *pp_pkt = NULL; + } else { /* get size of buffer holding assembled message */ @@ -453,7 +494,19 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_ drop = 4; } + else if (cr == AVCT_RSP && req_continue == TRUE) + { + avrc_cmd.pdu = AVRC_PDU_REQUEST_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 = 2; + AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd); + } + } } + return drop; } #endif /* (AVRC_METADATA_INCLUDED == TRUE) */ @@ -604,7 +657,21 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr, p_msg->vendor_len = p_pkt->len - (p_data - p_begin); #if (AVRC_METADATA_INCLUDED == TRUE) - drop = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg); + if (p_msg->company_id == AVRC_CO_METADATA) + { + /* Validate length for metadata message */ + if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)) + { + if (cr == AVCT_CMD) + reject = TRUE; + else + drop = TRUE; + break; + } + + /* Check+handle fragmented messages */ + drop = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg); + } if (drop) { free = FALSE; diff --git a/stack/avrc/avrc_bld_ct.c b/stack/avrc/avrc_bld_ct.c new file mode 100644 index 0000000..039eab8 --- /dev/null +++ b/stack/avrc/avrc_bld_ct.c @@ -0,0 +1,250 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ + + +#if (AVRC_METADATA_INCLUDED == TRUE) +/******************************************************************************* +** +** Function avrc_bld_next_cmd +** +** Description This function builds the Request Continue or Abort command. +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API0("avrc_bld_next_cmd"); + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; /* pdu + rsvd */ + + /* add fixed lenth 1 - pdu_id (1) */ + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/***************************************************************************** +** the following commands are introduced in AVRCP 1.4 +*****************************************************************************/ + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) +/******************************************************************************* +** +** Function avrc_bld_set_abs_volume_cmd +** +** Description This function builds the Set Absolute Volume command. +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API0("avrc_bld_set_abs_volume_cmd"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; /* pdu + rsvd */ + /* add fixed lenth 1 - volume (1) */ + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume)); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_vol_change_notfn +** +** Description This function builds the register notification for volume change. +** +** 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) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API0("avrc_bld_vol_change"); + /* 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); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} +#endif + +/******************************************************************************* +** +** Function avrc_bld_init_cmd_buffer +** +** Description This function initializes the command buffer based on PDU +** +** Returns NULL, if no GKI buffer or failure to build the message. +** Otherwise, the GKI buffer that contains the initialized message. +** +*******************************************************************************/ +static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd) +{ + UINT16 offset = 0, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE; + BT_HDR *p_pkt=NULL; + UINT8 opcode; + + opcode = avrc_opcode_from_pdu(p_cmd->pdu); + AVRC_TRACE_API2("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode); + + switch (opcode) + { + case AVRC_OP_PASS_THRU: + offset = AVRC_MSG_PASS_THRU_OFFSET; + break; + + case AVRC_OP_VENDOR: + offset = AVRC_MSG_VENDOR_OFFSET; + break; + } + + /* allocate and initialize the buffer */ + p_pkt = (BT_HDR *)GKI_getbuf(len); + if (p_pkt) + { + UINT8 *p_data, *p_start; + + p_pkt->layer_specific = chnl; + p_pkt->event = opcode; + p_pkt->offset = offset; + p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_start = p_data; + + /* pass thru - group navigation - has a two byte op_id, so dont do it here */ + if (opcode != AVRC_OP_PASS_THRU) + *p_data++ = p_cmd->pdu; + + switch (opcode) + { + case AVRC_OP_VENDOR: + /* reserved 0, packet_type 0 */ + UINT8_TO_BE_STREAM(p_data, 0); + /* continue to the next "case to add length */ + /* add fixed lenth - 0 */ + UINT16_TO_BE_STREAM(p_data, 0); + break; + } + + p_pkt->len = (p_data - p_start); + } + p_cmd->cmd.opcode = opcode; + return p_pkt; +} + +/******************************************************************************* +** +** Function AVRC_BldCommand +** +** Description This function builds the given AVRCP command to the given +** GKI buffer +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +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_API2("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status); + if (!p_cmd || !pp_pkt) + { + AVRC_TRACE_API2("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p", + p_cmd, pp_pkt); + return AVRC_STS_BAD_PARAM; + } + + if (*pp_pkt == NULL) + { + if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL) + { + AVRC_TRACE_API0("AVRC_BldCommand: Failed to initialize command buffer"); + return AVRC_STS_INTERNAL_ERR; + } + alloc = TRUE; + } + status = AVRC_STS_NO_ERROR; + p_pkt = *pp_pkt; + + switch (p_cmd->pdu) + { + case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ + status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt); + break; + + case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ + status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt); + break; +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ + 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 + break; + + } + + if (alloc && (status != AVRC_STS_NO_ERROR) ) + { + GKI_freebuf(p_pkt); + *pp_pkt = NULL; + } + AVRC_TRACE_API1("AVRC_BldCommand: returning %d", status); + return status; +} +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + diff --git a/stack/avrc/avrc_pars_ct.c b/stack/avrc/avrc_pars_ct.c new file mode 100755 index 0000000..85a9233 --- /dev/null +++ b/stack/avrc/avrc_pars_ct.c @@ -0,0 +1,148 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ + +#if (AVRC_METADATA_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avrc_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_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len) +{ + tAVRC_STS status = AVRC_STS_NO_ERROR; + UINT8 *p = p_msg->p_vendor_data; + UINT16 len; + UINT8 xx, yy; + tAVRC_NOTIF_RSP_PARAM *p_param; + tAVRC_APP_SETTING *p_app_set; + tAVRC_APP_SETTING_TEXT *p_app_txt; + tAVRC_ATTR_ENTRY *p_entry; + UINT32 *p_u32; + UINT8 *p_u8; + UINT16 size_needed; + UINT8 eventid=0; + + BE_STREAM_TO_UINT8 (p_result->pdu, p); + p++; /* skip the reserved/packe_type byte */ + BE_STREAM_TO_UINT16 (len, p); + AVRC_TRACE_DEBUG4("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); + if (p_msg->hdr.ctype == AVRC_RSP_REJ) + { + p_result->rsp.status = *p; + return p_result->rsp.status; + } + + switch (p_result->pdu) + { + /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ + /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ + if (len != 1) + status = AVRC_STS_INTERNAL_ERR; + else + { + BE_STREAM_TO_UINT8 (p_result->volume.volume, p); + } + break; +#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ + + case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + BE_STREAM_TO_UINT8 (eventid, p); + if(AVRC_EVT_VOLUME_CHANGE==eventid + && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype + || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype)) + { + p_result->reg_notif.status=p_msg->hdr.ctype; + p_result->reg_notif.event_id=eventid; + BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); + } + AVRC_TRACE_DEBUG2("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid, + p_result->reg_notif.param.volume); +#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ + break; + default: + status = AVRC_STS_BAD_CMD; + break; + } + + return status; +} + +/******************************************************************************* +** +** Function AVRC_ParsResponse +** +** Description This function is a superset of AVRC_ParsMetadata to parse the response. +** +** 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_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len) +{ + tAVRC_STS status = AVRC_STS_INTERNAL_ERR; + UINT16 id; + + if (p_msg && p_result) + { + switch (p_msg->hdr.opcode) + { + case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */ + status = avrc_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf, buf_len); + break; + + case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */ + status = avrc_pars_pass_thru(&p_msg->pass, &id); + if (status == AVRC_STS_NO_ERROR) + { + p_result->pdu = (UINT8)id; + } + break; + + default: + AVRC_TRACE_ERROR1("AVRC_ParsResponse() unknown opcode:0x%x", p_msg->hdr.opcode); + break; + } + p_result->rsp.opcode = p_msg->hdr.opcode; + p_result->rsp.status = status; + } + return status; +} + + +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ diff --git a/stack/avrc/avrc_pars_tg.c b/stack/avrc/avrc_pars_tg.c index 0d9cf34..d3d5262 100755 --- a/stack/avrc/avrc_pars_tg.c +++ b/stack/avrc/avrc_pars_tg.c @@ -244,9 +244,19 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ if (len != 5) status = AVRC_STS_INTERNAL_ERR; - BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p); - BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + else + { + BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p); + BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + } + break; + + case AVRC_PDU_SET_ABSOLUTE_VOLUME: + { + if(len!=1) + status = AVRC_STS_INTERNAL_ERR; break; + } /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ diff --git a/stack/avrc/avrc_sdp.c b/stack/avrc/avrc_sdp.c index e447e48..7ddf0f7 100755 --- a/stack/avrc/avrc_sdp.c +++ b/stack/avrc/avrc_sdp.c @@ -38,13 +38,26 @@ tAVRC_CB avrc_cb; const tSDP_PROTOCOL_ELEM avrc_proto_list [] = { {UUID_PROTOCOL_L2CAP, 1, {AVCT_PSM, 0} }, +#if AVRC_ADV_CTRL_INCLUDED == TRUE + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} } +#else #if AVRC_METADATA_INCLUDED == TRUE {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_2, 0} } #else {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_0, 0} } #endif +#endif }; +#if AVRC_ADV_CTRL_INCLUDED == TRUE +const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] = +{ + {AVRC_NUM_PROTO_ELEMS, + { + {UUID_PROTOCOL_L2CAP, 1, {AVCT_BR_PSM, 0} }, + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} }}} +}; +#endif /****************************************************************************** @@ -210,18 +223,31 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, /* add service class id list */ class_list[0] = service_uuid; +#if AVRC_ADV_CTRL_INCLUDED == TRUE + if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) + { + class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; + count = 2; + } +#endif result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list); /* add protocol descriptor list */ result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, (tSDP_PROTOCOL_ELEM *)avrc_proto_list); /* add profile descriptor list */ +#if AVRC_ADV_CTRL_INCLUDED == TRUE + /* 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 result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_3); #else result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_0); #endif - +#endif /* add supported categories */ p = temp; -- 2.11.0