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        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 */
105static 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
144static 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
179static 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
219static 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 */
269static 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 */
316static 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
378static const struct SLAndroidConfigurationItf_ IAndroidConfiguration_Itf = {
379    IAndroidConfiguration_SetConfiguration,
380    IAndroidConfiguration_GetConfiguration,
381    IAndroidConfiguration_AcquireJavaProxy,
382    IAndroidConfiguration_ReleaseJavaProxy
383};
384
385void IAndroidConfiguration_init(void *self)
386{
387    IAndroidConfiguration *thiz = (IAndroidConfiguration *) self;
388    thiz->mItf = &IAndroidConfiguration_Itf;
389}
390
391void 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