Closed m-kiso closed 3 years ago
Hi,
I look forward to hearing from you.
Hi, @m-kiso
Different codecs have different sampling rates. The sampling rate using CVSD codec is 8k, and the sampling rate using mSBC codec is 16K. If ESP32 is used as I2S slave, you need to pay attention to the problem of data format (big-endian or little-endian).
Thanks
Hi, @xiongweichao
Thank you for your reply.
I have the following configuration and I want to skip the audio data, but I hear noise in the headset.
[STM32] ---(CVSD 8kHz , 16bit , mono )---> [ESP32] ---( Bluetooth HFP)---> [Headset]
Also, I have written the source as attached, but I cannot come up with a source to convert the frequency. I am sorry, but if you have a sample source to convert the audio data, please provide it.
audio_gateway\src\main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_bt_api.h"
//add
#include "bt_app_core.h"
#include "uart_ctrl.h"
#include "bt_pair_ctrl.h"
#include "i2s_ctrl.h"
#define TAG "MAIN"
void app_main(void)
{
uint8_t rcode = SUCCESS;
esp_log_level_set(TAG, ESP_LOG_INFO);
/* Initialize NVS — it is used to store PHY calibration data */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_err_t err;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
rcode = ERR_BLE_INIT;
//return;
}
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
rcode = ERR_BLE_ENABLE;
//return;
}
if ((err = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
rcode = ERR_BLE_INIT;
//return;
}
if ((err = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
rcode = ERR_BLE_ENABLE;
//return;
}
/* create application task */
ESP_LOGI(TAG, "start");
if(rcode == SUCCESS){
ESP_LOGI(TAG, "init bluetooth modules");
i2s_ctrl_init();
bt_app_task_start_up();
bt_pair_ctrl_init();
}
uart_ctrl_task_start_up(rcode);
}
}
audio_gateway\src\i2s_ctrl.c
#include <string.h>
#include "freertos/xtensa_api.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "esp_system.h"
#include "esp_log.h"
#include "freertos/semphr.h"
#include "sdkconfig.h"
#include "osi/allocator.h"
#include <esp32/rom/ets_sys.h>
#include "driver/i2s.h"
#include "i2s_ctrl.h"
#define I2S_PORT 1
static void i2s_ctrl_task_handler(void *pvParameters);
//static xQueueHandle i2s_queue = NULL;
static xTaskHandle i2s_ctrl_task_handle = NULL;
#define RINGBUF_SIZE 7200
static RingbufHandle_t m_rb = NULL; //音声用リングバッファ
#define I2S_BUFFER_SIZE 30
uint8_t Mic_Buffer[I2S_BUFFER_SIZE];
void i2s_ctrl_get_data(RingbufHandle_t rbuf, uint64_t size){
uint32_t item_size = 0;
uint8_t *data;
//uint8_t *data2;
if (!rbuf || !m_rb) {
return;
}
//ESP_LOGE(I2S_CTRL_TAG, "size %d", item_size);
//バッファサイズ取得
vRingbufferGetInfo(m_rb, NULL, NULL, NULL, NULL, &item_size);
if (item_size > 0) {
//ESP_LOGE(I2S_CTRL_TAG, "size %d", item_size);
data = xRingbufferReceiveUpTo(m_rb, &item_size, 0, size);
//data2 = osi_malloc(item_size*2);
/*for(int i=0; i<item_size; i++){
//printf("%d,%d\n", data[i*2], data[i*2+1]);
//printf("%d\n", data[i]);
data2[i*2] = data[i];
data2[i*2 + 1] = data[i];
}*/
//BaseType_t done = xRingbufferSend(rbuf, data2, item_size*2, 0);
BaseType_t done = xRingbufferSend(rbuf, data, item_size, 0);
if (!done) {
ESP_LOGE(I2S_CTRL_TAG, "rb send fail2");
}
vRingbufferReturnItem(m_rb, data);
//osi_free(data2);
}
}
#define TABLE_SIZE 50
// Produce a sine audio
/*
static const int16_t sine_int16[TABLE_SIZE] = {
0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557,
19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466,
31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738,
31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886,
19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057,
0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557,
-19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466,
-31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738,
-31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886,
-19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057,
};
*/
/*
static const int16_t sine_int16[TABLE_SIZE] = {
0, 4107, 8149, 12062, 15786,
19260, 22431, 25247, 27666, 29648,
31163, 32187, 32702, 32702, 32187,
31163, 29648, 27666, 25247, 22431,
19260, 15786, 12062, 8149, 4107,
0, -4107, -8149, -12062, -15786,
-19260, -22431, -25247, -27666, -29648,
-31163, -32187, -32702, -32702, -32187,
-31163, -29648, -27666, -25247, -22431,
-19260, -15786, -12062, -8149, -4107,
};*/
size_t total;
static void i2s_ctrl_task_handler(void *pvParameters){
ESP_LOGI(I2S_CTRL_TAG, "i2s handle");
//取得できたbyte数
size_t transBytes;
size_t loop = 0;
uint8_t* data;
int sound;
total = 0;
int a = -110;
printf("%d", a);
for(;;) {
//ESP_LOGI(I2S_CTRL_TAG, "read");
i2s_read(I2S_PORT, (char*)Mic_Buffer, I2S_BUFFER_SIZE, &transBytes, portMAX_DELAY);
if(transBytes > 0){
total += transBytes;
data = osi_malloc(transBytes);
for(int i=0; i<transBytes/2; i++){
//sound = (Mic_Buffer[i*2] << 8) | Mic_Buffer[i*2 + 1];
//sound = sound^0xFFFF;
//printf("%d\n", sound);
//printf("%x, %x\n", Mic_Buffer[i*2], Mic_Buffer[i*2+1]);
//data[i*2] = (sound & 0xff00) >> 8;
//data[i*2+1] = sound & 0x00ff;
//printf("%d, %d\n", Mic_Buffer[i*2], Mic_Buffer[i*2+1]);
//data[i*2] = Mic_Buffer[i*2+1];
//data[i*2+1] = Mic_Buffer[i*2];
data[i*2] = Mic_Buffer[i*2];
data[i*2+1] = Mic_Buffer[i*2+1];
}
/*for(int i=0; i<transBytes/2; i++){
data[i*2] = sine_int16[loop];
data[i*2+1] = sine_int16[loop];
loop++;
if(loop >= TABLE_SIZE){
loop -= TABLE_SIZE;
}
}*/
//ESP_LOGI(I2S_CTRL_TAG, "byte %d", transBytes);
BaseType_t done = xRingbufferSend(m_rb, data, transBytes, 0);
if (!done) {
ESP_LOGE(I2S_CTRL_TAG, "rb send fail1");
}
osi_free(data);
}
//WDTのリセット用ディレイ
vTaskDelay(1);
//ets_delay_us(3500);
}
}
void i2s_ctrl_init(){
//I2S入力設定(I2S)
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX, // スレーブモード、受信
.sample_rate = 44100,//8000, // 8kHz
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // 16bit
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, //I2S_CHANNEL_FMT_ONLY_LEFT, // ステレオ(L,R)
.communication_format = I2S_COMM_FORMAT_STAND_I2S, // MSB
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, //Default interrupt priority
.dma_buf_count = 4, // バッファの数
.dma_buf_len = I2S_BUFFER_SIZE, // バッファサイズ
.use_apll = false, // APLLは使わない
.tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow
.fixed_mclk = 0 // APLLのMCLK設定
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); //I2S1のコンフィグ設定
i2s_pin_config_t pin_config = {
.bck_io_num = 25, //ビットクロック
.ws_io_num = 22, //ワールドクロック(L/R)
.data_out_num = -1, //未使用
.data_in_num = 27 //入力データ
};
i2s_set_pin(I2S_PORT, &pin_config); //I2S1のピン設定
}
void i2s_ctrl_task_start_up(){
m_rb = xRingbufferCreate(RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
ESP_LOGI(I2S_CTRL_TAG, "start task");
xTaskCreate(i2s_ctrl_task_handler, "I2S", 2048, NULL, configMAX_PRIORITIES - 2, &i2s_ctrl_task_handle);
}
void i2s_ctrl_task_shut_down(){
ESP_LOGI(I2S_CTRL_TAG, "shutdown %d", total);
if (i2s_ctrl_task_handle) {
vTaskDelete(i2s_ctrl_task_handle);
i2s_ctrl_task_handle = NULL;
}
if (m_rb) {
vRingbufferDelete(m_rb);
}
/*if (uart_queue) {
vQueueDelete(uart_queue);
uart_queue = NULL;
}*/
}
audio_gateway\src\bt_ctrl.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_hf_ag_api.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "time.h"
#include "sys/time.h"
#include "sdkconfig.h"
#include "osi/allocator.h"
//add
#include "bt_app_core.h"
#include "bt_ctrl.h"
#include "i2s_ctrl.h"
//以下ログ用
const char *c_hf_evt_str[] = {
"CONNECTION_STATE_EVT", /*!< SERVICE LEVEL CONNECTION STATE CONTROL */
"AUDIO_STATE_EVT", /*!< AUDIO CONNECTION STATE CONTROL */
"VR_STATE_CHANGE_EVT", /*!< VOICE RECOGNITION CHANGE */
"VOLUME_CONTROL_EVT", /*!< AUDIO VOLUME CONTROL */
"UNKNOW_AT_CMD", /*!< UNKNOW AT COMMAND RECIEVED */
"IND_UPDATE", /*!< INDICATION UPDATE */
"CIND_RESPONSE_EVT", /*!< CALL & DEVICE INDICATION */
"COPS_RESPONSE_EVT", /*!< CURRENT OPERATOR EVENT */
"CLCC_RESPONSE_EVT", /*!< LIST OF CURRENT CALL EVENT */
"CNUM_RESPONSE_EVT", /*!< SUBSCRIBER INFORTMATION OF CALL EVENT */
"DTMF_RESPONSE_EVT", /*!< DTMF TRANSFER EVT */
"NREC_RESPONSE_EVT", /*!< NREC RESPONSE EVT */
"ANSWER_INCOMING_EVT", /*!< ANSWER INCOMING EVT */
"REJECT_INCOMING_EVT", /*!< AREJECT INCOMING EVT */
"DIAL_EVT", /*!< DIAL INCOMING EVT */
"WBS_EVT", /*!< CURRENT CODEC EVT */
"BCS_EVT", /*!< CODEC NEGO EVT */
};
//esp_hf_connection_state_t
const char *c_connection_state_str[] = {
"DISCONNECTED",
"CONNECTING",
"CONNECTED",
"SLC_CONNECTED",
"DISCONNECTING",
};
// esp_hf_audio_state_t
const char *c_audio_state_str[] = {
"disconnected",
"connecting",
"connected",
"connected_msbc",
};
/// esp_hf_vr_state_t
const char *c_vr_state_str[] = {
"Disabled",
"Enabled",
};
// esp_hf_control_target_t
const char *c_volume_control_target_str[] = {
"SPEAKER",
"MICROPHONE",
};
const char *c_nrec_status_str[] = {
"NREC DISABLE",
"NREC ABLE",
};
#define ESP_HFP_RINGBUF_SIZE 1800
// 7500 microseconds(=12 slots) is aligned to 1 msbc frame duration, and is multiple of common Tesco for eSCO link with EV3 or 2-EV3 packet type
#define PCM_BLOCK_DURATION_US (7500)
//使わない
#define WBS_PCM_SAMPLING_RATE_KHZ (16)
#define PCM_SAMPLING_RATE_KHZ (8)
#define BYTES_PER_SAMPLE (2)
//使わない
#define WBS_PCM_INPUT_DATA_SIZE (WBS_PCM_SAMPLING_RATE_KHZ * PCM_BLOCK_DURATION_US / 1000 * BYTES_PER_SAMPLE) //240
#define PCM_INPUT_DATA_SIZE (PCM_SAMPLING_RATE_KHZ * PCM_BLOCK_DURATION_US / 1000 * BYTES_PER_SAMPLE) //120
#define PCM_GENERATOR_TICK_US (4000) //タイマー周期 microsec
static long s_data_num = 0;
static RingbufHandle_t s_m_rb = NULL; //音声用リングバッファ
static uint64_t s_time_new, s_time_old; //処理時間
static esp_timer_handle_t s_periodic_timer; //タイマー用ハンドラー
static uint64_t s_last_enter_time;
static uint64_t s_us_duration; //音声送信中に経過した時間
static xSemaphoreHandle s_send_data_Semaphore = NULL; //リソース管理?
static xTaskHandle s_bt_app_send_data_task_handler = NULL;
static esp_hf_audio_state_t s_audio_code;
int m_connect_status = 0;
int m_audio_status = 0;
uint8_t m_play_flag = 0;
#define AUDIO_PLAY 0
#define AUDIO_STOP 1
static void bt_app_send_data_timer_cb(void *arg){
if (!xSemaphoreGive(s_send_data_Semaphore)) {
//ESP_LOGE(BT_CTRL_TAG, "%s xSemaphoreGive failed", __func__);
return;
}
return;
}
//再生停止時の音声データ作成
void bt_ctrl_create_0data(uint8_t *p_buf, uint32_t sz){
uint8_t* data = osi_malloc(sz);
memset(data, 0x7fff, sz);
BaseType_t done = xRingbufferSend(p_buf, data, sz, 0);
if (!done) {
ESP_LOGE(BT_CTRL_TAG, "rb send fail da");
}
osi_free(data);
}
//音声データ送信
static uint32_t bt_ctrl_outgoing_cb(uint8_t *p_buf, uint32_t sz){
size_t item_size = 0;
uint8_t *data;
if (!s_m_rb) {
return 0;
}
//バッファ取得
vRingbufferGetInfo(s_m_rb, NULL, NULL, NULL, NULL, &item_size);
//ESP_LOGI(BT_CTRL_TAG, "Outgoing %d, %d", sz, item_size);
if (item_size >= sz) {
//ESP_LOGI(BT_CTRL_TAG, "send %d, %d", sz, item_size);
data = xRingbufferReceiveUpTo(s_m_rb, &item_size, 0, sz);
/*for(int i=0;i<item_size/2; i++){
printf("%d, %d\n", data[i*2], data[i*2+1]);
}
printf("\n");*/
//音声送信
memcpy(p_buf, data, item_size);
vRingbufferReturnItem(s_m_rb, data);
return sz;
} else {
// data not enough, do not read\n
//ESP_LOGI(BT_CTRL_TAG, "not enough %d", sz);
return 0;
}
return 0;
}
//からデータ受信時に呼び出し
static void bt_ctrl_incoming_cb(const uint8_t *buf, uint32_t sz){
//ESP_LOGI(BT_CTRL_TAG, "Incoming");
s_time_new = esp_timer_get_time();
s_data_num += sz;
if ((s_time_new - s_time_old) >= 3000000) {
//print_speed();
}
}
static void bt_app_send_data_task(void *arg){
uint64_t frame_data_num;
uint32_t item_size = 0;
for (;;) {
if (xSemaphoreTake(s_send_data_Semaphore, (portTickType)portMAX_DELAY)) {
s_us_duration = esp_timer_get_time() - s_last_enter_time;
if(s_audio_code == ESP_HF_AUDIO_STATE_CONNECTED_MSBC) {
//使わない
// time of a frame is 7.5ms, sample is 120, data is 2 (byte/sample), so a frame is 240 byte (HF_SBC_ENC_RAW_DATA_SIZE)
frame_data_num = s_us_duration / (PCM_BLOCK_DURATION_US / WBS_PCM_INPUT_DATA_SIZE);
s_last_enter_time += frame_data_num * (PCM_BLOCK_DURATION_US / WBS_PCM_INPUT_DATA_SIZE);
} else {
//送信中に経過した時間分のデータ数を計算
frame_data_num = s_us_duration / (PCM_BLOCK_DURATION_US / PCM_INPUT_DATA_SIZE);
s_last_enter_time += frame_data_num * (PCM_BLOCK_DURATION_US / PCM_INPUT_DATA_SIZE);
}
if(m_play_flag == AUDIO_PLAY){
i2s_ctrl_get_data(s_m_rb, frame_data_num);
}else{
bt_ctrl_create_0data(s_m_rb, frame_data_num);
}
//リングバッファのサイズ取得
vRingbufferGetInfo(s_m_rb, NULL, NULL, NULL, NULL, &item_size);
if(s_audio_code == ESP_HF_AUDIO_STATE_CONNECTED_MSBC) {
if(item_size >= WBS_PCM_INPUT_DATA_SIZE) {
esp_hf_outgoing_data_ready();
}
} else {
//音声データが120個分溜まったとき出力
if(item_size >= PCM_INPUT_DATA_SIZE) {
esp_hf_outgoing_data_ready();
}
}
}
}
}
//音声送信準備
void bt_app_send_data(void){
//I2S受信準備
i2s_ctrl_task_start_up();
s_send_data_Semaphore = xSemaphoreCreateBinary();
xTaskCreate(bt_app_send_data_task, "BtAppSendDataTask", 2048, NULL, configMAX_PRIORITIES - 3, &s_bt_app_send_data_task_handler);
s_m_rb = xRingbufferCreate(ESP_HFP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
//タイマーを設定して、起動
const esp_timer_create_args_t c_periodic_timer_args = {
.callback = &bt_app_send_data_timer_cb,
.name = "periodic"
};
ESP_ERROR_CHECK(esp_timer_create(&c_periodic_timer_args, &s_periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(s_periodic_timer, PCM_GENERATOR_TICK_US));
s_last_enter_time = esp_timer_get_time();
return;
}
//音声接続が切断した時の処理
void bt_app_send_data_shut_down(void){
ESP_LOGI(BT_CTRL_TAG, "SHUTDOWN");
//I2Sタスク終了
i2s_ctrl_task_shut_down();
if (s_bt_app_send_data_task_handler) {
vTaskDelete(s_bt_app_send_data_task_handler);
s_bt_app_send_data_task_handler = NULL;
}
if (s_send_data_Semaphore) {
vSemaphoreDelete(s_send_data_Semaphore);
s_send_data_Semaphore = NULL;
}
if(s_periodic_timer) {
ESP_ERROR_CHECK(esp_timer_stop(s_periodic_timer));
ESP_ERROR_CHECK(esp_timer_delete(s_periodic_timer));
}
if (s_m_rb) {
vRingbufferDelete(s_m_rb);
}
return;
}
void bt_ctrl_cb(esp_hf_cb_event_t event, esp_hf_cb_param_t *param){
if (event <= ESP_HF_BCS_RESPONSE_EVT) {
ESP_LOGI(BT_CTRL_TAG, "APP HFP event: %s", c_hf_evt_str[event]);
} else {
ESP_LOGE(BT_CTRL_TAG, "APP HFP invalid event %d", event);
}
switch (event) {
//接続状態が変更された時?
case ESP_HF_CONNECTION_STATE_EVT:
{
//接続時にペアリングIDを記録する
ESP_LOGI(BT_CTRL_TAG, "--connection state %s, peer feats 0x%x, chld_feats 0x%x",
c_connection_state_str[param->conn_stat.state],
param->conn_stat.peer_feat,
param->conn_stat.chld_feat);
memcpy(hf_peer_addr, param->conn_stat.remote_bda, ESP_BD_ADDR_LEN);
m_connect_status = param->conn_stat.state;
if(m_connect_status == 3){
//接続成功時、音声接続
esp_bt_hf_connect_audio(hf_peer_addr);
}
break;
}
case ESP_HF_CIND_RESPONSE_EVT:
{
//接続成功時の初期化?
ESP_LOGI(BT_CTRL_TAG, "--CIND Start.");
esp_hf_call_status_t call_status = 0;
esp_hf_call_setup_status_t call_setup_status = 0;
esp_hf_network_state_t ntk_state = 1;
int signal = 4;
esp_hf_roaming_status_t roam = 0;
int batt_lev = 3;
esp_hf_call_held_status_t call_held_status = 0;
esp_bt_hf_cind_response(hf_peer_addr,call_status,call_setup_status,ntk_state,signal,roam,batt_lev,call_held_status);
break;
}
case ESP_HF_AUDIO_STATE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--Audio State %s", c_audio_state_str[param->audio_stat.state]);
m_audio_status = param->audio_stat.state;
if (m_audio_status == ESP_HF_AUDIO_STATE_CONNECTED ||
m_audio_status == ESP_HF_AUDIO_STATE_CONNECTED_MSBC){
//オーディオ接続状態
if(m_audio_status == ESP_HF_AUDIO_STATE_CONNECTED) {
//コーデックはCVSD
s_audio_code = ESP_HF_AUDIO_STATE_CONNECTED;
} else {
//HFPの最新仕様(今回使用しない)
s_audio_code = ESP_HF_AUDIO_STATE_CONNECTED_MSBC;
}
//s_time_old = esp_timer_get_time();
//esp_bt_hf_register_data_callback(bt_ctrl_incoming_cb, bt_ctrl_outgoing_cb);
/* Begin send esco data task */
//bt_app_send_data();
} else if (m_audio_status == ESP_HF_AUDIO_STATE_DISCONNECTED) {
//切断
ESP_LOGI(BT_CTRL_TAG, "--ESP AG Audio Connection Disconnected.");
bt_app_send_data_shut_down();
}else{
ESP_LOGI(BT_CTRL_TAG, "else");
}
break;
}
case ESP_HF_BVRA_RESPONSE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--Voice Recognition is %s", c_vr_state_str[param->vra_rep.value]);
break;
}
case ESP_HF_VOLUME_CONTROL_EVT:
{
//音量調整系の応答?
ESP_LOGI(BT_CTRL_TAG, "--Volume Target: %s, Volume %d", c_volume_control_target_str[param->volume_control.type], param->volume_control.volume);
break;
}
case ESP_HF_UNAT_RESPONSE_EVT:
{
//???
ESP_LOGI(BT_CTRL_TAG, "--UNKOW AT CMD: %s", param->unat_rep.unat);
esp_hf_unat_response(hf_peer_addr, NULL);
break;
}
case ESP_HF_IND_UPDATE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--UPDATE INDCATOR!");
break;
}
case ESP_HF_COPS_RESPONSE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--RESPONSE");
break;
}
case ESP_HF_CLCC_RESPONSE_EVT:
{
//サービスレベルの接続を設定する?
int index = 1;
//mandatory
esp_hf_current_call_direction_t dir = 1; //in/out
esp_hf_current_call_status_t current_call_status = 0;
esp_hf_current_call_mode_t mode = 0; //voice/data/fax
esp_hf_current_call_mpty_type_t mpty = 0; //single/multi
//option
char *number = {"123456"};
esp_hf_call_addr_type_t type = ESP_HF_CALL_ADDR_TYPE_UNKNOWN;
ESP_LOGI(BT_CTRL_TAG, "--Calling Line Identification.");
esp_bt_hf_clcc_response(hf_peer_addr, index, dir, current_call_status, mode, mpty, number, type);
break;
}
case ESP_HF_CNUM_RESPONSE_EVT:
{
break;
}
case ESP_HF_VTS_RESPONSE_EVT:
{
//ESP_LOGI(BT_CTRL_TAG, "--DTMF code is: %s.", param->vts_rep.code);
break;
}
case ESP_HF_NREC_RESPONSE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--NREC status is: %s.", c_nrec_status_str[param->nrec.state]);
break;
}
case ESP_HF_ATA_RESPONSE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--Asnwer Incoming Call.");
break;
}
case ESP_HF_CHUP_RESPONSE_EVT:
{
ESP_LOGI(BT_CTRL_TAG, "--Reject Incoming Call.");
break;
}
case ESP_HF_DIAL_EVT:
{
break;
}
case ESP_HF_BCS_RESPONSE_EVT:
{
//ESP_LOGI(BT_CTRL_TAG, "--Consequence of codec negotiation: %s",c_codec_mode_str[param->bcs_rep.mode]);
break;
}
default:
ESP_LOGI(BT_CTRL_TAG, "Unsupported HF_AG EVT: %d.", event);
break;
}
}
void bt_ctrl_get_status(uint8_t* bt, uint8_t* audio){
*bt = m_connect_status;
*audio = m_audio_status;
}
void bt_ctrl_play(){
if(!s_bt_app_send_data_task_handler){
//ESP_LOGE(BT_CTRL_TAG, "play");
//最初の再生コマンド
s_time_old = esp_timer_get_time();
esp_bt_hf_register_data_callback(bt_ctrl_incoming_cb, bt_ctrl_outgoing_cb);
/* Begin send esco data task */
bt_app_send_data();
}else{
if(m_play_flag == AUDIO_STOP){
//2回目以降の再生コマンド
//ESP_LOGE(BT_CTRL_TAG, "replay");
s_time_old = esp_timer_get_time();
vRingbufferDelete(s_m_rb);
s_m_rb = xRingbufferCreate(ESP_HFP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
i2s_ctrl_task_start_up();
}
}
m_play_flag = AUDIO_PLAY;
}
void bt_ctrl_stop(){
//bt_app_send_data_shut_down();
i2s_ctrl_task_shut_down();
m_play_flag = AUDIO_STOP;
}
Regards,
Hi, @xiongweichao Thank you for your reply.
I don't know what this data format (little-endian or big-endian) is, because the audio data is output from the customer's STM32. We are checking now.
What I want to know in a hurry is what kind of conversion expression source I should write for the following configuration. Or do I not need the conversion formula?
[STM32] ---(CVSD 8kHz , 16bit , mono )---> [ESP32] ---(Bluetooth HFP)---> [Headset].
Regards,
Hi, @m-kiso
Please try to modify the value of I2S_BUFFER_SIZE to be greater than 240. If it still doesn't work, please try the following code if it can solve your problem.
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = 16000, // CVSD=8000 mSBC=16000
.bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 1024,
.use_apll = true,
};
Thanks
Hi, @xiongweichao
Thank you for your prompt reply! I will try and reply as soon as possible.
Thanks,
Hi, @xiongweichao
I haven't changed the I2S_BUFFER_SIZE yet, but I did printf the data acquired by I2S and graphed it, and found that it was being sent in a digital data-like format.
How should I convert this data if I send it via HFP?
Thanks,
Hi, @xiongweichao
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = 16000, // CVSD=8000 mSBC=16000
.bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */ .
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 1024,
.use_apll = true,
};
If you have a next move, please let me know.
Thanks,
Hi, @xiongweichao
Is there an update on this?
Thanks,
Hi, @m-kiso
Is bt_ctrl_play
used?
Thanks
Hi, @xiongweichao
Yes, I do use bt_ctrl_play. Also, the actual sound you hear is something like this.
Thanks,
Hi, @m-kiso
But in the source code you provided, I didn't see you using bt_ctrl_play. You can try using the attachment below, this sound is not noise.
Thanks audio_example_file.zip
Hi, @xiongweichao
Thank you for your prompt reply!
I apologize for the lack of explanation regarding bt_ctrl_play. bt_ctrl_play is used in the following way when a message is received by UART.
void uart_ctrl_request_play_voice(uint8_t* dtmp, size_t size){
uint8_t command = dtmp[3];
if(m_resp_code == SUCCESS){
if(command == '0'){
ESP_LOGI(UART_CTRL_TAG, "play");
bt_ctrl_play();
//bt_a2dp_ctrl_play();
}else if(command == '1'){
ESP_LOGI(UART_CTRL_TAG, "stop");
bt_ctrl_stop();
//bt_a2dp_ctrl_stop();
}else{
ESP_LOGI(UART_CTRL_TAG, "unknown");
bt_ctrl_stop();
//bt_a2dp_ctrl_stop();
}
}
uart_ctrl_send_response(m_resp_code, NULL, 0);
}
Please tell me, did you check the audio in audio_example_file.zip
with HFP?
Thanks,
Hi, @m-kiso
Thanks
Hi, @xiongweichao
I have some good news. I think I've solved this problem.
I shifted the i2s_read
value by a higher bit as shown below, and heard clean audio data.
ret = i2s_read(I2S_NUM, samples, sizeof(samples), &read_bytes, portMAX_DELAY);
if ((ret == ESP_OK) && read_bytes) {
len = read_bytes / 2;
for (i = 0; i < len; i++) {
buffer[i] = samples[i] >> 8;
}
xBytesSent = xStreamBufferSend(stream_buffer, (void*)buffer, len, pdMS_TO_TICKS(100));
}
I'm not sure why the problem was solved by shifting the upper bits, but this problem can be closed.
Thank you for your support.
@m-kiso Thanks for reporting and sharing updates, and glad the issue resolved, feel free to reopen.
I has succeeded playing a sine audio in the Example project.
Hello @m-kiso, did you make any changes to the original hfp_ag
example in order to hear correctly the sinusoid from the client side? I am using the v4.3
code (same as you), but the sinusoid I receive is really distorted, as you can see from here. Any help would be much appreciated.
Environment
Hardware: ESP32-WROOM-32E Software: esp-idf V4.3 Example project: \esp32\examples\bluetooth\bluedroid\classic_bt\hfp_ag
Problem Description
I has succeeded playing a sine audio in the Example project. So I try to read audio data from I2S and send to the bluetooth HFP(HCI protocol).
I changed bt_app_hf.c in the Example project. I take audio data from i2s_read() and put s_m_rb(RingBuffer) instead of bt_app_hf_create_audio_data(). Then, I heard only noise.
What should I do?
Code to reproduce this issue
I2S config is