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 13, 2024
1 parent 3d5fc71 commit c3ac32d
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 8 deletions.
16 changes: 16 additions & 0 deletions src/cubeb-jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ cubeb_jni_init()
return cubeb_jni_ptr;
}

extern "C" const char *
cubeb_fx_type_description(cubeb_fx_type type)
{
switch (type) {
case CUBEB_FX_ACOUSTIC_ECHO_CANCELER:
return "CUBEB_FX_ACOUSTIC_ECHO_CANCELER";
case CUBEB_FX_AUTOMATIC_GAIN_CONTROL:
return "CUBEB_FX_AUTOMATIC_GAIN_CONTROL";
case CUBEB_FX_NOISE_SUPPRESSOR:
return "CUBEB_FX_NOISE_SUPPRESSOR";
case CUBEB_FX_SENTINEL__:
return "UNKNOWN CUBEB_FX TYPE";
}
return "UNKNOWN CUBEB_FX TYPE";
}

extern "C" bool
cubeb_fx_is_available(cubeb_jni * cubeb_jni_ptr, cubeb_fx_type type)
{
Expand Down
2 changes: 2 additions & 0 deletions src/cubeb-jni.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ extern "C" {
cubeb_jni *
cubeb_jni_init();

const char *
cubeb_fx_type_description(cubeb_fx_type type);
bool
cubeb_fx_is_available(cubeb_jni * cubeb_jni_ptr, cubeb_fx_type type);
cubeb_fx *
Expand Down
108 changes: 100 additions & 8 deletions src/cubeb_aaudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ using namespace std;
X(AAudioStream_getState) \
X(AAudioStream_getFramesWritten) \
X(AAudioStream_getFramesPerBurst) \
X(AAudioStream_getSessionId) \
X(AAudioStreamBuilder_setInputPreset) \
X(AAudioStreamBuilder_setUsage) \
X(AAudioStreamBuilder_setFramesPerDataCallback)
X(AAudioStreamBuilder_setFramesPerDataCallback) \
X(AAudioStreamBuilder_setSessionId)

// not needed or added later on
// X(AAudioStreamBuilder_setDeviceId) \
Expand All @@ -80,11 +82,9 @@ using namespace std;
// X(AAudioStream_getXRunCount) \
// X(AAudioStream_isMMapUsed) \
// X(AAudioStreamBuilder_setContentType) \
// X(AAudioStreamBuilder_setSessionId) \
// X(AAudioStream_getUsage) \
// X(AAudioStream_getContentType) \
// X(AAudioStream_getInputPreset) \
// X(AAudioStream_getSessionId) \
// END: not needed or added later on

#define MAKE_TYPEDEF(x) static decltype(x) * cubeb_##x;
Expand Down Expand Up @@ -114,6 +114,10 @@ aaudio_stream_start_locked(cubeb_stream * stm, lock_guard<mutex> & lock);
static void
reinitialize_stream(cubeb_stream * stm);

static int
aaudio_get_supported_input_processing_params(
cubeb * ctx, cubeb_input_processing_params * params);

enum class stream_state {
INIT = 0,
STOPPED,
Expand All @@ -136,6 +140,10 @@ struct AAudioTimingInfo {
uint32_t input_latency;
};

struct cubeb_fx_delete {
void operator()(cubeb_fx * fx) { cubeb_fx_destroy(fx); }
};

struct cubeb_stream {
/* Note: Must match cubeb_stream layout in cubeb.c. */
cubeb * context{};
Expand Down Expand Up @@ -165,6 +173,7 @@ struct cubeb_stream {

unique_ptr<cubeb_stream_params> output_stream_params;
unique_ptr<cubeb_stream_params> input_stream_params;
unique_ptr<cubeb_fx, cubeb_fx_delete> fxs[CUBEB_FX_SENTINEL__]{};
uint32_t latency_frames{};
cubeb_sample_format out_format{};
uint32_t sample_rate{};
Expand Down Expand Up @@ -1192,13 +1201,12 @@ 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_session_id_t session_id =
stm->voice_input ? AAUDIO_SESSION_ID_ALLOCATE : AAUDIO_SESSION_ID_NONE;
WRAP(AAudioStreamBuilder_setSessionId)(sb, session_id);
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 All @@ -1211,6 +1219,15 @@ aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex> & lock)
return res_err;
}

if (stm->voice_input) {
aaudio_session_id_t session =
WRAP(AAudioStream_getSessionId)(stm->istream);
for (size_t i = 0; i < CUBEB_FX_SENTINEL__; ++i) {
stm->fxs[i].reset(cubeb_fx_init(
stm->context->jni.get(), static_cast<cubeb_fx_type>(i), session));
}
}

int32_t input_burst_size =
WRAP(AAudioStream_getFramesPerBurst)(stm->istream);
LOG("AAudio input burst size: %d", input_burst_size);
Expand Down Expand Up @@ -1670,6 +1687,81 @@ aaudio_stream_set_volume(cubeb_stream * stm, float volume)
return CUBEB_OK;
}

static cubeb_input_processing_params
cubeb_fx_type_to_processing_param(cubeb_fx_type type)
{
switch (type) {
case CUBEB_FX_ACOUSTIC_ECHO_CANCELER:
return CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION;
case CUBEB_FX_AUTOMATIC_GAIN_CONTROL:
return CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL;
case CUBEB_FX_NOISE_SUPPRESSOR:
return CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION;
case CUBEB_FX_SENTINEL__:
return CUBEB_INPUT_PROCESSING_PARAM_NONE;
}
return CUBEB_INPUT_PROCESSING_PARAM_NONE;
}

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

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;
}

// Make sure we support all the effects we are trying to enable.
cubeb_input_processing_params supported = CUBEB_INPUT_PROCESSING_PARAM_NONE;
aaudio_get_supported_input_processing_params(stm->context, &supported);
cubeb_input_processing_params intersection =
static_cast<cubeb_input_processing_params>(supported & params);
if (intersection != params) {
LOG("%s: attempted to set an unsupported param. supported=%d, params=%d",
__func__, supported, params);
return CUBEB_ERROR_INVALID_PARAMETER;
}

// Make sure we have instances of all the effects we are trying to enable.
bool fx_params[CUBEB_FX_SENTINEL__]{};
for (size_t i = 0; i < CUBEB_FX_SENTINEL__; ++i) {
const cubeb_fx_type fx_type = static_cast<cubeb_fx_type>(i);
const cubeb_input_processing_params param =
cubeb_fx_type_to_processing_param(fx_type);
fx_params[i] = params & param;

if (!stm->fxs[i] && fx_params[i]) {
LOG("%s: attempted to enable %s that we don't have", __func__,
cubeb_fx_type_description(fx_type));
return CUBEB_ERROR;
}
}

// Set enabled state of all the effect instances we have.
for (size_t i = 0; i < CUBEB_FX_SENTINEL__; ++i) {
const cubeb_fx_type fx_type = static_cast<cubeb_fx_type>(i);
if (cubeb_fx * fx = stm->fxs[i].get()) {
if (int e = cubeb_fx_set_enabled(fx, fx_params[i])) {
LOG("%s: failed to %s %s. e=%d", __func__,
fx_params[i] ? "enable" : "disable",
cubeb_fx_type_description(fx_type), e);
return CUBEB_ERROR;
}
}
}

LOG("%s: successfully set params %d", __func__, params);
return CUBEB_OK;
}

aaudio_data_callback_result_t
dummy_callback(AAudioStream * stream, void * userData, void * audioData,
int32_t numFrames)
Expand Down Expand Up @@ -1798,7 +1890,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 c3ac32d

Please sign in to comment.