sles.cpp revision b7154f2324c8ae44b820c07c69aaa80a4bb9e418
1773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi/*
2773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * Copyright (C) 2010 The Android Open Source Project
3773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi *
4773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
5773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * you may not use this file except in compliance with the License.
6773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * You may obtain a copy of the License at
7773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi *
8773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
9773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi *
10773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
11773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
12773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * See the License for the specific language governing permissions and
14773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi * limitations under the License.
15773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi */
16d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
17d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten/* OpenSL ES prototype */
18d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
19773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi#include "sles_allinclusive.h"
20c116ab2a033ee7dc78cfd458defe38d4528383a8Jean-Michel Trivi#include "sles_check_audioplayer_ext.h"
21bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
22d20441ee29747b206cb0d197260c3ac78d7762daGlenn Kasten#ifdef USE_ANDROID
23773e0429cbb9e85b4f1c6eb5a095ccd7b57f5ba4Jean-Michel Trivi#include "sles_to_android_ext.h"
242045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten#endif
25d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
26bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten/* Private functions */
27bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
28b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// Map an IObject to it's "object ID" (which is really a class ID)
29b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
30b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn KastenSLuint32 IObjectToObjectID(IObject *this)
31b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
32b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    assert(NULL != this);
33b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    return this->mClass->mObjectID;
34b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
35b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
36bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Map SLInterfaceID to its minimal perfect hash (MPH), or -1 if unknown
37bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
3861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/*static*/ int IID_to_MPH(const SLInterfaceID iid)
39d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
40bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (&SL_IID_array[0] <= iid && &SL_IID_array[MPH_MAX] > iid)
41bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        return iid - &SL_IID_array[0];
42bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (NULL != iid) {
43bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        // FIXME Replace this linear search by a good MPH algorithm
44bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        const struct SLInterfaceID_ *srch = &SL_IID_array[0];
45bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        unsigned MPH;
46bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        for (MPH = 0; MPH < MPH_MAX; ++MPH, ++srch)
47bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            if (!memcmp(iid, srch, sizeof(struct SLInterfaceID_)))
48bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                return MPH;
49bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
50bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    return -1;
51bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
52bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
5329b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten// Check the interface IDs passed into a Create operation
5429b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten
55979a3f8743646af9999a89dff9e13b972b7efd87Glenn KastenSLresult checkInterfaces(const ClassTable *class__,
56bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds,
57bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    const SLboolean *pInterfaceRequired, unsigned *pExposedMask)
58bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
59bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    assert(NULL != class__ && NULL != pExposedMask);
60bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    unsigned exposedMask = 0;
61bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    const struct iid_vtable *interfaces = class__->mInterfaces;
62bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 interfaceCount = class__->mInterfaceCount;
63bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 i;
64bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    // FIXME This section could be pre-computed per class
65bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    for (i = 0; i < interfaceCount; ++i) {
66bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        switch (interfaces[i].mInterface) {
67bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        case INTERFACE_IMPLICIT:
68bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            exposedMask |= 1 << i;
69bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            break;
70bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        default:
71bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            break;
72bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        }
73bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
74d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    if (0 < numInterfaces) {
75d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        if (NULL == pInterfaceIds || NULL == pInterfaceRequired)
76d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten            return SL_RESULT_PARAMETER_INVALID;
77d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        for (i = 0; i < numInterfaces; ++i) {
78bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            SLInterfaceID iid = pInterfaceIds[i];
79bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            if (NULL == iid)
80bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                return SL_RESULT_PARAMETER_INVALID;
8129b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            int MPH, index;
8229b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            if ((0 > (MPH = IID_to_MPH(iid))) ||
8329b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten                (0 > (index = class__->mMPH_to_index[MPH]))) {
84bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                if (pInterfaceRequired[i])
85bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    return SL_RESULT_FEATURE_UNSUPPORTED;
86bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                continue;
87bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            }
8829b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // FIXME this seems a bit strong? what is correct logic?
8929b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // we are requesting a duplicate explicit interface,
9029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // or we are requesting one which is already implicit ?
9129b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // if (exposedMask & (1 << index))
9229b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            //    return SL_RESULT_PARAMETER_INVALID;
9329b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            exposedMask |= (1 << index);
94d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        }
95d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    }
96bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    *pExposedMask = exposedMask;
97d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
98d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
99d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
10061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten// private helper shared by decoder and encoder
10161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn KastenSLresult GetCodecCapabilities(SLuint32 decoderId, SLuint32 *pIndex,
10261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLAudioCodecDescriptor *pDescriptor,
10361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const struct CodecDescriptor *codecDescriptors)
104bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
10561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pIndex)
10661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
10761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const struct CodecDescriptor *cd = codecDescriptors;
10861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLuint32 index;
10961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pDescriptor) {
11061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        for (index = 0 ; NULL != cd->mDescriptor; ++cd)
11161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            if (cd->mCodecID == decoderId)
11261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                ++index;
11361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        *pIndex = index;
11461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_SUCCESS;
11561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
11661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    index = *pIndex;
11761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    for ( ; NULL != cd->mDescriptor; ++cd) {
11861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        if (cd->mCodecID == decoderId) {
11961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            if (0 == index) {
12061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                *pDescriptor = *cd->mDescriptor;
12161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                return SL_RESULT_SUCCESS;
12261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            }
12361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            --index;
12461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
12561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
12661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_PARAMETER_INVALID;
127bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
1282045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
12961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/* Interface initialization hooks */
1302045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
131a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenextern void
132a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DCommit_init(void *),
133a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DDoppler_init(void *),
134a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DGrouping_init(void *),
135a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DLocation_init(void *),
136a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DMacroscopic_init(void *),
137a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DSource_init(void *),
13861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioDecoderCapabilities_init(void *),
13961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioEncoderCapabilities_init(void *),
14061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioEncoder_init(void *),
14161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioIODeviceCapabilities_init(void *),
142a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IBassBoost_init(void *),
1430b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IBufferQueue_init(void *),
14461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDeviceVolume_init(void *),
14561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicInterfaceManagement_init(void *),
14661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicSource_init(void *),
14761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_init(void *),
1480b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IEngineCapabilities_init(void *),
1490b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IEngine_init(void *),
150a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IEnvironmentalReverb_init(void *),
151a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IEqualizer_init(void *),
15261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    ILEDArray_init(void *),
1530b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDIMessage_init(void *),
1540b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDIMuteSolo_init(void *),
1550b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDITempo_init(void *),
1560b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDITime_init(void *),
15761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IMetadataExtraction_init(void *),
15861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IMetadataTraversal_init(void *),
15961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IMuteSolo_init(void *),
16061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_init(void *),
1610b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IOutputMix_init(void *),
16261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IPitch_init(void *),
1630b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_init(void *),
16461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IPlaybackRate_init(void *),
16561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IPrefetchStatus_init(void *),
166a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IPresetReverb_init(void *),
16761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IRatePitch_init(void *),
16861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IRecord_init(void *),
1690b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    ISeek_init(void *),
17061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IThreadSync_init(void *),
17161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IVibra_init(void *),
172a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IVirtualizer_init(void *),
1730b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IVisualization_init(void *),
1740b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IVolume_init(void *);
175a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
176b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#ifdef USE_OUTPUTMIXEXT
177b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenextern void
178b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt_init(void *);
179b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif
180b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
18161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/*static*/ const struct MPH_init MPH_init_table[MPH_MAX] = {
182a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DCOMMIT, */ I3DCommit_init, NULL },
183a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DDOPPLER, */ I3DDoppler_init, NULL },
184a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DGROUPING, */ I3DGrouping_init, NULL },
185a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DLOCATION, */ I3DLocation_init, NULL },
186a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DMACROSCOPIC, */ I3DMacroscopic_init, NULL },
187a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DSOURCE, */ I3DSource_init, NULL },
18861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIODECODERCAPABILITIES, */ IAudioDecoderCapabilities_init, NULL },
18961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIOENCODER, */ IAudioEncoder_init, NULL },
19061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIOENCODERCAPABILITIES, */ IAudioEncoderCapabilities_init, NULL },
19161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIOIODEVICECAPABILITIES, */ IAudioIODeviceCapabilities_init,
192bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        NULL },
193a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_BASSBOOST, */ IBassBoost_init, NULL },
1940b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_BUFFERQUEUE, */ IBufferQueue_init, NULL },
19561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_DEVICEVOLUME, */ IDeviceVolume_init, NULL },
19661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_DYNAMICINTERFACEMANAGEMENT, */ IDynamicInterfaceManagement_init,
197bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        NULL },
19861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_DYNAMICSOURCE, */ IDynamicSource_init, NULL },
19961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_EFFECTSEND, */ IEffectSend_init, NULL },
2000b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_ENGINE, */ IEngine_init, NULL },
2010b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_ENGINECAPABILITIES, */ IEngineCapabilities_init, NULL },
202a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_ENVIRONMENTALREVERB, */ IEnvironmentalReverb_init, NULL },
203a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_EQUALIZER, */ IEqualizer_init, NULL },
20461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_LED, */ ILEDArray_init, NULL },
20561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_METADATAEXTRACTION, */ IMetadataExtraction_init, NULL },
20661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_METADATATRAVERSAL, */ IMetadataTraversal_init, NULL },
2070b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDIMESSAGE, */ IMIDIMessage_init, NULL },
2080b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDITIME, */ IMIDITime_init, NULL },
2090b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDITEMPO, */ IMIDITempo_init, NULL },
2100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDIMUTESOLO, */ IMIDIMuteSolo_init, NULL },
21161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_MUTESOLO, */ IMuteSolo_init, NULL },
212bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    { /* MPH_NULL, */ NULL, NULL },
21361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_OBJECT, */ IObject_init, NULL },
2140b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_OUTPUTMIX, */ IOutputMix_init, NULL },
21561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_PITCH, */ IPitch_init, NULL },
2160b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_PLAY, */ IPlay_init, NULL },
21761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_PLAYBACKRATE, */ IPlaybackRate_init, NULL },
21861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_PREFETCHSTATUS, */ IPrefetchStatus_init, NULL },
219a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_PRESETREVERB, */ IPresetReverb_init, NULL },
22061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_RATEPITCH, */ IRatePitch_init, NULL },
22161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_RECORD, */ IRecord_init, NULL },
2220b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_SEEK, */ ISeek_init, NULL },
22361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_THREADSYNC, */ IThreadSync_init, NULL },
22461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_VIBRA, */ IVibra_init, NULL },
225a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_VIRTUALIZER, */ IVirtualizer_init, NULL },
226a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_VISUALIZATION, */ IVisualization_init, NULL },
2270b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_VOLUME, */ IVolume_init, NULL },
228bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    { /* MPH_OUTPUTMIXEXT, */
229bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifdef USE_OUTPUTMIXEXT
230b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        IOutputMixExt_init, NULL
231bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#else
232bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        NULL, NULL
233bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
234bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        }
235bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
236bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
237bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Construct a new instance of the specified class, exposing selected interfaces
238bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
239979a3f8743646af9999a89dff9e13b972b7efd87Glenn KastenIObject *construct(const ClassTable *class__,
24029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    unsigned exposedMask, SLEngineItf engine)
241bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
24272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    IObject *this;
243bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifndef NDEBUG
24472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    this = (IObject *) malloc(class__->mSize);
245bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#else
24672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    this = (IObject *) calloc(1, class__->mSize);
247bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
248bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (NULL != this) {
249bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifndef NDEBUG
250bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        // for debugging, to detect uninitialized fields
251bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        memset(this, 0x55, class__->mSize);
252bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
25329b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten        this->mClass = class__;
25429b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten        this->mExposedMask = exposedMask;
25572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        unsigned lossOfControlMask = 0;
25672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        IEngine *thisEngine = (IEngine *) engine;
25772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        if (NULL == thisEngine)
25872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            thisEngine = &((CEngine *) this)->mEngine;
25972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        else if (thisEngine->mLossOfControlGlobal)
26072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            lossOfControlMask = ~0;
26172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        this->mLossOfControlMask = lossOfControlMask;
262bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        const struct iid_vtable *x = class__->mInterfaces;
263bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        unsigned i;
264bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        for (i = 0; exposedMask; ++i, ++x, exposedMask >>= 1) {
265bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            if (exposedMask & 1) {
26683f93b0afd3607b1570d8473c2f6e45276c133baGlenn Kasten                void *self = (char *) this + x->mOffset;
26772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten                ((IObject **) self)[1] = this;
26883f93b0afd3607b1570d8473c2f6e45276c133baGlenn Kasten                VoidHook init = MPH_init_table[x->mMPH].mInit;
269bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                if (NULL != init)
270bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    (*init)(self);
271bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            }
272bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        }
27372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        // FIXME need a lock
27472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        if (INSTANCE_MAX > thisEngine->mInstanceCount) {
27572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            // FIXME ignores Destroy
27672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            thisEngine->mInstances[thisEngine->mInstanceCount++] = this;
27772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        }
27872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        // FIXME else what
279bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
280bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    return this;
281bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
282bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
283b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// The sync thread runs periodically to synchronize audio state between
284b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// the application and platform-specific device driver; for best results
285b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// it should run about every graphics frame (e.g. 20 Hz to 50 Hz).
286d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
287b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void *sync_body(void *arg)
288d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
2890b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    CEngine *this = (CEngine *) arg;
2900b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    for (;;) {
2910b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        usleep(20000*50);
2920b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        unsigned i;
2930b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        for (i = 0; i < INSTANCE_MAX; ++i) {
2940b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            IObject *instance = (IObject *) this->mEngine.mInstances[i];
2950b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            if (NULL == instance)
2960b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                continue;
297b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            switch (IObjectToObjectID(instance)) {
298b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            case SL_OBJECTID_AUDIOPLAYER:
299b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                write(1, ".", 1);
300b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                break;
301b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            default:
302b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                break;
303b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
3040b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        }
3052045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
3060b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    return NULL;
307d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
308d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
3090b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/* Initial entry points */
310d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
3110b167267bda99b68346045ccab14e810121d5de4Glenn KastenSLresult SLAPIENTRY slCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions,
3120b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    const SLEngineOption *pEngineOptions, SLuint32 numInterfaces,
3130b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
314d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
3150b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == pEngine)
316d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
3170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    *pEngine = NULL;
3180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // default values
3190b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLboolean threadSafe = SL_BOOLEAN_TRUE;
3200b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLboolean lossOfControlGlobal = SL_BOOLEAN_FALSE;
3210b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL != pEngineOptions) {
3220b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        SLuint32 i;
3230b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        const SLEngineOption *option = pEngineOptions;
3240b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        for (i = 0; i < numOptions; ++i, ++option) {
3250b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            switch (option->feature) {
3260b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            case SL_ENGINEOPTION_THREADSAFE:
3270b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                threadSafe = (SLboolean) option->data;
3280b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                break;
3290b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            case SL_ENGINEOPTION_LOSSOFCONTROL:
3300b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                lossOfControlGlobal = (SLboolean) option->data;
3310b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                break;
3320b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            default:
3330b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                return SL_RESULT_PARAMETER_INVALID;
3340b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            }
3350b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        }
33629b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    }
3370b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    unsigned exposedMask;
338b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    const ClassTable *pCEngine_class = objectIDtoClass(SL_OBJECTID_ENGINE);
339b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLresult result = checkInterfaces(pCEngine_class, numInterfaces,
3400b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        pInterfaceIds, pInterfaceRequired, &exposedMask);
3410b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (SL_RESULT_SUCCESS != result)
3420b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        return result;
343b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    CEngine *this = (CEngine *) construct(pCEngine_class, exposedMask, NULL);
3440b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == this)
3450b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        return SL_RESULT_MEMORY_FAILURE;
3460b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    this->mObject.mLossOfControlMask = lossOfControlGlobal ? ~0 : 0;
3470b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    this->mEngine.mLossOfControlGlobal = lossOfControlGlobal;
3480b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    this->mEngineCapabilities.mThreadSafe = threadSafe;
3490b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    int ok;
350b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    ok = pthread_create(&this->mSyncThread, (const pthread_attr_t *) NULL, sync_body, this);
3510b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    assert(ok == 0);
3520b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    *pEngine = &this->mObject.mItf;
353d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
354d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
355d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
3560b167267bda99b68346045ccab14e810121d5de4Glenn KastenSLresult SLAPIENTRY slQueryNumSupportedEngineInterfaces(
3570b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLuint32 *pNumSupportedInterfaces)
358d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
3590b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == pNumSupportedInterfaces)
3602045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_RESULT_PARAMETER_INVALID;
361b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    const ClassTable *pCEngine_class = objectIDtoClass(SL_OBJECTID_ENGINE);
362b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    *pNumSupportedInterfaces = pCEngine_class->mInterfaceCount;
363d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
364d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
365d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
3660b167267bda99b68346045ccab14e810121d5de4Glenn KastenSLresult SLAPIENTRY slQuerySupportedEngineInterfaces(SLuint32 index,
3670b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLInterfaceID *pInterfaceId)
368d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
3690b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == pInterfaceId)
3702045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_RESULT_PARAMETER_INVALID;
371b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    const ClassTable *pCEngine_class = objectIDtoClass(SL_OBJECTID_ENGINE);
372b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    if (pCEngine_class->mInterfaceCount <= index)
373b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        return SL_RESULT_PARAMETER_INVALID;
374b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    *pInterfaceId = &SL_IID_array[pCEngine_class->mInterfaces[index].mMPH];
375d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
376d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
377d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
378d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten/* End */
379