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