diff options
author | Paul McLean <pmclean@google.com> | 2016-03-04 14:04:28 -0700 |
---|---|---|
committer | Paul McLean <pmclean@google.com> | 2016-03-09 08:16:56 -0700 |
commit | 053b3c2696e5e1b28dd5e02c54b0e3aedc21168d (patch) | |
tree | d47246bb9b1f144f710e2581b1d71cb6af02e1e1 | |
parent | 96c2d9fb5afbaca71e04afa1f5fb933aa28f06f7 (diff) | |
download | android_frameworks_wilhelm-053b3c2696e5e1b28dd5e02c54b0e3aedc21168d.tar.gz android_frameworks_wilhelm-053b3c2696e5e1b28dd5e02c54b0e3aedc21168d.tar.bz2 android_frameworks_wilhelm-053b3c2696e5e1b28dd5e02c54b0e3aedc21168d.zip |
"Refinements" to Native Audio Routing API
Change method names to more generic "AcquireJavaProxy" to support
(potentially) multiple proxy types.
Add "Release" method.
Remove JNIEnv* parameter from Acquire and Release methods.
Add Type ID parameter to support (potential) multiple proxy types.
Enforce "singleton" allocation for proxies.
Disallow proxy acquisition for innapropriate players/recorders.
Refactor to make the code clearer.
Bug: 23899814
Change-Id: Iff354ba46547781e0998a9032de96f445d1474b8
-rw-r--r-- | include/SLES/OpenSLES_Android.h | 14 | ||||
-rw-r--r-- | src/Android.mk | 3 | ||||
-rw-r--r-- | src/itf/IAndroidConfiguration.c | 318 | ||||
-rw-r--r-- | src/itfstruct.h | 4 |
4 files changed, 258 insertions, 81 deletions
diff --git a/include/SLES/OpenSLES_Android.h b/include/SLES/OpenSLES_Android.h index 122b0af..dc85580 100644 --- a/include/SLES/OpenSLES_Android.h +++ b/include/SLES/OpenSLES_Android.h @@ -194,6 +194,11 @@ extern SL_API const SLInterfaceID SL_IID_ANDROIDCONFIGURATION; struct SLAndroidConfigurationItf_; typedef const struct SLAndroidConfigurationItf_ * const * SLAndroidConfigurationItf; +/* + * Java Proxy Type IDs + */ +#define SL_ANDROID_JAVA_PROXY_ROUTING 0x0001 + struct SLAndroidConfigurationItf_ { SLresult (*SetConfiguration) (SLAndroidConfigurationItf self, @@ -207,9 +212,12 @@ struct SLAndroidConfigurationItf_ { void *pConfigValue ); - SLresult (*AcquireJavaAudioRouting) (SLAndroidConfigurationItf self, - JNIEnv* j_env, - jobject *pObject); + SLresult (*AcquireJavaProxy) (SLAndroidConfigurationItf self, + SLuint32 proxyType, + jobject *pProxyObj); + + SLresult (*ReleaseJavaProxy) (SLAndroidConfigurationItf self, + SLuint32 proxyType); }; diff --git a/src/Android.mk b/src/Android.mk index a40a8e5..6d1f8ba 100644 --- a/src/Android.mk +++ b/src/Android.mk @@ -186,7 +186,8 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libgui \ libdl \ - libeffects + libeffects \ + libandroid_runtime # For Brillo, we do not want this dependency as it significantly increases the # size of the checkout. Also, the library is dependent on Java (which is not diff --git a/src/itf/IAndroidConfiguration.c b/src/itf/IAndroidConfiguration.c index 506e2cc..9465269 100644 --- a/src/itf/IAndroidConfiguration.c +++ b/src/itf/IAndroidConfiguration.c @@ -16,9 +16,13 @@ /* AndroidConfiguration implementation */ +#include <android/log.h> + #include "sles_allinclusive.h" #include <SLES/OpenSLES_Android.h> +#include <android_runtime/AndroidRuntime.h> + static SLresult IAndroidConfiguration_SetConfiguration(SLAndroidConfigurationItf self, const SLchar *configKey, const void *pConfigValue, @@ -98,104 +102,191 @@ static SLresult IAndroidConfiguration_GetConfiguration(SLAndroidConfigurationItf /* * Native Routing API */ +static SLresult ValidatePlayerConfig(IAndroidConfiguration* iConfig) { + SLresult result; + + if (iConfig->mRoutingProxy != NULL) { + result = SL_RESULT_PRECONDITIONS_VIOLATED; + SL_LOGE("Error creating routing object - Routing Proxy Already Acquired."); + } + else { + IObject* configObj = iConfig->mThis; // get corresponding object + CAudioPlayer* player = (CAudioPlayer*)configObj; // get the native player + + switch (player->mAndroidObjType) { + case AUDIOPLAYER_FROM_PCM_BUFFERQUEUE: + if (player->mObject.mState != SL_OBJECT_STATE_REALIZED) { + // Make sure the player has been realized. + result = SL_RESULT_PRECONDITIONS_VIOLATED; + SL_LOGE("Error creating routing object - Player not realized."); + } else { + android::AudioTrack* pAudioTrack = player->mAudioTrack.get(); + if (pAudioTrack == NULL) { + result = SL_RESULT_INTERNAL_ERROR; + SL_LOGE("Error creating routing object - Couldn't get AudioTrack."); + } else { + result = SL_RESULT_SUCCESS; + } + } + break; + + default: + result = SL_RESULT_PARAMETER_INVALID; + SL_LOGE("Error creating routing object - Player is not a buffer-queue player."); + break; + } + } + + return result; +} + +static SLresult AllocPlayerRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) { + SLresult result; + + IObject* configObj = iConfig->mThis; // get corresponding object + android::AudioTrack* pAudioTrack = ((CAudioPlayer*)configObj)->mAudioTrack.get(); + + JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); + + // Get the constructor for (Java) AudioTrackRoutingProxy + jclass clsAudioTrackRoutingProxy = + j_env->FindClass("android/media/AudioTrackRoutingProxy"); + jmethodID midAudioTrackRoutingProxy_ctor = + j_env->GetMethodID(clsAudioTrackRoutingProxy, "<init>", "(J)V"); + + j_env->ExceptionClear(); + + jobject localObjRef = + j_env->NewObject(clsAudioTrackRoutingProxy, + midAudioTrackRoutingProxy_ctor, + (uintptr_t)pAudioTrack /*audioTrackObjInLong*/); + *proxyObj = j_env->NewGlobalRef(localObjRef); + + if (j_env->ExceptionCheck()) { + SL_LOGE("Java exception creating player routing object."); + result = SL_RESULT_INTERNAL_ERROR; + } else { + // stash it in the Interface object + iConfig->mRoutingProxy = *proxyObj; + result = SL_RESULT_SUCCESS; + } + + return result; +} + +static SLresult ValidateRecorderConfig(IAndroidConfiguration* iConfig) { + SLresult result; + + if (iConfig->mRoutingProxy != NULL) { + result = SL_RESULT_PRECONDITIONS_VIOLATED; + SL_LOGE("Error creating routing object - Routing Proxy Already Acquired."); + } else { + IObject* configObj = iConfig->mThis; // get corresponding object + CAudioRecorder* recorder = (CAudioRecorder*)configObj; // get the native recorder + switch (recorder->mAndroidObjType) { + case AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE: + if (recorder->mObject.mState != SL_OBJECT_STATE_REALIZED) { + // Make sure the recorder has been realized. + result = SL_RESULT_PRECONDITIONS_VIOLATED; + SL_LOGE("Error creating routing object - Recorder not realized."); + } else { + android::AudioRecord* pAudioRecord = recorder->mAudioRecord.get(); + if (pAudioRecord == NULL) { + result = SL_RESULT_INTERNAL_ERROR; + SL_LOGE("Error creating routing object - Couldn't get AudioRecord."); + } else if (iConfig->mRoutingProxy != NULL) { + result = SL_RESULT_PRECONDITIONS_VIOLATED; + SL_LOGE("Error creating routing object - Routing Proxy Already Acquired."); + } else { + result = SL_RESULT_SUCCESS; + } + } + break; + + default: + result = SL_RESULT_PARAMETER_INVALID; + SL_LOGE("Error creating routing object - Recorder is not a buffer-queue recorder."); + break; + } + } + + return result; +} + +static SLresult AllocRecorderRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) { + SLresult result; + + IObject* configObj = iConfig->mThis; // get corresponding object + android::AudioRecord* pAudioRecord = ((CAudioRecorder*)configObj)->mAudioRecord.get(); + + JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); + + // Get the constructor for (Java) AudioRecordRoutingProxy + jclass clsAudioRecordRoutingProxy = + j_env->FindClass("android/media/AudioRecordRoutingProxy"); + jmethodID midAudioRecordRoutingProxy_ctor = + j_env->GetMethodID(clsAudioRecordRoutingProxy, "<init>", "(J)V"); + + j_env->ExceptionClear(); + jobject localObjRef = + j_env->NewObject(clsAudioRecordRoutingProxy, + midAudioRecordRoutingProxy_ctor, + (uintptr_t)pAudioRecord /*audioRecordObjInLong*/); + *proxyObj = j_env->NewGlobalRef(localObjRef); + if (j_env->ExceptionCheck()) { + SL_LOGE("Java exception creating recorder routing object."); + result = SL_RESULT_INTERNAL_ERROR; + } else { + // stash it in the Interface object + iConfig->mRoutingProxy = *proxyObj; + result = SL_RESULT_SUCCESS; + } + + return result; +} /* - * Acquires a Java AudioRouting object (interface implementation) which can be used to control - * the routing of the associated native player or recorder. Note that the Java Routing object - * can not be acquired until the AudioTrack or AudioRecorder associated with the - * SLAndroidConfigurationItf has been realized (i.e. SLPlayItf::realize() or - * SLRecordItf::realize() has been called). + * Acquires a Java proxy object, such as AudioRouting object which can be used to control + * aspects of the associated native player or recorder. * Parameters: * self An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer * or AudioRecorder. * j_env The Java Environment pointer (passed in to the calling JNI function). - * pObject Points to the jobject to receive the acquired AudioRouting interface - * implementation. - * Returns SL_RESULT_SUCCESS is the AudioRouting is acquired, SL_RESULT_PARAMETER_INVALID if + * proxyType Specifies the type of proxy desired. Currently only SL_ANDROID_JAVA_PROXY_ROUTING + * is supported. + * proxyObj + * Points to the jobject to receive the acquired Java proxy object (as a GlobalRef). + * Returns SL_RESULT_SUCCESS is the proxy object is acquired, SL_RESULT_PARAMETER_INVALID if * there is a problem with the arguments causing the function to fail, + * <working on this> * SL_RESULT_PRECONDITIONS_VIOLATED it the AudioPlayer or AudioRecorder object associated * with the ConfigurationItf has not been realized. */ -static SLresult IAndroidConfiguration_AcquireJavaAudioRouting(SLAndroidConfigurationItf self, - JNIEnv *j_env, jobject *pObject) +static SLresult IAndroidConfiguration_AcquireJavaProxy(SLAndroidConfigurationItf self, + SLuint32 proxyType, + jobject* proxyObj) { SL_ENTER_INTERFACE - if (j_env == NULL || self == NULL || pObject == NULL) { + if (self == NULL || proxyObj == NULL || proxyType != SL_ANDROID_JAVA_PROXY_ROUTING) { result = SL_RESULT_PARAMETER_INVALID; } else { - IObject *thisObject = InterfaceToIObject((IAndroidConfiguration *) self); + IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; - switch (IObjectToObjectID(thisObject)) { + int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); + switch (objID) { case SL_OBJECTID_AUDIOPLAYER: - { - // Get the constructor for (Java) AudioTrackRoutingProxy - jclass clsAudioTrackRoutingProxy = - j_env->FindClass("android/media/AudioTrackRoutingProxy"); - jmethodID midAudioTrackRoutingProxy_ctor = - j_env->GetMethodID(clsAudioTrackRoutingProxy, "<init>", "(J)V"); - - IAndroidConfiguration* configItf = (IAndroidConfiguration*)self; // Get internal struct - IObject* configObj = configItf->mThis; // get corresponding object - CAudioPlayer* player = (CAudioPlayer*)configObj; // get the native player - - // Make sure the player has been realized. - if (player->mObject.mState != SL_OBJECT_STATE_REALIZED) { - result = SL_RESULT_PRECONDITIONS_VIOLATED; - SL_LOGE("Error creating routing object - Player not realized."); - } else { - android::AudioTrack* pAudioTrack = player->mAudioTrack.get(); - if (pAudioTrack == NULL) { - result = SL_RESULT_INTERNAL_ERROR; - } else { - *pObject = j_env->NewObject(clsAudioTrackRoutingProxy, - midAudioTrackRoutingProxy_ctor, - (uintptr_t)pAudioTrack /*audioTrackObjInLong*/); - if (j_env->ExceptionCheck()) { - SL_LOGE("Java exception creating player routing object."); - result = SL_RESULT_INTERNAL_ERROR; - } else { - result = SL_RESULT_SUCCESS; - } - } + result = ValidatePlayerConfig(iConfig); + if (result == SL_RESULT_SUCCESS) { + result = AllocPlayerRoutingProxy(iConfig, proxyObj); } - } break; case SL_OBJECTID_AUDIORECORDER: - { - // Get the constructor for (Java) AudioRecordRoutingProxy - jclass clsAudioRecordRoutingProxy = - j_env->FindClass("android/media/AudioRecordRoutingProxy"); - jmethodID midAudioRecordRoutingProxy_ctor = - j_env->GetMethodID(clsAudioRecordRoutingProxy, "<init>", "(J)V"); - - IAndroidConfiguration* configItf = (IAndroidConfiguration*)self; // Get internal struct - IObject* configObj = configItf->mThis; // get corresponding object - CAudioRecorder* recorder = (CAudioRecorder*)configObj; // get the native recorder - - // Make sure the recorder has been realized. - if (recorder->mObject.mState != SL_OBJECT_STATE_REALIZED) { - result = SL_RESULT_PRECONDITIONS_VIOLATED; - SL_LOGE("Error creating routing object - Recorder not realized."); - } else { - android::AudioRecord* pAudioRecord = recorder->mAudioRecord.get(); - if (pAudioRecord == NULL) { - result = SL_RESULT_INTERNAL_ERROR; - } else { - *pObject = - j_env->NewObject(clsAudioRecordRoutingProxy, - midAudioRecordRoutingProxy_ctor, - (uintptr_t)pAudioRecord /*audioRecordObjInLong*/); - if (j_env->ExceptionCheck()) { - SL_LOGE("Java exception creating recorder routing object."); - result = SL_RESULT_INTERNAL_ERROR; - } else { - result = SL_RESULT_SUCCESS; - } - } + result = ValidateRecorderConfig(iConfig); + if (result == SL_RESULT_SUCCESS) { + result = AllocRecorderRoutingProxy(iConfig, proxyObj); } - } break; default: @@ -207,10 +298,83 @@ static SLresult IAndroidConfiguration_AcquireJavaAudioRouting(SLAndroidConfigura SL_LEAVE_INTERFACE } +/* + * Release a Java proxy object, such as AudioRouting object, (and any resources it is holding). + * Parameters: + * self An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer + * or AudioRecorder. + * j_env The Java Environment pointer (passed in to the calling JNI function). + * proxyType Specifies the type of proxy object. Currently only SL_ANDROID_JAVA_PROXY_ROUTING + * is supported. + * Returns SL_RESULT_SUCCESS is the proxy object is release, SL_RESULT_PARAMETER_INVALID if + * there is a problem with the arguments causing the function to fail, + */ +static SLresult IAndroidConfiguration_ReleaseJavaProxy(SLAndroidConfigurationItf self, + SLuint32 proxyType) { + SL_ENTER_INTERFACE + + IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; + + if (self == NULL || + proxyType != SL_ANDROID_JAVA_PROXY_ROUTING || + iConfig->mRoutingProxy == NULL) { + result = SL_RESULT_PARAMETER_INVALID; + } else { + int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); + switch (objID) { + case SL_OBJECTID_AUDIOPLAYER: + { + JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); + + // Get the release method for (Java) AudioTrackRoutingProxy + jclass clsAudioTrackRoutingProxy = + j_env->FindClass("android/media/AudioTrackRoutingProxy"); + jmethodID midAudioTrackRoutingProxy_release = + j_env->GetMethodID(clsAudioTrackRoutingProxy, "native_release", "()V"); + + j_env->ExceptionClear(); + j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioTrackRoutingProxy_release); + if (j_env->ExceptionCheck()) { + SL_LOGE("Java exception releasing recorder routing object."); + result = SL_RESULT_INTERNAL_ERROR; + } + j_env->DeleteGlobalRef(iConfig->mRoutingProxy); + iConfig->mRoutingProxy = NULL; + } + break; + + case SL_OBJECTID_AUDIORECORDER: + { + JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); + + // Get the release method for (Java) AudioTrackRoutingProxy + jclass clsAudioRecordRoutingProxy = + j_env->FindClass("android/media/AudioRecordRoutingProxy"); + jmethodID midAudioRecordRoutingProxy_release = + j_env->GetMethodID(clsAudioRecordRoutingProxy, "native_release", "()V"); + + j_env->ExceptionClear(); + j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioRecordRoutingProxy_release); + if (j_env->ExceptionCheck()) { + SL_LOGE("Java exception releasing recorder routing object."); + result = SL_RESULT_INTERNAL_ERROR; + } + j_env->DeleteGlobalRef(iConfig->mRoutingProxy); + iConfig->mRoutingProxy = NULL; + } + break; + } + result = SL_RESULT_SUCCESS; + } + + SL_LEAVE_INTERFACE +} + static const struct SLAndroidConfigurationItf_ IAndroidConfiguration_Itf = { IAndroidConfiguration_SetConfiguration, IAndroidConfiguration_GetConfiguration, - IAndroidConfiguration_AcquireJavaAudioRouting + IAndroidConfiguration_AcquireJavaProxy, + IAndroidConfiguration_ReleaseJavaProxy }; void IAndroidConfiguration_init(void *self) diff --git a/src/itfstruct.h b/src/itfstruct.h index 815f21e..c1e111e 100644 --- a/src/itfstruct.h +++ b/src/itfstruct.h @@ -16,6 +16,8 @@ #include "Configuration.h" #ifdef ANDROID +#include <jni.h> + #include "media/AudioEffect.h" #include "hardware/audio_effect.h" #endif @@ -662,6 +664,8 @@ typedef struct { typedef struct { const struct SLAndroidConfigurationItf_ *mItf; IObject *mThis; + // only 1 each. When we support other Proxy types, we will need to get more clever about this. + jobject mRoutingProxy; } IAndroidConfiguration; typedef struct { |