summaryrefslogtreecommitdiffstats
path: root/stack/avrc
diff options
context:
space:
mode:
Diffstat (limited to 'stack/avrc')
-rw-r--r--stack/avrc/avrc_api.c588
-rw-r--r--stack/avrc/avrc_int.h138
-rw-r--r--stack/avrc/avrc_opt.c230
-rw-r--r--stack/avrc/avrc_sdp.c297
4 files changed, 1253 insertions, 0 deletions
diff --git a/stack/avrc/avrc_api.c b/stack/avrc/avrc_api.c
new file mode 100644
index 0000000..b6347d7
--- /dev/null
+++ b/stack/avrc/avrc_api.c
@@ -0,0 +1,588 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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:
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * nterface to AVRCP mandatory commands
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "wcassert.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+
+#define AVRC_MAX_RCV_CTRL_EVT AVCT_BROWSE_UNCONG_IND_EVT
+
+static const UINT8 avrc_ctrl_event_map[] =
+{
+ AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_CFM_EVT */
+ AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_IND_EVT */
+ AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */
+ AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */
+ AVRC_CONG_IND_EVT, /* AVCT_CONG_IND_EVT */
+ AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */
+ AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_CFM_EVT */
+ AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_IND_EVT */
+ AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */
+ AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */
+ AVRC_BROWSE_CONG_IND_EVT, /* AVCT_BROWSE_CONG_IND_EVT */
+ AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT */
+};
+
+#define AVRC_OP_DROP 0xFE /* use this unused opcode to indication no need to call the callback function */
+#define AVRC_OP_DROP_N_FREE 0xFD /* use this unused opcode to indication no need to call the callback function & free buffer */
+
+/******************************************************************************
+**
+** Function avrc_ctrl_cback
+**
+** Description This is the callback function used by AVCTP to report
+** received link events.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result,
+ BD_ADDR peer_addr)
+{
+ UINT8 avrc_event;
+
+ if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback)
+ {
+ avrc_event = avrc_ctrl_event_map[event];
+ if (event == AVCT_CONNECT_CFM_EVT)
+ {
+ if (result != 0) /* failed */
+ avrc_event = AVRC_CLOSE_IND_EVT;
+ }
+ (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
+ }
+ /* else drop the unknown event*/
+}
+
+/******************************************************************************
+**
+** Function avrc_get_data_ptr
+**
+** Description If the offset in the received buffer is smaller than required
+** move the portion of data AVRC cares.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static UINT8 * avrc_get_data_ptr(BT_HDR *p_pkt)
+{
+ UINT8 *p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ int i, gap;
+
+ if (p_pkt->offset < AVCT_MSG_OFFSET)
+ {
+ gap = AVCT_MSG_OFFSET - p_pkt->offset;
+ for(i=p_pkt->len; i>0; i--)
+ {
+ *(p_data + i + gap) = *(p_data + i);
+ }
+ p_pkt->offset += gap;
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ }
+ *p_data = AVRC_RSP_IMPL_STBL;
+ return p_data;
+}
+
+
+/******************************************************************************
+**
+** Function avrc_msg_cback
+**
+** Description This is the callback function used by AVCTP to report
+** received AV control messages.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
+ BT_HDR *p_pkt)
+{
+ UINT8 opcode;
+ tAVRC_MSG msg;
+ UINT8 *p_data;
+ UINT8 *p_begin;
+ BOOLEAN drop = FALSE;
+ BOOLEAN free = TRUE;
+ BT_HDR *p_rsp = NULL;
+ UINT8 *p_rsp_data;
+ int xx;
+ BOOLEAN reject = FALSE;
+#if (BT_USE_TRACES == TRUE)
+ char *p_drop_msg = "dropped";
+#endif
+ tAVRC_MSG_VENDOR *p_msg = &msg.vendor;
+
+ if (cr == AVCT_CMD &&
+ (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len)))
+ {
+ /* Ignore the invalid AV/C command frame */
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "dropped - too long AV/C cmd frame size";
+#endif
+ GKI_freebuf(p_pkt);
+ return;
+ }
+
+ if (cr == AVCT_REJ)
+ {
+ /* The peer thinks that this PID is no longer open - remove this handle */
+ /* */
+ GKI_freebuf(p_pkt);
+ AVCT_RemoveConn(handle);
+ return;
+ }
+
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ memset(&msg, 0, sizeof(tAVRC_MSG) );
+ {
+ msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
+ AVRC_TRACE_DEBUG4("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
+ handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
+ msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
+ opcode = p_data[2];
+ }
+
+ if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
+ ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
+ {
+
+ switch(opcode)
+ {
+ case AVRC_OP_UNIT_INFO:
+ if (cr == AVCT_CMD)
+ {
+ /* send the response to the peer */
+ p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */
+ /* check & set the offset. set response code, set subunit_type & subunit_id,
+ set AVRC_OP_UNIT_INFO */
+ p_rsp_data = avrc_get_data_ptr(p_pkt) + AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ *p_rsp_data++ = 7;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto respond";
+#endif
+ }
+ else
+ {
+ /* parse response */
+ p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
+ msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.unit.unit = *p_data & AVRC_SUBID_MASK;
+ p_data++;
+ AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
+ }
+ break;
+
+ case AVRC_OP_SUB_INFO:
+ if (cr == AVCT_CMD)
+ {
+ /* send the response to the peer */
+ p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */
+ /* check & set the offset. set response code, set (subunit_type & subunit_id),
+ set AVRC_OP_SUB_INFO, set (page & extention code) */
+ p_rsp_data = avrc_get_data_ptr(p_pkt) + 4;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
+ p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
+ p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "auto responded";
+#endif
+ }
+ else
+ {
+ /* parse response */
+ p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
+ xx = 0;
+ while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
+ {
+ msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
+ if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
+ msg.sub.panel = TRUE;
+ xx++;
+ }
+ }
+ break;
+
+ case AVRC_OP_VENDOR:
+ p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
+ p_begin = p_data;
+ if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
+ {
+ if (cr == AVCT_CMD)
+ reject = TRUE;
+ else
+ drop = TRUE;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
+ p_msg->p_vendor_data = p_data;
+ p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
+
+ break;
+
+ case AVRC_OP_PASS_THRU:
+ if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
+ {
+ if (cr == AVCT_CMD)
+ reject = TRUE;
+ else
+ drop = TRUE;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+ msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
+ if (AVRC_PASS_STATE_MASK & *p_data)
+ msg.pass.state = TRUE;
+ else
+ msg.pass.state = FALSE;
+ p_data++;
+ msg.pass.pass_len = *p_data++;
+ if (msg.pass.pass_len != p_pkt->len - 5)
+ msg.pass.pass_len = p_pkt->len - 5;
+ if (msg.pass.pass_len)
+ msg.pass.p_pass_data = p_data;
+ else
+ msg.pass.p_pass_data = NULL;
+ break;
+
+
+ default:
+ if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
+ {
+ /* reject unsupported opcode */
+ reject = TRUE;
+ }
+ drop = TRUE;
+ break;
+ }
+ }
+ else /* drop the event */
+ {
+ drop = TRUE;
+ }
+
+ if (reject)
+ {
+ /* reject unsupported opcode */
+ p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */
+ p_rsp_data = avrc_get_data_ptr(p_pkt);
+ *p_rsp_data = AVRC_RSP_REJ;
+#if (BT_USE_TRACES == TRUE)
+ p_drop_msg = "rejected";
+#endif
+ cr = AVCT_RSP;
+ drop = TRUE;
+ }
+
+ if (p_rsp)
+ {
+ /* set to send response right away */
+ AVCT_MsgReq( handle, label, cr, p_rsp);
+ free = FALSE;
+ drop = TRUE;
+ }
+
+ if (drop == FALSE)
+ {
+ msg.hdr.opcode = opcode;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ }
+#if (BT_USE_TRACES == TRUE)
+ else
+ {
+ AVRC_TRACE_WARNING5("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+ p_drop_msg,
+ handle, avrc_cb.ccb[handle].control, cr, opcode);
+ }
+#endif
+
+
+ if (free)
+ GKI_freebuf(p_pkt);
+}
+
+
+
+
+/******************************************************************************
+**
+** Function avrc_pass_msg
+**
+** Description Compose a PASS THROUGH command according to p_msg
+**
+** Input Parameters:
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns pointer to a valid GKI buffer if successful.
+** NULL if p_msg is NULL.
+**
+******************************************************************************/
+static BT_HDR * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
+{
+ BT_HDR *p_cmd = NULL;
+ UINT8 *p_data;
+
+ WC_ASSERT(p_msg != NULL);
+ WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len));
+
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
+ *p_data++ = AVRC_OP_PASS_THRU;
+ *p_data = (AVRC_PASS_OP_ID_MASK&p_msg->op_id);
+ if (p_msg->state)
+ *p_data |= AVRC_PASS_STATE_MASK;
+ p_data++;
+
+ if (p_msg->op_id == AVRC_ID_VENDOR)
+ {
+ *p_data++ = p_msg->pass_len;
+ if (p_msg->pass_len && p_msg->p_pass_data)
+ {
+ memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
+ p_data += p_msg->pass_len;
+ }
+ }
+ else /* set msg len to 0 for other op_id */
+ {
+ /* set msg len to 0 for other op_id */
+ *p_data++ = 0;
+ }
+ p_cmd->len = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
+ }
+ return p_cmd;
+}
+
+/******************************************************************************
+**
+** Function AVRC_Open
+**
+** Description This function is called to open a connection to AVCTP.
+** The connection can be either an initiator or acceptor, as
+** determined by the p_ccb->stream parameter.
+** The connection can be a target, a controller or for both role,
+** as determined by the p_ccb->control parameter.
+** By definition, a target connection is an acceptor connection
+** that waits for an incoming AVCTP connection from the peer.
+** The connection remains available to the application until
+** the application closes it by calling AVRC_Close(). The
+** application does not need to reopen the connection after an
+** AVRC_CLOSE_IND_EVT is received.
+**
+** Input Parameters:
+** p_ccb->company_id: Company Identifier.
+**
+** p_ccb->p_ctrl_cback: Pointer to control callback function.
+**
+** p_ccb->p_msg_cback: Pointer to message callback function.
+**
+** p_ccb->conn: AVCTP connection role. This is set to
+** AVCTP_INT for initiator connections and AVCTP_ACP
+** for acceptor connections.
+**
+** p_ccb->control: Control role. This is set to
+** AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+** for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
+** for connections that support both roles.
+**
+** peer_addr: BD address of peer device. This value is
+** only used for initiator connections; for acceptor
+** connections it can be set to NULL.
+**
+** Output Parameters:
+** p_handle: Pointer to handle. This parameter is only
+** valid if AVRC_SUCCESS is returned.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if there are not enough resources to open
+** the connection.
+**
+******************************************************************************/
+UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
+{
+ UINT16 status;
+ tAVCT_CC cc;
+
+ cc.p_ctrl_cback = avrc_ctrl_cback; /* Control callback */
+ cc.p_msg_cback = avrc_msg_cback; /* Message callback */
+ cc.pid = UUID_SERVCLASS_AV_REMOTE_CONTROL; /* Profile ID */
+ cc.role = p_ccb->conn; /* Initiator/acceptor role */
+ cc.control = p_ccb->control; /* Control role (Control/Target) */
+
+ status = AVCT_CreateConn(p_handle, &cc, peer_addr);
+ if (status == AVCT_SUCCESS)
+ {
+ memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
+ }
+ AVRC_TRACE_DEBUG4("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control, status, *p_handle);
+
+ return status;
+}
+
+/******************************************************************************
+**
+** Function AVRC_Close
+**
+** Description Close a connection opened with AVRC_Open().
+** This function is called when the
+** application is no longer using a connection.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_Close(UINT8 handle)
+{
+ AVRC_TRACE_DEBUG1("AVRC_Close handle:%d", handle);
+ return AVCT_RemoveConn(handle);
+}
+
+
+/******************************************************************************
+**
+** Function AVRC_MsgReq
+**
+** Description This function is used to send the AVRCP byte stream in p_pkt
+** down to AVCTP.
+**
+** It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
+** p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+** p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+** The above BT_HDR settings are set by the AVRC_Bld* functions.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
+{
+ return AVRC_NO_RESOURCES;
+}
+
+
+/******************************************************************************
+**
+** Function AVRC_PassCmd
+**
+** Description Send a PASS THROUGH command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
+{
+ BT_HDR *p_buf;
+ WC_ASSERT(p_msg != NULL);
+ if (p_msg)
+ {
+ p_msg->hdr.ctype = AVRC_CMD_CTRL;
+ p_buf = avrc_pass_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+ }
+ return AVRC_NO_RESOURCES;
+}
+
+/******************************************************************************
+**
+** Function AVRC_PassRsp
+**
+** Description Send a PASS THROUGH response to the peer device. This
+** function can only be called for target role connections.
+** This function must be called when a PASS THROUGH command
+** message is received from the peer through the
+** tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label. Must be the same value as
+** passed with the command message in the callback function.
+**
+** p_msg: Pointer to PASS THROUGH message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
+{
+ BT_HDR *p_buf;
+ WC_ASSERT(p_msg != NULL);
+ if (p_msg)
+ {
+ p_buf = avrc_pass_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
+ }
+ return AVRC_NO_RESOURCES;
+}
+
diff --git a/stack/avrc/avrc_int.h b/stack/avrc/avrc_int.h
new file mode 100644
index 0000000..b6c90b1
--- /dev/null
+++ b/stack/avrc/avrc_int.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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:
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * VRCP internal header file.
+ *
+ ******************************************************************************/
+
+
+#ifndef AVRC_INT_H
+#define AVRC_INT_H
+
+#include "avct_defs.h"
+#include "avrc_api.h"
+
+/* DEBUG FLAGS
+ *
+ * #define META_DEBUG_ENABLED
+ */
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* Number of attributes in AVRC SDP record. */
+#define AVRC_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define AVRC_NUM_PROTO_ELEMS 2
+
+#ifndef AVRC_MIN_CMD_LEN
+#define AVRC_MIN_CMD_LEN 20
+#endif
+
+#define AVRC_UNIT_OPRND_BYTES 5
+#define AVRC_SUB_OPRND_BYTES 4
+#define AVRC_SUBRSP_OPRND_BYTES 3
+#define AVRC_SUB_PAGE_MASK 7
+#define AVRC_SUB_PAGE_SHIFT 4
+#define AVRC_SUB_EXT_CODE 7
+#define AVRC_PASS_OP_ID_MASK 0x7F
+#define AVRC_PASS_STATE_MASK 0x80
+#define AVRC_CMD_OPRND_PAD 0xFF
+
+#define AVRC_CTYPE_MASK 0x0F
+#define AVRC_SUBTYPE_MASK 0xF8
+#define AVRC_SUBTYPE_SHIFT 3
+#define AVRC_SUBID_MASK 0x07
+#define AVRC_SUBID_IGNORE 0x07
+
+#define AVRC_SINGLE_PARAM_SIZE 1
+#define AVRC_METADATA_PKT_TYPE_MASK 0x03
+#define AVRC_PASS_THOUGH_MSG_MASK 0x80 /* MSB of msg_type indicates the PAS THROUGH msg */
+#define AVRC_VENDOR_UNIQUE_MASK 0x70 /* vendor unique id */
+
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;}
+
+#define AVRC_AVC_HDR_SIZE 3 /* ctype, subunit*, opcode */
+
+#define AVRC_MIN_META_HDR_SIZE 4 /* pdu id(1), packet type(1), param len(2) */
+#define AVRC_MIN_BROWSE_HDR_SIZE 3 /* pdu id(1), param len(2) */
+
+#define AVRC_VENDOR_HDR_SIZE 6 /* ctype, subunit*, opcode, CO_ID */
+#define AVRC_MSG_VENDOR_OFFSET 23
+#define AVRC_MIN_VENDOR_SIZE (AVRC_MSG_VENDOR_OFFSET + BT_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)
+
+#define AVRC_PASS_THRU_SIZE 8
+#define AVRC_MSG_PASS_THRU_OFFSET 25
+#define AVRC_MIN_PASS_THRU_SIZE (AVRC_MSG_PASS_THRU_OFFSET + BT_HDR_SIZE + 4)
+
+#define AVRC_MIN_BROWSE_SIZE (AVCT_BROWSE_OFFSET + BT_HDR_SIZE + AVRC_MIN_BROWSE_HDR_SIZE)
+
+#define AVRC_CTRL_PKT_LEN(pf, pk) {pf = (UINT8 *)((pk) + 1) + (pk)->offset + 2;}
+
+#define AVRC_MAX_CTRL_DATA_LEN (AVRC_PACKET_LEN)
+
+/*****************************************************************************
+** Type definitions
+*****************************************************************************/
+
+
+typedef struct
+{
+ tAVRC_CONN_CB ccb[AVCT_NUM_CONN];
+ tAVRC_FIND_CBACK *p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
+ UINT16 service_uuid; /* service UUID to search */
+ UINT8 trace_level;
+} tAVRC_CB;
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if AVRC_DYNAMIC_MEMORY == FALSE
+AVRC_API extern tAVRC_CB avrc_cb;
+#else
+AVRC_API extern tAVRC_CB *avrc_cb_ptr;
+#define avrc_cb (*avrc_cb_ptr)
+#endif
+
+extern BOOLEAN avrc_is_valid_pdu_id(UINT8 pdu_id);
+extern BOOLEAN avrc_is_valid_player_attrib_value(UINT8 attrib, UINT8 value);
+extern BT_HDR * avrc_alloc_ctrl_pkt (UINT8 pdu);
+extern tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id);
+extern UINT8 avrc_opcode_from_pdu(UINT8 pdu);
+extern BOOLEAN avrc_is_valid_opcode(UINT8 opcode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVRC_INT_H */
+
diff --git a/stack/avrc/avrc_opt.c b/stack/avrc/avrc_opt.c
new file mode 100644
index 0000000..208a6c2
--- /dev/null
+++ b/stack/avrc/avrc_opt.c
@@ -0,0 +1,230 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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:
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * nterface to AVRCP optional commands
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+#include "wcassert.h"
+
+
+/******************************************************************************
+**
+** Function avrc_vendor_msg
+**
+** Description Compose a VENDOR DEPENDENT command according to p_msg
+**
+** Input Parameters:
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns pointer to a valid GKI buffer if successful.
+** NULL if p_msg is NULL.
+**
+******************************************************************************/
+static BT_HDR * avrc_vendor_msg(tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_cmd;
+ UINT8 *p_data;
+
+ WC_ASSERT(p_msg != NULL);
+
+ WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->vendor_len));
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (p_msg->hdr.subunit_type << AVRC_SUBTYPE_SHIFT) | p_msg->hdr.subunit_id;
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, p_msg->company_id);
+ if(p_msg->vendor_len && p_msg->p_vendor_data)
+ {
+ memcpy(p_data, p_msg->p_vendor_data, p_msg->vendor_len);
+ }
+ p_cmd->len = (UINT16) (p_data + p_msg->vendor_len - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ }
+ return p_cmd;
+}
+
+/******************************************************************************
+**
+** Function AVRC_UnitCmd
+**
+** Description Send a UNIT INFO command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_UnitCmd(UINT8 handle, UINT8 label)
+{
+ BT_HDR *p_cmd;
+ UINT8 *p_data;
+
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = AVRC_CMD_STATUS;
+ /* unit & id ignore */
+ *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+ *p_data++ = AVRC_OP_UNIT_INFO;
+ memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_UNIT_OPRND_BYTES);
+ p_cmd->len = p_data + AVRC_UNIT_OPRND_BYTES - (UINT8 *)(p_cmd + 1) - p_cmd->offset;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ }
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+**
+** Function AVRC_SubCmd
+**
+** Description Send a SUBUNIT INFO command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** page: Specifies which part of the subunit type table
+** is requested. For AVRCP it is typically zero.
+** Value range is 0-7.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_SubCmd(UINT8 handle, UINT8 label, UINT8 page)
+{
+ BT_HDR *p_cmd;
+ UINT8 *p_data;
+
+ if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
+ {
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = AVRC_CMD_STATUS;
+ /* unit & id ignore */
+ *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+ *p_data++ = AVRC_OP_SUB_INFO;
+ *p_data++ = ((page&AVRC_SUB_PAGE_MASK) << AVRC_SUB_PAGE_SHIFT) | AVRC_SUB_EXT_CODE;
+ memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_SUB_OPRND_BYTES);
+ p_cmd->len = p_data + AVRC_SUB_OPRND_BYTES - (UINT8 *)(p_cmd + 1) - p_cmd->offset;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+ }
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+**
+** Function AVRC_VendorCmd
+**
+** Description Send a VENDOR DEPENDENT command to the peer device. This
+** function can only be called for controller role connections.
+** Any response message from the peer is passed back through
+** the tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label.
+**
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_VendorCmd(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_buf = avrc_vendor_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+ else
+ return AVCT_NO_RESOURCES;
+}
+
+
+/******************************************************************************
+**
+** Function AVRC_VendorRsp
+**
+** Description Send a VENDOR DEPENDENT response to the peer device. This
+** function can only be called for target role connections.
+** This function must be called when a VENDOR DEPENDENT
+** command message is received from the peer through the
+** tAVRC_MSG_CBACK callback function.
+**
+** Input Parameters:
+** handle: Handle of this connection.
+**
+** label: Transaction label. Must be the same value as
+** passed with the command message in the callback function.
+**
+** p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+UINT16 AVRC_VendorRsp(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg)
+{
+ BT_HDR *p_buf = avrc_vendor_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
+ else
+ return AVCT_NO_RESOURCES;
+}
+
+
+
diff --git a/stack/avrc/avrc_sdp.c b/stack/avrc/avrc_sdp.c
new file mode 100644
index 0000000..427894c
--- /dev/null
+++ b/stack/avrc/avrc_sdp.c
@@ -0,0 +1,297 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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:
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * AVRCP SDP related functions
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "gki.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if AVRC_DYNAMIC_MEMORY == FALSE
+tAVRC_CB avrc_cb;
+#endif
+
+/* update AVRC_NUM_PROTO_ELEMS if this constant is changed */
+const tSDP_PROTOCOL_ELEM avrc_proto_list [] =
+{
+ {UUID_PROTOCOL_L2CAP, 1, {AVCT_PSM, 0} },
+ {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_0, 0} }
+};
+
+
+
+/******************************************************************************
+**
+** Function avrc_sdp_cback
+**
+** Description This is the SDP callback function used by A2D_FindService.
+** This function will be executed by SDP when the service
+** search is completed. If the search is successful, it
+** finds the first record in the database that matches the
+** UUID of the search. Then retrieves various parameters
+** from the record. When it is finished it calls the
+** application callback function.
+**
+** Returns Nothing.
+**
+******************************************************************************/
+static void avrc_sdp_cback(UINT16 status)
+{
+ AVRC_TRACE_API1("avrc_sdp_cback status: %d", status);
+
+ /* reset service_uuid, so can start another find service */
+ avrc_cb.service_uuid = 0;
+
+ /* return info from sdp record in app callback function */
+ (*avrc_cb.p_cback) (status);
+
+ return;
+}
+
+/******************************************************************************
+**
+** Function AVRC_FindService
+**
+** Description This function is called by the application to perform service
+** discovery and retrieve AVRCP SDP record information from a
+** peer device. Information is returned for the first service
+** record found on the server that matches the service UUID.
+** The callback function will be executed when service discovery
+** is complete. There can only be one outstanding call to
+** AVRC_FindService() at a time; the application must wait for
+** the callback before it makes another call to the function.
+** The application is responsible for allocating memory for the
+** discovery database. It is recommended that the size of the
+** discovery database be at least 300 bytes. The application
+** can deallocate the memory after the callback function has
+** executed.
+**
+** Input Parameters:
+** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+** bd_addr: BD address of the peer device.
+**
+** p_db: SDP discovery database parameters.
+**
+** p_cback: Pointer to the callback function.
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_BAD_PARAMS if discovery database parameters are invalid.
+** AVRC_NO_RESOURCES if there are not enough resources to
+** perform the service search.
+**
+******************************************************************************/
+UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
+ tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback)
+{
+ tSDP_UUID uuid_list;
+ BOOLEAN result = TRUE;
+ UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SERVICE_NAME,
+ ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_PROVIDER_NAME};
+
+ AVRC_TRACE_API1("AVRC_FindService uuid: %x", service_uuid);
+ if( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
+ p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+ return AVRC_BAD_PARAM;
+
+ /* check if it is busy */
+ if( avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET ||
+ avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ return AVRC_NO_RESOURCES;
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ if(p_db->p_attrs == NULL || p_db->num_attr == 0)
+ {
+ p_db->p_attrs = a2d_attr_list;
+ p_db->num_attr = AVRC_NUM_ATTR;
+ }
+
+ result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr,
+ p_db->p_attrs);
+
+ if (result == TRUE)
+ {
+ /* store service_uuid and discovery db pointer */
+ avrc_cb.p_db = p_db->p_db;
+ avrc_cb.service_uuid = service_uuid;
+ avrc_cb.p_cback = p_cback;
+
+ /* perform service search */
+ result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
+ }
+
+ return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+/******************************************************************************
+**
+** Function AVRC_AddRecord
+**
+** Description This function is called to build an AVRCP SDP record.
+** Prior to calling this function the application must
+** call SDP_CreateRecord() to create an SDP record.
+**
+** Input Parameters:
+** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+** p_service_name: Pointer to a null-terminated character
+** string containing the service name.
+** If service name is not used set this to NULL.
+**
+** p_provider_name: Pointer to a null-terminated character
+** string containing the provider name.
+** If provider name is not used set this to NULL.
+**
+** categories: Supported categories.
+**
+** sdp_handle: SDP handle returned by SDP_CreateRecord().
+**
+** Output Parameters:
+** None.
+**
+** Returns AVRC_SUCCESS if successful.
+** AVRC_NO_RESOURCES if not enough resources to build the SDP record.
+**
+******************************************************************************/
+UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name,
+ char *p_provider_name, UINT16 categories, UINT32 sdp_handle)
+{
+ UINT16 browse_list[1];
+ BOOLEAN result = TRUE;
+ UINT8 temp[8];
+ UINT8 *p;
+ UINT16 count = 1;
+ UINT16 class_list[2];
+
+
+ AVRC_TRACE_API1("AVRC_AddRecord uuid: %x", service_uuid);
+
+ if( service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL )
+ return AVRC_BAD_PARAM;
+
+ /* add service class id list */
+ class_list[0] = service_uuid;
+ 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 */
+ result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_0);
+
+ /* add supported categories */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, categories);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ (UINT32)2, (UINT8*)temp);
+
+ /* add provider name */
+ if (p_provider_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name);
+ }
+
+ /* add service name */
+ if (p_service_name != NULL)
+ {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+
+ return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+
+
+/******************************************************************************
+**
+** Function AVRC_SetTraceLevel
+**
+** Description Sets the trace level for AVRC. If 0xff is passed, the
+** current trace level is returned.
+**
+** Input Parameters:
+** new_level: The level to set the AVRC tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new trace level or current trace level if
+** the input parameter is 0xff.
+**
+******************************************************************************/
+UINT8 AVRC_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ avrc_cb.trace_level = new_level;
+
+ return (avrc_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function AVRC_Init
+**
+** Description This function is called at stack startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** control block and tracing level.
+**
+** Returns void
+**
+*******************************************************************************/
+void AVRC_Init(void)
+{
+ memset(&avrc_cb, 0, sizeof(tAVRC_CB));
+
+#if defined(AVRC_INITIAL_TRACE_LEVEL)
+ avrc_cb.trace_level = AVRC_INITIAL_TRACE_LEVEL;
+#else
+ avrc_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+