avrc_api.c revision 6dae552ef8d82b30fa66efab9c6f75644a805bbe
1/******************************************************************************
2 *
3 *  Copyright (C) 2003-2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 *  Interface to AVRCP mandatory commands
22 *
23 ******************************************************************************/
24#include <string.h>
25
26#include "gki.h"
27#include "avrc_api.h"
28#include "avrc_int.h"
29#include "wcassert.h"
30
31/*****************************************************************************
32**  Global data
33*****************************************************************************/
34
35
36#define AVRC_MAX_RCV_CTRL_EVT   AVCT_BROWSE_UNCONG_IND_EVT
37
38static const UINT8 avrc_ctrl_event_map[] =
39{
40    AVRC_OPEN_IND_EVT,  /* AVCT_CONNECT_CFM_EVT */
41    AVRC_OPEN_IND_EVT,  /* AVCT_CONNECT_IND_EVT */
42    AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */
43    AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */
44    AVRC_CONG_IND_EVT,  /* AVCT_CONG_IND_EVT */
45    AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */
46    AVRC_BROWSE_OPEN_IND_EVT,  /* AVCT_BROWSE_CONN_CFM_EVT   */
47    AVRC_BROWSE_OPEN_IND_EVT,  /* AVCT_BROWSE_CONN_IND_EVT   */
48    AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */
49    AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */
50    AVRC_BROWSE_CONG_IND_EVT,  /* AVCT_BROWSE_CONG_IND_EVT    */
51    AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT  */
52};
53
54#define AVRC_OP_DROP        0xFE    /* use this unused opcode to indication no need to call the callback function */
55#define AVRC_OP_DROP_N_FREE 0xFD    /* use this unused opcode to indication no need to call the callback function & free buffer */
56
57/******************************************************************************
58**
59** Function         avrc_ctrl_cback
60**
61** Description      This is the callback function used by AVCTP to report
62**                  received link events.
63**
64** Returns          Nothing.
65**
66******************************************************************************/
67static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result,
68                                BD_ADDR peer_addr)
69{
70    UINT8   avrc_event;
71
72    if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback)
73    {
74        avrc_event = avrc_ctrl_event_map[event];
75        if (event == AVCT_CONNECT_CFM_EVT)
76        {
77            if (result != 0) /* failed */
78                avrc_event = AVRC_CLOSE_IND_EVT;
79        }
80        (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
81    }
82    /* else drop the unknown event*/
83}
84
85/******************************************************************************
86**
87** Function         avrc_get_data_ptr
88**
89** Description      If the offset in the received buffer is smaller than required
90**                  move the portion of data AVRC cares.
91**
92** Returns          Nothing.
93**
94******************************************************************************/
95static UINT8 * avrc_get_data_ptr(BT_HDR *p_pkt)
96{
97    UINT8   *p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
98    int     i, gap;
99
100    if (p_pkt->offset < AVCT_MSG_OFFSET)
101    {
102        gap = AVCT_MSG_OFFSET - p_pkt->offset;
103        for(i=p_pkt->len; i>0; i--)
104        {
105            *(p_data + i + gap) = *(p_data + i);
106        }
107        p_pkt->offset   += gap;
108        p_data          = (UINT8 *)(p_pkt+1) + p_pkt->offset;
109    }
110    *p_data         = AVRC_RSP_IMPL_STBL;
111    return p_data;
112}
113
114#if (AVRC_METADATA_INCLUDED == TRUE)
115/******************************************************************************
116**
117** Function         avrc_prep_end_frag
118**
119** Description      This function prepares an end response fragment
120**
121** Returns          Nothing.
122**
123******************************************************************************/
124static void avrc_prep_end_frag(UINT8 handle)
125{
126    tAVRC_FRAG_CB   *p_fcb;
127    BT_HDR  *p_pkt_new;
128    UINT8   *p_data, *p_orig_data;
129    UINT8   rsp_type;
130
131    AVRC_TRACE_DEBUG0 ("avrc_prep_end_frag" );
132    p_fcb = &avrc_cb.fcb[handle];
133
134    /* The response type of the end fragment should be the same as the the PDU of "End Fragment
135    ** Response" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
136    */
137    p_orig_data = ((UINT8 *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
138    rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
139
140    p_pkt_new           = p_fcb->p_fmsg;
141    p_pkt_new->len      -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
142    p_pkt_new->offset   += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
143    p_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
144    *p_data++       = rsp_type;
145    *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
146    *p_data++       = AVRC_OP_VENDOR;
147    AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
148    *p_data++       = p_fcb->frag_pdu;
149    *p_data++       = AVRC_PKT_END;
150
151    /* 4=pdu, pkt_type & len */
152    UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE));
153}
154
155/******************************************************************************
156**
157** Function         avrc_send_continue_frag
158**
159** Description      This function sends a continue response fragment
160**
161** Returns          Nothing.
162**
163******************************************************************************/
164static void avrc_send_continue_frag(UINT8 handle, UINT8 label)
165{
166    tAVRC_FRAG_CB   *p_fcb;
167    BT_HDR  *p_pkt_old, *p_pkt;
168    UINT8   *p_old, *p_data;
169    UINT8   cr = AVCT_RSP;
170    tAVRC_RSP   rej_rsp;
171
172    p_fcb = &avrc_cb.fcb[handle];
173    p_pkt = p_fcb->p_fmsg;
174
175    AVRC_TRACE_DEBUG1 ("avrc_send_continue_frag len(%d) / AVRC_MAX_CTRL_DATA_LEN", p_pkt->len );
176    if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
177    {
178        p_pkt_old = p_fcb->p_fmsg;
179        p_pkt = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + AVCT_MSG_OFFSET + BT_HDR_SIZE));
180        if (p_pkt)
181        {
182            p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
183            p_pkt->offset       = AVCT_MSG_OFFSET;
184            p_pkt->layer_specific = p_pkt_old->layer_specific;
185            p_pkt->event = p_pkt_old->event;
186            p_old = (UINT8 *)(p_pkt_old+1) + p_pkt_old->offset;
187            p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
188            memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
189            /* use AVRC continue packet type */
190            p_data += AVRC_VENDOR_HDR_SIZE;
191            p_data++; /* pdu */
192            *p_data++ = AVRC_PKT_CONTINUE;
193            /* 4=pdu, pkt_type & len */
194            UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4));
195
196            /* prepare the left over for as an end fragment */
197            avrc_prep_end_frag (handle);
198        }
199        else
200        {
201            /* use the current GKI buffer to send Internal error status */
202            p_pkt = p_fcb->p_fmsg;
203            p_fcb->p_fmsg = NULL;
204            p_fcb->frag_enabled = FALSE;
205            AVRC_TRACE_ERROR0 ("AVRC_MsgReq no buffers for fragmentation - send internal error" );
206            p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
207            *p_data++ = AVRC_PDU_REQUEST_CONTINUATION_RSP;
208            *p_data++ = 0;
209            UINT16_TO_BE_STREAM(p_data, 0);
210            p_pkt->len = 4;
211            rej_rsp.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
212            rej_rsp.status = AVRC_STS_INTERNAL_ERR;
213            AVRC_BldResponse( handle, (tAVRC_RESPONSE *)&rej_rsp, &p_pkt);
214            cr = AVCT_RSP;
215        }
216    }
217    else
218    {
219        /* end fragment. clean the control block */
220        p_fcb->frag_enabled = FALSE;
221        p_fcb->p_fmsg       = NULL;
222    }
223    AVCT_MsgReq( handle, label, cr, p_pkt);
224}
225
226/******************************************************************************
227**
228** Function         avrc_proc_vendor_command
229**
230** Description      This function processes received vendor command.
231**
232** Returns          if not NULL, the response to send right away.
233**
234******************************************************************************/
235static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
236                               BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg)
237{
238    BT_HDR      *p_rsp = NULL;
239    UINT8       *p_data;
240    UINT8       *p_begin;
241    UINT8       pkt_type;
242    BOOLEAN     abort_frag = FALSE;
243    tAVRC_STS   status = AVRC_STS_NO_ERROR;
244    tAVRC_FRAG_CB   *p_fcb;
245
246    p_begin  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
247    p_data   = p_begin + AVRC_VENDOR_HDR_SIZE;
248    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
249
250    if (pkt_type != AVRC_PKT_SINGLE)
251    {
252        /* reject - commands can only be in single packets at AVRCP level */
253        AVRC_TRACE_ERROR1 ("commands must be in single packet pdu:0x%x", *p_data );
254        /* use the current GKI buffer to send the reject */
255        status = AVRC_STS_BAD_CMD;
256    }
257    /* check if there are fragments waiting to be sent */
258    else if (avrc_cb.fcb[handle].frag_enabled)
259    {
260        p_fcb = &avrc_cb.fcb[handle];
261        if (p_msg->company_id == AVRC_CO_METADATA)
262        {
263            switch (*p_data)
264            {
265            case AVRC_PDU_ABORT_CONTINUATION_RSP:
266                /* aborted by CT - send accept response */
267                abort_frag = TRUE;
268                p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset;
269                *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
270                if (*(p_data + 4) != p_fcb->frag_pdu)
271                {
272                    *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
273                    *(p_data + 4) = AVRC_STS_BAD_PARAM;
274                }
275                else
276                {
277                    p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
278                    UINT16_TO_BE_STREAM(p_data, 0);
279                    p_pkt->len = (p_data - p_begin);
280                }
281                AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt);
282                p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */
283                break;
284
285            case AVRC_PDU_REQUEST_CONTINUATION_RSP:
286                if (*(p_data + 4) == p_fcb->frag_pdu)
287                {
288                    avrc_send_continue_frag(handle, label);
289                    p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
290                }
291                else
292                {
293                    /* the pdu id does not match - reject the command using the current GKI buffer */
294                    AVRC_TRACE_ERROR2("avrc_proc_vendor_command continue pdu: 0x%x does not match \
295                    current re-assembly pdu: 0x%x",
296                        *(p_data + 4), p_fcb->frag_pdu);
297                    status = AVRC_STS_BAD_PARAM;
298                    abort_frag = TRUE;
299                }
300                break;
301
302            default:
303                /* implicit abort */
304                abort_frag = TRUE;
305            }
306        }
307        else
308        {
309            abort_frag = TRUE;
310            /* implicit abort */
311        }
312
313        if (abort_frag)
314        {
315            if (p_fcb->p_fmsg)
316                GKI_freebuf(p_fcb->p_fmsg);
317            p_fcb->p_fmsg = NULL;
318            p_fcb->frag_enabled = FALSE;
319        }
320    }
321
322    if (status != AVRC_STS_NO_ERROR)
323    {
324        /* use the current GKI buffer to build/send the reject message */
325        p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
326        *p_data++ = AVRC_RSP_REJ;
327        p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
328        *p_data++ = 0;                  /* pkt_type */
329        UINT16_TO_BE_STREAM(p_data, 1); /* len */
330        *p_data++ = status;             /* error code */
331        p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
332        p_rsp = p_pkt;
333    }
334
335    return p_rsp;
336}
337
338/******************************************************************************
339**
340** Function         avrc_proc_far_msg
341**
342** Description      This function processes metadata fragmenation
343**                  and reassembly
344**
345** Returns          0, to report the message with msg_cback .
346**
347******************************************************************************/
348static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_pkt,
349    tAVRC_MSG_VENDOR *p_msg)
350{
351    BT_HDR      *p_pkt = *pp_pkt;
352    UINT8       *p_data;
353    BOOLEAN     drop = FALSE;
354    BT_HDR      *p_rsp = NULL;
355    BT_HDR      *p_cmd = NULL;
356    BOOLEAN     req_continue = FALSE;
357    BT_HDR      *p_pkt_new = NULL;
358    UINT8       pkt_type;
359    UINT16      buf_len;
360    tAVRC_RASM_CB   *p_rcb;
361    tAVRC_NEXT_CMD   avrc_cmd;
362
363    p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
364
365    /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */
366    p_data += AVRC_VENDOR_HDR_SIZE;
367
368    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
369    AVRC_TRACE_DEBUG1 ("pkt_type %d", pkt_type );
370    p_rcb = &avrc_cb.rcb[handle];
371    if (p_msg->company_id == AVRC_CO_METADATA)
372    {
373        /* check if the message needs to be re-assembled */
374        if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
375        {
376            /* previous fragments need to be dropped, when received another new message */
377            p_rcb->rasm_offset = 0;
378            if (p_rcb->p_rmsg)
379            {
380                GKI_freebuf(p_rcb->p_rmsg);
381                p_rcb->p_rmsg = NULL;
382            }
383        }
384
385        if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
386        {
387            /* not a single response packet - need to re-assemble metadata messages */
388            if (pkt_type == AVRC_PKT_START)
389            {
390                /* Allocate buffer for re-assembly */
391                p_rcb->rasm_pdu = *p_data;
392                if ((p_rcb->p_rmsg = (BT_HDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
393                {
394                    /* Copy START packet to buffer for re-assembling fragments*/
395                    memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR));   /* Copy bt hdr */
396
397                    /* Copy metadata message */
398                    memcpy((UINT8 *)(p_rcb->p_rmsg + 1),
399                           (UINT8 *)(p_pkt+1) + p_pkt->offset, p_pkt->len);
400
401                    /* offset of start of metadata response in reassembly buffer */
402                    p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
403
404                    /* Free original START packet, replace with pointer to reassembly buffer  */
405                    GKI_freebuf(p_pkt);
406                    *pp_pkt = p_rcb->p_rmsg;
407                }
408                else
409                {
410                    /* Unable to allocate buffer for fragmented avrc message. Reuse START
411                                      buffer for reassembly (re-assembled message may fit into ACL buf) */
412                    AVRC_TRACE_DEBUG0 ("Unable to allocate buffer for fragmented avrc message, \
413                                       reusing START buffer for reassembly");
414                    p_rcb->rasm_offset = p_pkt->offset;
415                    p_rcb->p_rmsg = p_pkt;
416                }
417
418                /* set offset to point to where to copy next - use the same re-asm logic as AVCT */
419                p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
420                req_continue = TRUE;
421            }
422            else if (p_rcb->p_rmsg == NULL)
423            {
424                /* Received a CONTINUE/END, but no corresponding START
425                              (or previous fragmented response was dropped) */
426                AVRC_TRACE_DEBUG0 ("Received a CONTINUE/END without no corresponding START \
427                                   (or previous fragmented response was dropped)");
428                drop = 5;
429                GKI_freebuf(p_pkt);
430                *pp_pkt = NULL;
431            }
432            else
433            {
434                /* get size of buffer holding assembled message */
435                buf_len = GKI_get_buf_size (p_rcb->p_rmsg) - sizeof(BT_HDR);
436                /* adjust offset and len of fragment for header byte */
437                p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
438                p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
439                /* verify length */
440                if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
441                {
442                    AVRC_TRACE_WARNING0("Fragmented message too big! - report the partial message");
443                    p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
444                    pkt_type = AVRC_PKT_END;
445                }
446
447                /* copy contents of p_pkt to p_rx_msg */
448                memcpy((UINT8 *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
449                       (UINT8 *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
450
451                if (pkt_type == AVRC_PKT_END)
452                {
453                    p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
454                    p_rcb->p_rmsg->len += p_pkt->len;
455                    p_pkt_new = p_rcb->p_rmsg;
456                    p_rcb->rasm_offset = 0;
457                    p_rcb->p_rmsg = NULL;
458                    p_msg->p_vendor_data   = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
459                    p_msg->hdr.ctype       = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
460                    /* 6 = ctype, subunit*, opcode & CO_ID */
461                    p_msg->p_vendor_data  += AVRC_VENDOR_HDR_SIZE;
462                    p_msg->vendor_len      = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
463                    p_data = p_msg->p_vendor_data + 1; /* skip pdu */
464                    *p_data++ = AVRC_PKT_SINGLE;
465                    UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
466                    AVRC_TRACE_DEBUG3("end frag:%d, total len:%d, offset:%d", p_pkt->len,
467                        p_pkt_new->len, p_pkt_new->offset);
468                }
469                else
470                {
471                    p_rcb->p_rmsg->offset += p_pkt->len;
472                    p_rcb->p_rmsg->len += p_pkt->len;
473                    p_pkt_new = NULL;
474                    req_continue = TRUE;
475                }
476                GKI_freebuf(p_pkt);
477                *pp_pkt = p_pkt_new;
478            }
479        }
480
481        if (cr == AVCT_CMD)
482        {
483            p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
484            if (p_rsp)
485            {
486                AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
487                drop = 3;
488            }
489            else if (p_msg->hdr.opcode == AVRC_OP_DROP)
490            {
491                drop = 1;
492            }
493            else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
494                drop = 4;
495
496        }
497        else if (cr == AVCT_RSP && req_continue == TRUE)
498        {
499            avrc_cmd.pdu    = AVRC_PDU_REQUEST_CONTINUATION_RSP;
500            avrc_cmd.status = AVRC_STS_NO_ERROR;
501            avrc_cmd.target_pdu = p_rcb->rasm_pdu;
502            if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR)
503            {
504                drop = 2;
505                AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
506            }
507        }
508    }
509
510    return drop;
511}
512#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
513
514/******************************************************************************
515**
516** Function         avrc_msg_cback
517**
518** Description      This is the callback function used by AVCTP to report
519**                  received AV control messages.
520**
521** Returns          Nothing.
522**
523******************************************************************************/
524static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
525                               BT_HDR *p_pkt)
526{
527    UINT8       opcode;
528    tAVRC_MSG   msg;
529    UINT8       *p_data;
530    UINT8       *p_begin;
531    UINT8       drop = 0;
532    BOOLEAN     free = TRUE;
533    BT_HDR      *p_rsp = NULL;
534    UINT8       *p_rsp_data;
535    int         xx;
536    BOOLEAN     reject = FALSE;
537#if (BT_USE_TRACES == TRUE)
538    char        *p_drop_msg = "dropped";
539#endif
540    tAVRC_MSG_VENDOR *p_msg = &msg.vendor;
541
542    if (cr == AVCT_CMD &&
543        (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len)))
544    {
545        /* Ignore the invalid AV/C command frame */
546#if (BT_USE_TRACES == TRUE)
547        p_drop_msg = "dropped - too long AV/C cmd frame size";
548#endif
549        GKI_freebuf(p_pkt);
550        return;
551    }
552
553    if (cr == AVCT_REJ)
554    {
555        /* The peer thinks that this PID is no longer open - remove this handle */
556        /*  */
557        GKI_freebuf(p_pkt);
558        AVCT_RemoveConn(handle);
559        return;
560    }
561
562    p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
563    memset(&msg, 0, sizeof(tAVRC_MSG) );
564    {
565        msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
566        AVRC_TRACE_DEBUG4("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
567                handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
568        msg.hdr.subunit_type    = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
569        msg.hdr.subunit_id      = p_data[1] & AVRC_SUBID_MASK;
570        opcode                  = p_data[2];
571    }
572
573    if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
574        ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
575    {
576
577        switch(opcode)
578        {
579        case AVRC_OP_UNIT_INFO:
580            if (cr == AVCT_CMD)
581            {
582                /* send the response to the peer */
583                p_rsp           = p_pkt; /* this also sets free = FALSE, drop = TRUE */
584                /* check & set the offset. set response code, set subunit_type & subunit_id,
585                   set AVRC_OP_UNIT_INFO */
586                /* 3 bytes: ctype, subunit*, opcode */
587                p_rsp_data      = avrc_get_data_ptr(p_pkt) + AVRC_AVC_HDR_SIZE;
588                *p_rsp_data++   = 7;
589                /* Panel subunit & id=0 */
590                *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
591                AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
592                p_rsp->len      = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
593                cr = AVCT_RSP;
594#if (BT_USE_TRACES == TRUE)
595                p_drop_msg = "auto respond";
596#endif
597            }
598            else
599            {
600                /* parse response */
601                p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
602                msg.unit.unit_type  = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
603                msg.unit.unit       = *p_data & AVRC_SUBID_MASK;
604                p_data++;
605                AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
606            }
607            break;
608
609        case AVRC_OP_SUB_INFO:
610            if (cr == AVCT_CMD)
611            {
612                /* send the response to the peer */
613                p_rsp           = p_pkt; /* this also sets free = FALSE, drop = TRUE */
614                /* check & set the offset. set response code, set (subunit_type & subunit_id),
615                   set AVRC_OP_SUB_INFO, set (page & extention code) */
616                p_rsp_data      = avrc_get_data_ptr(p_pkt) + 4;
617                /* Panel subunit & id=0 */
618                *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
619                memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
620                p_rsp_data      += AVRC_SUBRSP_OPRND_BYTES;
621                p_rsp->len      = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
622                cr = AVCT_RSP;
623#if (BT_USE_TRACES == TRUE)
624                p_drop_msg = "auto responded";
625#endif
626            }
627            else
628            {
629                /* parse response */
630                p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
631                msg.sub.page    = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
632                xx      = 0;
633                while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
634                {
635                    msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
636                    if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
637                        msg.sub.panel   = TRUE;
638                    xx++;
639                }
640            }
641            break;
642
643        case AVRC_OP_VENDOR:
644            p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
645            p_begin = p_data;
646            if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
647            {
648                if (cr == AVCT_CMD)
649                    reject = TRUE;
650                else
651                    drop = TRUE;
652                break;
653            }
654            p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
655            AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
656            p_msg->p_vendor_data   = p_data;
657            p_msg->vendor_len      = p_pkt->len - (p_data - p_begin);
658
659#if (AVRC_METADATA_INCLUDED == TRUE)
660            if (p_msg->company_id == AVRC_CO_METADATA)
661            {
662                /* Validate length for metadata message */
663                if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE))
664                {
665                    if (cr == AVCT_CMD)
666                        reject = TRUE;
667                    else
668                        drop = TRUE;
669                    break;
670                }
671
672                /* Check+handle fragmented messages */
673                drop = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
674            }
675            if (drop)
676            {
677                free = FALSE;
678                if (drop == 4)
679                    free = TRUE;
680#if (BT_USE_TRACES == TRUE)
681                switch (drop)
682                {
683                case 1:
684                    p_drop_msg = "sent_frag";
685                    break;
686                case 2:
687                    p_drop_msg = "req_cont";
688                    break;
689                case 3:
690                    p_drop_msg = "sent_frag3";
691                    break;
692                case 4:
693                    p_drop_msg = "sent_frag_free";
694                    break;
695                default:
696                    p_drop_msg = "sent_fragd";
697                }
698#endif
699            }
700#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
701            break;
702
703        case AVRC_OP_PASS_THRU:
704            if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
705            {
706                if (cr == AVCT_CMD)
707                    reject = TRUE;
708                else
709                    drop = TRUE;
710                break;
711            }
712            p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
713            msg.pass.op_id  = (AVRC_PASS_OP_ID_MASK & *p_data);
714            if (AVRC_PASS_STATE_MASK & *p_data)
715                msg.pass.state  = TRUE;
716            else
717                msg.pass.state  = FALSE;
718            p_data++;
719            msg.pass.pass_len    = *p_data++;
720            if (msg.pass.pass_len != p_pkt->len - 5)
721                msg.pass.pass_len = p_pkt->len - 5;
722            if (msg.pass.pass_len)
723                msg.pass.p_pass_data = p_data;
724            else
725                msg.pass.p_pass_data = NULL;
726            break;
727
728
729        default:
730            if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
731            {
732                /* reject unsupported opcode */
733                reject = TRUE;
734            }
735            drop    = TRUE;
736            break;
737        }
738    }
739    else /* drop the event */
740    {
741            drop    = TRUE;
742    }
743
744    if (reject)
745    {
746        /* reject unsupported opcode */
747        p_rsp           = p_pkt; /* this also sets free = FALSE, drop = TRUE */
748        p_rsp_data      = avrc_get_data_ptr(p_pkt);
749        *p_rsp_data     = AVRC_RSP_REJ;
750#if (BT_USE_TRACES == TRUE)
751        p_drop_msg = "rejected";
752#endif
753        cr      = AVCT_RSP;
754        drop    = TRUE;
755    }
756
757    if (p_rsp)
758    {
759        /* set to send response right away */
760        AVCT_MsgReq( handle, label, cr, p_rsp);
761        free = FALSE;
762        drop = TRUE;
763    }
764
765    if (drop == FALSE)
766    {
767        msg.hdr.opcode = opcode;
768        (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
769    }
770#if (BT_USE_TRACES == TRUE)
771    else
772    {
773        AVRC_TRACE_WARNING5("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
774                p_drop_msg,
775                handle, avrc_cb.ccb[handle].control, cr, opcode);
776    }
777#endif
778
779
780    if (free)
781        GKI_freebuf(p_pkt);
782}
783
784
785
786
787/******************************************************************************
788**
789** Function         avrc_pass_msg
790**
791** Description      Compose a PASS THROUGH command according to p_msg
792**
793**                  Input Parameters:
794**                      p_msg: Pointer to PASS THROUGH message structure.
795**
796**                  Output Parameters:
797**                      None.
798**
799** Returns          pointer to a valid GKI buffer if successful.
800**                  NULL if p_msg is NULL.
801**
802******************************************************************************/
803static BT_HDR  * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
804{
805    BT_HDR  *p_cmd = NULL;
806    UINT8   *p_data;
807
808    WC_ASSERT(p_msg != NULL);
809    WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len));
810
811    if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
812    {
813        p_cmd->offset   = AVCT_MSG_OFFSET;
814        p_cmd->layer_specific   = AVCT_DATA_CTRL;
815        p_data          = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
816        *p_data++       = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
817        *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
818        *p_data++       = AVRC_OP_PASS_THRU;
819        *p_data         = (AVRC_PASS_OP_ID_MASK&p_msg->op_id);
820        if (p_msg->state)
821            *p_data     |= AVRC_PASS_STATE_MASK;
822        p_data++;
823
824        if (p_msg->op_id == AVRC_ID_VENDOR)
825        {
826            *p_data++       = p_msg->pass_len;
827            if (p_msg->pass_len && p_msg->p_pass_data)
828            {
829                memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
830                p_data += p_msg->pass_len;
831            }
832        }
833        else /* set msg len to 0 for other op_id */
834        {
835            /* set msg len to 0 for other op_id */
836            *p_data++       = 0;
837        }
838        p_cmd->len      = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
839    }
840    return p_cmd;
841}
842
843/******************************************************************************
844**
845** Function         AVRC_Open
846**
847** Description      This function is called to open a connection to AVCTP.
848**                  The connection can be either an initiator or acceptor, as
849**                  determined by the p_ccb->stream parameter.
850**                  The connection can be a target, a controller or for both role,
851**                  as determined by the p_ccb->control parameter.
852**                  By definition, a target connection is an acceptor connection
853**                  that waits for an incoming AVCTP connection from the peer.
854**                  The connection remains available to the application until
855**                  the application closes it by calling AVRC_Close().  The
856**                  application does not need to reopen the connection after an
857**                  AVRC_CLOSE_IND_EVT is received.
858**
859**                  Input Parameters:
860**                      p_ccb->company_id: Company Identifier.
861**
862**                      p_ccb->p_ctrl_cback:  Pointer to control callback function.
863**
864**                      p_ccb->p_msg_cback:  Pointer to message callback function.
865**
866**                      p_ccb->conn: AVCTP connection role.  This is set to
867**                      AVCTP_INT for initiator connections and AVCTP_ACP
868**                      for acceptor connections.
869**
870**                      p_ccb->control: Control role.  This is set to
871**                      AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
872**                      for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
873**                      for connections that support both roles.
874**
875**                      peer_addr: BD address of peer device.  This value is
876**                      only used for initiator connections; for acceptor
877**                      connections it can be set to NULL.
878**
879**                  Output Parameters:
880**                      p_handle: Pointer to handle.  This parameter is only
881**                                valid if AVRC_SUCCESS is returned.
882**
883** Returns          AVRC_SUCCESS if successful.
884**                  AVRC_NO_RESOURCES if there are not enough resources to open
885**                  the connection.
886**
887******************************************************************************/
888UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
889{
890    UINT16      status;
891    tAVCT_CC    cc;
892
893    cc.p_ctrl_cback = avrc_ctrl_cback;      /* Control callback */
894    cc.p_msg_cback  = avrc_msg_cback;       /* Message callback */
895    cc.pid          = UUID_SERVCLASS_AV_REMOTE_CONTROL;  /* Profile ID */
896    cc.role         = p_ccb->conn;          /* Initiator/acceptor role */
897    cc.control      = p_ccb->control;       /* Control role (Control/Target) */
898
899    status = AVCT_CreateConn(p_handle, &cc, peer_addr);
900    if (status == AVCT_SUCCESS)
901    {
902        memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
903#if (AVRC_METADATA_INCLUDED == TRUE)
904        memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
905        memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
906#endif
907    }
908    AVRC_TRACE_DEBUG4("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control,
909        status, *p_handle);
910
911    return status;
912}
913
914/******************************************************************************
915**
916** Function         AVRC_Close
917**
918** Description      Close a connection opened with AVRC_Open().
919**                  This function is called when the
920**                  application is no longer using a connection.
921**
922**                  Input Parameters:
923**                      handle: Handle of this connection.
924**
925**                  Output Parameters:
926**                      None.
927**
928** Returns          AVRC_SUCCESS if successful.
929**                  AVRC_BAD_HANDLE if handle is invalid.
930**
931******************************************************************************/
932UINT16 AVRC_Close(UINT8 handle)
933{
934    AVRC_TRACE_DEBUG1("AVRC_Close handle:%d", handle);
935    return AVCT_RemoveConn(handle);
936}
937
938
939/******************************************************************************
940**
941** Function         AVRC_MsgReq
942**
943** Description      This function is used to send the AVRCP byte stream in p_pkt
944**                  down to AVCTP.
945**
946**                  It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
947**                  p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
948**                  p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
949**                  The above BT_HDR settings are set by the AVRC_Bld* functions.
950**
951** Returns          AVRC_SUCCESS if successful.
952**                  AVRC_BAD_HANDLE if handle is invalid.
953**
954******************************************************************************/
955UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
956{
957#if (AVRC_METADATA_INCLUDED == TRUE)
958    UINT8   *p_data;
959    UINT8   cr = AVCT_CMD;
960    BOOLEAN chk_frag = TRUE;
961    UINT8   *p_start = NULL;
962    tAVRC_FRAG_CB   *p_fcb;
963    UINT16  len;
964    BT_HDR  *p_pkt_new;
965
966    if (!p_pkt)
967        return AVRC_BAD_PARAM;
968
969    if (ctype >= AVRC_RSP_NOT_IMPL)
970        cr = AVCT_RSP;
971
972    if (p_pkt->event == AVRC_OP_VENDOR)
973    {
974        /* add AVRCP Vendor Dependent headers */
975        p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
976        p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
977        p_pkt->len += AVRC_VENDOR_HDR_SIZE;
978        p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
979        *p_data++       = (ctype & AVRC_CTYPE_MASK);
980        *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
981        *p_data++       = AVRC_OP_VENDOR;
982        AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
983    }
984    else if (p_pkt->event == AVRC_OP_PASS_THRU)
985    {
986        /* add AVRCP Pass Through headers */
987        p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
988        p_pkt->offset -= AVRC_PASS_THRU_SIZE;
989        p_pkt->len += AVRC_PASS_THRU_SIZE;
990        p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
991        *p_data++       = (ctype & AVRC_CTYPE_MASK);
992        *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
993        *p_data++       = AVRC_OP_PASS_THRU;/* opcode */
994        *p_data++       = AVRC_ID_VENDOR;   /* operation id */
995        *p_data++       = 5;                /* operation data len */
996        AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
997    }
998
999    /* abandon previous fragments */
1000    p_fcb = &avrc_cb.fcb[handle];
1001    if (p_fcb->frag_enabled)
1002        p_fcb->frag_enabled = FALSE;
1003
1004    if (p_fcb->p_fmsg)
1005    {
1006        GKI_freebuf(p_fcb->p_fmsg);
1007        p_fcb->p_fmsg = NULL;
1008    }
1009
1010    /* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
1011     * check for fragmentation only on the response */
1012    if ((cr == AVCT_RSP) && (chk_frag == TRUE))
1013    {
1014        if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
1015        {
1016            AVRC_TRACE_DEBUG1 ("p_pkt->len(%d) > AVRC_MAX_CTRL_DATA_LEN", p_pkt->len );
1017            p_pkt_new = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + AVCT_MSG_OFFSET
1018                + BT_HDR_SIZE));
1019            if (p_pkt_new)
1020            {
1021                p_fcb->frag_enabled = TRUE;
1022                p_fcb->p_fmsg       = p_pkt;
1023                p_fcb->frag_pdu     = *p_start;
1024                p_pkt               = p_pkt_new;
1025                p_pkt_new           = p_fcb->p_fmsg;
1026                p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
1027                p_pkt->offset       = p_pkt_new->offset;
1028                p_pkt->layer_specific = p_pkt_new->layer_specific;
1029                p_pkt->event = p_pkt_new->event;
1030                p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
1031                p_start -= AVRC_VENDOR_HDR_SIZE;
1032                memcpy (p_data, p_start, AVRC_MAX_CTRL_DATA_LEN);
1033                /* use AVRC start packet type */
1034                p_data += AVRC_VENDOR_HDR_SIZE;
1035                p_data++; /* pdu */
1036                *p_data++ = AVRC_PKT_START;
1037                /* 4 pdu, pkt_type & len */
1038                len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
1039                UINT16_TO_BE_STREAM(p_data, len);
1040
1041                /* prepare the left over for as an end fragment */
1042                avrc_prep_end_frag (handle);
1043                AVRC_TRACE_DEBUG3 ("p_pkt len:%d/%d, next len:%d", p_pkt->len, len, p_fcb->p_fmsg->len );
1044            }
1045            else
1046            {
1047                AVRC_TRACE_ERROR0 ("AVRC_MsgReq no buffers for fragmentation" );
1048                GKI_freebuf(p_pkt);
1049    return AVRC_NO_RESOURCES;
1050}
1051        }
1052    }
1053
1054    return AVCT_MsgReq( handle, label, cr, p_pkt);
1055#else
1056    return AVRC_NO_RESOURCES;
1057#endif
1058}
1059
1060
1061/******************************************************************************
1062**
1063** Function         AVRC_PassCmd
1064**
1065** Description      Send a PASS THROUGH command to the peer device.  This
1066**                  function can only be called for controller role connections.
1067**                  Any response message from the peer is passed back through
1068**                  the tAVRC_MSG_CBACK callback function.
1069**
1070**                  Input Parameters:
1071**                      handle: Handle of this connection.
1072**
1073**                      label: Transaction label.
1074**
1075**                      p_msg: Pointer to PASS THROUGH message structure.
1076**
1077**                  Output Parameters:
1078**                      None.
1079**
1080** Returns          AVRC_SUCCESS if successful.
1081**                  AVRC_BAD_HANDLE if handle is invalid.
1082**
1083******************************************************************************/
1084UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
1085{
1086    BT_HDR *p_buf;
1087    WC_ASSERT(p_msg != NULL);
1088    if (p_msg)
1089    {
1090        p_msg->hdr.ctype    = AVRC_CMD_CTRL;
1091        p_buf = avrc_pass_msg(p_msg);
1092        if (p_buf)
1093            return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
1094    }
1095    return AVRC_NO_RESOURCES;
1096}
1097
1098/******************************************************************************
1099**
1100** Function         AVRC_PassRsp
1101**
1102** Description      Send a PASS THROUGH response to the peer device.  This
1103**                  function can only be called for target role connections.
1104**                  This function must be called when a PASS THROUGH command
1105**                  message is received from the peer through the
1106**                  tAVRC_MSG_CBACK callback function.
1107**
1108**                  Input Parameters:
1109**                      handle: Handle of this connection.
1110**
1111**                      label: Transaction label.  Must be the same value as
1112**                      passed with the command message in the callback function.
1113**
1114**                      p_msg: Pointer to PASS THROUGH message structure.
1115**
1116**                  Output Parameters:
1117**                      None.
1118**
1119** Returns          AVRC_SUCCESS if successful.
1120**                  AVRC_BAD_HANDLE if handle is invalid.
1121**
1122******************************************************************************/
1123UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
1124{
1125    BT_HDR *p_buf;
1126    WC_ASSERT(p_msg != NULL);
1127    if (p_msg)
1128    {
1129        p_buf = avrc_pass_msg(p_msg);
1130        if (p_buf)
1131            return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
1132    }
1133    return AVRC_NO_RESOURCES;
1134}
1135
1136