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