Skip to content

Commit

Permalink
Implement aaudio_set_input_processing_params
Browse files Browse the repository at this point in the history
  • Loading branch information
Pehrsons committed Jun 18, 2024
1 parent d2179a0 commit 321c252
Showing 1 changed file with 145 additions and 12 deletions.
157 changes: 145 additions & 12 deletions src/cubeb_aaudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <limits>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <vector>

Expand Down Expand Up @@ -64,6 +65,7 @@ using namespace std;
X(AAudioStream_getState) \
X(AAudioStream_getFramesWritten) \
X(AAudioStream_getFramesPerBurst) \
X(AAudioStream_getInputPreset) \
X(AAudioStreamBuilder_setInputPreset) \
X(AAudioStreamBuilder_setUsage) \
X(AAudioStreamBuilder_setFramesPerDataCallback)
Expand All @@ -82,7 +84,6 @@ using namespace std;
// X(AAudioStreamBuilder_setSessionId) \
// X(AAudioStream_getUsage) \
// X(AAudioStream_getContentType) \
// X(AAudioStream_getInputPreset) \
// X(AAudioStream_getSessionId) \
// END: not needed or added later on

Expand Down Expand Up @@ -172,6 +173,7 @@ struct cubeb_stream {
unsigned out_frame_size{};
bool voice_input{};
bool voice_output{};
cubeb_input_processing_params input_processing_params{};
uint64_t previous_clock{};
};

Expand Down Expand Up @@ -886,7 +888,7 @@ aaudio_input_data_cb(AAudioStream * astream, void * user_data,
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}

static void
static int
reinitialize_stream_locked(cubeb_stream * stm, lock_guard<mutex> & lock)
{
stream_state state = stm->state.load();
Expand All @@ -905,7 +907,7 @@ reinitialize_stream_locked(cubeb_stream * stm, lock_guard<mutex> & lock)
LOG("aaudio_stream_init_impl error while reiniting: %s",
WRAP(AAudio_convertResultToText)(err));
stm->state.store(stream_state::ERROR);
return;
return err;
}

if (was_playing) {
Expand All @@ -915,9 +917,11 @@ reinitialize_stream_locked(cubeb_stream * stm, lock_guard<mutex> & lock)
LOG("aaudio_stream_start error while reiniting: %s",
WRAP(AAudio_convertResultToText)(err));
stm->state.store(stream_state::ERROR);
return;
return err;
}
}

return CUBEB_OK;
}

static void
Expand Down Expand Up @@ -1010,6 +1014,7 @@ aaudio_stream_destroy(cubeb_stream * stm)
{
lock_guard lock(stm->mutex);
stm->in_use.store(false);
stm->input_processing_params = CUBEB_INPUT_PROCESSING_PARAM_NONE;
aaudio_stream_destroy_locked(stm, lock);
}

Expand Down Expand Up @@ -1074,6 +1079,23 @@ aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard<mutex> & lock)
stm->state.store(stream_state::INIT);
}

static std::optional<aaudio_input_preset_t>
input_processing_params_to_input_preset(cubeb_input_processing_params params)
{
switch (static_cast<int>(params)) {
case CUBEB_INPUT_PROCESSING_PARAM_NONE:
return AAUDIO_INPUT_PRESET_UNPROCESSED;
case CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL:
return AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
case (CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION |
CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL |
CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION):
return AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION;
default:
return std::nullopt;
}
}

static int
aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex> & lock)
{
Expand Down Expand Up @@ -1191,13 +1213,11 @@ aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex> & lock)
// input
cubeb_stream_params in_params;
if (stm->input_stream_params) {
// Match what the OpenSL backend does for now, we could use UNPROCESSED and
// VOICE_COMMUNICATION here, but we'd need to make it clear that
// application-level AEC and other voice processing should be disabled
// there.
int input_preset = stm->voice_input ? AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
: AAUDIO_INPUT_PRESET_CAMCORDER;
WRAP(AAudioStreamBuilder_setInputPreset)(sb, input_preset);
aaudio_input_preset_t preset =
stm->voice_input ? *input_processing_params_to_input_preset(
stm->input_processing_params)
: AAUDIO_INPUT_PRESET_CAMCORDER;
WRAP(AAudioStreamBuilder_setInputPreset)(sb, preset);
WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_INPUT);
WRAP(AAudioStreamBuilder_setDataCallback)(sb, in_data_callback, stm);
assert(stm->latency_frames < std::numeric_limits<int32_t>::max());
Expand Down Expand Up @@ -1669,6 +1689,119 @@ aaudio_stream_set_volume(cubeb_stream * stm, float volume)
return CUBEB_OK;
}

static const char *
input_preset_to_str(aaudio_input_preset_t preset)
{
switch (preset) {
case AAUDIO_INPUT_PRESET_GENERIC:
return "GENERIC";
case AAUDIO_INPUT_PRESET_CAMCORDER:
return "CAMCORDER";
case AAUDIO_INPUT_PRESET_VOICE_RECOGNITION:
return "VOICE_RECOGNITION";
case AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION:
return "VOICE_COMMUNICATION";
case AAUDIO_INPUT_PRESET_UNPROCESSED:
return "UNPROCESSED";
case AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE:
return "VOICE_PERFORMANCE";
}
return "UNKNOWN";
}

static const char *
input_processing_params_to_str(cubeb_input_processing_params params)
{
switch (static_cast<int>(params)) {
case CUBEB_INPUT_PROCESSING_PARAM_NONE:
return "None";
case CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION:
return "AEC";
case CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL:
return "AGC";
case CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION:
return "NS";
case CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION |
CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL:
return "AEC | AGC";
case CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION |
CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION:
return "AEC | NS";
case CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL |
CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION:
return "AGC | NS";
case CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION |
CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL |
CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION:
return "AEC | AGC | NS";
}
return "Unknown";
}

static int
aaudio_set_input_processing_params(cubeb_stream * stm,
cubeb_input_processing_params params)
{
assert(stm);

LOG("%s(stm=%p, params=%s)", __func__, stm,
input_processing_params_to_str(params));

if (!stm->istream) {
LOG("%s: no input stream", __func__);
return CUBEB_ERROR_INVALID_PARAMETER;
}

if (!stm->voice_input) {
LOG("%s: input stream is not a voice stream", __func__);
return CUBEB_ERROR_INVALID_PARAMETER;
}

const auto preset = input_processing_params_to_input_preset(params);
if (!preset) {
LOG("%s: attempted to set unsupported params %s", __func__,
input_processing_params_to_str(params));
return CUBEB_ERROR_INVALID_PARAMETER;
}

const auto current = WRAP(AAudioStream_getInputPreset)(stm->istream);
if (*preset == current) {
LOG("%s: no change in preset: %s", __func__, input_preset_to_str(current));
return CUBEB_OK;
}

lock_guard lock(stm->mutex);
LOG("%s: reinitializing stream due to preset change. %s->%s", __func__,
input_preset_to_str(preset.value_or(AAUDIO_INPUT_PRESET_UNPROCESSED)),
input_preset_to_str(*preset));
cubeb_input_processing_params current_params = stm->input_processing_params;
stm->input_processing_params = params;
int err = reinitialize_stream_locked(stm, lock);
if (err == CUBEB_OK) {
LOG("%s: stream %p successfully set params %s (preset %s).", __func__, stm,
input_processing_params_to_str(params), input_preset_to_str(*preset));
return CUBEB_OK;
}

stm->input_processing_params = current_params;
err = reinitialize_stream_locked(stm, lock);
if (err == CUBEB_OK) {
LOG("%s: stream %p failed to set params %s (preset %s), current params "
"%s have been restored.",
__func__, stm, input_processing_params_to_str(params),
input_preset_to_str(*preset),
input_processing_params_to_str(current_params));
} else {
LOG("%s: stream %p failed to set params %s (preset %s), and restoring "
"current params %s failed also. e=%d.",
__func__, stm, input_processing_params_to_str(params),
input_preset_to_str(*preset),
input_processing_params_to_str(current_params), err);
stm->state.store(stream_state::ERROR);
}
return CUBEB_ERROR;
}

aaudio_data_callback_result_t
dummy_callback(AAudioStream * stream, void * userData, void * audioData,
int32_t numFrames)
Expand Down Expand Up @@ -1785,7 +1918,7 @@ const static struct cubeb_ops aaudio_ops = {
/*.stream_set_name =*/nullptr,
/*.stream_get_current_device =*/nullptr,
/*.stream_set_input_mute =*/nullptr,
/*.stream_set_input_processing_params =*/nullptr,
/*.stream_set_input_processing_params =*/aaudio_set_input_processing_params,
/*.stream_device_destroy =*/nullptr,
/*.stream_register_device_changed_callback =*/nullptr,
/*.register_device_collection_changed =*/nullptr};
Expand Down

0 comments on commit 321c252

Please sign in to comment.