1 /** @file
2  *  @brief Bluetooth Media Control Client/Protocol implementation
3  */
4 
5 /*
6  * Copyright (c) 2019-2024 Nordic Semiconductor ASA
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 #include <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <string.h>
15 
16 #include <zephyr/autoconf.h>
17 #include <zephyr/bluetooth/audio/mcc.h>
18 #include <zephyr/bluetooth/att.h>
19 #include <zephyr/bluetooth/audio/mcs.h>
20 #include <zephyr/bluetooth/audio/media_proxy.h>
21 #include <zephyr/bluetooth/bluetooth.h>
22 #include <zephyr/bluetooth/conn.h>
23 #include <zephyr/bluetooth/gatt.h>
24 #include <zephyr/bluetooth/services/ots.h>
25 #include <zephyr/bluetooth/uuid.h>
26 #include <zephyr/device.h>
27 #include <zephyr/init.h>
28 #include <zephyr/kernel.h>
29 #include <zephyr/logging/log.h>
30 #include <zephyr/net_buf.h>
31 #include <zephyr/sys/__assert.h>
32 #include <zephyr/sys/atomic.h>
33 #include <zephyr/sys/byteorder.h>
34 #include <zephyr/sys/check.h>
35 #include <zephyr/sys/util.h>
36 #include <zephyr/sys/util_macro.h>
37 #include <zephyr/types.h>
38 
39 #include "../services/ots/ots_client_internal.h"
40 #include "common/bt_str.h"
41 #include "mcc_internal.h"
42 #include "mcs_internal.h"
43 
44 /* TODO: Temporarily copied here from media_proxy_internal.h - clean up */
45 /* Debug output of 48 bit Object ID value */
46 /* (Zephyr does not yet support debug output of more than 32 bit values.) */
47 /* Takes a text and a 64-bit integer as input */
48 #define LOG_DBG_OBJ_ID(text, id64) \
49 	do { \
50 		if (IS_ENABLED(CONFIG_BT_MCS_LOG_LEVEL)) { \
51 			char t[BT_OTS_OBJ_ID_STR_LEN]; \
52 			(void)bt_ots_obj_id_to_str(id64, t, sizeof(t)); \
53 			LOG_DBG(text "0x%s", t); \
54 		} \
55 	} while (0)
56 
57 LOG_MODULE_REGISTER(bt_mcc, CONFIG_BT_MCC_LOG_LEVEL);
58 
59 static struct mcs_instance_t mcs_instance;
60 static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
61 
62 static struct bt_mcc_cb *mcc_cb;
63 static bool subscribe_all;
64 
65 #ifdef CONFIG_BT_MCC_OTS
66 NET_BUF_SIMPLE_DEFINE_STATIC(otc_obj_buf, CONFIG_BT_MCC_OTC_OBJ_BUF_SIZE);
67 static struct bt_ots_client_cb otc_cb;
68 #endif /* CONFIG_BT_MCC_OTS */
69 
70 
71 
72 #ifdef CONFIG_BT_MCC_OTS
73 void on_obj_selected(struct bt_ots_client *otc_inst,
74 		     struct bt_conn *conn, int err);
75 
76 void on_object_metadata(struct bt_ots_client *otc_inst,
77 			struct bt_conn *conn, int err,
78 			uint8_t metadata_read);
79 
80 int on_icon_content(struct bt_ots_client *otc_inst,
81 		    struct bt_conn *conn, uint32_t offset,
82 		    uint32_t len, uint8_t *data_p, bool is_complete);
83 #endif /* CONFIG_BT_MCC_OTS */
84 
lookup_inst_by_conn(struct bt_conn * conn)85 struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn)
86 {
87 	if (conn == NULL) {
88 		return NULL;
89 	}
90 
91 	/* TODO: Expand when supporting more instances */
92 	return &mcs_instance;
93 }
94 
mcc_player_name_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)95 static void mcc_player_name_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length)
96 {
97 	int cb_err = err;
98 	char name[CONFIG_BT_MCC_MEDIA_PLAYER_NAME_MAX];
99 
100 	LOG_DBG("err: 0x%02x, length: %d, data: %p", err, length, data);
101 
102 	if (err) {
103 		LOG_DBG("err: 0x%02x", err);
104 	} else if (!data) {
105 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
106 	} else {
107 		LOG_HEXDUMP_DBG(data, length, "Player name read");
108 
109 		if (length >= sizeof(name)) {
110 			length = sizeof(name) - 1;
111 		}
112 
113 		(void)memcpy(&name, data, length);
114 		name[length] = '\0';
115 		LOG_DBG("Player name: %s", name);
116 	}
117 
118 	if (mcc_cb && mcc_cb->read_player_name) {
119 		mcc_cb->read_player_name(conn, cb_err, name);
120 	}
121 }
122 
mcc_read_player_name_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)123 static uint8_t mcc_read_player_name_cb(struct bt_conn *conn, uint8_t err,
124 				       struct bt_gatt_read_params *params,
125 				       const void *data, uint16_t length)
126 {
127 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
128 
129 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
130 	mcc_player_name_cb(conn, err, data, length);
131 
132 	return BT_GATT_ITER_STOP;
133 }
134 
135 
136 #ifdef CONFIG_BT_MCC_OTS
mcc_read_icon_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)137 static uint8_t mcc_read_icon_obj_id_cb(struct bt_conn *conn, uint8_t err,
138 				       struct bt_gatt_read_params *params,
139 				       const void *data, uint16_t length)
140 {
141 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
142 	int cb_err = err;
143 	uint8_t *pid = (uint8_t *)data;
144 	uint64_t id = 0;
145 
146 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
147 	LOG_DBG("err: 0x%02x, length: %d, data: %p", err, length, data);
148 	if (err) {
149 		LOG_DBG("err: 0x%02x", err);
150 	} else if ((!pid) || (length != BT_OTS_OBJ_ID_SIZE)) {
151 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
152 	} else {
153 		LOG_HEXDUMP_DBG(pid, length, "Icon Object ID");
154 		id = sys_get_le48(pid);
155 		LOG_DBG_OBJ_ID("Icon Object ID: ", id);
156 
157 		if (!BT_MCS_VALID_OBJ_ID(id)) {
158 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
159 		}
160 	}
161 
162 	if (mcc_cb && mcc_cb->read_icon_obj_id) {
163 		mcc_cb->read_icon_obj_id(conn, cb_err, id);
164 	}
165 
166 	return BT_GATT_ITER_STOP;
167 }
168 #endif /* CONFIG_BT_MCC_OTS */
169 
170 #if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL)
mcc_read_icon_url_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)171 static uint8_t mcc_read_icon_url_cb(struct bt_conn *conn, uint8_t err,
172 				    struct bt_gatt_read_params *params,
173 				    const void *data, uint16_t length)
174 {
175 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
176 	int cb_err = err;
177 	char url[CONFIG_BT_MCC_ICON_URL_MAX];
178 
179 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
180 	LOG_DBG("err: 0x%02x, length: %d, data: %p", err, length, data);
181 	if (err) {
182 		LOG_DBG("err: 0x%02x", err);
183 	} else if (!data) {
184 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
185 	} else if (length >= sizeof(url)) {
186 		cb_err = BT_ATT_ERR_INSUFFICIENT_RESOURCES;
187 	} else {
188 		LOG_HEXDUMP_DBG(data, length, "Icon URL");
189 		(void)memcpy(&url, data, length);
190 		url[length] = '\0';
191 		LOG_DBG("Icon URL: %s", url);
192 	}
193 
194 	if (mcc_cb && mcc_cb->read_icon_url) {
195 		mcc_cb->read_icon_url(conn, cb_err, url);
196 	}
197 
198 	return BT_GATT_ITER_STOP;
199 }
200 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */
201 
202 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE)
mcc_track_title_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)203 static void mcc_track_title_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length)
204 {
205 	int cb_err = err;
206 	char title[CONFIG_BT_MCC_TRACK_TITLE_MAX];
207 
208 	if (err) {
209 		LOG_DBG("err: 0x%02x", err);
210 	} else if (!data) {
211 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
212 	} else {
213 		LOG_HEXDUMP_DBG(data, length, "Track title");
214 		if (length >= sizeof(title)) {
215 			/* If the description is too long; clip it. */
216 			length = sizeof(title) - 1;
217 		}
218 		(void)memcpy(&title, data, length);
219 		title[length] = '\0';
220 		LOG_DBG("Track title: %s", title);
221 	}
222 
223 	if (mcc_cb && mcc_cb->read_track_title) {
224 		mcc_cb->read_track_title(conn, cb_err, title);
225 	}
226 }
227 
mcc_read_track_title_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)228 static uint8_t mcc_read_track_title_cb(struct bt_conn *conn, uint8_t err,
229 				       struct bt_gatt_read_params *params,
230 				       const void *data, uint16_t length)
231 {
232 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
233 
234 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
235 	mcc_track_title_cb(conn, err, data, length);
236 
237 	return BT_GATT_ITER_STOP;
238 }
239 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE)*/
240 
241 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
mcc_track_duration_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)242 static void mcc_track_duration_cb(struct bt_conn *conn, uint8_t err, const void *data,
243 				  uint16_t length)
244 {
245 	int cb_err = err;
246 	int32_t dur = 0;
247 
248 	if (err) {
249 		LOG_DBG("err: 0x%02x", err);
250 	} else if ((!data) || (length != sizeof(dur))) {
251 		LOG_DBG("length: %d, data: %p", length, data);
252 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
253 	} else {
254 		dur = sys_get_le32((uint8_t *)data);
255 		LOG_DBG("Track duration: %d", dur);
256 		LOG_HEXDUMP_DBG(data, sizeof(int32_t), "Track duration");
257 	}
258 
259 	if (mcc_cb && mcc_cb->read_track_duration) {
260 		mcc_cb->read_track_duration(conn, cb_err, dur);
261 	}
262 }
263 
mcc_read_track_duration_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)264 static uint8_t mcc_read_track_duration_cb(struct bt_conn *conn, uint8_t err,
265 					  struct bt_gatt_read_params *params,
266 					  const void *data, uint16_t length)
267 {
268 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
269 
270 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
271 	mcc_track_duration_cb(conn, err, data, length);
272 
273 	return BT_GATT_ITER_STOP;
274 }
275 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
276 
277 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
mcc_track_position_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)278 static void mcc_track_position_cb(struct bt_conn *conn, uint8_t err, const void *data,
279 				  uint16_t length)
280 {
281 	int cb_err = err;
282 	int32_t pos = 0;
283 
284 	if (err) {
285 		LOG_DBG("err: 0x%02x", err);
286 	} else if ((!data) || (length != sizeof(pos))) {
287 		LOG_DBG("length: %d, data: %p", length, data);
288 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
289 	} else  {
290 		pos = sys_get_le32((uint8_t *)data);
291 		LOG_DBG("Track position: %d", pos);
292 		LOG_HEXDUMP_DBG(data, sizeof(pos), "Track position");
293 	}
294 
295 	if (mcc_cb && mcc_cb->read_track_position) {
296 		mcc_cb->read_track_position(conn, cb_err, pos);
297 	}
298 }
299 
mcc_read_track_position_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)300 static uint8_t mcc_read_track_position_cb(struct bt_conn *conn, uint8_t err,
301 					  struct bt_gatt_read_params *params,
302 					  const void *data, uint16_t length)
303 {
304 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
305 
306 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
307 	mcc_track_position_cb(conn, err, data, length);
308 
309 	return BT_GATT_ITER_STOP;
310 }
311 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
312 
313 #if defined(CONFIG_BT_MCC_SET_TRACK_POSITION)
mcs_write_track_position_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)314 static void mcs_write_track_position_cb(struct bt_conn *conn, uint8_t err,
315 					struct bt_gatt_write_params *params)
316 {
317 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
318 	int cb_err = err;
319 	int32_t pos = 0;
320 
321 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
322 	if (err) {
323 		LOG_DBG("err: 0x%02x", err);
324 	} else if (!params->data || params->length != sizeof(pos)) {
325 		LOG_DBG("length: %d, data: %p", params->length, params->data);
326 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
327 	} else {
328 		pos = sys_get_le32((uint8_t *)params->data);
329 		LOG_DBG("Track position: %d", pos);
330 		LOG_HEXDUMP_DBG(params->data, sizeof(pos), "Track position in callback");
331 	}
332 
333 	if (mcc_cb && mcc_cb->set_track_position) {
334 		mcc_cb->set_track_position(conn, cb_err, pos);
335 	}
336 }
337 #endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */
338 
339 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
mcc_playback_speed_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)340 static void mcc_playback_speed_cb(struct bt_conn *conn, uint8_t err, const void *data,
341 				  uint16_t length)
342 {
343 	int cb_err = err;
344 	int8_t speed = 0;
345 
346 	if (err) {
347 		LOG_DBG("err: 0x%02x", err);
348 	} else if ((!data) || (length != sizeof(speed))) {
349 		LOG_DBG("length: %d, data: %p", length, data);
350 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
351 	} else {
352 		speed = *(int8_t *)data;
353 		LOG_DBG("Playback speed: %d", speed);
354 		LOG_HEXDUMP_DBG(data, sizeof(int8_t), "Playback speed");
355 	}
356 
357 	if (mcc_cb && mcc_cb->read_playback_speed) {
358 		mcc_cb->read_playback_speed(conn, cb_err, speed);
359 	}
360 }
361 
mcc_read_playback_speed_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)362 static uint8_t mcc_read_playback_speed_cb(struct bt_conn *conn, uint8_t err,
363 					  struct bt_gatt_read_params *params,
364 					  const void *data, uint16_t length)
365 {
366 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
367 
368 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
369 	mcc_playback_speed_cb(conn, err, data, length);
370 
371 	return BT_GATT_ITER_STOP;
372 }
373 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
374 
375 #if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
mcs_write_playback_speed_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)376 static void mcs_write_playback_speed_cb(struct bt_conn *conn, uint8_t err,
377 					struct bt_gatt_write_params *params)
378 {
379 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
380 	int cb_err = err;
381 	int8_t speed = 0;
382 
383 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
384 	if (err) {
385 		LOG_DBG("err: 0x%02x", err);
386 	} else if (!params->data || params->length != sizeof(speed)) {
387 		LOG_DBG("length: %d, data: %p", params->length, params->data);
388 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
389 	} else {
390 		speed = *(int8_t *)params->data;
391 		LOG_DBG("Playback_speed: %d", speed);
392 	}
393 
394 	if (mcc_cb && mcc_cb->set_playback_speed) {
395 		mcc_cb->set_playback_speed(conn, cb_err, speed);
396 	}
397 }
398 #endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */
399 
400 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
mcc_seeking_speed_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)401 static void mcc_seeking_speed_cb(struct bt_conn *conn, uint8_t err, const void *data,
402 				 uint16_t length)
403 {
404 	int cb_err = err;
405 	int8_t speed = 0;
406 
407 	if (err) {
408 		LOG_DBG("err: 0x%02x", err);
409 	} else if ((!data) || (length != sizeof(speed))) {
410 		LOG_DBG("length: %d, data: %p", length, data);
411 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
412 	} else {
413 		speed = *(int8_t *)data;
414 		LOG_DBG("Seeking speed: %d", speed);
415 		LOG_HEXDUMP_DBG(data, sizeof(int8_t), "Seeking speed");
416 	}
417 
418 	if (mcc_cb && mcc_cb->read_seeking_speed) {
419 		mcc_cb->read_seeking_speed(conn, cb_err, speed);
420 	}
421 }
422 
mcc_read_seeking_speed_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)423 static uint8_t mcc_read_seeking_speed_cb(struct bt_conn *conn, uint8_t err,
424 					 struct bt_gatt_read_params *params,
425 					 const void *data, uint16_t length)
426 {
427 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
428 
429 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
430 	mcc_seeking_speed_cb(conn, err, data, length);
431 
432 	return BT_GATT_ITER_STOP;
433 }
434 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
435 
436 #ifdef CONFIG_BT_MCC_OTS
mcc_read_segments_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)437 static uint8_t mcc_read_segments_obj_id_cb(struct bt_conn *conn, uint8_t err,
438 					   struct bt_gatt_read_params *params,
439 					   const void *data, uint16_t length)
440 {
441 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
442 	int cb_err = err;
443 	uint8_t *pid = (uint8_t *)data;
444 	uint64_t id = 0;
445 
446 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
447 	if (err) {
448 		LOG_DBG("err: 0x%02x", err);
449 	} else if ((!pid) || (length != BT_OTS_OBJ_ID_SIZE)) {
450 		LOG_DBG("length: %d, data: %p", length, data);
451 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
452 	} else {
453 		LOG_HEXDUMP_DBG(pid, length, "Segments Object ID");
454 		id = sys_get_le48(pid);
455 		LOG_DBG_OBJ_ID("Segments Object ID: ", id);
456 
457 		if (!BT_MCS_VALID_OBJ_ID(id)) {
458 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
459 		}
460 	}
461 
462 	if (mcc_cb && mcc_cb->read_segments_obj_id) {
463 		mcc_cb->read_segments_obj_id(conn, cb_err, id);
464 	}
465 
466 	return BT_GATT_ITER_STOP;
467 }
468 
mcc_current_track_obj_id_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)469 static void mcc_current_track_obj_id_cb(struct bt_conn *conn, uint8_t err, const void *data,
470 					uint16_t length)
471 {
472 	int cb_err = err;
473 	uint8_t *pid = (uint8_t *)data;
474 	uint64_t id = 0;
475 
476 	if (err) {
477 		LOG_DBG("err: 0x%02x", err);
478 	} else if ((!pid) || (length != BT_OTS_OBJ_ID_SIZE)) {
479 		LOG_DBG("length: %d, data: %p", length, data);
480 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
481 	} else {
482 		LOG_HEXDUMP_DBG(pid, length, "Current Track Object ID");
483 		id = sys_get_le48(pid);
484 		LOG_DBG_OBJ_ID("Current Track Object ID: ", id);
485 
486 		if (!BT_MCS_VALID_OBJ_ID(id)) {
487 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
488 		}
489 	}
490 
491 	if (mcc_cb && mcc_cb->read_current_track_obj_id) {
492 		mcc_cb->read_current_track_obj_id(conn, cb_err, id);
493 	}
494 }
495 
mcc_read_current_track_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)496 static uint8_t mcc_read_current_track_obj_id_cb(struct bt_conn *conn, uint8_t err,
497 						struct bt_gatt_read_params *params,
498 						const void *data, uint16_t length)
499 {
500 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
501 
502 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
503 	mcc_current_track_obj_id_cb(conn, err, data, length);
504 
505 	return BT_GATT_ITER_STOP;
506 }
507 
mcs_write_current_track_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)508 static void mcs_write_current_track_obj_id_cb(struct bt_conn *conn, uint8_t err,
509 					      struct bt_gatt_write_params *params)
510 {
511 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
512 	int cb_err = err;
513 	uint64_t obj_id = 0;
514 
515 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
516 	if (err) {
517 		LOG_DBG("err: 0x%02x", err);
518 	} else if (!params->data || params->length != BT_OTS_OBJ_ID_SIZE) {
519 		LOG_DBG("length: %d, data: %p", params->length, params->data);
520 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
521 	} else {
522 		obj_id = sys_get_le48((const uint8_t *)params->data);
523 		LOG_DBG_OBJ_ID("Object ID: ", obj_id);
524 
525 		if (!BT_MCS_VALID_OBJ_ID(obj_id)) {
526 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
527 		}
528 	}
529 
530 	if (mcc_cb && mcc_cb->set_current_track_obj_id) {
531 		mcc_cb->set_current_track_obj_id(conn, cb_err, obj_id);
532 	}
533 }
534 
mcc_next_track_obj_id_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)535 static void mcc_next_track_obj_id_cb(struct bt_conn *conn, uint8_t err, const void *data,
536 				     uint16_t length)
537 {
538 	int cb_err = err;
539 	uint8_t *pid = (uint8_t *)data;
540 	uint64_t id = 0;
541 
542 	if (err) {
543 		LOG_DBG("err: 0x%02x", err);
544 	} else if (length == 0) {
545 		LOG_DBG("Characteristic is empty");
546 	} else if (!pid || (length != BT_OTS_OBJ_ID_SIZE)) {
547 		LOG_DBG("length: %d, data: %p", length, data);
548 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
549 	} else {
550 		LOG_HEXDUMP_DBG(pid, length, "Next Track Object ID");
551 		id = sys_get_le48(pid);
552 		LOG_DBG_OBJ_ID("Next Track Object ID: ", id);
553 
554 		if (!BT_MCS_VALID_OBJ_ID(id)) {
555 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
556 		}
557 	}
558 
559 	if (mcc_cb && mcc_cb->read_next_track_obj_id) {
560 		mcc_cb->read_next_track_obj_id(conn, cb_err, id);
561 	}
562 }
563 
mcc_read_next_track_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)564 static uint8_t mcc_read_next_track_obj_id_cb(struct bt_conn *conn, uint8_t err,
565 					     struct bt_gatt_read_params *params,
566 					     const void *data, uint16_t length)
567 {
568 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
569 
570 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
571 	mcc_next_track_obj_id_cb(conn, err, data, length);
572 
573 	return BT_GATT_ITER_STOP;
574 }
575 
mcs_write_next_track_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)576 static void mcs_write_next_track_obj_id_cb(struct bt_conn *conn, uint8_t err,
577 					   struct bt_gatt_write_params *params)
578 {
579 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
580 	int cb_err = err;
581 	uint64_t obj_id = 0;
582 
583 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
584 	if (err) {
585 		LOG_DBG("err: 0x%02x", err);
586 	} else if (!params->data || params->length != BT_OTS_OBJ_ID_SIZE) {
587 		LOG_DBG("length: %d, data: %p", params->length, params->data);
588 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
589 	} else {
590 		obj_id = sys_get_le48((const uint8_t *)params->data);
591 		LOG_DBG_OBJ_ID("Object ID: ", obj_id);
592 
593 		if (!BT_MCS_VALID_OBJ_ID(obj_id)) {
594 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
595 		}
596 	}
597 
598 	if (mcc_cb && mcc_cb->set_next_track_obj_id) {
599 		mcc_cb->set_next_track_obj_id(conn, cb_err, obj_id);
600 	}
601 }
602 
mcc_parent_group_obj_id_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)603 static void mcc_parent_group_obj_id_cb(struct bt_conn *conn, uint8_t err, const void *data,
604 				       uint16_t length)
605 {
606 	int cb_err = err;
607 	uint8_t *pid = (uint8_t *)data;
608 	uint64_t id = 0;
609 
610 	if (err) {
611 		LOG_DBG("err: 0x%02x", err);
612 	} else if (!pid || (length != BT_OTS_OBJ_ID_SIZE)) {
613 		LOG_DBG("length: %d, data: %p", length, data);
614 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
615 	} else {
616 		LOG_HEXDUMP_DBG(pid, length, "Parent Group Object ID");
617 		id = sys_get_le48(pid);
618 		LOG_DBG_OBJ_ID("Parent Group Object ID: ", id);
619 
620 		if (!BT_MCS_VALID_OBJ_ID(id)) {
621 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
622 		}
623 	}
624 
625 	if (mcc_cb && mcc_cb->read_parent_group_obj_id) {
626 		mcc_cb->read_parent_group_obj_id(conn, cb_err, id);
627 	}
628 }
629 
mcc_read_parent_group_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)630 static uint8_t mcc_read_parent_group_obj_id_cb(struct bt_conn *conn, uint8_t err,
631 					       struct bt_gatt_read_params *params,
632 					       const void *data, uint16_t length)
633 {
634 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
635 
636 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
637 	mcc_parent_group_obj_id_cb(conn, err, data, length);
638 
639 	return BT_GATT_ITER_STOP;
640 }
641 
mcc_current_group_obj_id_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)642 static void mcc_current_group_obj_id_cb(struct bt_conn *conn, uint8_t err, const void *data,
643 					uint16_t length)
644 {
645 	int cb_err = err;
646 	uint8_t *pid = (uint8_t *)data;
647 	uint64_t id = 0;
648 
649 	if (err) {
650 		LOG_DBG("err: 0x%02x", err);
651 	} else if (!pid || (length != BT_OTS_OBJ_ID_SIZE)) {
652 		LOG_DBG("length: %d, data: %p", length, data);
653 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
654 	} else {
655 		LOG_HEXDUMP_DBG(pid, length, "Current Group Object ID");
656 		id = sys_get_le48(pid);
657 		LOG_DBG_OBJ_ID("Current Group Object ID: ", id);
658 
659 		if (!BT_MCS_VALID_OBJ_ID(id)) {
660 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
661 		}
662 	}
663 
664 	if (mcc_cb && mcc_cb->read_current_group_obj_id) {
665 		mcc_cb->read_current_group_obj_id(conn, cb_err, id);
666 	}
667 }
668 
mcc_read_current_group_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)669 static uint8_t mcc_read_current_group_obj_id_cb(struct bt_conn *conn, uint8_t err,
670 						struct bt_gatt_read_params *params,
671 						const void *data, uint16_t length)
672 {
673 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
674 
675 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
676 	mcc_current_group_obj_id_cb(conn, err, data, length);
677 
678 	return BT_GATT_ITER_STOP;
679 }
680 
mcs_write_current_group_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)681 static void mcs_write_current_group_obj_id_cb(struct bt_conn *conn, uint8_t err,
682 					      struct bt_gatt_write_params *params)
683 {
684 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
685 	int cb_err = err;
686 	uint64_t obj_id = 0;
687 
688 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
689 	if (err) {
690 		LOG_DBG("err: 0x%02x", err);
691 	} else if (!params->data || params->length != BT_OTS_OBJ_ID_SIZE) {
692 		LOG_DBG("length: %d, data: %p", params->length, params->data);
693 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
694 	} else {
695 		obj_id = sys_get_le48((const uint8_t *)params->data);
696 		LOG_DBG_OBJ_ID("Object ID: ", obj_id);
697 
698 		if (!BT_MCS_VALID_OBJ_ID(obj_id)) {
699 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
700 		}
701 	}
702 
703 	if (mcc_cb && mcc_cb->set_current_group_obj_id) {
704 		mcc_cb->set_current_group_obj_id(conn, cb_err, obj_id);
705 	}
706 }
707 #endif /* CONFIG_BT_MCC_OTS */
708 
709 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
mcc_playing_order_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)710 static void mcc_playing_order_cb(struct bt_conn *conn, uint8_t err, const void *data,
711 				 uint16_t length)
712 {
713 	int cb_err = err;
714 	uint8_t order = 0;
715 
716 	if (err) {
717 		LOG_DBG("err: 0x%02x", err);
718 	} else if ((!data) || (length != sizeof(order))) {
719 		LOG_DBG("length: %d, data: %p", length, data);
720 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
721 	} else {
722 		order = *(uint8_t *)data;
723 		LOG_DBG("Playing order: %d", order);
724 		LOG_HEXDUMP_DBG(data, sizeof(order), "Playing order");
725 	}
726 
727 	if (mcc_cb && mcc_cb->read_playing_order) {
728 		mcc_cb->read_playing_order(conn, cb_err, order);
729 	}
730 }
731 
mcc_read_playing_order_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)732 static uint8_t mcc_read_playing_order_cb(struct bt_conn *conn, uint8_t err,
733 					 struct bt_gatt_read_params *params,
734 					 const void *data, uint16_t length)
735 {
736 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
737 
738 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
739 	mcc_playing_order_cb(conn, err, data, length);
740 
741 	return BT_GATT_ITER_STOP;
742 }
743 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
744 
745 #if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER)
mcs_write_playing_order_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)746 static void mcs_write_playing_order_cb(struct bt_conn *conn, uint8_t err,
747 				       struct bt_gatt_write_params *params)
748 {
749 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
750 	int cb_err = err;
751 	uint8_t order = 0;
752 
753 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
754 	if (err) {
755 		LOG_DBG("err: 0x%02x", err);
756 	} else if (!params->data || params->length != sizeof(order)) {
757 		LOG_DBG("length: %d, data: %p", params->length, params->data);
758 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
759 	} else {
760 		order = *(uint8_t *)params->data;
761 		LOG_DBG("Playing order: %d", *(uint8_t *)params->data);
762 	}
763 
764 	if (mcc_cb && mcc_cb->set_playing_order) {
765 		mcc_cb->set_playing_order(conn, cb_err, order);
766 	}
767 }
768 #endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */
769 
770 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED)
mcc_read_playing_orders_supported_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)771 static uint8_t mcc_read_playing_orders_supported_cb(struct bt_conn *conn, uint8_t err,
772 						    struct bt_gatt_read_params *params,
773 						    const void *data, uint16_t length)
774 {
775 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
776 	int cb_err = err;
777 	uint16_t orders = 0;
778 
779 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
780 	if (err) {
781 		LOG_DBG("err: 0x%02x", err);
782 	} else if (!data || length != sizeof(orders)) {
783 		LOG_DBG("length: %d, data: %p", length, data);
784 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
785 	} else {
786 		orders = sys_get_le16((uint8_t *)data);
787 		LOG_DBG("Playing orders_supported: %d", orders);
788 		LOG_HEXDUMP_DBG(data, sizeof(orders), "Playing orders supported");
789 	}
790 
791 	if (mcc_cb && mcc_cb->read_playing_orders_supported) {
792 		mcc_cb->read_playing_orders_supported(conn, cb_err, orders);
793 	}
794 
795 	return BT_GATT_ITER_STOP;
796 }
797 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */
798 
799 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
mcc_media_state_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)800 static void mcc_media_state_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length)
801 {
802 	int cb_err = err;
803 	uint8_t state = 0;
804 
805 	if (err) {
806 		LOG_DBG("err: 0x%02x", err);
807 	} else if (!data || length != sizeof(state)) {
808 		LOG_DBG("length: %d, data: %p", length, data);
809 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
810 	} else {
811 		state = *(uint8_t *)data;
812 		LOG_DBG("Media state: %d", state);
813 		LOG_HEXDUMP_DBG(data, sizeof(uint8_t), "Media state");
814 	}
815 
816 	if (mcc_cb && mcc_cb->read_media_state) {
817 		mcc_cb->read_media_state(conn, cb_err, state);
818 	}
819 }
820 
mcc_read_media_state_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)821 static uint8_t mcc_read_media_state_cb(struct bt_conn *conn, uint8_t err,
822 				       struct bt_gatt_read_params *params,
823 				       const void *data, uint16_t length)
824 {
825 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
826 
827 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
828 	mcc_media_state_cb(conn, err, data, length);
829 
830 	return BT_GATT_ITER_STOP;
831 }
832 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
833 
834 #if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT)
mcs_write_cp_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)835 static void mcs_write_cp_cb(struct bt_conn *conn, uint8_t err,
836 			    struct bt_gatt_write_params *params)
837 {
838 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
839 	int cb_err = err;
840 	struct mpl_cmd cmd = {0};
841 
842 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
843 
844 	if (err) {
845 		LOG_DBG("err: 0x%02x", err);
846 	} else if (!params->data ||
847 		   (params->length != sizeof(cmd.opcode) &&
848 		    params->length != sizeof(cmd.opcode) + sizeof(cmd.param))) {
849 		/* Above: No data pointer, or length not equal to any of the */
850 		/* two possible values */
851 		LOG_DBG("length: %d, data: %p", params->length, params->data);
852 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
853 	} else {
854 		(void)memcpy(&cmd.opcode, params->data, sizeof(cmd.opcode));
855 		if (params->length == sizeof(cmd.opcode) + sizeof(cmd.param)) {
856 			(void)memcpy(&cmd.param,
857 			       (char *)(params->data) + sizeof(cmd.opcode),
858 			       sizeof(cmd.param));
859 			cmd.use_param = true;
860 			LOG_DBG("Command in callback: %d, param: %d", cmd.opcode, cmd.param);
861 		}
862 	}
863 
864 	if (mcc_cb && mcc_cb->send_cmd) {
865 		mcc_cb->send_cmd(conn, cb_err, &cmd);
866 	}
867 }
868 #endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */
869 
870 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
mcc_opcodes_supported_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)871 static void mcc_opcodes_supported_cb(struct bt_conn *conn, uint8_t err, const void *data,
872 				     uint16_t length)
873 {
874 	int cb_err = err;
875 	int32_t operations = 0;
876 
877 	if (err) {
878 		LOG_DBG("err: 0x%02x", err);
879 	} else if ((!data) || (length != sizeof(operations))) {
880 		LOG_DBG("length: %d, data: %p", length, data);
881 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
882 
883 	} else {
884 		operations = sys_get_le32((uint8_t *)data);
885 		LOG_DBG("Opcodes supported: %d", operations);
886 		LOG_HEXDUMP_DBG(data, sizeof(operations), "Opcodes_supported");
887 	}
888 
889 	if (mcc_cb && mcc_cb->read_opcodes_supported) {
890 		mcc_cb->read_opcodes_supported(conn, cb_err, operations);
891 	}
892 }
893 
mcc_read_opcodes_supported_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)894 static uint8_t mcc_read_opcodes_supported_cb(struct bt_conn *conn, uint8_t err,
895 					     struct bt_gatt_read_params *params,
896 					     const void *data, uint16_t length)
897 {
898 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
899 
900 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
901 	mcc_opcodes_supported_cb(conn, err, data, length);
902 
903 	return BT_GATT_ITER_STOP;
904 }
905 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
906 
907 #ifdef CONFIG_BT_MCC_OTS
mcs_write_scp_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)908 static void mcs_write_scp_cb(struct bt_conn *conn, uint8_t err,
909 			     struct bt_gatt_write_params *params)
910 {
911 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, write_params);
912 	int cb_err = err;
913 	struct mpl_search search = {0};
914 
915 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
916 
917 	if (err) {
918 		LOG_DBG("err: 0x%02x", err);
919 	} else if (!params->data ||
920 		   (params->length > SEARCH_LEN_MAX)) {
921 		LOG_DBG("length: %d, data: %p", params->length, params->data);
922 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
923 	} else {
924 		search.len = params->length;
925 		(void)memcpy(search.search, params->data, params->length);
926 		LOG_DBG("Length of returned value in callback: %d", search.len);
927 	}
928 
929 	if (mcc_cb && mcc_cb->send_search) {
930 		mcc_cb->send_search(conn, cb_err, &search);
931 	}
932 }
933 
mcc_search_results_obj_id_cb(struct bt_conn * conn,uint8_t err,const void * data,uint16_t length)934 static void mcc_search_results_obj_id_cb(struct bt_conn *conn, uint8_t err,
935 					 const void *data, uint16_t length)
936 {
937 	int cb_err = err;
938 	uint8_t *pid = (uint8_t *)data;
939 	uint64_t id = 0;
940 
941 	if (err) {
942 		LOG_DBG("err: 0x%02x", err);
943 	} else if (length == 0) {
944 		/* OK - this characteristic may be zero length */
945 		/* cb_err and id already have correct values */
946 		LOG_DBG("Zero-length Search Results Object ID");
947 	} else if (!pid || (length != BT_OTS_OBJ_ID_SIZE)) {
948 		LOG_DBG("length: %d, pid: %p", length, pid);
949 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
950 	} else {
951 		id = sys_get_le48(pid);
952 		LOG_DBG_OBJ_ID("Search Results Object ID: ", id);
953 
954 		if (!BT_MCS_VALID_OBJ_ID(id)) {
955 			cb_err = BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
956 		}
957 	}
958 
959 	if (mcc_cb && mcc_cb->read_search_results_obj_id) {
960 		mcc_cb->read_search_results_obj_id(conn, cb_err, id);
961 	}
962 }
963 
mcc_read_search_results_obj_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)964 static uint8_t mcc_read_search_results_obj_id_cb(struct bt_conn *conn, uint8_t err,
965 						 struct bt_gatt_read_params *params,
966 						 const void *data, uint16_t length)
967 {
968 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
969 
970 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
971 	mcc_search_results_obj_id_cb(conn, err, data, length);
972 
973 	return BT_GATT_ITER_STOP;
974 }
975 #endif /* CONFIG_BT_MCC_OTS */
976 
977 #if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID)
mcc_read_content_control_id_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)978 static uint8_t mcc_read_content_control_id_cb(struct bt_conn *conn, uint8_t err,
979 					      struct bt_gatt_read_params *params,
980 					      const void *data, uint16_t length)
981 {
982 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params, struct mcs_instance_t, read_params);
983 	int cb_err = err;
984 	uint8_t ccid = 0;
985 
986 	atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
987 
988 	if (err) {
989 		LOG_DBG("err: 0x%02x", err);
990 	} else if ((!data) || (length != sizeof(ccid))) {
991 		LOG_DBG("length: %d, data: %p", length, data);
992 		cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
993 
994 	} else {
995 		ccid = *(uint8_t *)data;
996 		LOG_DBG("Content control ID: %d", ccid);
997 	}
998 
999 	if (mcc_cb && mcc_cb->read_content_control_id) {
1000 		mcc_cb->read_content_control_id(conn, cb_err, ccid);
1001 	}
1002 
1003 	return BT_GATT_ITER_STOP;
1004 }
1005 #endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */
1006 
mcs_notify_handler(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)1007 static uint8_t mcs_notify_handler(struct bt_conn *conn,
1008 				  struct bt_gatt_subscribe_params *params,
1009 				  const void *data, uint16_t length)
1010 {
1011 	uint16_t handle = params->value_handle;
1012 	struct mcs_instance_t *mcs_inst;
1013 
1014 	if (data == NULL) {
1015 		LOG_DBG("[UNSUBSCRIBED] 0x%04X", params->value_handle);
1016 		params->value_handle = 0U;
1017 
1018 		return BT_GATT_ITER_CONTINUE;
1019 	}
1020 
1021 	mcs_inst = lookup_inst_by_conn(conn);
1022 	if (mcs_inst == NULL) {
1023 		LOG_DBG("Could not find MCS instance from conn %p", (void *)conn);
1024 
1025 		return BT_GATT_ITER_CONTINUE;
1026 	}
1027 
1028 	LOG_DBG("Notification, handle: %d", handle);
1029 
1030 	if (handle == mcs_inst->player_name_handle) {
1031 		LOG_DBG("Player Name notification");
1032 		mcc_player_name_cb(conn, 0, data, length);
1033 
1034 	} else if (handle == mcs_inst->track_changed_handle) {
1035 		/* The Track Changed characteristic can only be */
1036 		/* notified, so that is handled directly here */
1037 		int cb_err = 0;
1038 
1039 		LOG_DBG("Track Changed notification");
1040 		LOG_DBG("data: %p, length: %u", data, length);
1041 
1042 		if (length != 0) {
1043 			LOG_DBG("Non-zero length: %u", length);
1044 			cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
1045 		}
1046 
1047 		if (mcc_cb && mcc_cb->track_changed_ntf) {
1048 			mcc_cb->track_changed_ntf(conn, cb_err);
1049 		}
1050 
1051 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION)
1052 	} else if (handle == mcs_inst->track_title_handle) {
1053 		LOG_DBG("Track Title notification");
1054 		mcc_track_title_cb(conn, 0, data, length);
1055 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */
1056 
1057 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
1058 	} else if (handle == mcs_inst->track_duration_handle) {
1059 		LOG_DBG("Track Duration notification");
1060 		mcc_track_duration_cb(conn, 0, data, length);
1061 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
1062 
1063 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
1064 	} else if (handle == mcs_inst->track_position_handle) {
1065 		LOG_DBG("Track Position notification");
1066 		mcc_track_position_cb(conn, 0, data, length);
1067 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
1068 
1069 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
1070 	} else if (handle == mcs_inst->playback_speed_handle) {
1071 		LOG_DBG("Playback Speed notification");
1072 		mcc_playback_speed_cb(conn, 0, data, length);
1073 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
1074 
1075 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
1076 	} else if (handle == mcs_inst->seeking_speed_handle) {
1077 		LOG_DBG("Seeking Speed notification");
1078 		mcc_seeking_speed_cb(conn, 0, data, length);
1079 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
1080 
1081 #ifdef CONFIG_BT_MCC_OTS
1082 	} else if (handle == mcs_inst->current_track_obj_id_handle) {
1083 		LOG_DBG("Current Track notification");
1084 		mcc_current_track_obj_id_cb(conn, 0, data, length);
1085 
1086 	} else if (handle == mcs_inst->next_track_obj_id_handle) {
1087 		LOG_DBG("Next Track notification");
1088 		mcc_next_track_obj_id_cb(conn, 0, data, length);
1089 
1090 	} else if (handle == mcs_inst->parent_group_obj_id_handle) {
1091 		LOG_DBG("Parent Group notification");
1092 		mcc_parent_group_obj_id_cb(conn, 0, data, length);
1093 
1094 	} else if (handle == mcs_inst->current_group_obj_id_handle) {
1095 		LOG_DBG("Current Group notification");
1096 		mcc_current_group_obj_id_cb(conn, 0, data, length);
1097 #endif /* CONFIG_BT_MCC_OTS */
1098 
1099 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
1100 	} else if (handle == mcs_inst->playing_order_handle) {
1101 		LOG_DBG("Playing Order notification");
1102 		mcc_playing_order_cb(conn, 0, data, length);
1103 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
1104 
1105 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
1106 	} else if (handle == mcs_inst->media_state_handle) {
1107 		LOG_DBG("Media State notification");
1108 		mcc_media_state_cb(conn, 0, data, length);
1109 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
1110 
1111 	} else if (handle == mcs_inst->cp_handle) {
1112 		/* The control point is a special case - only */
1113 		/* writable and notifiable.  Handle directly here. */
1114 		struct mpl_cmd_ntf ntf = {0};
1115 		int cb_err = 0;
1116 
1117 		LOG_DBG("Control Point notification");
1118 		if (length == sizeof(ntf.requested_opcode) + sizeof(ntf.result_code)) {
1119 			ntf.requested_opcode = *(uint8_t *)data;
1120 			ntf.result_code = *((uint8_t *)data +
1121 						sizeof(ntf.requested_opcode));
1122 			LOG_DBG("Command: %d, result: %d",
1123 				ntf.requested_opcode, ntf.result_code);
1124 		} else {
1125 			LOG_DBG("length: %d, data: %p", length, data);
1126 			cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
1127 		}
1128 
1129 		if (mcc_cb && mcc_cb->cmd_ntf) {
1130 			mcc_cb->cmd_ntf(conn, cb_err, &ntf);
1131 		}
1132 
1133 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
1134 	} else if (handle == mcs_inst->opcodes_supported_handle) {
1135 		LOG_DBG("Opcodes Supported notification");
1136 		mcc_opcodes_supported_cb(conn, 0, data, length);
1137 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
1138 
1139 #ifdef CONFIG_BT_MCC_OTS
1140 	} else if (handle == mcs_inst->scp_handle) {
1141 		/* The search control point is a special case - only */
1142 		/* writable and notifiable.  Handle directly here. */
1143 		int cb_err = 0;
1144 		uint8_t result_code = 0;
1145 
1146 		LOG_DBG("Search Control Point notification");
1147 		if (length == sizeof(result_code)) {
1148 			result_code = *(uint8_t *)data;
1149 			LOG_DBG("Result: %d", result_code);
1150 		} else {
1151 			LOG_DBG("length: %d, data: %p", length, data);
1152 			cb_err = BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
1153 		}
1154 
1155 		if (mcc_cb && mcc_cb->search_ntf) {
1156 			mcc_cb->search_ntf(conn, cb_err, result_code);
1157 		}
1158 
1159 	} else if (handle == mcs_inst->search_results_obj_id_handle) {
1160 		LOG_DBG("Search Results notification");
1161 		mcc_search_results_obj_id_cb(conn, 0, data, length);
1162 #endif /* CONFIG_BT_MCC_OTS */
1163 	} else {
1164 		LOG_DBG("Unknown handle: %d (0x%04X)", handle, handle);
1165 	}
1166 
1167 	return BT_GATT_ITER_CONTINUE;
1168 }
1169 
reset_mcs_inst(struct mcs_instance_t * mcs_inst)1170 static int reset_mcs_inst(struct mcs_instance_t *mcs_inst)
1171 {
1172 	if (mcs_inst->conn != NULL) {
1173 		struct bt_conn *conn = mcs_inst->conn;
1174 		struct bt_conn_info info;
1175 		int err;
1176 
1177 		err = bt_conn_get_info(conn, &info);
1178 		if (err != 0) {
1179 			return err;
1180 		}
1181 
1182 		if (info.state == BT_CONN_STATE_CONNECTED) {
1183 			/* It's okay if these fail with -EINVAL as that means that they are
1184 			 * not currently subscribed
1185 			 */
1186 			err = bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params);
1187 			if (err != 0 && err != -EINVAL) {
1188 				LOG_DBG("Failed to unsubscribe to name: %d", err);
1189 
1190 				return err;
1191 			}
1192 
1193 			err = bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params);
1194 			if (err != 0 && err != -EINVAL) {
1195 				LOG_DBG("Failed to unsubscribe to track change: %d", err);
1196 
1197 				return err;
1198 			}
1199 
1200 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION)
1201 			err = bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params);
1202 			if (err != 0 && err != -EINVAL) {
1203 				LOG_DBG("Failed to unsubscribe to track title: %d", err);
1204 
1205 				return err;
1206 			}
1207 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */
1208 
1209 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
1210 			err = bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params);
1211 			if (err != 0 && err != -EINVAL) {
1212 				LOG_DBG("Failed to unsubscribe to track duration: %d", err);
1213 
1214 				return err;
1215 			}
1216 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
1217 
1218 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
1219 			err = bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params);
1220 			if (err != 0 && err != -EINVAL) {
1221 				LOG_DBG("Failed to unsubscribe to track position: %d", err);
1222 
1223 				return err;
1224 			}
1225 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
1226 
1227 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
1228 			err = bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params);
1229 			if (err != 0 && err != -EINVAL) {
1230 				LOG_DBG("Failed to unsubscribe to playback speed: %d", err);
1231 
1232 				return err;
1233 			}
1234 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
1235 
1236 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
1237 			err = bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params);
1238 			if (err != 0 && err != -EINVAL) {
1239 				LOG_DBG("Failed to unsubscribe to seeking speed: %d", err);
1240 
1241 				return err;
1242 			}
1243 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
1244 
1245 #ifdef CONFIG_BT_MCC_OTS
1246 			err = bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params);
1247 			if (err != 0 && err != -EINVAL) {
1248 				LOG_DBG("Failed to unsubscribe to current track object: %d", err);
1249 
1250 				return err;
1251 			}
1252 
1253 			err = bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params);
1254 			if (err != 0 && err != -EINVAL) {
1255 				LOG_DBG("Failed to unsubscribe to next track object: %d", err);
1256 
1257 				return err;
1258 			}
1259 
1260 			err = bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params);
1261 			if (err != 0 && err != -EINVAL) {
1262 				LOG_DBG("Failed to unsubscribe to parent group object: %d", err);
1263 
1264 				return err;
1265 			}
1266 
1267 			err = bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params);
1268 			if (err != 0 && err != -EINVAL) {
1269 				LOG_DBG("Failed to unsubscribe to current group object: %d", err);
1270 
1271 				return err;
1272 			}
1273 
1274 #endif /* CONFIG_BT_MCC_OTS */
1275 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
1276 			err = bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params);
1277 			if (err != 0 && err != -EINVAL) {
1278 				LOG_DBG("Failed to unsubscribe to playing order: %d", err);
1279 
1280 				return err;
1281 			}
1282 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
1283 
1284 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
1285 			err = bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params);
1286 			if (err != 0 && err != -EINVAL) {
1287 				LOG_DBG("Failed to unsubscribe to media state: %d", err);
1288 
1289 				return err;
1290 			}
1291 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
1292 
1293 			err = bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params);
1294 			if (err != 0 && err != -EINVAL) {
1295 				LOG_DBG("Failed to unsubscribe to control point: %d", err);
1296 
1297 				return err;
1298 			}
1299 
1300 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
1301 			err = bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params);
1302 			if (err != 0 && err != -EINVAL) {
1303 				LOG_DBG("Failed to unsubscribe to supported opcodes: %d", err);
1304 
1305 				return err;
1306 			}
1307 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
1308 
1309 #ifdef CONFIG_BT_MCC_OTS
1310 			err = bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params);
1311 			if (err != 0 && err != -EINVAL) {
1312 				LOG_DBG("Failed to unsubscribe to search control point: %d", err);
1313 
1314 				return err;
1315 			}
1316 
1317 			err = bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params);
1318 			if (err != 0 && err != -EINVAL) {
1319 				LOG_DBG("Failed to unsubscribe to search results: %d", err);
1320 
1321 				return err;
1322 			}
1323 
1324 			err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params);
1325 			if (err != 0 && err != -EINVAL) {
1326 				LOG_DBG("Failed to unsubscribe to oacp: %d", err);
1327 
1328 				return err;
1329 			}
1330 
1331 			err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params);
1332 			if (err != 0 && err != -EINVAL) {
1333 				LOG_DBG("Failed to unsubscribe to olcp: %d", err);
1334 
1335 				return err;
1336 			}
1337 #endif /* CONFIG_BT_MCC_OTS */
1338 		}
1339 
1340 		bt_conn_unref(conn);
1341 		mcs_inst->conn = NULL;
1342 	}
1343 
1344 	(void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, player_name_sub_params));
1345 #ifdef CONFIG_BT_MCC_OTS
1346 	/* Reset OTC instance as well if supported */
1347 	(void)memset(&mcs_inst->otc, 0, offsetof(struct bt_ots_client, oacp_sub_params));
1348 #endif /* CONFIG_BT_MCC_OTS */
1349 
1350 	return 0;
1351 }
1352 
disconnected_cb(struct bt_conn * conn,uint8_t reason)1353 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
1354 {
1355 	struct mcs_instance_t *mcs_inst;
1356 
1357 	mcs_inst = lookup_inst_by_conn(conn);
1358 	if (mcs_inst != NULL) {
1359 		(void)reset_mcs_inst(mcs_inst);
1360 	}
1361 }
1362 
1363 BT_CONN_CB_DEFINE(conn_callbacks) = {
1364 	.disconnected = disconnected_cb,
1365 };
1366 
1367 /* Called when discovery is completed - successfully or with error */
discovery_complete(struct bt_conn * conn,int err)1368 static void discovery_complete(struct bt_conn *conn, int err)
1369 {
1370 	struct mcs_instance_t *mcs_inst;
1371 
1372 	LOG_DBG("Discovery completed, err: %d", err);
1373 
1374 	mcs_inst = lookup_inst_by_conn(conn);
1375 	if (mcs_inst != NULL) {
1376 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
1377 		if (err != 0) {
1378 			(void)reset_mcs_inst(mcs_inst);
1379 		}
1380 	}
1381 
1382 	if (mcc_cb && mcc_cb->discover_mcs) {
1383 		mcc_cb->discover_mcs(conn, err);
1384 	}
1385 }
1386 
1387 #ifdef CONFIG_BT_MCC_OTS
discover_otc_char_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)1388 static uint8_t discover_otc_char_func(struct bt_conn *conn,
1389 				      const struct bt_gatt_attr *attr,
1390 				      struct bt_gatt_discover_params *params)
1391 {
1392 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
1393 						       struct mcs_instance_t,
1394 						       discover_params);
1395 	int err = 0;
1396 	struct bt_gatt_chrc *chrc;
1397 	struct bt_gatt_subscribe_params *sub_params = NULL;
1398 
1399 	if (attr) {
1400 		/* Found an attribute */
1401 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
1402 
1403 		if (params->type != BT_GATT_DISCOVER_CHARACTERISTIC) {
1404 			/* But it was not a characteristic - continue search */
1405 			return BT_GATT_ITER_CONTINUE;
1406 		}
1407 
1408 		/* We have found an attribute, and it is a characteristic */
1409 		/* Find out which attribute, and subscribe if we should */
1410 		chrc = (struct bt_gatt_chrc *)attr->user_data;
1411 		if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_FEATURE)) {
1412 			LOG_DBG("OTS Features");
1413 			mcs_inst->otc.feature_handle = chrc->value_handle;
1414 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_NAME)) {
1415 			LOG_DBG("Object Name");
1416 			mcs_inst->otc.obj_name_handle = chrc->value_handle;
1417 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_TYPE)) {
1418 			LOG_DBG("Object Type");
1419 			mcs_inst->otc.obj_type_handle = chrc->value_handle;
1420 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_SIZE)) {
1421 			LOG_DBG("Object Size");
1422 			mcs_inst->otc.obj_size_handle = chrc->value_handle;
1423 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_ID)) {
1424 			LOG_DBG("Object ID");
1425 			mcs_inst->otc.obj_id_handle = chrc->value_handle;
1426 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_PROPERTIES)) {
1427 			LOG_DBG("Object properties %d", chrc->value_handle);
1428 			mcs_inst->otc.obj_properties_handle = chrc->value_handle;
1429 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_ACTION_CP)) {
1430 			LOG_DBG("Object Action Control Point");
1431 			mcs_inst->otc.oacp_handle = chrc->value_handle;
1432 			sub_params = &mcs_inst->otc.oacp_sub_params;
1433 			sub_params->disc_params = &mcs_inst->otc.oacp_sub_disc_params;
1434 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_OTS_LIST_CP)) {
1435 			LOG_DBG("Object List Control Point");
1436 			mcs_inst->otc.olcp_handle = chrc->value_handle;
1437 			sub_params = &mcs_inst->otc.olcp_sub_params;
1438 			sub_params->disc_params = &mcs_inst->otc.olcp_sub_disc_params;
1439 		}
1440 
1441 		if (sub_params) {
1442 			sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
1443 			sub_params->end_handle = mcs_inst->otc.end_handle;
1444 			sub_params->value = BT_GATT_CCC_INDICATE;
1445 			sub_params->value_handle = chrc->value_handle;
1446 			sub_params->notify = bt_ots_client_indicate_handler;
1447 			atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
1448 
1449 			err = bt_gatt_subscribe(conn, sub_params);
1450 			if (err != 0) {
1451 				LOG_DBG("Failed to subscribe (err %d)", err);
1452 				discovery_complete(conn, err);
1453 
1454 				return BT_GATT_ITER_STOP;
1455 			}
1456 		}
1457 
1458 		return BT_GATT_ITER_CONTINUE;
1459 	}
1460 
1461 	/* No more attributes found */
1462 	mcs_inst->otc.cb = &otc_cb;
1463 	bt_ots_client_register(&mcs_inst->otc);
1464 
1465 	LOG_DBG("Setup complete for included OTS");
1466 	(void)memset(params, 0, sizeof(*params));
1467 
1468 	discovery_complete(conn, err);
1469 
1470 	return BT_GATT_ITER_STOP;
1471 }
1472 #endif /* CONFIG_BT_MCC_OTS */
1473 
1474 #ifdef CONFIG_BT_MCC_OTS
1475 /* This function is called when an included service is found.
1476  * The function will store the start and end handle for the service,
1477  * and continue the search for more instances of included services.
1478  * Lastly, it will start discovery of OTS characteristics.
1479  */
1480 
discover_include_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)1481 static uint8_t discover_include_func(struct bt_conn *conn,
1482 				     const struct bt_gatt_attr *attr,
1483 				     struct bt_gatt_discover_params *params)
1484 {
1485 	struct bt_gatt_include *include;
1486 	int err = 0;
1487 
1488 	if (attr) {
1489 		struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
1490 							       struct mcs_instance_t,
1491 							       discover_params);
1492 
1493 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
1494 
1495 		__ASSERT(params->type == BT_GATT_DISCOVER_INCLUDE,
1496 			 "Wrong type");
1497 
1498 		/* We have found an included service */
1499 		include = (struct bt_gatt_include *)attr->user_data;
1500 		LOG_DBG("Include UUID %s", bt_uuid_str(include->uuid));
1501 
1502 		if (bt_uuid_cmp(include->uuid, BT_UUID_OTS)) {
1503 			/* But it is not OTS - continue search */
1504 			LOG_WRN("Included service is not OTS");
1505 			return BT_GATT_ITER_CONTINUE;
1506 		}
1507 
1508 		/* We have the included OTS service (MCS includes only one) */
1509 		LOG_DBG("Discover include complete for GMCS: OTS");
1510 		mcs_inst->otc.start_handle = include->start_handle;
1511 		mcs_inst->otc.end_handle = include->end_handle;
1512 		(void)memset(params, 0, sizeof(*params));
1513 
1514 		/* Discover characteristics of the included OTS */
1515 		mcs_inst->discover_params.start_handle = mcs_inst->otc.start_handle;
1516 		mcs_inst->discover_params.end_handle = mcs_inst->otc.end_handle;
1517 		mcs_inst->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
1518 		mcs_inst->discover_params.func = discover_otc_char_func;
1519 
1520 		LOG_DBG("Start discovery of OTS characteristics");
1521 		err = bt_gatt_discover(conn, &mcs_inst->discover_params);
1522 		if (err) {
1523 			LOG_DBG("Discovery of OTS chars. failed");
1524 			discovery_complete(conn, err);
1525 		}
1526 		return BT_GATT_ITER_STOP;
1527 	}
1528 
1529 	LOG_DBG("No included OTS found");
1530 	/* This is OK, the server may not support OTS. But in that case,
1531 	 *  discovery stops here.
1532 	 */
1533 	discovery_complete(conn, err);
1534 	return BT_GATT_ITER_STOP;
1535 }
1536 
1537 /* Start discovery of included services */
discover_included(struct mcs_instance_t * mcs_inst,struct bt_conn * conn)1538 static void discover_included(struct mcs_instance_t *mcs_inst, struct bt_conn *conn)
1539 {
1540 	int err;
1541 
1542 	memset(&mcs_inst->discover_params, 0, sizeof(mcs_inst->discover_params));
1543 
1544 	mcs_inst->discover_params.start_handle = mcs_inst->start_handle;
1545 	mcs_inst->discover_params.end_handle = mcs_inst->end_handle;
1546 	mcs_inst->discover_params.type = BT_GATT_DISCOVER_INCLUDE;
1547 	mcs_inst->discover_params.func = discover_include_func;
1548 
1549 	LOG_DBG("Start discovery of included services");
1550 	err = bt_gatt_discover(conn, &mcs_inst->discover_params);
1551 	if (err) {
1552 		LOG_DBG("Discovery of included service failed: %d", err);
1553 		discovery_complete(conn, err);
1554 	}
1555 }
1556 #endif /* CONFIG_BT_MCC_OTS */
1557 
1558 static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst,
1559 				    struct bt_conn *conn);
1560 
1561 /* This function will subscribe to GMCS CCCDs.
1562  * After this, the function will start discovery of included services.
1563  */
subscribe_mcs_char_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * params)1564 static void subscribe_mcs_char_func(struct bt_conn *conn, uint8_t err,
1565 				    struct bt_gatt_subscribe_params *params)
1566 {
1567 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params->disc_params,
1568 						       struct mcs_instance_t,
1569 						       discover_params);
1570 	bool subscription_done;
1571 
1572 	if (err) {
1573 		LOG_DBG("Subscription callback error: %u", err);
1574 		params->subscribe = NULL;
1575 		discovery_complete(conn, err);
1576 		return;
1577 	}
1578 
1579 	LOG_DBG("Subscribed: value handle: %d, ccc handle: %d",
1580 	       params->value_handle, params->ccc_handle);
1581 
1582 	if (params->value_handle == 0) {
1583 		/* Unsubscribing, ignore */
1584 		return;
1585 	}
1586 
1587 	/* Subscribe to next characteristic */
1588 	subscription_done = subscribe_next_mcs_char(mcs_inst, conn);
1589 
1590 	if (subscription_done) {
1591 		params->subscribe = NULL;
1592 #ifdef CONFIG_BT_MCC_OTS
1593 		/* Start discovery of included services to find OTS */
1594 		discover_included(mcs_inst, conn);
1595 #else
1596 		/* If OTS is not configured, discovery ends here */
1597 		discovery_complete(conn, 0);
1598 #endif /* CONFIG_BT_MCC_OTS */
1599 	}
1600 }
1601 
1602 /* Subscribe to a characteristic - helper function */
do_subscribe(struct mcs_instance_t * mcs_inst,struct bt_conn * conn,uint16_t handle,struct bt_gatt_subscribe_params * sub_params)1603 static int do_subscribe(struct mcs_instance_t *mcs_inst, struct bt_conn *conn,
1604 			uint16_t handle,
1605 			struct bt_gatt_subscribe_params *sub_params)
1606 {
1607 	sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
1608 	sub_params->end_handle = mcs_inst->end_handle;
1609 	sub_params->value_handle = handle;
1610 	sub_params->notify = mcs_notify_handler;
1611 	sub_params->subscribe = subscribe_mcs_char_func;
1612 	/* disc_params pointer is also used as subscription flag */
1613 	sub_params->disc_params = &mcs_inst->discover_params;
1614 	atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
1615 
1616 	LOG_DBG("Subscring to handle %d", handle);
1617 	return bt_gatt_subscribe(conn, sub_params);
1618 }
1619 
1620 /* Subscribe to the next GMCS CCCD.
1621  * @return true if there are no more characteristics to subscribe to
1622  */
subscribe_next_mcs_char(struct mcs_instance_t * mcs_inst,struct bt_conn * conn)1623 static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst,
1624 				    struct bt_conn *conn)
1625 {
1626 	struct bt_gatt_subscribe_params *sub_params = NULL;
1627 	uint16_t handle;
1628 
1629 	/* The characteristics may be in any order on the server, and
1630 	 * not all of them may exist => need to check all.
1631 	 * For each of the subscribable characteristics
1632 	 * - check if we have a handle for it
1633 	 * - check sub_params.disc_params pointer to see if we have
1634 	 *   already subscribed to it (set in do_subscribe() ).
1635 	 */
1636 
1637 	if (mcs_inst->player_name_handle &&
1638 	    mcs_inst->player_name_sub_params.value &&
1639 	    mcs_inst->player_name_sub_params.disc_params == NULL) {
1640 		sub_params = &mcs_inst->player_name_sub_params;
1641 		handle = mcs_inst->player_name_handle;
1642 	} else if (mcs_inst->track_changed_handle &&
1643 		   mcs_inst->track_changed_sub_params.value &&
1644 		   mcs_inst->track_changed_sub_params.disc_params == NULL) {
1645 		sub_params = &mcs_inst->track_changed_sub_params;
1646 		handle = mcs_inst->track_changed_handle;
1647 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION)
1648 	} else if (mcs_inst->track_title_handle &&
1649 		   mcs_inst->track_title_sub_params.value &&
1650 		   mcs_inst->track_title_sub_params.disc_params == NULL) {
1651 		sub_params = &mcs_inst->track_title_sub_params;
1652 		handle = mcs_inst->track_title_handle;
1653 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */
1654 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
1655 	} else if (mcs_inst->track_duration_handle &&
1656 		   mcs_inst->track_duration_sub_params.value &&
1657 		   mcs_inst->track_duration_sub_params.disc_params == NULL) {
1658 		sub_params = &mcs_inst->track_duration_sub_params;
1659 		handle = mcs_inst->track_duration_handle;
1660 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
1661 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
1662 	} else if (mcs_inst->track_position_handle &&
1663 		   mcs_inst->track_position_sub_params.value &&
1664 		   mcs_inst->track_position_sub_params.disc_params == NULL) {
1665 		sub_params = &mcs_inst->track_position_sub_params;
1666 		handle = mcs_inst->track_position_handle;
1667 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
1668 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
1669 	} else if (mcs_inst->playback_speed_handle &&
1670 		   mcs_inst->playback_speed_sub_params.value &&
1671 		   mcs_inst->playback_speed_sub_params.disc_params == NULL) {
1672 		sub_params = &mcs_inst->playback_speed_sub_params;
1673 		handle = mcs_inst->playback_speed_handle;
1674 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
1675 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
1676 	} else if (mcs_inst->seeking_speed_handle &&
1677 		   mcs_inst->seeking_speed_sub_params.value &&
1678 		   mcs_inst->seeking_speed_sub_params.disc_params == NULL) {
1679 		sub_params = &mcs_inst->seeking_speed_sub_params;
1680 		handle = mcs_inst->seeking_speed_handle;
1681 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
1682 #ifdef CONFIG_BT_MCC_OTS
1683 	} else if (mcs_inst->current_track_obj_id_handle &&
1684 		   mcs_inst->current_track_obj_sub_params.value &&
1685 		   mcs_inst->current_track_obj_sub_params.disc_params == NULL) {
1686 		sub_params = &mcs_inst->current_track_obj_sub_params;
1687 		handle = mcs_inst->current_track_obj_id_handle;
1688 	} else if (mcs_inst->next_track_obj_id_handle &&
1689 		   mcs_inst->next_track_obj_sub_params.value &&
1690 		   mcs_inst->next_track_obj_sub_params.disc_params == NULL) {
1691 		sub_params = &mcs_inst->next_track_obj_sub_params;
1692 		handle = mcs_inst->next_track_obj_id_handle;
1693 	} else if (mcs_inst->parent_group_obj_id_handle &&
1694 		   mcs_inst->parent_group_obj_sub_params.value &&
1695 		   mcs_inst->parent_group_obj_sub_params.disc_params == NULL) {
1696 		sub_params = &mcs_inst->parent_group_obj_sub_params;
1697 		handle = mcs_inst->parent_group_obj_id_handle;
1698 	} else if (mcs_inst->current_group_obj_id_handle &&
1699 		   mcs_inst->current_group_obj_sub_params.value &&
1700 		   mcs_inst->current_group_obj_sub_params.disc_params == NULL) {
1701 		sub_params = &mcs_inst->current_group_obj_sub_params;
1702 		handle = mcs_inst->current_group_obj_id_handle;
1703 #endif /* CONFIG_BT_MCC_OTS */
1704 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
1705 	} else if (mcs_inst->playing_order_handle &&
1706 		   mcs_inst->playing_order_sub_params.value &&
1707 		   mcs_inst->playing_order_sub_params.disc_params == NULL) {
1708 		sub_params = &mcs_inst->playing_order_sub_params;
1709 		handle = mcs_inst->playing_order_handle;
1710 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
1711 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
1712 	} else if (mcs_inst->media_state_handle &&
1713 		  mcs_inst->media_state_sub_params.value &&
1714 		  mcs_inst->media_state_sub_params.disc_params == NULL) {
1715 		sub_params = &mcs_inst->media_state_sub_params;
1716 		handle = mcs_inst->media_state_handle;
1717 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
1718 	} else if (mcs_inst->cp_handle &&
1719 		   mcs_inst->cp_sub_params.value &&
1720 		   mcs_inst->cp_sub_params.disc_params == NULL) {
1721 		sub_params = &mcs_inst->cp_sub_params;
1722 		handle = mcs_inst->cp_handle;
1723 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
1724 	} else if (mcs_inst->opcodes_supported_handle &&
1725 		   mcs_inst->opcodes_supported_sub_params.value &&
1726 		   mcs_inst->opcodes_supported_sub_params.disc_params == NULL) {
1727 		sub_params = &mcs_inst->opcodes_supported_sub_params;
1728 		handle = mcs_inst->opcodes_supported_handle;
1729 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
1730 #ifdef CONFIG_BT_MCC_OTS
1731 	} else if (mcs_inst->scp_handle &&
1732 		   mcs_inst->scp_sub_params.value &&
1733 		   mcs_inst->scp_sub_params.disc_params == NULL) {
1734 		sub_params = &mcs_inst->scp_sub_params;
1735 		handle = mcs_inst->scp_handle;
1736 	} else if (mcs_inst->search_results_obj_id_handle &&
1737 		   mcs_inst->search_results_obj_sub_params.value &&
1738 		   mcs_inst->search_results_obj_sub_params.disc_params == NULL) {
1739 		sub_params = &mcs_inst->search_results_obj_sub_params;
1740 		handle = mcs_inst->search_results_obj_id_handle;
1741 #endif /* CONFIG_BT_MCC_OTS */
1742 	}
1743 
1744 	if (sub_params != NULL) {
1745 		const int err = do_subscribe(mcs_inst, conn, handle,
1746 					     sub_params);
1747 
1748 		if (err) {
1749 			LOG_DBG("Could not subscribe: %d", err);
1750 			discovery_complete(conn, err);
1751 		}
1752 
1753 		return false;
1754 	}
1755 
1756 	/* If we have come here, there are no more characteristics to
1757 	 * subscribe to, and we are done.
1758 	 */
1759 	return true;
1760 }
1761 
1762 /* This function is called when characteristics are found.
1763  * The function will store handles to GMCS characteristics.
1764  * After this, the function will start subscription to characteristics
1765  */
discover_mcs_char_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)1766 static uint8_t discover_mcs_char_func(struct bt_conn *conn,
1767 				      const struct bt_gatt_attr *attr,
1768 				      struct bt_gatt_discover_params *params)
1769 {
1770 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
1771 						       struct mcs_instance_t,
1772 						       discover_params);
1773 	struct bt_gatt_chrc *chrc;
1774 	bool subscription_done = true;
1775 
1776 	if (attr) {
1777 		/* Found an attribute */
1778 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
1779 
1780 		if (params->type != BT_GATT_DISCOVER_CHARACTERISTIC) {
1781 			/* But it was not a characteristic - continue search */
1782 			return BT_GATT_ITER_CONTINUE;
1783 		}
1784 
1785 		/* We have found an attribute, and it is a characteristic */
1786 		/* Find out which attribute, and subscribe if we should */
1787 		chrc = (struct bt_gatt_chrc *)attr->user_data;
1788 
1789 		if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYER_NAME)) {
1790 			LOG_DBG("Player name, UUID: %s", bt_uuid_str(chrc->uuid));
1791 			mcs_inst->player_name_handle = chrc->value_handle;
1792 			/* Use discovery params pointer as subscription flag */
1793 			mcs_inst->player_name_sub_params.disc_params = NULL;
1794 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1795 				mcs_inst->player_name_sub_params.value = BT_GATT_CCC_NOTIFY;
1796 			}
1797 #ifdef CONFIG_BT_MCC_OTS
1798 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_ICON_OBJ_ID)) {
1799 			LOG_DBG("Icon Object, UUID: %s", bt_uuid_str(chrc->uuid));
1800 			mcs_inst->icon_obj_id_handle = chrc->value_handle;
1801 #endif /* CONFIG_BT_MCC_OTS */
1802 #if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL)
1803 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_ICON_URL)) {
1804 			LOG_DBG("Icon URL, UUID: %s", bt_uuid_str(chrc->uuid));
1805 			mcs_inst->icon_url_handle = chrc->value_handle;
1806 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */
1807 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_CHANGED)) {
1808 			LOG_DBG("Track Changed, UUID: %s", bt_uuid_str(chrc->uuid));
1809 			mcs_inst->track_changed_handle = chrc->value_handle;
1810 			mcs_inst->track_changed_sub_params.disc_params = NULL;
1811 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1812 				mcs_inst->track_changed_sub_params.value = BT_GATT_CCC_NOTIFY;
1813 			}
1814 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE)
1815 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_TITLE)) {
1816 			LOG_DBG("Track Title, UUID: %s", bt_uuid_str(chrc->uuid));
1817 			mcs_inst->track_title_handle = chrc->value_handle;
1818 #if defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION)
1819 			mcs_inst->track_title_sub_params.disc_params = NULL;
1820 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1821 				mcs_inst->track_title_sub_params.value = BT_GATT_CCC_NOTIFY;
1822 			}
1823 #endif /* defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */
1824 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */
1825 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
1826 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_DURATION)) {
1827 			LOG_DBG("Track Duration, UUID: %s", bt_uuid_str(chrc->uuid));
1828 			mcs_inst->track_duration_handle = chrc->value_handle;
1829 			mcs_inst->track_duration_sub_params.disc_params = NULL;
1830 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1831 				mcs_inst->track_duration_sub_params.value = BT_GATT_CCC_NOTIFY;
1832 			}
1833 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
1834 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION)
1835 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_POSITION)) {
1836 			LOG_DBG("Track Position, UUID: %s", bt_uuid_str(chrc->uuid));
1837 			mcs_inst->track_position_handle = chrc->value_handle;
1838 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
1839 			mcs_inst->track_position_sub_params.disc_params = NULL;
1840 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1841 				mcs_inst->track_position_sub_params.value = BT_GATT_CCC_NOTIFY;
1842 			}
1843 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
1844 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */
1845 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
1846 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYBACK_SPEED)) {
1847 			LOG_DBG("Playback Speed, UUID: %s", bt_uuid_str(chrc->uuid));
1848 			mcs_inst->playback_speed_handle = chrc->value_handle;
1849 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
1850 			mcs_inst->playback_speed_sub_params.disc_params = NULL;
1851 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1852 				mcs_inst->playback_speed_sub_params.value = BT_GATT_CCC_NOTIFY;
1853 			}
1854 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
1855 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) ||
1856 	* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
1857 	*/
1858 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
1859 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEEKING_SPEED)) {
1860 			LOG_DBG("Seeking Speed, UUID: %s", bt_uuid_str(chrc->uuid));
1861 			mcs_inst->seeking_speed_handle = chrc->value_handle;
1862 			mcs_inst->seeking_speed_sub_params.disc_params = NULL;
1863 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1864 				mcs_inst->seeking_speed_sub_params.value = BT_GATT_CCC_NOTIFY;
1865 			}
1866 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
1867 #ifdef CONFIG_BT_MCC_OTS
1868 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID)) {
1869 			LOG_DBG("Track Segments Object, UUID: %s", bt_uuid_str(chrc->uuid));
1870 			mcs_inst->segments_obj_id_handle = chrc->value_handle;
1871 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_CURRENT_TRACK_OBJ_ID)) {
1872 			LOG_DBG("Current Track Object, UUID: %s", bt_uuid_str(chrc->uuid));
1873 			mcs_inst->current_track_obj_id_handle = chrc->value_handle;
1874 			mcs_inst->current_track_obj_sub_params.disc_params = NULL;
1875 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1876 				mcs_inst->current_track_obj_sub_params.value =
1877 					BT_GATT_CCC_NOTIFY;
1878 			}
1879 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_NEXT_TRACK_OBJ_ID)) {
1880 			LOG_DBG("Next Track Object, UUID: %s", bt_uuid_str(chrc->uuid));
1881 			mcs_inst->next_track_obj_id_handle = chrc->value_handle;
1882 			mcs_inst->next_track_obj_sub_params.disc_params = NULL;
1883 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1884 				mcs_inst->next_track_obj_sub_params.value = BT_GATT_CCC_NOTIFY;
1885 			}
1886 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PARENT_GROUP_OBJ_ID)) {
1887 			LOG_DBG("Parent Group Object, UUID: %s", bt_uuid_str(chrc->uuid));
1888 			mcs_inst->parent_group_obj_id_handle = chrc->value_handle;
1889 			mcs_inst->parent_group_obj_sub_params.disc_params = NULL;
1890 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1891 				mcs_inst->parent_group_obj_sub_params.value =
1892 					BT_GATT_CCC_NOTIFY;
1893 			}
1894 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_CURRENT_GROUP_OBJ_ID)) {
1895 			LOG_DBG("Group Object, UUID: %s", bt_uuid_str(chrc->uuid));
1896 			mcs_inst->current_group_obj_id_handle = chrc->value_handle;
1897 			mcs_inst->current_group_obj_sub_params.disc_params = NULL;
1898 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1899 				mcs_inst->current_group_obj_sub_params.value =
1900 					BT_GATT_CCC_NOTIFY;
1901 			}
1902 #endif /* CONFIG_BT_MCC_OTS */
1903 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER)
1904 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDER)) {
1905 			LOG_DBG("Playing Order, UUID: %s", bt_uuid_str(chrc->uuid));
1906 			mcs_inst->playing_order_handle = chrc->value_handle;
1907 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
1908 			mcs_inst->playing_order_sub_params.disc_params = NULL;
1909 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1910 				mcs_inst->playing_order_sub_params.value = BT_GATT_CCC_NOTIFY;
1911 			}
1912 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
1913 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */
1914 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED)
1915 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDERS)) {
1916 			LOG_DBG("Playing Orders supported, UUID: %s", bt_uuid_str(chrc->uuid));
1917 			mcs_inst->playing_orders_supported_handle = chrc->value_handle;
1918 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */
1919 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
1920 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_STATE)) {
1921 			LOG_DBG("Media State, UUID: %s", bt_uuid_str(chrc->uuid));
1922 			mcs_inst->media_state_handle = chrc->value_handle;
1923 			mcs_inst->media_state_sub_params.disc_params = NULL;
1924 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1925 				mcs_inst->media_state_sub_params.value = BT_GATT_CCC_NOTIFY;
1926 			}
1927 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
1928 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_POINT)) {
1929 			LOG_DBG("Media Control Point, UUID: %s", bt_uuid_str(chrc->uuid));
1930 			mcs_inst->cp_handle = chrc->value_handle;
1931 			mcs_inst->cp_sub_params.disc_params = NULL;
1932 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1933 				mcs_inst->cp_sub_params.value = BT_GATT_CCC_NOTIFY;
1934 			}
1935 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
1936 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_OPCODES)) {
1937 			LOG_DBG("Media control opcodes supported, UUID: %s",
1938 			       bt_uuid_str(chrc->uuid));
1939 			mcs_inst->opcodes_supported_handle = chrc->value_handle;
1940 			mcs_inst->opcodes_supported_sub_params.disc_params = NULL;
1941 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1942 				mcs_inst->opcodes_supported_sub_params.value =
1943 					BT_GATT_CCC_NOTIFY;
1944 			}
1945 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
1946 #ifdef CONFIG_BT_MCC_OTS
1947 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEARCH_CONTROL_POINT)) {
1948 			LOG_DBG("Search control point, UUID: %s", bt_uuid_str(chrc->uuid));
1949 			mcs_inst->scp_handle = chrc->value_handle;
1950 			mcs_inst->scp_sub_params.disc_params = NULL;
1951 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1952 				mcs_inst->scp_sub_params.value = BT_GATT_CCC_NOTIFY;
1953 			}
1954 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID)) {
1955 			LOG_DBG("Search Results object, UUID: %s", bt_uuid_str(chrc->uuid));
1956 			mcs_inst->search_results_obj_id_handle = chrc->value_handle;
1957 			mcs_inst->search_results_obj_sub_params.disc_params = NULL;
1958 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1959 				mcs_inst->search_results_obj_sub_params.value =
1960 					BT_GATT_CCC_NOTIFY;
1961 			}
1962 #endif /* CONFIG_BT_MCC_OTS */
1963 #if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID)
1964 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_CCID)) {
1965 			LOG_DBG("Content Control ID, UUID: %s", bt_uuid_str(chrc->uuid));
1966 			mcs_inst->content_control_id_handle = chrc->value_handle;
1967 #endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */
1968 		}
1969 
1970 
1971 		/* Continue to search for more attributes */
1972 		return BT_GATT_ITER_CONTINUE;
1973 	}
1974 
1975 	/* No more attributes found */
1976 	LOG_DBG("GMCS characteristics found");
1977 	(void)memset(params, 0, sizeof(*params));
1978 
1979 	/* Either subscribe to characteristics, or continue to discovery of
1980 	 *included services.
1981 	 * Subscription is done after discovery, not in parallel with it,
1982 	 * to avoid queuing many ATT requests that requires buffers.
1983 	 */
1984 	if (subscribe_all) {
1985 		subscription_done = subscribe_next_mcs_char(mcs_inst, conn);
1986 	}
1987 
1988 	if (subscription_done) {
1989 		/* Not subscribing, or there was nothing to subscribe to */
1990 #ifdef CONFIG_BT_MCC_OTS
1991 		/* Start discovery of included services to find OTS */
1992 		discover_included(mcs_inst, conn);
1993 #else
1994 		/* If OTS is not configured, discovery ends here */
1995 		discovery_complete(conn, 0);
1996 #endif /* CONFIG_BT_MCC_OTS */
1997 	}
1998 
1999 	return BT_GATT_ITER_STOP;
2000 }
2001 
2002 /* This function is called when a (primary) GMCS service has been discovered.
2003  * The function will store the start and end handle for the service. It will
2004  * then start discovery of the characteristics of the GMCS service.
2005  */
discover_primary_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)2006 static uint8_t discover_primary_func(struct bt_conn *conn,
2007 				     const struct bt_gatt_attr *attr,
2008 				     struct bt_gatt_discover_params *params)
2009 {
2010 	struct bt_gatt_service_val *prim_service;
2011 
2012 	if (attr) {
2013 		struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
2014 							       struct mcs_instance_t,
2015 							       discover_params);
2016 		int err;
2017 		/* Found an attribute */
2018 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
2019 
2020 		if (params->type != BT_GATT_DISCOVER_PRIMARY) {
2021 			/* But it was not a primary service - continue search */
2022 			LOG_WRN("Unexpected parameters");
2023 			return BT_GATT_ITER_CONTINUE;
2024 		}
2025 
2026 		/* We have found an attribute, and it is a primary service */
2027 		/* (Must be GMCS, since that is the one we searched for.) */
2028 		LOG_DBG("Primary discovery complete");
2029 		LOG_DBG("UUID: %s", bt_uuid_str(attr->uuid));
2030 		prim_service = (struct bt_gatt_service_val *)attr->user_data;
2031 		LOG_DBG("UUID: %s", bt_uuid_str(prim_service->uuid));
2032 
2033 		mcs_inst->start_handle = attr->handle + 1;
2034 		mcs_inst->end_handle = prim_service->end_handle;
2035 
2036 		/* Start discovery of characteristics */
2037 		mcs_inst->discover_params.uuid = NULL;
2038 		mcs_inst->discover_params.start_handle = mcs_inst->start_handle;
2039 		mcs_inst->discover_params.end_handle = mcs_inst->end_handle;
2040 		mcs_inst->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
2041 		mcs_inst->discover_params.func = discover_mcs_char_func;
2042 
2043 		LOG_DBG("Start discovery of GMCS characteristics");
2044 		err = bt_gatt_discover(conn, &mcs_inst->discover_params);
2045 		if (err) {
2046 			LOG_DBG("Discovery failed: %d", err);
2047 			discovery_complete(conn, err);
2048 		}
2049 		return BT_GATT_ITER_STOP;
2050 	}
2051 
2052 	/* No attribute of the searched for type found */
2053 	LOG_DBG("Could not find an GMCS instance on the server");
2054 
2055 	discovery_complete(conn, -ENODATA);
2056 	return BT_GATT_ITER_STOP;
2057 }
2058 
2059 
bt_mcc_init(struct bt_mcc_cb * cb)2060 int bt_mcc_init(struct bt_mcc_cb *cb)
2061 {
2062 	mcc_cb = cb;
2063 
2064 #ifdef CONFIG_BT_MCC_OTS
2065 	/* Set up the callbacks from OTC */
2066 	/* TODO: Have one single content callback. */
2067 	/* For now: Use the icon callback for content - it is the first, */
2068 	/* and this will anyway be reset later. */
2069 	otc_cb.obj_data_read     = on_icon_content;
2070 	otc_cb.obj_selected      = on_obj_selected;
2071 	otc_cb.obj_metadata_read = on_object_metadata;
2072 
2073 	LOG_DBG("Object selected callback: %p", otc_cb.obj_selected);
2074 	LOG_DBG("Object content callback: %p", otc_cb.obj_data_read);
2075 	LOG_DBG("Object metadata callback: %p", otc_cb.obj_metadata_read);
2076 #endif /* CONFIG_BT_MCC_OTS */
2077 
2078 	return 0;
2079 }
2080 
2081 
2082 /* Initiate discovery.
2083  * Discovery is handled by a chain of functions, where each function does its
2084  * part, and then initiates a further discovery, with a new callback function.
2085  *
2086  * The order of discovery is follows:
2087  * 1: Discover GMCS primary service (started here)
2088  * 2: Discover characteristics of GMCS
2089  * 3: Subscribe to characteristics of GMCS
2090  * 4: Discover OTS service included in GMCS
2091  * 5: Discover characteristics of OTS and subscribe to them
2092  */
bt_mcc_discover_mcs(struct bt_conn * conn,bool subscribe)2093 int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe)
2094 {
2095 	struct mcs_instance_t *mcs_inst;
2096 	int err;
2097 
2098 	CHECKIF(!conn) {
2099 		return -EINVAL;
2100 	}
2101 
2102 	mcs_inst = lookup_inst_by_conn(conn);
2103 	if (mcs_inst == NULL) {
2104 		/* TODO: Need to find existing or new MCS instance here */
2105 		return -EINVAL;
2106 	}
2107 
2108 	if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2109 		return -EBUSY;
2110 	}
2111 
2112 	subscribe_all = subscribe;
2113 	err = reset_mcs_inst(mcs_inst);
2114 	if (err != 0) {
2115 		LOG_DBG("Failed to reset MCS instance %p: %d", mcs_inst, err);
2116 
2117 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2118 
2119 		return err;
2120 	}
2121 	(void)memcpy(&uuid, BT_UUID_GMCS, sizeof(uuid));
2122 
2123 	mcs_inst->discover_params.func = discover_primary_func;
2124 	mcs_inst->discover_params.uuid = &uuid.uuid;
2125 	mcs_inst->discover_params.type = BT_GATT_DISCOVER_PRIMARY;
2126 	mcs_inst->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
2127 	mcs_inst->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
2128 
2129 	LOG_DBG("start discovery of GMCS primary service");
2130 	err = bt_gatt_discover(conn, &mcs_inst->discover_params);
2131 	if (err != 0) {
2132 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2133 		return err;
2134 	}
2135 
2136 	mcs_inst->conn = bt_conn_ref(conn);
2137 
2138 	return 0;
2139 }
2140 
bt_mcc_read_player_name(struct bt_conn * conn)2141 int bt_mcc_read_player_name(struct bt_conn *conn)
2142 {
2143 	struct mcs_instance_t *mcs_inst;
2144 	int err;
2145 
2146 	CHECKIF(conn == NULL) {
2147 		LOG_DBG("conn is NULL");
2148 
2149 		return -EINVAL;
2150 	}
2151 
2152 	mcs_inst = lookup_inst_by_conn(conn);
2153 	if (mcs_inst == NULL) {
2154 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2155 
2156 		return -EINVAL;
2157 	} else if (mcs_inst->player_name_handle == 0) {
2158 		LOG_DBG("handle not set");
2159 
2160 		return -EINVAL;
2161 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2162 
2163 		LOG_DBG("mcs_inst busy");
2164 		return -EBUSY;
2165 	}
2166 
2167 	mcs_inst->read_params.func = mcc_read_player_name_cb;
2168 	mcs_inst->read_params.handle_count = 1;
2169 	mcs_inst->read_params.single.handle = mcs_inst->player_name_handle;
2170 	mcs_inst->read_params.single.offset = 0U;
2171 
2172 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2173 	if (err != 0) {
2174 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2175 	}
2176 	return err;
2177 }
2178 
2179 #ifdef CONFIG_BT_MCC_OTS
bt_mcc_read_icon_obj_id(struct bt_conn * conn)2180 int bt_mcc_read_icon_obj_id(struct bt_conn *conn)
2181 {
2182 	struct mcs_instance_t *mcs_inst;
2183 	int err;
2184 
2185 	CHECKIF(conn == NULL) {
2186 		LOG_DBG("conn is NULL");
2187 
2188 		return -EINVAL;
2189 	}
2190 
2191 	mcs_inst = lookup_inst_by_conn(conn);
2192 	if (mcs_inst == NULL) {
2193 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2194 
2195 		return -EINVAL;
2196 	} else if (mcs_inst->icon_obj_id_handle == 0) {
2197 		LOG_DBG("handle not set");
2198 
2199 		return -EINVAL;
2200 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2201 
2202 		LOG_DBG("mcs_inst busy");
2203 		return -EBUSY;
2204 	}
2205 
2206 	mcs_inst->read_params.func = mcc_read_icon_obj_id_cb;
2207 	mcs_inst->read_params.handle_count = 1;
2208 	mcs_inst->read_params.single.handle = mcs_inst->icon_obj_id_handle;
2209 	mcs_inst->read_params.single.offset = 0U;
2210 
2211 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2212 	if (err != 0) {
2213 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2214 	}
2215 	return err;
2216 }
2217 #endif /* CONFIG_BT_MCC_OTS */
2218 
2219 #if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL)
bt_mcc_read_icon_url(struct bt_conn * conn)2220 int bt_mcc_read_icon_url(struct bt_conn *conn)
2221 {
2222 	struct mcs_instance_t *mcs_inst;
2223 	int err;
2224 
2225 	CHECKIF(conn == NULL) {
2226 		LOG_DBG("conn is NULL");
2227 
2228 		return -EINVAL;
2229 	}
2230 
2231 	mcs_inst = lookup_inst_by_conn(conn);
2232 	if (mcs_inst == NULL) {
2233 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2234 
2235 		return -EINVAL;
2236 	} else if (mcs_inst->icon_url_handle == 0) {
2237 		LOG_DBG("handle not set");
2238 
2239 		return -EINVAL;
2240 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2241 
2242 		LOG_DBG("mcs_inst busy");
2243 		return -EBUSY;
2244 	}
2245 
2246 	mcs_inst->read_params.func = mcc_read_icon_url_cb;
2247 	mcs_inst->read_params.handle_count = 1;
2248 	mcs_inst->read_params.single.handle = mcs_inst->icon_url_handle;
2249 	mcs_inst->read_params.single.offset = 0U;
2250 
2251 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2252 	if (err != 0) {
2253 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2254 	}
2255 	return err;
2256 }
2257 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */
2258 
2259 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE)
bt_mcc_read_track_title(struct bt_conn * conn)2260 int bt_mcc_read_track_title(struct bt_conn *conn)
2261 {
2262 	struct mcs_instance_t *mcs_inst;
2263 	int err;
2264 
2265 	CHECKIF(conn == NULL) {
2266 		LOG_DBG("conn is NULL");
2267 
2268 		return -EINVAL;
2269 	}
2270 
2271 	mcs_inst = lookup_inst_by_conn(conn);
2272 	if (mcs_inst == NULL) {
2273 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2274 
2275 		return -EINVAL;
2276 	} else if (mcs_inst->track_title_handle == 0) {
2277 		LOG_DBG("handle not set");
2278 
2279 		return -EINVAL;
2280 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2281 
2282 		LOG_DBG("mcs_inst busy");
2283 		return -EBUSY;
2284 	}
2285 
2286 	mcs_inst->read_params.func = mcc_read_track_title_cb;
2287 	mcs_inst->read_params.handle_count = 1;
2288 	mcs_inst->read_params.single.handle = mcs_inst->track_title_handle;
2289 	mcs_inst->read_params.single.offset = 0U;
2290 
2291 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2292 	if (err != 0) {
2293 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2294 	}
2295 	return err;
2296 }
2297 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */
2298 
2299 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
bt_mcc_read_track_duration(struct bt_conn * conn)2300 int bt_mcc_read_track_duration(struct bt_conn *conn)
2301 {
2302 	struct mcs_instance_t *mcs_inst;
2303 	int err;
2304 
2305 	CHECKIF(conn == NULL) {
2306 		LOG_DBG("conn is NULL");
2307 
2308 		return -EINVAL;
2309 	}
2310 
2311 	mcs_inst = lookup_inst_by_conn(conn);
2312 	if (mcs_inst == NULL) {
2313 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2314 
2315 		return -EINVAL;
2316 	} else if (mcs_inst->track_duration_handle == 0) {
2317 		LOG_DBG("handle not set");
2318 
2319 		return -EINVAL;
2320 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2321 
2322 		LOG_DBG("mcs_inst busy");
2323 		return -EBUSY;
2324 	}
2325 
2326 	mcs_inst->read_params.func = mcc_read_track_duration_cb;
2327 	mcs_inst->read_params.handle_count = 1;
2328 	mcs_inst->read_params.single.handle = mcs_inst->track_duration_handle;
2329 	mcs_inst->read_params.single.offset = 0U;
2330 
2331 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2332 	if (err != 0) {
2333 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2334 	}
2335 	return err;
2336 }
2337 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
2338 
2339 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
bt_mcc_read_track_position(struct bt_conn * conn)2340 int bt_mcc_read_track_position(struct bt_conn *conn)
2341 {
2342 	struct mcs_instance_t *mcs_inst;
2343 	int err;
2344 
2345 	CHECKIF(conn == NULL) {
2346 		LOG_DBG("conn is NULL");
2347 
2348 		return -EINVAL;
2349 	}
2350 
2351 	mcs_inst = lookup_inst_by_conn(conn);
2352 	if (mcs_inst == NULL) {
2353 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2354 
2355 		return -EINVAL;
2356 	} else if (mcs_inst->track_position_handle == 0) {
2357 		LOG_DBG("handle not set");
2358 
2359 		return -EINVAL;
2360 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2361 
2362 		LOG_DBG("mcs_inst busy");
2363 		return -EBUSY;
2364 	}
2365 
2366 	mcs_inst->read_params.func = mcc_read_track_position_cb;
2367 	mcs_inst->read_params.handle_count = 1;
2368 	mcs_inst->read_params.single.handle = mcs_inst->track_position_handle;
2369 	mcs_inst->read_params.single.offset = 0U;
2370 
2371 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2372 	if (err != 0) {
2373 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2374 	}
2375 	return err;
2376 }
2377 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
2378 
2379 #if defined(CONFIG_BT_MCC_SET_TRACK_POSITION)
bt_mcc_set_track_position(struct bt_conn * conn,int32_t pos)2380 int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos)
2381 {
2382 	struct mcs_instance_t *mcs_inst;
2383 	int err;
2384 
2385 	CHECKIF(conn == NULL) {
2386 		LOG_DBG("conn is NULL");
2387 
2388 		return -EINVAL;
2389 	}
2390 
2391 	mcs_inst = lookup_inst_by_conn(conn);
2392 	if (mcs_inst == NULL) {
2393 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2394 
2395 		return -EINVAL;
2396 	} else if (mcs_inst->track_position_handle == 0) {
2397 		LOG_DBG("handle not set");
2398 
2399 		return -EINVAL;
2400 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2401 
2402 		LOG_DBG("mcs_inst busy");
2403 		return -EBUSY;
2404 	}
2405 
2406 	(void)memcpy(mcs_inst->write_buf, &pos, sizeof(pos));
2407 
2408 	mcs_inst->write_params.offset = 0;
2409 	mcs_inst->write_params.data = mcs_inst->write_buf;
2410 	mcs_inst->write_params.length = sizeof(pos);
2411 	mcs_inst->write_params.handle = mcs_inst->track_position_handle;
2412 	mcs_inst->write_params.func = mcs_write_track_position_cb;
2413 
2414 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(pos), "Track position sent");
2415 
2416 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2417 	if (err != 0) {
2418 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2419 	}
2420 	return err;
2421 }
2422 #endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */
2423 
2424 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
bt_mcc_read_playback_speed(struct bt_conn * conn)2425 int bt_mcc_read_playback_speed(struct bt_conn *conn)
2426 {
2427 	struct mcs_instance_t *mcs_inst;
2428 	int err;
2429 
2430 	CHECKIF(conn == NULL) {
2431 		LOG_DBG("conn is NULL");
2432 
2433 		return -EINVAL;
2434 	}
2435 
2436 	mcs_inst = lookup_inst_by_conn(conn);
2437 	if (mcs_inst == NULL) {
2438 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2439 
2440 		return -EINVAL;
2441 	} else if (mcs_inst->playback_speed_handle == 0) {
2442 		LOG_DBG("handle not set");
2443 
2444 		return -EINVAL;
2445 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2446 
2447 		LOG_DBG("mcs_inst busy");
2448 		return -EBUSY;
2449 	}
2450 
2451 	mcs_inst->read_params.func = mcc_read_playback_speed_cb;
2452 	mcs_inst->read_params.handle_count = 1;
2453 	mcs_inst->read_params.single.handle = mcs_inst->playback_speed_handle;
2454 	mcs_inst->read_params.single.offset = 0U;
2455 
2456 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2457 	if (err != 0) {
2458 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2459 	}
2460 	return err;
2461 }
2462 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
2463 
2464 #if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
bt_mcc_set_playback_speed(struct bt_conn * conn,int8_t speed)2465 int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed)
2466 {
2467 	struct mcs_instance_t *mcs_inst;
2468 	int err;
2469 
2470 	CHECKIF(conn == NULL) {
2471 		LOG_DBG("conn is NULL");
2472 
2473 		return -EINVAL;
2474 	}
2475 
2476 	mcs_inst = lookup_inst_by_conn(conn);
2477 	if (mcs_inst == NULL) {
2478 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2479 
2480 		return -EINVAL;
2481 	} else if (mcs_inst->playback_speed_handle == 0) {
2482 		LOG_DBG("handle not set");
2483 
2484 		return -EINVAL;
2485 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2486 
2487 		LOG_DBG("mcs_inst busy");
2488 		return -EBUSY;
2489 	}
2490 
2491 	(void)memcpy(mcs_inst->write_buf, &speed, sizeof(speed));
2492 
2493 	mcs_inst->write_params.offset = 0;
2494 	mcs_inst->write_params.data = mcs_inst->write_buf;
2495 	mcs_inst->write_params.length = sizeof(speed);
2496 	mcs_inst->write_params.handle = mcs_inst->playback_speed_handle;
2497 	mcs_inst->write_params.func = mcs_write_playback_speed_cb;
2498 
2499 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(speed), "Playback speed");
2500 
2501 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2502 	if (err != 0) {
2503 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2504 	}
2505 	return err;
2506 }
2507 #endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */
2508 
2509 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
bt_mcc_read_seeking_speed(struct bt_conn * conn)2510 int bt_mcc_read_seeking_speed(struct bt_conn *conn)
2511 {
2512 	struct mcs_instance_t *mcs_inst;
2513 	int err;
2514 
2515 	CHECKIF(conn == NULL) {
2516 		LOG_DBG("conn is NULL");
2517 
2518 		return -EINVAL;
2519 	}
2520 
2521 	mcs_inst = lookup_inst_by_conn(conn);
2522 	if (mcs_inst == NULL) {
2523 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2524 
2525 		return -EINVAL;
2526 	} else if (mcs_inst->seeking_speed_handle == 0) {
2527 		LOG_DBG("handle not set");
2528 
2529 		return -EINVAL;
2530 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2531 
2532 		LOG_DBG("mcs_inst busy");
2533 		return -EBUSY;
2534 	}
2535 
2536 	mcs_inst->read_params.func = mcc_read_seeking_speed_cb;
2537 	mcs_inst->read_params.handle_count = 1;
2538 	mcs_inst->read_params.single.handle = mcs_inst->seeking_speed_handle;
2539 	mcs_inst->read_params.single.offset = 0U;
2540 
2541 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2542 	if (err != 0) {
2543 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2544 	}
2545 	return err;
2546 }
2547 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
2548 
2549 #ifdef CONFIG_BT_MCC_OTS
bt_mcc_read_segments_obj_id(struct bt_conn * conn)2550 int bt_mcc_read_segments_obj_id(struct bt_conn *conn)
2551 {
2552 	struct mcs_instance_t *mcs_inst;
2553 	int err;
2554 
2555 	CHECKIF(conn == NULL) {
2556 		LOG_DBG("conn is NULL");
2557 
2558 		return -EINVAL;
2559 	}
2560 
2561 	mcs_inst = lookup_inst_by_conn(conn);
2562 	if (mcs_inst == NULL) {
2563 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2564 
2565 		return -EINVAL;
2566 	} else if (mcs_inst->segments_obj_id_handle == 0) {
2567 		LOG_DBG("handle not set");
2568 
2569 		return -EINVAL;
2570 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2571 
2572 		LOG_DBG("mcs_inst busy");
2573 		return -EBUSY;
2574 	}
2575 
2576 	mcs_inst->read_params.func = mcc_read_segments_obj_id_cb;
2577 	mcs_inst->read_params.handle_count = 1;
2578 	mcs_inst->read_params.single.handle = mcs_inst->segments_obj_id_handle;
2579 	mcs_inst->read_params.single.offset = 0U;
2580 
2581 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2582 	if (err != 0) {
2583 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2584 	}
2585 	return err;
2586 }
2587 
bt_mcc_read_current_track_obj_id(struct bt_conn * conn)2588 int bt_mcc_read_current_track_obj_id(struct bt_conn *conn)
2589 {
2590 	struct mcs_instance_t *mcs_inst;
2591 	int err;
2592 
2593 	CHECKIF(conn == NULL) {
2594 		LOG_DBG("conn is NULL");
2595 
2596 		return -EINVAL;
2597 	}
2598 
2599 	mcs_inst = lookup_inst_by_conn(conn);
2600 	if (mcs_inst == NULL) {
2601 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2602 
2603 		return -EINVAL;
2604 	} else if (mcs_inst->current_track_obj_id_handle == 0) {
2605 		LOG_DBG("handle not set");
2606 
2607 		return -EINVAL;
2608 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2609 
2610 		LOG_DBG("mcs_inst busy");
2611 		return -EBUSY;
2612 	}
2613 
2614 	mcs_inst->read_params.func = mcc_read_current_track_obj_id_cb;
2615 	mcs_inst->read_params.handle_count = 1;
2616 	mcs_inst->read_params.single.handle = mcs_inst->current_track_obj_id_handle;
2617 	mcs_inst->read_params.single.offset = 0U;
2618 
2619 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2620 	if (err != 0) {
2621 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2622 	}
2623 	return err;
2624 }
2625 
bt_mcc_set_current_track_obj_id(struct bt_conn * conn,uint64_t obj_id)2626 int bt_mcc_set_current_track_obj_id(struct bt_conn *conn, uint64_t obj_id)
2627 {
2628 	struct mcs_instance_t *mcs_inst;
2629 	int err;
2630 
2631 	CHECKIF(conn == NULL) {
2632 		LOG_DBG("conn is NULL");
2633 
2634 		return -EINVAL;
2635 	}
2636 
2637 	CHECKIF(!BT_MCS_VALID_OBJ_ID(obj_id)) {
2638 		LOG_DBG("Object ID 0x%016llx invalid", obj_id);
2639 		return -EINVAL;
2640 	}
2641 
2642 	mcs_inst = lookup_inst_by_conn(conn);
2643 	if (mcs_inst == NULL) {
2644 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2645 
2646 		return -EINVAL;
2647 	} else if (mcs_inst->current_track_obj_id_handle == 0) {
2648 		LOG_DBG("handle not set");
2649 
2650 		return -EINVAL;
2651 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2652 
2653 		LOG_DBG("mcs_inst busy");
2654 		return -EBUSY;
2655 	}
2656 
2657 	sys_put_le48(obj_id, mcs_inst->write_buf);
2658 	mcs_inst->write_params.offset = 0;
2659 	mcs_inst->write_params.data = mcs_inst->write_buf;
2660 	mcs_inst->write_params.length = BT_OTS_OBJ_ID_SIZE;
2661 	mcs_inst->write_params.handle = mcs_inst->current_track_obj_id_handle;
2662 	mcs_inst->write_params.func = mcs_write_current_track_obj_id_cb;
2663 
2664 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, BT_OTS_OBJ_ID_SIZE, "Object Id");
2665 
2666 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2667 	if (err != 0) {
2668 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2669 	}
2670 	return err;
2671 }
2672 
bt_mcc_read_next_track_obj_id(struct bt_conn * conn)2673 int bt_mcc_read_next_track_obj_id(struct bt_conn *conn)
2674 {
2675 	struct mcs_instance_t *mcs_inst;
2676 	int err;
2677 
2678 	CHECKIF(conn == NULL) {
2679 		LOG_DBG("conn is NULL");
2680 
2681 		return -EINVAL;
2682 	}
2683 
2684 	mcs_inst = lookup_inst_by_conn(conn);
2685 	if (mcs_inst == NULL) {
2686 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2687 
2688 		return -EINVAL;
2689 	} else if (mcs_inst->next_track_obj_id_handle == 0) {
2690 		LOG_DBG("handle not set");
2691 
2692 		return -EINVAL;
2693 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2694 
2695 		LOG_DBG("mcs_inst busy");
2696 		return -EBUSY;
2697 	}
2698 
2699 	mcs_inst->read_params.func = mcc_read_next_track_obj_id_cb;
2700 	mcs_inst->read_params.handle_count = 1;
2701 	mcs_inst->read_params.single.handle = mcs_inst->next_track_obj_id_handle;
2702 	mcs_inst->read_params.single.offset = 0U;
2703 
2704 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2705 	if (err != 0) {
2706 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2707 	}
2708 	return err;
2709 }
2710 
bt_mcc_set_next_track_obj_id(struct bt_conn * conn,uint64_t obj_id)2711 int bt_mcc_set_next_track_obj_id(struct bt_conn *conn, uint64_t obj_id)
2712 {
2713 	struct mcs_instance_t *mcs_inst;
2714 	int err;
2715 
2716 	CHECKIF(conn == NULL) {
2717 		LOG_DBG("conn is NULL");
2718 
2719 		return -EINVAL;
2720 	}
2721 
2722 	CHECKIF(!BT_MCS_VALID_OBJ_ID(obj_id)) {
2723 		LOG_DBG("Object ID 0x%016llx invalid", obj_id);
2724 		return -EINVAL;
2725 	}
2726 
2727 	mcs_inst = lookup_inst_by_conn(conn);
2728 	if (mcs_inst == NULL) {
2729 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2730 
2731 		return -EINVAL;
2732 	} else if (mcs_inst->next_track_obj_id_handle == 0) {
2733 		LOG_DBG("handle not set");
2734 
2735 		return -EINVAL;
2736 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2737 
2738 		LOG_DBG("mcs_inst busy");
2739 		return -EBUSY;
2740 	}
2741 
2742 	sys_put_le48(obj_id, mcs_inst->write_buf);
2743 	mcs_inst->write_params.offset = 0;
2744 	mcs_inst->write_params.data = mcs_inst->write_buf;
2745 	mcs_inst->write_params.length = BT_OTS_OBJ_ID_SIZE;
2746 	mcs_inst->write_params.handle = mcs_inst->next_track_obj_id_handle;
2747 	mcs_inst->write_params.func = mcs_write_next_track_obj_id_cb;
2748 
2749 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, BT_OTS_OBJ_ID_SIZE, "Object Id");
2750 
2751 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2752 	if (err != 0) {
2753 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2754 	}
2755 	return err;
2756 }
2757 
bt_mcc_read_parent_group_obj_id(struct bt_conn * conn)2758 int bt_mcc_read_parent_group_obj_id(struct bt_conn *conn)
2759 {
2760 	struct mcs_instance_t *mcs_inst;
2761 	int err;
2762 
2763 	CHECKIF(conn == NULL) {
2764 		LOG_DBG("conn is NULL");
2765 
2766 		return -EINVAL;
2767 	}
2768 
2769 	mcs_inst = lookup_inst_by_conn(conn);
2770 	if (mcs_inst == NULL) {
2771 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2772 
2773 		return -EINVAL;
2774 	} else if (mcs_inst->parent_group_obj_id_handle == 0) {
2775 		LOG_DBG("handle not set");
2776 
2777 		return -EINVAL;
2778 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2779 
2780 		LOG_DBG("mcs_inst busy");
2781 		return -EBUSY;
2782 	}
2783 
2784 	mcs_inst->read_params.func = mcc_read_parent_group_obj_id_cb;
2785 	mcs_inst->read_params.handle_count = 1;
2786 	mcs_inst->read_params.single.handle = mcs_inst->parent_group_obj_id_handle;
2787 	mcs_inst->read_params.single.offset = 0U;
2788 
2789 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2790 	if (err != 0) {
2791 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2792 	}
2793 	return err;
2794 }
2795 
bt_mcc_read_current_group_obj_id(struct bt_conn * conn)2796 int bt_mcc_read_current_group_obj_id(struct bt_conn *conn)
2797 {
2798 	struct mcs_instance_t *mcs_inst;
2799 	int err;
2800 
2801 	CHECKIF(conn == NULL) {
2802 		LOG_DBG("conn is NULL");
2803 
2804 		return -EINVAL;
2805 	}
2806 
2807 	mcs_inst = lookup_inst_by_conn(conn);
2808 	if (mcs_inst == NULL) {
2809 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2810 
2811 		return -EINVAL;
2812 	} else if (mcs_inst->current_group_obj_id_handle == 0) {
2813 		LOG_DBG("handle not set");
2814 
2815 		return -EINVAL;
2816 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2817 
2818 		LOG_DBG("mcs_inst busy");
2819 		return -EBUSY;
2820 	}
2821 
2822 	mcs_inst->read_params.func = mcc_read_current_group_obj_id_cb;
2823 	mcs_inst->read_params.handle_count = 1;
2824 	mcs_inst->read_params.single.handle = mcs_inst->current_group_obj_id_handle;
2825 	mcs_inst->read_params.single.offset = 0U;
2826 
2827 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2828 	if (err != 0) {
2829 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2830 	}
2831 	return err;
2832 }
2833 
bt_mcc_set_current_group_obj_id(struct bt_conn * conn,uint64_t obj_id)2834 int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t obj_id)
2835 {
2836 	struct mcs_instance_t *mcs_inst;
2837 	int err;
2838 
2839 	CHECKIF(conn == NULL) {
2840 		LOG_DBG("conn is NULL");
2841 
2842 		return -EINVAL;
2843 	}
2844 
2845 	CHECKIF(!BT_MCS_VALID_OBJ_ID(obj_id)) {
2846 		LOG_DBG("Object ID 0x%016llx invalid", obj_id);
2847 		return -EINVAL;
2848 	}
2849 
2850 	mcs_inst = lookup_inst_by_conn(conn);
2851 	if (mcs_inst == NULL) {
2852 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2853 
2854 		return -EINVAL;
2855 	} else if (mcs_inst->current_group_obj_id_handle == 0) {
2856 		LOG_DBG("handle not set");
2857 
2858 		return -EINVAL;
2859 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2860 
2861 		LOG_DBG("mcs_inst busy");
2862 		return -EBUSY;
2863 	}
2864 
2865 	sys_put_le48(obj_id, mcs_inst->write_buf);
2866 	mcs_inst->write_params.offset = 0;
2867 	mcs_inst->write_params.data = mcs_inst->write_buf;
2868 	mcs_inst->write_params.length = BT_OTS_OBJ_ID_SIZE;
2869 	mcs_inst->write_params.handle = mcs_inst->current_group_obj_id_handle;
2870 	mcs_inst->write_params.func = mcs_write_current_group_obj_id_cb;
2871 
2872 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, BT_OTS_OBJ_ID_SIZE, "Object Id");
2873 
2874 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2875 	if (err != 0) {
2876 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2877 	}
2878 	return err;
2879 }
2880 #endif /* CONFIG_BT_MCC_OTS */
2881 
2882 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
bt_mcc_read_playing_order(struct bt_conn * conn)2883 int bt_mcc_read_playing_order(struct bt_conn *conn)
2884 {
2885 	struct mcs_instance_t *mcs_inst;
2886 	int err;
2887 
2888 	CHECKIF(conn == NULL) {
2889 		LOG_DBG("conn is NULL");
2890 
2891 		return -EINVAL;
2892 	}
2893 
2894 	mcs_inst = lookup_inst_by_conn(conn);
2895 	if (mcs_inst == NULL) {
2896 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2897 
2898 		return -EINVAL;
2899 	} else if (mcs_inst->playing_order_handle == 0) {
2900 		LOG_DBG("handle not set");
2901 
2902 		return -EINVAL;
2903 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2904 
2905 		LOG_DBG("mcs_inst busy");
2906 		return -EBUSY;
2907 	}
2908 
2909 	mcs_inst->read_params.func = mcc_read_playing_order_cb;
2910 	mcs_inst->read_params.handle_count = 1;
2911 	mcs_inst->read_params.single.handle = mcs_inst->playing_order_handle;
2912 	mcs_inst->read_params.single.offset = 0U;
2913 
2914 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2915 	if (err != 0) {
2916 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2917 	}
2918 	return err;
2919 }
2920 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
2921 
2922 #if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER)
bt_mcc_set_playing_order(struct bt_conn * conn,uint8_t order)2923 int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order)
2924 {
2925 	struct mcs_instance_t *mcs_inst;
2926 	int err;
2927 
2928 	CHECKIF(conn == NULL) {
2929 		LOG_DBG("conn is NULL");
2930 
2931 		return -EINVAL;
2932 	}
2933 
2934 	CHECKIF(!IN_RANGE(order, BT_MCS_PLAYING_ORDER_SINGLE_ONCE,
2935 			  BT_MCS_PLAYING_ORDER_SHUFFLE_REPEAT)) {
2936 		LOG_DBG("Invalid playing order 0x%02X", order);
2937 
2938 		return -EINVAL;
2939 	}
2940 
2941 	mcs_inst = lookup_inst_by_conn(conn);
2942 	if (mcs_inst == NULL) {
2943 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2944 
2945 		return -EINVAL;
2946 	} else if (mcs_inst->playing_order_handle == 0) {
2947 		LOG_DBG("handle not set");
2948 
2949 		return -EINVAL;
2950 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2951 
2952 		LOG_DBG("mcs_inst busy");
2953 		return -EBUSY;
2954 	}
2955 
2956 	(void)memcpy(mcs_inst->write_buf, &order, sizeof(order));
2957 
2958 	mcs_inst->write_params.offset = 0;
2959 	mcs_inst->write_params.data = mcs_inst->write_buf;
2960 	mcs_inst->write_params.length = sizeof(order);
2961 	mcs_inst->write_params.handle = mcs_inst->playing_order_handle;
2962 	mcs_inst->write_params.func = mcs_write_playing_order_cb;
2963 
2964 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(order), "Playing order");
2965 
2966 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2967 	if (err != 0) {
2968 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
2969 	}
2970 	return err;
2971 }
2972 #endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */
2973 
2974 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED)
bt_mcc_read_playing_orders_supported(struct bt_conn * conn)2975 int bt_mcc_read_playing_orders_supported(struct bt_conn *conn)
2976 {
2977 	struct mcs_instance_t *mcs_inst;
2978 	int err;
2979 
2980 	CHECKIF(conn == NULL) {
2981 		LOG_DBG("conn is NULL");
2982 
2983 		return -EINVAL;
2984 	}
2985 
2986 	mcs_inst = lookup_inst_by_conn(conn);
2987 	if (mcs_inst == NULL) {
2988 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2989 
2990 		return -EINVAL;
2991 	} else if (mcs_inst->playing_orders_supported_handle == 0) {
2992 		LOG_DBG("handle not set");
2993 
2994 		return -EINVAL;
2995 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
2996 
2997 		LOG_DBG("mcs_inst busy");
2998 		return -EBUSY;
2999 	}
3000 
3001 	mcs_inst->read_params.func = mcc_read_playing_orders_supported_cb;
3002 	mcs_inst->read_params.handle_count = 1;
3003 	mcs_inst->read_params.single.handle = mcs_inst->playing_orders_supported_handle;
3004 	mcs_inst->read_params.single.offset = 0U;
3005 
3006 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3007 	if (err != 0) {
3008 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3009 	}
3010 	return err;
3011 }
3012 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */
3013 
3014 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
bt_mcc_read_media_state(struct bt_conn * conn)3015 int bt_mcc_read_media_state(struct bt_conn *conn)
3016 {
3017 	struct mcs_instance_t *mcs_inst;
3018 	int err;
3019 
3020 	CHECKIF(conn == NULL) {
3021 		LOG_DBG("conn is NULL");
3022 
3023 		return -EINVAL;
3024 	}
3025 
3026 	mcs_inst = lookup_inst_by_conn(conn);
3027 	if (mcs_inst == NULL) {
3028 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3029 
3030 		return -EINVAL;
3031 	} else if (mcs_inst->media_state_handle == 0) {
3032 		LOG_DBG("handle not set");
3033 
3034 		return -EINVAL;
3035 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3036 
3037 		LOG_DBG("mcs_inst busy");
3038 		return -EBUSY;
3039 	}
3040 
3041 	mcs_inst->read_params.func = mcc_read_media_state_cb;
3042 	mcs_inst->read_params.handle_count = 1;
3043 	mcs_inst->read_params.single.handle = mcs_inst->media_state_handle;
3044 	mcs_inst->read_params.single.offset = 0U;
3045 
3046 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3047 	if (err != 0) {
3048 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3049 	}
3050 	return err;
3051 }
3052 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
3053 
3054 #if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT)
bt_mcc_send_cmd(struct bt_conn * conn,const struct mpl_cmd * cmd)3055 int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd)
3056 {
3057 	struct mcs_instance_t *mcs_inst;
3058 	size_t length;
3059 	int err;
3060 
3061 	CHECKIF(conn == NULL) {
3062 		LOG_DBG("conn is NULL");
3063 
3064 		return -EINVAL;
3065 	}
3066 
3067 	CHECKIF(cmd == NULL) {
3068 		LOG_DBG("cmd is NULL");
3069 
3070 		return -EINVAL;
3071 	}
3072 
3073 	CHECKIF(!BT_MCS_VALID_OP(cmd->opcode)) {
3074 		LOG_DBG("Opcode 0x%02X is invalid", cmd->opcode);
3075 
3076 		return -EINVAL;
3077 	}
3078 
3079 	mcs_inst = lookup_inst_by_conn(conn);
3080 	if (mcs_inst == NULL) {
3081 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3082 
3083 		return -EINVAL;
3084 	} else if (mcs_inst->cp_handle == 0) {
3085 		LOG_DBG("handle not set");
3086 
3087 		return -EINVAL;
3088 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3089 
3090 		LOG_DBG("mcs_inst busy");
3091 		return -EBUSY;
3092 	}
3093 
3094 	length = sizeof(cmd->opcode);
3095 	(void)memcpy(mcs_inst->write_buf, &cmd->opcode, length);
3096 	if (cmd->use_param) {
3097 		length += sizeof(cmd->param);
3098 		(void)memcpy(&mcs_inst->write_buf[sizeof(cmd->opcode)], &cmd->param,
3099 		       sizeof(cmd->param));
3100 	}
3101 
3102 	mcs_inst->write_params.offset = 0;
3103 	mcs_inst->write_params.data = mcs_inst->write_buf;
3104 	mcs_inst->write_params.length = length;
3105 	mcs_inst->write_params.handle = mcs_inst->cp_handle;
3106 	mcs_inst->write_params.func = mcs_write_cp_cb;
3107 
3108 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(*cmd), "Command sent");
3109 
3110 	err = bt_gatt_write(conn, &mcs_inst->write_params);
3111 	if (err != 0) {
3112 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3113 	}
3114 	return err;
3115 }
3116 #endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */
3117 
3118 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
bt_mcc_read_opcodes_supported(struct bt_conn * conn)3119 int bt_mcc_read_opcodes_supported(struct bt_conn *conn)
3120 {
3121 	struct mcs_instance_t *mcs_inst;
3122 	int err;
3123 
3124 	CHECKIF(conn == NULL) {
3125 		LOG_DBG("conn is NULL");
3126 
3127 		return -EINVAL;
3128 	}
3129 
3130 	mcs_inst = lookup_inst_by_conn(conn);
3131 	if (mcs_inst == NULL) {
3132 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3133 
3134 		return -EINVAL;
3135 	} else if (mcs_inst->opcodes_supported_handle == 0) {
3136 		LOG_DBG("handle not set");
3137 
3138 		return -EINVAL;
3139 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3140 
3141 		LOG_DBG("mcs_inst busy");
3142 		return -EBUSY;
3143 	}
3144 
3145 	mcs_inst->read_params.func = mcc_read_opcodes_supported_cb;
3146 	mcs_inst->read_params.handle_count = 1;
3147 	mcs_inst->read_params.single.handle = mcs_inst->opcodes_supported_handle;
3148 	mcs_inst->read_params.single.offset = 0U;
3149 
3150 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3151 	if (err != 0) {
3152 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3153 	}
3154 	return err;
3155 }
3156 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
3157 
3158 #ifdef CONFIG_BT_MCC_OTS
bt_mcc_send_search(struct bt_conn * conn,const struct mpl_search * search)3159 int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search)
3160 {
3161 	struct mcs_instance_t *mcs_inst;
3162 	int err;
3163 
3164 	CHECKIF(conn == NULL) {
3165 		LOG_DBG("conn is NULL");
3166 
3167 		return -EINVAL;
3168 	}
3169 
3170 	CHECKIF(search == NULL) {
3171 		LOG_DBG("search is NULL");
3172 
3173 		return -EINVAL;
3174 	}
3175 
3176 	CHECKIF(!IN_RANGE(search->len, SEARCH_LEN_MIN, SEARCH_LEN_MAX)) {
3177 		LOG_DBG("Invalid search->len: %u", search->len);
3178 
3179 		return -EINVAL;
3180 	}
3181 
3182 	mcs_inst = lookup_inst_by_conn(conn);
3183 	if (mcs_inst == NULL) {
3184 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3185 
3186 		return -EINVAL;
3187 	} else if (mcs_inst->scp_handle == 0) {
3188 		LOG_DBG("handle not set");
3189 
3190 		return -EINVAL;
3191 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3192 
3193 		LOG_DBG("mcs_inst busy");
3194 		return -EBUSY;
3195 	}
3196 
3197 	(void)memcpy(mcs_inst->write_buf, &search->search, search->len);
3198 
3199 	mcs_inst->write_params.offset = 0;
3200 	mcs_inst->write_params.data = mcs_inst->write_buf;
3201 	mcs_inst->write_params.length = search->len;
3202 	mcs_inst->write_params.handle = mcs_inst->scp_handle;
3203 	mcs_inst->write_params.func = mcs_write_scp_cb;
3204 
3205 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, search->len, "Search sent");
3206 
3207 	err = bt_gatt_write(conn, &mcs_inst->write_params);
3208 	if (err != 0) {
3209 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3210 	}
3211 	return err;
3212 }
3213 
bt_mcc_read_search_results_obj_id(struct bt_conn * conn)3214 int bt_mcc_read_search_results_obj_id(struct bt_conn *conn)
3215 {
3216 	struct mcs_instance_t *mcs_inst;
3217 	int err;
3218 
3219 	CHECKIF(conn == NULL) {
3220 		LOG_DBG("conn is NULL");
3221 
3222 		return -EINVAL;
3223 	}
3224 
3225 	mcs_inst = lookup_inst_by_conn(conn);
3226 	if (mcs_inst == NULL) {
3227 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3228 
3229 		return -EINVAL;
3230 	} else if (mcs_inst->search_results_obj_id_handle == 0) {
3231 		LOG_DBG("handle not set");
3232 
3233 		return -EINVAL;
3234 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3235 
3236 		LOG_DBG("mcs_inst busy");
3237 		return -EBUSY;
3238 	}
3239 
3240 	mcs_inst->read_params.func = mcc_read_search_results_obj_id_cb;
3241 	mcs_inst->read_params.handle_count = 1;
3242 	mcs_inst->read_params.single.handle = mcs_inst->search_results_obj_id_handle;
3243 	mcs_inst->read_params.single.offset = 0U;
3244 
3245 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3246 	if (err != 0) {
3247 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3248 	}
3249 	return err;
3250 }
3251 #endif /* CONFIG_BT_MCC_OTS */
3252 
3253 #if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID)
bt_mcc_read_content_control_id(struct bt_conn * conn)3254 int bt_mcc_read_content_control_id(struct bt_conn *conn)
3255 {
3256 	struct mcs_instance_t *mcs_inst;
3257 	int err;
3258 
3259 	CHECKIF(conn == NULL) {
3260 		LOG_DBG("conn is NULL");
3261 
3262 		return -EINVAL;
3263 	}
3264 
3265 	mcs_inst = lookup_inst_by_conn(conn);
3266 	if (mcs_inst == NULL) {
3267 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3268 
3269 		return -EINVAL;
3270 	} else if (mcs_inst->content_control_id_handle == 0) {
3271 		LOG_DBG("handle not set");
3272 
3273 		return -EINVAL;
3274 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3275 
3276 		LOG_DBG("mcs_inst busy");
3277 		return -EBUSY;
3278 	}
3279 
3280 	mcs_inst->read_params.func = mcc_read_content_control_id_cb;
3281 	mcs_inst->read_params.handle_count = 1;
3282 	mcs_inst->read_params.single.handle = mcs_inst->content_control_id_handle;
3283 	mcs_inst->read_params.single.offset = 0U;
3284 
3285 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3286 	if (err != 0) {
3287 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3288 	}
3289 	return err;
3290 }
3291 #endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */
3292 
3293 #ifdef CONFIG_BT_MCC_OTS
3294 
on_obj_selected(struct bt_ots_client * otc_inst,struct bt_conn * conn,int result)3295 void on_obj_selected(struct bt_ots_client *otc_inst,
3296 		     struct bt_conn *conn, int result)
3297 {
3298 	struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3299 
3300 	LOG_DBG("Current object selected");
3301 
3302 	if (mcs_inst != NULL) {
3303 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3304 	}
3305 
3306 	/* TODO: Read metadata here? */
3307 	/* For now: Left to the application */
3308 
3309 	/* Only one object at a time is selected in OTS */
3310 	/* When the selected callback comes, a new object is selected */
3311 	/* Reset the object buffer */
3312 	net_buf_simple_reset(&otc_obj_buf);
3313 
3314 	if (mcc_cb && mcc_cb->otc_obj_selected) {
3315 		mcc_cb->otc_obj_selected(conn, OLCP_RESULT_TO_ERROR(result));
3316 	}
3317 }
3318 
3319 /* TODO: Merge the object callback functions into one */
3320 /* Use a notion of the "active" object, as done in mpl.c, for tracking  */
on_icon_content(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)3321 int on_icon_content(struct bt_ots_client *otc_inst, struct bt_conn *conn,
3322 		    uint32_t offset, uint32_t len, uint8_t *data_p,
3323 		    bool is_complete)
3324 {
3325 	int cb_err = 0;
3326 
3327 	LOG_DBG("Received Media Player Icon content, %i bytes at offset %i",
3328 		len, offset);
3329 
3330 	LOG_HEXDUMP_DBG(data_p, len, "Icon content");
3331 
3332 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3333 		LOG_WRN("Can not fit whole object");
3334 		cb_err = -EMSGSIZE;
3335 	}
3336 
3337 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3338 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3339 
3340 	if (is_complete) {
3341 		struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3342 
3343 		LOG_DBG("Icon object received");
3344 
3345 		if (mcs_inst != NULL) {
3346 			atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3347 		}
3348 
3349 		if (mcc_cb && mcc_cb->otc_icon_object) {
3350 			mcc_cb->otc_icon_object(conn, cb_err, &otc_obj_buf);
3351 		}
3352 		/* Reset buf in case the same object is read again without */
3353 		/* calling select in between */
3354 		net_buf_simple_reset(&otc_obj_buf);
3355 	}
3356 
3357 	return BT_OTS_CONTINUE;
3358 }
3359 
3360 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3361 struct track_seg_t {
3362 	uint8_t            name_len;
3363 	char               name[CONFIG_BT_MCC_SEGMENT_NAME_MAX];
3364 	int32_t            pos;
3365 };
3366 
3367 struct track_segs_t {
3368 	uint16_t              cnt;
3369 	struct track_seg_t    segs[CONFIG_BT_MCC_TRACK_SEGS_MAX_CNT];
3370 };
3371 
decode_track_segments(struct net_buf_simple * buff,struct track_segs_t * track_segs)3372 static void decode_track_segments(struct net_buf_simple *buff,
3373 				  struct track_segs_t *track_segs)
3374 {
3375 	uint16_t i;
3376 	struct track_seg_t *seg;
3377 	uint8_t *name;
3378 	struct net_buf_simple tmp_buf;
3379 
3380 	/* Copy the buf, to not consume the original in this debug function */
3381 	net_buf_simple_clone(buff, &tmp_buf);
3382 
3383 	while (tmp_buf.len &&
3384 	       track_segs->cnt < CONFIG_BT_MCC_TRACK_SEGS_MAX_CNT) {
3385 
3386 		i = track_segs->cnt++;
3387 		seg = &track_segs->segs[i];
3388 
3389 		seg->name_len =  net_buf_simple_pull_u8(&tmp_buf);
3390 		if (seg->name_len + sizeof(int32_t) > tmp_buf.len) {
3391 			LOG_WRN("Segment too long");
3392 			return;
3393 		}
3394 
3395 		if (seg->name_len) {
3396 
3397 			name = net_buf_simple_pull_mem(&tmp_buf, seg->name_len);
3398 
3399 			if (seg->name_len >= CONFIG_BT_MCC_SEGMENT_NAME_MAX) {
3400 				seg->name_len =
3401 					CONFIG_BT_MCC_SEGMENT_NAME_MAX - 1;
3402 			}
3403 			(void)memcpy(seg->name, name, seg->name_len);
3404 		}
3405 		seg->name[seg->name_len] = '\0';
3406 
3407 		track_segs->segs[i].pos = (int32_t)net_buf_simple_pull_le32(&tmp_buf);
3408 	}
3409 }
3410 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3411 
on_track_segments_content(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)3412 int on_track_segments_content(struct bt_ots_client *otc_inst,
3413 			      struct bt_conn *conn, uint32_t offset,
3414 			      uint32_t len, uint8_t *data_p, bool is_complete)
3415 {
3416 	int cb_err = 0;
3417 
3418 	LOG_DBG("Received Track Segments content, %i bytes at offset %i",
3419 		len, offset);
3420 
3421 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3422 		LOG_WRN("Can not fit whole object");
3423 		cb_err = -EMSGSIZE;
3424 	}
3425 
3426 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3427 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3428 
3429 	if (is_complete) {
3430 		struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3431 
3432 		LOG_DBG("Track segment object received");
3433 
3434 		if (mcs_inst != NULL) {
3435 			atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3436 		}
3437 
3438 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3439 		struct track_segs_t track_segments;
3440 
3441 		track_segments.cnt = 0;
3442 		decode_track_segments(&otc_obj_buf, &track_segments);
3443 		for (int i = 0; i < track_segments.cnt; i++) {
3444 			LOG_DBG("Track segment %i:", i);
3445 			LOG_DBG("\t-Name\t:%s",
3446 			       track_segments.segs[i].name);
3447 			LOG_DBG("\t-Position\t:%d", track_segments.segs[i].pos);
3448 		}
3449 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3450 
3451 		if (mcc_cb && mcc_cb->otc_track_segments_object) {
3452 			mcc_cb->otc_track_segments_object(conn,
3453 							   cb_err, &otc_obj_buf);
3454 		}
3455 
3456 		net_buf_simple_reset(&otc_obj_buf);
3457 	}
3458 
3459 	return BT_OTS_CONTINUE;
3460 }
3461 
on_current_track_content(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)3462 int on_current_track_content(struct bt_ots_client *otc_inst,
3463 			     struct bt_conn *conn, uint32_t offset,
3464 			     uint32_t len, uint8_t *data_p, bool is_complete)
3465 {
3466 	int cb_err = 0;
3467 
3468 	LOG_DBG("Received Current Track content, %i bytes at offset %i",
3469 	       len, offset);
3470 
3471 	LOG_HEXDUMP_DBG(data_p, len, "Track content");
3472 
3473 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3474 		LOG_WRN("Can not fit whole object");
3475 		cb_err = -EMSGSIZE;
3476 	}
3477 
3478 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3479 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3480 
3481 	if (is_complete) {
3482 		struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3483 
3484 		LOG_DBG("Current Track Object received");
3485 
3486 		if (mcs_inst != NULL) {
3487 			atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3488 		}
3489 
3490 		if (mcc_cb && mcc_cb->otc_current_track_object) {
3491 			mcc_cb->otc_current_track_object(conn, cb_err, &otc_obj_buf);
3492 		}
3493 
3494 		net_buf_simple_reset(&otc_obj_buf);
3495 	}
3496 
3497 	return BT_OTS_CONTINUE;
3498 }
3499 
on_next_track_content(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)3500 int on_next_track_content(struct bt_ots_client *otc_inst,
3501 			  struct bt_conn *conn, uint32_t offset, uint32_t len,
3502 			  uint8_t *data_p, bool is_complete)
3503 {
3504 	int cb_err = 0;
3505 
3506 	LOG_DBG("Received Next Track content, %i bytes at offset %i",
3507 	       len, offset);
3508 
3509 	LOG_HEXDUMP_DBG(data_p, len, "Track content");
3510 
3511 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3512 		LOG_WRN("Can not fit whole object");
3513 		cb_err = -EMSGSIZE;
3514 	}
3515 
3516 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3517 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3518 
3519 	if (is_complete) {
3520 		struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3521 
3522 		LOG_DBG("Next Track Object received");
3523 
3524 		if (mcs_inst != NULL) {
3525 			atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3526 		}
3527 
3528 		if (mcc_cb && mcc_cb->otc_next_track_object) {
3529 			mcc_cb->otc_next_track_object(conn, cb_err, &otc_obj_buf);
3530 		}
3531 
3532 		net_buf_simple_reset(&otc_obj_buf);
3533 	}
3534 
3535 	return BT_OTS_CONTINUE;
3536 }
3537 
3538 
3539 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3540 struct id_list_elem_t {
3541 	uint8_t  type;
3542 	uint64_t id;
3543 };
3544 
3545 struct id_list_t {
3546 	struct id_list_elem_t ids[CONFIG_BT_MCC_GROUP_RECORDS_MAX];
3547 	uint16_t cnt;
3548 };
3549 
decode_group(struct net_buf_simple * buff,struct id_list_t * ids)3550 static void decode_group(struct net_buf_simple *buff,
3551 			 struct id_list_t *ids)
3552 {
3553 	struct net_buf_simple tmp_buf;
3554 
3555 	/* Copy the buf, to not consume the original in this debug function */
3556 	net_buf_simple_clone(buff, &tmp_buf);
3557 
3558 	while ((tmp_buf.len) && (ids->cnt < CONFIG_BT_MCC_GROUP_RECORDS_MAX)) {
3559 		ids->ids[ids->cnt].type = net_buf_simple_pull_u8(&tmp_buf);
3560 		ids->ids[ids->cnt++].id = net_buf_simple_pull_le48(&tmp_buf);
3561 	}
3562 }
3563 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3564 
on_parent_group_content(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)3565 int on_parent_group_content(struct bt_ots_client *otc_inst,
3566 			    struct bt_conn *conn, uint32_t offset,
3567 			    uint32_t len, uint8_t *data_p, bool is_complete)
3568 {
3569 	int cb_err = 0;
3570 
3571 	LOG_DBG("Received Parent Group content, %i bytes at offset %i",
3572 		len, offset);
3573 
3574 	LOG_HEXDUMP_DBG(data_p, len, "Group content");
3575 
3576 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3577 		LOG_WRN("Can not fit whole object");
3578 		cb_err = -EMSGSIZE;
3579 	}
3580 
3581 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3582 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3583 
3584 	if (is_complete) {
3585 		struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3586 
3587 		LOG_DBG("Parent Group object received");
3588 
3589 		if (mcs_inst != NULL) {
3590 			atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3591 		}
3592 
3593 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3594 		struct id_list_t group = {0};
3595 
3596 		decode_group(&otc_obj_buf, &group);
3597 		for (int i = 0; i < group.cnt; i++) {
3598 			char t[BT_OTS_OBJ_ID_STR_LEN];
3599 
3600 			(void)bt_ots_obj_id_to_str(group.ids[i].id, t,
3601 						   BT_OTS_OBJ_ID_STR_LEN);
3602 			LOG_DBG("Object type: %d, object  ID: %s",
3603 			       group.ids[i].type, t);
3604 		}
3605 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3606 
3607 		if (mcc_cb && mcc_cb->otc_parent_group_object) {
3608 			mcc_cb->otc_parent_group_object(conn, cb_err, &otc_obj_buf);
3609 		}
3610 
3611 		net_buf_simple_reset(&otc_obj_buf);
3612 	}
3613 
3614 	return BT_OTS_CONTINUE;
3615 }
3616 
on_current_group_content(struct bt_ots_client * otc_inst,struct bt_conn * conn,uint32_t offset,uint32_t len,uint8_t * data_p,bool is_complete)3617 int on_current_group_content(struct bt_ots_client *otc_inst,
3618 			     struct bt_conn *conn, uint32_t offset,
3619 			     uint32_t len, uint8_t *data_p, bool is_complete)
3620 {
3621 	int cb_err = 0;
3622 
3623 	LOG_DBG("Received Current Group content, %i bytes at offset %i",
3624 		len, offset);
3625 
3626 	LOG_HEXDUMP_DBG(data_p, len, "Group content");
3627 
3628 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3629 		LOG_WRN("Can not fit whole object");
3630 		cb_err = -EMSGSIZE;
3631 	}
3632 
3633 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3634 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3635 
3636 	if (is_complete) {
3637 		struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3638 
3639 		LOG_DBG("Current Group object received");
3640 
3641 		if (mcs_inst != NULL) {
3642 			atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3643 		}
3644 
3645 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3646 		struct id_list_t group = {0};
3647 
3648 		decode_group(&otc_obj_buf, &group);
3649 		for (int i = 0; i < group.cnt; i++) {
3650 			char t[BT_OTS_OBJ_ID_STR_LEN];
3651 
3652 			(void)bt_ots_obj_id_to_str(group.ids[i].id, t,
3653 						   BT_OTS_OBJ_ID_STR_LEN);
3654 			LOG_DBG("Object type: %d, object  ID: %s",
3655 			       group.ids[i].type, t);
3656 		}
3657 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3658 
3659 		if (mcc_cb && mcc_cb->otc_current_group_object) {
3660 			mcc_cb->otc_current_group_object(conn, cb_err, &otc_obj_buf);
3661 		}
3662 
3663 		net_buf_simple_reset(&otc_obj_buf);
3664 	}
3665 
3666 	return BT_OTS_CONTINUE;
3667 }
3668 
on_object_metadata(struct bt_ots_client * otc_inst,struct bt_conn * conn,int err,uint8_t metadata_read)3669 void on_object_metadata(struct bt_ots_client *otc_inst,
3670 			struct bt_conn *conn, int err,
3671 			uint8_t metadata_read)
3672 {
3673 	struct mcs_instance_t *mcs_inst = lookup_inst_by_conn(conn);
3674 
3675 	LOG_INF("Object's meta data:");
3676 	LOG_INF("\tCurrent size\t:%u", otc_inst->cur_object.size.cur);
3677 
3678 	if (otc_inst->cur_object.size.cur > otc_obj_buf.size) {
3679 		LOG_DBG("Object larger than allocated buffer");
3680 	}
3681 
3682 	if (mcs_inst != NULL) {
3683 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3684 	}
3685 
3686 	bt_ots_metadata_display(&otc_inst->cur_object, 1);
3687 
3688 	if (mcc_cb && mcc_cb->otc_obj_metadata) {
3689 		mcc_cb->otc_obj_metadata(conn, err);
3690 	}
3691 }
3692 
bt_mcc_otc_read_object_metadata(struct bt_conn * conn)3693 int bt_mcc_otc_read_object_metadata(struct bt_conn *conn)
3694 {
3695 	struct mcs_instance_t *mcs_inst;
3696 	int err;
3697 
3698 	CHECKIF(conn == NULL) {
3699 		LOG_DBG("conn is NULL");
3700 
3701 		return -EINVAL;
3702 	}
3703 
3704 	mcs_inst = lookup_inst_by_conn(conn);
3705 	if (mcs_inst == NULL) {
3706 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3707 
3708 		return -EINVAL;
3709 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3710 
3711 		LOG_DBG("mcs_inst busy");
3712 		return -EBUSY;
3713 	}
3714 
3715 	err = bt_ots_client_read_object_metadata(&mcs_inst->otc, conn,
3716 						 BT_OTS_METADATA_REQ_ALL);
3717 	if (err) {
3718 		LOG_DBG("Error reading the object: %d", err);
3719 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3720 	}
3721 
3722 	return err;
3723 }
3724 
3725 
bt_mcc_otc_read_icon_object(struct bt_conn * conn)3726 int bt_mcc_otc_read_icon_object(struct bt_conn *conn)
3727 {
3728 	struct mcs_instance_t *mcs_inst;
3729 	int err;
3730 
3731 	CHECKIF(conn == NULL) {
3732 		LOG_DBG("conn is NULL");
3733 
3734 		return -EINVAL;
3735 	}
3736 
3737 	mcs_inst = lookup_inst_by_conn(conn);
3738 	if (mcs_inst == NULL) {
3739 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3740 
3741 		return -EINVAL;
3742 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3743 
3744 		LOG_DBG("mcs_inst busy");
3745 		return -EBUSY;
3746 	}
3747 
3748 	mcs_inst->otc.cb->obj_data_read = on_icon_content;
3749 
3750 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3751 	if (err) {
3752 		LOG_DBG("Error reading the object: %d", err);
3753 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3754 	}
3755 
3756 	return err;
3757 }
3758 
bt_mcc_otc_read_track_segments_object(struct bt_conn * conn)3759 int bt_mcc_otc_read_track_segments_object(struct bt_conn *conn)
3760 {
3761 	struct mcs_instance_t *mcs_inst;
3762 	int err;
3763 
3764 	CHECKIF(conn == NULL) {
3765 		LOG_DBG("conn is NULL");
3766 
3767 		return -EINVAL;
3768 	}
3769 
3770 	mcs_inst = lookup_inst_by_conn(conn);
3771 	if (mcs_inst == NULL) {
3772 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3773 
3774 		return -EINVAL;
3775 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3776 
3777 		LOG_DBG("mcs_inst busy");
3778 		return -EBUSY;
3779 	}
3780 
3781 	/* TODO: Assumes object is already selected */
3782 	mcs_inst->otc.cb->obj_data_read = on_track_segments_content;
3783 
3784 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3785 	if (err) {
3786 		LOG_DBG("Error reading the object: %d", err);
3787 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3788 	}
3789 
3790 	return err;
3791 }
3792 
bt_mcc_otc_read_current_track_object(struct bt_conn * conn)3793 int bt_mcc_otc_read_current_track_object(struct bt_conn *conn)
3794 {
3795 	struct mcs_instance_t *mcs_inst;
3796 	int err;
3797 
3798 	CHECKIF(conn == NULL) {
3799 		LOG_DBG("conn is NULL");
3800 
3801 		return -EINVAL;
3802 	}
3803 
3804 	mcs_inst = lookup_inst_by_conn(conn);
3805 	if (mcs_inst == NULL) {
3806 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3807 
3808 		return -EINVAL;
3809 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3810 
3811 		LOG_DBG("mcs_inst busy");
3812 		return -EBUSY;
3813 	}
3814 
3815 	/* TODO: Assumes object is already selected */
3816 	mcs_inst->otc.cb->obj_data_read = on_current_track_content;
3817 
3818 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3819 	if (err) {
3820 		LOG_DBG("Error reading the object: %d", err);
3821 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3822 	}
3823 
3824 	return err;
3825 }
3826 
bt_mcc_otc_read_next_track_object(struct bt_conn * conn)3827 int bt_mcc_otc_read_next_track_object(struct bt_conn *conn)
3828 {
3829 	struct mcs_instance_t *mcs_inst;
3830 	int err;
3831 
3832 	CHECKIF(conn == NULL) {
3833 		LOG_DBG("conn is NULL");
3834 
3835 		return -EINVAL;
3836 	}
3837 
3838 	mcs_inst = lookup_inst_by_conn(conn);
3839 	if (mcs_inst == NULL) {
3840 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3841 
3842 		return -EINVAL;
3843 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3844 
3845 		LOG_DBG("mcs_inst busy");
3846 		return -EBUSY;
3847 	}
3848 
3849 	/* TODO: Assumes object is already selected */
3850 	mcs_inst->otc.cb->obj_data_read = on_next_track_content;
3851 
3852 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3853 	if (err) {
3854 		LOG_DBG("Error reading the object: %d", err);
3855 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3856 	}
3857 
3858 	return err;
3859 }
3860 
bt_mcc_otc_read_parent_group_object(struct bt_conn * conn)3861 int bt_mcc_otc_read_parent_group_object(struct bt_conn *conn)
3862 {
3863 	struct mcs_instance_t *mcs_inst;
3864 	int err;
3865 
3866 	CHECKIF(conn == NULL) {
3867 		LOG_DBG("conn is NULL");
3868 
3869 		return -EINVAL;
3870 	}
3871 
3872 	mcs_inst = lookup_inst_by_conn(conn);
3873 	if (mcs_inst == NULL) {
3874 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3875 
3876 		return -EINVAL;
3877 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3878 
3879 		LOG_DBG("mcs_inst busy");
3880 		return -EBUSY;
3881 	}
3882 
3883 	/* TODO: Assumes object is already selected */
3884 
3885 	/* Reuse callback for current group */
3886 	mcs_inst->otc.cb->obj_data_read = on_parent_group_content;
3887 
3888 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3889 	if (err) {
3890 		LOG_DBG("Error reading the object: %d", err);
3891 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3892 	}
3893 
3894 	return err;
3895 }
3896 
bt_mcc_otc_read_current_group_object(struct bt_conn * conn)3897 int bt_mcc_otc_read_current_group_object(struct bt_conn *conn)
3898 {
3899 	struct mcs_instance_t *mcs_inst;
3900 	int err;
3901 
3902 	CHECKIF(conn == NULL) {
3903 		LOG_DBG("conn is NULL");
3904 
3905 		return -EINVAL;
3906 	}
3907 
3908 	mcs_inst = lookup_inst_by_conn(conn);
3909 	if (mcs_inst == NULL) {
3910 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3911 
3912 		return -EINVAL;
3913 	} else if (atomic_test_and_set_bit(mcs_inst->flags, MCC_FLAG_BUSY)) {
3914 
3915 		LOG_DBG("mcs_inst busy");
3916 		return -EBUSY;
3917 	}
3918 
3919 	/* TODO: Assumes object is already selected */
3920 	mcs_inst->otc.cb->obj_data_read = on_current_group_content;
3921 
3922 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3923 	if (err) {
3924 		LOG_DBG("Error reading the object: %d", err);
3925 		atomic_clear_bit(mcs_inst->flags, MCC_FLAG_BUSY);
3926 	}
3927 
3928 	return err;
3929 }
3930 
3931 #if defined(CONFIG_BT_MCC_SHELL)
bt_mcc_otc_inst(struct bt_conn * conn)3932 struct bt_ots_client *bt_mcc_otc_inst(struct bt_conn *conn)
3933 {
3934 	struct mcs_instance_t *mcs_inst;
3935 
3936 	mcs_inst = lookup_inst_by_conn(conn);
3937 	if (mcs_inst == NULL) {
3938 		return NULL;
3939 	}
3940 
3941 	return &mcs_inst->otc;
3942 }
3943 #endif /* defined(CONFIG_BT_MCC_SHELL) */
3944 
3945 #endif /* CONFIG_BT_MCC_OTS */
3946