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 26 static 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 67 static 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 default: 92 result = SL_RESULT_FEATURE_UNSUPPORTED; 93 break; 94 } 95 96 interface_unlock_exclusive(thiz); 97 } 98 99 SL_LEAVE_INTERFACE 100 } 101 102 /* 103 * Native Routing API 104 */ 105 static SLresult ValidatePlayerConfig(IAndroidConfiguration* iConfig) { 106 SLresult result; 107 108 if (iConfig->mRoutingProxy != NULL) { 109 result = SL_RESULT_PRECONDITIONS_VIOLATED; 110 SL_LOGE("Error creating player routing object - Routing Proxy Already Acquired."); 111 } 112 else { 113 IObject* configObj = iConfig->mThis; // get corresponding object 114 CAudioPlayer* player = (CAudioPlayer*)configObj; // get the native player 115 116 switch (player->mAndroidObjType) { 117 case AUDIOPLAYER_FROM_PCM_BUFFERQUEUE: 118 //TODO remove these commented out lines when our comfort level is good 119 // if (player->mObject.mState != SL_OBJECT_STATE_REALIZED) { 120 // // Make sure the player has been realized. 121 // result = SL_RESULT_PRECONDITIONS_VIOLATED; 122 // SL_LOGE("Error creating routing object - Player not realized."); 123 // } else { 124 // android::AudioTrack* pAudioTrack = player->mAudioTrack.get(); 125 // if (pAudioTrack == NULL) { 126 // result = SL_RESULT_INTERNAL_ERROR; 127 // SL_LOGE("Error creating routing object - Couldn't get AudioTrack."); 128 // } else { 129 result = SL_RESULT_SUCCESS; 130 // } 131 // } 132 break; 133 134 default: 135 result = SL_RESULT_PARAMETER_INVALID; 136 SL_LOGE("Error creating routing object - Player is not a buffer-queue player."); 137 break; 138 } 139 } 140 141 return result; 142 } 143 144 static SLresult AllocPlayerRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) { 145 SLresult result; 146 147 IObject* configObj = iConfig->mThis; // get corresponding object 148 android::AudioTrack* pAudioTrack = ((CAudioPlayer*)configObj)->mTrackPlayer->mAudioTrack.get(); 149 150 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 151 152 // Get the constructor for (Java) AudioTrackRoutingProxy 153 jclass clsAudioTrackRoutingProxy = 154 j_env->FindClass("android/media/AudioTrackRoutingProxy"); 155 jmethodID midAudioTrackRoutingProxy_ctor = 156 j_env->GetMethodID(clsAudioTrackRoutingProxy, "<init>", "(J)V"); 157 158 j_env->ExceptionClear(); 159 160 jobject localObjRef = 161 j_env->NewObject(clsAudioTrackRoutingProxy, 162 midAudioTrackRoutingProxy_ctor, 163 (jlong)pAudioTrack /*audioTrackObjInLong*/); 164 165 *proxyObj = j_env->NewGlobalRef(localObjRef); 166 167 if (j_env->ExceptionCheck()) { 168 SL_LOGE("Java exception creating player routing object."); 169 result = SL_RESULT_INTERNAL_ERROR; 170 } else { 171 // stash it in the Interface object 172 iConfig->mRoutingProxy = *proxyObj; 173 result = SL_RESULT_SUCCESS; 174 } 175 176 return result; 177 } 178 179 static SLresult ValidateRecorderConfig(IAndroidConfiguration* iConfig) { 180 SLresult result; 181 182 if (iConfig->mRoutingProxy != NULL) { 183 result = SL_RESULT_PRECONDITIONS_VIOLATED; 184 SL_LOGE("Error creating record routing object - Routing Proxy Already Acquired."); 185 } else { 186 IObject* configObj = iConfig->mThis; // get corresponding object 187 CAudioRecorder* recorder = (CAudioRecorder*)configObj; // get the native recorder 188 switch (recorder->mAndroidObjType) { 189 case AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE: 190 //TODO remove these commented out lines when our comfort level is good 191 // if (recorder->mObject.mState != SL_OBJECT_STATE_REALIZED) { 192 // // Make sure the recorder has been realized. 193 // result = SL_RESULT_PRECONDITIONS_VIOLATED; 194 // SL_LOGE("Error creating routing object - Recorder not realized."); 195 // } else { 196 // android::AudioRecord* pAudioRecord = recorder->mAudioRecord.get(); 197 // if (pAudioRecord == NULL) { 198 // result = SL_RESULT_INTERNAL_ERROR; 199 // SL_LOGE("Error creating routing object - Couldn't get AudioRecord."); 200 // } else if (iConfig->mRoutingProxy != NULL) { 201 // result = SL_RESULT_PRECONDITIONS_VIOLATED; 202 // SL_LOGE("Error creating routing object - Routing Proxy Already Acquired."); 203 // } else { 204 result = SL_RESULT_SUCCESS; 205 // } 206 // } 207 break; 208 209 default: 210 result = SL_RESULT_PARAMETER_INVALID; 211 SL_LOGE("Error creating routing object - Recorder is not a buffer-queue recorder."); 212 break; 213 } 214 } 215 216 return result; 217 } 218 219 static SLresult AllocRecorderRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) { 220 SLresult result; 221 222 IObject* configObj = iConfig->mThis; // get corresponding object 223 android::AudioRecord* pAudioRecord = ((CAudioRecorder*)configObj)->mAudioRecord.get(); 224 225 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 226 227 // Get the constructor for (Java) AudioRecordRoutingProxy 228 jclass clsAudioRecordRoutingProxy = 229 j_env->FindClass("android/media/AudioRecordRoutingProxy"); 230 jmethodID midAudioRecordRoutingProxy_ctor = 231 j_env->GetMethodID(clsAudioRecordRoutingProxy, "<init>", "(J)V"); 232 233 j_env->ExceptionClear(); 234 jobject localObjRef = 235 j_env->NewObject(clsAudioRecordRoutingProxy, 236 midAudioRecordRoutingProxy_ctor, 237 (jlong)pAudioRecord /*audioRecordObjInLong*/); 238 239 *proxyObj = j_env->NewGlobalRef(localObjRef); 240 if (j_env->ExceptionCheck()) { 241 SL_LOGE("Java exception creating recorder routing object."); 242 result = SL_RESULT_INTERNAL_ERROR; 243 } else { 244 // stash it in the Interface object 245 iConfig->mRoutingProxy = *proxyObj; 246 result = SL_RESULT_SUCCESS; 247 } 248 249 return result; 250 } 251 252 /* 253 * Acquires a Java proxy object, such as AudioRouting object which can be used to control 254 * aspects of the associated native player or recorder. 255 * Parameters: 256 * self An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer 257 * or AudioRecorder. 258 * j_env The Java Environment pointer (passed in to the calling JNI function). 259 * proxyType Specifies the type of proxy desired. Currently only SL_ANDROID_JAVA_PROXY_ROUTING 260 * is supported. 261 * proxyObj 262 * Points to the jobject to receive the acquired Java proxy object (as a GlobalRef). 263 * Returns SL_RESULT_SUCCESS is the proxy object is acquired, SL_RESULT_PARAMETER_INVALID if 264 * there is a problem with the arguments causing the function to fail, 265 * <working on this> 266 * SL_RESULT_PRECONDITIONS_VIOLATED it the AudioPlayer or AudioRecorder object associated 267 * with the ConfigurationItf has not been realized. 268 */ 269 static SLresult IAndroidConfiguration_AcquireJavaProxy(SLAndroidConfigurationItf self, 270 SLuint32 proxyType, 271 jobject* proxyObj) 272 { 273 SL_ENTER_INTERFACE 274 275 if (self == NULL || proxyObj == NULL || proxyType != SL_ANDROID_JAVA_PROXY_ROUTING) { 276 result = SL_RESULT_PARAMETER_INVALID; 277 } else { 278 IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; 279 280 int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); 281 switch (objID) { 282 case SL_OBJECTID_AUDIOPLAYER: 283 result = ValidatePlayerConfig(iConfig); 284 if (result == SL_RESULT_SUCCESS) { 285 result = AllocPlayerRoutingProxy(iConfig, proxyObj); 286 } 287 break; 288 289 case SL_OBJECTID_AUDIORECORDER: 290 result = ValidateRecorderConfig(iConfig); 291 if (result == SL_RESULT_SUCCESS) { 292 result = AllocRecorderRoutingProxy(iConfig, proxyObj); 293 } 294 break; 295 296 default: 297 result = SL_RESULT_PARAMETER_INVALID; 298 break; 299 } 300 } 301 302 SL_LEAVE_INTERFACE 303 } 304 305 /* 306 * Release a Java proxy object, such as AudioRouting object, (and any resources it is holding). 307 * Parameters: 308 * self An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer 309 * or AudioRecorder. 310 * j_env The Java Environment pointer (passed in to the calling JNI function). 311 * proxyType Specifies the type of proxy object. Currently only SL_ANDROID_JAVA_PROXY_ROUTING 312 * is supported. 313 * Returns SL_RESULT_SUCCESS is the proxy object is release, SL_RESULT_PARAMETER_INVALID if 314 * there is a problem with the arguments causing the function to fail, 315 */ 316 static SLresult IAndroidConfiguration_ReleaseJavaProxy(SLAndroidConfigurationItf self, 317 SLuint32 proxyType) { 318 SL_ENTER_INTERFACE 319 320 IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self; 321 322 if (self == NULL || 323 proxyType != SL_ANDROID_JAVA_PROXY_ROUTING || 324 iConfig->mRoutingProxy == NULL) { 325 result = SL_RESULT_PARAMETER_INVALID; 326 } else { 327 int objID = IObjectToObjectID(InterfaceToIObject(iConfig)); 328 switch (objID) { 329 case SL_OBJECTID_AUDIOPLAYER: 330 { 331 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 332 333 // Get the release method for (Java) AudioTrackRoutingProxy 334 jclass clsAudioTrackRoutingProxy = 335 j_env->FindClass("android/media/AudioTrackRoutingProxy"); 336 jmethodID midAudioTrackRoutingProxy_release = 337 j_env->GetMethodID(clsAudioTrackRoutingProxy, "native_release", "()V"); 338 339 j_env->ExceptionClear(); 340 j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioTrackRoutingProxy_release); 341 if (j_env->ExceptionCheck()) { 342 SL_LOGE("Java exception releasing recorder routing object."); 343 result = SL_RESULT_INTERNAL_ERROR; 344 } 345 j_env->DeleteGlobalRef(iConfig->mRoutingProxy); 346 iConfig->mRoutingProxy = NULL; 347 } 348 break; 349 350 case SL_OBJECTID_AUDIORECORDER: 351 { 352 JNIEnv* j_env = android::AndroidRuntime::getJNIEnv(); 353 354 // Get the release method for (Java) AudioTrackRoutingProxy 355 jclass clsAudioRecordRoutingProxy = 356 j_env->FindClass("android/media/AudioRecordRoutingProxy"); 357 jmethodID midAudioRecordRoutingProxy_release = 358 j_env->GetMethodID(clsAudioRecordRoutingProxy, "native_release", "()V"); 359 360 j_env->ExceptionClear(); 361 j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioRecordRoutingProxy_release); 362 if (j_env->ExceptionCheck()) { 363 SL_LOGE("Java exception releasing recorder routing object."); 364 result = SL_RESULT_INTERNAL_ERROR; 365 } 366 j_env->DeleteGlobalRef(iConfig->mRoutingProxy); 367 iConfig->mRoutingProxy = NULL; 368 } 369 break; 370 } 371 372 result = SL_RESULT_SUCCESS; 373 } 374 375 SL_LEAVE_INTERFACE 376 } 377 378 static const struct SLAndroidConfigurationItf_ IAndroidConfiguration_Itf = { 379 IAndroidConfiguration_SetConfiguration, 380 IAndroidConfiguration_GetConfiguration, 381 IAndroidConfiguration_AcquireJavaProxy, 382 IAndroidConfiguration_ReleaseJavaProxy 383 }; 384 385 void IAndroidConfiguration_init(void *self) 386 { 387 IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; 388 thiz->mItf = &IAndroidConfiguration_Itf; 389 } 390 391 void IAndroidConfiguration_deinit(void *self) 392 { 393 IAndroidConfiguration *thiz = (IAndroidConfiguration *) self; 394 if (thiz->mRoutingProxy != NULL) { 395 thiz->mItf->ReleaseJavaProxy(&thiz->mItf, SL_ANDROID_JAVA_PROXY_ROUTING); 396 } 397 } 398 399