1 /*
2 * Copyright 2023 NXP
3 * Copyright (c) 2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <zephyr/autoconf.h>
12 #include <zephyr/bluetooth/addr.h>
13 #include <zephyr/bluetooth/audio/audio.h>
14 #include <zephyr/bluetooth/audio/bap.h>
15 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
16 #include <zephyr/bluetooth/audio/csip.h>
17 #include <zephyr/bluetooth/audio/tmap.h>
18 #include <zephyr/bluetooth/audio/cap.h>
19 #include <zephyr/bluetooth/audio/mcs.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/byteorder.h>
22 #include <zephyr/bluetooth/conn.h>
23 #include <zephyr/bluetooth/gap.h>
24 #include <zephyr/bluetooth/hci.h>
25 #include <zephyr/bluetooth/uuid.h>
26 #include <zephyr/kernel.h>
27 #include <zephyr/sys/byteorder.h>
28 #include <zephyr/sys/printk.h>
29 #include <zephyr/sys/util.h>
30 #include <zephyr/sys/util_macro.h>
31 #include <zephyr/types.h>
32
33 #include "tmap_peripheral.h"
34
35 static struct bt_conn *default_conn;
36 static struct k_work_delayable call_terminate_set_work;
37 static struct k_work_delayable media_pause_set_work;
38
39 static uint8_t unicast_server_addata[] = {
40 BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL), /* ASCS UUID */
41 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, /* Target Announcement */
42 BT_BYTES_LIST_LE16(AVAILABLE_SINK_CONTEXT),
43 BT_BYTES_LIST_LE16(AVAILABLE_SOURCE_CONTEXT),
44 0x00, /* Metadata length */
45 };
46
47 static const uint8_t cap_addata[] = {
48 BT_UUID_16_ENCODE(BT_UUID_CAS_VAL),
49 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED,
50 };
51
52 static uint8_t tmap_addata[] = {
53 BT_UUID_16_ENCODE(BT_UUID_TMAS_VAL), /* TMAS UUID */
54 BT_BYTES_LIST_LE16(BT_TMAP_ROLE_UMR | BT_TMAP_ROLE_CT), /* TMAP Role */
55 };
56
57 static uint8_t csis_rsi_addata[BT_CSIP_RSI_SIZE];
58 static bool peer_is_cg;
59 static bool peer_is_ums;
60
61 static const struct bt_data ad[] = {
62 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
63 BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE,
64 BT_BYTES_LIST_LE16(BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD)),
65 BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),
66 BT_UUID_16_ENCODE(BT_UUID_CAS_VAL), BT_UUID_16_ENCODE(BT_UUID_TMAS_VAL)),
67 #if defined(CONFIG_BT_CSIP_SET_MEMBER)
68 BT_DATA(BT_DATA_CSIS_RSI, csis_rsi_addata, ARRAY_SIZE(csis_rsi_addata)),
69 #endif /* CONFIG_BT_CSIP_SET_MEMBER */
70 BT_DATA(BT_DATA_SVC_DATA16, tmap_addata, ARRAY_SIZE(tmap_addata)),
71 BT_DATA(BT_DATA_SVC_DATA16, cap_addata, ARRAY_SIZE(cap_addata)),
72 BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)),
73 BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
74 };
75
76 static K_SEM_DEFINE(sem_connected, 0, 1);
77 static K_SEM_DEFINE(sem_security_updated, 0, 1);
78 static K_SEM_DEFINE(sem_disconnected, 0, 1);
79 static K_SEM_DEFINE(sem_discovery_done, 0, 1);
80
tmap_discovery_complete(enum bt_tmap_role peer_role,struct bt_conn * conn,int err)81 void tmap_discovery_complete(enum bt_tmap_role peer_role, struct bt_conn *conn, int err)
82 {
83 if (conn != default_conn) {
84 return;
85 }
86
87 if (err) {
88 printk("TMAS discovery failed! (err %d)\n", err);
89 return;
90 }
91
92 peer_is_cg = (peer_role & BT_TMAP_ROLE_CG) != 0;
93 peer_is_ums = (peer_role & BT_TMAP_ROLE_UMS) != 0;
94 printk("TMAP discovery done\n");
95 k_sem_give(&sem_discovery_done);
96 }
97
98 static struct bt_tmap_cb tmap_callbacks = {
99 .discovery_complete = tmap_discovery_complete
100 };
101
connected(struct bt_conn * conn,uint8_t err)102 static void connected(struct bt_conn *conn, uint8_t err)
103 {
104 char addr[BT_ADDR_LE_STR_LEN];
105
106 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
107
108 if (err != 0) {
109 printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
110
111 default_conn = NULL;
112 return;
113 }
114
115 printk("Connected: %s\n", addr);
116 default_conn = bt_conn_ref(conn);
117 k_sem_give(&sem_connected);
118 }
119
disconnected(struct bt_conn * conn,uint8_t reason)120 static void disconnected(struct bt_conn *conn, uint8_t reason)
121 {
122 char addr[BT_ADDR_LE_STR_LEN];
123
124 if (conn != default_conn) {
125 return;
126 }
127
128 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
129
130 printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
131
132 bt_conn_unref(default_conn);
133 default_conn = NULL;
134
135 k_sem_give(&sem_disconnected);
136 }
137
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)138 static void security_changed(struct bt_conn *conn, bt_security_t level,
139 enum bt_security_err err)
140 {
141 if (err == 0) {
142 printk("Security changed: %u\n", err);
143 k_sem_give(&sem_security_updated);
144 } else {
145 printk("Failed to set security level: %s(%u)", bt_security_err_to_str(err), err);
146 }
147 }
148
149 BT_CONN_CB_DEFINE(conn_callbacks) = {
150 .connected = connected,
151 .disconnected = disconnected,
152 .security_changed = security_changed,
153 };
154
155 #if defined(CONFIG_BT_PRIVACY) && defined(CONFIG_BT_CSIP_SET_MEMBER)
adv_rpa_expired_cb(struct bt_le_ext_adv * adv)156 static bool adv_rpa_expired_cb(struct bt_le_ext_adv *adv)
157 {
158 char rsi_str[13];
159 int err;
160
161 err = csip_generate_rsi(csis_rsi_addata);
162 if (err != 0) {
163 printk("Failed to generate RSI (err %d)\n", err);
164 return false;
165 }
166
167 snprintk(rsi_str, ARRAY_SIZE(rsi_str), "%02x%02x%02x%02x%02x%02x",
168 csis_rsi_addata[0], csis_rsi_addata[1], csis_rsi_addata[2],
169 csis_rsi_addata[3], csis_rsi_addata[4], csis_rsi_addata[5]);
170
171 printk("PRSI: 0x%s\n", rsi_str);
172
173 err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
174 if (err) {
175 printk("Failed to set advertising data (err %d)\n", err);
176 return false;
177 }
178
179 return true;
180 }
181 #endif /* CONFIG_BT_PRIVACY && CONFIG_BT_CSIP_SET_MEMBER */
182
183 static const struct bt_le_ext_adv_cb adv_cb = {
184 #if defined(CONFIG_BT_PRIVACY) && defined(CONFIG_BT_CSIP_SET_MEMBER)
185 .rpa_expired = adv_rpa_expired_cb,
186 #endif /* CONFIG_BT_PRIVACY && CONFIG_BT_CSIP_SET_MEMBER */
187 };
188
audio_timer_timeout(struct k_work * work)189 static void audio_timer_timeout(struct k_work *work)
190 {
191 int err = ccp_terminate_call();
192
193 if (err != 0) {
194 printk("Error sending call terminate command!\n");
195 }
196 }
197
media_play_timeout(struct k_work * work)198 static void media_play_timeout(struct k_work *work)
199 {
200 int err = mcp_send_cmd(BT_MCS_OPC_PAUSE);
201
202 if (err != 0) {
203 printk("Error sending pause command!\n");
204 }
205 }
206
main(void)207 int main(void)
208 {
209 int err;
210 struct bt_le_ext_adv *adv;
211
212 err = bt_enable(NULL);
213 if (err != 0) {
214 printk("Bluetooth init failed (err %d)\n", err);
215 return err;
216 }
217
218 printk("Bluetooth initialized\n");
219
220 k_work_init_delayable(&call_terminate_set_work, audio_timer_timeout);
221 k_work_init_delayable(&media_pause_set_work, media_play_timeout);
222
223 printk("Initializing TMAP and setting role\n");
224 err = bt_tmap_register(BT_TMAP_ROLE_CT | BT_TMAP_ROLE_UMR);
225 if (err != 0) {
226 return err;
227 }
228
229 if (IS_ENABLED(CONFIG_TMAP_PERIPHERAL_DUO)) {
230 err = csip_set_member_init();
231 if (err != 0) {
232 printk("CSIP Set Member init failed (err %d)\n", err);
233 return err;
234 }
235
236 err = csip_generate_rsi(csis_rsi_addata);
237 if (err != 0) {
238 printk("Failed to generate RSI (err %d)\n", err);
239 return err;
240 }
241 }
242
243 err = vcp_vol_renderer_init();
244 if (err != 0) {
245 return err;
246 }
247 printk("VCP initialized\n");
248
249 err = bap_unicast_sr_init();
250 if (err != 0) {
251 return err;
252 }
253 printk("BAP initialized\n");
254
255 err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, &adv_cb, &adv);
256 if (err) {
257 printk("Failed to create advertising set (err %d)\n", err);
258 return err;
259 }
260
261 err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
262 if (err) {
263 printk("Failed to set advertising data (err %d)\n", err);
264 return err;
265 }
266
267 err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
268 if (err) {
269 printk("Failed to start advertising set (err %d)\n", err);
270 return err;
271 }
272
273 printk("Advertising successfully started\n");
274 k_sem_take(&sem_connected, K_FOREVER);
275 k_sem_take(&sem_security_updated, K_FOREVER);
276
277 err = bt_tmap_discover(default_conn, &tmap_callbacks);
278 if (err != 0) {
279 return err;
280 }
281 k_sem_take(&sem_discovery_done, K_FOREVER);
282
283 err = ccp_call_ctrl_init(default_conn);
284 if (err != 0) {
285 return err;
286 }
287 printk("CCP initialized\n");
288
289 err = mcp_ctlr_init(default_conn);
290 if (err != 0) {
291 return err;
292 }
293 printk("MCP initialized\n");
294
295 if (peer_is_cg) {
296 /* Initiate a call with CCP */
297 err = ccp_originate_call();
298 if (err != 0) {
299 printk("Error sending call originate command!\n");
300 }
301 /* Start timer to send terminate call command */
302 k_work_schedule(&call_terminate_set_work, K_MSEC(2000));
303 }
304
305 if (peer_is_ums) {
306 /* Play media with MCP */
307 err = mcp_send_cmd(BT_MCS_OPC_PLAY);
308 if (err != 0) {
309 printk("Error sending media play command!\n");
310 }
311
312 /* Start timer to send media pause command */
313 k_work_schedule(&media_pause_set_work, K_MSEC(2000));
314
315 err = k_sem_take(&sem_disconnected, K_FOREVER);
316 if (err != 0) {
317 printk("failed to take sem_disconnected (err %d)\n", err);
318 }
319 }
320
321 return 0;
322 }
323