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