sles.c revision a3080daa505f91df51a808c85ddb37c48745bf7c
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/* OpenSL ES private and global functions not associated with an interface or class */
18
19#include "sles_allinclusive.h"
20
21
22/** \brief Return true if the specified interface exists and has been initialized for this object.
23 *  Returns false if the class does not support this kind of interface, or the class supports the
24 *  interface but this particular object has not had the interface exposed at object creation time
25 *  or by DynamicInterface::AddInterface. Note that the return value is not affected by whether
26 *  the application has requested access to the interface with Object::GetInterface. Assumes on
27 *  entry that the object is locked for either shared or exclusive access.
28 */
29
30bool IsInterfaceInitialized(IObject *this, unsigned MPH)
31{
32    assert(NULL != this);
33    assert( /* (MPH_MIN <= MPH) && */ (MPH < (unsigned) MPH_MAX));
34    const ClassTable *class__ = this->mClass;
35    assert(NULL != class__);
36    int index;
37    if (0 > (index = class__->mMPH_to_index[MPH])) {
38        return false;
39    }
40    assert(MAX_INDEX >= class__->mInterfaceCount);
41    assert(class__->mInterfaceCount > (unsigned) index);
42    switch (this->mInterfaceStates[index]) {
43    case INTERFACE_EXPOSED:
44    case INTERFACE_ADDED:
45        return true;
46    default:
47        return false;
48    }
49}
50
51
52/** \brief Map an IObject to it's "object ID" (which is really a class ID) */
53
54SLuint32 IObjectToObjectID(IObject *this)
55{
56    assert(NULL != this);
57    return this->mClass->mObjectID;
58}
59
60
61/** \brief Acquire a strong reference to an object.
62 *  Check that object has the specified "object ID" (which is really a class ID) and is in the
63 *  realized state.  If so, then acquire a strong reference to it and return true.
64 *  Otherwise return false.
65 */
66
67SLresult AcquireStrongRef(IObject *object, SLuint32 expectedObjectID)
68{
69    if (NULL == object) {
70        return SL_RESULT_PARAMETER_INVALID;
71    }
72    // NTH additional validity checks on address here
73    SLresult result;
74    object_lock_exclusive(object);
75    SLuint32 actualObjectID = IObjectToObjectID(object);
76    if (expectedObjectID != actualObjectID) {
77        SL_LOGE("object %p has object ID %lu but expected %lu", object, actualObjectID,
78            expectedObjectID);
79        result = SL_RESULT_PARAMETER_INVALID;
80    } else if (SL_OBJECT_STATE_REALIZED != object->mState) {
81        SL_LOGE("object %p with object ID %lu is not realized", object, actualObjectID);
82        result = SL_RESULT_PRECONDITIONS_VIOLATED;
83    } else {
84        ++object->mStrongRefCount;
85        result = SL_RESULT_SUCCESS;
86    }
87    object_unlock_exclusive(object);
88    return result;
89}
90
91
92/** \brief Release a strong reference to an object.
93 *  Entry condition: the object is locked.
94 *  Exit condition: the object is unlocked.
95 *  Finishes the destroy if needed.
96 */
97
98void ReleaseStrongRefAndUnlockExclusive(IObject *object)
99{
100#ifdef USE_DEBUG
101    assert(pthread_equal(pthread_self(), object->mOwner));
102#endif
103    assert(0 < object->mStrongRefCount);
104    if ((0 == --object->mStrongRefCount) && (SL_OBJECT_STATE_DESTROYING == object->mState)) {
105        // FIXME do the destroy here - merge with IDestroy
106        // but can't do this until we move Destroy to the sync thread
107        // as Destroy is now a blocking operation, and to avoid a race
108    } else {
109        object_unlock_exclusive(object);
110    }
111}
112
113
114/** \brief Release a strong reference to an object.
115 *  Entry condition: the object is unlocked.
116 *  Exit condition: the object is unlocked.
117 *  Finishes the destroy if needed.
118 */
119
120void ReleaseStrongRef(IObject *object)
121{
122    assert(NULL != object);
123    object_lock_exclusive(object);
124    ReleaseStrongRefAndUnlockExclusive(object);
125}
126
127
128/** \brief Convert POSIX pthread error code to OpenSL ES result code */
129
130SLresult err_to_result(int err)
131{
132    if (EAGAIN == err || ENOMEM == err) {
133        return SL_RESULT_RESOURCE_ERROR;
134    }
135    if (0 != err) {
136        return SL_RESULT_INTERNAL_ERROR;
137    }
138    return SL_RESULT_SUCCESS;
139}
140
141
142/** \brief Check the interface IDs passed into a Create operation */
143
144SLresult checkInterfaces(const ClassTable *class__, SLuint32 numInterfaces,
145    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired, unsigned *pExposedMask)
146{
147    assert(NULL != class__ && NULL != pExposedMask);
148    // Initially no interfaces are exposed
149    unsigned exposedMask = 0;
150    const struct iid_vtable *interfaces = class__->mInterfaces;
151    SLuint32 interfaceCount = class__->mInterfaceCount;
152    SLuint32 i;
153    // Expose all implicit interfaces
154    for (i = 0; i < interfaceCount; ++i) {
155        switch (interfaces[i].mInterface) {
156        case INTERFACE_IMPLICIT:
157            // there must be an initialization hook present
158            if (NULL != MPH_init_table[interfaces[i].mMPH].mInit) {
159                exposedMask |= 1 << i;
160            }
161            break;
162        default:
163            break;
164        }
165    }
166    if (0 < numInterfaces) {
167        if (NULL == pInterfaceIds || NULL == pInterfaceRequired) {
168            return SL_RESULT_PARAMETER_INVALID;
169        }
170        // Loop for each requested interface
171        for (i = 0; i < numInterfaces; ++i) {
172            SLInterfaceID iid = pInterfaceIds[i];
173            if (NULL == iid) {
174                return SL_RESULT_PARAMETER_INVALID;
175            }
176            int MPH, index;
177            if ((0 > (MPH = IID_to_MPH(iid))) ||
178                    // there must be an initialization hook present
179                    (NULL == MPH_init_table[MPH].mInit) ||
180                    (0 > (index = class__->mMPH_to_index[MPH]))) {
181                // Here if interface was not found, or is not available for this object type
182                if (pInterfaceRequired[i]) {
183                    // Application said it required the interface, so give up
184                    SL_LOGE("class %s interface %lu required but unavailable MPH=%d",
185                            class__->mName, i, MPH);
186                    return SL_RESULT_FEATURE_UNSUPPORTED;
187                }
188                // Application said it didn't really need the interface, so ignore
189                continue;
190            }
191            // The requested interface was both found and available, so expose it
192            exposedMask |= (1 << index);
193            // Note that we ignore duplicate requests, including equal and aliased IDs
194        }
195    }
196    *pExposedMask = exposedMask;
197    return SL_RESULT_SUCCESS;
198}
199
200
201/** \brief Helper shared by decoder and encoder */
202
203SLresult GetCodecCapabilities(SLuint32 codecId, SLuint32 *pIndex,
204    SLAudioCodecDescriptor *pDescriptor, const CodecDescriptor *codecDescriptors)
205{
206    if (NULL == pIndex) {
207        return SL_RESULT_PARAMETER_INVALID;
208    }
209    const CodecDescriptor *cd = codecDescriptors;
210    SLuint32 index;
211    if (NULL == pDescriptor) {
212        for (index = 0 ; NULL != cd->mDescriptor; ++cd) {
213            if (cd->mCodecID == codecId) {
214                ++index;
215            }
216        }
217        *pIndex = index;
218        return SL_RESULT_SUCCESS;
219    }
220    index = *pIndex;
221    for ( ; NULL != cd->mDescriptor; ++cd) {
222        if (cd->mCodecID == codecId) {
223            if (0 == index) {
224                *pDescriptor = *cd->mDescriptor;
225#if 0   // Temporary workaround for Khronos bug 6331
226                if (0 < pDescriptor->numSampleRatesSupported) {
227                    // The malloc is not in the 1.0.1 specification
228                    SLmilliHertz *temp = (SLmilliHertz *) malloc(sizeof(SLmilliHertz) *
229                        pDescriptor->numSampleRatesSupported);
230                    assert(NULL != temp);
231                    memcpy(temp, pDescriptor->pSampleRatesSupported, sizeof(SLmilliHertz) *
232                        pDescriptor->numSampleRatesSupported);
233                    pDescriptor->pSampleRatesSupported = temp;
234                } else {
235                    pDescriptor->pSampleRatesSupported = NULL;
236                }
237#endif
238                return SL_RESULT_SUCCESS;
239            }
240            --index;
241        }
242    }
243    return SL_RESULT_PARAMETER_INVALID;
244}
245
246
247/** \brief Check a data locator and make local deep copy */
248
249static SLresult checkDataLocator(void *pLocator, DataLocator *pDataLocator)
250{
251    if (NULL == pLocator) {
252        pDataLocator->mLocatorType = SL_DATALOCATOR_NULL;
253        return SL_RESULT_SUCCESS;
254    }
255    SLresult result;
256    SLuint32 locatorType = *(SLuint32 *)pLocator;
257    switch (locatorType) {
258
259    case SL_DATALOCATOR_ADDRESS:
260        pDataLocator->mAddress = *(SLDataLocator_Address *)pLocator;
261        // if length is greater than zero, then the address must be non-NULL
262        if ((0 < pDataLocator->mAddress.length) && (NULL == pDataLocator->mAddress.pAddress)) {
263            SL_LOGE("pAddress is NULL");
264            return SL_RESULT_PARAMETER_INVALID;
265        }
266        break;
267
268    case SL_DATALOCATOR_BUFFERQUEUE:
269#ifdef ANDROID
270    // This is an alias that is _not_ converted; the rest of the code must check for both locator
271    // types. That's because it is only an alias for audio players, not audio recorder objects
272    // so we have to remember the distinction.
273    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
274#endif
275        pDataLocator->mBufferQueue = *(SLDataLocator_BufferQueue *)pLocator;
276        // number of buffers must be specified, there is no default value, and must not be excessive
277        if (!((1 <= pDataLocator->mBufferQueue.numBuffers) &&
278            (pDataLocator->mBufferQueue.numBuffers <= 255))) {
279            SL_LOGE("numBuffers=%u", (unsigned) pDataLocator->mBufferQueue.numBuffers);
280            return SL_RESULT_PARAMETER_INVALID;
281        }
282        break;
283
284    case SL_DATALOCATOR_IODEVICE:
285        {
286        pDataLocator->mIODevice = *(SLDataLocator_IODevice *)pLocator;
287        SLuint32 deviceType = pDataLocator->mIODevice.deviceType;
288        SLObjectItf device = pDataLocator->mIODevice.device;
289        if (NULL != device) {
290            pDataLocator->mIODevice.deviceID = 0;
291            SLuint32 expectedObjectID;
292            switch (deviceType) {
293            case SL_IODEVICE_LEDARRAY:
294                expectedObjectID = SL_OBJECTID_LEDDEVICE;
295                break;
296            case SL_IODEVICE_VIBRA:
297                expectedObjectID = SL_OBJECTID_VIBRADEVICE;
298                break;
299            // audio input and audio output cannot be specified via objects
300            case SL_IODEVICE_AUDIOINPUT:
301            // worse yet, an SL_IODEVICE enum constant for audio output does not exist yet
302            // case SL_IODEVICE_AUDIOOUTPUT:
303            default:
304                SL_LOGE("invalid deviceType %lu", deviceType);
305                pDataLocator->mIODevice.device = NULL;
306                return SL_RESULT_PARAMETER_INVALID;
307            }
308            // check that device has the correct object ID and is realized,
309            // and acquire a strong reference to it
310            result = AcquireStrongRef((IObject *) device, expectedObjectID);
311            if (SL_RESULT_SUCCESS != result) {
312                SL_LOGE("locator type is IODEVICE, but device field %p has wrong object ID or is " \
313                    "not realized", device);
314                pDataLocator->mIODevice.device = NULL;
315                return result;
316            }
317        } else {
318            SLuint32 deviceID = pDataLocator->mIODevice.deviceID;
319            // FIXME this section should be OEM-configurable
320            switch (deviceType) {
321            case SL_IODEVICE_LEDARRAY:
322                if (SL_DEFAULTDEVICEID_LED != deviceID) {
323                    SL_LOGE("invalid LED deviceID %lu", deviceID);
324                    return SL_RESULT_PARAMETER_INVALID;
325                }
326                break;
327            case SL_IODEVICE_VIBRA:
328                if (SL_DEFAULTDEVICEID_VIBRA != deviceID) {
329                    SL_LOGE("invalid vibra deviceID %lu", deviceID);
330                    return SL_RESULT_PARAMETER_INVALID;
331                }
332                break;
333            case SL_IODEVICE_AUDIOINPUT:
334                if (SL_DEFAULTDEVICEID_AUDIOINPUT != deviceID) {
335                    SL_LOGE("invalid audio input deviceID %lu", deviceID);
336                    return SL_RESULT_PARAMETER_INVALID;
337                }
338                break;
339            default:
340                SL_LOGE("invalid deviceType %lu", deviceType);
341                return SL_RESULT_PARAMETER_INVALID;
342            }
343        }
344        }
345        break;
346
347    case SL_DATALOCATOR_MIDIBUFFERQUEUE:
348        pDataLocator->mMIDIBufferQueue = *(SLDataLocator_MIDIBufferQueue *)pLocator;
349        if (0 == pDataLocator->mMIDIBufferQueue.tpqn) {
350            pDataLocator->mMIDIBufferQueue.tpqn = 192;
351        }
352        // number of buffers must be specified, there is no default value, and must not be excessive
353        if (!((1 <= pDataLocator->mMIDIBufferQueue.numBuffers) &&
354            (pDataLocator->mMIDIBufferQueue.numBuffers <= 255))) {
355            SL_LOGE("invalid MIDI buffer queue");
356            return SL_RESULT_PARAMETER_INVALID;
357        }
358        break;
359
360    case SL_DATALOCATOR_OUTPUTMIX:
361        pDataLocator->mOutputMix = *(SLDataLocator_OutputMix *)pLocator;
362        // check that output mix object has the correct object ID and is realized,
363        // and acquire a strong reference to it
364        result = AcquireStrongRef((IObject *) pDataLocator->mOutputMix.outputMix,
365            SL_OBJECTID_OUTPUTMIX);
366        if (SL_RESULT_SUCCESS != result) {
367            SL_LOGE("locatorType is SL_DATALOCATOR_OUTPUTMIX, but outputMix field %p does not " \
368                "refer to an SL_OBJECTID_OUTPUTMIX or is not realized", \
369                pDataLocator->mOutputMix.outputMix);
370            pDataLocator->mOutputMix.outputMix = NULL;
371            return result;
372        }
373        break;
374
375    case SL_DATALOCATOR_URI:
376        {
377        pDataLocator->mURI = *(SLDataLocator_URI *)pLocator;
378        if (NULL == pDataLocator->mURI.URI) {
379            SL_LOGE("invalid URI");
380            return SL_RESULT_PARAMETER_INVALID;
381        }
382        // NTH verify URI address for validity
383        size_t len = strlen((const char *) pDataLocator->mURI.URI);
384        SLchar *myURI = (SLchar *) malloc(len + 1);
385        if (NULL == myURI) {
386            pDataLocator->mURI.URI = NULL;
387            return SL_RESULT_MEMORY_FAILURE;
388        }
389        memcpy(myURI, pDataLocator->mURI.URI, len + 1);
390        // Verify that another thread didn't change the NUL-terminator after we used it
391        // to determine length of string to copy. It's OK if the string became shorter.
392        if ('\0' != myURI[len]) {
393            free(myURI);
394            pDataLocator->mURI.URI = NULL;
395            return SL_RESULT_PARAMETER_INVALID;
396        }
397        pDataLocator->mURI.URI = myURI;
398        }
399        break;
400
401#ifdef ANDROID
402    case SL_DATALOCATOR_ANDROIDFD:
403        {
404        pDataLocator->mFD = *(SLDataLocator_AndroidFD *)pLocator;
405        SL_LOGV("Data locator FD: fd=%ld offset=%lld length=%lld", pDataLocator->mFD.fd,
406                pDataLocator->mFD.offset, pDataLocator->mFD.length);
407        // NTH check against process fd limit
408        if (0 > pDataLocator->mFD.fd) {
409            return SL_RESULT_PARAMETER_INVALID;
410        }
411        }
412        break;
413#endif
414
415    default:
416        SL_LOGE("invalid locatorType %lu", locatorType);
417        return SL_RESULT_PARAMETER_INVALID;
418    }
419
420    // Verify that another thread didn't change the locatorType field after we used it
421    // to determine sizeof struct to copy.
422    if (locatorType != pDataLocator->mLocatorType) {
423        return SL_RESULT_PARAMETER_INVALID;
424    }
425    return SL_RESULT_SUCCESS;
426}
427
428
429/** \brief Free the local deep copy of a data locator */
430
431static void freeDataLocator(DataLocator *pDataLocator)
432{
433    switch (pDataLocator->mLocatorType) {
434    case SL_DATALOCATOR_URI:
435        if (NULL != pDataLocator->mURI.URI) {
436            free(pDataLocator->mURI.URI);
437            pDataLocator->mURI.URI = NULL;
438        }
439        pDataLocator->mURI.URI = NULL;
440        break;
441    case SL_DATALOCATOR_IODEVICE:
442        if (NULL != pDataLocator->mIODevice.device) {
443            ReleaseStrongRef((IObject *) pDataLocator->mIODevice.device);
444            pDataLocator->mIODevice.device = NULL;
445        }
446        break;
447    case SL_DATALOCATOR_OUTPUTMIX:
448        if (NULL != pDataLocator->mOutputMix.outputMix) {
449            ReleaseStrongRef((IObject *) pDataLocator->mOutputMix.outputMix);
450            pDataLocator->mOutputMix.outputMix = NULL;
451        }
452        break;
453    default:
454        break;
455    }
456}
457
458
459/** \brief Check a data format and make local deep copy */
460
461static SLresult checkDataFormat(void *pFormat, DataFormat *pDataFormat)
462{
463    SLresult result = SL_RESULT_SUCCESS;
464
465    if (NULL == pFormat) {
466        pDataFormat->mFormatType = SL_DATAFORMAT_NULL;
467    } else {
468        SLuint32 formatType = *(SLuint32 *)pFormat;
469        switch (formatType) {
470
471        case SL_DATAFORMAT_PCM:
472            pDataFormat->mPCM = *(SLDataFormat_PCM *)pFormat;
473            do {
474
475                // check the channel count
476                switch (pDataFormat->mPCM.numChannels) {
477                case 1:     // mono
478                case 2:     // stereo
479                    break;
480                case 0:     // unknown
481                    result = SL_RESULT_PARAMETER_INVALID;
482                    break;
483                default:    // multi-channel
484                    result = SL_RESULT_CONTENT_UNSUPPORTED;
485                    break;
486                }
487                if (SL_RESULT_SUCCESS != result) {
488                    SL_LOGE("numChannels=%u", (unsigned) pDataFormat->mPCM.numChannels);
489                    break;
490                }
491
492                // check the sampling rate
493                switch (pDataFormat->mPCM.samplesPerSec) {
494                case SL_SAMPLINGRATE_8:
495                case SL_SAMPLINGRATE_11_025:
496                case SL_SAMPLINGRATE_12:
497                case SL_SAMPLINGRATE_16:
498                case SL_SAMPLINGRATE_22_05:
499                case SL_SAMPLINGRATE_24:
500                case SL_SAMPLINGRATE_32:
501                case SL_SAMPLINGRATE_44_1:
502                case SL_SAMPLINGRATE_48:
503                case SL_SAMPLINGRATE_64:
504                case SL_SAMPLINGRATE_88_2:
505                case SL_SAMPLINGRATE_96:
506                case SL_SAMPLINGRATE_192:
507                    break;
508                case 0:
509                    result = SL_RESULT_PARAMETER_INVALID;
510                    break;
511                default:
512                    result = SL_RESULT_CONTENT_UNSUPPORTED;
513                    break;
514                }
515                if (SL_RESULT_SUCCESS != result) {
516                    SL_LOGE("samplesPerSec=%u", (unsigned) pDataFormat->mPCM.samplesPerSec);
517                    break;
518                }
519
520                // check the sample bit depth
521                switch (pDataFormat->mPCM.bitsPerSample) {
522                case SL_PCMSAMPLEFORMAT_FIXED_8:
523                case SL_PCMSAMPLEFORMAT_FIXED_16:
524                    break;
525                case SL_PCMSAMPLEFORMAT_FIXED_20:
526                case SL_PCMSAMPLEFORMAT_FIXED_24:
527                case SL_PCMSAMPLEFORMAT_FIXED_28:
528                case SL_PCMSAMPLEFORMAT_FIXED_32:
529                    result = SL_RESULT_CONTENT_UNSUPPORTED;
530                    break;
531                default:
532                    result = SL_RESULT_PARAMETER_INVALID;
533                    break;
534                }
535                if (SL_RESULT_SUCCESS != result) {
536                    SL_LOGE("bitsPerSample=%u", (unsigned) pDataFormat->mPCM.bitsPerSample);
537                    break;
538                }
539
540                // check the container bit depth
541                switch (pDataFormat->mPCM.containerSize) {
542                case SL_PCMSAMPLEFORMAT_FIXED_8:
543                case SL_PCMSAMPLEFORMAT_FIXED_16:
544                    if (pDataFormat->mPCM.containerSize != pDataFormat->mPCM.bitsPerSample) {
545                        result = SL_RESULT_CONTENT_UNSUPPORTED;
546                    }
547                    break;
548                default:
549                    result = SL_RESULT_CONTENT_UNSUPPORTED;
550                    break;
551                }
552                if (SL_RESULT_SUCCESS != result) {
553                    SL_LOGE("containerSize=%u", (unsigned) pDataFormat->mPCM.containerSize);
554                    break;
555                }
556
557                // check the channel mask
558                switch (pDataFormat->mPCM.channelMask) {
559                case SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT:
560                    if (2 != pDataFormat->mPCM.numChannels) {
561                        result = SL_RESULT_PARAMETER_INVALID;
562                    }
563                    break;
564                case SL_SPEAKER_FRONT_LEFT:
565                case SL_SPEAKER_FRONT_RIGHT:
566                case SL_SPEAKER_FRONT_CENTER:
567                    if (1 != pDataFormat->mPCM.numChannels) {
568                        result = SL_RESULT_PARAMETER_INVALID;
569                    }
570                    break;
571                case 0:
572                    pDataFormat->mPCM.channelMask = pDataFormat->mPCM.numChannels == 2 ?
573                        SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT : SL_SPEAKER_FRONT_CENTER;
574                    break;
575                default:
576                    result = SL_RESULT_PARAMETER_INVALID;
577                    break;
578                }
579                if (SL_RESULT_SUCCESS != result) {
580                    SL_LOGE("channelMask=0x%lx numChannels=%lu", pDataFormat->mPCM.channelMask,
581                        pDataFormat->mPCM.numChannels);
582                    break;
583                }
584
585                // check the endianness / byte order
586                switch (pDataFormat->mPCM.endianness) {
587                case SL_BYTEORDER_LITTLEENDIAN:
588                case SL_BYTEORDER_BIGENDIAN:
589                    break;
590                // native is proposed but not yet in spec
591                default:
592                    result = SL_RESULT_PARAMETER_INVALID;
593                    break;
594                }
595                if (SL_RESULT_SUCCESS != result) {
596                    SL_LOGE("endianness=%u", (unsigned) pDataFormat->mPCM.endianness);
597                    break;
598                }
599
600                // here if all checks passed successfully
601
602            } while(0);
603            break;
604
605        case SL_DATAFORMAT_MIME:
606            pDataFormat->mMIME = *(SLDataFormat_MIME *)pFormat;
607            if (NULL != pDataFormat->mMIME.mimeType) {
608                // NTH check address for validity
609                size_t len = strlen((const char *) pDataFormat->mMIME.mimeType);
610                SLchar *myMIME = (SLchar *) malloc(len + 1);
611                if (NULL == myMIME) {
612                    result = SL_RESULT_MEMORY_FAILURE;
613                } else {
614                    memcpy(myMIME, pDataFormat->mMIME.mimeType, len + 1);
615                    // make sure MIME string was not modified asynchronously
616                    if ('\0' != myMIME[len]) {
617                        free(myMIME);
618                        myMIME = NULL;
619                        result = SL_RESULT_PRECONDITIONS_VIOLATED;
620                    }
621                }
622                pDataFormat->mMIME.mimeType = myMIME;
623            }
624            break;
625
626        default:
627            result = SL_RESULT_PARAMETER_INVALID;
628            SL_LOGE("formatType=%u", (unsigned) formatType);
629            break;
630
631        }
632
633        // make sure format type was not modified asynchronously
634        if ((SL_RESULT_SUCCESS == result) && (formatType != pDataFormat->mFormatType)) {
635            result = SL_RESULT_PRECONDITIONS_VIOLATED;
636        }
637
638    }
639
640    return result;
641}
642
643
644/** \brief Check interface ID compatibility with respect to a particular data locator format */
645
646SLresult checkSourceFormatVsInterfacesCompatibility(const DataLocatorFormat *pDataLocatorFormat,
647        SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds,
648            const SLboolean *pInterfaceRequired) {
649    // can't request SLSeekItf if data source is a buffer queue
650    // FIXME there are other invalid combinations -- see docs
651    SLuint32 i;
652    switch (pDataLocatorFormat->mLocator.mLocatorType) {
653    case SL_DATALOCATOR_BUFFERQUEUE:
654#ifdef ANDROID
655    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
656#endif
657        for (i = 0; i < numInterfaces; i++) {
658            // FIXME the == needs work
659            if (pInterfaceRequired[i] && (SL_IID_SEEK == pInterfaceIds[i])) {
660                SL_LOGE("can't request SL_IID_SEEK with a buffer queue data source");
661                return SL_RESULT_FEATURE_UNSUPPORTED;
662            }
663        }
664        break;
665    default:
666        break;
667    }
668    return SL_RESULT_SUCCESS;
669}
670
671
672/** \brief Free the local deep copy of a data format */
673
674static void freeDataFormat(DataFormat *pDataFormat)
675{
676    switch (pDataFormat->mFormatType) {
677    case SL_DATAFORMAT_MIME:
678        if (NULL != pDataFormat->mMIME.mimeType) {
679            free(pDataFormat->mMIME.mimeType);
680            pDataFormat->mMIME.mimeType = NULL;
681        }
682        break;
683    default:
684        break;
685    }
686}
687
688
689/** \brief Check a data source and make local deep copy */
690
691SLresult checkDataSource(const SLDataSource *pDataSrc, DataLocatorFormat *pDataLocatorFormat)
692{
693    if (NULL == pDataSrc) {
694        SL_LOGE("pDataSrc NULL");
695        return SL_RESULT_PARAMETER_INVALID;
696    }
697    SLDataSource myDataSrc = *pDataSrc;
698    SLresult result;
699    result = checkDataLocator(myDataSrc.pLocator, &pDataLocatorFormat->mLocator);
700    if (SL_RESULT_SUCCESS != result) {
701        return result;
702    }
703    switch (pDataLocatorFormat->mLocator.mLocatorType) {
704
705    case SL_DATALOCATOR_URI:
706    case SL_DATALOCATOR_ADDRESS:
707    case SL_DATALOCATOR_BUFFERQUEUE:
708    case SL_DATALOCATOR_MIDIBUFFERQUEUE:
709#ifdef ANDROID
710    case SL_DATALOCATOR_ANDROIDFD:
711    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
712#endif
713        result = checkDataFormat(myDataSrc.pFormat, &pDataLocatorFormat->mFormat);
714        if (SL_RESULT_SUCCESS != result) {
715            freeDataLocator(&pDataLocatorFormat->mLocator);
716            return result;
717        }
718        break;
719
720    case SL_DATALOCATOR_NULL:
721    case SL_DATALOCATOR_OUTPUTMIX:
722    default:
723        // invalid but fall through; the invalid locator will be caught later
724        SL_LOGE("mLocatorType=%u", (unsigned) pDataLocatorFormat->mLocator.mLocatorType);
725        // keep going
726
727    case SL_DATALOCATOR_IODEVICE:
728        // for these data locator types, ignore the pFormat as it might be uninitialized
729        pDataLocatorFormat->mFormat.mFormatType = SL_DATAFORMAT_NULL;
730        break;
731    }
732
733    pDataLocatorFormat->u.mSource.pLocator = &pDataLocatorFormat->mLocator;
734    pDataLocatorFormat->u.mSource.pFormat = &pDataLocatorFormat->mFormat;
735    return SL_RESULT_SUCCESS;
736}
737
738
739/** \brief Check a data sink and make local deep copy */
740
741SLresult checkDataSink(const SLDataSink *pDataSink, DataLocatorFormat *pDataLocatorFormat,
742        SLuint32 objType)
743{
744    if (NULL == pDataSink) {
745        SL_LOGE("pDataSink NULL");
746        return SL_RESULT_PARAMETER_INVALID;
747    }
748    SLDataSink myDataSink = *pDataSink;
749    SLresult result;
750    result = checkDataLocator(myDataSink.pLocator, &pDataLocatorFormat->mLocator);
751    if (SL_RESULT_SUCCESS != result) {
752        return result;
753    }
754    switch (pDataLocatorFormat->mLocator.mLocatorType) {
755
756    case SL_DATALOCATOR_URI:
757    case SL_DATALOCATOR_ADDRESS:
758        result = checkDataFormat(myDataSink.pFormat, &pDataLocatorFormat->mFormat);
759        if (SL_RESULT_SUCCESS != result) {
760            freeDataLocator(&pDataLocatorFormat->mLocator);
761            return result;
762        }
763        break;
764
765    case SL_DATALOCATOR_BUFFERQUEUE:
766#ifdef ANDROID
767    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
768#endif
769        if (SL_OBJECTID_AUDIOPLAYER == objType) {
770            SL_LOGE("buffer queue can't be used as data sink for audio player");
771            result = SL_RESULT_PARAMETER_INVALID;
772        } else if (SL_OBJECTID_AUDIORECORDER == objType) {
773#ifdef ANDROID
774            if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE !=
775                pDataLocatorFormat->mLocator.mLocatorType) {
776                SL_LOGE("audio recorder source locator must be SL_DATALOCATOR_ANDROIDBUFFERQUEUE");
777                result = SL_RESULT_PARAMETER_INVALID;
778            } else {
779                result = checkDataFormat(myDataSink.pFormat, &pDataLocatorFormat->mFormat);
780            }
781#else
782            SL_LOGE("mLocatorType=%u", (unsigned) pDataLocatorFormat->mLocator.mLocatorType);
783            result = SL_RESULT_PARAMETER_INVALID;
784#endif
785        }
786        if (SL_RESULT_SUCCESS != result) {
787            freeDataLocator(&pDataLocatorFormat->mLocator);
788            return result;
789        }
790        break;
791
792    case SL_DATALOCATOR_NULL:
793    case SL_DATALOCATOR_MIDIBUFFERQUEUE:
794    default:
795        // invalid but fall through; the invalid locator will be caught later
796        SL_LOGE("mLocatorType=%u", (unsigned) pDataLocatorFormat->mLocator.mLocatorType);
797        // keep going
798
799    case SL_DATALOCATOR_IODEVICE:
800    case SL_DATALOCATOR_OUTPUTMIX:
801        // for these data locator types, ignore the pFormat as it might be uninitialized
802        pDataLocatorFormat->mFormat.mFormatType = SL_DATAFORMAT_NULL;
803        break;
804    }
805
806    pDataLocatorFormat->u.mSink.pLocator = &pDataLocatorFormat->mLocator;
807    pDataLocatorFormat->u.mSink.pFormat = &pDataLocatorFormat->mFormat;
808    return SL_RESULT_SUCCESS;
809}
810
811
812/** \brief Free the local deep copy of a data locator format */
813
814void freeDataLocatorFormat(DataLocatorFormat *dlf)
815{
816    freeDataLocator(&dlf->mLocator);
817    freeDataFormat(&dlf->mFormat);
818}
819
820
821/* Interface initialization hooks */
822
823extern void
824    I3DCommit_init(void *),
825    I3DDoppler_init(void *),
826    I3DGrouping_deinit(void *),
827    I3DGrouping_init(void *),
828    I3DLocation_init(void *),
829    I3DMacroscopic_init(void *),
830    I3DSource_init(void *),
831    IAndroidConfiguration_init(void *),
832    IAndroidEffectCapabilities_init(void *),
833    IAndroidEffectSend_init(void *),
834    IAndroidEffect_init(void *),
835    IAudioDecoderCapabilities_init(void *),
836    IAudioEncoderCapabilities_init(void *),
837    IAudioEncoder_init(void *),
838    IAudioIODeviceCapabilities_init(void *),
839    IBassBoost_init(void *),
840    IBufferQueue_init(void *),
841    IDeviceVolume_init(void *),
842    IDynamicInterfaceManagement_init(void *),
843    IDynamicSource_init(void *),
844    IEffectSend_init(void *),
845    IEngineCapabilities_init(void *),
846    IEngine_init(void *),
847    IEnvironmentalReverb_init(void *),
848    IEqualizer_init(void *),
849    ILEDArray_init(void *),
850    IMIDIMessage_init(void *),
851    IMIDIMuteSolo_init(void *),
852    IMIDITempo_init(void *),
853    IMIDITime_init(void *),
854    IMetadataExtraction_init(void *),
855    IMetadataTraversal_init(void *),
856    IMuteSolo_init(void *),
857    IObject_init(void *),
858    IOutputMixExt_init(void *),
859    IOutputMix_init(void *),
860    IPitch_init(void *),
861    IPlay_init(void *),
862    IPlaybackRate_init(void *),
863    IPrefetchStatus_init(void *),
864    IPresetReverb_init(void *),
865    IRatePitch_init(void *),
866    IRecord_init(void *),
867    ISeek_init(void *),
868    IThreadSync_init(void *),
869    IVibra_init(void *),
870    IVirtualizer_init(void *),
871    IVisualization_init(void *),
872    IVolume_init(void *);
873
874extern void
875    IObject_deinit(void *);
876
877#if !(USE_PROFILES & USE_PROFILES_MUSIC)
878#define IDynamicSource_init         NULL
879#define IMetadataExtraction_init    NULL
880#define IMetadataTraversal_init     NULL
881#define IPlaybackRate_init          NULL
882#define IVisualization_init         NULL
883#endif
884
885#if !(USE_PROFILES & USE_PROFILES_GAME)
886#define I3DCommit_init      NULL
887#define I3DDoppler_init     NULL
888#define I3DGrouping_init    NULL
889#define I3DLocation_init    NULL
890#define I3DMacroscopic_init NULL
891#define I3DSource_init      NULL
892#define IMIDIMessage_init   NULL
893#define IMIDIMuteSolo_init  NULL
894#define IMIDITempo_init     NULL
895#define IMIDITime_init      NULL
896#define IPitch_init         NULL
897#define IRatePitch_init     NULL
898#define I3DGrouping_deinit  NULL
899#endif
900
901#if !(USE_PROFILES & USE_PROFILES_BASE)
902#define IAudioDecoderCapabilities_init   NULL
903#define IAudioEncoderCapabilities_init   NULL
904#define IAudioEncoder_init               NULL
905#define IAudioIODeviceCapabilities_init  NULL
906#define IDeviceVolume_init               NULL
907#define IDynamicInterfaceManagement_init NULL
908#define IEngineCapabilities_init         NULL
909#define IOutputMix_init                  NULL
910#define IThreadSync_init                 NULL
911#endif
912
913#if !(USE_PROFILES & USE_PROFILES_OPTIONAL)
914#define ILEDArray_init  NULL
915#define IVibra_init     NULL
916#endif
917
918#ifndef ANDROID
919#define IAndroidConfiguration_init      NULL
920#define IAndroidEffect_init             NULL
921#define IAndroidEffectCapabilities_init NULL
922#define IAndroidEffectSend_init         NULL
923#endif
924
925#ifndef USE_OUTPUTMIXEXT
926#define IOutputMixExt_init  NULL
927#endif
928
929
930/*static*/ const struct MPH_init MPH_init_table[MPH_MAX] = {
931    { /* MPH_3DCOMMIT, */ I3DCommit_init, NULL, NULL },
932    { /* MPH_3DDOPPLER, */ I3DDoppler_init, NULL, NULL },
933    { /* MPH_3DGROUPING, */ I3DGrouping_init, NULL, I3DGrouping_deinit },
934    { /* MPH_3DLOCATION, */ I3DLocation_init, NULL, NULL },
935    { /* MPH_3DMACROSCOPIC, */ I3DMacroscopic_init, NULL, NULL },
936    { /* MPH_3DSOURCE, */ I3DSource_init, NULL, NULL },
937    { /* MPH_AUDIODECODERCAPABILITIES, */ IAudioDecoderCapabilities_init, NULL, NULL },
938    { /* MPH_AUDIOENCODER, */ IAudioEncoder_init, NULL, NULL },
939    { /* MPH_AUDIOENCODERCAPABILITIES, */ IAudioEncoderCapabilities_init, NULL, NULL },
940    { /* MPH_AUDIOIODEVICECAPABILITIES, */ IAudioIODeviceCapabilities_init, NULL, NULL },
941    { /* MPH_BASSBOOST, */ IBassBoost_init, NULL, NULL },
942    { /* MPH_BUFFERQUEUE, */ IBufferQueue_init, NULL, NULL },
943    { /* MPH_DEVICEVOLUME, */ IDeviceVolume_init, NULL, NULL },
944    { /* MPH_DYNAMICINTERFACEMANAGEMENT, */ IDynamicInterfaceManagement_init, NULL, NULL },
945    { /* MPH_DYNAMICSOURCE, */ IDynamicSource_init, NULL, NULL },
946    { /* MPH_EFFECTSEND, */ IEffectSend_init, NULL, NULL },
947    { /* MPH_ENGINE, */ IEngine_init, NULL, NULL },
948    { /* MPH_ENGINECAPABILITIES, */ IEngineCapabilities_init, NULL, NULL },
949    { /* MPH_ENVIRONMENTALREVERB, */ IEnvironmentalReverb_init, NULL, NULL },
950    { /* MPH_EQUALIZER, */ IEqualizer_init, NULL, NULL },
951    { /* MPH_LED, */ ILEDArray_init, NULL, NULL },
952    { /* MPH_METADATAEXTRACTION, */ IMetadataExtraction_init, NULL, NULL },
953    { /* MPH_METADATATRAVERSAL, */ IMetadataTraversal_init, NULL, NULL },
954    { /* MPH_MIDIMESSAGE, */ IMIDIMessage_init, NULL, NULL },
955    { /* MPH_MIDITIME, */ IMIDITime_init, NULL, NULL },
956    { /* MPH_MIDITEMPO, */ IMIDITempo_init, NULL, NULL },
957    { /* MPH_MIDIMUTESOLO, */ IMIDIMuteSolo_init, NULL, NULL },
958    { /* MPH_MUTESOLO, */ IMuteSolo_init, NULL, NULL },
959    { /* MPH_NULL, */ NULL, NULL, NULL },
960    { /* MPH_OBJECT, */ IObject_init, NULL, IObject_deinit },
961    { /* MPH_OUTPUTMIX, */ IOutputMix_init, NULL, NULL },
962    { /* MPH_PITCH, */ IPitch_init, NULL, NULL },
963    { /* MPH_PLAY, */ IPlay_init, NULL, NULL },
964    { /* MPH_PLAYBACKRATE, */ IPlaybackRate_init, NULL, NULL },
965    { /* MPH_PREFETCHSTATUS, */ IPrefetchStatus_init, NULL, NULL },
966    { /* MPH_PRESETREVERB, */ IPresetReverb_init, NULL, NULL },
967    { /* MPH_RATEPITCH, */ IRatePitch_init, NULL, NULL },
968    { /* MPH_RECORD, */ IRecord_init, NULL, NULL },
969    { /* MPH_SEEK, */ ISeek_init, NULL, NULL },
970    { /* MPH_THREADSYNC, */ IThreadSync_init, NULL, NULL },
971    { /* MPH_VIBRA, */ IVibra_init, NULL, NULL },
972    { /* MPH_VIRTUALIZER, */ IVirtualizer_init, NULL, NULL },
973    { /* MPH_VISUALIZATION, */ IVisualization_init, NULL, NULL },
974    { /* MPH_VOLUME, */ IVolume_init, NULL, NULL },
975    { /* MPH_OUTPUTMIXEXT, */ IOutputMixExt_init, NULL, NULL },
976    { /* MPH_ANDROIDEFFECT */ IAndroidEffect_init, NULL, NULL },
977    { /* MPH_ANDROIDEFFECTCAPABILITIES */ IAndroidEffectCapabilities_init, NULL, NULL },
978    { /* MPH_ANDROIDEFFECTSEND */ IAndroidEffectSend_init, NULL, NULL },
979    { /* MPH_ANDROIDCONFIGURATION */ IAndroidConfiguration_init, NULL, NULL },
980    { /* MPH_ANDROIDSIMPLEBUFFERQUEUE, */ IBufferQueue_init /* alias */, NULL, NULL }
981};
982
983
984/** \brief Construct a new instance of the specified class, exposing selected interfaces */
985
986IObject *construct(const ClassTable *class__, unsigned exposedMask, SLEngineItf engine)
987{
988    IObject *this;
989    this = (IObject *) calloc(1, class__->mSize);
990    if (NULL != this) {
991        unsigned lossOfControlMask = 0;
992        // a NULL engine means we are constructing the engine
993        IEngine *thisEngine = (IEngine *) engine;
994        if (NULL == thisEngine) {
995            thisEngine = &((CEngine *) this)->mEngine;
996        } else {
997            interface_lock_exclusive(thisEngine);
998            if (MAX_INSTANCE <= thisEngine->mInstanceCount) {
999                SL_LOGE("Too many objects");
1000                interface_unlock_exclusive(thisEngine);
1001                free(this);
1002                return NULL;
1003            }
1004            // pre-allocate a pending slot, but don't assign bit from mInstanceMask yet
1005            ++thisEngine->mInstanceCount;
1006            assert(((unsigned) ~0) != thisEngine->mInstanceMask);
1007            interface_unlock_exclusive(thisEngine);
1008            // const, no lock needed
1009            if (thisEngine->mLossOfControlGlobal) {
1010                lossOfControlMask = ~0;
1011            }
1012        }
1013        this->mLossOfControlMask = lossOfControlMask;
1014        this->mClass = class__;
1015        this->mEngine = thisEngine;
1016        const struct iid_vtable *x = class__->mInterfaces;
1017        SLuint8 *interfaceStateP = this->mInterfaceStates;
1018        SLuint32 index;
1019        for (index = 0; index < class__->mInterfaceCount; ++index, ++x, exposedMask >>= 1) {
1020            SLuint8 state;
1021            if (exposedMask & 1) {
1022                void *self = (char *) this + x->mOffset;
1023                // IObject does not have an mThis, so [1] is not always defined
1024                if (index) {
1025                    ((IObject **) self)[1] = this;
1026                }
1027                VoidHook init = MPH_init_table[x->mMPH].mInit;
1028                // paranoid double-check for presence of an initialization hook
1029                if (NULL != init) {
1030                    (*init)(self);
1031                }
1032                // IObject does not require a call to GetInterface
1033                if (index) {
1034                    ((size_t *) self)[0] ^= ~0;
1035                }
1036                state = INTERFACE_EXPOSED;
1037            } else {
1038                state = INTERFACE_UNINITIALIZED;
1039            }
1040            *interfaceStateP++ = state;
1041        }
1042        // note that the new object is not yet published; creator must call IObject_Publish
1043    }
1044    return this;
1045}
1046
1047
1048/* Initial global entry points */
1049
1050
1051/** \brief slCreateEngine Function */
1052
1053SLresult SLAPIENTRY slCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions,
1054    const SLEngineOption *pEngineOptions, SLuint32 numInterfaces,
1055    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
1056{
1057    SL_ENTER_GLOBAL
1058
1059    do {
1060
1061#ifdef ANDROID
1062        android::ProcessState::self()->startThreadPool();
1063#ifndef USE_BACKPORT
1064        android::DataSource::RegisterDefaultSniffers();
1065#endif
1066#endif
1067
1068        if (NULL == pEngine) {
1069            result = SL_RESULT_PARAMETER_INVALID;
1070            break;
1071        }
1072        *pEngine = NULL;
1073
1074        if ((0 < numOptions) && (NULL == pEngineOptions)) {
1075            SL_LOGE("numOptions=%lu and pEngineOptions=NULL", numOptions);
1076            result = SL_RESULT_PARAMETER_INVALID;
1077            break;
1078        }
1079
1080        // default values
1081        SLboolean threadSafe = SL_BOOLEAN_TRUE;
1082        SLboolean lossOfControlGlobal = SL_BOOLEAN_FALSE;
1083
1084        // process engine options
1085        SLuint32 i;
1086        const SLEngineOption *option = pEngineOptions;
1087        result = SL_RESULT_SUCCESS;
1088        for (i = 0; i < numOptions; ++i, ++option) {
1089            switch (option->feature) {
1090            case SL_ENGINEOPTION_THREADSAFE:
1091                threadSafe = SL_BOOLEAN_FALSE != (SLboolean) option->data; // normalize
1092                break;
1093            case SL_ENGINEOPTION_LOSSOFCONTROL:
1094                lossOfControlGlobal = SL_BOOLEAN_FALSE != (SLboolean) option->data; // normalize
1095                break;
1096            default:
1097                SL_LOGE("unknown engine option: feature=%lu data=%lu",
1098                    option->feature, option->data);
1099                result = SL_RESULT_PARAMETER_INVALID;
1100                break;
1101            }
1102        }
1103        if (SL_RESULT_SUCCESS != result) {
1104            break;
1105        }
1106
1107        unsigned exposedMask;
1108        const ClassTable *pCEngine_class = objectIDtoClass(SL_OBJECTID_ENGINE);
1109        result = checkInterfaces(pCEngine_class, numInterfaces,
1110            pInterfaceIds, pInterfaceRequired, &exposedMask);
1111        if (SL_RESULT_SUCCESS != result) {
1112            break;
1113        }
1114
1115        CEngine *this = (CEngine *) construct(pCEngine_class, exposedMask, NULL);
1116        if (NULL == this) {
1117            result = SL_RESULT_MEMORY_FAILURE;
1118            break;
1119        }
1120
1121        this->mObject.mLossOfControlMask = lossOfControlGlobal ? ~0 : 0;
1122        this->mEngine.mLossOfControlGlobal = lossOfControlGlobal;
1123        this->mEngineCapabilities.mThreadSafe = threadSafe;
1124        *pEngine = &this->mObject.mItf;
1125
1126    } while(0);
1127
1128    SL_LEAVE_GLOBAL
1129}
1130
1131
1132/** \brief slQueryNumSupportedEngineInterfaces Function */
1133
1134SLresult SLAPIENTRY slQueryNumSupportedEngineInterfaces(SLuint32 *pNumSupportedInterfaces)
1135{
1136    SL_ENTER_GLOBAL
1137
1138    if (NULL == pNumSupportedInterfaces) {
1139        result = SL_RESULT_PARAMETER_INVALID;
1140    } else {
1141        const ClassTable *class__ = objectIDtoClass(SL_OBJECTID_ENGINE);
1142        assert(NULL != class__);
1143        SLuint32 count = 0;
1144        SLuint32 i;
1145        for (i = 0; i < class__->mInterfaceCount; ++i) {
1146            switch (class__->mInterfaces[i].mInterface) {
1147            case INTERFACE_IMPLICIT:
1148            case INTERFACE_EXPLICIT:
1149            case INTERFACE_DYNAMIC:
1150                ++count;
1151                break;
1152            case INTERFACE_UNAVAILABLE:
1153                break;
1154            default:
1155                assert(false);
1156                break;
1157            }
1158        }
1159        *pNumSupportedInterfaces = count;
1160        result = SL_RESULT_SUCCESS;
1161    }
1162
1163    SL_LEAVE_GLOBAL
1164}
1165
1166
1167/** \brief slQuerySupportedEngineInterfaces Function */
1168
1169SLresult SLAPIENTRY slQuerySupportedEngineInterfaces(SLuint32 index, SLInterfaceID *pInterfaceId)
1170{
1171    SL_ENTER_GLOBAL
1172
1173    if (NULL == pInterfaceId) {
1174        result = SL_RESULT_PARAMETER_INVALID;
1175    } else {
1176        *pInterfaceId = NULL;
1177        const ClassTable *class__ = objectIDtoClass(SL_OBJECTID_ENGINE);
1178        assert(NULL != class__);
1179        result = SL_RESULT_PARAMETER_INVALID;   // will be reset later
1180        SLuint32 i;
1181        for (i = 0; i < class__->mInterfaceCount; ++i) {
1182            switch (class__->mInterfaces[i].mInterface) {
1183            case INTERFACE_IMPLICIT:
1184            case INTERFACE_EXPLICIT:
1185            case INTERFACE_DYNAMIC:
1186                break;
1187            case INTERFACE_UNAVAILABLE:
1188                continue;
1189            default:
1190                assert(false);
1191                break;
1192            }
1193            if (index == 0) {
1194                // The engine has no aliases, but if it did, this would return only the primary
1195                *pInterfaceId = &SL_IID_array[class__->mInterfaces[i].mMPH];
1196                result = SL_RESULT_SUCCESS;
1197                break;
1198            }
1199            --index;
1200        }
1201    }
1202
1203    SL_LEAVE_GLOBAL
1204}
1205