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