From ba05d5c2b251db949eb32ef4a6f7a3a77563a4a0 Mon Sep 17 00:00:00 2001 From: Make Shi Date: Mon, 21 Apr 2025 16:17:39 +0800 Subject: [PATCH] Bluetooth: Shell: AVRCP: support unit info request and response Add avrcp_unit_info_req callback function in shell and a command to set the unit info response. Signed-off-by: Make Shi --- subsys/bluetooth/host/classic/shell/avrcp.c | 159 +++++++++++++++----- 1 file changed, 124 insertions(+), 35 deletions(-) diff --git a/subsys/bluetooth/host/classic/shell/avrcp.c b/subsys/bluetooth/host/classic/shell/avrcp.c index a54e97f2f10..91eebe7ab1e 100644 --- a/subsys/bluetooth/host/classic/shell/avrcp.c +++ b/subsys/bluetooth/host/classic/shell/avrcp.c @@ -30,8 +30,11 @@ #include "common/bt_shell_private.h" struct bt_avrcp_ct *default_ct; +struct bt_avrcp_tg *default_tg; static bool avrcp_ct_registered; +static bool avrcp_tg_registered; static uint8_t local_tid; +static uint8_t tg_tid; static uint8_t get_next_tid(void) { @@ -54,6 +57,7 @@ static void avrcp_ct_disconnected(struct bt_avrcp_ct *ct) { bt_shell_print("AVRCP CT disconnected"); local_tid = 0; + default_ct = NULL; } static void avrcp_get_cap_rsp(struct bt_avrcp_ct *ct, uint8_t tid, @@ -111,7 +115,7 @@ static void avrcp_passthrough_rsp(struct bt_avrcp_ct *ct, uint8_t tid, bt_avrcp_ } } -static struct bt_avrcp_ct_cb avrcp_ct_cb = { +static struct bt_avrcp_ct_cb app_avrcp_ct_cb = { .connected = avrcp_ct_connected, .disconnected = avrcp_ct_disconnected, .get_cap_rsp = avrcp_get_cap_rsp, @@ -120,6 +124,30 @@ static struct bt_avrcp_ct_cb avrcp_ct_cb = { .passthrough_rsp = avrcp_passthrough_rsp, }; +static void avrcp_tg_connected(struct bt_conn *conn, struct bt_avrcp_tg *tg) +{ + bt_shell_print("AVRCP TG connected"); + default_tg = tg; +} + +static void avrcp_tg_disconnected(struct bt_avrcp_tg *tg) +{ + bt_shell_print("AVRCP TG disconnected"); + default_tg = NULL; +} + +static void avrcp_unit_info_req(struct bt_avrcp_tg *tg, uint8_t tid) +{ + bt_shell_print("AVRCP unit info request received"); + tg_tid = tid; +} + +static struct bt_avrcp_tg_cb app_avrcp_tg_cb = { + .connected = avrcp_tg_connected, + .disconnected = avrcp_tg_disconnected, + .unit_info_req = avrcp_unit_info_req, +}; + static int register_ct_cb(const struct shell *sh) { int err; @@ -128,12 +156,12 @@ static int register_ct_cb(const struct shell *sh) return 0; } - err = bt_avrcp_ct_register_cb(&avrcp_ct_cb); + err = bt_avrcp_ct_register_cb(&app_avrcp_ct_cb); if (!err) { avrcp_ct_registered = true; - shell_print(sh, "AVRCP callbacks registered"); + shell_print(sh, "AVRCP CT callbacks registered"); } else { - shell_print(sh, "failed to register callbacks"); + shell_print(sh, "failed to register AVRCP CT callbacks"); } return err; @@ -151,14 +179,47 @@ static int cmd_register_ct_cb(const struct shell *sh, int32_t argc, char *argv[] return 0; } +static int register_tg_cb(const struct shell *sh) +{ + int err; + + if (avrcp_tg_registered) { + return 0; + } + + err = bt_avrcp_tg_register_cb(&app_avrcp_tg_cb); + if (!err) { + avrcp_tg_registered = true; + shell_print(sh, "AVRCP TG callbacks registered"); + } else { + shell_print(sh, "failed to register AVRCP TG callbacks"); + } + + return err; +} + +static int cmd_register_tg_cb(const struct shell *sh, int32_t argc, char *argv[]) +{ + if (avrcp_tg_registered) { + shell_print(sh, "already registered"); + return 0; + } + + register_tg_cb(sh); + + return 0; +} + static int cmd_connect(const struct shell *sh, int32_t argc, char *argv[]) { int err; - if (!avrcp_ct_registered) { - if (register_ct_cb(sh) != 0) { - return -ENOEXEC; - } + if (!avrcp_ct_registered && register_ct_cb(sh) != 0) { + return -ENOEXEC; + } + + if (!avrcp_tg_registered && register_tg_cb(sh) != 0) { + return -ENOEXEC; } if (!default_conn) { @@ -167,7 +228,7 @@ static int cmd_connect(const struct shell *sh, int32_t argc, char *argv[]) } err = bt_avrcp_connect(default_conn); - if (!err) { + if (err) { shell_error(sh, "fail to connect AVRCP"); } @@ -176,15 +237,18 @@ static int cmd_connect(const struct shell *sh, int32_t argc, char *argv[]) static int cmd_disconnect(const struct shell *sh, int32_t argc, char *argv[]) { - if (!avrcp_ct_registered) { - if (register_ct_cb(sh) != 0) { - return -ENOEXEC; - } + if ((!avrcp_ct_registered) && (!avrcp_tg_registered)) { + shell_error(sh, "Neither CT nor TG callbacks are registered."); + return -ENOEXEC; } - if (default_ct != NULL) { + if (!default_conn) { + shell_print(sh, "Not connected"); + return -ENOEXEC; + } + + if ((default_ct != NULL) || (default_tg != NULL)) { bt_avrcp_disconnect(default_conn); - default_ct = NULL; } else { shell_error(sh, "AVRCP is not connected"); } @@ -194,10 +258,8 @@ static int cmd_disconnect(const struct shell *sh, int32_t argc, char *argv[]) static int cmd_get_unit_info(const struct shell *sh, int32_t argc, char *argv[]) { - if (!avrcp_ct_registered) { - if (register_ct_cb(sh) != 0) { - return -ENOEXEC; - } + if (!avrcp_ct_registered && register_ct_cb(sh) != 0) { + return -ENOEXEC; } if (default_ct != NULL) { @@ -209,12 +271,36 @@ static int cmd_get_unit_info(const struct shell *sh, int32_t argc, char *argv[]) return 0; } +static int cmd_send_unit_info_rsp(const struct shell *sh, int32_t argc, char *argv[]) +{ + struct bt_avrcp_unit_info_rsp rsp; + int err; + + if (!avrcp_tg_registered && register_tg_cb(sh) != 0) { + return -ENOEXEC; + } + + rsp.unit_type = BT_AVRCP_SUBUNIT_TYPE_PANEL; + rsp.company_id = BT_AVRCP_COMPANY_ID_BLUETOOTH_SIG; + + if (default_tg != NULL) { + err = bt_avrcp_tg_send_unit_info_rsp(default_tg, tg_tid, &rsp); + if (!err) { + shell_print(sh, "AVRCP send unit info response"); + } else { + shell_error(sh, "Failed to send unit info response"); + } + } else { + shell_error(sh, "AVRCP is not connected"); + } + + return 0; +} + static int cmd_get_subunit_info(const struct shell *sh, int32_t argc, char *argv[]) { - if (!avrcp_ct_registered) { - if (register_ct_cb(sh) != 0) { - return -ENOEXEC; - } + if (!avrcp_ct_registered && register_ct_cb(sh) != 0) { + return -ENOEXEC; } if (default_ct != NULL) { @@ -229,17 +315,15 @@ static int cmd_get_subunit_info(const struct shell *sh, int32_t argc, char *argv static int cmd_passthrough(const struct shell *sh, bt_avrcp_opid_t opid, const uint8_t *payload, uint8_t len) { - if (!avrcp_ct_registered) { - if (register_ct_cb(sh) != 0) { - return -ENOEXEC; - } + if (!avrcp_ct_registered && register_ct_cb(sh) != 0) { + return -ENOEXEC; } if (default_ct != NULL) { bt_avrcp_ct_passthrough(default_ct, get_next_tid(), opid, BT_AVRCP_BUTTON_PRESSED, - payload, len); + payload, len); bt_avrcp_ct_passthrough(default_ct, get_next_tid(), opid, BT_AVRCP_BUTTON_RELEASED, - payload, len); + payload, len); } else { shell_error(sh, "AVRCP is not connected"); } @@ -261,10 +345,8 @@ static int cmd_get_cap(const struct shell *sh, int32_t argc, char *argv[]) { const char *cap_id; - if (!avrcp_ct_registered) { - if (register_ct_cb(sh) != 0) { - return -ENOEXEC; - } + if (!avrcp_ct_registered && register_ct_cb(sh) != 0) { + return -ENOEXEC; } if (default_ct == NULL) { @@ -284,7 +366,7 @@ static int cmd_get_cap(const struct shell *sh, int32_t argc, char *argv[]) SHELL_STATIC_SUBCMD_SET_CREATE( ct_cmds, - SHELL_CMD_ARG(register_ct_cb, NULL, "register avrcp callbacks", cmd_register_ct_cb, 1, 0), + SHELL_CMD_ARG(register_cb, NULL, "register avrcp ct callbacks", cmd_register_ct_cb, 1, 0), SHELL_CMD_ARG(get_unit, NULL, "get unit info", cmd_get_unit_info, 1, 0), SHELL_CMD_ARG(get_subunit, NULL, "get subunit info", cmd_get_subunit_info, 1, 0), SHELL_CMD_ARG(get_cap, NULL, "get capabilities ", cmd_get_cap, 2, @@ -293,6 +375,12 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(pause, NULL, "request a pause at the remote player", cmd_pause, 1, 0), SHELL_SUBCMD_SET_END); +SHELL_STATIC_SUBCMD_SET_CREATE( + tg_cmds, + SHELL_CMD_ARG(register_cb, NULL, "register avrcp tg callbacks", cmd_register_tg_cb, 1, 0), + SHELL_CMD_ARG(send_unit_rsp, NULL, "send unit info response", cmd_send_unit_info_rsp, 1, 0), + SHELL_SUBCMD_SET_END); + static int cmd_avrcp(const struct shell *sh, size_t argc, char **argv) { if (argc == 1) { @@ -310,7 +398,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE( avrcp_cmds, SHELL_CMD_ARG(connect, NULL, "connect AVRCP", cmd_connect, 1, 0), SHELL_CMD_ARG(disconnect, NULL, "disconnect AVRCP", cmd_disconnect, 1, 0), - SHELL_CMD(ct, &ct_cmds, "AVRCP CT shell commands", cmd_avrcp), + SHELL_CMD(ct, &ct_cmds, "AVRCP CT shell commands", cmd_avrcp), + SHELL_CMD(tg, &tg_cmds, "AVRCP TG shell commands", cmd_avrcp), SHELL_SUBCMD_SET_END); SHELL_CMD_ARG_REGISTER(avrcp, &avrcp_cmds, "Bluetooth AVRCP sh commands", cmd_avrcp, 1, 1);