a2dp to seperate file

This commit is contained in:
Martijn Scheepers
2022-04-25 15:17:50 +02:00
parent 3a71298533
commit 4ede660f06
7 changed files with 169 additions and 147 deletions

View File

@@ -12,5 +12,8 @@
"idf.portWin": "COM5", "idf.portWin": "COM5",
"idf.pythonBinPathWin": "C:\\Users\\ms\\.espressif\\python_env\\idf4.4_py3.8_env\\Scripts\\python.exe", "idf.pythonBinPathWin": "C:\\Users\\ms\\.espressif\\python_env\\idf4.4_py3.8_env\\Scripts\\python.exe",
"idf.toolsPathWin": "C:\\Users\\ms\\.espressif", "idf.toolsPathWin": "C:\\Users\\ms\\.espressif",
"idf.flashType": "UART" "idf.flashType": "UART",
"files.associations": {
"esp_log.h": "c"
}
} }

View File

@@ -1,4 +1,4 @@
idf_component_register(SRCS "H2201_i2s.c" "bt_app_av.c" idf_component_register(SRCS "H2201_a2dp.c" "H2201_i2s.c" "bt_app_av.c"
"bt_app_core.c" "bt_app_core.c"
"main.c" "main.c"
INCLUDE_DIRS ".") INCLUDE_DIRS ".")

140
ESP32/main/H2201_a2dp.c Normal file
View File

@@ -0,0 +1,140 @@
#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;
}
}

19
ESP32/main/H2201_a2dp.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef __H2201_A2DP_H__
#define __H2201_A2DP_H__
#include <stdint.h>
#include "esp_a2dp_api.h"
#define H2201_A2DP_TAG "A2DP"
/**
* @brief callback function for A2DP sink
*/
void h2201_a2dp_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
/**
* @brief callback function for A2DP sink audio data stream
*/
void h2201_a2dp_data_callback(const uint8_t *data, uint32_t len);
#endif /* __H2201_A2DP_H__ */

View File

@@ -1,12 +1,3 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
@@ -36,46 +27,14 @@
#define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3) #define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3)
#define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4) #define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4)
static void h2201_a2dp_eventhandler(uint16_t event, void *p_param);
static void h2201_avrcp_controller_eventhandler(uint16_t event, void *p_param); static void h2201_avrcp_controller_eventhandler(uint16_t event, void *p_param);
static void h2201_avrcp_target_eventhandler(uint16_t event, void *p_param); static void h2201_avrcp_target_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"};
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap; static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
static _lock_t s_volume_lock; static _lock_t s_volume_lock;
static uint8_t s_volume = 0; static uint8_t s_volume = 0;
static bool s_volume_notify; static bool s_volume_notify;
/* 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(BT_AV_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(BT_AV_TAG, "Audio packet count %u", s_pkt_cnt);
// }
}
void bt_app_alloc_meta_buffer(esp_avrc_ct_cb_param_t *param) void bt_app_alloc_meta_buffer(esp_avrc_ct_cb_param_t *param)
{ {
esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(param); esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(param);
@@ -126,92 +85,6 @@ void h2201_avrcp_target_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_pa
} }
} }
static void h2201_a2dp_eventhandler(uint16_t event, void *p_param)
{
ESP_LOGD(BT_AV_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(BT_AV_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(BT_AV_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(BT_AV_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(BT_AV_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(BT_AV_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(BT_AV_TAG, "A2DP PROF STATE: Init Compl\n");
}
else
{
ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Deinit Compl\n");
}
break;
}
default:
ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
break;
}
}
static void h2201_avrcp_new_track(void) static void h2201_avrcp_new_track(void)
{ {
// request metadata // request metadata

View File

@@ -1,11 +1,3 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef __BT_APP_AV_H__ #ifndef __BT_APP_AV_H__
#define __BT_APP_AV_H__ #define __BT_APP_AV_H__
@@ -17,16 +9,6 @@
#define BT_RC_TG_TAG "RCTG" #define BT_RC_TG_TAG "RCTG"
#define BT_RC_CT_TAG "RCCT" #define BT_RC_CT_TAG "RCCT"
/**
* @brief callback function for A2DP sink
*/
void h2201_a2dp_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
/**
* @brief callback function for A2DP sink audio data stream
*/
void h2201_a2dp_data_callback(const uint8_t *data, uint32_t len);
/** /**
* @brief callback function for AVRCP controller * @brief callback function for AVRCP controller
*/ */

View File

@@ -24,8 +24,10 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_bt.h" #include "esp_bt.h"
#include "bt_app_core.h" #include "bt_app_core.h"
#include "bt_app_av.h" #include "bt_app_av.h"
#include "esp_bt_main.h" #include "esp_bt_main.h"
#include "esp_bt_device.h" #include "esp_bt_device.h"
#include "esp_gap_bt_api.h" #include "esp_gap_bt_api.h"
@@ -33,6 +35,9 @@
#include "esp_avrc_api.h" #include "esp_avrc_api.h"
#include "driver/i2s.h" #include "driver/i2s.h"
#include "H2201_a2dp.h"
/* event for handler "bt_av_hdl_stack_up */ /* event for handler "bt_av_hdl_stack_up */
enum enum
{ {