140 lines
4.4 KiB
C
140 lines
4.4 KiB
C
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "esp_log.h"
|
|
|
|
#include "esp_bt_main.h"
|
|
#include "esp_bt_device.h"
|
|
#include "esp_gap_bt_api.h"
|
|
#include "esp_a2dp_api.h"
|
|
#include "esp_avrc_api.h"
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "driver/i2s.h"
|
|
|
|
#include "sys/lock.h"
|
|
|
|
#include "bt_app_core.h"
|
|
#include "H2201_i2s.h"
|
|
#include "H2201_a2dp.h"
|
|
|
|
static void h2201_a2dp_eventhandler(uint16_t event, void *p_param);
|
|
|
|
static uint32_t s_pkt_cnt = 0;
|
|
static esp_a2d_audio_state_t s_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
|
static const char *s_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
|
|
static const char *s_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"};
|
|
|
|
/* callback for A2DP sink */
|
|
void h2201_a2dp_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
|
{
|
|
switch (event)
|
|
{
|
|
case ESP_A2D_CONNECTION_STATE_EVT:
|
|
case ESP_A2D_AUDIO_STATE_EVT:
|
|
case ESP_A2D_AUDIO_CFG_EVT:
|
|
case ESP_A2D_PROF_STATE_EVT:
|
|
{
|
|
bt_app_work_dispatch(h2201_a2dp_eventhandler, event, param, sizeof(esp_a2d_cb_param_t), NULL);
|
|
break;
|
|
}
|
|
default:
|
|
ESP_LOGE(H2201_A2DP_TAG, "Invalid A2DP event: %d", event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void h2201_a2dp_data_callback(const uint8_t *data, uint32_t len)
|
|
{
|
|
h2201_i2s_write_ringbuf(data, len);
|
|
// if (++s_pkt_cnt % 100 == 0) {
|
|
// ESP_LOGI(H2201_A2DP_TAG, "Audio packet count %u", s_pkt_cnt);
|
|
// }
|
|
}
|
|
|
|
static void h2201_a2dp_eventhandler(uint16_t event, void *p_param)
|
|
{
|
|
ESP_LOGD(H2201_A2DP_TAG, "%s evt %d", __func__, event);
|
|
esp_a2d_cb_param_t *a2d = NULL;
|
|
switch (event)
|
|
{
|
|
case ESP_A2D_CONNECTION_STATE_EVT:
|
|
{
|
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
uint8_t *bda = a2d->conn_stat.remote_bda;
|
|
ESP_LOGI(H2201_A2DP_TAG, "A2DP connection state: %s, [%02x:%02x:%02x:%02x:%02x:%02x]", s_a2d_conn_state_str[a2d->conn_stat.state], bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
|
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED)
|
|
{
|
|
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
|
h2201_i2s_task_shut_down();
|
|
}
|
|
else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED)
|
|
{
|
|
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
|
|
h2201_i2s_task_start_up();
|
|
}
|
|
break;
|
|
}
|
|
case ESP_A2D_AUDIO_STATE_EVT:
|
|
{
|
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
ESP_LOGI(H2201_A2DP_TAG, "A2DP audio state: %s", s_a2d_audio_state_str[a2d->audio_stat.state]);
|
|
s_audio_state = a2d->audio_stat.state;
|
|
if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state)
|
|
{
|
|
s_pkt_cnt = 0;
|
|
}
|
|
break;
|
|
}
|
|
case ESP_A2D_AUDIO_CFG_EVT:
|
|
{
|
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
ESP_LOGI(H2201_A2DP_TAG, "A2DP audio stream configuration, codec type %d", a2d->audio_cfg.mcc.type);
|
|
// for now only SBC stream is supported
|
|
if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC)
|
|
{
|
|
int sample_rate = 16000;
|
|
char oct0 = a2d->audio_cfg.mcc.cie.sbc[0];
|
|
if (oct0 & (0x01 << 6))
|
|
{
|
|
sample_rate = 32000;
|
|
}
|
|
else if (oct0 & (0x01 << 5))
|
|
{
|
|
sample_rate = 44100;
|
|
}
|
|
else if (oct0 & (0x01 << 4))
|
|
{
|
|
sample_rate = 48000;
|
|
}
|
|
i2s_set_clk(0, sample_rate, 16, 2);
|
|
|
|
ESP_LOGI(H2201_A2DP_TAG, "Configure audio player %x-%x-%x-%x",
|
|
a2d->audio_cfg.mcc.cie.sbc[0],
|
|
a2d->audio_cfg.mcc.cie.sbc[1],
|
|
a2d->audio_cfg.mcc.cie.sbc[2],
|
|
a2d->audio_cfg.mcc.cie.sbc[3]);
|
|
ESP_LOGI(H2201_A2DP_TAG, "Audio player configured, sample rate=%d", sample_rate);
|
|
}
|
|
break;
|
|
}
|
|
case ESP_A2D_PROF_STATE_EVT:
|
|
{
|
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
if (ESP_A2D_INIT_SUCCESS == a2d->a2d_prof_stat.init_state)
|
|
{
|
|
ESP_LOGI(H2201_A2DP_TAG, "A2DP PROF STATE: Init Compl\n");
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGI(H2201_A2DP_TAG, "A2DP PROF STATE: Deinit Compl\n");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
ESP_LOGE(H2201_A2DP_TAG, "%s unhandled evt %d", __func__, event);
|
|
break;
|
|
}
|
|
} |