1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* AndroidConfiguration implementation */ 18 19#include <android/log.h> 20 21#include "sles_allinclusive.h" 22#include <SLES/OpenSLES_Android.h> 23 24#include <android_runtime/AndroidRuntime.h> 25 26static SLresult IAndroidConfiguration_SetConfiguration(SLAndroidConfigurationItf self, 27 const SLchar *configKey, 28 const void *pConfigValue, 29 SLuint32 valueSize) 30{ 31 SL_ENTER_INTERFACE 32 33 // object-specific code will check that valueSize is large enough for the key 34 if (NULL == configKey || NULL == pConfigValue || valueSize == 0) { 35 result = SL_RESULT_PARAMETER_INVALID; 36 37 } else { 38 IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; 39 interface_lock_exclusive(thiz); 40 41 // route configuration to the appropriate object 42 switch (IObjectToObjectID((thiz)->mThis)) { 43 case SL_OBJECTID_AUDIORECORDER: 44 SL_LOGV("SetConfiguration issued for AudioRecorder key=%s valueSize=%u", 45 configKey, valueSize); 46 result = android_audioRecorder_setConfig((CAudioRecorder *) thiz->mThis, configKey, 47 pConfigValue, valueSize); 48 break; 49 case SL_OBJECTID_AUDIOPLAYER: 50 SL_LOGV("SetConfiguration issued for AudioPlayer key=%s valueSize=%u", 51 configKey, valueSize); 52 result = android_audioPlayer_setConfig((CAudioPlayer *) thiz->mThis, configKey, 53 pConfigValue, valueSize); 54 break; 55 default: 56 result = SL_RESULT_FEATURE_UNSUPPORTED; 57 break; 58 } 59 60 interface_unlock_exclusive(thiz); 61 } 62 63 SL_LEAVE_INTERFACE 64} 65 66 67static SLresult IAndroidConfiguration_GetConfiguration(SLAndroidConfigurationItf self, 68 const SLchar *configKey, 69 SLuint32 *pValueSize, 70 void *pConfigValue) 71{ 72 SL_ENTER_INTERFACE 73 74 // non-NULL pValueSize is required, but a NULL pConfigValue is allowed, so 75 // that we can report the actual value size without returning the value itself 76 if (NULL == configKey || NULL == pValueSize) { 77 result = SL_RESULT_PARAMETER_INVALID; 78 } else { 79 IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; 80 interface_lock_exclusive(thiz); 81 82 // route configuration request to the appropriate object 83 switch (IObjectToObjectID((thiz)->mThis)) { 84 case SL_OBJECTID_AUDIORECORDER: 85 result = android_audioRecorder_getConfig((CAudioRecorder *) thiz->mThis, configKey, 86 pValueSize, pConfigValue); 87 break; 88 case SL_OBJECTID_AUDIOPLAYER: 89 result = android_audioPlayer_getConfig((CAudioPlayer *) thiz->mThis, configKey, 90 pValueSize, pConfigValue); 91 break; 92 default: 93 result = SL_RESULT_FEATURE_UNSUPPORTED; 94 break; 95 } 96 97 interface_unlock_exclusive(thiz); 98 } 99 100 SL_LEAVE_INTERFACE 101} 102 103/* 104 * Native Routing API 105 */ 106static SLresult ValidatePlayerConfig(IAndroidConfiguration* iConfig) { 107 SLresult result; 108 109 if (iConfig->mRoutingProxy != NULL) { 110 result = SL_RESULT_PRECONDITIONS_VIOLATED; 111 SL_LOGE("Error creating player routing object - Routing Proxy Already Acquired."); 112 } 113 else { 114 IObject* configObj = iConfig->mThis; // get corresponding object 115 CAudioPlayer* player = (CAudioPlayer*)configObj; // get the native player 116 117 switch (player->mAndroidObjType) { 118 case AUDIOPLAYER_FROM_PCM_BUFFERQUEUE: 119 //TODO remove these commented out lines when our comfort level is good 120// if (player->mObject.mState != SL_OBJECT_STATE_REALIZED) { 121// // Make sure the player has been realized. 122// result = SL_RESULT_PRECONDITIONS_VIOLATED; 123// SL_LOGE("Error creating routing object - Player not realized."); 124// } else { 125// android::AudioTrack* pAudioTrack = player->mAudioTrack.get(); 126// if (pAudioTrack == NULL) { 127// result = SL_RESULT_INTERNAL_ERROR; 128// SL_LOGE("Error creating routing object - Couldn't get AudioTrack."); 129// } else { 130 result = SL_RESULT_SUCCESS; 131// } 132// } 133 break; 134 135 default: 136 result = SL_RESULT_PARAMETER_INVALID; 137 SL_LOGE("Error creating routing object - Player is not a buffer-queue player."); 138 break; 139 } 140 } 141 142 return result; 143} 144 145static SLresult AllocPlayerRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) { 146 SLresult result; 147 148 IObject* configObj = iConfig->mThis; // get corresponding object 149 android::AudioTrack* pAudioTrack = ((CAudioPlayer*)configObj)->mTrackPlayer->mAudioTrack.get(); 150 151 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 152 153 // Get the constructor for (Java) AudioTrackRoutingProxy 154 jclass clsAudioTrackRoutingProxy = 155 j_env->FindClass("android/media/AudioTrackRoutingProxy"); 156 jmethodID midAudioTrackRoutingProxy_ctor = 157 j_env->GetMethodID(clsAudioTrackRoutingProxy, "<init>", "(J)V"); 158 159 j_env->ExceptionClear(); 160 161 jobject localObjRef = 162 j_env->NewObject(clsAudioTrackRoutingProxy, 163 midAudioTrackRoutingProxy_ctor, 164 (jlong)pAudioTrack /*audioTrackObjInLong*/); 165 166 *proxyObj = j_env->NewGlobalRef(localObjRef); 167 168 if (j_env->ExceptionCheck()) { 169 SL_LOGE("Java exception creating player routing object."); 170 result = SL_RESULT_INTERNAL_ERROR; 171 } else { 172 // stash it in the Interface object 173 iConfig->mRoutingProxy = *proxyObj; 174 result = SL_RESULT_SUCCESS; 175 } 176 177 return result; 178} 179 180static SLresult ValidateRecorderConfig(IAndroidConfiguration* iConfig) { 181 SLresult result; 182 183 if (iConfig->mRoutingProxy != NULL) { 184 result = SL_RESULT_PRECONDITIONS_VIOLATED; 185 SL_LOGE("Error creating record routing object - Routing Proxy Already Acquired."); 186 } else { 187 IObject* configObj = iConfig->mThis; // get corresponding object 188 CAudioRecorder* recorder = (CAudioRecorder*)configObj; // get the native recorder 189 switch (recorder->mAndroidObjType) { 190 case AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE: 191 //TODO remove these commented out lines when our comfort level is good 192// if (recorder->mObject.mState != SL_OBJECT_STATE_REALIZED) { 193// // Make sure the recorder has been realized. 194// result = SL_RESULT_PRECONDITIONS_VIOLATED; 195// SL_LOGE("Error creating routing object - Recorder not realized."); 196// } else { 197// android::AudioRecord* pAudioRecord = recorder->mAudioRecord.get(); 198// if (pAudioRecord == NULL) { 199// result = SL_RESULT_INTERNAL_ERROR; 200// SL_LOGE("Error creating routing object - Couldn't get AudioRecord."); 201// } else if (iConfig->mRoutingProxy != NULL) { 202// result = SL_RESULT_PRECONDITIONS_VIOLATED; 203// SL_LOGE("Error creating routing object - Routing Proxy Already Acquired." 204// ); 205// } else { 206 result = SL_RESULT_SUCCESS; 207// } 208// } 209 break; 210 211 default: 212 result = SL_RESULT_PARAMETER_INVALID; 213 SL_LOGE("Error creating routing object - Recorder is not a buffer-queue recorder."); 214 break; 215 } 216 } 217 218 return result; 219} 220 221static SLresult AllocRecorderRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) { 222 SLresult result; 223 224 IObject* configObj = iConfig->mThis; // get corresponding object 225 android::AudioRecord* pAudioRecord = ((CAudioRecorder*)configObj)->mAudioRecord.get(); 226 227 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 228 229 // Get the constructor for (Java) AudioRecordRoutingProxy 230 jclass clsAudioRecordRoutingProxy = 231 j_env->FindClass("android/media/AudioRecordRoutingProxy"); 232 jmethodID midAudioRecordRoutingProxy_ctor = 233 j_env->GetMethodID(clsAudioRecordRoutingProxy, "<init>", "(J)V"); 234 235 j_env->ExceptionClear(); 236 jobject localObjRef = 237 j_env->NewObject(clsAudioRecordRoutingProxy, 238 midAudioRecordRoutingProxy_ctor, 239 (jlong)pAudioRecord /*audioRecordObjInLong*/); 240 241 *proxyObj = j_env->NewGlobalRef(localObjRef); 242 if (j_env->ExceptionCheck()) { 243 SL_LOGE("Java exception creating recorder routing object."); 244 result = SL_RESULT_INTERNAL_ERROR; 245 } else { 246 // stash it in the Interface object 247 iConfig->mRoutingProxy = *proxyObj; 248 result = SL_RESULT_SUCCESS; 249 } 250 251 return result; 252} 253 254/* 255 * Acquires a Java proxy object, such as AudioRouting object which can be used to control 256 * aspects of the associated native player or recorder. 257 * Parameters: 258 * self An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer 259 * or AudioRecorder. 260 * j_env The Java Environment pointer (passed in to the calling JNI function). 261 * proxyType Specifies the type of proxy desired. Currently only SL_ANDROID_JAVA_PROXY_ROUTING 262 * is supported. 263 * proxyObj 264 * Points to the jobject to receive the acquired Java proxy object (as a GlobalRef). 265 * Returns SL_RESULT_SUCCESS is the proxy object is acquired, SL_RESULT_PARAMETER_INVALID if 266 * there is a problem with the arguments causing the function to fail, 267 * <working on this> 268 * SL_RESULT_PRECONDITIONS_VIOLATED it the AudioPlayer or AudioRecorder object associated 269 * with the ConfigurationItf has not been realized. 270 */ 271static SLresult IAndroidConfiguration_AcquireJavaProxy(SLAndroidConfigurationItf self, 272 SLuint32 proxyType, 273 jobject* proxyObj) 274{ 275 SL_ENTER_INTERFACE 276 277 if (self == NULL || proxyObj == NULL || proxyType != SL_ANDROID_JAVA_PROXY_ROUTING) { 278 result = SL_RESULT_PARAMETER_INVALID; 279 } else { 280 IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; 281 282 int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); 283 switch (objID) { 284 case SL_OBJECTID_AUDIOPLAYER: 285 result = ValidatePlayerConfig(iConfig); 286 if (result == SL_RESULT_SUCCESS) { 287 result = AllocPlayerRoutingProxy(iConfig, proxyObj); 288 } 289 break; 290 291 case SL_OBJECTID_AUDIORECORDER: 292 result = ValidateRecorderConfig(iConfig); 293 if (result == SL_RESULT_SUCCESS) { 294 result = AllocRecorderRoutingProxy(iConfig, proxyObj); 295 } 296 break; 297 298 default: 299 result = SL_RESULT_PARAMETER_INVALID; 300 break; 301 } 302 } 303 304 SL_LEAVE_INTERFACE 305} 306 307/* 308 * Release a Java proxy object, such as AudioRouting object, (and any resources it is holding). 309 * Parameters: 310 * self An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer 311 * or AudioRecorder. 312 * j_env The Java Environment pointer (passed in to the calling JNI function). 313 * proxyType Specifies the type of proxy object. Currently only SL_ANDROID_JAVA_PROXY_ROUTING 314 * is supported. 315 * Returns SL_RESULT_SUCCESS is the proxy object is release, SL_RESULT_PARAMETER_INVALID if 316 * there is a problem with the arguments causing the function to fail, 317 */ 318static SLresult IAndroidConfiguration_ReleaseJavaProxy(SLAndroidConfigurationItf self, 319 SLuint32 proxyType) { 320 SL_ENTER_INTERFACE 321 322 IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; 323 324 if (self == NULL || 325 proxyType != SL_ANDROID_JAVA_PROXY_ROUTING || 326 iConfig->mRoutingProxy == NULL) { 327 result = SL_RESULT_PARAMETER_INVALID; 328 } else { 329 int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); 330 switch (objID) { 331 case SL_OBJECTID_AUDIOPLAYER: 332 { 333 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 334 335 // Get the release method for (Java) AudioTrackRoutingProxy 336 jclass clsAudioTrackRoutingProxy = 337 j_env->FindClass("android/media/AudioTrackRoutingProxy"); 338 jmethodID midAudioTrackRoutingProxy_release = 339 j_env->GetMethodID(clsAudioTrackRoutingProxy, "native_release", "()V"); 340 341 j_env->ExceptionClear(); 342 j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioTrackRoutingProxy_release); 343 if (j_env->ExceptionCheck()) { 344 SL_LOGE("Java exception releasing recorder routing object."); 345 result = SL_RESULT_INTERNAL_ERROR; 346 } 347 j_env->DeleteGlobalRef(iConfig->mRoutingProxy); 348 iConfig->mRoutingProxy = NULL; 349 } 350 break; 351 352 case SL_OBJECTID_AUDIORECORDER: 353 { 354 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 355 356 // Get the release method for (Java) AudioTrackRoutingProxy 357 jclass clsAudioRecordRoutingProxy = 358 j_env->FindClass("android/media/AudioRecordRoutingProxy"); 359 jmethodID midAudioRecordRoutingProxy_release = 360 j_env->GetMethodID(clsAudioRecordRoutingProxy, "native_release", "()V"); 361 362 j_env->ExceptionClear(); 363 j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioRecordRoutingProxy_release); 364 if (j_env->ExceptionCheck()) { 365 SL_LOGE("Java exception releasing recorder routing object."); 366 result = SL_RESULT_INTERNAL_ERROR; 367 } 368 j_env->DeleteGlobalRef(iConfig->mRoutingProxy); 369 iConfig->mRoutingProxy = NULL; 370 } 371 break; 372 } 373 374 result = SL_RESULT_SUCCESS; 375 } 376 377 SL_LEAVE_INTERFACE 378} 379 380static const struct SLAndroidConfigurationItf_ IAndroidConfiguration_Itf = { 381 IAndroidConfiguration_SetConfiguration, 382 IAndroidConfiguration_GetConfiguration, 383 IAndroidConfiguration_AcquireJavaProxy, 384 IAndroidConfiguration_ReleaseJavaProxy 385}; 386 387void IAndroidConfiguration_init(void *self) 388{ 389 IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; 390 thiz->mItf = &IAndroidConfiguration_Itf; 391} 392 393void IAndroidConfiguration_deinit(void *self) 394{ 395 IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; 396 if (thiz->mRoutingProxy != NULL) { 397 thiz->mItf->ReleaseJavaProxy(&thiz->mItf, SL_ANDROID_JAVA_PROXY_ROUTING); 398 } 399} 400 401