/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* 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, SLuint32 valueSize) { SL_ENTER_INTERFACE // object-specific code will check that valueSize is large enough for the key if (NULL == configKey || NULL == pConfigValue || valueSize == 0) { result = SL_RESULT_PARAMETER_INVALID; } else { IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; interface_lock_exclusive(thiz); // route configuration to the appropriate object switch (IObjectToObjectID((thiz)->mThis)) { case SL_OBJECTID_AUDIORECORDER: SL_LOGV("SetConfiguration issued for AudioRecorder key=%s valueSize=%u", configKey, valueSize); result = android_audioRecorder_setConfig((CAudioRecorder *) thiz->mThis, configKey, pConfigValue, valueSize); break; case SL_OBJECTID_AUDIOPLAYER: SL_LOGV("SetConfiguration issued for AudioPlayer key=%s valueSize=%u", configKey, valueSize); result = android_audioPlayer_setConfig((CAudioPlayer *) thiz->mThis, configKey, pConfigValue, valueSize); break; default: result = SL_RESULT_FEATURE_UNSUPPORTED; break; } interface_unlock_exclusive(thiz); } SL_LEAVE_INTERFACE } static SLresult IAndroidConfiguration_GetConfiguration(SLAndroidConfigurationItf self, const SLchar *configKey, SLuint32 *pValueSize, void *pConfigValue) { SL_ENTER_INTERFACE // non-NULL pValueSize is required, but a NULL pConfigValue is allowed, so // that we can report the actual value size without returning the value itself if (NULL == configKey || NULL == pValueSize) { result = SL_RESULT_PARAMETER_INVALID; } else { IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; interface_lock_exclusive(thiz); // route configuration request to the appropriate object switch (IObjectToObjectID((thiz)->mThis)) { case SL_OBJECTID_AUDIORECORDER: result = android_audioRecorder_getConfig((CAudioRecorder *) thiz->mThis, configKey, pValueSize, pConfigValue); break; case SL_OBJECTID_AUDIOPLAYER: result = android_audioPlayer_getConfig((CAudioPlayer *) thiz->mThis, configKey, pValueSize, pConfigValue); default: result = SL_RESULT_FEATURE_UNSUPPORTED; break; } interface_unlock_exclusive(thiz); } SL_LEAVE_INTERFACE } /* * Native Routing API */ static SLresult ValidatePlayerConfig(IAndroidConfiguration* iConfig) { SLresult result; if (iConfig->mRoutingProxy != NULL) { result = SL_RESULT_PRECONDITIONS_VIOLATED; SL_LOGE("Error creating player 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: //TODO remove these commented out lines when our comfort level is good // 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, (jlong)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 record 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: //TODO remove these commented out lines when our comfort level is good // 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, (jlong)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 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). * 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_AcquireJavaProxy(SLAndroidConfigurationItf self, SLuint32 proxyType, jobject* proxyObj) { SL_ENTER_INTERFACE if (self == NULL || proxyObj == NULL || proxyType != SL_ANDROID_JAVA_PROXY_ROUTING) { result = SL_RESULT_PARAMETER_INVALID; } else { IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); switch (objID) { case SL_OBJECTID_AUDIOPLAYER: result = ValidatePlayerConfig(iConfig); if (result == SL_RESULT_SUCCESS) { result = AllocPlayerRoutingProxy(iConfig, proxyObj); } break; case SL_OBJECTID_AUDIORECORDER: result = ValidateRecorderConfig(iConfig); if (result == SL_RESULT_SUCCESS) { result = AllocRecorderRoutingProxy(iConfig, proxyObj); } break; default: result = SL_RESULT_PARAMETER_INVALID; break; } } 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_AcquireJavaProxy, IAndroidConfiguration_ReleaseJavaProxy }; void IAndroidConfiguration_init(void *self) { IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; thiz->mItf = &IAndroidConfiguration_Itf; } void IAndroidConfiguration_deinit(void *self) { IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; if (thiz->mRoutingProxy != NULL) { thiz->mItf->ReleaseJavaProxy(&thiz->mItf, SL_ANDROID_JAVA_PROXY_ROUTING); } }