1 /*
2 * Copyright 2023 NXP
3 * Copyright (c) 2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <errno.h>
9 #include <stddef.h>
10 #include <stdint.h>
11
12 #include <zephyr/bluetooth/audio/audio.h>
13 #include <zephyr/bluetooth/audio/vcp.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/conn.h>
16 #include <zephyr/bluetooth/hci.h>
17 #include <zephyr/sys/printk.h>
18
19 static struct bt_vcp_vol_ctlr *vcp_vol_ctlr;
20
vcs_discover_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t vocs_count,uint8_t aics_count)21 static void vcs_discover_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err,
22 uint8_t vocs_count, uint8_t aics_count)
23 {
24 if (err != 0) {
25 printk("VCP: Service could not be discovered (%d)\n", err);
26 return;
27 }
28 }
29
vcs_write_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)30 static void vcs_write_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
31 {
32 if (err != 0) {
33 printk("VCP: Write failed (%d)\n", err);
34 return;
35 }
36 }
37
vcs_state_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t volume,uint8_t mute)38 static void vcs_state_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err,
39 uint8_t volume, uint8_t mute)
40 {
41 if (err != 0) {
42 printk("VCP: state cb err (%d)", err);
43 return;
44 }
45
46 printk("VCS volume %u, mute %u\n", volume, mute);
47 }
48
vcs_flags_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err,uint8_t flags)49 static void vcs_flags_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err,
50 uint8_t flags)
51 {
52 if (err != 0) {
53 printk("VCP: flags cb err (%d)", err);
54 return;
55 }
56
57 printk("VCS flags 0x%02X\n", flags);
58 }
59
60 static struct bt_vcp_vol_ctlr_cb vcp_cbs = {
61 .discover = vcs_discover_cb,
62 .vol_down = vcs_write_cb,
63 .vol_up = vcs_write_cb,
64 .mute = vcs_write_cb,
65 .unmute = vcs_write_cb,
66 .vol_down_unmute = vcs_write_cb,
67 .vol_up_unmute = vcs_write_cb,
68 .vol_set = vcs_write_cb,
69 .state = vcs_state_cb,
70 .flags = vcs_flags_cb,
71 };
72
process_profile_connection(struct bt_conn * conn)73 static int process_profile_connection(struct bt_conn *conn)
74 {
75 int err = 0;
76
77 err = bt_vcp_vol_ctlr_discover(conn, &vcp_vol_ctlr);
78
79 if (err != 0) {
80 printk("bt_vcp_vol_ctlr_discover (err %d)\n", err);
81 }
82
83 return err;
84 }
85
connected(struct bt_conn * conn,uint8_t err)86 static void connected(struct bt_conn *conn, uint8_t err)
87 {
88 if (err) {
89 printk("Connection failed, err %d %s\n", err, bt_hci_err_to_str(err));
90 return;
91 }
92
93 if (process_profile_connection(conn) != 0) {
94 printk("Profile connection failed");
95 }
96 }
97
98 BT_CONN_CB_DEFINE(conn_callbacks) = {
99 .connected = connected,
100 };
101
vcp_vol_ctlr_init(void)102 int vcp_vol_ctlr_init(void)
103 {
104 int err;
105
106 err = bt_vcp_vol_ctlr_cb_register(&vcp_cbs);
107 if (err != 0) {
108 printk("CB register failed (err %d)\n", err);
109 }
110
111 return err;
112 }
113
vcp_vol_ctlr_mute(void)114 int vcp_vol_ctlr_mute(void)
115 {
116 int err;
117
118 if (vcp_vol_ctlr != NULL) {
119 err = bt_vcp_vol_ctlr_mute(vcp_vol_ctlr);
120 } else {
121 err = -EINVAL;
122 }
123
124 return err;
125 }
126
vcp_vol_ctlr_unmute(void)127 int vcp_vol_ctlr_unmute(void)
128 {
129 int err;
130
131 if (vcp_vol_ctlr != NULL) {
132 err = bt_vcp_vol_ctlr_unmute(vcp_vol_ctlr);
133 } else {
134 err = -EINVAL;
135 }
136
137 return err;
138 }
139
vcp_vol_ctlr_set_vol(uint8_t volume)140 int vcp_vol_ctlr_set_vol(uint8_t volume)
141 {
142 int err;
143
144 if (vcp_vol_ctlr != NULL) {
145 err = bt_vcp_vol_ctlr_set_vol(vcp_vol_ctlr, volume);
146 } else {
147 err = -EINVAL;
148 }
149
150 return err;
151 }
152