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