1 /** @file
2 * @brief Audio Video Remote Control Profile
3 */
4
5 /*
6 * Copyright (c) 2015-2016 Intel Corporation
7 * Copyright (C) 2024 Xiaomi Corporation
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <string.h>
13 #include <errno.h>
14 #include <zephyr/sys/atomic.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/sys/util.h>
17 #include <zephyr/sys/printk.h>
18
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/classic/avrcp.h>
21 #include <zephyr/bluetooth/classic/sdp.h>
22 #include <zephyr/bluetooth/l2cap.h>
23
24 #include "host/hci_core.h"
25 #include "host/conn_internal.h"
26 #include "host/l2cap_internal.h"
27 #include "avctp_internal.h"
28 #include "avrcp_internal.h"
29
30 #define LOG_LEVEL CONFIG_BT_AVRCP_LOG_LEVEL
31 #include <zephyr/logging/log.h>
32 LOG_MODULE_REGISTER(bt_avrcp);
33
34 struct bt_avrcp {
35 struct bt_avctp session;
36 struct bt_avrcp_req req;
37 struct k_work_delayable timeout_work;
38 uint8_t local_tid;
39 };
40
41 struct avrcp_handler {
42 bt_avrcp_opcode_t opcode;
43 void (*func)(struct bt_avrcp *avrcp, struct net_buf *buf, bt_avctp_cr_t cr);
44 };
45
46 #define AVRCP_TIMEOUT K_SECONDS(3) /* Shell be greater than TMTP (1000ms) */
47 #define AVRCP_AVCTP(_avctp) CONTAINER_OF(_avctp, struct bt_avrcp, session)
48 #define AVRCP_KWORK(_work) \
49 CONTAINER_OF(CONTAINER_OF(_work, struct k_work_delayable, work), struct bt_avrcp, \
50 timeout_work)
51
52 static const struct bt_avrcp_cb *avrcp_cb;
53 static struct bt_avrcp avrcp_connection[CONFIG_BT_MAX_CONN];
54
55 #if defined(CONFIG_BT_AVRCP_TARGET)
56 static struct bt_sdp_attribute avrcp_tg_attrs[] = {
57 BT_SDP_NEW_SERVICE,
58 BT_SDP_LIST(
59 BT_SDP_ATTR_SVCLASS_ID_LIST,
60 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
61 BT_SDP_DATA_ELEM_LIST(
62 {
63 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
64 BT_SDP_ARRAY_16(BT_SDP_AV_REMOTE_TARGET_SVCLASS)
65 },
66 )
67 ),
68 BT_SDP_LIST(
69 BT_SDP_ATTR_PROTO_DESC_LIST,
70 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),
71 BT_SDP_DATA_ELEM_LIST(
72 {
73 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
74 BT_SDP_DATA_ELEM_LIST({BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
75 BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)},
76 {
77 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
78 BT_SDP_ARRAY_16(BT_UUID_AVCTP_VAL)
79 },
80 )
81 },
82 {
83 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
84 BT_SDP_DATA_ELEM_LIST(
85 {
86 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
87 BT_SDP_ARRAY_16(BT_UUID_AVCTP_VAL)
88 },
89 {
90 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
91 BT_SDP_ARRAY_16(AVCTP_VER_1_4)
92 },
93 )
94 },
95 )
96 ),
97 /* C1: Browsing not supported */
98 /* C2: Cover Art not supported */
99 BT_SDP_LIST(
100 BT_SDP_ATTR_PROFILE_DESC_LIST,
101 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
102 BT_SDP_DATA_ELEM_LIST(
103 {
104 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
105 BT_SDP_DATA_ELEM_LIST(
106 {
107 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
108 BT_SDP_ARRAY_16(BT_SDP_AV_REMOTE_SVCLASS)
109 },
110 {
111 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
112 BT_SDP_ARRAY_16(AVRCP_VER_1_6)
113 },
114 )
115 },
116 )
117 ),
118 BT_SDP_SUPPORTED_FEATURES(AVRCP_CAT_1 | AVRCP_CAT_2),
119 /* O: Provider Name not presented */
120 BT_SDP_SERVICE_NAME("AVRCP Target"),
121 };
122
123 static struct bt_sdp_record avrcp_tg_rec = BT_SDP_RECORD(avrcp_tg_attrs);
124 #endif /* CONFIG_BT_AVRCP_TARGET */
125
126 #if defined(CONFIG_BT_AVRCP_CONTROLLER)
127 static struct bt_sdp_attribute avrcp_ct_attrs[] = {
128 BT_SDP_NEW_SERVICE,
129 BT_SDP_LIST(
130 BT_SDP_ATTR_SVCLASS_ID_LIST,
131 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
132 BT_SDP_DATA_ELEM_LIST(
133 {
134 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
135 BT_SDP_ARRAY_16(BT_SDP_AV_REMOTE_SVCLASS)
136 },
137 {
138 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
139 BT_SDP_ARRAY_16(BT_SDP_AV_REMOTE_CONTROLLER_SVCLASS)
140 },
141 )
142 ),
143 BT_SDP_LIST(
144 BT_SDP_ATTR_PROTO_DESC_LIST,
145 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),
146 BT_SDP_DATA_ELEM_LIST(
147 {
148 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
149 BT_SDP_DATA_ELEM_LIST(
150 {
151 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
152 BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
153 },
154 {
155 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
156 BT_SDP_ARRAY_16(BT_UUID_AVCTP_VAL)
157 },
158 )
159 },
160 {
161 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
162 BT_SDP_DATA_ELEM_LIST(
163 {
164 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
165 BT_SDP_ARRAY_16(BT_UUID_AVCTP_VAL)
166 },
167 {
168 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
169 BT_SDP_ARRAY_16(AVCTP_VER_1_4)
170 },
171 )
172 },
173 )
174 ),
175 /* C1: Browsing not supported */
176 BT_SDP_LIST(
177 BT_SDP_ATTR_PROFILE_DESC_LIST,
178 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
179 BT_SDP_DATA_ELEM_LIST(
180 {
181 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
182 BT_SDP_DATA_ELEM_LIST(
183 {
184 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
185 BT_SDP_ARRAY_16(BT_SDP_AV_REMOTE_SVCLASS)
186 },
187 {
188 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
189 BT_SDP_ARRAY_16(AVRCP_VER_1_6)
190 },
191 )
192 },
193 )
194 ),
195 BT_SDP_SUPPORTED_FEATURES(AVRCP_CAT_1 | AVRCP_CAT_2),
196 /* O: Provider Name not presented */
197 BT_SDP_SERVICE_NAME("AVRCP Controller"),
198 };
199
200 static struct bt_sdp_record avrcp_ct_rec = BT_SDP_RECORD(avrcp_ct_attrs);
201 #endif /* CONFIG_BT_AVRCP_CONTROLLER */
202
get_new_connection(struct bt_conn * conn)203 static struct bt_avrcp *get_new_connection(struct bt_conn *conn)
204 {
205 struct bt_avrcp *avrcp;
206
207 if (!conn) {
208 LOG_ERR("Invalid Input (err: %d)", -EINVAL);
209 return NULL;
210 }
211
212 avrcp = &avrcp_connection[bt_conn_index(conn)];
213 memset(avrcp, 0, sizeof(struct bt_avrcp));
214 return avrcp;
215 }
216
avrcp_timeout(struct k_work * work)217 static void avrcp_timeout(struct k_work *work)
218 {
219 struct bt_avrcp *avrcp = AVRCP_KWORK(work);
220
221 LOG_WRN("Timeout: tid 0x%X, opc 0x%02X", avrcp->req.tid, avrcp->req.opcode);
222 }
223
224 /* The AVCTP L2CAP channel established */
avrcp_connected(struct bt_avctp * session)225 static void avrcp_connected(struct bt_avctp *session)
226 {
227 struct bt_avrcp *avrcp = AVRCP_AVCTP(session);
228
229 if ((avrcp_cb != NULL) && (avrcp_cb->connected != NULL)) {
230 avrcp_cb->connected(avrcp);
231 }
232
233 k_work_init_delayable(&avrcp->timeout_work, avrcp_timeout);
234 }
235
236 /* The AVCTP L2CAP channel released */
avrcp_disconnected(struct bt_avctp * session)237 static void avrcp_disconnected(struct bt_avctp *session)
238 {
239 struct bt_avrcp *avrcp = AVRCP_AVCTP(session);
240
241 if ((avrcp_cb != NULL) && (avrcp_cb->disconnected != NULL)) {
242 avrcp_cb->disconnected(avrcp);
243 }
244 }
245
avrcp_vendor_dependent_handler(struct bt_avrcp * avrcp,struct net_buf * buf,bt_avctp_cr_t cr)246 static void avrcp_vendor_dependent_handler(struct bt_avrcp *avrcp, struct net_buf *buf,
247 bt_avctp_cr_t cr)
248 {
249 /* ToDo */
250 }
251
avrcp_unit_info_handler(struct bt_avrcp * avrcp,struct net_buf * buf,bt_avctp_cr_t cr)252 static void avrcp_unit_info_handler(struct bt_avrcp *avrcp, struct net_buf *buf, bt_avctp_cr_t cr)
253 {
254 struct bt_avrcp_header *avrcp_hdr;
255 struct bt_avrcp_unit_info_rsp rsp;
256
257 if (cr == BT_AVCTP_CMD) {
258 /* ToDo */
259 } else { /* BT_AVCTP_RESPONSE */
260 if ((avrcp_cb != NULL) && (avrcp_cb->unit_info_rsp != NULL)) {
261 net_buf_pull(buf, sizeof(*avrcp_hdr));
262 if (buf->len != 5) {
263 LOG_ERR("Invalid unit info length");
264 return;
265 }
266 net_buf_pull_u8(buf); /* Always 0x07 */
267 rsp.unit_type = FIELD_GET(GENMASK(7, 3), net_buf_pull_u8(buf));
268 rsp.company_id = net_buf_pull_be24(buf);
269 avrcp_cb->unit_info_rsp(avrcp, &rsp);
270 }
271 }
272 }
273
avrcp_subunit_info_handler(struct bt_avrcp * avrcp,struct net_buf * buf,bt_avctp_cr_t cr)274 static void avrcp_subunit_info_handler(struct bt_avrcp *avrcp, struct net_buf *buf,
275 bt_avctp_cr_t cr)
276 {
277 struct bt_avrcp_header *avrcp_hdr;
278 struct bt_avrcp_subunit_info_rsp rsp;
279 uint8_t tmp;
280
281 if (cr == BT_AVCTP_CMD) {
282 /* ToDo */
283 } else { /* BT_AVCTP_RESPONSE */
284 if ((avrcp_cb != NULL) && (avrcp_cb->subunit_info_rsp != NULL)) {
285 net_buf_pull(buf, sizeof(*avrcp_hdr));
286 if (buf->len < 5) {
287 LOG_ERR("Invalid subunit info length");
288 return;
289 }
290 net_buf_pull_u8(buf); /* Always 0x07 */
291 tmp = net_buf_pull_u8(buf);
292 rsp.subunit_type = FIELD_GET(GENMASK(7, 3), tmp);
293 rsp.max_subunit_id = FIELD_GET(GENMASK(2, 0), tmp);
294 if (buf->len < (rsp.max_subunit_id << 1)) {
295 LOG_ERR("Invalid subunit info response");
296 return;
297 }
298 rsp.extended_subunit_type = buf->data;
299 rsp.extended_subunit_id = rsp.extended_subunit_type + rsp.max_subunit_id;
300 avrcp_cb->subunit_info_rsp(avrcp, &rsp);
301 }
302 }
303 }
304
avrcp_pass_through_handler(struct bt_avrcp * avrcp,struct net_buf * buf,bt_avctp_cr_t cr)305 static void avrcp_pass_through_handler(struct bt_avrcp *avrcp, struct net_buf *buf,
306 bt_avctp_cr_t cr)
307 {
308 /* ToDo */
309 }
310
311 static const struct avrcp_handler handler[] = {
312 { BT_AVRCP_OPC_VENDOR_DEPENDENT, avrcp_vendor_dependent_handler },
313 { BT_AVRCP_OPC_UNIT_INFO, avrcp_unit_info_handler },
314 { BT_AVRCP_OPC_SUBUNIT_INFO, avrcp_subunit_info_handler },
315 { BT_AVRCP_OPC_PASS_THROUGH, avrcp_pass_through_handler },
316 };
317
318 /* An AVRCP message received */
avrcp_recv(struct bt_avctp * session,struct net_buf * buf)319 static int avrcp_recv(struct bt_avctp *session, struct net_buf *buf)
320 {
321 struct bt_avrcp *avrcp = AVRCP_AVCTP(session);
322 struct bt_avctp_header *avctp_hdr;
323 struct bt_avrcp_header *avrcp_hdr;
324 uint8_t tid, i;
325 bt_avctp_cr_t cr;
326 bt_avrcp_ctype_t ctype;
327 bt_avrcp_subunit_id_t subunit_id;
328 bt_avrcp_subunit_type_t subunit_type;
329
330 avctp_hdr = (void *)buf->data;
331 net_buf_pull(buf, sizeof(*avctp_hdr));
332 if (buf->len < sizeof(*avrcp_hdr)) {
333 LOG_ERR("invalid AVRCP header received");
334 return -EINVAL;
335 }
336
337 avrcp_hdr = (void *)buf->data;
338 tid = BT_AVCTP_HDR_GET_TRANSACTION_LABLE(avctp_hdr);
339 cr = BT_AVCTP_HDR_GET_CR(avctp_hdr);
340 ctype = BT_AVRCP_HDR_GET_CTYPE(avrcp_hdr);
341 subunit_id = BT_AVRCP_HDR_GET_SUBUNIT_ID(avrcp_hdr);
342 subunit_type = BT_AVRCP_HDR_GET_SUBUNIT_TYPE(avrcp_hdr);
343
344 if (avctp_hdr->pid != sys_cpu_to_be16(BT_SDP_AV_REMOTE_SVCLASS)) {
345 return -EINVAL; /* Ignore other profile */
346 }
347
348 LOG_DBG("AVRCP msg received, cr:0x%X, tid:0x%X, ctype: 0x%X, opc:0x%02X,", cr, tid, ctype,
349 avrcp_hdr->opcode);
350 if (cr == BT_AVCTP_RESPONSE) {
351 if (avrcp_hdr->opcode == BT_AVRCP_OPC_VENDOR_DEPENDENT &&
352 ctype == BT_AVRCP_CTYPE_CHANGED) {
353 /* Status changed notifiation, do not reset timer */
354 } else if (avrcp_hdr->opcode == BT_AVRCP_OPC_PASS_THROUGH) {
355 /* No max response time for pass through commands */
356 } else if (tid != avrcp->req.tid || subunit_type != avrcp->req.subunit ||
357 avrcp_hdr->opcode != avrcp->req.opcode) {
358 LOG_WRN("unexpected AVRCP response, expected tid:0x%X, subunit:0x%X, "
359 "opc:0x%02X",
360 avrcp->req.tid, avrcp->req.subunit, avrcp->req.opcode);
361 } else {
362 k_work_cancel_delayable(&avrcp->timeout_work);
363 }
364 }
365
366 for (i = 0U; i < ARRAY_SIZE(handler); i++) {
367 if (avrcp_hdr->opcode == handler[i].opcode) {
368 handler[i].func(avrcp, buf, cr);
369 return 0;
370 }
371 }
372
373 return 0;
374 }
375
376 static const struct bt_avctp_ops_cb avctp_ops = {
377 .connected = avrcp_connected,
378 .disconnected = avrcp_disconnected,
379 .recv = avrcp_recv,
380 };
381
avrcp_accept(struct bt_conn * conn,struct bt_avctp ** session)382 static int avrcp_accept(struct bt_conn *conn, struct bt_avctp **session)
383 {
384 struct bt_avrcp *avrcp;
385
386 avrcp = get_new_connection(conn);
387 if (!avrcp) {
388 return -ENOMEM;
389 }
390
391 *session = &(avrcp->session);
392 avrcp->session.ops = &avctp_ops;
393
394 LOG_DBG("session: %p", &(avrcp->session));
395
396 return 0;
397 }
398
399 static struct bt_avctp_event_cb avctp_cb = {
400 .accept = avrcp_accept,
401 };
402
bt_avrcp_init(void)403 int bt_avrcp_init(void)
404 {
405 int err;
406
407 /* Register event handlers with AVCTP */
408 err = bt_avctp_register(&avctp_cb);
409 if (err < 0) {
410 LOG_ERR("AVRCP registration failed");
411 return err;
412 }
413
414 #if defined(CONFIG_BT_AVRCP_TARGET)
415 bt_sdp_register_service(&avrcp_tg_rec);
416 #endif /* CONFIG_BT_AVRCP_CONTROLLER */
417
418 #if defined(CONFIG_BT_AVRCP_CONTROLLER)
419 bt_sdp_register_service(&avrcp_ct_rec);
420 #endif /* CONFIG_BT_AVRCP_CONTROLLER */
421
422 LOG_DBG("AVRCP Initialized successfully.");
423 return 0;
424 }
425
bt_avrcp_connect(struct bt_conn * conn)426 struct bt_avrcp *bt_avrcp_connect(struct bt_conn *conn)
427 {
428 struct bt_avrcp *avrcp;
429 int err;
430
431 avrcp = get_new_connection(conn);
432 if (!avrcp) {
433 LOG_ERR("Cannot allocate memory");
434 return NULL;
435 }
436
437 avrcp->session.ops = &avctp_ops;
438 err = bt_avctp_connect(conn, &(avrcp->session));
439 if (err < 0) {
440 /* If error occurs, undo the saving and return the error */
441 memset(avrcp, 0, sizeof(struct bt_avrcp));
442 LOG_DBG("AVCTP Connect failed");
443 return NULL;
444 }
445
446 LOG_DBG("Connection request sent");
447 return avrcp;
448 }
449
bt_avrcp_disconnect(struct bt_avrcp * avrcp)450 int bt_avrcp_disconnect(struct bt_avrcp *avrcp)
451 {
452 int err;
453
454 err = bt_avctp_disconnect(&(avrcp->session));
455 if (err < 0) {
456 LOG_DBG("AVCTP Disconnect failed");
457 return err;
458 }
459
460 return err;
461 }
462
avrcp_create_pdu(struct bt_avrcp * avrcp,bt_avctp_cr_t cr)463 static struct net_buf *avrcp_create_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr)
464 {
465 struct net_buf *buf;
466
467 buf = bt_avctp_create_pdu(&(avrcp->session), cr, BT_AVCTP_PKT_TYPE_SINGLE,
468 BT_AVCTP_IPID_NONE, &avrcp->local_tid,
469 sys_cpu_to_be16(BT_SDP_AV_REMOTE_SVCLASS));
470
471 return buf;
472 }
473
avrcp_create_unit_pdu(struct bt_avrcp * avrcp,bt_avctp_cr_t cr)474 static struct net_buf *avrcp_create_unit_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr)
475 {
476 struct net_buf *buf;
477 struct bt_avrcp_unit_info_cmd *cmd;
478
479 buf = avrcp_create_pdu(avrcp, cr);
480 if (!buf) {
481 return buf;
482 }
483
484 cmd = net_buf_add(buf, sizeof(*cmd));
485 memset(cmd, 0, sizeof(*cmd));
486 BT_AVRCP_HDR_SET_CTYPE(&cmd->hdr, cr == BT_AVCTP_CMD ? BT_AVRCP_CTYPE_STATUS
487 : BT_AVRCP_CTYPE_IMPLEMENTED_STABLE);
488 BT_AVRCP_HDR_SET_SUBUNIT_ID(&cmd->hdr, BT_AVRCP_SUBUNIT_ID_IGNORE);
489 BT_AVRCP_HDR_SET_SUBUNIT_TYPE(&cmd->hdr, BT_AVRCP_SUBUNIT_TYPE_UNIT);
490 cmd->hdr.opcode = BT_AVRCP_OPC_UNIT_INFO;
491
492 return buf;
493 }
494
avrcp_create_subunit_pdu(struct bt_avrcp * avrcp,bt_avctp_cr_t cr)495 static struct net_buf *avrcp_create_subunit_pdu(struct bt_avrcp *avrcp, bt_avctp_cr_t cr)
496 {
497 struct net_buf *buf;
498 struct bt_avrcp_unit_info_cmd *cmd;
499
500 buf = avrcp_create_pdu(avrcp, cr);
501 if (!buf) {
502 return buf;
503 }
504
505 cmd = net_buf_add(buf, sizeof(*cmd));
506 memset(cmd, 0, sizeof(*cmd));
507 BT_AVRCP_HDR_SET_CTYPE(&cmd->hdr, cr == BT_AVCTP_CMD ? BT_AVRCP_CTYPE_STATUS
508 : BT_AVRCP_CTYPE_IMPLEMENTED_STABLE);
509 BT_AVRCP_HDR_SET_SUBUNIT_ID(&cmd->hdr, BT_AVRCP_SUBUNIT_ID_IGNORE);
510 BT_AVRCP_HDR_SET_SUBUNIT_TYPE(&cmd->hdr, BT_AVRCP_SUBUNIT_TYPE_UNIT);
511 cmd->hdr.opcode = BT_AVRCP_OPC_SUBUNIT_INFO;
512
513 return buf;
514 }
515
avrcp_send(struct bt_avrcp * avrcp,struct net_buf * buf)516 static int avrcp_send(struct bt_avrcp *avrcp, struct net_buf *buf)
517 {
518 int err;
519 struct bt_avctp_header *avctp_hdr = (struct bt_avctp_header *)(buf->data);
520 struct bt_avrcp_header *avrcp_hdr =
521 (struct bt_avrcp_header *)(buf->data + sizeof(*avctp_hdr));
522 uint8_t tid = BT_AVCTP_HDR_GET_TRANSACTION_LABLE(avctp_hdr);
523 bt_avctp_cr_t cr = BT_AVCTP_HDR_GET_CR(avctp_hdr);
524 bt_avrcp_ctype_t ctype = BT_AVRCP_HDR_GET_CTYPE(avrcp_hdr);
525 bt_avrcp_subunit_type_t subunit_type = BT_AVRCP_HDR_GET_SUBUNIT_TYPE(avrcp_hdr);
526
527 LOG_DBG("AVRCP send cr:0x%X, tid:0x%X, ctype: 0x%X, opc:0x%02X\n", cr, tid, ctype,
528 avrcp_hdr->opcode);
529 err = bt_avctp_send(&(avrcp->session), buf);
530 if (err < 0) {
531 return err;
532 }
533
534 if (cr == BT_AVCTP_CMD && avrcp_hdr->opcode != BT_AVRCP_OPC_PASS_THROUGH) {
535 avrcp->req.tid = tid;
536 avrcp->req.subunit = subunit_type;
537 avrcp->req.opcode = avrcp_hdr->opcode;
538
539 k_work_reschedule(&avrcp->timeout_work, AVRCP_TIMEOUT);
540 }
541
542 return 0;
543 }
544
bt_avrcp_get_unit_info(struct bt_avrcp * avrcp)545 int bt_avrcp_get_unit_info(struct bt_avrcp *avrcp)
546 {
547 struct net_buf *buf;
548 uint8_t param[5];
549
550 buf = avrcp_create_unit_pdu(avrcp, BT_AVCTP_CMD);
551 if (!buf) {
552 return -ENOMEM;
553 }
554
555 memset(param, 0xFF, ARRAY_SIZE(param));
556 net_buf_add_mem(buf, param, sizeof(param));
557
558 return avrcp_send(avrcp, buf);
559 }
560
bt_avrcp_get_subunit_info(struct bt_avrcp * avrcp)561 int bt_avrcp_get_subunit_info(struct bt_avrcp *avrcp)
562 {
563 struct net_buf *buf;
564 uint8_t param[5];
565
566 buf = avrcp_create_subunit_pdu(avrcp, BT_AVCTP_CMD);
567 if (!buf) {
568 return -ENOMEM;
569 }
570
571 memset(param, 0xFF, ARRAY_SIZE(param));
572 param[0] = FIELD_PREP(GENMASK(6, 4), AVRCP_SUBUNIT_PAGE) |
573 FIELD_PREP(GENMASK(2, 0), AVRCP_SUBUNIT_EXTENSION_COED);
574 net_buf_add_mem(buf, param, sizeof(param));
575
576 return avrcp_send(avrcp, buf);
577 }
578
bt_avrcp_register_cb(const struct bt_avrcp_cb * cb)579 int bt_avrcp_register_cb(const struct bt_avrcp_cb *cb)
580 {
581 avrcp_cb = cb;
582 return 0;
583 }
584