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, &this->mDataSource);
173                    if (SL_RESULT_SUCCESS != result) {
174                        break;
175                    }
176
177                    result = checkDataSink(pAudioSnk, &this->mDataSink, SL_OBJECTID_AUDIOPLAYER);
178                    if (SL_RESULT_SUCCESS != result) {
179                        break;
180                    }
181
182                    // It would be unsafe to ever refer to the application pointers again
183                    pAudioSrc = NULL;
184                    pAudioSnk = NULL;
185
186                    // Check that the requested interfaces are compatible with the data source
187                    result = checkSourceFormatVsInterfacesCompatibility(&this->mDataSource,
188                            pCAudioPlayer_class, exposedMask);
189                    if (SL_RESULT_SUCCESS != result) {
190                        break;
191                    }
192
193                    // copy the buffer queue count from source locator to the buffer queue interface
194                    // we have already range-checked the value down to a smaller width
195
196                    switch (this->mDataSource.mLocator.mLocatorType) {
197                    case SL_DATALOCATOR_BUFFERQUEUE:
198#ifdef ANDROID
199                    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
200#endif
201                        this->mBufferQueue.mNumBuffers =
202                                (SLuint16) this->mDataSource.mLocator.mBufferQueue.numBuffers;
203                        assert(SL_DATAFORMAT_PCM == this->mDataSource.mFormat.mFormatType);
204                        this->mNumChannels = this->mDataSource.mFormat.mPCM.numChannels;
205                        this->mSampleRateMilliHz = this->mDataSource.mFormat.mPCM.samplesPerSec;
206                        break;
207                    default:
208                        this->mBufferQueue.mNumBuffers = 0;
209                        break;
210                    }
211
212                    // check the audio source and sink parameters against platform support
213#ifdef ANDROID
214                    result = android_audioPlayer_checkSourceSink(this);
215                    if (SL_RESULT_SUCCESS != result) {
216                        break;
217                    }
218#endif
219
220#ifdef USE_SNDFILE
221                    result = SndFile_checkAudioPlayerSourceSink(this);
222                    if (SL_RESULT_SUCCESS != result) {
223                        break;
224                    }
225#endif
226
227#ifdef USE_OUTPUTMIXEXT
228                    result = IOutputMixExt_checkAudioPlayerSourceSink(this);
229                    if (SL_RESULT_SUCCESS != result) {
230                        break;
231                    }
232#endif
233
234                    // FIXME move to dedicated function
235                    // Allocate memory for buffer queue
236
237                    //if (0 != this->mBufferQueue.mNumBuffers) {
238                        // inline allocation of circular mArray, up to a typical max
239                        if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) {
240                            this->mBufferQueue.mArray = this->mBufferQueue.mTypical;
241                        } else {
242                            // Avoid possible integer overflow during multiplication; this arbitrary
243                            // maximum is big enough to not interfere with real applications, but
244                            // small enough to not overflow.
245                            if (this->mBufferQueue.mNumBuffers >= 256) {
246                                result = SL_RESULT_MEMORY_FAILURE;
247                                break;
248                            }
249                            this->mBufferQueue.mArray = (BufferHeader *) malloc((this->mBufferQueue.
250                                mNumBuffers + 1) * sizeof(BufferHeader));
251                            if (NULL == this->mBufferQueue.mArray) {
252                                result = SL_RESULT_MEMORY_FAILURE;
253                                break;
254                            }
255                        }
256                        this->mBufferQueue.mFront = this->mBufferQueue.mArray;
257                        this->mBufferQueue.mRear = this->mBufferQueue.mArray;
258                        //}
259
260                        // used to store the data source of our audio player
261                        this->mDynamicSource.mDataSource = &this->mDataSource.u.mSource;
262
263                        // platform-specific initialization
264#ifdef ANDROID
265                        android_audioPlayer_create(this);
266#endif
267
268                } while (0);
269
270                if (SL_RESULT_SUCCESS != result) {
271                    IObject_Destroy(&this->mObject.mItf);
272                } else {
273                    IObject_Publish(&this->mObject);
274                    // return the new audio player object
275                    *pPlayer = &this->mObject.mItf;
276                }
277
278            }
279        }
280
281    }
282
283    SL_LEAVE_INTERFACE
284}
285
286
287static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pRecorder,
288    SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces,
289    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
290{
291    SL_ENTER_INTERFACE
292
293#if (USE_PROFILES & USE_PROFILES_OPTIONAL) || defined(ANDROID)
294    if (NULL == pRecorder) {
295        result = SL_RESULT_PARAMETER_INVALID;
296    } else {
297        *pRecorder = NULL;
298        unsigned exposedMask;
299        const ClassTable *pCAudioRecorder_class = objectIDtoClass(SL_OBJECTID_AUDIORECORDER);
300        if (NULL == pCAudioRecorder_class) {
301            result = SL_RESULT_FEATURE_UNSUPPORTED;
302        } else {
303            result = checkInterfaces(pCAudioRecorder_class, numInterfaces,
304                    pInterfaceIds, pInterfaceRequired, &exposedMask);
305        }
306
307        if (SL_RESULT_SUCCESS == result) {
308
309            // Construct our new AudioRecorder instance
310            CAudioRecorder *this = (CAudioRecorder *) construct(pCAudioRecorder_class, exposedMask,
311                    self);
312            if (NULL == this) {
313                result = SL_RESULT_MEMORY_FAILURE;
314            } else {
315
316                do {
317
318                    // Initialize fields not associated with any interface
319
320                    // Default data source in case of failure in checkDataSource
321                    this->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL;
322                    this->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL;
323
324                    // Default data sink in case of failure in checkDataSink
325                    this->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL;
326                    this->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL;
327
328                    // These fields are set to real values by
329                    // android_audioRecorder_checkSourceSinkSupport.  Note that the data sink is
330                    // always PCM buffer queue, so we know the channel count and sample rate early.
331                    this->mNumChannels = 0;
332                    this->mSampleRateMilliHz = 0;
333#ifdef ANDROID
334                    this->mAudioRecord = NULL;
335                    this->mRecordSource = android::AUDIO_SOURCE_DEFAULT;
336#endif
337
338                    // Check the source and sink parameters, and make a local copy of all parameters
339                    result = checkDataSource(pAudioSrc, &this->mDataSource);
340                    if (SL_RESULT_SUCCESS != result) {
341                        break;
342                    }
343                    result = checkDataSink(pAudioSnk, &this->mDataSink, SL_OBJECTID_AUDIORECORDER);
344                    if (SL_RESULT_SUCCESS != result) {
345                        break;
346                    }
347
348                    // It would be unsafe to ever refer to the application pointers again
349                    pAudioSrc = NULL;
350                    pAudioSnk = NULL;
351
352                    // check the audio source and sink parameters against platform support
353#ifdef ANDROID
354                    result = android_audioRecorder_checkSourceSinkSupport(this);
355                    if (SL_RESULT_SUCCESS != result) {
356                        SL_LOGE("Cannot create AudioRecorder: invalid source or sink");
357                        break;
358                    }
359#endif
360
361#ifdef ANDROID
362                    // Allocate memory for buffer queue
363                    SLuint32 locatorType = this->mDataSink.mLocator.mLocatorType;
364                    if (locatorType == SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE) {
365                        this->mBufferQueue.mNumBuffers =
366                            this->mDataSink.mLocator.mBufferQueue.numBuffers;
367                        // inline allocation of circular Buffer Queue mArray, up to a typical max
368                        if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) {
369                            this->mBufferQueue.mArray = this->mBufferQueue.mTypical;
370                        } else {
371                            // Avoid possible integer overflow during multiplication; this arbitrary
372                            // maximum is big enough to not interfere with real applications, but
373                            // small enough to not overflow.
374                            if (this->mBufferQueue.mNumBuffers >= 256) {
375                                result = SL_RESULT_MEMORY_FAILURE;
376                                break;
377                            }
378                            this->mBufferQueue.mArray = (BufferHeader *) malloc((this->mBufferQueue.
379                                    mNumBuffers + 1) * sizeof(BufferHeader));
380                            if (NULL == this->mBufferQueue.mArray) {
381                                result = SL_RESULT_MEMORY_FAILURE;
382                                break;
383                            }
384                        }
385                        this->mBufferQueue.mFront = this->mBufferQueue.mArray;
386                        this->mBufferQueue.mRear = this->mBufferQueue.mArray;
387                    }
388#endif
389
390                    // platform-specific initialization
391#ifdef ANDROID
392                    android_audioRecorder_create(this);
393#endif
394
395                } while (0);
396
397                if (SL_RESULT_SUCCESS != result) {
398                    IObject_Destroy(&this->mObject.mItf);
399                } else {
400                    IObject_Publish(&this->mObject);
401                    // return the new audio recorder object
402                    *pRecorder = &this->mObject.mItf;
403                }
404            }
405
406        }
407
408    }
409#else
410    result = SL_RESULT_FEATURE_UNSUPPORTED;
411#endif
412
413    SL_LEAVE_INTERFACE
414}
415
416
417static SLresult IEngine_CreateMidiPlayer(SLEngineItf self, SLObjectItf *pPlayer,
418    SLDataSource *pMIDISrc, SLDataSource *pBankSrc, SLDataSink *pAudioOutput,
419    SLDataSink *pVibra, SLDataSink *pLEDArray, SLuint32 numInterfaces,
420    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
421{
422    SL_ENTER_INTERFACE
423
424#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_PHONE)
425    if ((NULL == pPlayer) || (NULL == pMIDISrc) || (NULL == pAudioOutput)) {
426        result = SL_RESULT_PARAMETER_INVALID;
427    } else {
428        *pPlayer = NULL;
429        unsigned exposedMask;
430        const ClassTable *pCMidiPlayer_class = objectIDtoClass(SL_OBJECTID_MIDIPLAYER);
431        if (NULL == pCMidiPlayer_class) {
432            result = SL_RESULT_FEATURE_UNSUPPORTED;
433        } else {
434            result = checkInterfaces(pCMidiPlayer_class, numInterfaces,
435                pInterfaceIds, pInterfaceRequired, &exposedMask);
436        }
437        if (SL_RESULT_SUCCESS == result) {
438            CMidiPlayer *this = (CMidiPlayer *) construct(pCMidiPlayer_class, exposedMask, self);
439            if (NULL == this) {
440                result = SL_RESULT_MEMORY_FAILURE;
441            } else {
442                // FIXME a fake value - why not use value from IPlay_init? what does CT check for?
443                this->mPlay.mDuration = 0;
444                IObject_Publish(&this->mObject);
445                // return the new MIDI player object
446                *pPlayer = &this->mObject.mItf;
447            }
448        }
449    }
450#else
451    result = SL_RESULT_FEATURE_UNSUPPORTED;
452#endif
453
454    SL_LEAVE_INTERFACE
455}
456
457
458static SLresult IEngine_CreateListener(SLEngineItf self, SLObjectItf *pListener,
459    SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
460{
461    SL_ENTER_INTERFACE
462
463#if USE_PROFILES & USE_PROFILES_GAME
464    if (NULL == pListener) {
465        result = SL_RESULT_PARAMETER_INVALID;
466    } else {
467        *pListener = NULL;
468        unsigned exposedMask;
469        const ClassTable *pCListener_class = objectIDtoClass(SL_OBJECTID_LISTENER);
470        if (NULL == pCListener_class) {
471            result = SL_RESULT_FEATURE_UNSUPPORTED;
472        } else {
473            result = checkInterfaces(pCListener_class, numInterfaces,
474                pInterfaceIds, pInterfaceRequired, &exposedMask);
475        }
476        if (SL_RESULT_SUCCESS == result) {
477            CListener *this = (CListener *) construct(pCListener_class, exposedMask, self);
478            if (NULL == this) {
479                result = SL_RESULT_MEMORY_FAILURE;
480            } else {
481                IObject_Publish(&this->mObject);
482                // return the new 3D listener object
483                *pListener = &this->mObject.mItf;
484            }
485        }
486    }
487#else
488    result = SL_RESULT_FEATURE_UNSUPPORTED;
489#endif
490
491    SL_LEAVE_INTERFACE
492}
493
494
495static SLresult IEngine_Create3DGroup(SLEngineItf self, SLObjectItf *pGroup, SLuint32 numInterfaces,
496    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
497{
498    SL_ENTER_INTERFACE
499
500#if USE_PROFILES & USE_PROFILES_GAME
501    if (NULL == pGroup) {
502        result = SL_RESULT_PARAMETER_INVALID;
503    } else {
504        *pGroup = NULL;
505        unsigned exposedMask;
506        const ClassTable *pC3DGroup_class = objectIDtoClass(SL_OBJECTID_3DGROUP);
507        if (NULL == pC3DGroup_class) {
508            result = SL_RESULT_FEATURE_UNSUPPORTED;
509        } else {
510            result = checkInterfaces(pC3DGroup_class, numInterfaces,
511                pInterfaceIds, pInterfaceRequired, &exposedMask);
512        }
513        if (SL_RESULT_SUCCESS == result) {
514            C3DGroup *this = (C3DGroup *) construct(pC3DGroup_class, exposedMask, self);
515            if (NULL == this) {
516                result = SL_RESULT_MEMORY_FAILURE;
517            } else {
518                this->mMemberMask = 0;
519                IObject_Publish(&this->mObject);
520                // return the new 3D group object
521                *pGroup = &this->mObject.mItf;
522            }
523        }
524    }
525#else
526    result = SL_RESULT_FEATURE_UNSUPPORTED;
527#endif
528
529    SL_LEAVE_INTERFACE
530}
531
532
533static SLresult IEngine_CreateOutputMix(SLEngineItf self, SLObjectItf *pMix, SLuint32 numInterfaces,
534    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
535{
536    SL_ENTER_INTERFACE
537
538    if (NULL == pMix) {
539        result = SL_RESULT_PARAMETER_INVALID;
540    } else {
541        *pMix = NULL;
542        unsigned exposedMask;
543        const ClassTable *pCOutputMix_class = objectIDtoClass(SL_OBJECTID_OUTPUTMIX);
544        assert(NULL != pCOutputMix_class);
545        result = checkInterfaces(pCOutputMix_class, numInterfaces,
546            pInterfaceIds, pInterfaceRequired, &exposedMask);
547        if (SL_RESULT_SUCCESS == result) {
548            COutputMix *this = (COutputMix *) construct(pCOutputMix_class, exposedMask, self);
549            if (NULL == this) {
550                result = SL_RESULT_MEMORY_FAILURE;
551            } else {
552#ifdef ANDROID
553                android_outputMix_create(this);
554#endif
555#ifdef USE_SDL
556                IEngine *thisEngine = this->mObject.mEngine;
557                interface_lock_exclusive(thisEngine);
558                bool unpause = false;
559                if (NULL == thisEngine->mOutputMix) {
560                    thisEngine->mOutputMix = this;
561                    unpause = true;
562                }
563                interface_unlock_exclusive(thisEngine);
564#endif
565                IObject_Publish(&this->mObject);
566#ifdef USE_SDL
567                if (unpause) {
568                    // Enable SDL_callback to be called periodically by SDL's internal thread
569                    SDL_PauseAudio(0);
570                }
571#endif
572                // return the new output mix object
573                *pMix = &this->mObject.mItf;
574            }
575        }
576    }
577
578    SL_LEAVE_INTERFACE
579}
580
581
582static SLresult IEngine_CreateMetadataExtractor(SLEngineItf self, SLObjectItf *pMetadataExtractor,
583    SLDataSource *pDataSource, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds,
584    const SLboolean *pInterfaceRequired)
585{
586    SL_ENTER_INTERFACE
587
588#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_MUSIC)
589    if (NULL == pMetadataExtractor) {
590        result = SL_RESULT_PARAMETER_INVALID;
591    } else {
592        *pMetadataExtractor = NULL;
593        unsigned exposedMask;
594        const ClassTable *pCMetadataExtractor_class =
595            objectIDtoClass(SL_OBJECTID_METADATAEXTRACTOR);
596        if (NULL == pCMetadataExtractor_class) {
597            result = SL_RESULT_FEATURE_UNSUPPORTED;
598        } else {
599            result = checkInterfaces(pCMetadataExtractor_class, numInterfaces,
600                pInterfaceIds, pInterfaceRequired, &exposedMask);
601        }
602        if (SL_RESULT_SUCCESS == result) {
603            CMetadataExtractor *this = (CMetadataExtractor *)
604                construct(pCMetadataExtractor_class, exposedMask, self);
605            if (NULL == this) {
606                result = SL_RESULT_MEMORY_FAILURE;
607            } else {
608                IObject_Publish(&this->mObject);
609                // return the new metadata extractor object
610                *pMetadataExtractor = &this->mObject.mItf;
611                result = SL_RESULT_SUCCESS;
612            }
613        }
614    }
615#else
616    result = SL_RESULT_FEATURE_UNSUPPORTED;
617#endif
618
619    SL_LEAVE_INTERFACE
620}
621
622
623static SLresult IEngine_CreateExtensionObject(SLEngineItf self, SLObjectItf *pObject,
624    void *pParameters, SLuint32 objectID, SLuint32 numInterfaces,
625    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
626{
627    SL_ENTER_INTERFACE
628
629    if (NULL == pObject) {
630        result = SL_RESULT_PARAMETER_INVALID;
631    } else {
632        *pObject = NULL;
633        result = SL_RESULT_FEATURE_UNSUPPORTED;
634    }
635
636    SL_LEAVE_INTERFACE
637}
638
639
640static SLresult IEngine_QueryNumSupportedInterfaces(SLEngineItf self,
641    SLuint32 objectID, SLuint32 *pNumSupportedInterfaces)
642{
643    SL_ENTER_INTERFACE
644
645    if (NULL == pNumSupportedInterfaces) {
646        result = SL_RESULT_PARAMETER_INVALID;
647    } else {
648        const ClassTable *class__ = objectIDtoClass(objectID);
649        if (NULL == class__) {
650            result = SL_RESULT_FEATURE_UNSUPPORTED;
651        } else {
652            SLuint32 count = 0;
653            SLuint32 i;
654            for (i = 0; i < class__->mInterfaceCount; ++i) {
655                switch (class__->mInterfaces[i].mInterface) {
656                case INTERFACE_IMPLICIT:
657                case INTERFACE_IMPLICIT_PREREALIZE:
658                case INTERFACE_EXPLICIT:
659                case INTERFACE_EXPLICIT_PREREALIZE:
660                case INTERFACE_DYNAMIC:
661                    ++count;
662                    break;
663                case INTERFACE_UNAVAILABLE:
664                    break;
665                default:
666                    assert(false);
667                    break;
668                }
669            }
670            *pNumSupportedInterfaces = count;
671            result = SL_RESULT_SUCCESS;
672        }
673    }
674
675    SL_LEAVE_INTERFACE;
676}
677
678
679static SLresult IEngine_QuerySupportedInterfaces(SLEngineItf self,
680    SLuint32 objectID, SLuint32 index, SLInterfaceID *pInterfaceId)
681{
682    SL_ENTER_INTERFACE
683
684    if (NULL == pInterfaceId) {
685        result = SL_RESULT_PARAMETER_INVALID;
686    } else {
687        *pInterfaceId = NULL;
688        const ClassTable *class__ = objectIDtoClass(objectID);
689        if (NULL == class__) {
690            result = SL_RESULT_FEATURE_UNSUPPORTED;
691        } else {
692            result = SL_RESULT_PARAMETER_INVALID; // will be reset later
693            SLuint32 i;
694            for (i = 0; i < class__->mInterfaceCount; ++i) {
695                switch (class__->mInterfaces[i].mInterface) {
696                case INTERFACE_IMPLICIT:
697                case INTERFACE_IMPLICIT_PREREALIZE:
698                case INTERFACE_EXPLICIT:
699                case INTERFACE_EXPLICIT_PREREALIZE:
700                case INTERFACE_DYNAMIC:
701                    break;
702                case INTERFACE_UNAVAILABLE:
703                    continue;
704                default:
705                    assert(false);
706                    break;
707                }
708                if (index == 0) {
709                    *pInterfaceId = &SL_IID_array[class__->mInterfaces[i].mMPH];
710                    result = SL_RESULT_SUCCESS;
711                    break;
712                }
713                --index;
714            }
715        }
716    }
717
718    SL_LEAVE_INTERFACE
719};
720
721
722static const char * const extensionNames[] = {
723#ifdef ANDROID
724    "ANDROID_SDK_LEVEL_9",  // Android 2.3 aka "Gingerbread"
725    // in the future, add more entries for each SDK level here, and
726    // don't delete the entries for previous SDK levels unless support is removed
727#else
728    "WILHELM_DESKTOP",
729#endif
730};
731
732
733static SLresult IEngine_QueryNumSupportedExtensions(SLEngineItf self, SLuint32 *pNumExtensions)
734{
735    SL_ENTER_INTERFACE
736
737    if (NULL == pNumExtensions) {
738        result = SL_RESULT_PARAMETER_INVALID;
739    } else {
740        *pNumExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]);
741        result = SL_RESULT_SUCCESS;
742    }
743
744    SL_LEAVE_INTERFACE
745}
746
747
748static SLresult IEngine_QuerySupportedExtension(SLEngineItf self,
749    SLuint32 index, SLchar *pExtensionName, SLint16 *pNameLength)
750{
751    SL_ENTER_INTERFACE
752
753    if (NULL == pNameLength) {
754        result = SL_RESULT_PARAMETER_INVALID;
755    } else {
756        size_t actualNameLength;
757        unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]);
758        if (index >= numExtensions) {
759            actualNameLength = 0;
760            result = SL_RESULT_PARAMETER_INVALID;
761        } else {
762            const char *extensionName = extensionNames[index];
763            actualNameLength = strlen(extensionName) + 1;
764            if (NULL == pExtensionName) {
765                // application is querying the name length in order to allocate a buffer
766                result = SL_RESULT_SUCCESS;
767            } else {
768                SLint16 availableNameLength = *pNameLength;
769                if (0 >= availableNameLength) {
770                    // there is not even room for the terminating NUL
771                    result = SL_RESULT_BUFFER_INSUFFICIENT;
772                } else if (actualNameLength > (size_t) availableNameLength) {
773                    // "no invalid strings are written. That is, the null-terminator always exists"
774                    memcpy(pExtensionName, extensionName, (size_t) availableNameLength - 1);
775                    pExtensionName[(size_t) availableNameLength - 1] = '\0';
776                    result = SL_RESULT_BUFFER_INSUFFICIENT;
777                } else {
778                    memcpy(pExtensionName, extensionName, actualNameLength);
779                    result = SL_RESULT_SUCCESS;
780                }
781            }
782        }
783        *pNameLength = actualNameLength;
784    }
785
786    SL_LEAVE_INTERFACE
787}
788
789
790static SLresult IEngine_IsExtensionSupported(SLEngineItf self,
791    const SLchar *pExtensionName, SLboolean *pSupported)
792{
793    SL_ENTER_INTERFACE
794
795    if (NULL == pSupported) {
796        result = SL_RESULT_PARAMETER_INVALID;
797    } else {
798        SLboolean isSupported = SL_BOOLEAN_FALSE;
799        if (NULL == pExtensionName) {
800            result = SL_RESULT_PARAMETER_INVALID;
801        } else {
802            unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]);
803            unsigned i;
804            for (i = 0; i < numExtensions; ++i) {
805                if (!strcmp((const char *) pExtensionName, extensionNames[i])) {
806                    isSupported = SL_BOOLEAN_TRUE;
807                    break;
808                }
809            }
810            result = SL_RESULT_SUCCESS;
811        }
812        *pSupported = isSupported;
813    }
814
815    SL_LEAVE_INTERFACE
816}
817
818
819static const struct SLEngineItf_ IEngine_Itf = {
820    IEngine_CreateLEDDevice,
821    IEngine_CreateVibraDevice,
822    IEngine_CreateAudioPlayer,
823    IEngine_CreateAudioRecorder,
824    IEngine_CreateMidiPlayer,
825    IEngine_CreateListener,
826    IEngine_Create3DGroup,
827    IEngine_CreateOutputMix,
828    IEngine_CreateMetadataExtractor,
829    IEngine_CreateExtensionObject,
830    IEngine_QueryNumSupportedInterfaces,
831    IEngine_QuerySupportedInterfaces,
832    IEngine_QueryNumSupportedExtensions,
833    IEngine_QuerySupportedExtension,
834    IEngine_IsExtensionSupported
835};
836
837void IEngine_init(void *self)
838{
839    IEngine *this = (IEngine *) self;
840    this->mItf = &IEngine_Itf;
841    // mLossOfControlGlobal is initialized in slCreateEngine
842#ifdef USE_SDL
843    this->mOutputMix = NULL;
844#endif
845    this->mInstanceCount = 1; // ourself
846    this->mInstanceMask = 0;
847    this->mChangedMask = 0;
848    unsigned i;
849    for (i = 0; i < MAX_INSTANCE; ++i) {
850        this->mInstances[i] = NULL;
851    }
852    this->mShutdown = SL_BOOLEAN_FALSE;
853    this->mShutdownAck = SL_BOOLEAN_FALSE;
854    // mThreadPool is initialized in CEngine_Realize
855    memset(&this->mThreadPool, 0, sizeof(ThreadPool));
856#if defined(ANDROID) && !defined(USE_BACKPORT)
857    this->mEqNumPresets = 0;
858    this->mEqPresetNames = NULL;
859#endif
860}
861
862void IEngine_deinit(void *self)
863{
864#if defined(ANDROID) && !defined(USE_BACKPORT)
865    IEngine *this = (IEngine *) self;
866    // free equalizer preset names
867    if (NULL != this->mEqPresetNames) {
868        for (unsigned i = 0; i < this->mEqNumPresets; ++i) {
869            if (NULL != this->mEqPresetNames[i]) {
870                delete[] this->mEqPresetNames[i];
871                this->mEqPresetNames[i] = NULL;
872            }
873        }
874        delete[] this->mEqPresetNames;
875        this->mEqPresetNames = NULL;
876    }
877    this->mEqNumPresets = 0;
878#endif
879}
880