IEngine.c revision 68d56b8ebaf60184a3aef988e3d2b09ed8b88c05
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/* Engine implementation */
18
19#include "sles_allinclusive.h"
20
21
22static SLresult IEngine_CreateLEDDevice(SLEngineItf self, SLObjectItf *pDevice, SLuint32 deviceID,
23    SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
24{
25    SL_ENTER_INTERFACE
26
27#if USE_PROFILES & USE_PROFILES_OPTIONAL
28    if ((NULL == pDevice) || (SL_DEFAULTDEVICEID_LED != deviceID)) {
29        result = SL_RESULT_PARAMETER_INVALID;
30    } else {
31        *pDevice = NULL;
32        unsigned exposedMask;
33        const ClassTable *pCLEDDevice_class = objectIDtoClass(SL_OBJECTID_LEDDEVICE);
34        if (NULL == pCLEDDevice_class) {
35            result = SL_RESULT_FEATURE_UNSUPPORTED;
36        } else {
37            result = checkInterfaces(pCLEDDevice_class, numInterfaces, pInterfaceIds,
38                pInterfaceRequired, &exposedMask);
39        }
40        if (SL_RESULT_SUCCESS == result) {
41            CLEDDevice *thiz = (CLEDDevice *) construct(pCLEDDevice_class, exposedMask, self);
42            if (NULL == thiz) {
43                result = SL_RESULT_MEMORY_FAILURE;
44            } else {
45                thiz->mDeviceID = deviceID;
46                IObject_Publish(&thiz->mObject);
47                // return the new LED object
48                *pDevice = &thiz->mObject.mItf;
49            }
50        }
51    }
52#else
53    result = SL_RESULT_FEATURE_UNSUPPORTED;
54#endif
55
56    SL_LEAVE_INTERFACE
57}
58
59
60static SLresult IEngine_CreateVibraDevice(SLEngineItf self, SLObjectItf *pDevice, SLuint32 deviceID,
61    SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
62{
63    SL_ENTER_INTERFACE
64
65#if USE_PROFILES & USE_PROFILES_OPTIONAL
66    if ((NULL == pDevice) || (SL_DEFAULTDEVICEID_VIBRA != deviceID)) {
67        result = SL_RESULT_PARAMETER_INVALID;
68    } else {
69        *pDevice = NULL;
70        unsigned exposedMask;
71        const ClassTable *pCVibraDevice_class = objectIDtoClass(SL_OBJECTID_VIBRADEVICE);
72        if (NULL == pCVibraDevice_class) {
73            result = SL_RESULT_FEATURE_UNSUPPORTED;
74        } else {
75            result = checkInterfaces(pCVibraDevice_class, numInterfaces,
76                pInterfaceIds, pInterfaceRequired, &exposedMask);
77        }
78        if (SL_RESULT_SUCCESS == result) {
79            CVibraDevice *thiz = (CVibraDevice *) construct(pCVibraDevice_class, exposedMask, self);
80            if (NULL == thiz) {
81                result = SL_RESULT_MEMORY_FAILURE;
82            } else {
83                thiz->mDeviceID = deviceID;
84                IObject_Publish(&thiz->mObject);
85                // return the new vibra object
86                *pDevice = &thiz->mObject.mItf;
87            }
88        }
89    }
90#else
91    result = SL_RESULT_FEATURE_UNSUPPORTED;
92#endif
93
94    SL_LEAVE_INTERFACE
95}
96
97
98static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer,
99    SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces,
100    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
101{
102    SL_ENTER_INTERFACE
103
104    if (NULL == pPlayer) {
105       result = SL_RESULT_PARAMETER_INVALID;
106    } else {
107        *pPlayer = NULL;
108        unsigned exposedMask;
109        const ClassTable *pCAudioPlayer_class = objectIDtoClass(SL_OBJECTID_AUDIOPLAYER);
110        assert(NULL != pCAudioPlayer_class);
111        result = checkInterfaces(pCAudioPlayer_class, numInterfaces,
112            pInterfaceIds, pInterfaceRequired, &exposedMask);
113        if (SL_RESULT_SUCCESS == result) {
114
115            // Construct our new AudioPlayer instance
116            CAudioPlayer *thiz = (CAudioPlayer *) construct(pCAudioPlayer_class, exposedMask, self);
117            if (NULL == thiz) {
118                result = SL_RESULT_MEMORY_FAILURE;
119            } else {
120
121                do {
122
123                    // Initialize private fields not associated with an interface
124
125                    // Default data source in case of failure in checkDataSource
126                    thiz->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL;
127                    thiz->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL;
128
129                    // Default data sink in case of failure in checkDataSink
130                    thiz->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL;
131                    thiz->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL;
132
133                    // Default is no per-channel mute or solo
134                    thiz->mMuteMask = 0;
135                    thiz->mSoloMask = 0;
136
137                    // Will be set soon for PCM buffer queues, or later by platform-specific code
138                    // during Realize or Prefetch
139                    thiz->mNumChannels = 0;
140                    thiz->mSampleRateMilliHz = 0;
141
142                    // More default values, in case destructor needs to be called early
143                    thiz->mDirectLevel = 0;
144#ifdef USE_OUTPUTMIXEXT
145                    thiz->mTrack = NULL;
146                    thiz->mGains[0] = 1.0f;
147                    thiz->mGains[1] = 1.0f;
148                    thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
149#endif
150#ifdef USE_SNDFILE
151                    thiz->mSndFile.mPathname = NULL;
152                    thiz->mSndFile.mSNDFILE = NULL;
153                    memset(&thiz->mSndFile.mSfInfo, 0, sizeof(SF_INFO));
154                    memset(&thiz->mSndFile.mMutex, 0, sizeof(pthread_mutex_t));
155                    thiz->mSndFile.mEOF = SL_BOOLEAN_FALSE;
156                    thiz->mSndFile.mWhich = 0;
157                    memset(thiz->mSndFile.mBuffer, 0, sizeof(thiz->mSndFile.mBuffer));
158#endif
159#ifdef ANDROID
160                    // extra safe initializations of pointers, in case of incomplete construction
161                    thiz->mpLock = NULL;
162                    thiz->mAudioTrack = NULL;
163                    // placement new (explicit constructor)
164                    // FIXME unnecessary once those fields are encapsulated in one class, rather
165                    //   than a structure
166                    (void) new (&thiz->mSfPlayer) android::sp<android::SfPlayer>();
167                    (void) new (&thiz->mAuxEffect) android::sp<android::AudioEffect>();
168                    (void) new (&thiz->mAPlayer) android::sp<android::GenericPlayer>();
169#endif
170
171                    // Check the source and sink parameters against generic constraints,
172                    // and make a local copy of all parameters in case other application threads
173                    // change memory concurrently.
174
175                    result = checkDataSource("pAudioSrc", pAudioSrc, &thiz->mDataSource,
176                            DATALOCATOR_MASK_URI | DATALOCATOR_MASK_ADDRESS |
177                            DATALOCATOR_MASK_BUFFERQUEUE
178#ifdef ANDROID
179                            | DATALOCATOR_MASK_ANDROIDFD | DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE
180                            | DATALOCATOR_MASK_ANDROIDBUFFERQUEUE
181#endif
182                            , DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM);
183
184                    if (SL_RESULT_SUCCESS != result) {
185                        break;
186                    }
187
188                    result = checkDataSink("pAudioSnk", pAudioSnk, &thiz->mDataSink,
189                            DATALOCATOR_MASK_OUTPUTMIX                  // for playback
190#ifdef ANDROID
191                            | DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE // for decode to a BQ
192                            | DATALOCATOR_MASK_BUFFERQUEUE              // for decode to a BQ
193#endif
194                            , DATAFORMAT_MASK_NULL
195#ifdef ANDROID
196                            | DATAFORMAT_MASK_PCM                       // for decode to PCM
197#endif
198                            );
199                    if (SL_RESULT_SUCCESS != result) {
200                        break;
201                    }
202
203                    // It would be unsafe to ever refer to the application pointers again
204                    pAudioSrc = NULL;
205                    pAudioSnk = NULL;
206
207                    // Check that the requested interfaces are compatible with the data source
208                    result = checkSourceFormatVsInterfacesCompatibility(&thiz->mDataSource,
209                            pCAudioPlayer_class, exposedMask);
210                    if (SL_RESULT_SUCCESS != result) {
211                        break;
212                    }
213
214                    // copy the buffer queue count from source locator (for playback) / from the
215                    // sink locator (for decode on ANDROID build) to the buffer queue interface
216                    // we have already range-checked the value down to a smaller width
217                    SLuint16 nbBuffers = 0;
218                    switch (thiz->mDataSource.mLocator.mLocatorType) {
219                    case SL_DATALOCATOR_BUFFERQUEUE:
220#ifdef ANDROID
221                    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
222#endif
223                        nbBuffers = (SLuint16) thiz->mDataSource.mLocator.mBufferQueue.numBuffers;
224                        assert(SL_DATAFORMAT_PCM == thiz->mDataSource.mFormat.mFormatType);
225                        thiz->mNumChannels = thiz->mDataSource.mFormat.mPCM.numChannels;
226                        thiz->mSampleRateMilliHz = thiz->mDataSource.mFormat.mPCM.samplesPerSec;
227                        break;
228                    default:
229                        nbBuffers = 0;
230                        break;
231                    }
232#ifdef ANDROID
233                    switch(thiz->mDataSink.mLocator.mLocatorType) {
234                    case SL_DATALOCATOR_BUFFERQUEUE:
235                    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
236                        nbBuffers = thiz->mDataSink.mLocator.mBufferQueue.numBuffers;
237                        assert(SL_DATAFORMAT_PCM == thiz->mDataSink.mFormat.mFormatType);
238                        thiz->mNumChannels = thiz->mDataSink.mFormat.mPCM.numChannels;
239                        thiz->mSampleRateMilliHz = thiz->mDataSink.mFormat.mPCM.samplesPerSec;
240                        break;
241                    default:
242                        // leave nbBuffers unchanged
243                        break;
244                    }
245#endif
246                    thiz->mBufferQueue.mNumBuffers = nbBuffers;
247
248                    // check the audio source and sink parameters against platform support
249#ifdef ANDROID
250                    result = android_audioPlayer_checkSourceSink(thiz);
251                    if (SL_RESULT_SUCCESS != result) {
252                        break;
253                    }
254#endif
255
256#ifdef USE_SNDFILE
257                    result = SndFile_checkAudioPlayerSourceSink(thiz);
258                    if (SL_RESULT_SUCCESS != result) {
259                        break;
260                    }
261#endif
262
263#ifdef USE_OUTPUTMIXEXT
264                    result = IOutputMixExt_checkAudioPlayerSourceSink(thiz);
265                    if (SL_RESULT_SUCCESS != result) {
266                        break;
267                    }
268#endif
269
270                    // Allocate memory for buffer queue
271
272                    //if (0 != thiz->mBufferQueue.mNumBuffers) {
273                        // inline allocation of circular mArray, up to a typical max
274                        if (BUFFER_HEADER_TYPICAL >= thiz->mBufferQueue.mNumBuffers) {
275                            thiz->mBufferQueue.mArray = thiz->mBufferQueue.mTypical;
276                        } else {
277                            // Avoid possible integer overflow during multiplication; this arbitrary
278                            // maximum is big enough to not interfere with real applications, but
279                            // small enough to not overflow.
280                            if (thiz->mBufferQueue.mNumBuffers >= 256) {
281                                result = SL_RESULT_MEMORY_FAILURE;
282                                break;
283                            }
284                            thiz->mBufferQueue.mArray = (BufferHeader *) malloc((thiz->mBufferQueue.
285                                mNumBuffers + 1) * sizeof(BufferHeader));
286                            if (NULL == thiz->mBufferQueue.mArray) {
287                                result = SL_RESULT_MEMORY_FAILURE;
288                                break;
289                            }
290                        }
291                        thiz->mBufferQueue.mFront = thiz->mBufferQueue.mArray;
292                        thiz->mBufferQueue.mRear = thiz->mBufferQueue.mArray;
293                        //}
294
295                        // used to store the data source of our audio player
296                        thiz->mDynamicSource.mDataSource = &thiz->mDataSource.u.mSource;
297
298                        // platform-specific initialization
299#ifdef ANDROID
300                        android_audioPlayer_create(thiz);
301#endif
302
303                } while (0);
304
305                if (SL_RESULT_SUCCESS != result) {
306                    IObject_Destroy(&thiz->mObject.mItf);
307                } else {
308                    IObject_Publish(&thiz->mObject);
309                    // return the new audio player object
310                    *pPlayer = &thiz->mObject.mItf;
311                }
312
313            }
314        }
315
316    }
317
318    SL_LEAVE_INTERFACE
319}
320
321
322static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pRecorder,
323    SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces,
324    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
325{
326    SL_ENTER_INTERFACE
327
328#if (USE_PROFILES & USE_PROFILES_OPTIONAL) || defined(ANDROID)
329    if (NULL == pRecorder) {
330        result = SL_RESULT_PARAMETER_INVALID;
331    } else {
332        *pRecorder = NULL;
333        unsigned exposedMask;
334        const ClassTable *pCAudioRecorder_class = objectIDtoClass(SL_OBJECTID_AUDIORECORDER);
335        if (NULL == pCAudioRecorder_class) {
336            result = SL_RESULT_FEATURE_UNSUPPORTED;
337        } else {
338            result = checkInterfaces(pCAudioRecorder_class, numInterfaces,
339                    pInterfaceIds, pInterfaceRequired, &exposedMask);
340        }
341
342        if (SL_RESULT_SUCCESS == result) {
343
344            // Construct our new AudioRecorder instance
345            CAudioRecorder *thiz = (CAudioRecorder *) construct(pCAudioRecorder_class, exposedMask,
346                    self);
347            if (NULL == thiz) {
348                result = SL_RESULT_MEMORY_FAILURE;
349            } else {
350
351                do {
352
353                    // Initialize fields not associated with any interface
354
355                    // Default data source in case of failure in checkDataSource
356                    thiz->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL;
357                    thiz->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL;
358
359                    // Default data sink in case of failure in checkDataSink
360                    thiz->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL;
361                    thiz->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL;
362
363                    // These fields are set to real values by
364                    // android_audioRecorder_checkSourceSinkSupport.  Note that the data sink is
365                    // always PCM buffer queue, so we know the channel count and sample rate early.
366                    thiz->mNumChannels = 0;
367                    thiz->mSampleRateMilliHz = 0;
368#ifdef ANDROID
369                    thiz->mAudioRecord = NULL;
370                    thiz->mRecordSource = android::AUDIO_SOURCE_DEFAULT;
371#endif
372
373                    // Check the source and sink parameters, and make a local copy of all parameters
374                    result = checkDataSource("pAudioSrc", pAudioSrc, &thiz->mDataSource,
375                            DATALOCATOR_MASK_IODEVICE, DATAFORMAT_MASK_NULL);
376                    if (SL_RESULT_SUCCESS != result) {
377                        break;
378                    }
379                    result = checkDataSink("pAudioSnk", pAudioSnk, &thiz->mDataSink,
380                            DATALOCATOR_MASK_URI
381#ifdef ANDROID
382                            | DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE
383#endif
384                            , DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM
385                    );
386                    if (SL_RESULT_SUCCESS != result) {
387                        break;
388                    }
389
390                    // It would be unsafe to ever refer to the application pointers again
391                    pAudioSrc = NULL;
392                    pAudioSnk = NULL;
393
394                    // check the audio source and sink parameters against platform support
395#ifdef ANDROID
396                    result = android_audioRecorder_checkSourceSinkSupport(thiz);
397                    if (SL_RESULT_SUCCESS != result) {
398                        SL_LOGE("Cannot create AudioRecorder: invalid source or sink");
399                        break;
400                    }
401#endif
402
403#ifdef ANDROID
404                    // Allocate memory for buffer queue
405                    SLuint32 locatorType = thiz->mDataSink.mLocator.mLocatorType;
406                    if (locatorType == SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE) {
407                        thiz->mBufferQueue.mNumBuffers =
408                            thiz->mDataSink.mLocator.mBufferQueue.numBuffers;
409                        // inline allocation of circular Buffer Queue mArray, up to a typical max
410                        if (BUFFER_HEADER_TYPICAL >= thiz->mBufferQueue.mNumBuffers) {
411                            thiz->mBufferQueue.mArray = thiz->mBufferQueue.mTypical;
412                        } else {
413                            // Avoid possible integer overflow during multiplication; this arbitrary
414                            // maximum is big enough to not interfere with real applications, but
415                            // small enough to not overflow.
416                            if (thiz->mBufferQueue.mNumBuffers >= 256) {
417                                result = SL_RESULT_MEMORY_FAILURE;
418                                break;
419                            }
420                            thiz->mBufferQueue.mArray = (BufferHeader *) malloc((thiz->mBufferQueue.
421                                    mNumBuffers + 1) * sizeof(BufferHeader));
422                            if (NULL == thiz->mBufferQueue.mArray) {
423                                result = SL_RESULT_MEMORY_FAILURE;
424                                break;
425                            }
426                        }
427                        thiz->mBufferQueue.mFront = thiz->mBufferQueue.mArray;
428                        thiz->mBufferQueue.mRear = thiz->mBufferQueue.mArray;
429                    }
430#endif
431
432                    // platform-specific initialization
433#ifdef ANDROID
434                    android_audioRecorder_create(thiz);
435#endif
436
437                } while (0);
438
439                if (SL_RESULT_SUCCESS != result) {
440                    IObject_Destroy(&thiz->mObject.mItf);
441                } else {
442                    IObject_Publish(&thiz->mObject);
443                    // return the new audio recorder object
444                    *pRecorder = &thiz->mObject.mItf;
445                }
446            }
447
448        }
449
450    }
451#else
452    result = SL_RESULT_FEATURE_UNSUPPORTED;
453#endif
454
455    SL_LEAVE_INTERFACE
456}
457
458
459static SLresult IEngine_CreateMidiPlayer(SLEngineItf self, SLObjectItf *pPlayer,
460    SLDataSource *pMIDISrc, SLDataSource *pBankSrc, SLDataSink *pAudioOutput,
461    SLDataSink *pVibra, SLDataSink *pLEDArray, SLuint32 numInterfaces,
462    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
463{
464    SL_ENTER_INTERFACE
465
466#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_PHONE)
467    if ((NULL == pPlayer) || (NULL == pMIDISrc) || (NULL == pAudioOutput)) {
468        result = SL_RESULT_PARAMETER_INVALID;
469    } else {
470        *pPlayer = NULL;
471        unsigned exposedMask;
472        const ClassTable *pCMidiPlayer_class = objectIDtoClass(SL_OBJECTID_MIDIPLAYER);
473        if (NULL == pCMidiPlayer_class) {
474            result = SL_RESULT_FEATURE_UNSUPPORTED;
475        } else {
476            result = checkInterfaces(pCMidiPlayer_class, numInterfaces,
477                pInterfaceIds, pInterfaceRequired, &exposedMask);
478        }
479        if (SL_RESULT_SUCCESS == result) {
480            CMidiPlayer *thiz = (CMidiPlayer *) construct(pCMidiPlayer_class, exposedMask, self);
481            if (NULL == thiz) {
482                result = SL_RESULT_MEMORY_FAILURE;
483            } else {
484#if 0
485                "pMIDISrc", pMIDISrc, URI | MIDIBUFFERQUEUE, NONE
486                "pBankSrc", pBanksrc, NULL | URI | ADDRESS, NULL
487                "pAudioOutput", pAudioOutput, OUTPUTMIX, NULL
488                "pVibra", pVibra, NULL | IODEVICE, NULL
489                "pLEDArray", pLEDArray, NULL | IODEVICE, NULL
490#endif
491                // a fake value - why not use value from IPlay_init? what does CT check for?
492                thiz->mPlay.mDuration = 0;
493                IObject_Publish(&thiz->mObject);
494                // return the new MIDI player object
495                *pPlayer = &thiz->mObject.mItf;
496            }
497        }
498    }
499#else
500    result = SL_RESULT_FEATURE_UNSUPPORTED;
501#endif
502
503    SL_LEAVE_INTERFACE
504}
505
506
507static SLresult IEngine_CreateListener(SLEngineItf self, SLObjectItf *pListener,
508    SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
509{
510    SL_ENTER_INTERFACE
511
512#if USE_PROFILES & USE_PROFILES_GAME
513    if (NULL == pListener) {
514        result = SL_RESULT_PARAMETER_INVALID;
515    } else {
516        *pListener = NULL;
517        unsigned exposedMask;
518        const ClassTable *pCListener_class = objectIDtoClass(SL_OBJECTID_LISTENER);
519        if (NULL == pCListener_class) {
520            result = SL_RESULT_FEATURE_UNSUPPORTED;
521        } else {
522            result = checkInterfaces(pCListener_class, numInterfaces,
523                pInterfaceIds, pInterfaceRequired, &exposedMask);
524        }
525        if (SL_RESULT_SUCCESS == result) {
526            CListener *thiz = (CListener *) construct(pCListener_class, exposedMask, self);
527            if (NULL == thiz) {
528                result = SL_RESULT_MEMORY_FAILURE;
529            } else {
530                IObject_Publish(&thiz->mObject);
531                // return the new 3D listener object
532                *pListener = &thiz->mObject.mItf;
533            }
534        }
535    }
536#else
537    result = SL_RESULT_FEATURE_UNSUPPORTED;
538#endif
539
540    SL_LEAVE_INTERFACE
541}
542
543
544static SLresult IEngine_Create3DGroup(SLEngineItf self, SLObjectItf *pGroup, SLuint32 numInterfaces,
545    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
546{
547    SL_ENTER_INTERFACE
548
549#if USE_PROFILES & USE_PROFILES_GAME
550    if (NULL == pGroup) {
551        result = SL_RESULT_PARAMETER_INVALID;
552    } else {
553        *pGroup = NULL;
554        unsigned exposedMask;
555        const ClassTable *pC3DGroup_class = objectIDtoClass(SL_OBJECTID_3DGROUP);
556        if (NULL == pC3DGroup_class) {
557            result = SL_RESULT_FEATURE_UNSUPPORTED;
558        } else {
559            result = checkInterfaces(pC3DGroup_class, numInterfaces,
560                pInterfaceIds, pInterfaceRequired, &exposedMask);
561        }
562        if (SL_RESULT_SUCCESS == result) {
563            C3DGroup *thiz = (C3DGroup *) construct(pC3DGroup_class, exposedMask, self);
564            if (NULL == thiz) {
565                result = SL_RESULT_MEMORY_FAILURE;
566            } else {
567                thiz->mMemberMask = 0;
568                IObject_Publish(&thiz->mObject);
569                // return the new 3D group object
570                *pGroup = &thiz->mObject.mItf;
571            }
572        }
573    }
574#else
575    result = SL_RESULT_FEATURE_UNSUPPORTED;
576#endif
577
578    SL_LEAVE_INTERFACE
579}
580
581
582static SLresult IEngine_CreateOutputMix(SLEngineItf self, SLObjectItf *pMix, SLuint32 numInterfaces,
583    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
584{
585    SL_ENTER_INTERFACE
586
587    if (NULL == pMix) {
588        result = SL_RESULT_PARAMETER_INVALID;
589    } else {
590        *pMix = NULL;
591        unsigned exposedMask;
592        const ClassTable *pCOutputMix_class = objectIDtoClass(SL_OBJECTID_OUTPUTMIX);
593        assert(NULL != pCOutputMix_class);
594        result = checkInterfaces(pCOutputMix_class, numInterfaces,
595            pInterfaceIds, pInterfaceRequired, &exposedMask);
596        if (SL_RESULT_SUCCESS == result) {
597            COutputMix *thiz = (COutputMix *) construct(pCOutputMix_class, exposedMask, self);
598            if (NULL == thiz) {
599                result = SL_RESULT_MEMORY_FAILURE;
600            } else {
601#ifdef ANDROID
602                android_outputMix_create(thiz);
603#endif
604#ifdef USE_SDL
605                IEngine *thisEngine = &thiz->mObject.mEngine->mEngine;
606                interface_lock_exclusive(thisEngine);
607                bool unpause = false;
608                if (NULL == thisEngine->mOutputMix) {
609                    thisEngine->mOutputMix = thiz;
610                    unpause = true;
611                }
612                interface_unlock_exclusive(thisEngine);
613#endif
614                IObject_Publish(&thiz->mObject);
615#ifdef USE_SDL
616                if (unpause) {
617                    // Enable SDL_callback to be called periodically by SDL's internal thread
618                    SDL_PauseAudio(0);
619                }
620#endif
621                // return the new output mix object
622                *pMix = &thiz->mObject.mItf;
623            }
624        }
625    }
626
627    SL_LEAVE_INTERFACE
628}
629
630
631static SLresult IEngine_CreateMetadataExtractor(SLEngineItf self, SLObjectItf *pMetadataExtractor,
632    SLDataSource *pDataSource, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds,
633    const SLboolean *pInterfaceRequired)
634{
635    SL_ENTER_INTERFACE
636
637#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_MUSIC)
638    if (NULL == pMetadataExtractor) {
639        result = SL_RESULT_PARAMETER_INVALID;
640    } else {
641        *pMetadataExtractor = NULL;
642        unsigned exposedMask;
643        const ClassTable *pCMetadataExtractor_class =
644            objectIDtoClass(SL_OBJECTID_METADATAEXTRACTOR);
645        if (NULL == pCMetadataExtractor_class) {
646            result = SL_RESULT_FEATURE_UNSUPPORTED;
647        } else {
648            result = checkInterfaces(pCMetadataExtractor_class, numInterfaces,
649                pInterfaceIds, pInterfaceRequired, &exposedMask);
650        }
651        if (SL_RESULT_SUCCESS == result) {
652            CMetadataExtractor *thiz = (CMetadataExtractor *)
653                construct(pCMetadataExtractor_class, exposedMask, self);
654            if (NULL == thiz) {
655                result = SL_RESULT_MEMORY_FAILURE;
656            } else {
657#if 0
658                "pDataSource", pDataSource, NONE, NONE
659#endif
660                IObject_Publish(&thiz->mObject);
661                // return the new metadata extractor object
662                *pMetadataExtractor = &thiz->mObject.mItf;
663                result = SL_RESULT_SUCCESS;
664            }
665        }
666    }
667#else
668    result = SL_RESULT_FEATURE_UNSUPPORTED;
669#endif
670
671    SL_LEAVE_INTERFACE
672}
673
674
675static SLresult IEngine_CreateExtensionObject(SLEngineItf self, SLObjectItf *pObject,
676    void *pParameters, SLuint32 objectID, SLuint32 numInterfaces,
677    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
678{
679    SL_ENTER_INTERFACE
680
681    if (NULL == pObject) {
682        result = SL_RESULT_PARAMETER_INVALID;
683    } else {
684        *pObject = NULL;
685        result = SL_RESULT_FEATURE_UNSUPPORTED;
686    }
687
688    SL_LEAVE_INTERFACE
689}
690
691
692static SLresult IEngine_QueryNumSupportedInterfaces(SLEngineItf self,
693    SLuint32 objectID, SLuint32 *pNumSupportedInterfaces)
694{
695    SL_ENTER_INTERFACE
696
697    if (NULL == pNumSupportedInterfaces) {
698        result = SL_RESULT_PARAMETER_INVALID;
699    } else {
700        const ClassTable *clazz = objectIDtoClass(objectID);
701        if (NULL == clazz) {
702            result = SL_RESULT_FEATURE_UNSUPPORTED;
703        } else {
704            SLuint32 count = 0;
705            SLuint32 i;
706            for (i = 0; i < clazz->mInterfaceCount; ++i) {
707                switch (clazz->mInterfaces[i].mInterface) {
708                case INTERFACE_IMPLICIT:
709                case INTERFACE_IMPLICIT_PREREALIZE:
710                case INTERFACE_EXPLICIT:
711                case INTERFACE_EXPLICIT_PREREALIZE:
712                case INTERFACE_DYNAMIC:
713                    ++count;
714                    break;
715                case INTERFACE_UNAVAILABLE:
716                    break;
717                default:
718                    assert(false);
719                    break;
720                }
721            }
722            *pNumSupportedInterfaces = count;
723            result = SL_RESULT_SUCCESS;
724        }
725    }
726
727    SL_LEAVE_INTERFACE;
728}
729
730
731static SLresult IEngine_QuerySupportedInterfaces(SLEngineItf self,
732    SLuint32 objectID, SLuint32 index, SLInterfaceID *pInterfaceId)
733{
734    SL_ENTER_INTERFACE
735
736    if (NULL == pInterfaceId) {
737        result = SL_RESULT_PARAMETER_INVALID;
738    } else {
739        *pInterfaceId = NULL;
740        const ClassTable *clazz = objectIDtoClass(objectID);
741        if (NULL == clazz) {
742            result = SL_RESULT_FEATURE_UNSUPPORTED;
743        } else {
744            result = SL_RESULT_PARAMETER_INVALID; // will be reset later
745            SLuint32 i;
746            for (i = 0; i < clazz->mInterfaceCount; ++i) {
747                switch (clazz->mInterfaces[i].mInterface) {
748                case INTERFACE_IMPLICIT:
749                case INTERFACE_IMPLICIT_PREREALIZE:
750                case INTERFACE_EXPLICIT:
751                case INTERFACE_EXPLICIT_PREREALIZE:
752                case INTERFACE_DYNAMIC:
753                    break;
754                case INTERFACE_UNAVAILABLE:
755                    continue;
756                default:
757                    assert(false);
758                    break;
759                }
760                if (index == 0) {
761                    *pInterfaceId = &SL_IID_array[clazz->mInterfaces[i].mMPH];
762                    result = SL_RESULT_SUCCESS;
763                    break;
764                }
765                --index;
766            }
767        }
768    }
769
770    SL_LEAVE_INTERFACE
771};
772
773
774static const char * const extensionNames[] = {
775#ifdef ANDROID
776    "ANDROID_SDK_LEVEL_12", // Android 3.0+ aka "Honeycomb MR1"
777#else
778    "WILHELM_DESKTOP",
779#endif
780};
781
782
783static SLresult IEngine_QueryNumSupportedExtensions(SLEngineItf self, SLuint32 *pNumExtensions)
784{
785    SL_ENTER_INTERFACE
786
787    if (NULL == pNumExtensions) {
788        result = SL_RESULT_PARAMETER_INVALID;
789    } else {
790        *pNumExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]);
791        result = SL_RESULT_SUCCESS;
792    }
793
794    SL_LEAVE_INTERFACE
795}
796
797
798static SLresult IEngine_QuerySupportedExtension(SLEngineItf self,
799    SLuint32 index, SLchar *pExtensionName, SLint16 *pNameLength)
800{
801    SL_ENTER_INTERFACE
802
803    if (NULL == pNameLength) {
804        result = SL_RESULT_PARAMETER_INVALID;
805    } else {
806        size_t actualNameLength;
807        unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]);
808        if (index >= numExtensions) {
809            actualNameLength = 0;
810            result = SL_RESULT_PARAMETER_INVALID;
811        } else {
812            const char *extensionName = extensionNames[index];
813            actualNameLength = strlen(extensionName) + 1;
814            if (NULL == pExtensionName) {
815                // application is querying the name length in order to allocate a buffer
816                result = SL_RESULT_SUCCESS;
817            } else {
818                SLint16 availableNameLength = *pNameLength;
819                if (0 >= availableNameLength) {
820                    // there is not even room for the terminating NUL
821                    result = SL_RESULT_BUFFER_INSUFFICIENT;
822                } else if (actualNameLength > (size_t) availableNameLength) {
823                    // "no invalid strings are written. That is, the null-terminator always exists"
824                    memcpy(pExtensionName, extensionName, (size_t) availableNameLength - 1);
825                    pExtensionName[(size_t) availableNameLength - 1] = '\0';
826                    result = SL_RESULT_BUFFER_INSUFFICIENT;
827                } else {
828                    memcpy(pExtensionName, extensionName, actualNameLength);
829                    result = SL_RESULT_SUCCESS;
830                }
831            }
832        }
833        *pNameLength = actualNameLength;
834    }
835
836    SL_LEAVE_INTERFACE
837}
838
839
840static SLresult IEngine_IsExtensionSupported(SLEngineItf self,
841    const SLchar *pExtensionName, SLboolean *pSupported)
842{
843    SL_ENTER_INTERFACE
844
845    if (NULL == pSupported) {
846        result = SL_RESULT_PARAMETER_INVALID;
847    } else {
848        SLboolean isSupported = SL_BOOLEAN_FALSE;
849        if (NULL == pExtensionName) {
850            result = SL_RESULT_PARAMETER_INVALID;
851        } else {
852            unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]);
853            unsigned i;
854            for (i = 0; i < numExtensions; ++i) {
855                if (!strcmp((const char *) pExtensionName, extensionNames[i])) {
856                    isSupported = SL_BOOLEAN_TRUE;
857                    break;
858                }
859            }
860            result = SL_RESULT_SUCCESS;
861        }
862        *pSupported = isSupported;
863    }
864
865    SL_LEAVE_INTERFACE
866}
867
868
869static const struct SLEngineItf_ IEngine_Itf = {
870    IEngine_CreateLEDDevice,
871    IEngine_CreateVibraDevice,
872    IEngine_CreateAudioPlayer,
873    IEngine_CreateAudioRecorder,
874    IEngine_CreateMidiPlayer,
875    IEngine_CreateListener,
876    IEngine_Create3DGroup,
877    IEngine_CreateOutputMix,
878    IEngine_CreateMetadataExtractor,
879    IEngine_CreateExtensionObject,
880    IEngine_QueryNumSupportedInterfaces,
881    IEngine_QuerySupportedInterfaces,
882    IEngine_QueryNumSupportedExtensions,
883    IEngine_QuerySupportedExtension,
884    IEngine_IsExtensionSupported
885};
886
887void IEngine_init(void *self)
888{
889    IEngine *thiz = (IEngine *) self;
890    thiz->mItf = &IEngine_Itf;
891    // mLossOfControlGlobal is initialized in slCreateEngine
892#ifdef USE_SDL
893    thiz->mOutputMix = NULL;
894#endif
895    thiz->mInstanceCount = 1; // ourself
896    thiz->mInstanceMask = 0;
897    thiz->mChangedMask = 0;
898    unsigned i;
899    for (i = 0; i < MAX_INSTANCE; ++i) {
900        thiz->mInstances[i] = NULL;
901    }
902    thiz->mShutdown = SL_BOOLEAN_FALSE;
903    thiz->mShutdownAck = SL_BOOLEAN_FALSE;
904}
905
906void IEngine_deinit(void *self)
907{
908}
909
910
911// OpenMAX AL Engine
912
913
914static XAresult IEngine_CreateCameraDevice(XAEngineItf self, XAObjectItf *pDevice,
915        XAuint32 deviceID, XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
916        const XAboolean *pInterfaceRequired)
917{
918    XA_ENTER_INTERFACE
919
920    //IXAEngine *thiz = (IXAEngine *) self;
921    result = SL_RESULT_FEATURE_UNSUPPORTED;
922
923    XA_LEAVE_INTERFACE
924}
925
926
927static XAresult IEngine_CreateRadioDevice(XAEngineItf self, XAObjectItf *pDevice,
928        XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
929        const XAboolean *pInterfaceRequired)
930{
931    XA_ENTER_INTERFACE
932
933    //IXAEngine *thiz = (IXAEngine *) self;
934    result = SL_RESULT_FEATURE_UNSUPPORTED;
935
936    XA_LEAVE_INTERFACE
937}
938
939
940static XAresult IXAEngine_CreateLEDDevice(XAEngineItf self, XAObjectItf *pDevice, XAuint32 deviceID,
941        XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
942        const XAboolean *pInterfaceRequired)
943{
944    // forward to OpenSL ES
945    return IEngine_CreateLEDDevice(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
946            (SLObjectItf *) pDevice, deviceID, numInterfaces, (const SLInterfaceID *) pInterfaceIds,
947            (const SLboolean *) pInterfaceRequired);
948}
949
950
951static XAresult IXAEngine_CreateVibraDevice(XAEngineItf self, XAObjectItf *pDevice,
952        XAuint32 deviceID, XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
953        const XAboolean *pInterfaceRequired)
954{
955    // forward to OpenSL ES
956    return IEngine_CreateVibraDevice(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
957            (SLObjectItf *) pDevice, deviceID, numInterfaces, (const SLInterfaceID *) pInterfaceIds,
958            (const SLboolean *) pInterfaceRequired);
959}
960
961
962static XAresult IEngine_CreateMediaPlayer(XAEngineItf self, XAObjectItf *pPlayer,
963        XADataSource *pDataSrc, XADataSource *pBankSrc, XADataSink *pAudioSnk,
964        XADataSink *pImageVideoSnk, XADataSink *pVibra, XADataSink *pLEDArray,
965        XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
966        const XAboolean *pInterfaceRequired)
967{
968    XA_ENTER_INTERFACE
969
970    if (NULL == pPlayer) {
971        result = XA_RESULT_PARAMETER_INVALID;
972    } else {
973        *pPlayer = NULL;
974        unsigned exposedMask;
975        const ClassTable *pCMediaPlayer_class = objectIDtoClass(XA_OBJECTID_MEDIAPLAYER);
976        assert(NULL != pCMediaPlayer_class);
977        result = checkInterfaces(pCMediaPlayer_class, numInterfaces,
978                (const SLInterfaceID *) pInterfaceIds, pInterfaceRequired, &exposedMask);
979        if (XA_RESULT_SUCCESS == result) {
980
981            // Construct our new MediaPlayer instance
982            CMediaPlayer *thiz = (CMediaPlayer *) construct(pCMediaPlayer_class, exposedMask,
983                    &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf);
984            if (NULL == thiz) {
985                result = XA_RESULT_MEMORY_FAILURE;
986            } else {
987
988                do {
989
990                    // Initialize private fields not associated with an interface
991
992                    // (assume calloc or memset 0 during allocation)
993                    // placement new
994#ifdef ANDROID
995                    // FIXME unnecessary once those fields are encapsulated in one class, rather
996                    //   than a structure
997                    (void) new (&thiz->mAVPlayer) android::sp<android::GenericPlayer>();
998#endif
999
1000                    // Check the source and sink parameters against generic constraints
1001
1002                    result = checkDataSource("pDataSrc", (const SLDataSource *) pDataSrc,
1003                            &thiz->mDataSource, DATALOCATOR_MASK_URI
1004#ifdef ANDROID
1005                            | DATALOCATOR_MASK_ANDROIDFD
1006                            | DATALOCATOR_MASK_ANDROIDBUFFERQUEUE
1007#endif
1008                            , DATAFORMAT_MASK_MIME);
1009                    if (XA_RESULT_SUCCESS != result) {
1010                        break;
1011                    }
1012
1013                    result = checkDataSource("pBankSrc", (const SLDataSource *) pBankSrc,
1014                            &thiz->mBankSource, DATALOCATOR_MASK_NULL | DATALOCATOR_MASK_URI |
1015                            DATALOCATOR_MASK_ADDRESS, DATAFORMAT_MASK_NULL);
1016                    if (XA_RESULT_SUCCESS != result) {
1017                        break;
1018                    }
1019
1020                    result = checkDataSink("pAudioSnk", (const SLDataSink *) pAudioSnk,
1021                            &thiz->mAudioSink, DATALOCATOR_MASK_OUTPUTMIX, DATAFORMAT_MASK_NULL);
1022                    if (XA_RESULT_SUCCESS != result) {
1023                        break;
1024                    }
1025
1026                    result = checkDataSink("pImageVideoSnk", (const SLDataSink *) pImageVideoSnk,
1027                            &thiz->mImageVideoSink, DATALOCATOR_MASK_NATIVEDISPLAY,
1028                            DATAFORMAT_MASK_NULL);
1029                    if (XA_RESULT_SUCCESS != result) {
1030                        break;
1031                    }
1032
1033                    result = checkDataSink("pVibra", (const SLDataSink *) pVibra, &thiz->mVibraSink,
1034                            DATALOCATOR_MASK_NULL | DATALOCATOR_MASK_IODEVICE,
1035                            DATAFORMAT_MASK_NULL);
1036                    if (XA_RESULT_SUCCESS != result) {
1037                        break;
1038                    }
1039
1040                    result = checkDataSink("pLEDArray", (const SLDataSink *) pLEDArray,
1041                            &thiz->mLEDArraySink, DATALOCATOR_MASK_NULL | DATALOCATOR_MASK_IODEVICE,
1042                            DATAFORMAT_MASK_NULL);
1043                    if (XA_RESULT_SUCCESS != result) {
1044                        break;
1045                    }
1046
1047                    // Unsafe to ever refer to application pointers again
1048                    pDataSrc = NULL;
1049                    pBankSrc = NULL;
1050                    pAudioSnk = NULL;
1051                    pImageVideoSnk = NULL;
1052                    pVibra = NULL;
1053                    pLEDArray = NULL;
1054
1055                    // Check that the requested interfaces are compatible with the data source
1056                    // ...
1057
1058                    // check the source and sink parameters against platform support
1059#ifdef ANDROID
1060                    // result = android_mediaPlayer_checkSourceSink(thiz);
1061                    if (XA_RESULT_SUCCESS != result) {
1062                        break;
1063                    }
1064#endif
1065
1066                    // platform-specific initialization
1067#ifdef ANDROID
1068                    android_Player_create(thiz);
1069#endif
1070
1071                } while (0);
1072
1073                if (XA_RESULT_SUCCESS != result) {
1074                    IObject_Destroy(&thiz->mObject.mItf);
1075                } else {
1076                    IObject_Publish(&thiz->mObject);
1077                    // return the new media player object
1078                    *pPlayer = (XAObjectItf) &thiz->mObject.mItf;
1079                }
1080
1081            }
1082        }
1083
1084    }
1085
1086    XA_LEAVE_INTERFACE
1087}
1088
1089
1090static XAresult IEngine_CreateMediaRecorder(XAEngineItf self, XAObjectItf *pRecorder,
1091        XADataSource *pAudioSrc, XADataSource *pImageVideoSrc,
1092        XADataSink *pDataSnk, XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
1093        const XAboolean *pInterfaceRequired)
1094{
1095    XA_ENTER_INTERFACE
1096
1097    //IXAEngine *thiz = (IXAEngine *) self;
1098    result = SL_RESULT_FEATURE_UNSUPPORTED;
1099
1100#if 0
1101    "pAudioSrc", pAudioSrc,
1102    "pImageVideoSrc", pImageVideoSrc,
1103    "pDataSink", pDataSnk,
1104#endif
1105
1106    XA_LEAVE_INTERFACE
1107}
1108
1109
1110static XAresult IXAEngine_CreateOutputMix(XAEngineItf self, XAObjectItf *pMix,
1111        XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds,
1112        const XAboolean *pInterfaceRequired)
1113{
1114    // forward to OpenSL ES
1115    return IEngine_CreateOutputMix(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
1116            (SLObjectItf *) pMix, numInterfaces, (const SLInterfaceID *) pInterfaceIds,
1117            (const SLboolean *) pInterfaceRequired);
1118}
1119
1120
1121static XAresult IXAEngine_CreateMetadataExtractor(XAEngineItf self, XAObjectItf *pMetadataExtractor,
1122            XADataSource *pDataSource, XAuint32 numInterfaces,
1123            const XAInterfaceID *pInterfaceIds, const XAboolean *pInterfaceRequired)
1124{
1125    // forward to OpenSL ES
1126    return IEngine_CreateMetadataExtractor(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
1127            (SLObjectItf *) pMetadataExtractor, (SLDataSource *) pDataSource, numInterfaces,
1128            (const SLInterfaceID *) pInterfaceIds, (const SLboolean *) pInterfaceRequired);
1129}
1130
1131
1132static XAresult IXAEngine_CreateExtensionObject(XAEngineItf self, XAObjectItf *pObject,
1133            void *pParameters, XAuint32 objectID, XAuint32 numInterfaces,
1134            const XAInterfaceID *pInterfaceIds, const XAboolean *pInterfaceRequired)
1135{
1136    // forward to OpenSL ES
1137    return IEngine_CreateExtensionObject(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
1138            (SLObjectItf *) pObject, pParameters, objectID, numInterfaces,
1139            (const SLInterfaceID *) pInterfaceIds, (const SLboolean *) pInterfaceRequired);
1140}
1141
1142
1143static XAresult IEngine_GetImplementationInfo(XAEngineItf self, XAuint32 *pMajor, XAuint32 *pMinor,
1144        XAuint32 *pStep, /* XAuint32 nImplementationTextSize, */ const XAchar *pImplementationText)
1145{
1146    XA_ENTER_INTERFACE
1147
1148    //IXAEngine *thiz = (IXAEngine *) self;
1149    result = SL_RESULT_FEATURE_UNSUPPORTED;
1150
1151    XA_LEAVE_INTERFACE
1152}
1153
1154
1155static XAresult IXAEngine_QuerySupportedProfiles(XAEngineItf self, XAint16 *pProfilesSupported)
1156{
1157    XA_ENTER_INTERFACE
1158
1159    if (NULL == pProfilesSupported) {
1160        result = XA_RESULT_PARAMETER_INVALID;
1161    } else {
1162#if 1
1163        *pProfilesSupported = 0;
1164        // the code below was copied from OpenSL ES and needs to be adapted for OpenMAX AL.
1165#else
1166        // The generic implementation doesn't implement any of the profiles, they shouldn't be
1167        // declared as supported. Also exclude the fake profiles BASE and OPTIONAL.
1168        *pProfilesSupported = USE_PROFILES &
1169                (USE_PROFILES_GAME | USE_PROFILES_MUSIC | USE_PROFILES_PHONE);
1170#endif
1171        result = XA_RESULT_SUCCESS;
1172    }
1173
1174    XA_LEAVE_INTERFACE
1175}
1176
1177
1178static XAresult IXAEngine_QueryNumSupportedInterfaces(XAEngineItf self, XAuint32 objectID,
1179        XAuint32 *pNumSupportedInterfaces)
1180{
1181    // forward to OpenSL ES
1182    return IEngine_QueryNumSupportedInterfaces(
1183            &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, objectID,
1184            pNumSupportedInterfaces);
1185}
1186
1187
1188static XAresult IXAEngine_QuerySupportedInterfaces(XAEngineItf self, XAuint32 objectID,
1189        XAuint32 index, XAInterfaceID *pInterfaceId)
1190{
1191    // forward to OpenSL ES
1192    return IEngine_QuerySupportedInterfaces(
1193            &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, objectID, index,
1194            (SLInterfaceID *) pInterfaceId);
1195}
1196
1197
1198static XAresult IXAEngine_QueryNumSupportedExtensions(XAEngineItf self, XAuint32 *pNumExtensions)
1199{
1200    // forward to OpenSL ES
1201    return IEngine_QueryNumSupportedExtensions(
1202            &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, pNumExtensions);
1203}
1204
1205
1206static XAresult IXAEngine_QuerySupportedExtension(XAEngineItf self, XAuint32 index,
1207        XAchar *pExtensionName, XAint16 *pNameLength)
1208{
1209    // forward to OpenSL ES
1210    return IEngine_QuerySupportedExtension(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
1211            index, pExtensionName, (SLint16 *) pNameLength);
1212}
1213
1214
1215static XAresult IXAEngine_IsExtensionSupported(XAEngineItf self, const XAchar *pExtensionName,
1216        XAboolean *pSupported)
1217{
1218    // forward to OpenSL ES
1219    return IEngine_IsExtensionSupported(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf,
1220            pExtensionName, pSupported);
1221}
1222
1223
1224static XAresult IXAEngine_QueryLEDCapabilities(XAEngineItf self, XAuint32 *pIndex,
1225        XAuint32 *pLEDDeviceID, XALEDDescriptor *pDescriptor)
1226{
1227    // forward to OpenSL ES EngineCapabilities
1228    return (XAresult) IEngineCapabilities_QueryLEDCapabilities(
1229            &((CEngine *) ((IXAEngine *) self)->mThis)->mEngineCapabilities.mItf, pIndex,
1230            pLEDDeviceID, (SLLEDDescriptor *) pDescriptor);
1231}
1232
1233
1234static XAresult IXAEngine_QueryVibraCapabilities(XAEngineItf self, XAuint32 *pIndex,
1235        XAuint32 *pVibraDeviceID, XAVibraDescriptor *pDescriptor)
1236{
1237    // forward to OpenSL ES EngineCapabilities
1238    return (XAresult) IEngineCapabilities_QueryVibraCapabilities(
1239            &((CEngine *) ((IXAEngine *) self)->mThis)->mEngineCapabilities.mItf, pIndex,
1240            pVibraDeviceID, (SLVibraDescriptor *) pDescriptor);
1241}
1242
1243
1244// OpenMAX AL engine v-table
1245
1246static const struct XAEngineItf_ IXAEngine_Itf = {
1247    IEngine_CreateCameraDevice,
1248    IEngine_CreateRadioDevice,
1249    IXAEngine_CreateLEDDevice,
1250    IXAEngine_CreateVibraDevice,
1251    IEngine_CreateMediaPlayer,
1252    IEngine_CreateMediaRecorder,
1253    IXAEngine_CreateOutputMix,
1254    IXAEngine_CreateMetadataExtractor,
1255    IXAEngine_CreateExtensionObject,
1256    IEngine_GetImplementationInfo,
1257    IXAEngine_QuerySupportedProfiles,
1258    IXAEngine_QueryNumSupportedInterfaces,
1259    IXAEngine_QuerySupportedInterfaces,
1260    IXAEngine_QueryNumSupportedExtensions,
1261    IXAEngine_QuerySupportedExtension,
1262    IXAEngine_IsExtensionSupported,
1263    IXAEngine_QueryLEDCapabilities,
1264    IXAEngine_QueryVibraCapabilities
1265};
1266
1267
1268void IXAEngine_init(void *self)
1269{
1270    IXAEngine *thiz = (IXAEngine *) self;
1271    thiz->mItf = &IXAEngine_Itf;
1272}
1273