1 /** @file
2  *  @brief Bluetooth Media Control Client/Protocol implementation
3  */
4 
5 /*
6  * Copyright (c) 2019 - 2021 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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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 	mcs_inst->busy = false;
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, busy));
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 		mcs_inst->busy = false;
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 			/* With ccc_handle == 0 it will use auto discovery */
1443 			sub_params->ccc_handle = 0;
1444 			sub_params->end_handle = mcs_inst->otc.end_handle;
1445 			sub_params->value = BT_GATT_CCC_INDICATE;
1446 			sub_params->value_handle = chrc->value_handle;
1447 			sub_params->notify = bt_ots_client_indicate_handler;
1448 			atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
1449 
1450 			err = bt_gatt_subscribe(conn, sub_params);
1451 			if (err != 0) {
1452 				LOG_DBG("Failed to subscribe (err %d)", err);
1453 				discovery_complete(conn, err);
1454 
1455 				return BT_GATT_ITER_STOP;
1456 			}
1457 		}
1458 
1459 		return BT_GATT_ITER_CONTINUE;
1460 	}
1461 
1462 	/* No more attributes found */
1463 	mcs_inst->otc.cb = &otc_cb;
1464 	bt_ots_client_register(&mcs_inst->otc);
1465 
1466 	LOG_DBG("Setup complete for included OTS");
1467 	(void)memset(params, 0, sizeof(*params));
1468 
1469 	discovery_complete(conn, err);
1470 
1471 	return BT_GATT_ITER_STOP;
1472 }
1473 #endif /* CONFIG_BT_MCC_OTS */
1474 
1475 #ifdef CONFIG_BT_MCC_OTS
1476 /* This function is called when an included service is found.
1477  * The function will store the start and end handle for the service,
1478  * and continue the search for more instances of included services.
1479  * Lastly, it will start discovery of OTS characteristics.
1480  */
1481 
discover_include_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)1482 static uint8_t discover_include_func(struct bt_conn *conn,
1483 				     const struct bt_gatt_attr *attr,
1484 				     struct bt_gatt_discover_params *params)
1485 {
1486 	struct bt_gatt_include *include;
1487 	int err = 0;
1488 
1489 	if (attr) {
1490 		struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
1491 							       struct mcs_instance_t,
1492 							       discover_params);
1493 
1494 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
1495 
1496 		__ASSERT(params->type == BT_GATT_DISCOVER_INCLUDE,
1497 			 "Wrong type");
1498 
1499 		/* We have found an included service */
1500 		include = (struct bt_gatt_include *)attr->user_data;
1501 		LOG_DBG("Include UUID %s", bt_uuid_str(include->uuid));
1502 
1503 		if (bt_uuid_cmp(include->uuid, BT_UUID_OTS)) {
1504 			/* But it is not OTS - continue search */
1505 			LOG_WRN("Included service is not OTS");
1506 			return BT_GATT_ITER_CONTINUE;
1507 		}
1508 
1509 		/* We have the included OTS service (MCS includes only one) */
1510 		LOG_DBG("Discover include complete for GMCS: OTS");
1511 		mcs_inst->otc.start_handle = include->start_handle;
1512 		mcs_inst->otc.end_handle = include->end_handle;
1513 		(void)memset(params, 0, sizeof(*params));
1514 
1515 		/* Discover characteristics of the included OTS */
1516 		mcs_inst->discover_params.start_handle = mcs_inst->otc.start_handle;
1517 		mcs_inst->discover_params.end_handle = mcs_inst->otc.end_handle;
1518 		mcs_inst->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
1519 		mcs_inst->discover_params.func = discover_otc_char_func;
1520 
1521 		LOG_DBG("Start discovery of OTS characteristics");
1522 		err = bt_gatt_discover(conn, &mcs_inst->discover_params);
1523 		if (err) {
1524 			LOG_DBG("Discovery of OTS chars. failed");
1525 			discovery_complete(conn, err);
1526 		}
1527 		return BT_GATT_ITER_STOP;
1528 	}
1529 
1530 	LOG_DBG("No included OTS found");
1531 	/* This is OK, the server may not support OTS. But in that case,
1532 	 *  discovery stops here.
1533 	 */
1534 	discovery_complete(conn, err);
1535 	return BT_GATT_ITER_STOP;
1536 }
1537 
1538 /* Start discovery of included services */
discover_included(struct mcs_instance_t * mcs_inst,struct bt_conn * conn)1539 static void discover_included(struct mcs_instance_t *mcs_inst, struct bt_conn *conn)
1540 {
1541 	int err;
1542 
1543 	memset(&mcs_inst->discover_params, 0, sizeof(mcs_inst->discover_params));
1544 
1545 	mcs_inst->discover_params.start_handle = mcs_inst->start_handle;
1546 	mcs_inst->discover_params.end_handle = mcs_inst->end_handle;
1547 	mcs_inst->discover_params.type = BT_GATT_DISCOVER_INCLUDE;
1548 	mcs_inst->discover_params.func = discover_include_func;
1549 
1550 	LOG_DBG("Start discovery of included services");
1551 	err = bt_gatt_discover(conn, &mcs_inst->discover_params);
1552 	if (err) {
1553 		LOG_DBG("Discovery of included service failed: %d", err);
1554 		discovery_complete(conn, err);
1555 	}
1556 }
1557 #endif /* CONFIG_BT_MCC_OTS */
1558 
1559 static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst,
1560 				    struct bt_conn *conn);
1561 
1562 /* This function will subscribe to GMCS CCCDs.
1563  * After this, the function will start discovery of included services.
1564  */
subscribe_mcs_char_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * params)1565 static void subscribe_mcs_char_func(struct bt_conn *conn, uint8_t err,
1566 				    struct bt_gatt_subscribe_params *params)
1567 {
1568 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params->disc_params,
1569 						       struct mcs_instance_t,
1570 						       discover_params);
1571 	bool subscription_done;
1572 
1573 	if (err) {
1574 		LOG_DBG("Subscription callback error: %u", err);
1575 		params->subscribe = NULL;
1576 		discovery_complete(conn, err);
1577 		return;
1578 	}
1579 
1580 	LOG_DBG("Subscribed: value handle: %d, ccc handle: %d",
1581 	       params->value_handle, params->ccc_handle);
1582 
1583 	if (params->value_handle == 0) {
1584 		/* Unsubscribing, ignore */
1585 		return;
1586 	}
1587 
1588 	/* Subscribe to next characteristic */
1589 	subscription_done = subscribe_next_mcs_char(mcs_inst, conn);
1590 
1591 	if (subscription_done) {
1592 		params->subscribe = NULL;
1593 #ifdef CONFIG_BT_MCC_OTS
1594 		/* Start discovery of included services to find OTS */
1595 		discover_included(mcs_inst, conn);
1596 #else
1597 		/* If OTS is not configured, discovery ends here */
1598 		discovery_complete(conn, 0);
1599 #endif /* CONFIG_BT_MCC_OTS */
1600 	}
1601 }
1602 
1603 /* 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)1604 static int do_subscribe(struct mcs_instance_t *mcs_inst, struct bt_conn *conn,
1605 			uint16_t handle,
1606 			struct bt_gatt_subscribe_params *sub_params)
1607 {
1608 	/* With ccc_handle == 0 it will use auto discovery */
1609 	sub_params->ccc_handle = 0;
1610 	sub_params->end_handle = mcs_inst->end_handle;
1611 	sub_params->value_handle = handle;
1612 	sub_params->notify = mcs_notify_handler;
1613 	sub_params->subscribe = subscribe_mcs_char_func;
1614 	/* disc_params pointer is also used as subscription flag */
1615 	sub_params->disc_params = &mcs_inst->discover_params;
1616 	atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
1617 
1618 	LOG_DBG("Subscring to handle %d", handle);
1619 	return bt_gatt_subscribe(conn, sub_params);
1620 }
1621 
1622 /* Subscribe to the next GMCS CCCD.
1623  * @return true if there are no more characteristics to subscribe to
1624  */
subscribe_next_mcs_char(struct mcs_instance_t * mcs_inst,struct bt_conn * conn)1625 static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst,
1626 				    struct bt_conn *conn)
1627 {
1628 	struct bt_gatt_subscribe_params *sub_params = NULL;
1629 	uint16_t handle;
1630 
1631 	/* The characteristics may be in any order on the server, and
1632 	 * not all of them may exist => need to check all.
1633 	 * For each of the subscribable characteristics
1634 	 * - check if we have a handle for it
1635 	 * - check sub_params.disc_params pointer to see if we have
1636 	 *   already subscribed to it (set in do_subscribe() ).
1637 	 */
1638 
1639 	if (mcs_inst->player_name_handle &&
1640 	    mcs_inst->player_name_sub_params.value &&
1641 	    mcs_inst->player_name_sub_params.disc_params == NULL) {
1642 		sub_params = &mcs_inst->player_name_sub_params;
1643 		handle = mcs_inst->player_name_handle;
1644 	} else if (mcs_inst->track_changed_handle &&
1645 		   mcs_inst->track_changed_sub_params.value &&
1646 		   mcs_inst->track_changed_sub_params.disc_params == NULL) {
1647 		sub_params = &mcs_inst->track_changed_sub_params;
1648 		handle = mcs_inst->track_changed_handle;
1649 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION)
1650 	} else if (mcs_inst->track_title_handle &&
1651 		   mcs_inst->track_title_sub_params.value &&
1652 		   mcs_inst->track_title_sub_params.disc_params == NULL) {
1653 		sub_params = &mcs_inst->track_title_sub_params;
1654 		handle = mcs_inst->track_title_handle;
1655 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */
1656 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
1657 	} else if (mcs_inst->track_duration_handle &&
1658 		   mcs_inst->track_duration_sub_params.value &&
1659 		   mcs_inst->track_duration_sub_params.disc_params == NULL) {
1660 		sub_params = &mcs_inst->track_duration_sub_params;
1661 		handle = mcs_inst->track_duration_handle;
1662 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
1663 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
1664 	} else if (mcs_inst->track_position_handle &&
1665 		   mcs_inst->track_position_sub_params.value &&
1666 		   mcs_inst->track_position_sub_params.disc_params == NULL) {
1667 		sub_params = &mcs_inst->track_position_sub_params;
1668 		handle = mcs_inst->track_position_handle;
1669 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
1670 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
1671 	} else if (mcs_inst->playback_speed_handle &&
1672 		   mcs_inst->playback_speed_sub_params.value &&
1673 		   mcs_inst->playback_speed_sub_params.disc_params == NULL) {
1674 		sub_params = &mcs_inst->playback_speed_sub_params;
1675 		handle = mcs_inst->playback_speed_handle;
1676 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
1677 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
1678 	} else if (mcs_inst->seeking_speed_handle &&
1679 		   mcs_inst->seeking_speed_sub_params.value &&
1680 		   mcs_inst->seeking_speed_sub_params.disc_params == NULL) {
1681 		sub_params = &mcs_inst->seeking_speed_sub_params;
1682 		handle = mcs_inst->seeking_speed_handle;
1683 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
1684 #ifdef CONFIG_BT_MCC_OTS
1685 	} else if (mcs_inst->current_track_obj_id_handle &&
1686 		   mcs_inst->current_track_obj_sub_params.value &&
1687 		   mcs_inst->current_track_obj_sub_params.disc_params == NULL) {
1688 		sub_params = &mcs_inst->current_track_obj_sub_params;
1689 		handle = mcs_inst->current_track_obj_id_handle;
1690 	} else if (mcs_inst->next_track_obj_id_handle &&
1691 		   mcs_inst->next_track_obj_sub_params.value &&
1692 		   mcs_inst->next_track_obj_sub_params.disc_params == NULL) {
1693 		sub_params = &mcs_inst->next_track_obj_sub_params;
1694 		handle = mcs_inst->next_track_obj_id_handle;
1695 	} else if (mcs_inst->parent_group_obj_id_handle &&
1696 		   mcs_inst->parent_group_obj_sub_params.value &&
1697 		   mcs_inst->parent_group_obj_sub_params.disc_params == NULL) {
1698 		sub_params = &mcs_inst->parent_group_obj_sub_params;
1699 		handle = mcs_inst->parent_group_obj_id_handle;
1700 	} else if (mcs_inst->current_group_obj_id_handle &&
1701 		   mcs_inst->current_group_obj_sub_params.value &&
1702 		   mcs_inst->current_group_obj_sub_params.disc_params == NULL) {
1703 		sub_params = &mcs_inst->current_group_obj_sub_params;
1704 		handle = mcs_inst->current_group_obj_id_handle;
1705 #endif /* CONFIG_BT_MCC_OTS */
1706 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
1707 	} else if (mcs_inst->playing_order_handle &&
1708 		   mcs_inst->playing_order_sub_params.value &&
1709 		   mcs_inst->playing_order_sub_params.disc_params == NULL) {
1710 		sub_params = &mcs_inst->playing_order_sub_params;
1711 		handle = mcs_inst->playing_order_handle;
1712 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
1713 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
1714 	} else if (mcs_inst->media_state_handle &&
1715 		  mcs_inst->media_state_sub_params.value &&
1716 		  mcs_inst->media_state_sub_params.disc_params == NULL) {
1717 		sub_params = &mcs_inst->media_state_sub_params;
1718 		handle = mcs_inst->media_state_handle;
1719 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
1720 	} else if (mcs_inst->cp_handle &&
1721 		   mcs_inst->cp_sub_params.value &&
1722 		   mcs_inst->cp_sub_params.disc_params == NULL) {
1723 		sub_params = &mcs_inst->cp_sub_params;
1724 		handle = mcs_inst->cp_handle;
1725 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
1726 	} else if (mcs_inst->opcodes_supported_handle &&
1727 		   mcs_inst->opcodes_supported_sub_params.value &&
1728 		   mcs_inst->opcodes_supported_sub_params.disc_params == NULL) {
1729 		sub_params = &mcs_inst->opcodes_supported_sub_params;
1730 		handle = mcs_inst->opcodes_supported_handle;
1731 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
1732 #ifdef CONFIG_BT_MCC_OTS
1733 	} else if (mcs_inst->scp_handle &&
1734 		   mcs_inst->scp_sub_params.value &&
1735 		   mcs_inst->scp_sub_params.disc_params == NULL) {
1736 		sub_params = &mcs_inst->scp_sub_params;
1737 		handle = mcs_inst->scp_handle;
1738 	} else if (mcs_inst->search_results_obj_id_handle &&
1739 		   mcs_inst->search_results_obj_sub_params.value &&
1740 		   mcs_inst->search_results_obj_sub_params.disc_params == NULL) {
1741 		sub_params = &mcs_inst->search_results_obj_sub_params;
1742 		handle = mcs_inst->search_results_obj_id_handle;
1743 #endif /* CONFIG_BT_MCC_OTS */
1744 	}
1745 
1746 	if (sub_params != NULL) {
1747 		const int err = do_subscribe(mcs_inst, conn, handle,
1748 					     sub_params);
1749 
1750 		if (err) {
1751 			LOG_DBG("Could not subscribe: %d", err);
1752 			discovery_complete(conn, err);
1753 		}
1754 
1755 		return false;
1756 	}
1757 
1758 	/* If we have come here, there are no more characteristics to
1759 	 * subscribe to, and we are done.
1760 	 */
1761 	return true;
1762 }
1763 
1764 /* This function is called when characteristics are found.
1765  * The function will store handles to GMCS characteristics.
1766  * After this, the function will start subscription to characteristics
1767  */
discover_mcs_char_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)1768 static uint8_t discover_mcs_char_func(struct bt_conn *conn,
1769 				      const struct bt_gatt_attr *attr,
1770 				      struct bt_gatt_discover_params *params)
1771 {
1772 	struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
1773 						       struct mcs_instance_t,
1774 						       discover_params);
1775 	struct bt_gatt_chrc *chrc;
1776 	bool subscription_done = true;
1777 
1778 	if (attr) {
1779 		/* Found an attribute */
1780 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
1781 
1782 		if (params->type != BT_GATT_DISCOVER_CHARACTERISTIC) {
1783 			/* But it was not a characteristic - continue search */
1784 			return BT_GATT_ITER_CONTINUE;
1785 		}
1786 
1787 		/* We have found an attribute, and it is a characteristic */
1788 		/* Find out which attribute, and subscribe if we should */
1789 		chrc = (struct bt_gatt_chrc *)attr->user_data;
1790 
1791 		if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYER_NAME)) {
1792 			LOG_DBG("Player name, UUID: %s", bt_uuid_str(chrc->uuid));
1793 			mcs_inst->player_name_handle = chrc->value_handle;
1794 			/* Use discovery params pointer as subscription flag */
1795 			mcs_inst->player_name_sub_params.disc_params = NULL;
1796 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1797 				mcs_inst->player_name_sub_params.value = BT_GATT_CCC_NOTIFY;
1798 			}
1799 #ifdef CONFIG_BT_MCC_OTS
1800 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_ICON_OBJ_ID)) {
1801 			LOG_DBG("Icon Object, UUID: %s", bt_uuid_str(chrc->uuid));
1802 			mcs_inst->icon_obj_id_handle = chrc->value_handle;
1803 #endif /* CONFIG_BT_MCC_OTS */
1804 #if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL)
1805 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_ICON_URL)) {
1806 			LOG_DBG("Icon URL, UUID: %s", bt_uuid_str(chrc->uuid));
1807 			mcs_inst->icon_url_handle = chrc->value_handle;
1808 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */
1809 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_CHANGED)) {
1810 			LOG_DBG("Track Changed, UUID: %s", bt_uuid_str(chrc->uuid));
1811 			mcs_inst->track_changed_handle = chrc->value_handle;
1812 			mcs_inst->track_changed_sub_params.disc_params = NULL;
1813 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1814 				mcs_inst->track_changed_sub_params.value = BT_GATT_CCC_NOTIFY;
1815 			}
1816 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE)
1817 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_TITLE)) {
1818 			LOG_DBG("Track Title, UUID: %s", bt_uuid_str(chrc->uuid));
1819 			mcs_inst->track_title_handle = chrc->value_handle;
1820 #if defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION)
1821 			mcs_inst->track_title_sub_params.disc_params = NULL;
1822 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1823 				mcs_inst->track_title_sub_params.value = BT_GATT_CCC_NOTIFY;
1824 			}
1825 #endif /* defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */
1826 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */
1827 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
1828 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_DURATION)) {
1829 			LOG_DBG("Track Duration, UUID: %s", bt_uuid_str(chrc->uuid));
1830 			mcs_inst->track_duration_handle = chrc->value_handle;
1831 			mcs_inst->track_duration_sub_params.disc_params = NULL;
1832 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1833 				mcs_inst->track_duration_sub_params.value = BT_GATT_CCC_NOTIFY;
1834 			}
1835 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
1836 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION)
1837 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_POSITION)) {
1838 			LOG_DBG("Track Position, UUID: %s", bt_uuid_str(chrc->uuid));
1839 			mcs_inst->track_position_handle = chrc->value_handle;
1840 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
1841 			mcs_inst->track_position_sub_params.disc_params = NULL;
1842 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1843 				mcs_inst->track_position_sub_params.value = BT_GATT_CCC_NOTIFY;
1844 			}
1845 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
1846 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */
1847 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
1848 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYBACK_SPEED)) {
1849 			LOG_DBG("Playback Speed, UUID: %s", bt_uuid_str(chrc->uuid));
1850 			mcs_inst->playback_speed_handle = chrc->value_handle;
1851 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
1852 			mcs_inst->playback_speed_sub_params.disc_params = NULL;
1853 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1854 				mcs_inst->playback_speed_sub_params.value = BT_GATT_CCC_NOTIFY;
1855 			}
1856 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
1857 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) ||
1858 	* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
1859 	*/
1860 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
1861 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEEKING_SPEED)) {
1862 			LOG_DBG("Seeking Speed, UUID: %s", bt_uuid_str(chrc->uuid));
1863 			mcs_inst->seeking_speed_handle = chrc->value_handle;
1864 			mcs_inst->seeking_speed_sub_params.disc_params = NULL;
1865 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1866 				mcs_inst->seeking_speed_sub_params.value = BT_GATT_CCC_NOTIFY;
1867 			}
1868 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
1869 #ifdef CONFIG_BT_MCC_OTS
1870 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID)) {
1871 			LOG_DBG("Track Segments Object, UUID: %s", bt_uuid_str(chrc->uuid));
1872 			mcs_inst->segments_obj_id_handle = chrc->value_handle;
1873 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_CURRENT_TRACK_OBJ_ID)) {
1874 			LOG_DBG("Current Track Object, UUID: %s", bt_uuid_str(chrc->uuid));
1875 			mcs_inst->current_track_obj_id_handle = chrc->value_handle;
1876 			mcs_inst->current_track_obj_sub_params.disc_params = NULL;
1877 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1878 				mcs_inst->current_track_obj_sub_params.value =
1879 					BT_GATT_CCC_NOTIFY;
1880 			}
1881 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_NEXT_TRACK_OBJ_ID)) {
1882 			LOG_DBG("Next Track Object, UUID: %s", bt_uuid_str(chrc->uuid));
1883 			mcs_inst->next_track_obj_id_handle = chrc->value_handle;
1884 			mcs_inst->next_track_obj_sub_params.disc_params = NULL;
1885 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1886 				mcs_inst->next_track_obj_sub_params.value = BT_GATT_CCC_NOTIFY;
1887 			}
1888 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PARENT_GROUP_OBJ_ID)) {
1889 			LOG_DBG("Parent Group Object, UUID: %s", bt_uuid_str(chrc->uuid));
1890 			mcs_inst->parent_group_obj_id_handle = chrc->value_handle;
1891 			mcs_inst->parent_group_obj_sub_params.disc_params = NULL;
1892 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1893 				mcs_inst->parent_group_obj_sub_params.value =
1894 					BT_GATT_CCC_NOTIFY;
1895 			}
1896 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_CURRENT_GROUP_OBJ_ID)) {
1897 			LOG_DBG("Group Object, UUID: %s", bt_uuid_str(chrc->uuid));
1898 			mcs_inst->current_group_obj_id_handle = chrc->value_handle;
1899 			mcs_inst->current_group_obj_sub_params.disc_params = NULL;
1900 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1901 				mcs_inst->current_group_obj_sub_params.value =
1902 					BT_GATT_CCC_NOTIFY;
1903 			}
1904 #endif /* CONFIG_BT_MCC_OTS */
1905 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER)
1906 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDER)) {
1907 			LOG_DBG("Playing Order, UUID: %s", bt_uuid_str(chrc->uuid));
1908 			mcs_inst->playing_order_handle = chrc->value_handle;
1909 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
1910 			mcs_inst->playing_order_sub_params.disc_params = NULL;
1911 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1912 				mcs_inst->playing_order_sub_params.value = BT_GATT_CCC_NOTIFY;
1913 			}
1914 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
1915 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */
1916 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED)
1917 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDERS)) {
1918 			LOG_DBG("Playing Orders supported, UUID: %s", bt_uuid_str(chrc->uuid));
1919 			mcs_inst->playing_orders_supported_handle = chrc->value_handle;
1920 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */
1921 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
1922 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_STATE)) {
1923 			LOG_DBG("Media State, UUID: %s", bt_uuid_str(chrc->uuid));
1924 			mcs_inst->media_state_handle = chrc->value_handle;
1925 			mcs_inst->media_state_sub_params.disc_params = NULL;
1926 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1927 				mcs_inst->media_state_sub_params.value = BT_GATT_CCC_NOTIFY;
1928 			}
1929 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
1930 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_POINT)) {
1931 			LOG_DBG("Media Control Point, UUID: %s", bt_uuid_str(chrc->uuid));
1932 			mcs_inst->cp_handle = chrc->value_handle;
1933 			mcs_inst->cp_sub_params.disc_params = NULL;
1934 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1935 				mcs_inst->cp_sub_params.value = BT_GATT_CCC_NOTIFY;
1936 			}
1937 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
1938 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_OPCODES)) {
1939 			LOG_DBG("Media control opcodes supported, UUID: %s",
1940 			       bt_uuid_str(chrc->uuid));
1941 			mcs_inst->opcodes_supported_handle = chrc->value_handle;
1942 			mcs_inst->opcodes_supported_sub_params.disc_params = NULL;
1943 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1944 				mcs_inst->opcodes_supported_sub_params.value =
1945 					BT_GATT_CCC_NOTIFY;
1946 			}
1947 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
1948 #ifdef CONFIG_BT_MCC_OTS
1949 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEARCH_CONTROL_POINT)) {
1950 			LOG_DBG("Search control point, UUID: %s", bt_uuid_str(chrc->uuid));
1951 			mcs_inst->scp_handle = chrc->value_handle;
1952 			mcs_inst->scp_sub_params.disc_params = NULL;
1953 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1954 				mcs_inst->scp_sub_params.value = BT_GATT_CCC_NOTIFY;
1955 			}
1956 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID)) {
1957 			LOG_DBG("Search Results object, UUID: %s", bt_uuid_str(chrc->uuid));
1958 			mcs_inst->search_results_obj_id_handle = chrc->value_handle;
1959 			mcs_inst->search_results_obj_sub_params.disc_params = NULL;
1960 			if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
1961 				mcs_inst->search_results_obj_sub_params.value =
1962 					BT_GATT_CCC_NOTIFY;
1963 			}
1964 #endif /* CONFIG_BT_MCC_OTS */
1965 #if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID)
1966 		} else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_CCID)) {
1967 			LOG_DBG("Content Control ID, UUID: %s", bt_uuid_str(chrc->uuid));
1968 			mcs_inst->content_control_id_handle = chrc->value_handle;
1969 #endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */
1970 		}
1971 
1972 
1973 		/* Continue to search for more attributes */
1974 		return BT_GATT_ITER_CONTINUE;
1975 	}
1976 
1977 	/* No more attributes found */
1978 	LOG_DBG("GMCS characteristics found");
1979 	(void)memset(params, 0, sizeof(*params));
1980 
1981 	/* Either subscribe to characteristics, or continue to discovery of
1982 	 *included services.
1983 	 * Subscription is done after discovery, not in parallel with it,
1984 	 * to avoid queuing many ATT requests that requires buffers.
1985 	 */
1986 	if (subscribe_all) {
1987 		subscription_done = subscribe_next_mcs_char(mcs_inst, conn);
1988 	}
1989 
1990 	if (subscription_done) {
1991 		/* Not subscribing, or there was nothing to subscribe to */
1992 #ifdef CONFIG_BT_MCC_OTS
1993 		/* Start discovery of included services to find OTS */
1994 		discover_included(mcs_inst, conn);
1995 #else
1996 		/* If OTS is not configured, discovery ends here */
1997 		discovery_complete(conn, 0);
1998 #endif /* CONFIG_BT_MCC_OTS */
1999 	}
2000 
2001 	return BT_GATT_ITER_STOP;
2002 }
2003 
2004 /* This function is called when a (primary) GMCS service has been discovered.
2005  * The function will store the start and end handle for the service. It will
2006  * then start discovery of the characteristics of the GMCS service.
2007  */
discover_primary_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)2008 static uint8_t discover_primary_func(struct bt_conn *conn,
2009 				     const struct bt_gatt_attr *attr,
2010 				     struct bt_gatt_discover_params *params)
2011 {
2012 	struct bt_gatt_service_val *prim_service;
2013 
2014 	if (attr) {
2015 		struct mcs_instance_t *mcs_inst = CONTAINER_OF(params,
2016 							       struct mcs_instance_t,
2017 							       discover_params);
2018 		int err;
2019 		/* Found an attribute */
2020 		LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
2021 
2022 		if (params->type != BT_GATT_DISCOVER_PRIMARY) {
2023 			/* But it was not a primary service - continue search */
2024 			LOG_WRN("Unexpected parameters");
2025 			return BT_GATT_ITER_CONTINUE;
2026 		}
2027 
2028 		/* We have found an attribute, and it is a primary service */
2029 		/* (Must be GMCS, since that is the one we searched for.) */
2030 		LOG_DBG("Primary discovery complete");
2031 		LOG_DBG("UUID: %s", bt_uuid_str(attr->uuid));
2032 		prim_service = (struct bt_gatt_service_val *)attr->user_data;
2033 		LOG_DBG("UUID: %s", bt_uuid_str(prim_service->uuid));
2034 
2035 		mcs_inst->start_handle = attr->handle + 1;
2036 		mcs_inst->end_handle = prim_service->end_handle;
2037 
2038 		/* Start discovery of characteristics */
2039 		mcs_inst->discover_params.uuid = NULL;
2040 		mcs_inst->discover_params.start_handle = mcs_inst->start_handle;
2041 		mcs_inst->discover_params.end_handle = mcs_inst->end_handle;
2042 		mcs_inst->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
2043 		mcs_inst->discover_params.func = discover_mcs_char_func;
2044 
2045 		LOG_DBG("Start discovery of GMCS characteristics");
2046 		err = bt_gatt_discover(conn, &mcs_inst->discover_params);
2047 		if (err) {
2048 			LOG_DBG("Discovery failed: %d", err);
2049 			discovery_complete(conn, err);
2050 		}
2051 		return BT_GATT_ITER_STOP;
2052 	}
2053 
2054 	/* No attribute of the searched for type found */
2055 	LOG_DBG("Could not find an GMCS instance on the server");
2056 
2057 	discovery_complete(conn, -ENODATA);
2058 	return BT_GATT_ITER_STOP;
2059 }
2060 
2061 
bt_mcc_init(struct bt_mcc_cb * cb)2062 int bt_mcc_init(struct bt_mcc_cb *cb)
2063 {
2064 	mcc_cb = cb;
2065 
2066 #ifdef CONFIG_BT_MCC_OTS
2067 	/* Set up the callbacks from OTC */
2068 	/* TODO: Have one single content callback. */
2069 	/* For now: Use the icon callback for content - it is the first, */
2070 	/* and this will anyway be reset later. */
2071 	otc_cb.obj_data_read     = on_icon_content;
2072 	otc_cb.obj_selected      = on_obj_selected;
2073 	otc_cb.obj_metadata_read = on_object_metadata;
2074 
2075 	LOG_DBG("Object selected callback: %p", otc_cb.obj_selected);
2076 	LOG_DBG("Object content callback: %p", otc_cb.obj_data_read);
2077 	LOG_DBG("Object metadata callback: %p", otc_cb.obj_metadata_read);
2078 #endif /* CONFIG_BT_MCC_OTS */
2079 
2080 	return 0;
2081 }
2082 
2083 
2084 /* Initiate discovery.
2085  * Discovery is handled by a chain of functions, where each function does its
2086  * part, and then initiates a further discovery, with a new callback function.
2087  *
2088  * The order of discovery is follows:
2089  * 1: Discover GMCS primary service (started here)
2090  * 2: Discover characteristics of GMCS
2091  * 3: Subscribe to characteristics of GMCS
2092  * 4: Discover OTS service included in GMCS
2093  * 5: Discover characteristics of OTS and subscribe to them
2094  */
bt_mcc_discover_mcs(struct bt_conn * conn,bool subscribe)2095 int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe)
2096 {
2097 	struct mcs_instance_t *mcs_inst;
2098 	int err;
2099 
2100 	CHECKIF(!conn) {
2101 		return -EINVAL;
2102 	}
2103 
2104 	mcs_inst = lookup_inst_by_conn(conn);
2105 	if (mcs_inst == NULL) {
2106 		/* TODO: Need to find existing or new MCS instance here */
2107 		return -EINVAL;
2108 	}
2109 
2110 	if (mcs_inst->busy) {
2111 		return -EBUSY;
2112 	}
2113 
2114 	subscribe_all = subscribe;
2115 	err = reset_mcs_inst(mcs_inst);
2116 	if (err != 0) {
2117 		LOG_DBG("Failed to reset MCS instance %p: %d", mcs_inst, err);
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 		return err;
2133 	}
2134 
2135 	mcs_inst->conn = bt_conn_ref(conn);
2136 	mcs_inst->busy = true;
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->busy) {
2158 
2159 		LOG_DBG("mcs_inst busy");
2160 		return -EBUSY;
2161 	} else if (mcs_inst->player_name_handle == 0) {
2162 		LOG_DBG("handle not set");
2163 
2164 		return -EINVAL;
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) {
2174 		mcs_inst->busy = true;
2175 	}
2176 	return err;
2177 }
2178 
2179 
2180 #ifdef CONFIG_BT_MCC_OTS
bt_mcc_read_icon_obj_id(struct bt_conn * conn)2181 int bt_mcc_read_icon_obj_id(struct bt_conn *conn)
2182 {
2183 	struct mcs_instance_t *mcs_inst;
2184 	int err;
2185 
2186 	CHECKIF(conn == NULL) {
2187 		LOG_DBG("conn is NULL");
2188 
2189 		return -EINVAL;
2190 	}
2191 
2192 	mcs_inst = lookup_inst_by_conn(conn);
2193 	if (mcs_inst == NULL) {
2194 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2195 
2196 		return -EINVAL;
2197 	} else if (mcs_inst->busy) {
2198 
2199 		LOG_DBG("mcs_inst busy");
2200 		return -EBUSY;
2201 	} else if (mcs_inst->icon_obj_id_handle == 0) {
2202 		LOG_DBG("handle not set");
2203 
2204 		return -EINVAL;
2205 	}
2206 
2207 	mcs_inst->read_params.func = mcc_read_icon_obj_id_cb;
2208 	mcs_inst->read_params.handle_count = 1;
2209 	mcs_inst->read_params.single.handle = mcs_inst->icon_obj_id_handle;
2210 	mcs_inst->read_params.single.offset = 0U;
2211 
2212 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2213 	if (!err) {
2214 		mcs_inst->busy = true;
2215 	}
2216 	return err;
2217 }
2218 #endif /* CONFIG_BT_MCC_OTS */
2219 
2220 #if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL)
bt_mcc_read_icon_url(struct bt_conn * conn)2221 int bt_mcc_read_icon_url(struct bt_conn *conn)
2222 {
2223 	struct mcs_instance_t *mcs_inst;
2224 	int err;
2225 
2226 	CHECKIF(conn == NULL) {
2227 		LOG_DBG("conn is NULL");
2228 
2229 		return -EINVAL;
2230 	}
2231 
2232 	mcs_inst = lookup_inst_by_conn(conn);
2233 	if (mcs_inst == NULL) {
2234 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2235 
2236 		return -EINVAL;
2237 	} else if (mcs_inst->busy) {
2238 
2239 		LOG_DBG("mcs_inst busy");
2240 		return -EBUSY;
2241 	} else if (mcs_inst->icon_url_handle == 0) {
2242 		LOG_DBG("handle not set");
2243 
2244 		return -EINVAL;
2245 	}
2246 
2247 	mcs_inst->read_params.func = mcc_read_icon_url_cb;
2248 	mcs_inst->read_params.handle_count = 1;
2249 	mcs_inst->read_params.single.handle = mcs_inst->icon_url_handle;
2250 	mcs_inst->read_params.single.offset = 0U;
2251 
2252 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2253 	if (!err) {
2254 		mcs_inst->busy = true;
2255 	}
2256 	return err;
2257 }
2258 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */
2259 
2260 #if defined(CONFIG_BT_MCC_READ_TRACK_TITLE)
bt_mcc_read_track_title(struct bt_conn * conn)2261 int bt_mcc_read_track_title(struct bt_conn *conn)
2262 {
2263 	struct mcs_instance_t *mcs_inst;
2264 	int err;
2265 
2266 	CHECKIF(conn == NULL) {
2267 		LOG_DBG("conn is NULL");
2268 
2269 		return -EINVAL;
2270 	}
2271 
2272 	mcs_inst = lookup_inst_by_conn(conn);
2273 	if (mcs_inst == NULL) {
2274 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2275 
2276 		return -EINVAL;
2277 	} else if (mcs_inst->busy) {
2278 
2279 		LOG_DBG("mcs_inst busy");
2280 		return -EBUSY;
2281 	} else if (mcs_inst->track_title_handle == 0) {
2282 		LOG_DBG("handle not set");
2283 
2284 		return -EINVAL;
2285 	}
2286 
2287 	mcs_inst->read_params.func = mcc_read_track_title_cb;
2288 	mcs_inst->read_params.handle_count = 1;
2289 	mcs_inst->read_params.single.handle = mcs_inst->track_title_handle;
2290 	mcs_inst->read_params.single.offset = 0U;
2291 
2292 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2293 	if (!err) {
2294 		mcs_inst->busy = true;
2295 	}
2296 	return err;
2297 }
2298 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */
2299 
2300 #if defined(CONFIG_BT_MCC_READ_TRACK_DURATION)
bt_mcc_read_track_duration(struct bt_conn * conn)2301 int bt_mcc_read_track_duration(struct bt_conn *conn)
2302 {
2303 	struct mcs_instance_t *mcs_inst;
2304 	int err;
2305 
2306 	CHECKIF(conn == NULL) {
2307 		LOG_DBG("conn is NULL");
2308 
2309 		return -EINVAL;
2310 	}
2311 
2312 	mcs_inst = lookup_inst_by_conn(conn);
2313 	if (mcs_inst == NULL) {
2314 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2315 
2316 		return -EINVAL;
2317 	} else if (mcs_inst->busy) {
2318 
2319 		LOG_DBG("mcs_inst busy");
2320 		return -EBUSY;
2321 	} else if (mcs_inst->track_duration_handle == 0) {
2322 		LOG_DBG("handle not set");
2323 
2324 		return -EINVAL;
2325 	}
2326 
2327 	mcs_inst->read_params.func = mcc_read_track_duration_cb;
2328 	mcs_inst->read_params.handle_count = 1;
2329 	mcs_inst->read_params.single.handle = mcs_inst->track_duration_handle;
2330 	mcs_inst->read_params.single.offset = 0U;
2331 
2332 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2333 	if (!err) {
2334 		mcs_inst->busy = true;
2335 	}
2336 	return err;
2337 }
2338 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */
2339 
2340 #if defined(CONFIG_BT_MCC_READ_TRACK_POSITION)
bt_mcc_read_track_position(struct bt_conn * conn)2341 int bt_mcc_read_track_position(struct bt_conn *conn)
2342 {
2343 	struct mcs_instance_t *mcs_inst;
2344 	int err;
2345 
2346 	CHECKIF(conn == NULL) {
2347 		LOG_DBG("conn is NULL");
2348 
2349 		return -EINVAL;
2350 	}
2351 
2352 	mcs_inst = lookup_inst_by_conn(conn);
2353 	if (mcs_inst == NULL) {
2354 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2355 
2356 		return -EINVAL;
2357 	} else if (mcs_inst->busy) {
2358 
2359 		LOG_DBG("mcs_inst busy");
2360 		return -EBUSY;
2361 	} else if (mcs_inst->track_position_handle == 0) {
2362 		LOG_DBG("handle not set");
2363 
2364 		return -EINVAL;
2365 	}
2366 
2367 	mcs_inst->read_params.func = mcc_read_track_position_cb;
2368 	mcs_inst->read_params.handle_count = 1;
2369 	mcs_inst->read_params.single.handle = mcs_inst->track_position_handle;
2370 	mcs_inst->read_params.single.offset = 0U;
2371 
2372 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2373 	if (!err) {
2374 		mcs_inst->busy = true;
2375 	}
2376 	return err;
2377 }
2378 #endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */
2379 
2380 #if defined(CONFIG_BT_MCC_SET_TRACK_POSITION)
bt_mcc_set_track_position(struct bt_conn * conn,int32_t pos)2381 int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos)
2382 {
2383 	struct mcs_instance_t *mcs_inst;
2384 	int err;
2385 
2386 	CHECKIF(conn == NULL) {
2387 		LOG_DBG("conn is NULL");
2388 
2389 		return -EINVAL;
2390 	}
2391 
2392 	mcs_inst = lookup_inst_by_conn(conn);
2393 	if (mcs_inst == NULL) {
2394 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2395 
2396 		return -EINVAL;
2397 	} else if (mcs_inst->busy) {
2398 
2399 		LOG_DBG("mcs_inst busy");
2400 		return -EBUSY;
2401 	} else if (mcs_inst->track_position_handle == 0) {
2402 		LOG_DBG("handle not set");
2403 
2404 		return -EINVAL;
2405 	}
2406 
2407 	(void)memcpy(mcs_inst->write_buf, &pos, sizeof(pos));
2408 
2409 	mcs_inst->write_params.offset = 0;
2410 	mcs_inst->write_params.data = mcs_inst->write_buf;
2411 	mcs_inst->write_params.length = sizeof(pos);
2412 	mcs_inst->write_params.handle = mcs_inst->track_position_handle;
2413 	mcs_inst->write_params.func = mcs_write_track_position_cb;
2414 
2415 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(pos), "Track position sent");
2416 
2417 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2418 	if (!err) {
2419 		mcs_inst->busy = true;
2420 	}
2421 	return err;
2422 }
2423 #endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */
2424 
2425 #if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED)
bt_mcc_read_playback_speed(struct bt_conn * conn)2426 int bt_mcc_read_playback_speed(struct bt_conn *conn)
2427 {
2428 	struct mcs_instance_t *mcs_inst;
2429 	int err;
2430 
2431 	CHECKIF(conn == NULL) {
2432 		LOG_DBG("conn is NULL");
2433 
2434 		return -EINVAL;
2435 	}
2436 
2437 	mcs_inst = lookup_inst_by_conn(conn);
2438 	if (mcs_inst == NULL) {
2439 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2440 
2441 		return -EINVAL;
2442 	} else if (mcs_inst->busy) {
2443 
2444 		LOG_DBG("mcs_inst busy");
2445 		return -EBUSY;
2446 	} else if (mcs_inst->playback_speed_handle == 0) {
2447 		LOG_DBG("handle not set");
2448 
2449 		return -EINVAL;
2450 	}
2451 
2452 	mcs_inst->read_params.func = mcc_read_playback_speed_cb;
2453 	mcs_inst->read_params.handle_count = 1;
2454 	mcs_inst->read_params.single.handle = mcs_inst->playback_speed_handle;
2455 	mcs_inst->read_params.single.offset = 0U;
2456 
2457 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2458 	if (!err) {
2459 		mcs_inst->busy = true;
2460 	}
2461 	return err;
2462 }
2463 #endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */
2464 
2465 #if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED)
bt_mcc_set_playback_speed(struct bt_conn * conn,int8_t speed)2466 int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed)
2467 {
2468 	struct mcs_instance_t *mcs_inst;
2469 	int err;
2470 
2471 	CHECKIF(conn == NULL) {
2472 		LOG_DBG("conn is NULL");
2473 
2474 		return -EINVAL;
2475 	}
2476 
2477 	mcs_inst = lookup_inst_by_conn(conn);
2478 	if (mcs_inst == NULL) {
2479 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2480 
2481 		return -EINVAL;
2482 	} else if (mcs_inst->busy) {
2483 
2484 		LOG_DBG("mcs_inst busy");
2485 		return -EBUSY;
2486 	} else if (mcs_inst->playback_speed_handle == 0) {
2487 		LOG_DBG("handle not set");
2488 
2489 		return -EINVAL;
2490 	}
2491 
2492 	(void)memcpy(mcs_inst->write_buf, &speed, sizeof(speed));
2493 
2494 	mcs_inst->write_params.offset = 0;
2495 	mcs_inst->write_params.data = mcs_inst->write_buf;
2496 	mcs_inst->write_params.length = sizeof(speed);
2497 	mcs_inst->write_params.handle = mcs_inst->playback_speed_handle;
2498 	mcs_inst->write_params.func = mcs_write_playback_speed_cb;
2499 
2500 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(speed), "Playback speed");
2501 
2502 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2503 	if (!err) {
2504 		mcs_inst->busy = true;
2505 	}
2506 	return err;
2507 }
2508 #endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */
2509 
2510 #if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED)
bt_mcc_read_seeking_speed(struct bt_conn * conn)2511 int bt_mcc_read_seeking_speed(struct bt_conn *conn)
2512 {
2513 	struct mcs_instance_t *mcs_inst;
2514 	int err;
2515 
2516 	CHECKIF(conn == NULL) {
2517 		LOG_DBG("conn is NULL");
2518 
2519 		return -EINVAL;
2520 	}
2521 
2522 	mcs_inst = lookup_inst_by_conn(conn);
2523 	if (mcs_inst == NULL) {
2524 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2525 
2526 		return -EINVAL;
2527 	} else if (mcs_inst->busy) {
2528 
2529 		LOG_DBG("mcs_inst busy");
2530 		return -EBUSY;
2531 	} else if (mcs_inst->seeking_speed_handle == 0) {
2532 		LOG_DBG("handle not set");
2533 
2534 		return -EINVAL;
2535 	}
2536 
2537 	mcs_inst->read_params.func = mcc_read_seeking_speed_cb;
2538 	mcs_inst->read_params.handle_count = 1;
2539 	mcs_inst->read_params.single.handle = mcs_inst->seeking_speed_handle;
2540 	mcs_inst->read_params.single.offset = 0U;
2541 
2542 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2543 	if (!err) {
2544 		mcs_inst->busy = true;
2545 	}
2546 	return err;
2547 }
2548 #endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */
2549 
2550 #ifdef CONFIG_BT_MCC_OTS
bt_mcc_read_segments_obj_id(struct bt_conn * conn)2551 int bt_mcc_read_segments_obj_id(struct bt_conn *conn)
2552 {
2553 	struct mcs_instance_t *mcs_inst;
2554 	int err;
2555 
2556 	CHECKIF(conn == NULL) {
2557 		LOG_DBG("conn is NULL");
2558 
2559 		return -EINVAL;
2560 	}
2561 
2562 	mcs_inst = lookup_inst_by_conn(conn);
2563 	if (mcs_inst == NULL) {
2564 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2565 
2566 		return -EINVAL;
2567 	} else if (mcs_inst->busy) {
2568 
2569 		LOG_DBG("mcs_inst busy");
2570 		return -EBUSY;
2571 	} else if (mcs_inst->segments_obj_id_handle == 0) {
2572 		LOG_DBG("handle not set");
2573 
2574 		return -EINVAL;
2575 	}
2576 
2577 	mcs_inst->read_params.func = mcc_read_segments_obj_id_cb;
2578 	mcs_inst->read_params.handle_count = 1;
2579 	mcs_inst->read_params.single.handle = mcs_inst->segments_obj_id_handle;
2580 	mcs_inst->read_params.single.offset = 0U;
2581 
2582 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2583 	if (!err) {
2584 		mcs_inst->busy = true;
2585 	}
2586 	return err;
2587 }
2588 
bt_mcc_read_current_track_obj_id(struct bt_conn * conn)2589 int bt_mcc_read_current_track_obj_id(struct bt_conn *conn)
2590 {
2591 	struct mcs_instance_t *mcs_inst;
2592 	int err;
2593 
2594 	CHECKIF(conn == NULL) {
2595 		LOG_DBG("conn is NULL");
2596 
2597 		return -EINVAL;
2598 	}
2599 
2600 	mcs_inst = lookup_inst_by_conn(conn);
2601 	if (mcs_inst == NULL) {
2602 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2603 
2604 		return -EINVAL;
2605 	} else if (mcs_inst->busy) {
2606 
2607 		LOG_DBG("mcs_inst busy");
2608 		return -EBUSY;
2609 	} else if (mcs_inst->current_track_obj_id_handle == 0) {
2610 		LOG_DBG("handle not set");
2611 
2612 		return -EINVAL;
2613 	}
2614 
2615 	mcs_inst->read_params.func = mcc_read_current_track_obj_id_cb;
2616 	mcs_inst->read_params.handle_count = 1;
2617 	mcs_inst->read_params.single.handle = mcs_inst->current_track_obj_id_handle;
2618 	mcs_inst->read_params.single.offset = 0U;
2619 
2620 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2621 	if (!err) {
2622 		mcs_inst->busy = true;
2623 	}
2624 	return err;
2625 }
2626 
bt_mcc_set_current_track_obj_id(struct bt_conn * conn,uint64_t obj_id)2627 int bt_mcc_set_current_track_obj_id(struct bt_conn *conn, uint64_t obj_id)
2628 {
2629 	struct mcs_instance_t *mcs_inst;
2630 	int err;
2631 
2632 	CHECKIF(conn == NULL) {
2633 		LOG_DBG("conn is NULL");
2634 
2635 		return -EINVAL;
2636 	}
2637 
2638 	CHECKIF(!BT_MCS_VALID_OBJ_ID(obj_id)) {
2639 		LOG_DBG("Object ID 0x%016llx invalid", obj_id);
2640 		return -EINVAL;
2641 	}
2642 
2643 	mcs_inst = lookup_inst_by_conn(conn);
2644 	if (mcs_inst == NULL) {
2645 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2646 
2647 		return -EINVAL;
2648 	} else if (mcs_inst->busy) {
2649 
2650 		LOG_DBG("mcs_inst busy");
2651 		return -EBUSY;
2652 	} else if (mcs_inst->current_track_obj_id_handle == 0) {
2653 		LOG_DBG("handle not set");
2654 
2655 		return -EINVAL;
2656 	}
2657 
2658 	sys_put_le48(obj_id, mcs_inst->write_buf);
2659 	mcs_inst->write_params.offset = 0;
2660 	mcs_inst->write_params.data = mcs_inst->write_buf;
2661 	mcs_inst->write_params.length = BT_OTS_OBJ_ID_SIZE;
2662 	mcs_inst->write_params.handle = mcs_inst->current_track_obj_id_handle;
2663 	mcs_inst->write_params.func = mcs_write_current_track_obj_id_cb;
2664 
2665 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, BT_OTS_OBJ_ID_SIZE, "Object Id");
2666 
2667 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2668 	if (!err) {
2669 		mcs_inst->busy = true;
2670 	}
2671 	return err;
2672 }
2673 
bt_mcc_read_next_track_obj_id(struct bt_conn * conn)2674 int bt_mcc_read_next_track_obj_id(struct bt_conn *conn)
2675 {
2676 	struct mcs_instance_t *mcs_inst;
2677 	int err;
2678 
2679 	CHECKIF(conn == NULL) {
2680 		LOG_DBG("conn is NULL");
2681 
2682 		return -EINVAL;
2683 	}
2684 
2685 	mcs_inst = lookup_inst_by_conn(conn);
2686 	if (mcs_inst == NULL) {
2687 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2688 
2689 		return -EINVAL;
2690 	} else if (mcs_inst->busy) {
2691 
2692 		LOG_DBG("mcs_inst busy");
2693 		return -EBUSY;
2694 	} else if (mcs_inst->next_track_obj_id_handle == 0) {
2695 		LOG_DBG("handle not set");
2696 
2697 		return -EINVAL;
2698 	}
2699 
2700 	mcs_inst->read_params.func = mcc_read_next_track_obj_id_cb;
2701 	mcs_inst->read_params.handle_count = 1;
2702 	mcs_inst->read_params.single.handle = mcs_inst->next_track_obj_id_handle;
2703 	mcs_inst->read_params.single.offset = 0U;
2704 
2705 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2706 	if (!err) {
2707 		mcs_inst->busy = true;
2708 	}
2709 	return err;
2710 }
2711 
bt_mcc_set_next_track_obj_id(struct bt_conn * conn,uint64_t obj_id)2712 int bt_mcc_set_next_track_obj_id(struct bt_conn *conn, uint64_t obj_id)
2713 {
2714 	struct mcs_instance_t *mcs_inst;
2715 	int err;
2716 
2717 	CHECKIF(conn == NULL) {
2718 		LOG_DBG("conn is NULL");
2719 
2720 		return -EINVAL;
2721 	}
2722 
2723 	CHECKIF(!BT_MCS_VALID_OBJ_ID(obj_id)) {
2724 		LOG_DBG("Object ID 0x%016llx invalid", obj_id);
2725 		return -EINVAL;
2726 	}
2727 
2728 	mcs_inst = lookup_inst_by_conn(conn);
2729 	if (mcs_inst == NULL) {
2730 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2731 
2732 		return -EINVAL;
2733 	} else if (mcs_inst->busy) {
2734 
2735 		LOG_DBG("mcs_inst busy");
2736 		return -EBUSY;
2737 	} else if (mcs_inst->next_track_obj_id_handle == 0) {
2738 		LOG_DBG("handle not set");
2739 
2740 		return -EINVAL;
2741 	}
2742 
2743 	sys_put_le48(obj_id, mcs_inst->write_buf);
2744 	mcs_inst->write_params.offset = 0;
2745 	mcs_inst->write_params.data = mcs_inst->write_buf;
2746 	mcs_inst->write_params.length = BT_OTS_OBJ_ID_SIZE;
2747 	mcs_inst->write_params.handle = mcs_inst->next_track_obj_id_handle;
2748 	mcs_inst->write_params.func = mcs_write_next_track_obj_id_cb;
2749 
2750 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, BT_OTS_OBJ_ID_SIZE, "Object Id");
2751 
2752 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2753 	if (!err) {
2754 		mcs_inst->busy = true;
2755 	}
2756 	return err;
2757 }
2758 
bt_mcc_read_parent_group_obj_id(struct bt_conn * conn)2759 int bt_mcc_read_parent_group_obj_id(struct bt_conn *conn)
2760 {
2761 	struct mcs_instance_t *mcs_inst;
2762 	int err;
2763 
2764 	CHECKIF(conn == NULL) {
2765 		LOG_DBG("conn is NULL");
2766 
2767 		return -EINVAL;
2768 	}
2769 
2770 	mcs_inst = lookup_inst_by_conn(conn);
2771 	if (mcs_inst == NULL) {
2772 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2773 
2774 		return -EINVAL;
2775 	} else if (mcs_inst->busy) {
2776 
2777 		LOG_DBG("mcs_inst busy");
2778 		return -EBUSY;
2779 	} else if (mcs_inst->parent_group_obj_id_handle == 0) {
2780 		LOG_DBG("handle not set");
2781 
2782 		return -EINVAL;
2783 	}
2784 
2785 	mcs_inst->read_params.func = mcc_read_parent_group_obj_id_cb;
2786 	mcs_inst->read_params.handle_count = 1;
2787 	mcs_inst->read_params.single.handle = mcs_inst->parent_group_obj_id_handle;
2788 	mcs_inst->read_params.single.offset = 0U;
2789 
2790 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2791 	if (!err) {
2792 		mcs_inst->busy = true;
2793 	}
2794 	return err;
2795 }
2796 
bt_mcc_read_current_group_obj_id(struct bt_conn * conn)2797 int bt_mcc_read_current_group_obj_id(struct bt_conn *conn)
2798 {
2799 	struct mcs_instance_t *mcs_inst;
2800 	int err;
2801 
2802 	CHECKIF(conn == NULL) {
2803 		LOG_DBG("conn is NULL");
2804 
2805 		return -EINVAL;
2806 	}
2807 
2808 	mcs_inst = lookup_inst_by_conn(conn);
2809 	if (mcs_inst == NULL) {
2810 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2811 
2812 		return -EINVAL;
2813 	} else if (mcs_inst->busy) {
2814 
2815 		LOG_DBG("mcs_inst busy");
2816 		return -EBUSY;
2817 	} else if (mcs_inst->current_group_obj_id_handle == 0) {
2818 		LOG_DBG("handle not set");
2819 
2820 		return -EINVAL;
2821 	}
2822 
2823 	mcs_inst->read_params.func = mcc_read_current_group_obj_id_cb;
2824 	mcs_inst->read_params.handle_count = 1;
2825 	mcs_inst->read_params.single.handle = mcs_inst->current_group_obj_id_handle;
2826 	mcs_inst->read_params.single.offset = 0U;
2827 
2828 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2829 	if (!err) {
2830 		mcs_inst->busy = true;
2831 	}
2832 	return err;
2833 }
2834 
bt_mcc_set_current_group_obj_id(struct bt_conn * conn,uint64_t obj_id)2835 int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t obj_id)
2836 {
2837 	struct mcs_instance_t *mcs_inst;
2838 	int err;
2839 
2840 	CHECKIF(conn == NULL) {
2841 		LOG_DBG("conn is NULL");
2842 
2843 		return -EINVAL;
2844 	}
2845 
2846 	CHECKIF(!BT_MCS_VALID_OBJ_ID(obj_id)) {
2847 		LOG_DBG("Object ID 0x%016llx invalid", obj_id);
2848 		return -EINVAL;
2849 	}
2850 
2851 	mcs_inst = lookup_inst_by_conn(conn);
2852 	if (mcs_inst == NULL) {
2853 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2854 
2855 		return -EINVAL;
2856 	} else if (mcs_inst->busy) {
2857 
2858 		LOG_DBG("mcs_inst busy");
2859 		return -EBUSY;
2860 	} else if (mcs_inst->current_group_obj_id_handle == 0) {
2861 		LOG_DBG("handle not set");
2862 
2863 		return -EINVAL;
2864 	}
2865 
2866 	sys_put_le48(obj_id, mcs_inst->write_buf);
2867 	mcs_inst->write_params.offset = 0;
2868 	mcs_inst->write_params.data = mcs_inst->write_buf;
2869 	mcs_inst->write_params.length = BT_OTS_OBJ_ID_SIZE;
2870 	mcs_inst->write_params.handle = mcs_inst->current_group_obj_id_handle;
2871 	mcs_inst->write_params.func = mcs_write_current_group_obj_id_cb;
2872 
2873 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, BT_OTS_OBJ_ID_SIZE, "Object Id");
2874 
2875 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2876 	if (!err) {
2877 		mcs_inst->busy = true;
2878 	}
2879 	return err;
2880 }
2881 #endif /* CONFIG_BT_MCC_OTS */
2882 
2883 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER)
bt_mcc_read_playing_order(struct bt_conn * conn)2884 int bt_mcc_read_playing_order(struct bt_conn *conn)
2885 {
2886 	struct mcs_instance_t *mcs_inst;
2887 	int err;
2888 
2889 	CHECKIF(conn == NULL) {
2890 		LOG_DBG("conn is NULL");
2891 
2892 		return -EINVAL;
2893 	}
2894 
2895 	mcs_inst = lookup_inst_by_conn(conn);
2896 	if (mcs_inst == NULL) {
2897 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2898 
2899 		return -EINVAL;
2900 	} else if (mcs_inst->busy) {
2901 
2902 		LOG_DBG("mcs_inst busy");
2903 		return -EBUSY;
2904 	} else if (mcs_inst->playing_order_handle == 0) {
2905 		LOG_DBG("handle not set");
2906 
2907 		return -EINVAL;
2908 	}
2909 
2910 	mcs_inst->read_params.func = mcc_read_playing_order_cb;
2911 	mcs_inst->read_params.handle_count = 1;
2912 	mcs_inst->read_params.single.handle = mcs_inst->playing_order_handle;
2913 	mcs_inst->read_params.single.offset = 0U;
2914 
2915 	err = bt_gatt_read(conn, &mcs_inst->read_params);
2916 	if (!err) {
2917 		mcs_inst->busy = true;
2918 	}
2919 	return err;
2920 }
2921 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */
2922 
2923 #if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER)
bt_mcc_set_playing_order(struct bt_conn * conn,uint8_t order)2924 int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order)
2925 {
2926 	struct mcs_instance_t *mcs_inst;
2927 	int err;
2928 
2929 	CHECKIF(conn == NULL) {
2930 		LOG_DBG("conn is NULL");
2931 
2932 		return -EINVAL;
2933 	}
2934 
2935 	mcs_inst = lookup_inst_by_conn(conn);
2936 	if (mcs_inst == NULL) {
2937 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2938 
2939 		return -EINVAL;
2940 	} else if (mcs_inst->busy) {
2941 
2942 		LOG_DBG("mcs_inst busy");
2943 		return -EBUSY;
2944 	} else if (mcs_inst->playing_order_handle == 0) {
2945 		LOG_DBG("handle not set");
2946 
2947 		return -EINVAL;
2948 	}
2949 
2950 	CHECKIF(!IN_RANGE(order,
2951 			  BT_MCS_PLAYING_ORDER_SINGLE_ONCE,
2952 			  BT_MCS_PLAYING_ORDER_SHUFFLE_REPEAT)) {
2953 		LOG_DBG("Invalid playing order 0x%02X", order);
2954 
2955 		return -EINVAL;
2956 	}
2957 
2958 	(void)memcpy(mcs_inst->write_buf, &order, sizeof(order));
2959 
2960 	mcs_inst->write_params.offset = 0;
2961 	mcs_inst->write_params.data = mcs_inst->write_buf;
2962 	mcs_inst->write_params.length = sizeof(order);
2963 	mcs_inst->write_params.handle = mcs_inst->playing_order_handle;
2964 	mcs_inst->write_params.func = mcs_write_playing_order_cb;
2965 
2966 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(order), "Playing order");
2967 
2968 	err = bt_gatt_write(conn, &mcs_inst->write_params);
2969 	if (!err) {
2970 		mcs_inst->busy = true;
2971 	}
2972 	return err;
2973 }
2974 #endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */
2975 
2976 #if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED)
bt_mcc_read_playing_orders_supported(struct bt_conn * conn)2977 int bt_mcc_read_playing_orders_supported(struct bt_conn *conn)
2978 {
2979 	struct mcs_instance_t *mcs_inst;
2980 	int err;
2981 
2982 	CHECKIF(conn == NULL) {
2983 		LOG_DBG("conn is NULL");
2984 
2985 		return -EINVAL;
2986 	}
2987 
2988 	mcs_inst = lookup_inst_by_conn(conn);
2989 	if (mcs_inst == NULL) {
2990 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
2991 
2992 		return -EINVAL;
2993 	} else if (mcs_inst->busy) {
2994 
2995 		LOG_DBG("mcs_inst busy");
2996 		return -EBUSY;
2997 	} else if (mcs_inst->playing_orders_supported_handle == 0) {
2998 		LOG_DBG("handle not set");
2999 
3000 		return -EINVAL;
3001 	}
3002 
3003 	mcs_inst->read_params.func = mcc_read_playing_orders_supported_cb;
3004 	mcs_inst->read_params.handle_count = 1;
3005 	mcs_inst->read_params.single.handle = mcs_inst->playing_orders_supported_handle;
3006 	mcs_inst->read_params.single.offset = 0U;
3007 
3008 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3009 	if (!err) {
3010 		mcs_inst->busy = true;
3011 	}
3012 	return err;
3013 }
3014 #endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */
3015 
3016 #if defined(CONFIG_BT_MCC_READ_MEDIA_STATE)
bt_mcc_read_media_state(struct bt_conn * conn)3017 int bt_mcc_read_media_state(struct bt_conn *conn)
3018 {
3019 	struct mcs_instance_t *mcs_inst;
3020 	int err;
3021 
3022 	CHECKIF(conn == NULL) {
3023 		LOG_DBG("conn is NULL");
3024 
3025 		return -EINVAL;
3026 	}
3027 
3028 	mcs_inst = lookup_inst_by_conn(conn);
3029 	if (mcs_inst == NULL) {
3030 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3031 
3032 		return -EINVAL;
3033 	} else if (mcs_inst->busy) {
3034 
3035 		LOG_DBG("mcs_inst busy");
3036 		return -EBUSY;
3037 	} else if (mcs_inst->media_state_handle == 0) {
3038 		LOG_DBG("handle not set");
3039 
3040 		return -EINVAL;
3041 	}
3042 
3043 	mcs_inst->read_params.func = mcc_read_media_state_cb;
3044 	mcs_inst->read_params.handle_count = 1;
3045 	mcs_inst->read_params.single.handle = mcs_inst->media_state_handle;
3046 	mcs_inst->read_params.single.offset = 0U;
3047 
3048 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3049 	if (!err) {
3050 		mcs_inst->busy = true;
3051 	}
3052 	return err;
3053 }
3054 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */
3055 
3056 #if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT)
bt_mcc_send_cmd(struct bt_conn * conn,const struct mpl_cmd * cmd)3057 int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd)
3058 {
3059 	struct mcs_instance_t *mcs_inst;
3060 	size_t length;
3061 	int err;
3062 
3063 	CHECKIF(conn == NULL) {
3064 		LOG_DBG("conn is NULL");
3065 
3066 		return -EINVAL;
3067 	}
3068 
3069 	mcs_inst = lookup_inst_by_conn(conn);
3070 	if (mcs_inst == NULL) {
3071 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3072 
3073 		return -EINVAL;
3074 	} else if (mcs_inst->busy) {
3075 
3076 		LOG_DBG("mcs_inst busy");
3077 		return -EBUSY;
3078 	} else if (mcs_inst->cp_handle == 0) {
3079 		LOG_DBG("handle not set");
3080 
3081 		return -EINVAL;
3082 	}
3083 
3084 	CHECKIF(cmd == NULL) {
3085 		LOG_DBG("cmd is NULL");
3086 
3087 		return -EINVAL;
3088 	}
3089 
3090 	CHECKIF(!BT_MCS_VALID_OP(cmd->opcode)) {
3091 		LOG_DBG("Opcode 0x%02X is invalid", cmd->opcode);
3092 
3093 		return -EINVAL;
3094 	}
3095 
3096 	length = sizeof(cmd->opcode);
3097 	(void)memcpy(mcs_inst->write_buf, &cmd->opcode, length);
3098 	if (cmd->use_param) {
3099 		length += sizeof(cmd->param);
3100 		(void)memcpy(&mcs_inst->write_buf[sizeof(cmd->opcode)], &cmd->param,
3101 		       sizeof(cmd->param));
3102 	}
3103 
3104 	mcs_inst->write_params.offset = 0;
3105 	mcs_inst->write_params.data = mcs_inst->write_buf;
3106 	mcs_inst->write_params.length = length;
3107 	mcs_inst->write_params.handle = mcs_inst->cp_handle;
3108 	mcs_inst->write_params.func = mcs_write_cp_cb;
3109 
3110 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, sizeof(*cmd), "Command sent");
3111 
3112 	err = bt_gatt_write(conn, &mcs_inst->write_params);
3113 	if (!err) {
3114 		mcs_inst->busy = true;
3115 	}
3116 	return err;
3117 }
3118 #endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */
3119 
3120 #if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
bt_mcc_read_opcodes_supported(struct bt_conn * conn)3121 int bt_mcc_read_opcodes_supported(struct bt_conn *conn)
3122 {
3123 	struct mcs_instance_t *mcs_inst;
3124 	int err;
3125 
3126 	CHECKIF(conn == NULL) {
3127 		LOG_DBG("conn is NULL");
3128 
3129 		return -EINVAL;
3130 	}
3131 
3132 	mcs_inst = lookup_inst_by_conn(conn);
3133 	if (mcs_inst == NULL) {
3134 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3135 
3136 		return -EINVAL;
3137 	} else if (mcs_inst->busy) {
3138 
3139 		LOG_DBG("mcs_inst busy");
3140 		return -EBUSY;
3141 	} else if (mcs_inst->opcodes_supported_handle == 0) {
3142 		LOG_DBG("handle not set");
3143 
3144 		return -EINVAL;
3145 	}
3146 
3147 	mcs_inst->read_params.func = mcc_read_opcodes_supported_cb;
3148 	mcs_inst->read_params.handle_count = 1;
3149 	mcs_inst->read_params.single.handle = mcs_inst->opcodes_supported_handle;
3150 	mcs_inst->read_params.single.offset = 0U;
3151 
3152 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3153 	if (!err) {
3154 		mcs_inst->busy = true;
3155 	}
3156 	return err;
3157 }
3158 #endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */
3159 
3160 #ifdef CONFIG_BT_MCC_OTS
bt_mcc_send_search(struct bt_conn * conn,const struct mpl_search * search)3161 int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search)
3162 {
3163 	struct mcs_instance_t *mcs_inst;
3164 	int err;
3165 
3166 	CHECKIF(conn == NULL) {
3167 		LOG_DBG("conn is NULL");
3168 
3169 		return -EINVAL;
3170 	}
3171 
3172 	mcs_inst = lookup_inst_by_conn(conn);
3173 	if (mcs_inst == NULL) {
3174 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3175 
3176 		return -EINVAL;
3177 	} else if (mcs_inst->busy) {
3178 
3179 		LOG_DBG("mcs_inst busy");
3180 		return -EBUSY;
3181 	} else if (mcs_inst->scp_handle == 0) {
3182 		LOG_DBG("handle not set");
3183 
3184 		return -EINVAL;
3185 	}
3186 
3187 	CHECKIF(search == NULL) {
3188 		LOG_DBG("search is NULL");
3189 
3190 		return -EINVAL;
3191 	}
3192 
3193 	CHECKIF(!IN_RANGE(search->len, SEARCH_LEN_MIN, SEARCH_LEN_MAX)) {
3194 		LOG_DBG("Invalid search->len: %u", search->len);
3195 
3196 		return -EINVAL;
3197 	}
3198 
3199 	(void)memcpy(mcs_inst->write_buf, &search->search, search->len);
3200 
3201 	mcs_inst->write_params.offset = 0;
3202 	mcs_inst->write_params.data = mcs_inst->write_buf;
3203 	mcs_inst->write_params.length = search->len;
3204 	mcs_inst->write_params.handle = mcs_inst->scp_handle;
3205 	mcs_inst->write_params.func = mcs_write_scp_cb;
3206 
3207 	LOG_HEXDUMP_DBG(mcs_inst->write_params.data, search->len, "Search sent");
3208 
3209 	err = bt_gatt_write(conn, &mcs_inst->write_params);
3210 	if (!err) {
3211 		mcs_inst->busy = true;
3212 	}
3213 	return err;
3214 }
3215 
bt_mcc_read_search_results_obj_id(struct bt_conn * conn)3216 int bt_mcc_read_search_results_obj_id(struct bt_conn *conn)
3217 {
3218 	struct mcs_instance_t *mcs_inst;
3219 	int err;
3220 
3221 	CHECKIF(conn == NULL) {
3222 		LOG_DBG("conn is NULL");
3223 
3224 		return -EINVAL;
3225 	}
3226 
3227 	mcs_inst = lookup_inst_by_conn(conn);
3228 	if (mcs_inst == NULL) {
3229 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3230 
3231 		return -EINVAL;
3232 	} else if (mcs_inst->busy) {
3233 
3234 		LOG_DBG("mcs_inst busy");
3235 		return -EBUSY;
3236 	} else if (mcs_inst->search_results_obj_id_handle == 0) {
3237 		LOG_DBG("handle not set");
3238 
3239 		return -EINVAL;
3240 	}
3241 
3242 	mcs_inst->read_params.func = mcc_read_search_results_obj_id_cb;
3243 	mcs_inst->read_params.handle_count = 1;
3244 	mcs_inst->read_params.single.handle = mcs_inst->search_results_obj_id_handle;
3245 	mcs_inst->read_params.single.offset = 0U;
3246 
3247 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3248 	if (!err) {
3249 		mcs_inst->busy = true;
3250 	}
3251 	return err;
3252 }
3253 #endif /* CONFIG_BT_MCC_OTS */
3254 
3255 #if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID)
bt_mcc_read_content_control_id(struct bt_conn * conn)3256 int bt_mcc_read_content_control_id(struct bt_conn *conn)
3257 {
3258 	struct mcs_instance_t *mcs_inst;
3259 	int err;
3260 
3261 	CHECKIF(conn == NULL) {
3262 		LOG_DBG("conn is NULL");
3263 
3264 		return -EINVAL;
3265 	}
3266 
3267 	mcs_inst = lookup_inst_by_conn(conn);
3268 	if (mcs_inst == NULL) {
3269 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3270 
3271 		return -EINVAL;
3272 	} else if (mcs_inst->busy) {
3273 
3274 		LOG_DBG("mcs_inst busy");
3275 		return -EBUSY;
3276 	} else if (mcs_inst->content_control_id_handle == 0) {
3277 		LOG_DBG("handle not set");
3278 
3279 		return -EINVAL;
3280 	}
3281 
3282 	mcs_inst->read_params.func = mcc_read_content_control_id_cb;
3283 	mcs_inst->read_params.handle_count = 1;
3284 	mcs_inst->read_params.single.handle = mcs_inst->content_control_id_handle;
3285 	mcs_inst->read_params.single.offset = 0U;
3286 
3287 	err = bt_gatt_read(conn, &mcs_inst->read_params);
3288 	if (!err) {
3289 		mcs_inst->busy = true;
3290 	}
3291 	return err;
3292 }
3293 #endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */
3294 
3295 #ifdef CONFIG_BT_MCC_OTS
3296 
on_obj_selected(struct bt_ots_client * otc_inst,struct bt_conn * conn,int result)3297 void on_obj_selected(struct bt_ots_client *otc_inst,
3298 		     struct bt_conn *conn, int result)
3299 {
3300 	LOG_DBG("Current object selected");
3301 	/* TODO: Read metadata here? */
3302 	/* For now: Left to the application */
3303 
3304 	/* Only one object at a time is selected in OTS */
3305 	/* When the selected callback comes, a new object is selected */
3306 	/* Reset the object buffer */
3307 	net_buf_simple_reset(&otc_obj_buf);
3308 
3309 	if (mcc_cb && mcc_cb->otc_obj_selected) {
3310 		mcc_cb->otc_obj_selected(conn, OLCP_RESULT_TO_ERROR(result));
3311 	}
3312 }
3313 
3314 /* TODO: Merge the object callback functions into one */
3315 /* 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)3316 int on_icon_content(struct bt_ots_client *otc_inst, struct bt_conn *conn,
3317 		    uint32_t offset, uint32_t len, uint8_t *data_p,
3318 		    bool is_complete)
3319 {
3320 	int cb_err = 0;
3321 
3322 	LOG_DBG("Received Media Player Icon content, %i bytes at offset %i",
3323 		len, offset);
3324 
3325 	LOG_HEXDUMP_DBG(data_p, len, "Icon content");
3326 
3327 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3328 		LOG_WRN("Can not fit whole object");
3329 		cb_err = -EMSGSIZE;
3330 	}
3331 
3332 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3333 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3334 
3335 	if (is_complete) {
3336 		LOG_DBG("Icon object received");
3337 
3338 		if (mcc_cb && mcc_cb->otc_icon_object) {
3339 			mcc_cb->otc_icon_object(conn, cb_err, &otc_obj_buf);
3340 		}
3341 		/* Reset buf in case the same object is read again without */
3342 		/* calling select in between */
3343 		net_buf_simple_reset(&otc_obj_buf);
3344 	}
3345 
3346 	return BT_OTS_CONTINUE;
3347 }
3348 
3349 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3350 struct track_seg_t {
3351 	uint8_t            name_len;
3352 	char               name[CONFIG_BT_MCC_SEGMENT_NAME_MAX];
3353 	int32_t            pos;
3354 };
3355 
3356 struct track_segs_t {
3357 	uint16_t              cnt;
3358 	struct track_seg_t    segs[CONFIG_BT_MCC_TRACK_SEGS_MAX_CNT];
3359 };
3360 
decode_track_segments(struct net_buf_simple * buff,struct track_segs_t * track_segs)3361 static void decode_track_segments(struct net_buf_simple *buff,
3362 				  struct track_segs_t *track_segs)
3363 {
3364 	uint16_t i;
3365 	struct track_seg_t *seg;
3366 	uint8_t *name;
3367 	struct net_buf_simple tmp_buf;
3368 
3369 	/* Copy the buf, to not consume the original in this debug function */
3370 	net_buf_simple_clone(buff, &tmp_buf);
3371 
3372 	while (tmp_buf.len &&
3373 	       track_segs->cnt < CONFIG_BT_MCC_TRACK_SEGS_MAX_CNT) {
3374 
3375 		i = track_segs->cnt++;
3376 		seg = &track_segs->segs[i];
3377 
3378 		seg->name_len =  net_buf_simple_pull_u8(&tmp_buf);
3379 		if (seg->name_len + sizeof(int32_t) > tmp_buf.len) {
3380 			LOG_WRN("Segment too long");
3381 			return;
3382 		}
3383 
3384 		if (seg->name_len) {
3385 
3386 			name = net_buf_simple_pull_mem(&tmp_buf, seg->name_len);
3387 
3388 			if (seg->name_len >= CONFIG_BT_MCC_SEGMENT_NAME_MAX) {
3389 				seg->name_len =
3390 					CONFIG_BT_MCC_SEGMENT_NAME_MAX - 1;
3391 			}
3392 			(void)memcpy(seg->name, name, seg->name_len);
3393 		}
3394 		seg->name[seg->name_len] = '\0';
3395 
3396 		track_segs->segs[i].pos = (int32_t)net_buf_simple_pull_le32(&tmp_buf);
3397 	}
3398 }
3399 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3400 
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)3401 int on_track_segments_content(struct bt_ots_client *otc_inst,
3402 			      struct bt_conn *conn, uint32_t offset,
3403 			      uint32_t len, uint8_t *data_p, bool is_complete)
3404 {
3405 	int cb_err = 0;
3406 
3407 	LOG_DBG("Received Track Segments content, %i bytes at offset %i",
3408 		len, offset);
3409 
3410 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3411 		LOG_WRN("Can not fit whole object");
3412 		cb_err = -EMSGSIZE;
3413 	}
3414 
3415 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3416 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3417 
3418 	if (is_complete) {
3419 		LOG_DBG("Track segment object received");
3420 
3421 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3422 		struct track_segs_t track_segments;
3423 
3424 		track_segments.cnt = 0;
3425 		decode_track_segments(&otc_obj_buf, &track_segments);
3426 		for (int i = 0; i < track_segments.cnt; i++) {
3427 			LOG_DBG("Track segment %i:", i);
3428 			LOG_DBG("\t-Name\t:%s",
3429 			       track_segments.segs[i].name);
3430 			LOG_DBG("\t-Position\t:%d", track_segments.segs[i].pos);
3431 		}
3432 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3433 
3434 		if (mcc_cb && mcc_cb->otc_track_segments_object) {
3435 			mcc_cb->otc_track_segments_object(conn,
3436 							   cb_err, &otc_obj_buf);
3437 		}
3438 
3439 		net_buf_simple_reset(&otc_obj_buf);
3440 	}
3441 
3442 	return BT_OTS_CONTINUE;
3443 }
3444 
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)3445 int on_current_track_content(struct bt_ots_client *otc_inst,
3446 			     struct bt_conn *conn, uint32_t offset,
3447 			     uint32_t len, uint8_t *data_p, bool is_complete)
3448 {
3449 	int cb_err = 0;
3450 
3451 	LOG_DBG("Received Current Track content, %i bytes at offset %i",
3452 	       len, offset);
3453 
3454 	LOG_HEXDUMP_DBG(data_p, len, "Track content");
3455 
3456 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3457 		LOG_WRN("Can not fit whole object");
3458 		cb_err = -EMSGSIZE;
3459 	}
3460 
3461 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3462 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3463 
3464 	if (is_complete) {
3465 		LOG_DBG("Current Track Object received");
3466 
3467 		if (mcc_cb && mcc_cb->otc_current_track_object) {
3468 			mcc_cb->otc_current_track_object(conn, cb_err, &otc_obj_buf);
3469 		}
3470 
3471 		net_buf_simple_reset(&otc_obj_buf);
3472 	}
3473 
3474 	return BT_OTS_CONTINUE;
3475 }
3476 
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)3477 int on_next_track_content(struct bt_ots_client *otc_inst,
3478 			  struct bt_conn *conn, uint32_t offset, uint32_t len,
3479 			  uint8_t *data_p, bool is_complete)
3480 {
3481 	int cb_err = 0;
3482 
3483 	LOG_DBG("Received Next Track content, %i bytes at offset %i",
3484 	       len, offset);
3485 
3486 	LOG_HEXDUMP_DBG(data_p, len, "Track content");
3487 
3488 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3489 		LOG_WRN("Can not fit whole object");
3490 		cb_err = -EMSGSIZE;
3491 	}
3492 
3493 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3494 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3495 
3496 	if (is_complete) {
3497 		LOG_DBG("Next Track Object received");
3498 
3499 		if (mcc_cb && mcc_cb->otc_next_track_object) {
3500 			mcc_cb->otc_next_track_object(conn, cb_err, &otc_obj_buf);
3501 		}
3502 
3503 		net_buf_simple_reset(&otc_obj_buf);
3504 	}
3505 
3506 	return BT_OTS_CONTINUE;
3507 }
3508 
3509 
3510 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3511 struct id_list_elem_t {
3512 	uint8_t  type;
3513 	uint64_t id;
3514 };
3515 
3516 struct id_list_t {
3517 	struct id_list_elem_t ids[CONFIG_BT_MCC_GROUP_RECORDS_MAX];
3518 	uint16_t cnt;
3519 };
3520 
decode_group(struct net_buf_simple * buff,struct id_list_t * ids)3521 static void decode_group(struct net_buf_simple *buff,
3522 			 struct id_list_t *ids)
3523 {
3524 	struct net_buf_simple tmp_buf;
3525 
3526 	/* Copy the buf, to not consume the original in this debug function */
3527 	net_buf_simple_clone(buff, &tmp_buf);
3528 
3529 	while ((tmp_buf.len) && (ids->cnt < CONFIG_BT_MCC_GROUP_RECORDS_MAX)) {
3530 		ids->ids[ids->cnt].type = net_buf_simple_pull_u8(&tmp_buf);
3531 		ids->ids[ids->cnt++].id = net_buf_simple_pull_le48(&tmp_buf);
3532 	}
3533 }
3534 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3535 
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)3536 int on_parent_group_content(struct bt_ots_client *otc_inst,
3537 			    struct bt_conn *conn, uint32_t offset,
3538 			    uint32_t len, uint8_t *data_p, bool is_complete)
3539 {
3540 	int cb_err = 0;
3541 
3542 	LOG_DBG("Received Parent Group content, %i bytes at offset %i",
3543 		len, offset);
3544 
3545 	LOG_HEXDUMP_DBG(data_p, len, "Group content");
3546 
3547 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3548 		LOG_WRN("Can not fit whole object");
3549 		cb_err = -EMSGSIZE;
3550 	}
3551 
3552 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3553 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3554 
3555 	if (is_complete) {
3556 		LOG_DBG("Parent Group object received");
3557 
3558 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3559 		struct id_list_t group = {0};
3560 
3561 		decode_group(&otc_obj_buf, &group);
3562 		for (int i = 0; i < group.cnt; i++) {
3563 			char t[BT_OTS_OBJ_ID_STR_LEN];
3564 
3565 			(void)bt_ots_obj_id_to_str(group.ids[i].id, t,
3566 						   BT_OTS_OBJ_ID_STR_LEN);
3567 			LOG_DBG("Object type: %d, object  ID: %s",
3568 			       group.ids[i].type, t);
3569 		}
3570 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3571 
3572 		if (mcc_cb && mcc_cb->otc_parent_group_object) {
3573 			mcc_cb->otc_parent_group_object(conn, cb_err, &otc_obj_buf);
3574 		}
3575 
3576 		net_buf_simple_reset(&otc_obj_buf);
3577 	}
3578 
3579 	return BT_OTS_CONTINUE;
3580 }
3581 
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)3582 int on_current_group_content(struct bt_ots_client *otc_inst,
3583 			     struct bt_conn *conn, uint32_t offset,
3584 			     uint32_t len, uint8_t *data_p, bool is_complete)
3585 {
3586 	int cb_err = 0;
3587 
3588 	LOG_DBG("Received Current Group content, %i bytes at offset %i",
3589 		len, offset);
3590 
3591 	LOG_HEXDUMP_DBG(data_p, len, "Group content");
3592 
3593 	if (len > net_buf_simple_tailroom(&otc_obj_buf)) {
3594 		LOG_WRN("Can not fit whole object");
3595 		cb_err = -EMSGSIZE;
3596 	}
3597 
3598 	net_buf_simple_add_mem(&otc_obj_buf, data_p,
3599 			       MIN(net_buf_simple_tailroom(&otc_obj_buf), len));
3600 
3601 	if (is_complete) {
3602 		LOG_DBG("Current Group object received");
3603 
3604 #if CONFIG_BT_MCC_LOG_LEVEL_DBG
3605 		struct id_list_t group = {0};
3606 
3607 		decode_group(&otc_obj_buf, &group);
3608 		for (int i = 0; i < group.cnt; i++) {
3609 			char t[BT_OTS_OBJ_ID_STR_LEN];
3610 
3611 			(void)bt_ots_obj_id_to_str(group.ids[i].id, t,
3612 						   BT_OTS_OBJ_ID_STR_LEN);
3613 			LOG_DBG("Object type: %d, object  ID: %s",
3614 			       group.ids[i].type, t);
3615 		}
3616 #endif /* CONFIG_BT_MCC_LOG_LEVEL_DBG */
3617 
3618 		if (mcc_cb && mcc_cb->otc_current_group_object) {
3619 			mcc_cb->otc_current_group_object(conn, cb_err, &otc_obj_buf);
3620 		}
3621 
3622 		net_buf_simple_reset(&otc_obj_buf);
3623 	}
3624 
3625 	return BT_OTS_CONTINUE;
3626 }
3627 
on_object_metadata(struct bt_ots_client * otc_inst,struct bt_conn * conn,int err,uint8_t metadata_read)3628 void on_object_metadata(struct bt_ots_client *otc_inst,
3629 			struct bt_conn *conn, int err,
3630 			uint8_t metadata_read)
3631 {
3632 	LOG_INF("Object's meta data:");
3633 	LOG_INF("\tCurrent size\t:%u", otc_inst->cur_object.size.cur);
3634 
3635 	if (otc_inst->cur_object.size.cur > otc_obj_buf.size) {
3636 		LOG_DBG("Object larger than allocated buffer");
3637 	}
3638 
3639 	bt_ots_metadata_display(&otc_inst->cur_object, 1);
3640 
3641 	if (mcc_cb && mcc_cb->otc_obj_metadata) {
3642 		mcc_cb->otc_obj_metadata(conn, err);
3643 	}
3644 }
3645 
bt_mcc_otc_read_object_metadata(struct bt_conn * conn)3646 int bt_mcc_otc_read_object_metadata(struct bt_conn *conn)
3647 {
3648 	struct mcs_instance_t *mcs_inst;
3649 	int err;
3650 
3651 	CHECKIF(conn == NULL) {
3652 		LOG_DBG("conn is NULL");
3653 
3654 		return -EINVAL;
3655 	}
3656 
3657 	mcs_inst = lookup_inst_by_conn(conn);
3658 	if (mcs_inst == NULL) {
3659 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3660 
3661 		return -EINVAL;
3662 	} else if (mcs_inst->busy) {
3663 
3664 		LOG_DBG("mcs_inst busy");
3665 		return -EBUSY;
3666 	}
3667 
3668 	err = bt_ots_client_read_object_metadata(&mcs_inst->otc, conn,
3669 						 BT_OTS_METADATA_REQ_ALL);
3670 	if (err) {
3671 		LOG_DBG("Error reading the object: %d", err);
3672 	}
3673 
3674 	return err;
3675 }
3676 
3677 
bt_mcc_otc_read_icon_object(struct bt_conn * conn)3678 int bt_mcc_otc_read_icon_object(struct bt_conn *conn)
3679 {
3680 	struct mcs_instance_t *mcs_inst;
3681 	int err;
3682 
3683 	CHECKIF(conn == NULL) {
3684 		LOG_DBG("conn is NULL");
3685 
3686 		return -EINVAL;
3687 	}
3688 
3689 	mcs_inst = lookup_inst_by_conn(conn);
3690 	if (mcs_inst == NULL) {
3691 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3692 
3693 		return -EINVAL;
3694 	} else if (mcs_inst->busy) {
3695 
3696 		LOG_DBG("mcs_inst busy");
3697 		return -EBUSY;
3698 	}
3699 
3700 	mcs_inst->otc.cb->obj_data_read = on_icon_content;
3701 
3702 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3703 	if (err) {
3704 		LOG_DBG("Error reading the object: %d", err);
3705 	}
3706 
3707 	return err;
3708 }
3709 
bt_mcc_otc_read_track_segments_object(struct bt_conn * conn)3710 int bt_mcc_otc_read_track_segments_object(struct bt_conn *conn)
3711 {
3712 	struct mcs_instance_t *mcs_inst;
3713 	int err;
3714 
3715 	CHECKIF(conn == NULL) {
3716 		LOG_DBG("conn is NULL");
3717 
3718 		return -EINVAL;
3719 	}
3720 
3721 	mcs_inst = lookup_inst_by_conn(conn);
3722 	if (mcs_inst == NULL) {
3723 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3724 
3725 		return -EINVAL;
3726 	} else if (mcs_inst->busy) {
3727 
3728 		LOG_DBG("mcs_inst busy");
3729 		return -EBUSY;
3730 	}
3731 
3732 	/* TODO: Assumes object is already selected */
3733 	mcs_inst->otc.cb->obj_data_read = on_track_segments_content;
3734 
3735 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3736 	if (err) {
3737 		LOG_DBG("Error reading the object: %d", err);
3738 	}
3739 
3740 	return err;
3741 }
3742 
bt_mcc_otc_read_current_track_object(struct bt_conn * conn)3743 int bt_mcc_otc_read_current_track_object(struct bt_conn *conn)
3744 {
3745 	struct mcs_instance_t *mcs_inst;
3746 	int err;
3747 
3748 	CHECKIF(conn == NULL) {
3749 		LOG_DBG("conn is NULL");
3750 
3751 		return -EINVAL;
3752 	}
3753 
3754 	mcs_inst = lookup_inst_by_conn(conn);
3755 	if (mcs_inst == NULL) {
3756 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3757 
3758 		return -EINVAL;
3759 	} else if (mcs_inst->busy) {
3760 
3761 		LOG_DBG("mcs_inst busy");
3762 		return -EBUSY;
3763 	}
3764 
3765 	/* TODO: Assumes object is already selected */
3766 	mcs_inst->otc.cb->obj_data_read = on_current_track_content;
3767 
3768 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3769 	if (err) {
3770 		LOG_DBG("Error reading the object: %d", err);
3771 	}
3772 
3773 	return err;
3774 }
3775 
bt_mcc_otc_read_next_track_object(struct bt_conn * conn)3776 int bt_mcc_otc_read_next_track_object(struct bt_conn *conn)
3777 {
3778 	struct mcs_instance_t *mcs_inst;
3779 	int err;
3780 
3781 	CHECKIF(conn == NULL) {
3782 		LOG_DBG("conn is NULL");
3783 
3784 		return -EINVAL;
3785 	}
3786 
3787 	mcs_inst = lookup_inst_by_conn(conn);
3788 	if (mcs_inst == NULL) {
3789 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3790 
3791 		return -EINVAL;
3792 	} else if (mcs_inst->busy) {
3793 
3794 		LOG_DBG("mcs_inst busy");
3795 		return -EBUSY;
3796 	}
3797 
3798 	/* TODO: Assumes object is already selected */
3799 	mcs_inst->otc.cb->obj_data_read = on_next_track_content;
3800 
3801 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3802 	if (err) {
3803 		LOG_DBG("Error reading the object: %d", err);
3804 	}
3805 
3806 	return err;
3807 }
3808 
bt_mcc_otc_read_parent_group_object(struct bt_conn * conn)3809 int bt_mcc_otc_read_parent_group_object(struct bt_conn *conn)
3810 {
3811 	struct mcs_instance_t *mcs_inst;
3812 	int err;
3813 
3814 	CHECKIF(conn == NULL) {
3815 		LOG_DBG("conn is NULL");
3816 
3817 		return -EINVAL;
3818 	}
3819 
3820 	mcs_inst = lookup_inst_by_conn(conn);
3821 	if (mcs_inst == NULL) {
3822 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3823 
3824 		return -EINVAL;
3825 	} else if (mcs_inst->busy) {
3826 
3827 		LOG_DBG("mcs_inst busy");
3828 		return -EBUSY;
3829 	}
3830 
3831 	/* TODO: Assumes object is already selected */
3832 
3833 	/* Reuse callback for current group */
3834 	mcs_inst->otc.cb->obj_data_read = on_parent_group_content;
3835 
3836 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3837 	if (err) {
3838 		LOG_DBG("Error reading the object: %d", err);
3839 	}
3840 
3841 	return err;
3842 }
3843 
bt_mcc_otc_read_current_group_object(struct bt_conn * conn)3844 int bt_mcc_otc_read_current_group_object(struct bt_conn *conn)
3845 {
3846 	struct mcs_instance_t *mcs_inst;
3847 	int err;
3848 
3849 	CHECKIF(conn == NULL) {
3850 		LOG_DBG("conn is NULL");
3851 
3852 		return -EINVAL;
3853 	}
3854 
3855 	mcs_inst = lookup_inst_by_conn(conn);
3856 	if (mcs_inst == NULL) {
3857 		LOG_DBG("Could not lookup mcs_inst from conn %p", (void *)conn);
3858 
3859 		return -EINVAL;
3860 	} else if (mcs_inst->busy) {
3861 
3862 		LOG_DBG("mcs_inst busy");
3863 		return -EBUSY;
3864 	}
3865 
3866 	/* TODO: Assumes object is already selected */
3867 	mcs_inst->otc.cb->obj_data_read = on_current_group_content;
3868 
3869 	err = bt_ots_client_read_object_data(&mcs_inst->otc, conn);
3870 	if (err) {
3871 		LOG_DBG("Error reading the object: %d", err);
3872 	}
3873 
3874 	return err;
3875 }
3876 
3877 #if defined(CONFIG_BT_MCC_SHELL)
bt_mcc_otc_inst(struct bt_conn * conn)3878 struct bt_ots_client *bt_mcc_otc_inst(struct bt_conn *conn)
3879 {
3880 	struct mcs_instance_t *mcs_inst;
3881 
3882 	mcs_inst = lookup_inst_by_conn(conn);
3883 	if (mcs_inst == NULL) {
3884 		return NULL;
3885 	}
3886 
3887 	return &mcs_inst->otc;
3888 }
3889 #endif /* defined(CONFIG_BT_MCC_SHELL) */
3890 
3891 #endif /* CONFIG_BT_MCC_OTS */
3892