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