fix(bt/bluedroid): add status management for audio sink service channel

This commit is contained in:
Jin Cheng
2026-01-09 14:57:36 +08:00
parent 5cdf6f448f
commit bdfb0f9e1d
3 changed files with 56 additions and 27 deletions
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Unlicense OR CC0-1.0 * SPDX-License-Identifier: Unlicense OR CC0-1.0
*/ */
@@ -11,6 +11,21 @@
#include <string.h> #include <string.h>
#include "esp_a2dp_api.h" #include "esp_a2dp_api.h"
#define RINGBUF_HIGHEST_WATER_LEVEL (32 * 1024)
#define RINGBUF_PREFETCH_WATER_LEVEL (20 * 1024)
typedef enum {
RINGBUFFER_MODE_PROCESSING, /* ringbuffer is buffering incoming audio data */
RINGBUFFER_MODE_PREFETCHING, /* ringbuffer is buffering incoming audio data */
RINGBUFFER_MODE_DROPPING /* ringbuffer is not buffering (dropping) incoming audio data */
} audio_sink_ringbuffer_mode_t;
typedef enum {
CHANNEL_STATUS_IDLE,
CHANNEL_STATUS_OPENED,
CHANNEL_STATUS_ENABLED
} audio_sink_chan_st_t;
/** /**
* @brief open audio sink service * @brief open audio sink service
*/ */
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Unlicense OR CC0-1.0 * SPDX-License-Identifier: Unlicense OR CC0-1.0
*/ */
@@ -21,17 +21,9 @@
/* log tag */ /* log tag */
#define AUDIO_SNK_SRV_DAC_TAG "SNK_SRV_DAC" #define AUDIO_SNK_SRV_DAC_TAG "SNK_SRV_DAC"
#define RINGBUF_HIGHEST_WATER_LEVEL (32 * 1024)
#define RINGBUF_PREFETCH_WATER_LEVEL (20 * 1024)
enum {
RINGBUFFER_MODE_PROCESSING, /* ringbuffer is buffering incoming audio data, I2S is working */
RINGBUFFER_MODE_PREFETCHING, /* ringbuffer is buffering incoming audio data, I2S is waiting */
RINGBUFFER_MODE_DROPPING /* ringbuffer is not buffering (dropping) incoming audio data, I2S is working */
};
typedef struct { typedef struct {
dac_continuous_handle_t tx_chan; /* handle of dac continuous channel */ dac_continuous_handle_t tx_chan; /* handle of dac continuous channel */
audio_sink_chan_st_t chan_st; /* dac channel status */
TaskHandle_t write_task_handle; /* handle of writing task */ TaskHandle_t write_task_handle; /* handle of writing task */
RingbufHandle_t ringbuf; /* handle of ringbuffer */ RingbufHandle_t ringbuf; /* handle of ringbuffer */
SemaphoreHandle_t write_semaphore; /* handle of write semaphore */ SemaphoreHandle_t write_semaphore; /* handle of write semaphore */
@@ -100,11 +92,17 @@ void audio_sink_srv_open(void)
}; };
/* Allocate continuous channels */ /* Allocate continuous channels */
ESP_ERROR_CHECK(dac_continuous_new_channels(&cont_cfg, &s_dac_cb.tx_chan)); ESP_ERROR_CHECK(dac_continuous_new_channels(&cont_cfg, &s_dac_cb.tx_chan));
s_dac_cb.chan_st = CHANNEL_STATUS_OPENED;
} }
void audio_sink_srv_close(void) void audio_sink_srv_close(void)
{ {
ESP_ERROR_CHECK(dac_continuous_del_channels(s_dac_cb.tx_chan)); audio_sink_srv_stop();
if (s_dac_cb.chan_st == CHANNEL_STATUS_OPENED) {
ESP_ERROR_CHECK(dac_continuous_del_channels(s_dac_cb.tx_chan));
s_dac_cb.chan_st = CHANNEL_STATUS_IDLE;
}
if (s_dac_cb.write_task_handle) { if (s_dac_cb.write_task_handle) {
vTaskDelete(s_dac_cb.write_task_handle); vTaskDelete(s_dac_cb.write_task_handle);
s_dac_cb.write_task_handle = NULL; s_dac_cb.write_task_handle = NULL;
@@ -122,7 +120,13 @@ void audio_sink_srv_close(void)
void audio_sink_srv_start(void) void audio_sink_srv_start(void)
{ {
dac_continuous_enable(s_dac_cb.tx_chan); if (s_dac_cb.chan_st != CHANNEL_STATUS_OPENED) {
ESP_LOGE(AUDIO_SNK_SRV_DAC_TAG, "%s, TX channel wrong state: %d", __func__, s_dac_cb.chan_st);
return;
}
ESP_ERROR_CHECK(dac_continuous_enable(s_dac_cb.tx_chan));
s_dac_cb.chan_st = CHANNEL_STATUS_ENABLED;
ESP_LOGI(AUDIO_SNK_SRV_DAC_TAG, "ringbuffer data empty! mode changed: RINGBUFFER_MODE_PREFETCHING"); ESP_LOGI(AUDIO_SNK_SRV_DAC_TAG, "ringbuffer data empty! mode changed: RINGBUFFER_MODE_PREFETCHING");
s_dac_cb.ringbuffer_mode = RINGBUFFER_MODE_PREFETCHING; s_dac_cb.ringbuffer_mode = RINGBUFFER_MODE_PREFETCHING;
if ((s_dac_cb.write_semaphore = xSemaphoreCreateBinary()) == NULL) { if ((s_dac_cb.write_semaphore = xSemaphoreCreateBinary()) == NULL) {
@@ -138,7 +142,10 @@ void audio_sink_srv_start(void)
void audio_sink_srv_stop(void) void audio_sink_srv_stop(void)
{ {
ESP_ERROR_CHECK(dac_continuous_disable(s_dac_cb.tx_chan)); if (s_dac_cb.chan_st == CHANNEL_STATUS_ENABLED) {
ESP_ERROR_CHECK(dac_continuous_disable(s_dac_cb.tx_chan));
s_dac_cb.chan_st = CHANNEL_STATUS_OPENED;
}
} }
void audio_sink_srv_codec_info_update(esp_a2d_mcc_t *mcc) void audio_sink_srv_codec_info_update(esp_a2d_mcc_t *mcc)
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Unlicense OR CC0-1.0 * SPDX-License-Identifier: Unlicense OR CC0-1.0
*/ */
@@ -21,17 +21,9 @@
/* log tag */ /* log tag */
#define AUDIO_SNK_SRV_I2S_TAG "SNK_SRV_I2S" #define AUDIO_SNK_SRV_I2S_TAG "SNK_SRV_I2S"
#define RINGBUF_HIGHEST_WATER_LEVEL (32 * 1024)
#define RINGBUF_PREFETCH_WATER_LEVEL (20 * 1024)
enum {
RINGBUFFER_MODE_PROCESSING, /* ringbuffer is buffering incoming audio data, I2S is working */
RINGBUFFER_MODE_PREFETCHING, /* ringbuffer is buffering incoming audio data, I2S is waiting */
RINGBUFFER_MODE_DROPPING /* ringbuffer is not buffering (dropping) incoming audio data, I2S is working */
};
typedef struct { typedef struct {
i2s_chan_handle_t tx_chan; /* handle of i2s channel */ i2s_chan_handle_t tx_chan; /* handle of i2s channel */
audio_sink_chan_st_t chan_st; /* i2s channel status */
TaskHandle_t write_task_handle; /* handle of writing task */ TaskHandle_t write_task_handle; /* handle of writing task */
RingbufHandle_t ringbuf; /* handle of ringbuffer */ RingbufHandle_t ringbuf; /* handle of ringbuffer */
SemaphoreHandle_t write_semaphore;/* handle of write semaphore */ SemaphoreHandle_t write_semaphore;/* handle of write semaphore */
@@ -115,11 +107,17 @@ void audio_sink_srv_open(void)
/* initialize I2S channel */ /* initialize I2S channel */
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &s_i2s_cb.tx_chan, NULL)); ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &s_i2s_cb.tx_chan, NULL));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(s_i2s_cb.tx_chan, &std_cfg)); ESP_ERROR_CHECK(i2s_channel_init_std_mode(s_i2s_cb.tx_chan, &std_cfg));
s_i2s_cb.chan_st = CHANNEL_STATUS_OPENED;
} }
void audio_sink_srv_close(void) void audio_sink_srv_close(void)
{ {
ESP_ERROR_CHECK(i2s_del_channel(s_i2s_cb.tx_chan)); audio_sink_srv_stop();
if (s_i2s_cb.chan_st == CHANNEL_STATUS_OPENED) {
ESP_ERROR_CHECK(i2s_del_channel(s_i2s_cb.tx_chan));
s_i2s_cb.chan_st = CHANNEL_STATUS_IDLE;
}
if (s_i2s_cb.write_task_handle) { if (s_i2s_cb.write_task_handle) {
vTaskDelete(s_i2s_cb.write_task_handle); vTaskDelete(s_i2s_cb.write_task_handle);
s_i2s_cb.write_task_handle = NULL; s_i2s_cb.write_task_handle = NULL;
@@ -137,7 +135,13 @@ void audio_sink_srv_close(void)
void audio_sink_srv_start(void) void audio_sink_srv_start(void)
{ {
i2s_channel_enable(s_i2s_cb.tx_chan); if (s_i2s_cb.chan_st != CHANNEL_STATUS_OPENED) {
ESP_LOGE(AUDIO_SNK_SRV_I2S_TAG, "%s, TX channel wrong state: %d", __func__, s_i2s_cb.chan_st);
return;
}
ESP_ERROR_CHECK(i2s_channel_enable(s_i2s_cb.tx_chan));
s_i2s_cb.chan_st = CHANNEL_STATUS_ENABLED;
ESP_LOGI(AUDIO_SNK_SRV_I2S_TAG, "ringbuffer data empty! mode changed: RINGBUFFER_MODE_PREFETCHING"); ESP_LOGI(AUDIO_SNK_SRV_I2S_TAG, "ringbuffer data empty! mode changed: RINGBUFFER_MODE_PREFETCHING");
s_i2s_cb.ringbuffer_mode = RINGBUFFER_MODE_PREFETCHING; s_i2s_cb.ringbuffer_mode = RINGBUFFER_MODE_PREFETCHING;
if ((s_i2s_cb.write_semaphore = xSemaphoreCreateBinary()) == NULL) { if ((s_i2s_cb.write_semaphore = xSemaphoreCreateBinary()) == NULL) {
@@ -153,7 +157,10 @@ void audio_sink_srv_start(void)
void audio_sink_srv_stop(void) void audio_sink_srv_stop(void)
{ {
ESP_ERROR_CHECK(i2s_channel_disable(s_i2s_cb.tx_chan)); if (s_i2s_cb.chan_st == CHANNEL_STATUS_ENABLED) {
ESP_ERROR_CHECK(i2s_channel_disable(s_i2s_cb.tx_chan));
s_i2s_cb.chan_st = CHANNEL_STATUS_OPENED;
}
} }
void audio_sink_srv_codec_info_update(esp_a2d_mcc_t *mcc) void audio_sink_srv_codec_info_update(esp_a2d_mcc_t *mcc)