a2dp to seperate file
This commit is contained in:
5
ESP32/.vscode/settings.json
vendored
5
ESP32/.vscode/settings.json
vendored
@@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
140
ESP32/main/H2201_a2dp.c
Normal 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
19
ESP32/main/H2201_a2dp.h
Normal 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__ */
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user