1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright 2024-2025 NXP
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/types.h>
10 #include <stddef.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <zephyr/sys/printk.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/kernel.h>
16
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/l2cap.h>
20 #include <zephyr/bluetooth/hci.h>
21 #include <zephyr/bluetooth/sbc.h>
22 #include <zephyr/bluetooth/classic/a2dp_codec_sbc.h>
23 #include <zephyr/bluetooth/classic/a2dp.h>
24 #include <zephyr/bluetooth/classic/sdp.h>
25 #include <zephyr/settings/settings.h>
26 #include "sine.h"
27
28 static struct bt_br_discovery_param br_discover;
29 static struct bt_br_discovery_result scan_result[CONFIG_BT_A2DP_SOURCE_DISCOVER_RESULT_COUNT];
30 struct k_work discover_work;
31
32 static struct bt_conn *default_conn;
33 struct bt_a2dp *default_a2dp;
34 static struct bt_a2dp_stream sbc_stream;
35 struct sbc_encoder encoder;
36
37 BT_A2DP_SBC_SOURCE_EP_DEFAULT(sbc_source_ep);
38 static bool peer_sbc_found;
39 struct bt_a2dp_codec_ie sbc_sink_ep_capabilities;
40 static struct bt_a2dp_ep sbc_sink_ep = {
41 .codec_cap = &sbc_sink_ep_capabilities,
42 };
43 BT_A2DP_SBC_EP_CFG_DEFAULT(sbc_cfg_default, A2DP_SBC_SAMP_FREQ_44100);
44
45 /* sbc audio stream control variables */
46 static int64_t ref_time;
47 static uint32_t a2dp_src_missed_count;
48 static volatile bool a2dp_src_playback;
49 static volatile int media_index;
50 static uint32_t a2dp_src_sf;
51 static uint8_t a2dp_src_nc;
52 static uint32_t send_samples_count;
53 static uint16_t send_count;
54 /* max pcm data size per interval. The max sample freq is 48K.
55 * interval * 48 * 2 (max channels) * 2 (sample width) * 2 (the worst case: send two intervals'
56 * data if timer is blocked)
57 */
58 static uint8_t a2dp_pcm_buffer[CONFIG_BT_A2DP_SOURCE_DATA_SEND_INTERVAL * 48 * 2 * 2 * 2];
59 NET_BUF_POOL_DEFINE(a2dp_tx_pool, CONFIG_BT_A2DP_SOURCE_DATA_BUF_COUNT,
60 BT_L2CAP_BUF_SIZE(CONFIG_BT_A2DP_SOURCE_DATA_BUF_SIZE),
61 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
62 static void a2dp_playback_timeout_handler(struct k_timer *timer);
63 K_TIMER_DEFINE(a2dp_player_timer, a2dp_playback_timeout_handler, NULL);
64
65 NET_BUF_POOL_DEFINE(sdp_discover_pool, 10, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
66 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
67
68 struct k_work_q audio_play_work_q;
69 static K_KERNEL_STACK_DEFINE(audio_play_work_q_thread_stack,
70 CONFIG_BT_A2DP_SOURCE_DATA_SEND_WORKQ_STACK_SIZE);
71
72 #define A2DP_VERSION 0x0104
73
74 static struct bt_sdp_attribute a2dp_source_attrs[] = {
75 BT_SDP_NEW_SERVICE,
76 BT_SDP_LIST(
77 BT_SDP_ATTR_SVCLASS_ID_LIST,
78 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
79 BT_SDP_DATA_ELEM_LIST(
80 {
81 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
82 BT_SDP_ARRAY_16(BT_SDP_AUDIO_SOURCE_SVCLASS)
83 },
84 )
85 ),
86 BT_SDP_LIST(
87 BT_SDP_ATTR_PROTO_DESC_LIST,
88 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),
89 BT_SDP_DATA_ELEM_LIST(
90 {
91 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
92 BT_SDP_DATA_ELEM_LIST(
93 {
94 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
95 BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
96 },
97 {
98 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
99 BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL)
100 },
101 )
102 },
103 {
104 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
105 BT_SDP_DATA_ELEM_LIST(
106 {
107 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
108 BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL)
109 },
110 {
111 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
112 BT_SDP_ARRAY_16(AVDTP_VERSION)
113 },
114 )
115 },
116 )
117 ),
118 BT_SDP_LIST(
119 BT_SDP_ATTR_PROFILE_DESC_LIST,
120 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
121 BT_SDP_DATA_ELEM_LIST(
122 {
123 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
124 BT_SDP_DATA_ELEM_LIST(
125 {
126 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
127 BT_SDP_ARRAY_16(BT_SDP_ADVANCED_AUDIO_SVCLASS)
128 },
129 {
130 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
131 BT_SDP_ARRAY_16(A2DP_VERSION)
132 },
133 )
134 },
135 )
136 ),
137 BT_SDP_SERVICE_NAME("A2DPSource"),
138 BT_SDP_SUPPORTED_FEATURES(0x0001U),
139 };
140
141 static struct bt_sdp_record a2dp_source_rec = BT_SDP_RECORD(a2dp_source_attrs);
142
a2dp_produce_media_check(uint32_t samples_num)143 static bool a2dp_produce_media_check(uint32_t samples_num)
144 {
145 uint16_t medialen;
146
147 /* Music Audio is Stereo */
148 medialen = (samples_num * a2dp_src_nc * 2);
149
150 /* need to use a2dp_pcm_buffer to do memcpy */
151 if ((a2dp_src_nc == 1) || ((media_index + (samples_num << 2)) > sizeof(media_data))) {
152 if (medialen > sizeof(a2dp_pcm_buffer)) {
153 return false;
154 }
155 }
156
157 return true;
158 }
159
a2dp_produce_media(uint32_t samples_num)160 static uint8_t *a2dp_produce_media(uint32_t samples_num)
161 {
162 uint8_t *media = NULL;
163 uint16_t medialen;
164
165 /* Music Audio is Stereo */
166 medialen = (samples_num * a2dp_src_nc * 2);
167
168 /* For mono or dual configuration, skip alternative samples */
169 if (a2dp_src_nc == 1) {
170 uint16_t index;
171
172 media = (uint8_t *)&a2dp_pcm_buffer[0];
173
174 for (index = 0; index < samples_num; index++) {
175 media[(2 * index)] = *((uint8_t *)media_data + media_index);
176 media[(2 * index) + 1] = *((uint8_t *)media_data + media_index + 1);
177 /* Update the tone index */
178 media_index += 4u;
179 if (media_index >= sizeof(media_data)) {
180 media_index = 0U;
181 }
182 }
183 } else {
184 if ((media_index + (samples_num << 2)) > sizeof(media_data)) {
185 media = (uint8_t *)&a2dp_pcm_buffer[0];
186 memcpy(media, ((uint8_t *)media_data + media_index),
187 sizeof(media_data) - media_index);
188 memcpy(&media[sizeof(media_data) - media_index],
189 ((uint8_t *)media_data),
190 ((samples_num << 2) - (sizeof(media_data) - media_index)));
191 /* Update the tone index */
192 media_index = ((samples_num << 2) -
193 (sizeof(media_data) - media_index));
194 } else {
195 media = ((uint8_t *)media_data + media_index);
196 /* Update the tone index */
197 media_index += (samples_num << 2);
198 if (media_index >= sizeof(media_data)) {
199 media_index = 0U;
200 }
201 }
202 }
203
204 return media;
205 }
206
audio_play_check(void)207 static void audio_play_check(void)
208 {
209 uint32_t a2dp_src_num_samples;
210 uint32_t pcm_frame_samples;
211 uint8_t frame_num;
212 struct net_buf *buf;
213 uint32_t pdu_len;
214
215 a2dp_src_num_samples = (uint16_t)((CONFIG_BT_A2DP_SOURCE_DATA_SEND_INTERVAL * a2dp_src_sf)
216 / 1000);
217 pcm_frame_samples = sbc_frame_samples(&encoder);
218 frame_num = a2dp_src_num_samples / pcm_frame_samples;
219 if (frame_num * pcm_frame_samples < a2dp_src_num_samples) {
220 frame_num++;
221 }
222 a2dp_src_num_samples = frame_num * pcm_frame_samples;
223
224 buf = bt_a2dp_stream_create_pdu(&a2dp_tx_pool, K_FOREVER);
225 pdu_len = frame_num * sbc_frame_encoded_bytes(&encoder);
226
227 if (pdu_len > net_buf_tailroom(buf)) {
228 printk("need increase buf size %d > %d\n", pdu_len, net_buf_tailroom(buf));
229 }
230
231 pdu_len += buf->len;
232 if (pdu_len > bt_a2dp_get_mtu(&sbc_stream)) {
233 printk("need decrease CONFIG_BT_A2DP_SOURCE_DATA_SEND_INTERVAL %d > %d\n", pdu_len,
234 bt_a2dp_get_mtu(&sbc_stream));
235 }
236
237 if (!a2dp_produce_media_check(a2dp_src_num_samples)) {
238 printk("need increase a2dp_pcm_buffer\n");
239 }
240
241 net_buf_unref(buf);
242 }
243
audio_work_handler(struct k_work * work)244 static void audio_work_handler(struct k_work *work)
245 {
246 int64_t period_ms;
247 uint32_t a2dp_src_num_samples;
248 uint8_t *pcm_data;
249 uint8_t index;
250 uint32_t pcm_frame_size;
251 uint32_t pcm_frame_samples;
252 uint32_t encoded_frame_size;
253 struct net_buf *buf;
254 uint8_t *sbc_hdr;
255 uint32_t pdu_len;
256 uint32_t out_size;
257 int err;
258 uint8_t frame_num = 0;
259 uint8_t remaining_frame_num;
260
261 /* If stopped then return */
262 if (!a2dp_src_playback || default_a2dp == NULL) {
263 return;
264 }
265
266 buf = bt_a2dp_stream_create_pdu(&a2dp_tx_pool, K_FOREVER);
267 if (buf == NULL) {
268 /* fail */
269 printk("no buf\n");
270 return;
271 }
272
273 period_ms = k_uptime_delta(&ref_time);
274
275 pcm_frame_size = sbc_frame_bytes(&encoder);
276 pcm_frame_samples = sbc_frame_samples(&encoder);
277 encoded_frame_size = sbc_frame_encoded_bytes(&encoder);
278
279 sbc_hdr = net_buf_add(buf, 1u);
280 /* Get the number of samples */
281 a2dp_src_num_samples = (uint16_t)((period_ms * a2dp_src_sf) / 1000);
282 a2dp_src_missed_count += (uint32_t)((period_ms * a2dp_src_sf) % 1000);
283 a2dp_src_missed_count += ((a2dp_src_num_samples % pcm_frame_samples) * 1000);
284 a2dp_src_num_samples = (a2dp_src_num_samples / pcm_frame_samples) * pcm_frame_samples;
285 remaining_frame_num = a2dp_src_num_samples / pcm_frame_samples;
286
287 pdu_len = buf->len + remaining_frame_num * encoded_frame_size;
288
289 /* Raw adjust for the drift */
290 while (a2dp_src_missed_count >= (1000 * pcm_frame_samples)) {
291 pdu_len += encoded_frame_size;
292 a2dp_src_num_samples += pcm_frame_samples;
293 remaining_frame_num++;
294 a2dp_src_missed_count -= (1000 * pcm_frame_samples);
295 }
296
297 do {
298 frame_num = remaining_frame_num;
299 /* adjust the buf size */
300 while ((pdu_len - buf->len > net_buf_tailroom(buf)) ||
301 (pdu_len > bt_a2dp_get_mtu(&sbc_stream)) ||
302 (!a2dp_produce_media_check(a2dp_src_num_samples))) {
303 pdu_len -= encoded_frame_size;
304 a2dp_src_missed_count += 1000 * pcm_frame_samples;
305 a2dp_src_num_samples -= pcm_frame_samples;
306 frame_num--;
307 }
308
309 pcm_data = a2dp_produce_media(a2dp_src_num_samples);
310 if (pcm_data == NULL) {
311 net_buf_unref(buf);
312 printk("no media data\n");
313 return;
314 }
315
316 for (index = 0; index < frame_num; index++) {
317 out_size = sbc_encode(&encoder,
318 (uint8_t *)&pcm_data[index * pcm_frame_size],
319 net_buf_tail(buf));
320 if (encoded_frame_size != out_size) {
321 printk("sbc encode fail\n");
322 continue;
323 }
324
325 net_buf_add(buf, encoded_frame_size);
326 }
327
328 *sbc_hdr = (uint8_t)BT_A2DP_SBC_MEDIA_HDR_ENCODE(frame_num, 0, 0, 0);
329
330 err = bt_a2dp_stream_send(&sbc_stream, buf, send_count, send_samples_count);
331 if (err != 0) {
332 net_buf_unref(buf);
333 printk(" Failed to send SBC audio data on streams(%d)\n", err);
334 }
335
336 send_count++;
337 send_samples_count += a2dp_src_num_samples;
338 remaining_frame_num -= frame_num;
339 } while (remaining_frame_num > 0);
340 }
341
342 static K_WORK_DEFINE(audio_work, audio_work_handler);
343
a2dp_playback_timeout_handler(struct k_timer * timer)344 static void a2dp_playback_timeout_handler(struct k_timer *timer)
345 {
346 k_work_submit_to_queue(&audio_play_work_q, &audio_work);
347 }
348
sbc_stream_configured(struct bt_a2dp_stream * stream)349 static void sbc_stream_configured(struct bt_a2dp_stream *stream)
350 {
351 struct sbc_encoder_init_param param;
352 struct bt_a2dp_codec_sbc_params *sbc_config = (struct bt_a2dp_codec_sbc_params *)
353 &sbc_cfg_default.codec_config->codec_ie[0];
354
355 printk("stream configured\n");
356
357 a2dp_src_sf = bt_a2dp_sbc_get_sampling_frequency(sbc_config);
358 a2dp_src_nc = bt_a2dp_sbc_get_channel_num(sbc_config);
359
360 param.bit_rate = CONFIG_BT_A2DP_SOURCE_SBC_BIT_RATE_DEFAULT;
361 param.samp_freq = a2dp_src_sf;
362 param.blk_len = bt_a2dp_sbc_get_block_length(sbc_config);
363 param.subband = bt_a2dp_sbc_get_subband_num(sbc_config);
364 param.alloc_mthd = bt_a2dp_sbc_get_allocation_method(sbc_config);
365 param.ch_mode = bt_a2dp_sbc_get_channel_mode(sbc_config);
366 param.ch_num = bt_a2dp_sbc_get_channel_num(sbc_config);
367 param.min_bitpool = sbc_config->min_bitpool;
368 param.max_bitpool = sbc_config->max_bitpool;
369
370 if (sbc_setup_encoder(&encoder, ¶m) != 0) {
371 printk("sbc encoder initialization fail\n");
372 return;
373 }
374
375 bt_a2dp_stream_establish(stream);
376 }
377
sbc_stream_established(struct bt_a2dp_stream * stream)378 static void sbc_stream_established(struct bt_a2dp_stream *stream)
379 {
380 printk("stream established\n");
381 audio_play_check();
382 bt_a2dp_stream_start(&sbc_stream);
383 }
384
sbc_stream_released(struct bt_a2dp_stream * stream)385 static void sbc_stream_released(struct bt_a2dp_stream *stream)
386 {
387 printk("stream released\n");
388 k_timer_stop(&a2dp_player_timer);
389 }
390
sbc_stream_started(struct bt_a2dp_stream * stream)391 static void sbc_stream_started(struct bt_a2dp_stream *stream)
392 {
393 uint32_t audio_time_interval = CONFIG_BT_A2DP_SOURCE_DATA_SEND_INTERVAL;
394
395 printk("stream started\n");
396 /* Start Audio Source */
397 a2dp_src_playback = true;
398
399 k_uptime_delta(&ref_time);
400 k_timer_start(&a2dp_player_timer, K_MSEC(audio_time_interval), K_MSEC(audio_time_interval));
401 }
402
403 static struct bt_a2dp_stream_ops sbc_stream_ops = {
404 .configured = sbc_stream_configured,
405 .established = sbc_stream_established,
406 .released = sbc_stream_released,
407 .started = sbc_stream_started,
408 };
409
a2dp_discover_ep_cb(struct bt_a2dp * a2dp,struct bt_a2dp_ep_info * info,struct bt_a2dp_ep ** ep)410 static uint8_t a2dp_discover_ep_cb(struct bt_a2dp *a2dp, struct bt_a2dp_ep_info *info,
411 struct bt_a2dp_ep **ep)
412 {
413 if (peer_sbc_found) {
414 int err;
415
416 bt_a2dp_stream_cb_register(&sbc_stream, &sbc_stream_ops);
417 err = bt_a2dp_stream_config(a2dp, &sbc_stream,
418 &sbc_source_ep, &sbc_sink_ep,
419 &sbc_cfg_default);
420 if (err != 0) {
421 printk("fail to configure\n");
422 }
423
424 return BT_A2DP_DISCOVER_EP_STOP;
425 }
426
427 if (info != NULL) {
428 printk("find one endpoint:");
429
430 if (info->codec_type == BT_A2DP_SBC) {
431 printk("it is SBC codec and use it\n");
432
433 if (ep != NULL && !peer_sbc_found) {
434 peer_sbc_found = true;
435 *ep = &sbc_sink_ep;
436 }
437 } else {
438 printk("it is not SBC codecs\n");
439 }
440 }
441
442 return BT_A2DP_DISCOVER_EP_CONTINUE;
443 }
444
445 static struct bt_avdtp_sep_info found_seps[CONFIG_BT_A2DP_SOURCE_EPS_DISCOVER_COUNT];
446
447 static struct bt_a2dp_discover_param ep_discover_param = {
448 .cb = a2dp_discover_ep_cb,
449 .seps_info = &found_seps[0],
450 .sep_count = CONFIG_BT_A2DP_SOURCE_EPS_DISCOVER_COUNT,
451 };
452
app_a2dp_connected(struct bt_a2dp * a2dp,int err)453 static void app_a2dp_connected(struct bt_a2dp *a2dp, int err)
454 {
455 if (err == 0) {
456 peer_sbc_found = false;
457
458 err = bt_a2dp_discover(a2dp, &ep_discover_param);
459 if (err != 0) {
460 printk("fail to discover\n");
461 }
462
463 printk("a2dp connected success\n");
464 } else {
465 if (default_a2dp != NULL) {
466 default_a2dp = NULL;
467 }
468
469 printk("a2dp connected fail\n");
470 }
471 }
472
app_a2dp_disconnected(struct bt_a2dp * a2dp)473 static void app_a2dp_disconnected(struct bt_a2dp *a2dp)
474 {
475 if (default_a2dp != NULL) {
476 default_a2dp = NULL;
477 }
478
479 a2dp_src_playback = false;
480 /* stop timer */
481 k_timer_stop(&a2dp_player_timer);
482 printk("a2dp disconnected\n");
483 }
484
sdp_discover_cb(struct bt_conn * conn,struct bt_sdp_client_result * result,const struct bt_sdp_discover_params * params)485 static uint8_t sdp_discover_cb(struct bt_conn *conn, struct bt_sdp_client_result *result,
486 const struct bt_sdp_discover_params *params)
487 {
488 int err;
489 uint16_t value;
490
491 printk("Discover done\n");
492
493 if (result != NULL && result->resp_buf != NULL) {
494 err = bt_sdp_get_proto_param(result->resp_buf, BT_SDP_PROTO_L2CAP, &value);
495
496 if (err != 0) {
497 printk("PSM is not found\n");
498 } else if (value == BT_UUID_AVDTP_VAL) {
499 printk("The A2DP server found, connecting a2dp\n");
500 default_a2dp = bt_a2dp_connect(conn);
501 if (default_a2dp == NULL) {
502 printk("Fail to create A2DP connection (err %d)\n", err);
503 }
504 }
505 }
506
507 return BT_SDP_DISCOVER_UUID_STOP;
508 }
509
510 static struct bt_sdp_discover_params sdp_discover = {
511 .type = BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
512 .func = sdp_discover_cb,
513 .pool = &sdp_discover_pool,
514 .uuid = BT_UUID_DECLARE_16(BT_SDP_AUDIO_SINK_SVCLASS),
515 };
516
connected(struct bt_conn * conn,uint8_t err)517 static void connected(struct bt_conn *conn, uint8_t err)
518 {
519 int res;
520
521 if (err != 0) {
522 if (default_conn != NULL) {
523 default_conn = NULL;
524 }
525
526 printk("Connection failed, err 0x%02x %s\n", err, bt_hci_err_to_str(err));
527 } else {
528 if (default_conn == conn) {
529 struct bt_conn_info info;
530
531 bt_conn_get_info(conn, &info);
532 if (info.type != BT_CONN_TYPE_BR) {
533 return;
534 }
535
536 /*
537 * Do an SDP Query on Successful ACL connection complete with the
538 * required device
539 */
540 res = bt_sdp_discover(default_conn, &sdp_discover);
541 if (res != 0) {
542 printk("SDP discovery failed (err %d)\n", res);
543 } else {
544 printk("SDP discovery started\n");
545 }
546 printk("Connected\n");
547 }
548 }
549 }
550
disconnected(struct bt_conn * conn,uint8_t reason)551 static void disconnected(struct bt_conn *conn, uint8_t reason)
552 {
553 printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
554
555 if (default_conn == conn) {
556 default_conn = NULL;
557 }
558 }
559
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)560 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
561 {
562 char addr[BT_ADDR_LE_STR_LEN];
563 struct bt_conn_info info;
564
565 bt_conn_get_info(conn, &info);
566
567 bt_addr_to_str(info.br.dst, addr, sizeof(addr));
568
569 printk("Security changed: %s level %u, err %s(%d)\n", addr, level,
570 bt_security_err_to_str(err), err);
571 }
572
573 static struct bt_conn_cb conn_callbacks = {
574 .connected = connected,
575 .disconnected = disconnected,
576 .security_changed = security_changed,
577 };
578
discovery_timeout_cb(const struct bt_br_discovery_result * results,size_t count)579 static void discovery_timeout_cb(const struct bt_br_discovery_result *results, size_t count)
580 {
581 char addr[BT_ADDR_LE_STR_LEN];
582 const uint8_t *eir;
583 bool cod_a2dp = false;
584 static uint8_t temp[240];
585 size_t len = sizeof(results->eir);
586 uint8_t major_device;
587 uint8_t minor_device;
588 size_t i;
589
590 for (i = 0; i < count; i++) {
591 bt_addr_to_str(&results[i].addr, addr, sizeof(addr));
592 printk("Device[%d]: %s, rssi %d, cod 0x%02x%02x%02x", i, addr, results[i].rssi,
593 results[i].cod[0], results[i].cod[1], results[i].cod[2]);
594
595 major_device = (uint8_t)BT_COD_MAJOR_DEVICE_CLASS(results[i].cod);
596 minor_device = (uint8_t)BT_COD_MINOR_DEVICE_CLASS(results[i].cod);
597
598 if ((major_device & BT_COD_MAJOR_AUDIO_VIDEO) != 0 &&
599 (minor_device & BT_COD_MAJOR_AUDIO_VIDEO_MINOR_WEARABLE_HEADSET) != 0) {
600 cod_a2dp = true;
601 }
602
603 eir = results[i].eir;
604
605 while ((eir[0] > 2) && (len > eir[0])) {
606 switch (eir[1]) {
607 case BT_DATA_NAME_SHORTENED:
608 case BT_DATA_NAME_COMPLETE:
609 memcpy(temp, &eir[2], eir[0] - 1);
610 temp[eir[0] - 1] = '\0'; /* Set end flag */
611 printk(", name %s", temp);
612 break;
613 default:
614 /* Skip the EIR */
615 break;
616 }
617 len = len - eir[0] - 1;
618 eir = eir + eir[0] + 1;
619 }
620 printk("\n");
621
622 if (cod_a2dp) {
623 break;
624 }
625 }
626
627 if (!cod_a2dp) {
628 (void)k_work_submit(&discover_work);
629 } else {
630 (void)k_work_cancel(&discover_work);
631 default_conn = bt_conn_create_br(&results[i].addr, BT_BR_CONN_PARAM_DEFAULT);
632
633 if (default_conn == NULL) {
634 printk("Fail to create the connection\n");
635 } else {
636 bt_conn_unref(default_conn);
637 }
638 }
639 }
640
discover_work_handler(struct k_work * work)641 static void discover_work_handler(struct k_work *work)
642 {
643 int err;
644
645 br_discover.length = 10;
646 br_discover.limited = false;
647
648 err = bt_br_discovery_start(&br_discover, scan_result,
649 CONFIG_BT_A2DP_SOURCE_DISCOVER_RESULT_COUNT);
650 if (err != 0) {
651 printk("Fail to start discovery (err %d)\n", err);
652 return;
653 }
654 }
655
656 static struct bt_br_discovery_cb discovery_cb = {
657 .timeout = discovery_timeout_cb,
658 };
659
660 static struct bt_a2dp_cb a2dp_cb = {
661 .connected = app_a2dp_connected,
662 .disconnected = app_a2dp_disconnected,
663 };
664
bt_ready(int err)665 static void bt_ready(int err)
666 {
667 if (err != 0) {
668 printk("Bluetooth init failed (err %d)\n", err);
669 return;
670 }
671
672 if (IS_ENABLED(CONFIG_SETTINGS)) {
673 settings_load();
674 }
675
676 printk("Bluetooth initialized\n");
677
678 bt_conn_cb_register(&conn_callbacks);
679
680 bt_br_discovery_cb_register(&discovery_cb);
681
682 bt_sdp_register_service(&a2dp_source_rec);
683
684 bt_a2dp_register_ep(&sbc_source_ep, BT_AVDTP_AUDIO, BT_AVDTP_SOURCE);
685
686 bt_a2dp_register_cb(&a2dp_cb);
687
688 k_work_queue_init(&audio_play_work_q);
689 k_work_queue_start(&audio_play_work_q, audio_play_work_q_thread_stack,
690 CONFIG_BT_A2DP_SOURCE_DATA_SEND_WORKQ_STACK_SIZE,
691 K_PRIO_COOP(CONFIG_BT_A2DP_SOURCE_DATA_SEND_WORKQ_PRIORITY), NULL);
692 k_thread_name_set(&audio_play_work_q.thread, "audio play");
693
694 k_work_init(&discover_work, discover_work_handler);
695
696 (void)k_work_submit(&discover_work);
697 }
698
main(void)699 int main(void)
700 {
701 int err;
702
703 printk("Bluetooth A2DP Source demo start...\n");
704
705 err = bt_enable(bt_ready);
706 if (err != 0) {
707 printk("Bluetooth init failed (err %d)\n", err);
708 }
709 return 0;
710 }
711