1 /** @file
2  *  @brief Bluetooth audio shell functions
3  *
4  *  This is not to be included by the application.
5  */
6 
7 /*
8  * Copyright (c) 2023 Nordic Semiconductor ASA
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #ifndef __AUDIO_H
14 #define __AUDIO_H
15 
16 #include <stdio.h>
17 
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/shell/shell.h>
20 #include <zephyr/sys/printk.h>
21 
22 #include "shell/bt.h"
23 
24 extern struct bt_csip_set_member_svc_inst *svc_inst;
25 
26 ssize_t audio_ad_data_add(struct bt_data *data, const size_t data_size, const bool discoverable,
27 			  const bool connectable);
28 ssize_t audio_pa_data_add(struct bt_data *data_array, const size_t data_array_size);
29 ssize_t csis_ad_data_add(struct bt_data *data, const size_t data_size, const bool discoverable);
30 size_t cap_acceptor_ad_data_add(struct bt_data data[], size_t data_size, bool discoverable);
31 
32 #if defined(CONFIG_BT_AUDIO)
33 /* Must guard before including audio.h as audio.h uses Kconfigs guarded by
34  * CONFIG_BT_AUDIO
35  */
36 #include <zephyr/bluetooth/audio/audio.h>
37 #include <zephyr/bluetooth/audio/bap.h>
38 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
39 #include <zephyr/bluetooth/audio/cap.h>
40 
41 struct named_lc3_preset {
42 	const char *name;
43 	struct bt_bap_lc3_preset preset;
44 };
45 
46 #if defined(CONFIG_BT_BAP_UNICAST)
47 
48 #define UNICAST_SERVER_STREAM_COUNT                                                                \
49 	COND_CODE_1(CONFIG_BT_ASCS, (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT), \
50 		    (0))
51 #define UNICAST_CLIENT_STREAM_COUNT                                                                \
52 	COND_CODE_1(CONFIG_BT_BAP_UNICAST_CLIENT,                                                  \
53 		    (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT +                                  \
54 		     CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT),                                  \
55 		    (0))
56 
57 struct unicast_stream {
58 	struct bt_cap_stream stream;
59 	struct bt_codec codec;
60 	struct bt_codec_qos qos;
61 };
62 
63 struct broadcast_stream {
64 	struct bt_cap_stream stream;
65 	struct bt_codec_data data;
66 };
67 
68 struct broadcast_source {
69 	union {
70 		struct bt_bap_broadcast_source *bap_source;
71 		struct bt_cap_broadcast_source *cap_source;
72 	};
73 	struct bt_codec codec;
74 	struct bt_codec_qos qos;
75 };
76 
77 extern struct unicast_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT +
78 								   UNICAST_CLIENT_STREAM_COUNT)];
79 
80 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
81 
82 extern struct bt_bap_unicast_group *default_unicast_group;
83 extern struct bt_bap_ep *snks[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
84 extern struct bt_bap_ep *srcs[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
85 extern const struct named_lc3_preset *default_sink_preset;
86 extern const struct named_lc3_preset *default_source_preset;
87 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
88 #endif /* CONFIG_BT_BAP_UNICAST */
89 
print_qos(const struct shell * sh,const struct bt_codec_qos * qos)90 static inline void print_qos(const struct shell *sh, const struct bt_codec_qos *qos)
91 {
92 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST)
93 	shell_print(sh,
94 		    "QoS: interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u latency %u pd %u",
95 		    qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->latency,
96 		    qos->pd);
97 #else
98 	shell_print(sh, "QoS: interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u pd %u",
99 		    qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->pd);
100 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_UNICAST */
101 }
102 
print_codec(const struct shell * sh,const struct bt_codec * codec)103 static inline void print_codec(const struct shell *sh, const struct bt_codec *codec)
104 {
105 	shell_print(sh, "codec 0x%02x cid 0x%04x vid 0x%04x", codec->id, codec->cid, codec->vid);
106 
107 #if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0
108 	shell_print(sh, "data_count %u", codec->data_count);
109 	for (size_t i = 0U; i < codec->data_count; i++) {
110 		shell_print(sh, "data #%u: type 0x%02x len %u", i, codec->data[i].data.type,
111 			    codec->data[i].data.data_len);
112 		shell_hexdump(sh, codec->data[i].data.data,
113 			      codec->data[i].data.data_len - sizeof(codec->data[i].data.type));
114 	}
115 #endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */
116 
117 #if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0
118 	shell_print(sh, "meta_count %u", codec->data_count);
119 	for (size_t i = 0U; i < codec->meta_count; i++) {
120 		shell_print(sh, "meta #%u: type 0x%02x len %u", i, codec->meta[i].data.type,
121 			    codec->meta[i].data.data_len);
122 		shell_hexdump(sh, codec->meta[i].data.data,
123 			      codec->meta[i].data.data_len - sizeof(codec->meta[i].data.type));
124 	}
125 #endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */
126 }
127 
128 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
129 extern struct broadcast_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
130 extern struct broadcast_source default_source;
131 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
132 
133 #if BROADCAST_SNK_SUBGROUP_CNT > 0
print_base(const struct shell * sh,const struct bt_bap_base * base)134 static inline void print_base(const struct shell *sh, const struct bt_bap_base *base)
135 {
136 	uint8_t bis_indexes[BT_ISO_MAX_GROUP_ISO_COUNT] = {0};
137 	/* "0xXX " requires 5 characters */
138 	char bis_indexes_str[5 * ARRAY_SIZE(bis_indexes) + 1];
139 	size_t index_count = 0;
140 
141 	for (size_t i = 0U; i < base->subgroup_count; i++) {
142 		const struct bt_bap_base_subgroup *subgroup;
143 
144 		subgroup = &base->subgroups[i];
145 
146 		shell_print(sh, "Subgroup[%d]:", i);
147 		print_codec(sh, &subgroup->codec);
148 
149 		for (size_t j = 0U; j < subgroup->bis_count; j++) {
150 			const struct bt_bap_base_bis_data *bis_data;
151 
152 			bis_data = &subgroup->bis_data[j];
153 
154 			shell_print(sh, "BIS[%d] index 0x%02x", j, bis_data->index);
155 			bis_indexes[index_count++] = bis_data->index;
156 
157 #if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0
158 			for (size_t k = 0U; k < bis_data->data_count; k++) {
159 				const struct bt_codec_data *codec_data;
160 
161 				codec_data = &bis_data->data[k];
162 
163 				shell_print(sh, "data #%u: type 0x%02x len %u", k,
164 					    codec_data->data.type, codec_data->data.data_len);
165 				shell_hexdump(sh, codec_data->data.data,
166 					      codec_data->data.data_len -
167 						      sizeof(codec_data->data.type));
168 			}
169 #endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */
170 		}
171 	}
172 
173 	(void)memset(bis_indexes_str, 0, sizeof(bis_indexes_str));
174 
175 	/* Create space separated list of indexes as hex values */
176 	for (size_t i = 0U; i < index_count; i++) {
177 		char bis_index_str[6];
178 
179 		sprintf(bis_index_str, "0x%02x ", bis_indexes[i]);
180 
181 		strcat(bis_indexes_str, bis_index_str);
182 		shell_print(sh, "[%d]: %s", i, bis_index_str);
183 	}
184 
185 	shell_print(sh, "Possible indexes: %s", bis_indexes_str);
186 }
187 #endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */
188 
copy_unicast_stream_preset(struct unicast_stream * stream,const struct named_lc3_preset * named_preset)189 static inline void copy_unicast_stream_preset(struct unicast_stream *stream,
190 					      const struct named_lc3_preset *named_preset)
191 {
192 	memcpy(&stream->qos, &named_preset->preset.qos, sizeof(stream->qos));
193 	memcpy(&stream->codec, &named_preset->preset.codec, sizeof(stream->codec));
194 
195 #if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0
196 	/* Need to update the `bt_data.data` pointer to the new value after copying the codec */
197 	for (size_t i = 0U; i < ARRAY_SIZE(stream->codec.data); i++) {
198 		const struct bt_codec_data *preset_data = &named_preset->preset.codec.data[i];
199 		struct bt_codec_data *data = &stream->codec.data[i];
200 		const uint8_t data_len = preset_data->data.data_len;
201 
202 		data->data.data = data->value;
203 		data->data.data_len = data_len;
204 		memcpy(data->value, preset_data->data.data, data_len);
205 	}
206 #endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */
207 
208 #if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0
209 	for (size_t i = 0U; i < ARRAY_SIZE(stream->codec.meta); i++) {
210 		const struct bt_codec_data *preset_data = &named_preset->preset.codec.meta[i];
211 		struct bt_codec_data *data = &stream->codec.meta[i];
212 		const uint8_t data_len = preset_data->data.data_len;
213 
214 		data->data.data = data->value;
215 		data->data.data_len = data_len;
216 		memcpy(data->value, preset_data->data.data, data_len);
217 	}
218 #endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */
219 }
220 
copy_broadcast_source_preset(struct broadcast_source * source,const struct named_lc3_preset * named_preset)221 static inline void copy_broadcast_source_preset(struct broadcast_source *source,
222 						const struct named_lc3_preset *named_preset)
223 {
224 	memcpy(&source->qos, &named_preset->preset.qos, sizeof(source->qos));
225 	memcpy(&source->codec, &named_preset->preset.codec, sizeof(source->codec));
226 
227 #if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0
228 	/* Need to update the `bt_data.data` pointer to the new value after copying the codec */
229 	for (size_t i = 0U; i < ARRAY_SIZE(source->codec.data); i++) {
230 		const struct bt_codec_data *preset_data = &named_preset->preset.codec.data[i];
231 		struct bt_codec_data *data = &source->codec.data[i];
232 		const uint8_t data_len = preset_data->data.data_len;
233 
234 		data->data.data = data->value;
235 		data->data.data_len = data_len;
236 		memcpy(data->value, preset_data->data.data, data_len);
237 	}
238 #endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */
239 
240 #if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0
241 	for (size_t i = 0U; i < ARRAY_SIZE(source->codec.meta); i++) {
242 		const struct bt_codec_data *preset_data = &named_preset->preset.codec.meta[i];
243 		struct bt_codec_data *data = &source->codec.meta[i];
244 		const uint8_t data_len = preset_data->data.data_len;
245 
246 		data->data.data = data->value;
247 		data->data.data_len = data_len;
248 		memcpy(data->value, preset_data->data.data, data_len);
249 	}
250 #endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */
251 }
252 
253 #endif /* CONFIG_BT_AUDIO */
254 
255 #endif /* __AUDIO_H */
256