A2DP source Task buffer fails to fill the Queue the 100th time, every time. Why?

smerrett79
Posts: 2
Joined: Tue Jan 24, 2023 12:58 am

A2DP source Task buffer fails to fill the Queue the 100th time, every time. Why?

Postby smerrett79 » Tue Jan 24, 2023 1:14 am

I'm using ESP32 4MB flash at 240 MHz and have code based on the A2DP source example in ESP-IDF. Because I want to move to more flexibility between the BT audio callback calls, I have filled the sample buffer outside the BT callback in a Task and am passing the pointer to the buffer in a Queue. I'm using a button Task and ISR to send the buffer task the button state and when it is pressed, the buffer stops sending a pointer to a buffer full of zeroes and sends a pointer to a buffer full of audio samples which it reads from SPIFFS using fread().

The problem is that I hear a crackle in the audio for samples after around 300 milliseconds. I have checked and the BT callback is finding the sample pointer Queue empty at that point - either the 99th (first time) or 100th(every subsequent time) loop round the buffer filling task. The buffer is 512 samples, btw, as you'd expect - to match the BT A2DP buffer size. The strange thing is that even after disabling watchdogs or changing their durations (the interrupt watchdog was set at 300ms initially) the failed sample is always at around 300 ms after the button is pressed (the 100th sample / loop round the buffer filling routine). If I play a 2 second audio clip from SPIFFS, or a 500 ms clip, there is only ever a crackle / failure to fill the Queue for the 100th loop since the button was pressed in the buffer filling task.

Forgive my commenting out and elements of old code, I'm having to try all sorts of things to work out what might be causing the queue error at the 100th sample.
  1. /*
  2.  * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3.  *
  4.  * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <string.h>
  11. #include "freertos/FreeRTOS.h"
  12. #include "freertos/task.h"
  13. #include "freertos/timers.h"
  14. #include "nvs.h"
  15. #include "nvs_flash.h"
  16. #include "esp_system.h"
  17. #include "esp_log.h"
  18.  
  19. #include "esp_bt.h"
  20. #include "bt_app_core.h"
  21. #include "esp_bt_main.h"
  22. #include "esp_bt_device.h"
  23. #include "esp_gap_bt_api.h"
  24. #include "esp_a2dp_api.h"
  25. #include "esp_avrc_api.h"
  26.  
  27. // FreeRTOS
  28. #include "driver/gpio.h" // for input to test audio responsiveness
  29. #include "freertos/queue.h" // so input tasks can trigger audio etc
  30. #include "freertos/stream_buffer.h" // to pass mixed audio samples from the mixing task to the BT audio callback
  31.  
  32. // For SPIFFS
  33. #include "esp_partition.h"
  34. #include "esp_spiffs.h"
  35. #include "esp_vfs.h"
  36.  
  37. /* log tags */
  38. #define BT_AV_TAG             "BT_AV"
  39. #define BT_RC_CT_TAG          "RC_CT"
  40. #define APP_TAG               "APP"
  41.  
  42. /* device name */
  43. //#define TARGET_DEVICE_NAME    "Aukey SK-M7"
  44. #define TARGET_DEVICE_NAME    "Untangled Pro"
  45. #define LOCAL_DEVICE_NAME     "ESP_A2DP_SRC"
  46.  
  47. /* AVRCP used transaction label */
  48. #define APP_RC_CT_TL_GET_CAPS            (0)
  49. #define APP_RC_CT_TL_RN_VOLUME_CHANGE    (1)
  50.  
  51. /* Pin name definitions*/
  52. #define BUTTON_PIN GPIO_NUM_27
  53. #define LED_PIN GPIO_NUM_2
  54.  
  55. /* ISR Flag*/
  56. #define ESP_INR_FLAG_DEFAULT 0
  57.  
  58. /* Whether to use SPIFFS or attached header file*/
  59.  
  60. #define SPIFFS_SAMPLE
  61.  
  62. #define SAMPLE_STREAM_BUFFER_SIZE 512
  63.  
  64. enum {
  65.     BT_APP_STACK_UP_EVT   = 0x0000,    /* event for stack up */
  66.     BT_APP_HEART_BEAT_EVT = 0xff00,    /* event for heart beat */
  67. };
  68.  
  69. /* A2DP global states */
  70. enum {
  71.     APP_AV_STATE_IDLE,
  72.     APP_AV_STATE_DISCOVERING,
  73.     APP_AV_STATE_DISCOVERED,
  74.     APP_AV_STATE_UNCONNECTED,
  75.     APP_AV_STATE_CONNECTING,
  76.     APP_AV_STATE_CONNECTED,
  77.     APP_AV_STATE_DISCONNECTING,
  78. };
  79.  
  80. /* sub states of APP_AV_STATE_CONNECTED */
  81. enum {
  82.     APP_AV_MEDIA_STATE_IDLE,
  83.     APP_AV_MEDIA_STATE_STARTING,
  84.     APP_AV_MEDIA_STATE_STARTED,
  85.     APP_AV_MEDIA_STATE_STOPPING,
  86. };
  87.  
  88. /* Holds pointer and number of samples to read for BT audio callback*/
  89. typedef struct
  90. {
  91.     uint8_t * data_pointer;
  92.     int number_of_bytes;
  93.     int sample_count;
  94. } t_stAudioSample;
  95.  
  96. /*********************************
  97.  * STATIC FUNCTION DECLARATIONS
  98.  ********************************/
  99.  
  100. /* handler for bluetooth stack enabled events */
  101. static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
  102.  
  103. /* avrc controller event handler */
  104. static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
  105.  
  106. /* GAP callback function */
  107. static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
  108.  
  109. /* callback function for A2DP source */
  110. static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
  111.  
  112. /* callback function for A2DP source SPIFFS audio data stream using queues to decide when to play */
  113. static int32_t bt_app_a2d_spiffs_mono_sample_button_cb(uint8_t *data, int32_t len);
  114.  
  115. /* callback function for A2DP source SPIFFS dual audio data stream using queues to decide when to play */
  116. static int32_t bt_app_a2d_spiffs_mixed_sample_button_cb(uint8_t *data, int32_t len);
  117.  
  118. /* callback function for A2DP source SPIFFS dual audio data stream using queues to decide when to play */
  119. static int32_t bt_app_a2d_stream_buffer_button_cb(uint8_t *data, int32_t len);
  120.  
  121. /* callback function for AVRCP controller */
  122. static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
  123.  
  124. /* handler for heart beat timer */
  125. static void bt_app_a2d_heart_beat(TimerHandle_t arg);
  126.  
  127. /* A2DP application state machine */
  128. static void bt_app_av_sm_hdlr(uint16_t event, void *param);
  129.  
  130. /* utils for transfer BLuetooth Deveice Address into string form */
  131. static char *bda2str(esp_bd_addr_t bda, char *str, size_t size);
  132.  
  133. /* A2DP application state machine handler for each state */
  134. static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param);
  135. static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param);
  136. static void bt_app_av_state_connected_hdlr(uint16_t event, void *param);
  137. static void bt_app_av_state_disconnecting_hdlr(uint16_t event, void *param);
  138.  
  139. /* initialise GPIOs for input/output*/
  140. static void app_gpio_init();
  141.  
  142.  
  143. /* ISR and ISR-called RTOS task*/
  144. /*static*/ void IRAM_ATTR button_isr_handler(void *arg);
  145. static void interrupt_task(void *arg);
  146. static void sample_mix_task(void *arg); // reads and mixes samples prior to transmission
  147.  
  148.  
  149. /*********************************
  150.  * STATIC VARIABLE DEFINITIONS
  151.  ********************************/
  152.  
  153. static esp_bd_addr_t s_peer_bda = {0};                        /* Bluetooth Device Address of peer device*/
  154. static uint8_t s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];  /* Bluetooth Device Name of peer device*/
  155. static int s_a2d_state = APP_AV_STATE_IDLE;                   /* A2DP global state */
  156. static int s_media_state = APP_AV_MEDIA_STATE_IDLE;           /* sub states of APP_AV_STATE_CONNECTED */
  157. static int s_intv_cnt = 0;                                    /* count of heart beat intervals */
  158. static int s_connecting_intv = 0;                             /* count of heart beat intervals for connecting */
  159. static uint32_t s_pkt_cnt = 0;                                /* count of packets */
  160. static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;         /* AVRC target notification event capability bit mask */
  161. static TimerHandle_t s_tmr;                                   /* handle of heart beat timer */
  162.  
  163. TaskHandle_t ISR = NULL;                                      /* handle for button ISR */
  164. QueueHandle_t buttonQueue;                                    /* handle for task data-sharing queue */
  165.  
  166. TaskHandle_t SM_task = NULL;                                      /* handle for button ISR */
  167. QueueHandle_t  sampleBufferQueue;                                     /* handle for task data-sharing queue */
  168.  
  169. // For SPIFFs
  170. FILE* sample_file;
  171. FILE* sample_fileA;
  172. FILE* sample_fileB;
  173. FILE* sample_fileC;
  174. static const char *TAG = "SPIFFS";
  175.  
  176. uint8_t mono_dataA[256] = {0};
  177. uint8_t mono_dataB[256] = {0};
  178. uint8_t sample_data[SAMPLE_STREAM_BUFFER_SIZE*2] = {0}; // initialise a test array of samples
  179. uint8_t blank_data[SAMPLE_STREAM_BUFFER_SIZE] = {0}; // silence samples for when there is no audio to send
  180.  
  181. //static uint8_t sample_data[512]; // stores our sample data
  182. const size_t sampleStreamBufferSize = 512; // size of bytes
  183. const size_t sampleStreamTriggerNumber = 1; // allow stream to be read from if only 1 byte is present
  184.  
  185. #define NUM_OF_VOLUME_SETTINGS 4
  186. uint8_t volumeDivisors[NUM_OF_VOLUME_SETTINGS] = {1, 2, 4, 8}; // what to divide sample magnitudes by for different volumes
  187. /*********************************
  188.  * STATIC FUNCTION DEFINITIONS
  189.  ********************************/
  190. static void init_spiffs()
  191. {
  192.     ESP_LOGI(TAG, "Initializing SPIFFS");
  193.  
  194.     esp_vfs_spiffs_conf_t conf = {
  195.       .base_path = "",
  196.       .partition_label = NULL,
  197.       .max_files = 5,
  198.       .format_if_mount_failed = false
  199.     };
  200.  
  201.     // Use settings defined above to initialize and mount SPIFFS filesystem.
  202.     // Note: esp_vfs_spiffs_register is an all-in-one convenience function.
  203.     esp_err_t ret = esp_vfs_spiffs_register(&conf);
  204.  
  205.     // Use POSIX and C standard library functions to work with files.
  206.     // First create a file.
  207.     // ESP_LOGI(TAG, "Opening file");
  208.     // FILE* f = fopen("/spiffs/hello.txt", "w");
  209.     // if (f == NULL) {
  210.     //     ESP_LOGE(TAG, "Failed to open file for writing");
  211.     //     return;
  212.     // }
  213.     // fprintf(f, "Hello World!\n");
  214.     // fclose(f);
  215.     // ESP_LOGI(TAG, "File written");
  216.  
  217.  
  218.         if (ret != ESP_OK) {
  219.             if (ret == ESP_FAIL) {
  220.                 ESP_LOGE(TAG, "Failed to mount or format filesystem");
  221.             } else if (ret == ESP_ERR_NOT_FOUND) {
  222.                 ESP_LOGE(TAG, "Failed to find SPIFFS partition");
  223.             } else {
  224.                 ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
  225.             }
  226.             return;
  227.         }
  228.  
  229.  
  230.     size_t total = 0, used = 0;
  231.     ret = esp_spiffs_info(NULL, &total, &used);
  232.     if (ret != ESP_OK) {
  233.         ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
  234.     } else {
  235.         ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
  236.     }
  237.  
  238.  
  239. }
  240.  
  241. static void list_directory(const char* path)
  242. {
  243.     printf("list_directory\n");
  244.     DIR* dir = opendir(path);
  245.     while (true) {
  246.         struct dirent* de = readdir(dir);
  247.         if (!de) {
  248.             break;
  249.         }
  250.         printf("file found: %s\n", de->d_name);
  251.         char pathname[1024];   /* should alwys be big enough */
  252.         sprintf( pathname, "/%s", de->d_name );
  253.         printf("pathname: %s\n", pathname);
  254.         FILE* f = fopen(pathname, "r");
  255.         if (f == NULL) {
  256.             printf("could not open: %s\n", de->d_name);
  257.         } else {
  258.             printf("could open: %s\n", de->d_name);
  259.             //char buf[32] = { 0 };
  260.             //int cb = fread(buf, 1, sizeof(buf), f);
  261.             fclose(f);
  262.         };
  263.     }
  264.     closedir(dir);
  265. }
  266.  
  267. static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
  268. {
  269.     if (bda == NULL || str == NULL || size < 18) {
  270.         return NULL;
  271.     }
  272.  
  273.     sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
  274.             bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
  275.     return str;
  276. }
  277.  
  278. static bool get_name_from_eir(uint8_t *eir, uint8_t *bdname, uint8_t *bdname_len)
  279. {
  280.     uint8_t *rmt_bdname = NULL;
  281.     uint8_t rmt_bdname_len = 0;
  282.  
  283.     if (!eir) {
  284.         return false;
  285.     }
  286.  
  287.     /* get complete or short local name from eir data */
  288.     rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
  289.     if (!rmt_bdname) {
  290.         rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
  291.     }
  292.  
  293.     if (rmt_bdname) {
  294.         if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
  295.             rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
  296.         }
  297.  
  298.         if (bdname) {
  299.             memcpy(bdname, rmt_bdname, rmt_bdname_len);
  300.             bdname[rmt_bdname_len] = '\0';
  301.         }
  302.         if (bdname_len) {
  303.             *bdname_len = rmt_bdname_len;
  304.         }
  305.         return true;
  306.     }
  307.  
  308.     return false;
  309. }
  310.  
  311. static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
  312. {
  313.     char bda_str[18];
  314.     uint32_t cod = 0;     /* class of device */
  315.     int32_t rssi = -129;  /* invalid value */
  316.     uint8_t *eir = NULL;
  317.     esp_bt_gap_dev_prop_t *p;
  318.  
  319.     /* handle the discovery results */
  320.     ESP_LOGI(BT_AV_TAG, "Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
  321.     for (int i = 0; i < param->disc_res.num_prop; i++) {
  322.         p = param->disc_res.prop + i;
  323.         switch (p->type) {
  324.         case ESP_BT_GAP_DEV_PROP_COD:
  325.             cod = *(uint32_t *)(p->val);
  326.             ESP_LOGI(BT_AV_TAG, "--Class of Device: 0x%x", cod);
  327.             break;
  328.         case ESP_BT_GAP_DEV_PROP_RSSI:
  329.             rssi = *(int8_t *)(p->val);
  330.             ESP_LOGI(BT_AV_TAG, "--RSSI: %d", rssi);
  331.             break;
  332.         case ESP_BT_GAP_DEV_PROP_EIR:
  333.             eir = (uint8_t *)(p->val);
  334.             ESP_LOGI(BT_AV_TAG, "--EIR: %d", eir);
  335.             break;
  336.         case ESP_BT_GAP_DEV_PROP_BDNAME:
  337.         default:
  338.             break;
  339.         }
  340.     }
  341.  
  342.     /* search for device with MAJOR service class as "rendering" in COD */
  343.     if (!esp_bt_gap_is_valid_cod(cod)  ||
  344.             !(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING) ) {
  345.         return;
  346.     }
  347.  
  348.     /* search for target device in its Extended Inqury Response */
  349.     if (eir) {
  350.         get_name_from_eir(eir, s_peer_bdname, NULL);
  351.         ESP_LOGI(BT_AV_TAG, "Found a rendering device name %s", s_peer_bdname);
  352.         if (strcmp((char *)s_peer_bdname, TARGET_DEVICE_NAME) == 0) {
  353.             ESP_LOGI(BT_AV_TAG, "Found a target device, address %s, name %s", bda_str, s_peer_bdname);
  354.             s_a2d_state = APP_AV_STATE_DISCOVERED;
  355.             memcpy(s_peer_bda, param->disc_res.bda, ESP_BD_ADDR_LEN); // s_peer_bda will now hold the BT address we want to connect to
  356.             ESP_LOGI(BT_AV_TAG, "Cancel device discovery ...");
  357.             esp_bt_gap_cancel_discovery();
  358.         }
  359.     }
  360. }
  361.  
  362. static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
  363. {
  364.     switch (event) {
  365.     /* when device discovered a result, this event comes */
  366.     case ESP_BT_GAP_DISC_RES_EVT: {
  367.         if (s_a2d_state == APP_AV_STATE_DISCOVERING) {
  368.             filter_inquiry_scan_result(param);
  369.         }
  370.         break;
  371.     }
  372.     /* when discovery state changed, this event comes */
  373.     case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
  374.         if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
  375.             if (s_a2d_state == APP_AV_STATE_DISCOVERED) {
  376.                 s_a2d_state = APP_AV_STATE_CONNECTING;
  377.                 ESP_LOGI(BT_AV_TAG, "Device discovery stopped.");
  378.                 ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer: %s", s_peer_bdname);
  379.                 /* connect source to peer device specificed by Bluetooth Device Address */
  380.                 esp_a2d_source_connect(s_peer_bda);
  381.             } else {
  382.                 /* not discovered, continue to discover */
  383.                 ESP_LOGI(BT_AV_TAG, "Device discovery failed, continue to discover...");
  384.                 esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
  385.             }
  386.         } else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
  387.             ESP_LOGI(BT_AV_TAG, "Discovery started.");
  388.         }
  389.         break;
  390.     }
  391.     /* when authentication completed, this event comes */
  392.     case ESP_BT_GAP_AUTH_CMPL_EVT: {
  393.         if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
  394.             ESP_LOGI(BT_AV_TAG, "authentication success: %s", param->auth_cmpl.device_name);
  395.             esp_log_buffer_hex(BT_AV_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
  396.         } else {
  397.             ESP_LOGE(BT_AV_TAG, "authentication failed, status: %d", param->auth_cmpl.stat);
  398.         }
  399.         break;
  400.     }
  401.     /* when Legacy Pairing pin code requested, this event comes */
  402.     case ESP_BT_GAP_PIN_REQ_EVT: {
  403.         ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit: %d", param->pin_req.min_16_digit);
  404.         if (param->pin_req.min_16_digit) {
  405.             ESP_LOGI(BT_AV_TAG, "Input pin code: 0000 0000 0000 0000");
  406.             esp_bt_pin_code_t pin_code = {0};
  407.             esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
  408.         } else {
  409.             ESP_LOGI(BT_AV_TAG, "Input pin code: 1234");
  410.             esp_bt_pin_code_t pin_code;
  411.             pin_code[0] = '1';
  412.             pin_code[1] = '2';
  413.             pin_code[2] = '3';
  414.             pin_code[3] = '4';
  415.             esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
  416.         }
  417.         break;
  418.     }
  419.  
  420. #if (CONFIG_BT_SSP_ENABLED == true)
  421.     /* when Security Simple Pairing user confirmation requested, this event comes */
  422.     case ESP_BT_GAP_CFM_REQ_EVT:
  423.         ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
  424.         esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
  425.         break;
  426.     /* when Security Simple Pairing passkey notified, this event comes */
  427.     case ESP_BT_GAP_KEY_NOTIF_EVT:
  428.         ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey: %d", param->key_notif.passkey);
  429.         break;
  430.     /* when Security Simple Pairing passkey requested, this event comes */
  431.     case ESP_BT_GAP_KEY_REQ_EVT:
  432.         ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
  433.         break;
  434. #endif
  435.  
  436.     /* when GAP mode changed, this event comes */
  437.     case ESP_BT_GAP_MODE_CHG_EVT:
  438.         ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode: %d", param->mode_chg.mode);
  439.         break;
  440.     /* other */
  441.     default: {
  442.         ESP_LOGI(BT_AV_TAG, "event: %d", event);
  443.         break;
  444.     }
  445.     }
  446.  
  447.     return;
  448. }
  449.  
  450. static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
  451. {
  452.     ESP_LOGD(BT_AV_TAG, "%s event: %d", __func__, event);
  453.  
  454.     switch (event) {
  455.     /* when stack up worked, this event comes */
  456.     case BT_APP_STACK_UP_EVT: {
  457.         char *dev_name = LOCAL_DEVICE_NAME;
  458.         esp_bt_dev_set_device_name(dev_name);
  459.         esp_bt_gap_register_callback(bt_app_gap_cb);
  460.  
  461.         esp_avrc_ct_init();
  462.         esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
  463.  
  464.         esp_avrc_rn_evt_cap_mask_t evt_set = {0};
  465.         esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
  466.         ESP_ERROR_CHECK(esp_avrc_tg_set_rn_evt_cap(&evt_set));
  467.  
  468.         esp_a2d_source_init();
  469.         esp_a2d_register_callback(&bt_app_a2d_cb);
  470. #ifdef SPIFFS_SAMPLE
  471.         esp_a2d_source_register_data_callback(bt_app_a2d_stream_buffer_button_cb); // Where to source the audio data from
  472. #else
  473. //        esp_a2d_source_register_data_callback(bt_app_a2d_snare_button_cb); // Where to source the audio data from
  474. #endif // SPIFFS_SAMPLE
  475.         esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, /*ESP_BT_NON_DISCOVERABLE*/ ESP_BT_GENERAL_DISCOVERABLE);
  476.  
  477.         ESP_LOGI(BT_AV_TAG, "Starting device discovery...");
  478.         s_a2d_state = APP_AV_STATE_DISCOVERING;
  479.         esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
  480.  
  481.         /* create and start heart beat timer */
  482.         do {
  483.             int tmr_id = 0;
  484.             s_tmr = xTimerCreate("connTmr", (10000 / portTICK_PERIOD_MS),
  485.                                  pdTRUE, (void *) &tmr_id, bt_app_a2d_heart_beat);
  486.             xTimerStart(s_tmr, portMAX_DELAY);
  487.         } while (0);
  488.         break;
  489.     }
  490.     /* other */
  491.     default: {
  492.         ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
  493.         break;
  494.     }
  495.     }
  496. }
  497.  
  498. static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
  499. {
  500.     bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
  501. }
  502.  
  503. /* read source audio from SPIFFS .raw sample files when we have been notified of a button press*/
  504. static int32_t bt_app_a2d_spiffs_mono_sample_button_cb(uint8_t *data, int32_t len)
  505. {
  506.     static bool button_pressed = false;
  507.  
  508.     if( xQueueReceive(buttonQueue, &button_pressed, (TickType_t)0))
  509.     {
  510.         sample_file = sample_file == sample_fileA ? sample_fileB : sample_fileA; // alternate between samples
  511.         ESP_LOGI(APP_TAG, "BT cb rxd message %d\n", button_pressed);  
  512.         fseek(sample_file, 0, SEEK_SET); // reset to play from beginning of sample to allow multiple hits to be played
  513.     }
  514.  
  515.     if (data == NULL || len < 0) {
  516.         return 0;
  517.     }
  518.  
  519.     if (sample_file == NULL) {
  520.         ESP_LOGE(BT_AV_TAG, "callback says sample file is not open");
  521.         return 0;
  522.     }
  523.  
  524.     if(button_pressed )
  525.     {
  526.         uint8_t mono_data[len/2];
  527.         int l = fread(mono_data, 1, len/2, sample_file);
  528.  
  529.         /* Method for converting mono sample to stereo*/
  530.         for (int i = 0; i < (len >> 1); i += 2) {
  531.                 // fill two samples with duplicate data to get stereo from mono sample in a normal time/duration
  532.               //  data[(i << 1) ] = mono_data[i];
  533.                 data[(i << 1) + 1] = mono_data[i + 1];
  534.               //  data[((i+1) << 1) ] = mono_data[i];
  535.                 data[((i+1) << 1) + 1] = mono_data[i + 1];
  536.  
  537.         }
  538.         // Deal with end of file
  539.         if (l < len/2) {
  540.             fseek(sample_file, 0, SEEK_SET); // reset the file pointer to the beginning for next play
  541.             button_pressed = false; // stop playing at the end of the sample
  542.             int32_t difference = len - 2 * l;
  543.           //  ESP_LOGI(BT_AV_TAG,"sample short by %i ", difference);
  544.             // Pad the buffer with silence
  545.             int i = 0;
  546.             for (i = l; i < (len >> 1); i++) {  
  547.                 data[(i << 1) ] = 0;
  548.                 data[(i << 1) + 1] = 0;
  549.             }
  550.         }
  551.     }
  552.     else // need to stream silence if no audio
  553.     {
  554.         for (int i = 0; i < (len >> 1); i++) {  
  555.             data[(i << 1) ] = 0;
  556.             data[(i << 1) + 1] = 0;
  557.         }
  558.     }
  559.     return len;
  560. }
  561.  
  562. /* read source audio from SPIFFS .raw sample files when we have been notified of a button press, and splice them together*/
  563. static int32_t bt_app_a2d_spiffs_mixed_sample_button_cb(uint8_t *data, int32_t len)
  564. {
  565.     static bool button_pressed = false;
  566.     static bool run_sampleA = false;
  567.     static bool run_sampleB = false;
  568.  
  569.     if( xQueueReceive(buttonQueue, &button_pressed, (TickType_t)0))
  570.     {
  571.         //sample_file = sample_file == sample_fileA ? sample_fileB : sample_fileA; // alternate between samples
  572.         //ESP_LOGI(APP_TAG, "BT cb rxd message %d\n", button_pressed);  
  573.         fseek(sample_fileA, 0, SEEK_SET); // reset to play from beginning of sample to allow multiple hits to be played
  574.         fseek(sample_fileB, 0, SEEK_SET); // reset to play from beginning of sample to allow multiple hits to be played
  575.         //run_sampleA = true;
  576.         //run_sampleB = true;
  577.     }
  578.  
  579.     if (data == NULL || len < 0) {
  580.         return 0;
  581.     }
  582.  
  583.     if (sample_fileA == NULL || sample_fileB == NULL) { // TODO: make null file handling for sample A and B graceful too
  584.         ESP_LOGE(BT_AV_TAG, "callback says at least one sample file is not open");
  585.         return 0;
  586.     }
  587.  
  588.     if(button_pressed )
  589.     {
  590.         // uint8_t mono_dataA[len >> 1] ;//= {0};
  591.         // uint8_t mono_dataB[len >> 1] ;// = {0};
  592.         int lA = 0;
  593.         int lB = 0;
  594.         if(run_sampleA)
  595.         {
  596.             lA = fread(mono_dataA, 1, len/2, sample_fileA);
  597.             if (lA < len/2) {
  598.                 fseek(sample_fileA, 0, SEEK_SET); // reset the file pointer to the beginning for next play
  599.                 run_sampleA = false; // stop playing at the end of the sample
  600.                 // int32_t difference = len - 2 * l;
  601.                 //  ESP_LOGI(BT_AV_TAG,"sample short by %i ", difference);
  602.                 // Pad the buffer with silence
  603.                 int i = 0;
  604.                 for (i = lA; i < (len >> 1); i += 2) {  
  605.                     mono_dataA[(i << 1) ] = 0;
  606.                     mono_dataA[(i << 1) + 1] = 0;
  607.                 }
  608.             }
  609.         }
  610.         else
  611.         {
  612.             // for (int i = 0; i < (len >> 1); i += 2) {  
  613.             //     mono_dataA[(i << 1) ] = 0;
  614.             //     mono_dataA[(i << 1) + 1] = 0;
  615.             // }
  616.         }
  617.         /*
  618.         if(run_sampleB)
  619.         {
  620.             lB = fread(mono_dataB, 1, len/2, sample_fileB);
  621.             if (lB < len/2) {
  622.                 fseek(sample_fileB, 0, SEEK_SET); // reset the file pointer to the beginning for next play
  623.                 run_sampleB = false; // stop playing at the end of the sample
  624.                 // int32_t difference = len - 2 * l;
  625.                 //  ESP_LOGI(BT_AV_TAG,"sample short by %i ", difference);
  626.                 // Pad the buffer with silence
  627.                 int i = 0;
  628.                 for (i = lB; i < (len >> 1); i += 2) {  
  629.                     mono_dataB[(i << 1) ] = 0;
  630.                     mono_dataB[(i << 1) + 1] = 0;
  631.                 }
  632.             }
  633.         }
  634.         else
  635.         {
  636.             for (int i = 0; i < (len >> 1); i += 2) {  
  637.                 mono_dataB[(i << 1) ] = 0;
  638.                 mono_dataB[(i << 1) + 1] = 0;
  639.             }
  640.         }
  641.  
  642. */
  643.         /* Method for converting mono sample to stereo*/
  644.         for (int i = 0; i < (len >> 1); i += 2) {
  645.                 // fill two samples with duplicate data to get stereo from mono sample in a normal time/duration
  646.                 // data[(i << 1) ] = (mono_dataA[i] >> 1) + (mono_dataB[i] >> 1);
  647.                 // data[(i << 1) + 1] = (mono_dataA[i + 1] >> 1) + (mono_dataB[i + 1] >> 1);
  648.                 // data[((i+1) << 1) ] = (mono_dataA[i] >> 1) + (mono_dataB[i] >> 1);
  649.                 // data[((i+1) << 1) + 1] = (mono_dataA[i + 1] >> 1) + (mono_dataB[i + 1] >> 1);
  650.                 data[(i << 1) ] = mono_dataA[i];
  651.                 data[(i << 1) + 1] = mono_dataA[i + 1];
  652.                 data[((i+1) << 1) ] = mono_dataA[i] ;
  653.                 data[((i+1) << 1) + 1] = mono_dataA[i + 1] ;
  654.         }
  655.         // Deal with end of file
  656.         // TODO: make this work properly, so end of shorter file doesn't hinder longer file
  657.         if (run_sampleA == false /*&& run_sampleB == false*/) {
  658.             button_pressed = false;
  659.         }
  660.     }
  661.     else // need to stream silence if no audio
  662.     {
  663.         for (int i = 0; i < (len >> 1); i++) {  
  664.             data[(i << 1) ] = 0;
  665.             data[(i << 1) + 1] = 0;
  666.         }
  667.     }
  668.     return len;
  669. }
  670.  
  671. /* read source audio from a FreeRTOS stream buffer when we have been notified of a button press*/
  672. static int32_t bt_app_a2d_stream_buffer_button_cb(uint8_t *data, int32_t len)
  673. {
  674.     static t_stAudioSample audio_clip;
  675.     if (data == NULL || len < 0) {
  676.         return 0;
  677.     }
  678.     //ESP_LOGI(APP_TAG, "BT cb len asked from buffer %d", len);  
  679.  
  680.     if (xQueueReceive(sampleBufferQueue, &audio_clip, (TickType_t )0))
  681.     {
  682.      //   memcpy(data, audio_clip.data_pointer, audio_clip.number_of_bytes);
  683.      for(int i = 0; i < audio_clip.number_of_bytes; i++)
  684.      {
  685.         data[i] = *(audio_clip.data_pointer + i);
  686.      }
  687.      len = audio_clip.number_of_bytes;
  688.     }
  689.     else
  690.     {
  691.         for(int i = 0; i < len; i++)
  692.         {
  693.             data[i] = 0;
  694.         }
  695.         ESP_LOGI(APP_TAG, "S: %d", audio_clip.sample_count);  
  696.     }
  697.     // if(len < 512)
  698.     //     ESP_LOGI(APP_TAG, "BT cb len read from buffer %d", len);  
  699.     xTaskNotifyGive( SM_task ); // direct to task messaging
  700.     return len;
  701. }
  702.  
  703. static void bt_app_a2d_heart_beat(TimerHandle_t arg)
  704. {
  705.     bt_app_work_dispatch(bt_app_av_sm_hdlr, BT_APP_HEART_BEAT_EVT, NULL, 0, NULL);
  706. }
  707.  
  708. static void bt_app_av_sm_hdlr(uint16_t event, void *param)
  709. {
  710.     ESP_LOGI(BT_AV_TAG, "%s state: %d, event: 0x%x", __func__, s_a2d_state, event);
  711.  
  712.     /* select handler according to different states */
  713.     switch (s_a2d_state) {
  714.     case APP_AV_STATE_DISCOVERING:
  715.     case APP_AV_STATE_DISCOVERED:
  716.         break;
  717.     case APP_AV_STATE_UNCONNECTED:
  718.         bt_app_av_state_unconnected_hdlr(event, param);
  719.         break;
  720.     case APP_AV_STATE_CONNECTING:
  721.         bt_app_av_state_connecting_hdlr(event, param);
  722.         break;
  723.     case APP_AV_STATE_CONNECTED:
  724.         bt_app_av_state_connected_hdlr(event, param);
  725.         break;
  726.     case APP_AV_STATE_DISCONNECTING:
  727.         bt_app_av_state_disconnecting_hdlr(event, param);
  728.         break;
  729.     default:
  730.         ESP_LOGE(BT_AV_TAG, "%s invalid state: %d", __func__, s_a2d_state);
  731.         break;
  732.     }
  733. }
  734.  
  735. static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param)
  736. {
  737.     esp_a2d_cb_param_t *a2d = NULL;
  738.     /* handle the events of intrest in unconnected state */
  739.     switch (event) {
  740.     case ESP_A2D_CONNECTION_STATE_EVT:
  741.     case ESP_A2D_AUDIO_STATE_EVT:
  742.     case ESP_A2D_AUDIO_CFG_EVT:
  743.     case ESP_A2D_MEDIA_CTRL_ACK_EVT:
  744.         break;
  745.     case BT_APP_HEART_BEAT_EVT: {
  746.         uint8_t *bda = s_peer_bda;
  747.         ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer address: %02x:%02x:%02x:%02x:%02x:%02x",
  748.                  bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
  749.         ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer named: %s", s_peer_bdname);
  750.         esp_a2d_source_connect(s_peer_bda);
  751.         s_a2d_state = APP_AV_STATE_CONNECTING;
  752.         s_connecting_intv = 0;
  753.         break;
  754.     }
  755.     case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
  756.         a2d = (esp_a2d_cb_param_t *)(param);
  757.         ESP_LOGI(BT_AV_TAG, "%s, delay value: %u * 1/10 ms", __func__, a2d->a2d_report_delay_value_stat.delay_value);
  758.         break;
  759.     }
  760.     default: {
  761.         ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
  762.         break;
  763.     }
  764.     }
  765. }
  766.  
  767. static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param)
  768. {
  769.     esp_a2d_cb_param_t *a2d = NULL;
  770.  
  771.     /* handle the events of intrest in connecting state */
  772.     switch (event) {
  773.     case ESP_A2D_CONNECTION_STATE_EVT: {
  774.         a2d = (esp_a2d_cb_param_t *)(param);
  775.         if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED) {
  776.             ESP_LOGI(BT_AV_TAG, "a2dp connected");
  777.             s_a2d_state =  APP_AV_STATE_CONNECTED;
  778.             s_media_state = APP_AV_MEDIA_STATE_IDLE;
  779.             esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
  780.         } else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
  781.             s_a2d_state =  APP_AV_STATE_UNCONNECTED;
  782.         }
  783.         break;
  784.     }
  785.     case ESP_A2D_AUDIO_STATE_EVT:
  786.     case ESP_A2D_AUDIO_CFG_EVT:
  787.     case ESP_A2D_MEDIA_CTRL_ACK_EVT:
  788.         break;
  789.     case BT_APP_HEART_BEAT_EVT:
  790.         /* Try reconnecting twice if disconnected*/
  791.         if (s_connecting_intv < 2)
  792.         {
  793.             ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer named: %s", s_peer_bdname);
  794.             esp_a2d_source_connect(s_peer_bda);
  795.         }
  796.         /**
  797.          * Switch state to APP_AV_STATE_UNCONNECTED
  798.          * when connecting lasts more than 2 heart beat intervals.
  799.          */
  800.         if (++s_connecting_intv >= 2) {
  801.             s_a2d_state = APP_AV_STATE_UNCONNECTED;
  802.             s_connecting_intv = 0;
  803.         }
  804.         break;
  805.     case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
  806.         a2d = (esp_a2d_cb_param_t *)(param);
  807.         ESP_LOGI(BT_AV_TAG, "%s, delay value: %u * 1/10 ms", __func__, a2d->a2d_report_delay_value_stat.delay_value);
  808.         break;
  809.     }
  810.     default:
  811.         ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
  812.         break;
  813.     }
  814. }
  815.  
  816. static void bt_app_av_media_proc(uint16_t event, void *param)
  817. {
  818.     esp_a2d_cb_param_t *a2d = NULL;
  819.  
  820.     switch (s_media_state) {
  821.     case APP_AV_MEDIA_STATE_IDLE: {
  822.         if (event == BT_APP_HEART_BEAT_EVT) {
  823.             ESP_LOGI(BT_AV_TAG, "a2dp media ready checking ...");
  824.             esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY);
  825.         } else if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
  826.             a2d = (esp_a2d_cb_param_t *)(param);
  827.             if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY &&
  828.                     a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
  829.                 ESP_LOGI(BT_AV_TAG, "a2dp media ready, starting ...");
  830.                 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_START);
  831.                 s_media_state = APP_AV_MEDIA_STATE_STARTING;
  832.             }
  833.         }
  834.         break;
  835.     }
  836.     case APP_AV_MEDIA_STATE_STARTING: {
  837.         if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
  838.             a2d = (esp_a2d_cb_param_t *)(param);
  839.             if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_START &&
  840.                     a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
  841.                 ESP_LOGI(BT_AV_TAG, "a2dp media start successfully.");
  842.                 s_intv_cnt = 0;
  843.                 s_media_state = APP_AV_MEDIA_STATE_STARTED;
  844.             } else {
  845.                 /* not started succesfully, transfer to idle state */
  846.                 ESP_LOGI(BT_AV_TAG, "a2dp media start failed.");
  847.                 s_media_state = APP_AV_MEDIA_STATE_IDLE;
  848.             }
  849.         }
  850.         break;
  851.     }
  852.     case APP_AV_MEDIA_STATE_STARTED: {
  853.         if (event == BT_APP_HEART_BEAT_EVT) {
  854.             /* stop media after 10 heart beat intervals */
  855.             if (++s_intv_cnt >= 10) {
  856.                 /*Comment out the automatic stopping every 10 heartbeats*/
  857.                 // ESP_LOGI(BT_AV_TAG, "a2dp media stopping...");
  858.                 // esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
  859.                 // s_media_state = APP_AV_MEDIA_STATE_STOPPING;
  860.                 s_intv_cnt = 0;
  861.             }
  862.         }
  863.         break;
  864.     }
  865.     case APP_AV_MEDIA_STATE_STOPPING: {
  866.         if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) {
  867.             a2d = (esp_a2d_cb_param_t *)(param);
  868.             if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP &&
  869.                     a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) {
  870.                 ESP_LOGI(BT_AV_TAG, "a2dp media stopped successfully, disconnecting...");
  871.                 s_media_state = APP_AV_MEDIA_STATE_IDLE;
  872.                 esp_a2d_source_disconnect(s_peer_bda);
  873.                 s_a2d_state = APP_AV_STATE_DISCONNECTING;
  874.             } else {
  875.                 ESP_LOGI(BT_AV_TAG, "a2dp media stopping...");
  876.                 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP);
  877.             }
  878.         }
  879.         break;
  880.     }
  881.     default: {
  882.         break;
  883.     }
  884.     }
  885. }
  886.  
  887. static void bt_app_av_state_connected_hdlr(uint16_t event, void *param)
  888. {
  889.     esp_a2d_cb_param_t *a2d = NULL;
  890.  
  891.     /* handle the events of interest in connected state */
  892.     switch (event) {
  893.     case ESP_A2D_CONNECTION_STATE_EVT: {
  894.         a2d = (esp_a2d_cb_param_t *)(param);
  895.         if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
  896.             ESP_LOGI(BT_AV_TAG, "a2dp disconnected");
  897.             s_a2d_state = APP_AV_STATE_UNCONNECTED;
  898.             esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_NON_DISCOVERABLE/*ESP_BT_GENERAL_DISCOVERABLE*/); // DEBUG: attempt to include existing headphones in scan
  899.         }
  900.         break;
  901.     }
  902.     case ESP_A2D_AUDIO_STATE_EVT: {
  903.         a2d = (esp_a2d_cb_param_t *)(param);
  904.         if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
  905.             s_pkt_cnt = 0;
  906.         }
  907.         break;
  908.     }
  909.     case ESP_A2D_AUDIO_CFG_EVT:
  910.         // not suppposed to occur for A2DP source
  911.         break;
  912.     case ESP_A2D_MEDIA_CTRL_ACK_EVT:
  913.     case BT_APP_HEART_BEAT_EVT: {
  914.         bt_app_av_media_proc(event, param);
  915.         break;
  916.     }
  917.     case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
  918.         a2d = (esp_a2d_cb_param_t *)(param);
  919.         ESP_LOGI(BT_AV_TAG, "%s, delay value: %u * 1/10 ms", __func__, a2d->a2d_report_delay_value_stat.delay_value);
  920.         break;
  921.     }
  922.     default: {
  923.         ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
  924.         break;
  925.     }
  926.     }
  927. }
  928.  
  929. static void bt_app_av_state_disconnecting_hdlr(uint16_t event, void *param)
  930. {
  931.     esp_a2d_cb_param_t *a2d = NULL;
  932.  
  933.     /* handle the events of intrest in disconnecing state */
  934.     switch (event) {
  935.     case ESP_A2D_CONNECTION_STATE_EVT: {
  936.         a2d = (esp_a2d_cb_param_t *)(param);
  937.         if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
  938.             ESP_LOGI(BT_AV_TAG, "a2dp disconnected");
  939.             s_a2d_state =  APP_AV_STATE_UNCONNECTED;
  940.             esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
  941.         }
  942.         break;
  943.     }
  944.     case ESP_A2D_AUDIO_STATE_EVT:
  945.     case ESP_A2D_AUDIO_CFG_EVT:
  946.     case ESP_A2D_MEDIA_CTRL_ACK_EVT:
  947.     case BT_APP_HEART_BEAT_EVT:
  948.         break;
  949.     case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
  950.         a2d = (esp_a2d_cb_param_t *)(param);
  951.         ESP_LOGI(BT_AV_TAG, "%s, delay value: 0x%u * 1/10 ms", __func__, a2d->a2d_report_delay_value_stat.delay_value);
  952.         break;
  953.     }
  954.     default: {
  955.         ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
  956.         break;
  957.     }
  958.     }
  959. }
  960.  
  961. /* callback function for AVRCP controller */
  962. static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
  963. {
  964.     switch (event) {
  965.     case ESP_AVRC_CT_CONNECTION_STATE_EVT:
  966.     case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
  967.     case ESP_AVRC_CT_METADATA_RSP_EVT:
  968.     case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
  969.     case ESP_AVRC_CT_REMOTE_FEATURES_EVT:
  970.     case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT:
  971.     case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
  972.         bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
  973.         break;
  974.     }
  975.     default: {
  976.         ESP_LOGE(BT_RC_CT_TAG, "Invalid AVRC event: %d", event);
  977.         break;
  978.     }
  979.     }
  980. }
  981.  
  982. static void bt_av_volume_changed(void)
  983. {
  984.     if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
  985.                                            ESP_AVRC_RN_VOLUME_CHANGE)) {
  986.         esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, ESP_AVRC_RN_VOLUME_CHANGE, 0);
  987.     }
  988. }
  989.  
  990. void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
  991. {
  992.     switch (event_id) {
  993.     /* when volume changed locally on target, this event comes */
  994.     case ESP_AVRC_RN_VOLUME_CHANGE: {
  995.         ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume);
  996.         ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume: volume %d", event_parameter->volume + 5);
  997.         esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, event_parameter->volume + 5);
  998.         bt_av_volume_changed();
  999.         break;
  1000.     }
  1001.     /* other */
  1002.     default:
  1003.         break;
  1004.     }
  1005. }
  1006.  
  1007. /* AVRC controller event handler */
  1008. static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
  1009. {
  1010.     ESP_LOGD(BT_RC_CT_TAG, "%s evt %d", __func__, event);
  1011.     esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param);
  1012.  
  1013.     switch (event) {
  1014.     /* when connection state changed, this event comes */
  1015.     case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
  1016.         uint8_t *bda = rc->conn_stat.remote_bda;
  1017.         ESP_LOGI(BT_RC_CT_TAG, "AVRC conn_state event: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
  1018.                  rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
  1019.  
  1020.         if (rc->conn_stat.connected) {
  1021.             esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
  1022.         } else {
  1023.             s_avrc_peer_rn_cap.bits = 0;
  1024.         }
  1025.         break;
  1026.     }
  1027.     /* when passthrough responsed, this event comes */
  1028.     case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
  1029.         ESP_LOGI(BT_RC_CT_TAG, "AVRC passthrough response: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
  1030.         break;
  1031.     }
  1032.     /* when metadata responsed, this event comes */
  1033.     case ESP_AVRC_CT_METADATA_RSP_EVT: {
  1034.         ESP_LOGI(BT_RC_CT_TAG, "AVRC metadata response: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text);
  1035.         free(rc->meta_rsp.attr_text);
  1036.         break;
  1037.     }
  1038.     /* when notification changed, this event comes */
  1039.     case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
  1040.         ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
  1041.         bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter);
  1042.         break;
  1043.     }
  1044.     /* when indicate feature of remote device, this event comes */
  1045.     case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
  1046.         ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %x, TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag);
  1047.         /* DEBUG: - hack to try and make reconnection more resilient*/
  1048.             // ESP_LOGI(BT_AV_TAG, "a2dp connected");
  1049.             // s_a2d_state =  APP_AV_STATE_CONNECTED;
  1050.             // s_media_state = APP_AV_MEDIA_STATE_IDLE;
  1051.         break;
  1052.     }
  1053.     /* when get supported notification events capability of peer device, this event comes */
  1054.     case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
  1055.         ESP_LOGI(BT_RC_CT_TAG, "remote rn_cap: count %d, bitmask 0x%x", rc->get_rn_caps_rsp.cap_count,
  1056.                  rc->get_rn_caps_rsp.evt_set.bits);
  1057.         s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
  1058.  
  1059.         bt_av_volume_changed();
  1060.         break;
  1061.     }
  1062.     /* when set absolute volume responsed, this event comes */
  1063.     case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
  1064.         ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume response: volume %d", rc->set_volume_rsp.volume);
  1065.         break;
  1066.     }
  1067.     /* other */
  1068.     default: {
  1069.         ESP_LOGE(BT_RC_CT_TAG, "%s unhandled event: %d", __func__, event);
  1070.         break;
  1071.     }
  1072.     }
  1073. }
  1074.  
  1075. /* Initialise GPIOS*/
  1076. static void app_gpio_init()
  1077. {
  1078.     /* Set up button pins*/
  1079.     gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
  1080.     gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLDOWN_ONLY);
  1081.     gpio_set_intr_type(BUTTON_PIN, GPIO_INTR_POSEDGE);
  1082.     gpio_install_isr_service(ESP_INR_FLAG_DEFAULT);
  1083.     gpio_isr_handler_add(BUTTON_PIN, button_isr_handler, NULL);
  1084.     /* Set up interrupt task*/
  1085.     xTaskCreate(interrupt_task, "interrupt_task", 4096, NULL, 10, &ISR);
  1086.  
  1087.     /* Set up LED pin*/
  1088.     gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
  1089.     gpio_set_level(LED_PIN, 1);
  1090. }
  1091.  
  1092. void IRAM_ATTR button_isr_handler(void *arg){
  1093.     xTaskResumeFromISR(ISR);
  1094. }
  1095.  
  1096. static void interrupt_task(void *arg){
  1097.   /* Button and led logic variables*/
  1098.   bool led_status = false;
  1099.   bool button_state = false;
  1100.   /* Debounce delay variables for TODO: implement in future*/
  1101.   TickType_t xLastWakeTime;
  1102.   const TickType_t xFrequency = 1;
  1103.   BaseType_t xWasDelayed;
  1104.  
  1105.   /* Create the queue to pass data to the A2DP audio data loader*/
  1106.   buttonQueue = xQueueCreate(1, sizeof(led_status));
  1107.     if (buttonQueue == 0)
  1108.     {
  1109.      ESP_LOGI(APP_TAG, "Failed to create buttonQueue= %p\n", buttonQueue);
  1110.     }
  1111. // bool old_button_state = false;
  1112.   while(1){
  1113.     vTaskSuspend(NULL);
  1114.     vTaskDelay(10/portTICK_PERIOD_MS); // delay for a modicum of debounce
  1115.   //  xTaskDelayUntil(10/portTICK_PERIOD_MS); // delay for a modicum of debounce
  1116.     button_state = (bool)gpio_get_level(BUTTON_PIN);
  1117.     if(button_state /*&& button_state != old_button_state*/)
  1118.     {
  1119.         led_status = !led_status;
  1120.      //   old_button_state = button_state;
  1121.         ESP_LOGI(APP_TAG,"Button pressed!");
  1122.         xQueueSend(buttonQueue, &button_state, (TickType_t)0);
  1123.     }
  1124.     gpio_set_level(LED_PIN, led_status);
  1125.    
  1126.   }
  1127. }
  1128.  
  1129. static void sample_mix_task(void *arg)
  1130. {
  1131.     static bool button_pressed = false;
  1132.     static int8_t raw_data[SAMPLE_STREAM_BUFFER_SIZE/2]; // Needs to be signed int for mixing and volume to work
  1133.     static int8_t raw_dataA[SAMPLE_STREAM_BUFFER_SIZE/2]; // Needs to be signed int for mixing and volume to work
  1134.     static int8_t raw_dataB[SAMPLE_STREAM_BUFFER_SIZE/2]; // Needs to be signed int for mixing and volume to work
  1135.     int8_t * rawArrayPointer = raw_dataA; // point to the array of mixed samples
  1136.     uint8_t * sampleArrayPointer = sample_data; // point to the array of mixed samples
  1137.     uint8_t * blankArrayPointer = blank_data; // point to the array of zeroes
  1138.     static int32_t sent = 0;
  1139.     int count = 0;
  1140.     int waitCount = 0;
  1141.     uint8_t increment = 0; // where we look in the volume divisor array
  1142.     uint8_t volume_divisor = volumeDivisors[increment]; // start with full volume
  1143.     static uint16_t pointerOffset = 0; // where in sample array to start reading from
  1144.  
  1145.     static t_stAudioSample audio_clip;
  1146.     audio_clip.data_pointer = sampleArrayPointer;
  1147.     audio_clip.number_of_bytes = SAMPLE_STREAM_BUFFER_SIZE;
  1148.  
  1149.     static t_stAudioSample blank_clip;
  1150.     blank_clip.data_pointer = blankArrayPointer;
  1151.     blank_clip.number_of_bytes = SAMPLE_STREAM_BUFFER_SIZE;
  1152.  
  1153.     // make the sample buffer pointer queue
  1154.     sampleBufferQueue = xQueueCreate(2, sizeof(t_stAudioSample));
  1155.     if (sampleBufferQueue == NULL)
  1156.     {
  1157.         ESP_LOGI(APP_TAG, "Failed to create sampleBufferQueue= %p\n", sampleBufferQueue);
  1158.     }
  1159.     while(1)
  1160.     {
  1161.         if(xQueueReceive(buttonQueue, &button_pressed, (TickType_t)0))
  1162.         {
  1163.             fseek(sample_fileA, 0, SEEK_SET);
  1164.             fseek(sample_fileB, 0, SEEK_SET);
  1165.             fseek(sample_fileC, 0, SEEK_SET);
  1166.             waitCount = 0; // start counter from zero when button pressed
  1167.         }
  1168.        
  1169.         if(button_pressed && uxQueueSpacesAvailable(sampleBufferQueue))
  1170.         {
  1171.             int lRead = fread(raw_data, 1, SAMPLE_STREAM_BUFFER_SIZE/2, sample_fileC);
  1172.            // int lReadB = fread(raw_dataB, 1, SAMPLE_STREAM_BUFFER_SIZE/2, sample_fileB);
  1173.             if (lRead < SAMPLE_STREAM_BUFFER_SIZE/2) {
  1174.                 button_pressed = false; // stop playing at the end of the sample
  1175.                 // Pad the buffer with silence
  1176.                 // int i = 0;
  1177.                 // for (i = lRead; i < (SAMPLE_STREAM_BUFFER_SIZE >> 1); i+=2 ) {  
  1178.                 //     sample_data[(i << 1) ] = 0;
  1179.                 //     sample_data[(i << 1) + 1] = 0;
  1180.                 // }
  1181.                 ESP_LOGI(APP_TAG, "End of sample, count %d, wait count %d", count, waitCount);
  1182.                 count = 0;  
  1183.                 waitCount = 0;
  1184.                 /* Change volume if desired*/
  1185.                 // increment = (increment + 1 ) % NUM_OF_VOLUME_SETTINGS;
  1186.                 // volume_divisor = volumeDivisors[increment];
  1187.             }
  1188.             /* Method for converting mono sample to stereo*/
  1189.             for (int i = 0; i < lRead; i += 2) {
  1190.                 /* Right ear audio */
  1191.                 //sample_data[(i << 1) ] = 0; //raw_data[i] / 1 ; // least significant element
  1192.                 sample_data[(i << 1) + 1 + pointerOffset] = raw_data[i + 1] /* / volume_divisor */; // most significant element
  1193.                 /* Left ear audio */
  1194.                 //sample_data[((i+1) << 1) ] = 0; //raw_data[i] / 1 ; // least significant element
  1195.                 sample_data[((i+1) << 1) + 1 + pointerOffset] = raw_data[i + 1] /* / volume_divisor */; // most significant element
  1196.             }
  1197.             audio_clip.sample_count = count++;
  1198.             // if (count > 90)
  1199.             // {
  1200.             //      button_pressed = false; // DEBUG see error only happens if running past 100 samples
  1201.             //      count = 0;
  1202.             //     fseek(sample_fileB, 0, SEEK_SET);
  1203.             // }
  1204.             audio_clip.data_pointer = sampleArrayPointer + pointerOffset;
  1205.             sent = xQueueSend(sampleBufferQueue, &audio_clip, (TickType_t)0);
  1206.             //rawArrayPointer = rawArrayPointer == raw_dataA ? raw_dataB : raw_dataA; // toggle between two arrays
  1207.             pointerOffset = pointerOffset == 0 ? SAMPLE_STREAM_BUFFER_SIZE : 0; // toggle between beginning and halfway through the array.
  1208.         }
  1209.         else if (button_pressed)
  1210.         {
  1211.             waitCount++; // count how many times this happened      
  1212.             //sent = xQueueSend(sampleBufferQueue, &blank_clip, (TickType_t)0);
  1213.             ulTaskNotifyTake(true, (TickType_t)10 ); // was 10, a bit crunchy with toms, got better with 100    
  1214.         }
  1215.         else if (uxQueueSpacesAvailable(sampleBufferQueue))
  1216.         {
  1217.             sent = xQueueSend(sampleBufferQueue, &blank_clip, (TickType_t)10);
  1218.         }
  1219.         else
  1220.         {
  1221.             //sent = xQueueSend(sampleBufferQueue, &blank_clip, (TickType_t)0);
  1222.            ulTaskNotifyTake(true, (TickType_t)10 ); // was 10, a bit crunchy with toms, got better with 100
  1223.         //     // Just send zeroes while no sample is playing
  1224.         }
  1225.         /* Wait for the BT audio callback to finish with samples*/
  1226.     //    ulTaskNotifyTake(true, (TickType_t)portMAX_DELAY ); // was 10, a bit crunchy with toms, got better with 100
  1227.     //    vTaskDelay(0); // virtual delay to prevent blocking and core wdt firing
  1228.    
  1229.     }
  1230. }
  1231.  
  1232. /********************************
  1233.  * Test SPIFFS
  1234. ********************************/
  1235. void app_test_spiffs()
  1236. {
  1237.     init_spiffs();
  1238.   ESP_LOGE(TAG, "list files in spiffs");
  1239.     list_directory("");
  1240.  
  1241.     struct stat st;
  1242.     if (stat("/R8-OpenSnare-MonoS16PCM44k.raw", &st) == 0) {
  1243.         ESP_LOGI(TAG, "R8-OpenSnare-MonoS16PCM44k.raw found");
  1244.         sample_fileA = fopen("/R8-OpenSnare-MonoS16PCM44k.raw", "rb");
  1245.         sample_file = sample_fileA;
  1246.     } else {
  1247.         ESP_LOGI(TAG, "R8-OpenSnare-MonoS16PCM44k.raw not found");
  1248.         sample_file = NULL;
  1249.     }
  1250.     if (stat("/R8-RoomTom1-MonoS16PCM44k.raw", &st) == 0) {
  1251.         ESP_LOGI(TAG, "R8-RoomTom1-MonoS16PCM44k.raw found");
  1252.         sample_fileB = fopen("/R8-RoomTom1-MonoS16PCM44k.raw", "rb");
  1253.         sample_file = sample_fileB;
  1254.     } else {
  1255.         ESP_LOGI(TAG, "R8-RoomTom1-MonoS16PCM44k.raw not found");
  1256.     }
  1257.     if (stat("/R8-CrashCymbal-M-S16PCM44k.raw", &st) == 0) {
  1258.         ESP_LOGI(TAG, "R8-CrashCymbal-M-S16PCM44k.raw found");
  1259.         sample_fileC = fopen("/R8-CrashCymbal-M-S16PCM44k.raw", "rb");
  1260.         sample_file = sample_fileC;
  1261.     } else {
  1262.         ESP_LOGI(TAG, "R8-CrashCymbal-M-S16PCM44k.raw not found");
  1263.         sample_file = NULL;
  1264.     }
  1265. }
  1266.  
  1267. /*********************************
  1268.  * MAIN ENTRY POINT
  1269.  ********************************/
  1270.  
  1271. void app_main(void)
  1272. {
  1273.     /* initialize NVS — it is used to store PHY calibration data */
  1274.     esp_err_t ret = nvs_flash_init();
  1275.     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  1276.         ESP_ERROR_CHECK(nvs_flash_erase());
  1277.         ret = nvs_flash_init();
  1278.     }
  1279.     ESP_ERROR_CHECK(ret);
  1280.  
  1281.     /*
  1282.      * This example only uses the functions of Classical Bluetooth.
  1283.      * So release the controller memory for Bluetooth Low Energy.
  1284.      */
  1285.     ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
  1286.  
  1287.     esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  1288.     if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
  1289.         ESP_LOGE(BT_AV_TAG, "%s initialize controller failed\n", __func__);
  1290.         return;
  1291.     }
  1292.     if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
  1293.         ESP_LOGE(BT_AV_TAG, "%s enable controller failed\n", __func__);
  1294.         return;
  1295.     }
  1296.     if (esp_bluedroid_init() != ESP_OK) {
  1297.         ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed\n", __func__);
  1298.         return;
  1299.     }
  1300.     if (esp_bluedroid_enable() != ESP_OK) {
  1301.         ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed\n", __func__);
  1302.         return;
  1303.     }
  1304.  
  1305. #if (CONFIG_BT_SSP_ENABLED == true)
  1306.     /* set default parameters for Secure Simple Pairing */
  1307.     esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
  1308.     esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
  1309.     esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
  1310. #endif
  1311.  
  1312.     /*
  1313.      * Set default parameters for Legacy Pairing
  1314.      * Use variable pin, input pin code when pairing
  1315.      */
  1316.     esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
  1317.     esp_bt_pin_code_t pin_code;
  1318.     esp_bt_gap_set_pin(pin_type, 0, pin_code);
  1319.  
  1320.     bt_app_task_start_up();
  1321.     /* Bluetooth device name, connection mode and profile set up */
  1322.     bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_STACK_UP_EVT, NULL, 0, NULL);
  1323.  
  1324.     /* Set up GPIOs*/
  1325.     app_gpio_init();
  1326.  
  1327.     /* Test if can open file in SPIFFS*/
  1328.     app_test_spiffs();
  1329.  
  1330.     /* Set up sample preparation task*/
  1331.     xTaskCreatePinnedToCore(sample_mix_task, "sample_mix_task", 8192, NULL, 10, &SM_task, 1);// pinned to core 1 as BT is on core 0
  1332.  //   xTaskCreate(sample_mix_task, "sample_mix_task", 8192, NULL, 10, &SM_task);// pinned to core 1 as BT is on core 0
  1333.  
  1334.     /* Start a non-returning while loop*/
  1335.     while(1)
  1336.     {
  1337.         vTaskDelay(10/portTICK_PERIOD_MS); // required to prevent watchdog from firing
  1338.     }
  1339.  
  1340. }

smerrett79
Posts: 2
Joined: Tue Jan 24, 2023 12:58 am

Re: A2DP source Task buffer fails to fill the Queue the 100th time, every time. Why?

Postby smerrett79 » Fri Feb 10, 2023 1:21 pm

So please could someone from Espressif or another forum regular give me some tips to improve my request for help? As no-one has responded so far that's probably because I haven't framed the question properly or provided enough detail for someone to suggest where to go troubleshooting next.

I attach my sdkconfig in case that is important to shed light on why I am getting this buffer glitching issue. I'm happy to remove my main.c file from the initial message if that is a problem, or even zip up the entire repo and post it. Just really keen to get some help from people more familiar with the part and the toolchain.

Thanks
Attachments
sdkconfig.zip
(13.37 KiB) Downloaded 359 times


Last bumped by smerrett79 on Fri Feb 10, 2023 1:21 pm.

Who is online

Users browsing this forum: No registered users and 112 guests