fix(audio): ES8311 BOTH complementary open + audio-stream close ref-count + mic unmute
- es8311 driver open() now allows OUTPUT->INPUT complementary (promotes to BOTH) when same native rate 44100 - audio-stream close_stream() ref-counts shared BOTH codec (don't close if other direction still open) - MCP recordVoice + VoiceRecorder app explicitly unmute and set 100% gain Fixes mic input not working - was returning ERROR_RESOURCE when output already open
This commit is contained in:
@@ -553,9 +553,14 @@ error_t close_stream(AudioStreamHandle handle_base) {
|
|||||||
Device* codec = is_input ? data->input_codec : data->output_codec;
|
Device* codec = is_input ? data->input_codec : data->output_codec;
|
||||||
AudioStreamHandleImpl** slot = is_input ? &data->open_input : &data->open_output;
|
AudioStreamHandleImpl** slot = is_input ? &data->open_input : &data->open_output;
|
||||||
|
|
||||||
|
// Determine if underlying codec is shared (BOTH codec used for both directions)
|
||||||
|
// In that case we must NOT close the codec if the other direction is still active.
|
||||||
|
Device* other_codec = is_input ? data->output_codec : data->input_codec;
|
||||||
|
AudioStreamHandleImpl** other_slot = is_input ? &data->open_output : &data->open_input;
|
||||||
|
bool codec_shared = (codec != nullptr && other_codec != nullptr && codec == other_codec);
|
||||||
|
|
||||||
xSemaphoreTake(data->mutex, portMAX_DELAY);
|
xSemaphoreTake(data->mutex, portMAX_DELAY);
|
||||||
if (handle->closing) {
|
if (handle->closing) {
|
||||||
// Already being closed by another caller (e.g. concurrent set_enabled + app close).
|
|
||||||
xSemaphoreGive(data->mutex);
|
xSemaphoreGive(data->mutex);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
@@ -563,14 +568,16 @@ error_t close_stream(AudioStreamHandle handle_base) {
|
|||||||
if (*slot == handle) {
|
if (*slot == handle) {
|
||||||
*slot = nullptr;
|
*slot = nullptr;
|
||||||
}
|
}
|
||||||
|
bool other_still_open = (other_slot != nullptr && *other_slot != nullptr && *other_slot != reinterpret_cast<AudioStreamHandleImpl*>(1));
|
||||||
bool must_drain = (handle->busy_count > 0);
|
bool must_drain = (handle->busy_count > 0);
|
||||||
|
bool should_close_codec = !codec_shared || !other_still_open;
|
||||||
xSemaphoreGive(data->mutex);
|
xSemaphoreGive(data->mutex);
|
||||||
|
|
||||||
if (must_drain && handle->drain_semaphore != nullptr) {
|
if (must_drain && handle->drain_semaphore != nullptr) {
|
||||||
xSemaphoreTake(handle->drain_semaphore, portMAX_DELAY);
|
xSemaphoreTake(handle->drain_semaphore, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codec != nullptr) {
|
if (should_close_codec && codec != nullptr) {
|
||||||
audio_codec_close(codec);
|
audio_codec_close(codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,16 +53,36 @@ error_t open(Device* device, const struct AudioCodecStreamConfig* config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (data->is_open) {
|
if (data->is_open) {
|
||||||
// open_direction == BOTH already serves INPUT-only or OUTPUT-only requests on the
|
// ES8311 is configured for WORK_MODE_BOTH, so an already-open device
|
||||||
// same sample settings -- only an exact direction mismatch (e.g. requesting BOTH
|
// can serve the opposite direction without reopening, provided sample
|
||||||
// while opened for INPUT only) needs a reopen.
|
// settings match. Promote open_direction to BOTH when we see a
|
||||||
bool direction_compatible = data->open_direction == config->direction
|
// complementary request.
|
||||||
|| data->open_direction == AUDIO_CODEC_DIR_BOTH;
|
bool is_complementary = (data->open_direction == AUDIO_CODEC_DIR_OUTPUT && config->direction == AUDIO_CODEC_DIR_INPUT)
|
||||||
|
|| (data->open_direction == AUDIO_CODEC_DIR_INPUT && config->direction == AUDIO_CODEC_DIR_OUTPUT);
|
||||||
|
bool direction_compatible = (data->open_direction == config->direction)
|
||||||
|
|| (data->open_direction == AUDIO_CODEC_DIR_BOTH)
|
||||||
|
|| (config->direction == AUDIO_CODEC_DIR_BOTH)
|
||||||
|
|| is_complementary;
|
||||||
bool same_config = direction_compatible
|
bool same_config = direction_compatible
|
||||||
&& data->open_sample_info.bits_per_sample == sample_info.bits_per_sample
|
&& data->open_sample_info.bits_per_sample == sample_info.bits_per_sample
|
||||||
&& data->open_sample_info.channel == sample_info.channel
|
&& data->open_sample_info.channel == sample_info.channel
|
||||||
&& data->open_sample_info.sample_rate == sample_info.sample_rate;
|
&& data->open_sample_info.sample_rate == sample_info.sample_rate;
|
||||||
return same_config ? ERROR_NONE : ERROR_RESOURCE;
|
if (same_config) {
|
||||||
|
// If we opened OUTPUT then INPUT (or vice versa), mark as BOTH
|
||||||
|
if (is_complementary) {
|
||||||
|
data->open_direction = AUDIO_CODEC_DIR_BOTH;
|
||||||
|
}
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
// Different sample config for opposite direction - ES8311 can only have one
|
||||||
|
// sample rate at a time (native 44100 resampled via audio-stream), so if
|
||||||
|
// codec rates differ we must fail. But if both sides use native 44100 (audio-stream
|
||||||
|
// always opens codec with native rate), we allow it.
|
||||||
|
if (direction_compatible) {
|
||||||
|
// Allow if both use same native rate path (audio-stream opens with codec's native)
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
return ERROR_RESOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (esp_codec_dev_open(data->codec_device, &sample_info) != ESP_CODEC_DEV_OK) {
|
if (esp_codec_dev_open(data->codec_device, &sample_info) != ESP_CODEC_DEV_OK) {
|
||||||
|
|||||||
@@ -796,6 +796,9 @@ bool recordVoice(int durationSec, const std::string& filename, size_t& recordedB
|
|||||||
set_error(error, "Failed to open audio input stream");
|
set_error(error, "Failed to open audio input stream");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
audio_stream_set_mute(state.audioStreamDevice, AUDIO_CODEC_DIR_INPUT, false);
|
||||||
|
audio_stream_set_volume(state.audioStreamDevice, AUDIO_CODEC_DIR_INPUT, 100.0f);
|
||||||
|
LOG_I(TAG, "Mic unmuted gain 100%% for %s", filename.c_str());
|
||||||
} else {
|
} else {
|
||||||
if (!configure_i2s(state, AUDIO_SAMPLE_RATE, 1, error)) {
|
if (!configure_i2s(state, AUDIO_SAMPLE_RATE, 1, error)) {
|
||||||
goto done;
|
goto done;
|
||||||
|
|||||||
Reference in New Issue
Block a user