/*
* 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);
}
}