* 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);
#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 \
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" };
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
}
}
+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
+}
/***************************************************************************
{
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)
{
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();
}
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);
}
{
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;
*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);
}
}
{
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:
}
+
+/*******************************************************************************
+**
+** 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
************************************************************************************/
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;
}
/***************************************************************************
**
+** 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
bt_rc_callbacks = NULL;
}
memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t));
+ lbl_destroy();
}
get_element_attr_rsp,
NULL, /* set_player_app_value_rsp */
register_notification_rsp,
+ set_volume,
cleanup,
};
{
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; i<MAX_TRANSACTIONS_PER_SESSION; i++)
+ {
+ if (FALSE==device.transaction[i].in_use)
+ {
+ BTIF_TRACE_DEBUG2("%s:Got transaction.label: %d",__FUNCTION__,device.transaction[i].lbl);
+ device.transaction[i].in_use = TRUE;
+ *ptransaction = &(device.transaction[i]);
+ result = BT_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&device.lbllock);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function release_transaction
+**
+** Description Will release a transaction for reuse
+**
+** Returns bt_status_t
+*******************************************************************************/
+void release_transaction(UINT8 lbl)
+{
+ rc_transaction_t *transaction = get_transaction_by_lbl(lbl);
+
+ /* If the transaction is in use... */
+ if (transaction != NULL)
+ {
+ BTIF_TRACE_DEBUG2("%s: lbl: %d", __FUNCTION__, lbl);
+ initialize_transaction(lbl);
+ }
+}
+
+/*******************************************************************************
+**
+** Function lbl_destroy
+**
+** Description Cleanup of the mutex
+**
+** Returns void
+*******************************************************************************/
+void lbl_destroy()
+{
+ pthread_mutex_destroy(&(device.lbllock));
+}
CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
default:
return "UNKNOWN_EVENT";
}
CASE_RETURN_STR(AVRC_EVT_BATTERY_STATUS_CHANGE)
CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE)
CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE)
default:
return "Unhandled Event ID";
CASE_RETURN_STR(AVRC_PDU_REGISTER_NOTIFICATION)
CASE_RETURN_STR(AVRC_PDU_REQUEST_CONTINUATION_RSP)
CASE_RETURN_STR(AVRC_PDU_ABORT_CONTINUATION_RSP)
-
+ CASE_RETURN_STR(AVRC_PDU_SET_ABSOLUTE_VOLUME)
default:
return "Unknown PDU";
}
#define AVRC_METADATA_INCLUDED TRUE
#endif
+#ifndef AVRC_ADV_CTRL_INCLUDED
+#define AVRC_ADV_CTRL_INCLUDED TRUE
+#endif
+
/******************************************************************************
**
** MCAP
./avrc/avrc_sdp.c \
./avrc/avrc_opt.c \
./avrc/avrc_bld_tg.c \
+ ./avrc/avrc_bld_ct.c \
./avrc/avrc_pars_tg.c \
+ ./avrc/avrc_pars_ct.c \
./avrc/avrc_utils.c \
./hid/hidh_api.c \
./hid/hidh_conn.c \
p_fcb = &avrc_cb.fcb[handle];
/* The response type of the end fragment should be the same as the the PDU of "End Fragment
- ** Respose" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383 */
+ ** Response" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
+ */
p_orig_data = ((UINT8 *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
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));
}
**
** 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 .
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];
/* 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 */
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) */
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;
--- /dev/null
+/******************************************************************************
+ *
+ * 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 <string.h>
+
+#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) */
+
--- /dev/null
+/******************************************************************************
+ *
+ * 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 <string.h>
+
+#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) */
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 */
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
/******************************************************************************
/* 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;