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