summaryrefslogtreecommitdiffstats
path: root/stack/avdt/avdt_ccb_act.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/avdt/avdt_ccb_act.c')
-rw-r--r--stack/avdt/avdt_ccb_act.c1108
1 files changed, 1108 insertions, 0 deletions
diff --git a/stack/avdt/avdt_ccb_act.c b/stack/avdt/avdt_ccb_act.c
new file mode 100644
index 0000000..5719be9
--- /dev/null
+++ b/stack/avdt/avdt_ccb_act.c
@@ -0,0 +1,1108 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the action functions associated with the channel
+ * control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "data_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "gki.h"
+#include "btu.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clear_ccb
+**
+** Description This function clears out certain buffers, queues, and
+** other data elements of a ccb.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+static void avdt_ccb_clear_ccb(tAVDT_CCB *p_ccb)
+{
+ BT_HDR *p_buf;
+
+ /* clear certain ccb variables */
+ p_ccb->cong = FALSE;
+ p_ccb->ret_count = 0;
+
+ /* free message being fragmented */
+ if (p_ccb->p_curr_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_curr_msg);
+ p_ccb->p_curr_msg = NULL;
+ }
+
+ /* free message being reassembled */
+ if (p_ccb->p_rx_msg != NULL)
+ {
+ GKI_freebuf(p_ccb->p_rx_msg);
+ p_ccb->p_rx_msg = NULL;
+ }
+
+ /* clear out response queue */
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL)
+ {
+ GKI_freebuf(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chan_open
+**
+** Description This function calls avdt_ad_open_req() to
+** initiate a signaling channel connection.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
+ avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chan_close
+**
+** Description This function calls avdt_ad_close_req() to close a
+** signaling channel connection.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* close the transport channel used by this CCB */
+ avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_close
+**
+** Description This function checks for active streams on this CCB.
+** If there are none, it starts an idle timer.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+
+ /* see if there are any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+ {
+ break;
+ }
+ }
+
+ /* if no active scbs start idle timer */
+ if (i == AVDT_NUM_SEPS)
+ {
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_IDLE, avdt_cb.rcb.idle_tout);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_discover_cmd
+**
+** Description This function is called when a discover command is
+** received from the peer. It gathers up the stream
+** information for all allocated streams and initiates
+** sending of a discover response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS];
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ int i;
+
+ p_data->msg.discover_rsp.p_sep_info = sep_info;
+ p_data->msg.discover_rsp.num_seps = 0;
+
+ /* for all allocated scbs */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if (p_scb->allocated)
+ {
+ /* copy sep info */
+ sep_info[i].in_use = p_scb->in_use;
+ sep_info[i].seid = i + 1;
+ sep_info[i].media_type = p_scb->cs.media_type;
+ sep_info[i].tsep = p_scb->cs.tsep;
+
+ p_data->msg.discover_rsp.num_seps++;
+ }
+ }
+
+ /* send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_discover_rsp
+**
+** Description This function is called when a discover response or
+** reject is received from the peer. It calls the application
+** callback function with the results.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* we're done with procedure */
+ p_ccb->proc_busy = FALSE;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
+ (tAVDT_CTRL *)(&p_data->msg.discover_rsp));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_getcap_cmd
+**
+** Description This function is called when a get capabilities command
+** is received from the peer. It retrieves the stream
+** configuration for the requested stream and initiates
+** sending of a get capabilities response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+
+ /* look up scb for seid sent to us */
+ p_scb = avdt_scb_by_hdl(p_data->msg.single.seid);
+
+ p_data->msg.svccap.p_cfg = &p_scb->cs.cfg;
+
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_getcap_rsp
+**
+** Description This function is called with a get capabilities response
+** or reject is received from the peer. It calls the
+** application callback function with the results.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* we're done with procedure */
+ p_ccb->proc_busy = FALSE;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
+ (tAVDT_CTRL *)(&p_data->msg.svccap));
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_start_cmd
+**
+** Description This function is called when a start command is received
+** from the peer. It verifies that all requested streams
+** are in the proper state. If so, it initiates sending of
+** a start response. Otherwise it sends a start reject.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 seid;
+ UINT8 err_code;
+
+ /* verify all streams in the right state */
+ if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code)) == 0)
+ {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_start_rsp
+**
+** Description This function is called when a start response or reject
+** is received from the peer. Using the SEIDs stored in the
+** current command message, it sends a start response or start
+** reject event to each SCB associated with the command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 event;
+ int i;
+ UINT8 *p;
+ tAVDT_SCB *p_scb;
+
+ /* determine rsp or rej event */
+ event = (p_data->msg.hdr.err_code == 0) ?
+ AVDT_SCB_MSG_START_RSP_EVT : AVDT_SCB_MSG_START_REJ_EVT;
+
+ /* get to where seid's are stashed in current cmd */
+ p = (UINT8 *)(p_ccb->p_curr_cmd + 1);
+
+ /* little trick here; length of current command equals number of streams */
+ for (i = 0; i < p_ccb->p_curr_cmd->len; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_suspend_cmd
+**
+** Description This function is called when a suspend command is received
+** from the peer. It verifies that all requested streams are
+** in the proper state. If so, it initiates sending of a
+** suspend response. Otherwise it sends a suspend reject.
+
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 seid;
+ UINT8 err_code;
+
+ /* verify all streams in the right state */
+ if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code)) == 0)
+ {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data);
+ }
+ else
+ {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_hdl_suspend_rsp
+**
+** Description This function is called when a suspend response or reject
+** is received from the peer. Using the SEIDs stored in the
+** current command message, it sends a suspend response or
+** suspend reject event to each SCB associated with the command.
+**
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 event;
+ int i;
+ UINT8 *p;
+ tAVDT_SCB *p_scb;
+
+ /* determine rsp or rej event */
+ event = (p_data->msg.hdr.err_code == 0) ?
+ AVDT_SCB_MSG_SUSPEND_RSP_EVT : AVDT_SCB_MSG_SUSPEND_REJ_EVT;
+
+ /* get to where seid's are stashed in current cmd */
+ p = (UINT8 *)(p_ccb->p_curr_cmd + 1);
+
+ /* little trick here; length of current command equals number of streams */
+ for (i = 0; i < p_ccb->p_curr_cmd->len; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_discover_cmd
+**
+** Description This function is called to send a discover command to the
+** peer. It copies variables needed for the procedure from
+** the event to the CCB. It marks the CCB as busy and then
+** sends a discover command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->discover.p_sep_info;
+ p_ccb->proc_cback = p_data->discover.p_cback;
+ p_ccb->proc_param = p_data->discover.num_seps;
+
+ /* we're busy */
+ p_ccb->proc_busy = TRUE;
+
+ /* build and queue discover req */
+ avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_discover_rsp
+**
+** Description This function is called to send a discover response to
+** the peer. It takes the stream information passed in the
+** event and sends a discover response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_getcap_cmd
+**
+** Description This function is called to send a get capabilities command
+** to the peer. It copies variables needed for the procedure
+** from the event to the CCB. It marks the CCB as busy and
+** then sends a get capabilities command.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 sig_id = AVDT_SIG_GETCAP;
+
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->getcap.p_cfg;
+ p_ccb->proc_cback = p_data->getcap.p_cback;
+
+ /* we're busy */
+ p_ccb->proc_busy = TRUE;
+
+ /* build and queue discover req */
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG *) &p_data->getcap.single);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_getcap_rsp
+**
+** Description This function is called to send a get capabilities response
+** to the peer. It takes the stream information passed in the
+** event and sends a get capabilities response.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 sig_id = AVDT_SIG_GETCAP;
+
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_start_cmd
+**
+** Description This function is called to send a start command to the
+** peer. It verifies that all requested streams are in the
+** proper state. If so, it sends a start command. Otherwise
+** send ourselves back a start reject.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ tAVDT_MSG avdt_msg;
+ UINT8 seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+ {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg);
+ }
+ else
+ {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_start_rsp
+**
+** Description This function is called to send a start response to the
+** peer. It takes the stream information passed in the event
+** and sends a start response. Then it sends a start event
+** to the SCB for each stream.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+ int i;
+
+ /* send response message */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg);
+
+ /* send start event to each scb */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_suspend_cmd
+**
+** Description This function is called to send a suspend command to the
+** peer. It verifies that all requested streams are in the
+** proper state. If so, it sends a suspend command.
+** Otherwise it calls the callback function for each requested
+** stream and sends a suspend confirmation with failure.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb;
+ tAVDT_MSG avdt_msg;
+ UINT8 seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+ {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+ else
+ {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_suspend_rsp
+**
+** Description This function is called to send a suspend response to the
+** peer. It takes the stream information passed in the event
+** and sends a suspend response. Then it sends a suspend event
+** to the SCB for each stream.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_SCB *p_scb;
+ int i;
+
+ /* send response message */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+
+ /* send start event to each scb */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++)
+ {
+ if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL)
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clear_cmds
+**
+** Description This function is called when the signaling channel is
+** closed to clean up any pending commands. For each pending
+** command in the command queue, it frees the command and
+** calls the application callback function indicating failure.
+** Certain CCB variables are also initialized.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ int i;
+ tAVDT_SCB *p_scb = &avdt_cb.scb[0];
+ UINT8 err_code = AVDT_ERR_CONNECT;
+
+ /* clear the ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out command queue; this is a little tricky here; we need
+ ** to handle the case where there is a command on deck in p_curr_cmd,
+ ** plus we need to clear out the queue
+ */
+ do
+ {
+ /* we know p_curr_cmd = NULL after this */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* set up next message */
+ p_ccb->p_curr_cmd = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q);
+
+ } while (p_ccb->p_curr_cmd != NULL);
+
+ /* send a CC_CLOSE_EVT any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+ {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_cmd_fail
+**
+** Description This function is called when there is a response timeout.
+** The currently pending command is freed and we fake a
+** reject message back to ourselves.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_MSG msg;
+ UINT8 evt;
+ tAVDT_SCB *p_scb;
+
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ /* set up data */
+ msg.hdr.err_code = p_data->err_code;
+ msg.hdr.err_param = 0;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* pretend that we received a rej message */
+ evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1];
+
+ if (evt & AVDT_CCB_MKR)
+ {
+ avdt_ccb_event(p_ccb, (UINT8) (evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+ }
+ else
+ {
+ /* we get the scb out of the current cmd */
+ p_scb = avdt_scb_by_hdl(*((UINT8 *)(p_ccb->p_curr_cmd + 1)));
+ if (p_scb != NULL)
+ {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+ }
+ }
+
+ GKI_freebuf(p_ccb->p_curr_cmd);
+ p_ccb->p_curr_cmd = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_free_cmd
+**
+** Description This function is called when a response is received for a
+** currently pending command. The command is freed.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ if (p_ccb->p_curr_cmd != NULL)
+ {
+ GKI_freebuf(p_ccb->p_curr_cmd);
+ p_ccb->p_curr_cmd = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_cong_state
+**
+** Description This function is called to set the congestion state for
+** the CCB.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ret_cmd
+**
+** Description This function is called to retransmit the currently
+** pending command. The retransmission count is incremented.
+** If the count reaches the maximum number of retransmissions,
+** the event is treated as a response timeout.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = AVDT_ERR_TIMEOUT;
+ BT_HDR *p_msg;
+
+ p_ccb->ret_count++;
+ if (p_ccb->ret_count == AVDT_RET_MAX)
+ {
+ /* command failed */
+ p_ccb->ret_count = 0;
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* go to next queued command */
+ avdt_ccb_snd_cmd(p_ccb, p_data);
+ }
+ else
+ {
+ /* if command pending and we're not congested and not sending a fragment */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd != NULL))
+ {
+ /* make copy of message in p_curr_cmd and send it */
+ if ((p_msg = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL)
+ {
+ memcpy(p_msg, p_ccb->p_curr_cmd,
+ (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + p_ccb->p_curr_cmd->len));
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+
+ /* restart timer */
+ btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_cmd
+**
+** Description This function is called the send the next command,
+** if any, in the command queue.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BT_HDR *p_msg;
+
+ /* do we have commands to send? send next command; make sure we're clear;
+ ** not congested, not sending fragment, not waiting for response
+ */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd == NULL))
+ {
+ if ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q)) != NULL)
+ {
+ /* make a copy of buffer in p_curr_cmd */
+ if ((p_ccb->p_curr_cmd = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL)
+ {
+ memcpy(p_ccb->p_curr_cmd, p_msg, (sizeof(BT_HDR) + p_msg->offset + p_msg->len));
+
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_snd_msg
+**
+** Description
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ BT_HDR *p_msg;
+
+ /* if not congested */
+ if (!p_ccb->cong)
+ {
+ /* are we sending a fragmented message? continue sending fragment */
+ if (p_ccb->p_curr_msg != NULL)
+ {
+ avdt_msg_send(p_ccb, NULL);
+ }
+ /* do we have responses to send? send them */
+ else if (!GKI_queue_is_empty(&p_ccb->rsp_q))
+ {
+ while ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL)
+ {
+ if (avdt_msg_send(p_ccb, p_msg) == TRUE)
+ {
+ /* break out if congested */
+ break;
+ }
+ }
+ }
+
+ /* do we have commands to send? send next command */
+ avdt_ccb_snd_cmd(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_reconn
+**
+** Description This function is called to enable a reconnect attempt when
+** a channel transitions from closing to idle state. It sets
+** the reconn variable to TRUE.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->reconn = TRUE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_clr_reconn
+**
+** Description This function is called to clear the reconn variable.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ p_ccb->reconn = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_reconn
+**
+** Description This function is called to check if a reconnect attempt
+** is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT
+** to the CCB. If disabled, the CCB is deallocated.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ UINT8 err_code = AVDT_ERR_CONNECT;
+
+ if (p_ccb->reconn)
+ {
+ p_ccb->reconn = FALSE;
+
+ /* clear out ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out current command, if any */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+ /* reopen the signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+ }
+ else
+ {
+ avdt_ccb_ll_closed(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_chk_timer
+**
+** Description This function stops the CCB timer if the idle timer is
+** running.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ if (p_ccb->timer_entry.event == BTU_TTYPE_AVDT_CCB_IDLE)
+ {
+ btu_stop_timer(&p_ccb->timer_entry);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_conn
+**
+** Description Set CCB variables associated with AVDT_ConnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* save callback */
+ p_ccb->p_conn_cback = p_data->connect.p_cback;
+
+ /* set security level */
+ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_data->connect.sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_set_disconn
+**
+** Description Set CCB variables associated with AVDT_DisconnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /*
+ AVDT_TRACE_EVENT2("avdt_ccb_set_disconn:conn:x%x, api:x%x",
+ p_ccb->p_conn_cback, p_data->disconnect.p_cback);
+ */
+ /* save callback */
+ if (p_data->disconnect.p_cback)
+ p_ccb->p_conn_cback = p_data->disconnect.p_cback;
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_do_disconn
+**
+** Description Do action associated with AVDT_DisconnectReq().
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* close channel */
+ avdt_ccb_chan_close(p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ll_closed
+**
+** Description Clear commands from and deallocate CCB.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CTRL_CBACK *p_cback;
+ BD_ADDR bd_addr;
+ tAVDT_CTRL avdt_ctrl;
+
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* save callback pointer, bd addr */
+ p_cback = p_ccb->p_conn_cback;
+ if (!p_cback)
+ p_cback = avdt_cb.p_conn_cback;
+ memcpy(bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* dealloc ccb */
+ avdt_ccb_dealloc(p_ccb, NULL);
+
+ /* call callback */
+ if (p_cback)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl);
+ }
+}
+
+/*******************************************************************************
+**
+** Function avdt_ccb_ll_opened
+**
+** Description Call callback on open.
+**
+**
+** Returns void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+ tAVDT_CTRL avdt_ctrl;
+
+ p_ccb->ll_opened = TRUE;
+
+ if (!p_ccb->p_conn_cback)
+ p_ccb->p_conn_cback = avdt_cb.p_conn_cback;
+
+ /* call callback */
+ if (p_ccb->p_conn_cback)
+ {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param;
+ (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, &avdt_ctrl);
+ }
+}