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