aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/android/cubeb-output-latency.h2
-rw-r--r--src/cubeb-jni.cpp116
-rw-r--r--src/cubeb-jni.h14
-rw-r--r--src/cubeb_aaudio.cpp35
4 files changed, 132 insertions, 35 deletions
diff --git a/src/android/cubeb-output-latency.h b/src/android/cubeb-output-latency.h
index 70dec8d..0f2760f 100644
--- a/src/android/cubeb-output-latency.h
+++ b/src/android/cubeb-output-latency.h
@@ -69,7 +69,7 @@ cubeb_get_output_latency(output_latency_function * ol)
assert(cubeb_output_latency_method_is_loaded(ol));
if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2) {
- return cubeb_get_output_latency_from_jni(ol->from_jni);
+ return cubeb_audio_manager_get_output_latency(ol->from_jni);
}
return cubeb_get_output_latency_from_media_library(ol->from_lib);
diff --git a/src/cubeb-jni.cpp b/src/cubeb-jni.cpp
index 8e7345b..5580d4e 100644
--- a/src/cubeb-jni.cpp
+++ b/src/cubeb-jni.cpp
@@ -1,7 +1,10 @@
/* clang-format off */
-#include "jni.h"
-#include <assert.h>
+#include "cubeb-jni.h"
#include "cubeb-jni-instances.h"
+#include <assert.h>
+#include <atomic>
+#include <initializer_list>
+#include <jni.h>
/* clang-format on */
#define AUDIO_STREAM_TYPE_MUSIC 3
@@ -9,9 +12,30 @@
struct cubeb_jni {
jobject s_audio_manager_obj = nullptr;
jclass s_audio_manager_class = nullptr;
- jmethodID s_get_output_latency_id = nullptr;
+ jmethodID s_audio_manager_get_output_latency_id = nullptr;
+ jmethodID s_audio_manager_set_mode_id = nullptr;
+ struct cubeb_fx_def {
+ jclass clazz = nullptr;
+ jmethodID static_function_is_available = nullptr;
+ } s_fxs[CUBEB_FX_SENTINEL__]{};
};
+static constexpr const char *
+cubeb_fx_name(cubeb_fx_type type)
+{
+ switch (type) {
+ case CUBEB_FX_ACOUSTIC_ECHO_CANCELER:
+ return "android/media/audiofx/AcousticEchoCanceler";
+ case CUBEB_FX_AUTOMATIC_GAIN_CONTROL:
+ return "android/media/audiofx/AutomaticGainControl";
+ case CUBEB_FX_NOISE_SUPPRESSOR:
+ return "android/media/audiofx/NoiseSuppressor";
+ case CUBEB_FX_SENTINEL__:
+ return nullptr;
+ }
+ return nullptr;
+}
+
extern "C" cubeb_jni *
cubeb_jni_init()
{
@@ -24,46 +48,73 @@ cubeb_jni_init()
cubeb_jni * cubeb_jni_ptr = new cubeb_jni;
assert(cubeb_jni_ptr);
- // Find the audio manager object and make it global to call it from another
- // method
- jclass context_class = jni_env->FindClass("android/content/Context");
- jfieldID audio_service_field = jni_env->GetStaticFieldID(
- context_class, "AUDIO_SERVICE", "Ljava/lang/String;");
- jstring jstr = (jstring)jni_env->GetStaticObjectField(context_class,
- audio_service_field);
- jmethodID get_system_service_id =
- jni_env->GetMethodID(context_class, "getSystemService",
- "(Ljava/lang/String;)Ljava/lang/Object;");
- jobject audio_manager_obj =
- jni_env->CallObjectMethod(ctx_obj, get_system_service_id, jstr);
- cubeb_jni_ptr->s_audio_manager_obj =
- reinterpret_cast<jobject>(jni_env->NewGlobalRef(audio_manager_obj));
+ {
+ // Find the audio manager object and make it global to call it from another
+ // method
+ jclass context_class = jni_env->FindClass("android/content/Context");
+ jfieldID audio_service_field = jni_env->GetStaticFieldID(
+ context_class, "AUDIO_SERVICE", "Ljava/lang/String;");
+ jstring jstr = (jstring)jni_env->GetStaticObjectField(context_class,
+ audio_service_field);
+ jmethodID get_system_service_id =
+ jni_env->GetMethodID(context_class, "getSystemService",
+ "(Ljava/lang/String;)Ljava/lang/Object;");
+ jobject audio_manager_obj =
+ jni_env->CallObjectMethod(ctx_obj, get_system_service_id, jstr);
+ cubeb_jni_ptr->s_audio_manager_obj =
+ reinterpret_cast<jobject>(jni_env->NewGlobalRef(audio_manager_obj));
+ jni_env->DeleteLocalRef(ctx_obj);
+ jni_env->DeleteLocalRef(context_class);
+ jni_env->DeleteLocalRef(jstr);
+ jni_env->DeleteLocalRef(audio_manager_obj);
+ }
- // Make the audio manager class a global reference in order to preserve method
- // id
- jclass audio_manager_class = jni_env->FindClass("android/media/AudioManager");
- cubeb_jni_ptr->s_audio_manager_class =
- reinterpret_cast<jclass>(jni_env->NewGlobalRef(audio_manager_class));
- cubeb_jni_ptr->s_get_output_latency_id =
- jni_env->GetMethodID(audio_manager_class, "getOutputLatency", "(I)I");
+ {
+ // Make the audio manager class a global reference in order to preserve
+ // method id
+ jclass audio_manager_class =
+ jni_env->FindClass("android/media/AudioManager");
+ cubeb_jni_ptr->s_audio_manager_class =
+ reinterpret_cast<jclass>(jni_env->NewGlobalRef(audio_manager_class));
+ cubeb_jni_ptr->s_audio_manager_get_output_latency_id =
+ jni_env->GetMethodID(audio_manager_class, "getOutputLatency", "(I)I");
+ cubeb_jni_ptr->s_audio_manager_set_mode_id =
+ jni_env->GetMethodID(audio_manager_class, "setMode", "(I)V");
+ jni_env->DeleteLocalRef(audio_manager_class);
+ }
- jni_env->DeleteLocalRef(ctx_obj);
- jni_env->DeleteLocalRef(context_class);
- jni_env->DeleteLocalRef(jstr);
- jni_env->DeleteLocalRef(audio_manager_obj);
- jni_env->DeleteLocalRef(audio_manager_class);
+ auto populate_fx_class = [&](cubeb_fx_type type) {
+ jclass c = jni_env->FindClass(cubeb_fx_name(type));
+ cubeb_jni::cubeb_fx_def & fx = cubeb_jni_ptr->s_fxs[type];
+ fx.clazz = reinterpret_cast<jclass>(jni_env->NewGlobalRef(c));
+ fx.static_function_is_available =
+ jni_env->GetStaticMethodID(c, "isAvailable", "()Z");
+ jni_env->DeleteLocalRef(c);
+ };
+ populate_fx_class(CUBEB_FX_ACOUSTIC_ECHO_CANCELER);
+ populate_fx_class(CUBEB_FX_AUTOMATIC_GAIN_CONTROL);
+ populate_fx_class(CUBEB_FX_NOISE_SUPPRESSOR);
return cubeb_jni_ptr;
}
+extern "C" bool
+cubeb_fx_is_available(cubeb_jni * cubeb_jni_ptr, cubeb_fx_type type)
+{
+ JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
+ cubeb_jni::cubeb_fx_def & fx = cubeb_jni_ptr->s_fxs[type];
+ return JNI_FALSE != jni_env->CallStaticBooleanMethod(
+ fx.clazz, fx.static_function_is_available);
+}
+
extern "C" int
-cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr)
+cubeb_audio_manager_get_output_latency(cubeb_jni * cubeb_jni_ptr)
{
assert(cubeb_jni_ptr);
JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
return jni_env->CallIntMethod(
cubeb_jni_ptr->s_audio_manager_obj,
- cubeb_jni_ptr->s_get_output_latency_id,
+ cubeb_jni_ptr->s_audio_manager_get_output_latency_id,
AUDIO_STREAM_TYPE_MUSIC); // param: AudioManager.STREAM_MUSIC
}
@@ -77,6 +128,9 @@ cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr)
jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_obj);
jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_class);
+ for (size_t i = 0; i < CUBEB_FX_SENTINEL__; ++i) {
+ jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_fxs[i].clazz);
+ }
delete cubeb_jni_ptr;
}
diff --git a/src/cubeb-jni.h b/src/cubeb-jni.h
index d63629f..c5bed6d 100644
--- a/src/cubeb-jni.h
+++ b/src/cubeb-jni.h
@@ -3,14 +3,26 @@
typedef struct cubeb_jni cubeb_jni;
+enum cubeb_fx_type {
+ CUBEB_FX_ACOUSTIC_ECHO_CANCELER,
+ CUBEB_FX_AUTOMATIC_GAIN_CONTROL,
+ CUBEB_FX_NOISE_SUPPRESSOR,
+ CUBEB_FX_SENTINEL__,
+};
+
#ifdef __cplusplus
extern "C" {
#endif
cubeb_jni *
cubeb_jni_init();
+
+bool
+cubeb_fx_is_available(cubeb_jni * cubeb_jni_ptr, cubeb_fx_type type);
+
int
-cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr);
+cubeb_audio_manager_get_output_latency(cubeb_jni * cubeb_jni_ptr);
+
void
cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr);
diff --git a/src/cubeb_aaudio.cpp b/src/cubeb_aaudio.cpp
index 9e81ed3..26f28f8 100644
--- a/src/cubeb_aaudio.cpp
+++ b/src/cubeb_aaudio.cpp
@@ -5,6 +5,7 @@
* accompanying file LICENSE for details.
*/
#include "cubeb-internal.h"
+#include "cubeb-jni.h"
#include "cubeb/cubeb.h"
#include "cubeb_android.h"
#include "cubeb_log.h"
@@ -135,6 +136,10 @@ struct AAudioTimingInfo {
uint32_t input_latency;
};
+struct cubeb_jni_delete {
+ void operator()(cubeb_jni * jni) { cubeb_jni_destroy(jni); }
+};
+
struct cubeb_stream {
/* Note: Must match cubeb_stream layout in cubeb.c. */
cubeb * context{};
@@ -179,6 +184,8 @@ struct cubeb {
struct cubeb_ops const * ops{};
void * libaaudio{};
+ std::unique_ptr<cubeb_jni, cubeb_jni_delete> jni;
+
struct {
// The state thread: it waits for state changes and stops
// drained streams.
@@ -1743,6 +1750,28 @@ aaudio_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
return CUBEB_OK;
}
+int
+aaudio_get_supported_input_processing_params(
+ cubeb * ctx, cubeb_input_processing_params * params)
+{
+ if (!ctx->jni) {
+ return CUBEB_ERROR_NOT_SUPPORTED;
+ }
+
+ if (cubeb_fx_is_available(ctx->jni.get(), CUBEB_FX_ACOUSTIC_ECHO_CANCELER)) {
+ *params = static_cast<cubeb_input_processing_params>(
+ CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION |
+ CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL |
+ CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION);
+ } else {
+ *params = CUBEB_INPUT_PROCESSING_PARAM_NONE;
+ }
+
+ LOG("%s: Supported params are %s (%d)", __func__,
+ input_processing_params_to_str(*params), *params);
+ return CUBEB_OK;
+}
+
extern "C" int
aaudio_init(cubeb ** context, char const * context_name);
@@ -1750,9 +1779,10 @@ const static struct cubeb_ops aaudio_ops = {
/*.init =*/aaudio_init,
/*.get_backend_id =*/aaudio_get_backend_id,
/*.get_max_channel_count =*/aaudio_get_max_channel_count,
- /* .get_min_latency =*/aaudio_get_min_latency,
+ /*.get_min_latency =*/aaudio_get_min_latency,
/*.get_preferred_sample_rate =*/aaudio_get_preferred_sample_rate,
- /*.get_supported_input_processing_params =*/nullptr,
+ /*.get_supported_input_processing_params =*/
+ aaudio_get_supported_input_processing_params,
/*.enumerate_devices =*/nullptr,
/*.device_collection_destroy =*/nullptr,
/*.destroy =*/aaudio_destroy,
@@ -1800,6 +1830,7 @@ aaudio_init(cubeb ** context, char const * /* context_name */)
cubeb * ctx = new cubeb;
ctx->ops = &aaudio_ops;
ctx->libaaudio = libaaudio;
+ ctx->jni.reset(cubeb_jni_init());
ctx->state.thread = std::thread(state_thread, ctx);