1 /*
2 This example code is in the Public Domain (or CC0 licensed, at your option.)
3
4 Unless required by applicable law or agreed to in writing, this
5 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 CONDITIONS OF ANY KIND, either express or implied.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include "freertos/FreeRTOS.h"
14 #include "freertos/task.h"
15 #include "freertos/timers.h"
16 #include "nvs.h"
17 #include "nvs_flash.h"
18 #include "esp_system.h"
19 #include "esp_log.h"
20
21 #include "esp_bt.h"
22 #include "bt_app_core.h"
23 #include "esp_bt_main.h"
24 #include "esp_bt_device.h"
25 #include "esp_gap_bt_api.h"
26 #include "esp_a2dp_api.h"
27 #include "esp_avrc_api.h"
28
29 #define BT_AV_TAG "BT_AV"
30 #define BT_RC_CT_TAG "RCCT"
31
32 // AVRCP used transaction label
33 #define APP_RC_CT_TL_GET_CAPS (0)
34 #define APP_RC_CT_TL_RN_VOLUME_CHANGE (1)
35
36 /* event for handler "bt_av_hdl_stack_up */
37 enum {
38 BT_APP_EVT_STACK_UP = 0,
39 };
40
41 /* A2DP global state */
42 enum {
43 APP_AV_STATE_IDLE,
44 APP_AV_STATE_DISCOVERING,
45 APP_AV_STATE_DISCOVERED,
46 APP_AV_STATE_UNCONNECTED,
47 APP_AV_STATE_CONNECTING,
48 APP_AV_STATE_CONNECTED,
49 APP_AV_STATE_DISCONNECTING,
50 };
51
52 /* sub states of APP_AV_STATE_CONNECTED */
53 enum {
54 APP_AV_MEDIA_STATE_IDLE,
55 APP_AV_MEDIA_STATE_STARTING,
56 APP_AV_MEDIA_STATE_STARTED,
57 APP_AV_MEDIA_STATE_STOPPING,
58 };
59
60 #define BT_APP_HEART_BEAT_EVT (0xff00)
61
62 /// handler for bluetooth stack enabled events
63 static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
64
65 /// callback function for A2DP source
66 static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
67
68 /// callback function for A2DP source audio data stream
69 static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len);
70
71 /// callback function for AVRCP controller
72 static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
73
74 static void a2d_app_heart_beat(void *arg);
75
76 /// A2DP application state machine
77 static void bt_app_av_sm_hdlr(uint16_t event, void *param);
78
79 /// avrc CT event handler
80 static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
81
82 /* A2DP application state machine handler for each state */
83 static void bt_app_av_state_unconnected(uint16_t event, void *param);
84 static void bt_app_av_state_connecting(uint16_t event, void *param);
85 static void bt_app_av_state_connected(uint16_t event, void *param);
86 static void bt_app_av_state_disconnecting(uint16_t event, void *param);
87
88 static esp_bd_addr_t s_peer_bda = {0};
89 static uint8_t s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
90 static int s_a2d_state = APP_AV_STATE_IDLE;
91 static int s_media_state = APP_AV_MEDIA_STATE_IDLE;
92 static int s_intv_cnt = 0;
93 static int s_connecting_intv = 0;
94 static uint32_t s_pkt_cnt = 0;
95 static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
96 static TimerHandle_t s_tmr;
97
bda2str(esp_bd_addr_t bda,char * str,size_t size)98 static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
99 {
100 if (bda == NULL || str == NULL || size < 18) {
101 return NULL;
102 }
103
104 uint8_t *p = bda;
105 sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
106 p[0], p[1], p[2], p[3], p[4], p[5]);
107 return str;
108 }
109
app_main(void)110 void app_main(void)
111 {
112 // Initialize NVS.
113 esp_err_t ret = nvs_flash_init();
114 if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
115 ESP_ERROR_CHECK(nvs_flash_erase());
116 ret = nvs_flash_init();
117 }
118 ESP_ERROR_CHECK( ret );
119
120 ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
121
122 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
123
124 if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
125 ESP_LOGE(BT_AV_TAG, "%s initialize controller failed\n", __func__);
126 return;
127 }
128
129 if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
130 ESP_LOGE(BT_AV_TAG, "%s enable controller failed\n", __func__);
131 return;
132 }
133
134 if (esp_bluedroid_init() != ESP_OK) {
135 ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed\n", __func__);
136 return;
137 }
138
139 if (esp_bluedroid_enable() != ESP_OK) {
140 ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed\n", __func__);
141 return;
142 }
143
144 /* create application task */
145 bt_app_task_start_up();
146
147 /* Bluetooth device name, connection mode and profile set up */
148 bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
149
150 #if (CONFIG_BT_SSP_ENABLED == true)
151 /* Set default parameters for Secure Simple Pairing */
152 esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
153 esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
154 esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
155 #endif
156
157 /*
158 * Set default parameters for Legacy Pairing
159 * Use variable pin, input pin code when pairing
160 */
161 esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
162 esp_bt_pin_code_t pin_code;
163 esp_bt_gap_set_pin(pin_type, 0, pin_code);
164 }
165
get_name_from_eir(uint8_t * eir,uint8_t * bdname,uint8_t * bdname_len)166 static bool get_name_from_eir(uint8_t *eir, uint8_t *bdname, uint8_t *bdname_len)
167 {
168 uint8_t *rmt_bdname = NULL;
169 uint8_t rmt_bdname_len = 0;
170
171 if (!eir) {
172 return false;
173 }
174
175 rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
176 if (!rmt_bdname) {
177 rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
178 }
179
180 if (rmt_bdname) {
181 if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
182 rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
183 }
184
185 if (bdname) {
186 memcpy(bdname, rmt_bdname, rmt_bdname_len);
187 bdname[rmt_bdname_len] = '\0';
188 }
189 if (bdname_len) {
190 *bdname_len = rmt_bdname_len;
191 }
192 return true;
193 }
194
195 return false;
196 }
197
filter_inquiry_scan_result(esp_bt_gap_cb_param_t * param)198 static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
199 {
200 char bda_str[18];
201 uint32_t cod = 0;
202 int32_t rssi = -129; /* invalid value */
203 uint8_t *eir = NULL;
204 esp_bt_gap_dev_prop_t *p;
205
206 ESP_LOGI(BT_AV_TAG, "Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
207 for (int i = 0; i < param->disc_res.num_prop; i++) {
208 p = param->disc_res.prop + i;
209 switch (p->type) {
210 case ESP_BT_GAP_DEV_PROP_COD:
211 cod = *(uint32_t *)(p->val);
212 ESP_LOGI(BT_AV_TAG, "--Class of Device: 0x%x", cod);
213 break;
214 case ESP_BT_GAP_DEV_PROP_RSSI:
215 rssi = *(int8_t *)(p->val);
216 ESP_LOGI(BT_AV_TAG, "--RSSI: %d", rssi);
217 break;
218 case ESP_BT_GAP_DEV_PROP_EIR:
219 eir = (uint8_t *)(p->val);
220 break;
221 case ESP_BT_GAP_DEV_PROP_BDNAME:
222 default:
223 break;
224 }
225 }
226
227 /* search for device with MAJOR service class as "rendering" in COD */
228 if (!esp_bt_gap_is_valid_cod(cod) ||
229 !(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING)) {
230 return;
231 }
232
233 /* search for device named "ESP_SPEAKER" in its extended inqury response */
234 if (eir) {
235 get_name_from_eir(eir, s_peer_bdname, NULL);
236 if (strcmp((char *)s_peer_bdname, "ESP_SPEAKER") != 0) {
237 return;
238 }
239
240 ESP_LOGI(BT_AV_TAG, "Found a target device, address %s, name %s", bda_str, s_peer_bdname);
241 s_a2d_state = APP_AV_STATE_DISCOVERED;
242 memcpy(s_peer_bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
243 ESP_LOGI(BT_AV_TAG, "Cancel device discovery ...");
244 esp_bt_gap_cancel_discovery();
245 }
246 }
247
248
bt_app_gap_cb(esp_bt_gap_cb_event_t event,esp_bt_gap_cb_param_t * param)249 void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
250 {
251 switch (event) {
252 case ESP_BT_GAP_DISC_RES_EVT: {
253 filter_inquiry_scan_result(param);
254 break;
255 }
256 case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
257 if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
258 if (s_a2d_state == APP_AV_STATE_DISCOVERED) {
259 s_a2d_state = APP_AV_STATE_CONNECTING;
260 ESP_LOGI(BT_AV_TAG, "Device discovery stopped.");
261 ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer: %s", s_peer_bdname);
262 esp_a2d_source_connect(s_peer_bda);
263 } else {
264 // not discovered, continue to discover
265 ESP_LOGI(BT_AV_TAG, "Device discovery failed, continue to discover...");
266 esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
267 }
268 } else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
269 ESP_LOGI(BT_AV_TAG, "Discovery started.");
270 }
271 break;
272 }
273 case ESP_BT_GAP_RMT_SRVCS_EVT:
274 case ESP_BT_GAP_RMT_SRVC_REC_EVT:
275 break;
276 case ESP_BT_GAP_AUTH_CMPL_EVT: {
277 if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
278 ESP_LOGI(BT_AV_TAG, "authentication success: %s", param->auth_cmpl.device_name);
279 esp_log_buffer_hex(BT_AV_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
280 } else {
281 ESP_LOGE(BT_AV_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
282 }
283 break;
284 }
285 case ESP_BT_GAP_PIN_REQ_EVT: {
286 ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
287 if (param->pin_req.min_16_digit) {
288 ESP_LOGI(BT_AV_TAG, "Input pin code: 0000 0000 0000 0000");
289 esp_bt_pin_code_t pin_code = {0};
290 esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
291 } else {
292 ESP_LOGI(BT_AV_TAG, "Input pin code: 1234");
293 esp_bt_pin_code_t pin_code;
294 pin_code[0] = '1';
295 pin_code[1] = '2';
296 pin_code[2] = '3';
297 pin_code[3] = '4';
298 esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
299 }
300 break;
301 }
302
303 #if (CONFIG_BT_SSP_ENABLED == true)
304 case ESP_BT_GAP_CFM_REQ_EVT:
305 ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
306 esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
307 break;
308 case ESP_BT_GAP_KEY_NOTIF_EVT:
309 ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
310 break;
311 case ESP_BT_GAP_KEY_REQ_EVT:
312 ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
313 break;
314 #endif
315
316 case ESP_BT_GAP_MODE_CHG_EVT:
317 ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d", param->mode_chg.mode);
318 break;
319
320 default: {
321 ESP_LOGI(BT_AV_TAG, "event: %d", event);
322 break;
323 }
324 }
325 return;
326 }
327
bt_av_hdl_stack_evt(uint16_t event,void * p_param)328 static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
329 {
330 ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
331 switch (event) {
332 case BT_APP_EVT_STACK_UP: {
333 /* set up device name */
334 char *dev_name = "ESP_A2DP_SRC";
335 esp_bt_dev_set_device_name(dev_name);
336
337 /* register GAP callback function */
338 esp_bt_gap_register_callback(bt_app_gap_cb);
339
340 /* initialize AVRCP controller */
341 esp_avrc_ct_init();
342 esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
343
344 esp_avrc_rn_evt_cap_mask_t evt_set = {0};
345 esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
346 assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
347
348 /* initialize A2DP source */
349 esp_a2d_register_callback(&bt_app_a2d_cb);
350 esp_a2d_source_register_data_callback(bt_app_a2d_data_cb);
351 esp_a2d_source_init();
352
353 /* set discoverable and connectable mode */
354 esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
355
356 /* start device discovery */
357 ESP_LOGI(BT_AV_TAG, "Starting device discovery...");
358 s_a2d_state = APP_AV_STATE_DISCOVERING;
359 esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
360
361 /* create and start heart beat timer */
362 do {
363 int tmr_id = 0;
364 s_tmr = xTimerCreate("connTmr", (10000 / portTICK_RATE_MS),
365 pdTRUE, (void *) &tmr_id, a2d_app_heart_beat);
366 xTimerStart(s_tmr, portMAX_DELAY);
367 } while (0);
368 break;
369 }
370 default:
371 ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
372 break;
373 }
374 }
375
bt_app_a2d_cb(esp_a2d_cb_event_t event,esp_a2d_cb_param_t * param)376 static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
377 {
378 bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
379 }
380
bt_app_a2d_data_cb(uint8_t * data,int32_t len)381 static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
382 {
383 if (len < 0 || data == NULL) {
384 return 0;
385 }
386
387 // generate random sequence
388 int val = rand() % (1 << 16);
389 for (int i = 0; i < (len >> 1); i++) {
390 data[(i << 1)] = val & 0xff;
391 data[(i << 1) + 1] = (val >> 8) & 0xff;
392 }
393
394 return len;
395 }
396
a2d_app_heart_beat(void * arg)397 static void a2d_app_heart_beat(void *arg)
398 {
399 bt_app_work_dispatch(bt_app_av_sm_hdlr, BT_APP_HEART_BEAT_EVT, NULL, 0, NULL);
400 }
401
bt_app_av_sm_hdlr(uint16_t event,void * param)402 static void bt_app_av_sm_hdlr(uint16_t event, void *param)
403 {
404 ESP_LOGI(BT_AV_TAG, "%s state %d, evt 0x%x", __func__, s_a2d_state, event);
405 switch (s_a2d_state) {
406 case APP_AV_STATE_DISCOVERING:
407 case APP_AV_STATE_DISCOVERED:
408 break;
409 case APP_AV_STATE_UNCONNECTED:
410 bt_app_av_state_unconnected(event, param);
411 break;
412 case APP_AV_STATE_CONNECTING:
413 bt_app_av_state_connecting(event, param);
414 break;
415 case APP_AV_STATE_CONNECTED:
416 bt_app_av_state_connected(event, param);
417 break;
418 case APP_AV_STATE_DISCONNECTING:
419 bt_app_av_state_disconnecting(event, param);
420 break;
421 default:
422 ESP_LOGE(BT_AV_TAG, "%s invalid state %d", __func__, s_a2d_state);
423 break;
424 }
425 }
426
bt_app_av_state_unconnected(uint16_t event,void * param)427 static void bt_app_av_state_unconnected(uint16_t event, void *param)
428 {
429 switch (event) {
430 case ESP_A2D_CONNECTION_STATE_EVT:
431 case ESP_A2D_AUDIO_STATE_EVT:
432 case ESP_A2D_AUDIO_CFG_EVT:
433 case ESP_A2D_MEDIA_CTRL_ACK_EVT:
434 break;
435 case BT_APP_HEART_BEAT_EVT: {
436 uint8_t *p = s_peer_bda;
437 ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer: %02x:%02x:%02x:%02x:%02x:%02x",
438 p[0], p[1], p[2], p[3], p[4], p[5]);
439 esp_a2d_source_connect(s_peer_bda);
440 s_a2d_state = APP_AV_STATE_CONNECTING;
441 s_connecting_intv = 0;
442 break;
443 }
444 default:
445 ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
446 break;
447 }
448 }
449
bt_app_av_state_connecting(uint16_t event,void * param)450 static void bt_app_av_state_connecting(uint16_t event, void *param)
451 {
452 esp_a2d_cb_param_t *a2d = NULL;
453 switch (event) {
454 case ESP_A2D_CONNECTION_STATE_EVT: {
455 a2d = (esp_a2d_cb_param_t *)(param);
456 if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
457 ESP_LOGI(BT_AV_TAG, "a2dp connected");
458 s_a2d_state = APP_AV_STATE_CONNECTED;
459 s_media_state = APP_AV_MEDIA_STATE_IDLE;
460 esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
461 } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
462 s_a2d_state = APP_AV_STATE_UNCONNECTED;
463 }
464 break;
465 }
466 case ESP_A2D_AUDIO_STATE_EVT:
467 case ESP_A2D_AUDIO_CFG_EVT:
468 case ESP_A2D_MEDIA_CTRL_ACK_EVT:
469 break;
470 case BT_APP_HEART_BEAT_EVT:
471 if (++s_connecting_intv >= 2) {
472 s_a2d_state = APP_AV_STATE_UNCONNECTED;
473 s_connecting_intv = 0;
474 }
475 break;
476 default:
477 ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
478 break;
479 }
480 }
481
bt_app_av_media_proc(uint16_t event,void * param)482 static void bt_app_av_media_proc(uint16_t event, void *param)
483 {
484 esp_a2d_cb_param_t *a2d = NULL;
485 switch (s_media_state) {
486 case APP_AV_MEDIA_STATE_IDLE: {
487 if (event == BT_APP_HEART_BEAT_EVT) {
488 ESP_LOGI(BT_AV_TAG, "a2dp media ready checking ...");
489 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY);
490 } else if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
491 a2d = (esp_a2d_cb_param_t *)(param);
492 if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY &&
493 a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
494 ESP_LOGI(BT_AV_TAG, "a2dp media ready, starting ...");
495 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_START);
496 s_media_state = APP_AV_MEDIA_STATE_STARTING;
497 }
498 }
499 break;
500 }
501 case APP_AV_MEDIA_STATE_STARTING: {
502 if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
503 a2d = (esp_a2d_cb_param_t *)(param);
504 if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
505 a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
506 ESP_LOGI(BT_AV_TAG, "a2dp media start successfully.");
507 s_intv_cnt = 0;
508 s_media_state = APP_AV_MEDIA_STATE_STARTED;
509 } else {
510 // not started succesfully, transfer to idle state
511 ESP_LOGI(BT_AV_TAG, "a2dp media start failed.");
512 s_media_state = APP_AV_MEDIA_STATE_IDLE;
513 }
514 }
515 break;
516 }
517 case APP_AV_MEDIA_STATE_STARTED: {
518 if (event == BT_APP_HEART_BEAT_EVT) {
519 if (++s_intv_cnt >= 10) {
520 ESP_LOGI(BT_AV_TAG, "a2dp media stopping...");
521 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
522 s_media_state = APP_AV_MEDIA_STATE_STOPPING;
523 s_intv_cnt = 0;
524 }
525 }
526 break;
527 }
528 case APP_AV_MEDIA_STATE_STOPPING: {
529 if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
530 a2d = (esp_a2d_cb_param_t *)(param);
531 if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP &&
532 a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
533 ESP_LOGI(BT_AV_TAG, "a2dp media stopped successfully, disconnecting...");
534 s_media_state = APP_AV_MEDIA_STATE_IDLE;
535 esp_a2d_source_disconnect(s_peer_bda);
536 s_a2d_state = APP_AV_STATE_DISCONNECTING;
537 } else {
538 ESP_LOGI(BT_AV_TAG, "a2dp media stopping...");
539 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
540 }
541 }
542 break;
543 }
544 }
545 }
546
bt_app_av_state_connected(uint16_t event,void * param)547 static void bt_app_av_state_connected(uint16_t event, void *param)
548 {
549 esp_a2d_cb_param_t *a2d = NULL;
550 switch (event) {
551 case ESP_A2D_CONNECTION_STATE_EVT: {
552 a2d = (esp_a2d_cb_param_t *)(param);
553 if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
554 ESP_LOGI(BT_AV_TAG, "a2dp disconnected");
555 s_a2d_state = APP_AV_STATE_UNCONNECTED;
556 esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
557 }
558 break;
559 }
560 case ESP_A2D_AUDIO_STATE_EVT: {
561 a2d = (esp_a2d_cb_param_t *)(param);
562 if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
563 s_pkt_cnt = 0;
564 }
565 break;
566 }
567 case ESP_A2D_AUDIO_CFG_EVT:
568 // not suppposed to occur for A2DP source
569 break;
570 case ESP_A2D_MEDIA_CTRL_ACK_EVT:
571 case BT_APP_HEART_BEAT_EVT: {
572 bt_app_av_media_proc(event, param);
573 break;
574 }
575 default:
576 ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
577 break;
578 }
579 }
580
bt_app_av_state_disconnecting(uint16_t event,void * param)581 static void bt_app_av_state_disconnecting(uint16_t event, void *param)
582 {
583 esp_a2d_cb_param_t *a2d = NULL;
584 switch (event) {
585 case ESP_A2D_CONNECTION_STATE_EVT: {
586 a2d = (esp_a2d_cb_param_t *)(param);
587 if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
588 ESP_LOGI(BT_AV_TAG, "a2dp disconnected");
589 s_a2d_state = APP_AV_STATE_UNCONNECTED;
590 esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
591 }
592 break;
593 }
594 case ESP_A2D_AUDIO_STATE_EVT:
595 case ESP_A2D_AUDIO_CFG_EVT:
596 case ESP_A2D_MEDIA_CTRL_ACK_EVT:
597 case BT_APP_HEART_BEAT_EVT:
598 break;
599 default:
600 ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
601 break;
602 }
603 }
604
bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event,esp_avrc_ct_cb_param_t * param)605 static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
606 {
607 switch (event) {
608 case ESP_AVRC_CT_METADATA_RSP_EVT:
609 case ESP_AVRC_CT_CONNECTION_STATE_EVT:
610 case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
611 case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
612 case ESP_AVRC_CT_REMOTE_FEATURES_EVT:
613 case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT:
614 case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
615 bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
616 break;
617 }
618 default:
619 ESP_LOGE(BT_RC_CT_TAG, "Invalid AVRC event: %d", event);
620 break;
621 }
622 }
623
bt_av_volume_changed(void)624 static void bt_av_volume_changed(void)
625 {
626 if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
627 ESP_AVRC_RN_VOLUME_CHANGE)) {
628 esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, ESP_AVRC_RN_VOLUME_CHANGE, 0);
629 }
630 }
631
bt_av_notify_evt_handler(uint8_t event_id,esp_avrc_rn_param_t * event_parameter)632 void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
633 {
634 switch (event_id) {
635 case ESP_AVRC_RN_VOLUME_CHANGE:
636 ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume);
637 ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume: volume %d", event_parameter->volume + 5);
638 esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, event_parameter->volume + 5);
639 bt_av_volume_changed();
640 break;
641 }
642 }
643
bt_av_hdl_avrc_ct_evt(uint16_t event,void * p_param)644 static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
645 {
646 ESP_LOGD(BT_RC_CT_TAG, "%s evt %d", __func__, event);
647 esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param);
648 switch (event) {
649 case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
650 uint8_t *bda = rc->conn_stat.remote_bda;
651 ESP_LOGI(BT_RC_CT_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
652 rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
653
654 if (rc->conn_stat.connected) {
655 // get remote supported event_ids of peer AVRCP Target
656 esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
657 } else {
658 // clear peer notification capability record
659 s_avrc_peer_rn_cap.bits = 0;
660 }
661 break;
662 }
663 case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
664 ESP_LOGI(BT_RC_CT_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
665 break;
666 }
667 case ESP_AVRC_CT_METADATA_RSP_EVT: {
668 ESP_LOGI(BT_RC_CT_TAG, "AVRC metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text);
669 free(rc->meta_rsp.attr_text);
670 break;
671 }
672 case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
673 ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
674 bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter);
675 break;
676 }
677 case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
678 ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %x, TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag);
679 break;
680 }
681 case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
682 ESP_LOGI(BT_RC_CT_TAG, "remote rn_cap: count %d, bitmask 0x%x", rc->get_rn_caps_rsp.cap_count,
683 rc->get_rn_caps_rsp.evt_set.bits);
684 s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
685
686 bt_av_volume_changed();
687 break;
688 }
689 case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
690 ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume rsp: volume %d", rc->set_volume_rsp.volume);
691 break;
692 }
693
694 default:
695 ESP_LOGE(BT_RC_CT_TAG, "%s unhandled evt %d", __func__, event);
696 break;
697 }
698 }
699