sles.c revision 0b167267bda99b68346045ccab14e810121d5de4
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
26d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten/* Forward declarations */
27d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
28bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenextern const struct SLInterfaceID_ SL_IID_array[MPH_MAX];
29bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
30bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten/* Private functions */
31bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
32bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Map SLInterfaceID to its minimal perfect hash (MPH), or -1 if unknown
33bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
3461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/*static*/ int IID_to_MPH(const SLInterfaceID iid)
35d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
36bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (&SL_IID_array[0] <= iid && &SL_IID_array[MPH_MAX] > iid)
37bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        return iid - &SL_IID_array[0];
38bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (NULL != iid) {
39bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        // FIXME Replace this linear search by a good MPH algorithm
40bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        const struct SLInterfaceID_ *srch = &SL_IID_array[0];
41bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        unsigned MPH;
42bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        for (MPH = 0; MPH < MPH_MAX; ++MPH, ++srch)
43bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            if (!memcmp(iid, srch, sizeof(struct SLInterfaceID_)))
44bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                return MPH;
45bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
46bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    return -1;
47bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
48bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
4929b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten// Check the interface IDs passed into a Create operation
5029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten
5172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kastenstatic SLresult checkInterfaces(const ClassTable *class__,
52bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds,
53bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    const SLboolean *pInterfaceRequired, unsigned *pExposedMask)
54bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
55bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    assert(NULL != class__ && NULL != pExposedMask);
56bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    unsigned exposedMask = 0;
57bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    const struct iid_vtable *interfaces = class__->mInterfaces;
58bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 interfaceCount = class__->mInterfaceCount;
59bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 i;
60bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    // FIXME This section could be pre-computed per class
61bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    for (i = 0; i < interfaceCount; ++i) {
62bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        switch (interfaces[i].mInterface) {
63bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        case INTERFACE_IMPLICIT:
64bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            exposedMask |= 1 << i;
65bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            break;
66bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        default:
67bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            break;
68bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        }
69bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
70d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    if (0 < numInterfaces) {
71d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        if (NULL == pInterfaceIds || NULL == pInterfaceRequired)
72d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten            return SL_RESULT_PARAMETER_INVALID;
73d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        for (i = 0; i < numInterfaces; ++i) {
74bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            SLInterfaceID iid = pInterfaceIds[i];
75bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            if (NULL == iid)
76bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                return SL_RESULT_PARAMETER_INVALID;
7729b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            int MPH, index;
7829b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            if ((0 > (MPH = IID_to_MPH(iid))) ||
7929b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten                (0 > (index = class__->mMPH_to_index[MPH]))) {
80bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                if (pInterfaceRequired[i])
81bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    return SL_RESULT_FEATURE_UNSUPPORTED;
82bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                continue;
83bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            }
8429b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // FIXME this seems a bit strong? what is correct logic?
8529b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // we are requesting a duplicate explicit interface,
8629b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // or we are requesting one which is already implicit ?
8729b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // if (exposedMask & (1 << index))
8829b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            //    return SL_RESULT_PARAMETER_INVALID;
8929b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            exposedMask |= (1 << index);
90d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        }
91d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    }
92bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    *pExposedMask = exposedMask;
93d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
94d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
95d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten// private helper shared by decoder and encoder
9761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn KastenSLresult GetCodecCapabilities(SLuint32 decoderId, SLuint32 *pIndex,
9861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLAudioCodecDescriptor *pDescriptor,
9961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const struct CodecDescriptor *codecDescriptors)
100bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
10161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pIndex)
10261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
10361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const struct CodecDescriptor *cd = codecDescriptors;
10461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLuint32 index;
10561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pDescriptor) {
10661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        for (index = 0 ; NULL != cd->mDescriptor; ++cd)
10761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            if (cd->mCodecID == decoderId)
10861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                ++index;
10961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        *pIndex = index;
11061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_SUCCESS;
11161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
11261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    index = *pIndex;
11361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    for ( ; NULL != cd->mDescriptor; ++cd) {
11461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        if (cd->mCodecID == decoderId) {
11561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            if (0 == index) {
11661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                *pDescriptor = *cd->mDescriptor;
11761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                return SL_RESULT_SUCCESS;
11861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            }
11961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            --index;
12061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
12161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
12261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_PARAMETER_INVALID;
123bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
1242045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
12561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/* Interface initialization hooks */
1262045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
127bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifdef USE_OUTPUTMIXEXT
128d20441ee29747b206cb0d197260c3ac78d7762daGlenn Kastenextern const struct SLOutputMixExtItf_ OutputMixExt_OutputMixExtItf;
129d20441ee29747b206cb0d197260c3ac78d7762daGlenn Kasten
130bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic void OutputMixExt_init(void *self)
131d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
13272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    IOutputMixExt *this =
13372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        (IOutputMixExt *) self;
134bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    this->mItf = &OutputMixExt_OutputMixExtItf;
135d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
136bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif // USE_OUTPUTMIXEXT
137d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
138a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten#ifdef __cplusplus
139a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenextern "C" {
140a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten#endif
141a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
142a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenextern void
143a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DCommit_init(void *),
144a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DDoppler_init(void *),
145a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DGrouping_init(void *),
146a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DLocation_init(void *),
147a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DMacroscopic_init(void *),
148a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    I3DSource_init(void *),
14961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioDecoderCapabilities_init(void *),
15061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioEncoderCapabilities_init(void *),
15161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioEncoder_init(void *),
15261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IAudioIODeviceCapabilities_init(void *),
153a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IBassBoost_init(void *),
1540b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IBufferQueue_init(void *),
15561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDeviceVolume_init(void *),
15661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicInterfaceManagement_init(void *),
15761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicSource_init(void *),
15861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IEffectSend_init(void *),
1590b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IEngineCapabilities_init(void *),
1600b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IEngine_init(void *),
161a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IEnvironmentalReverb_init(void *),
162a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IEqualizer_init(void *),
16361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    ILEDArray_init(void *),
1640b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDIMessage_init(void *),
1650b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDIMuteSolo_init(void *),
1660b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDITempo_init(void *),
1670b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IMIDITime_init(void *),
16861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IMetadataExtraction_init(void *),
16961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IMetadataTraversal_init(void *),
17061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IMuteSolo_init(void *),
17161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_init(void *),
1720b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IOutputMix_init(void *),
17361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IPitch_init(void *),
1740b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_init(void *),
17561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IPlaybackRate_init(void *),
17661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IPrefetchStatus_init(void *),
177a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IPresetReverb_init(void *),
17861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IRatePitch_init(void *),
17961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IRecord_init(void *),
1800b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    ISeek_init(void *),
18161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IThreadSync_init(void *),
18261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IVibra_init(void *),
183a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    IVirtualizer_init(void *),
1840b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IVisualization_init(void *),
1850b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IVolume_init(void *);
186a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
187a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten#ifdef __cplusplus
188a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
189a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten#endif
190a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
19161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/*static*/ const struct MPH_init MPH_init_table[MPH_MAX] = {
192a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DCOMMIT, */ I3DCommit_init, NULL },
193a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DDOPPLER, */ I3DDoppler_init, NULL },
194a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DGROUPING, */ I3DGrouping_init, NULL },
195a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DLOCATION, */ I3DLocation_init, NULL },
196a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DMACROSCOPIC, */ I3DMacroscopic_init, NULL },
197a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_3DSOURCE, */ I3DSource_init, NULL },
19861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIODECODERCAPABILITIES, */ IAudioDecoderCapabilities_init, NULL },
19961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIOENCODER, */ IAudioEncoder_init, NULL },
20061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIOENCODERCAPABILITIES, */ IAudioEncoderCapabilities_init, NULL },
20161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_AUDIOIODEVICECAPABILITIES, */ IAudioIODeviceCapabilities_init,
202bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        NULL },
203a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_BASSBOOST, */ IBassBoost_init, NULL },
2040b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_BUFFERQUEUE, */ IBufferQueue_init, NULL },
20561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_DEVICEVOLUME, */ IDeviceVolume_init, NULL },
20661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_DYNAMICINTERFACEMANAGEMENT, */ IDynamicInterfaceManagement_init,
207bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        NULL },
20861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_DYNAMICSOURCE, */ IDynamicSource_init, NULL },
20961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_EFFECTSEND, */ IEffectSend_init, NULL },
2100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_ENGINE, */ IEngine_init, NULL },
2110b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_ENGINECAPABILITIES, */ IEngineCapabilities_init, NULL },
212a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_ENVIRONMENTALREVERB, */ IEnvironmentalReverb_init, NULL },
213a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_EQUALIZER, */ IEqualizer_init, NULL },
21461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_LED, */ ILEDArray_init, NULL },
21561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_METADATAEXTRACTION, */ IMetadataExtraction_init, NULL },
21661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_METADATATRAVERSAL, */ IMetadataTraversal_init, NULL },
2170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDIMESSAGE, */ IMIDIMessage_init, NULL },
2180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDITIME, */ IMIDITime_init, NULL },
2190b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDITEMPO, */ IMIDITempo_init, NULL },
2200b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_MIDIMUTESOLO, */ IMIDIMuteSolo_init, NULL },
22161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_MUTESOLO, */ IMuteSolo_init, NULL },
222bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    { /* MPH_NULL, */ NULL, NULL },
22361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_OBJECT, */ IObject_init, NULL },
2240b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_OUTPUTMIX, */ IOutputMix_init, NULL },
22561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_PITCH, */ IPitch_init, NULL },
2260b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_PLAY, */ IPlay_init, NULL },
22761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_PLAYBACKRATE, */ IPlaybackRate_init, NULL },
22861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_PREFETCHSTATUS, */ IPrefetchStatus_init, NULL },
229a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_PRESETREVERB, */ IPresetReverb_init, NULL },
23061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_RATEPITCH, */ IRatePitch_init, NULL },
23161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_RECORD, */ IRecord_init, NULL },
2320b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_SEEK, */ ISeek_init, NULL },
23361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_THREADSYNC, */ IThreadSync_init, NULL },
23461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    { /* MPH_VIBRA, */ IVibra_init, NULL },
235a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_VIRTUALIZER, */ IVirtualizer_init, NULL },
236a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    { /* MPH_VISUALIZATION, */ IVisualization_init, NULL },
2370b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    { /* MPH_VOLUME, */ IVolume_init, NULL },
238bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    { /* MPH_OUTPUTMIXEXT, */
239bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifdef USE_OUTPUTMIXEXT
240bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        OutputMixExt_init, NULL
241bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#else
242bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        NULL, NULL
243bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
244bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        }
245bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
246bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
247bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten/* Classes vs. interfaces */
248bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
249bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// 3DGroup class
250bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
251bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable _3DGroup_interfaces[] = {
252bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
25372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, mObject)},
254bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
25572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, mDynamicInterfaceManagement)},
256bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DLOCATION, INTERFACE_IMPLICIT,
25772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DLocation)},
258bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DDOPPLER, INTERFACE_DYNAMIC_GAME,
25972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DDoppler)},
260bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DSOURCE, INTERFACE_GAME,
26172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DSource)},
262bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DMACROSCOPIC, INTERFACE_OPTIONAL,
26372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DMacroscopic)},
264bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
265bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
266a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten/*static*/ const ClassTable C3DGroup_class = {
267bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    _3DGroup_interfaces,
268bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(_3DGroup_interfaces)/sizeof(_3DGroup_interfaces[0]),
269bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_3DGroup,
270bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"3DGroup",
27172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(C3DGroup),
272bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_3DGROUP,
273bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
27472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    NULL,
275bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
276d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten};
277d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
278bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// AudioPlayer class
279bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
280bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten/* AudioPlayer private functions */
2812045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
2822045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten#ifdef USE_SNDFILE
2832045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
2842045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten// FIXME should run this asynchronously esp. for socket fd, not on mix thread
2852045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kastenstatic void SLAPIENTRY SndFile_Callback(SLBufferQueueItf caller, void *pContext)
2862045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten{
2872045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    struct SndFile *this = (struct SndFile *) pContext;
2882045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    SLresult result;
2892045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    if (NULL != this->mRetryBuffer && 0 < this->mRetrySize) {
290bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        result = (*caller)->Enqueue(caller, this->mRetryBuffer,
291bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            this->mRetrySize);
2922045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (SL_RESULT_BUFFER_INSUFFICIENT == result)
2932045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            return;     // what, again?
2942045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        assert(SL_RESULT_SUCCESS == result);
2952045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        this->mRetryBuffer = NULL;
2962045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        this->mRetrySize = 0;
2972045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return;
2982045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
2992045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    short *pBuffer = this->mIs0 ? this->mBuffer0 : this->mBuffer1;
3002045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    this->mIs0 ^= SL_BOOLEAN_TRUE;
3012045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    sf_count_t count;
3022045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // FIXME magic number
3032045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    count = sf_read_short(this->mSNDFILE, pBuffer, (sf_count_t) 512);
3042045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    if (0 < count) {
3052045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        SLuint32 size = count * sizeof(short);
3062045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        // FIXME if we had an internal API, could call this directly
3072045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        result = (*caller)->Enqueue(caller, pBuffer, size);
3082045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (SL_RESULT_BUFFER_INSUFFICIENT == result) {
3092045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            this->mRetryBuffer = pBuffer;
3102045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            this->mRetrySize = size;
3112045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            return;
3122045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        }
3132045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        assert(SL_RESULT_SUCCESS == result);
3142045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
3152045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten}
3162045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
3172045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kastenstatic SLboolean SndFile_IsSupported(const SF_INFO *sfinfo)
3182045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten{
3192045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    switch (sfinfo->format & SF_FORMAT_TYPEMASK) {
3202045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    case SF_FORMAT_WAV:
3212045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        break;
3222045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    default:
3232045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_BOOLEAN_FALSE;
3242045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
3252045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    switch (sfinfo->format & SF_FORMAT_SUBMASK) {
3262045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    case SF_FORMAT_PCM_16:
3272045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        break;
3282045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    default:
3292045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_BOOLEAN_FALSE;
3302045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
3312045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    switch (sfinfo->samplerate) {
3322045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    case 44100:
3332045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        break;
3342045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    default:
3352045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_BOOLEAN_FALSE;
3362045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
3372045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    switch (sfinfo->channels) {
3382045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    case 2:
3392045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        break;
3402045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    default:
3412045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_BOOLEAN_FALSE;
3422045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
3432045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    return SL_BOOLEAN_TRUE;
3442045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten}
3452045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
346bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif // USE_SNDFILE
3472045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
348a852e9eca77c64fcba11eb590bec7a11aca5fe16Jean-Michel Trivi
349bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic SLresult AudioPlayer_Realize(void *self)
350bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
35172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    CAudioPlayer *this = (CAudioPlayer *) self;
352bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLresult result = SL_RESULT_SUCCESS;
35348913d4519d5112319c4277d4966435fec2f551cJean-Michel Trivi
354a852e9eca77c64fcba11eb590bec7a11aca5fe16Jean-Michel Trivi#ifdef USE_ANDROID
355a852e9eca77c64fcba11eb590bec7a11aca5fe16Jean-Michel Trivi    // FIXME move this to android specific files
35648913d4519d5112319c4277d4966435fec2f551cJean-Michel Trivi    result = sles_to_android_realizeAudioPlayer(this);
357a852e9eca77c64fcba11eb590bec7a11aca5fe16Jean-Michel Trivi#endif
358a852e9eca77c64fcba11eb590bec7a11aca5fe16Jean-Michel Trivi
359bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifdef USE_SNDFILE
3602045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    if (NULL != this->mSndFile.mPathname) {
3612045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        SF_INFO sfinfo;
3622045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        sfinfo.format = 0;
3632045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        this->mSndFile.mSNDFILE = sf_open(
3642045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            (const char *) this->mSndFile.mPathname, SFM_READ, &sfinfo);
3652045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (NULL == this->mSndFile.mSNDFILE) {
3662045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            result = SL_RESULT_CONTENT_NOT_FOUND;
3672045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        } else if (!SndFile_IsSupported(&sfinfo)) {
3682045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            sf_close(this->mSndFile.mSNDFILE);
3692045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            this->mSndFile.mSNDFILE = NULL;
3702045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            result = SL_RESULT_CONTENT_UNSUPPORTED;
3712045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        } else {
37229b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // FIXME how do we know this interface is exposed?
373bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            SLBufferQueueItf bufferQueue = &this->mBufferQueue.mItf;
3742045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            // FIXME should use a private internal API, and disallow
3752045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            // application to have access to our buffer queue
3762045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            // FIXME if we had an internal API, could call this directly
37729b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // FIXME can't call this directly as we get a double lock
37829b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // result = (*bufferQueue)->RegisterCallback(bufferQueue,
37929b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            //    SndFile_Callback, &this->mSndFile);
38029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // FIXME so let's inline the code, but this is maintenance risk
38129b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // we know we are called by Object_Realize, which holds a lock,
38229b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            // but if interface lock != object lock, need to rewrite this
38372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            IBufferQueue *thisBQ =
38472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten                (IBufferQueue *) bufferQueue;
38529b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            thisBQ->mCallback = SndFile_Callback;
38629b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten            thisBQ->mContext = &this->mSndFile;
3872045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        }
3882045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
389bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif // USE_SNDFILE
3902045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    return result;
3912045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten}
3922045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
393bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic void AudioPlayer_Destroy(void *self)
3942045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten{
39572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    CAudioPlayer *this = (CAudioPlayer *) self;
3962045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // FIXME stop the player in a way that app can't restart it
397bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    // Free the buffer queue, if it was larger than typical
398bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (NULL != this->mBufferQueue.mArray &&
399bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        this->mBufferQueue.mArray != this->mBufferQueue.mTypical) {
4002045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        free(this->mBufferQueue.mArray);
401bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        this->mBufferQueue.mArray = NULL;
402bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
4032045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten#ifdef USE_SNDFILE
4042045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    if (NULL != this->mSndFile.mSNDFILE) {
4052045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        sf_close(this->mSndFile.mSNDFILE);
4062045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        this->mSndFile.mSNDFILE = NULL;
4072045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
408bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif // USE_SNDFILE
409bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
410bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
411bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable AudioPlayer_interfaces[] = {
412bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
41372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mObject)},
414bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
41572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mDynamicInterfaceManagement)},
416bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PLAY, INTERFACE_IMPLICIT,
41772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mPlay)},
418bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DDOPPLER, INTERFACE_DYNAMIC_GAME,
41972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, m3DDoppler)},
420bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DGROUPING, INTERFACE_GAME,
42172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, m3DGrouping)},
422bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DLOCATION, INTERFACE_GAME,
42372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, m3DLocation)},
424bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DSOURCE, INTERFACE_GAME,
42572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, m3DSource)},
426bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    // FIXME Currently we create an internal buffer queue for playing files
427bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_BUFFERQUEUE, /* INTERFACE_GAME */ INTERFACE_IMPLICIT,
42872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mBufferQueue)},
429bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_EFFECTSEND, INTERFACE_MUSIC_GAME,
43072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mEffectSend)},
431bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_MUTESOLO, INTERFACE_GAME,
43272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mMuteSolo)},
433bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_METADATAEXTRACTION, INTERFACE_MUSIC_GAME,
43472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mMetadataExtraction)},
435bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_METADATATRAVERSAL, INTERFACE_MUSIC_GAME,
43672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mMetadataTraversal)},
437bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PREFETCHSTATUS, INTERFACE_TBD,
43872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mPrefetchStatus)},
439bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_RATEPITCH, INTERFACE_DYNAMIC_GAME,
44072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mRatePitch)},
441bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_SEEK, INTERFACE_TBD,
44272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mSeek)},
443bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VOLUME, INTERFACE_TBD,
44472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mVolume)},
445bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DMACROSCOPIC, INTERFACE_OPTIONAL,
44672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, m3DMacroscopic)},
447bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_BASSBOOST, INTERFACE_OPTIONAL,
44872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mBassBoost)},
449bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICSOURCE, INTERFACE_OPTIONAL,
45072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mDynamicSource)},
451bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_ENVIRONMENTALREVERB, INTERFACE_OPTIONAL,
45272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mEnvironmentalReverb)},
453bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_EQUALIZER, INTERFACE_OPTIONAL,
45472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mEqualizer)},
455bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PITCH, INTERFACE_OPTIONAL,
45672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mPitch)},
457bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PRESETREVERB, INTERFACE_OPTIONAL,
45872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mPresetReverb)},
459bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PLAYBACKRATE, INTERFACE_OPTIONAL,
46072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mPlaybackRate)},
461bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VIRTUALIZER, INTERFACE_OPTIONAL,
46272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mVirtualizer)},
463bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VISUALIZATION, INTERFACE_OPTIONAL,
46472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioPlayer, mVisualization)}
465bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
466bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
467a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CAudioPlayer_class = {
468bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    AudioPlayer_interfaces,
469bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(AudioPlayer_interfaces)/sizeof(AudioPlayer_interfaces[0]),
470bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_AudioPlayer,
471bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"AudioPlayer",
47272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CAudioPlayer),
473bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_AUDIOPLAYER,
474bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    AudioPlayer_Realize,
47529b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL /*AudioPlayer_Resume*/,
476bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    AudioPlayer_Destroy
477bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
478bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
479bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// AudioRecorder class
480bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
481bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable AudioRecorder_interfaces[] = {
482bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
48372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mObject)},
484bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
48572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mDynamicInterfaceManagement)},
486bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_RECORD, INTERFACE_IMPLICIT,
48772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mRecord)},
488bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_AUDIOENCODER, INTERFACE_TBD,
48972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mAudioEncoder)},
490bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_BASSBOOST, INTERFACE_OPTIONAL,
49172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mBassBoost)},
492bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICSOURCE, INTERFACE_OPTIONAL,
49372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mDynamicSource)},
494bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_EQUALIZER, INTERFACE_OPTIONAL,
49572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mEqualizer)},
496bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VISUALIZATION, INTERFACE_OPTIONAL,
49772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mVisualization)},
498bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VOLUME, INTERFACE_OPTIONAL,
49972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CAudioRecorder, mVolume)}
500bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
501bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
502a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CAudioRecorder_class = {
503bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    AudioRecorder_interfaces,
504bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(AudioRecorder_interfaces)/sizeof(AudioRecorder_interfaces[0]),
505bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_AudioRecorder,
506bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"AudioRecorder",
50772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CAudioRecorder),
508bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_AUDIORECORDER,
509bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
51029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
511bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
512bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
513bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
514bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Engine class
515bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
516bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable Engine_interfaces[] = {
517bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
51872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mObject)},
519bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
52072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mDynamicInterfaceManagement)},
521bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_ENGINE, INTERFACE_IMPLICIT,
52272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mEngine)},
523bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_ENGINECAPABILITIES, INTERFACE_IMPLICIT,
52472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mEngineCapabilities)},
525bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_THREADSYNC, INTERFACE_IMPLICIT,
52672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mThreadSync)},
527bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_AUDIOIODEVICECAPABILITIES, INTERFACE_IMPLICIT,
52872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mAudioIODeviceCapabilities)},
529bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_AUDIODECODERCAPABILITIES, INTERFACE_EXPLICIT,
53072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mAudioDecoderCapabilities)},
531bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_AUDIOENCODERCAPABILITIES, INTERFACE_EXPLICIT,
53272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mAudioEncoderCapabilities)},
533bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DCOMMIT, INTERFACE_EXPLICIT_GAME,
53472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, m3DCommit)},
535bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DEVICEVOLUME, INTERFACE_OPTIONAL,
53672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CEngine, mDeviceVolume)}
537bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
538bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
539a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CEngine_class = {
540bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    Engine_interfaces,
541bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(Engine_interfaces)/sizeof(Engine_interfaces[0]),
542bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_Engine,
543bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"Engine",
54472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CEngine),
545bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_ENGINE,
546bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
54729b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
548bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
549bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
550bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
551bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// LEDDevice class
552bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
553bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable LEDDevice_interfaces[] = {
554bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
55572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CLEDDevice, mObject)},
556bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
55772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CLEDDevice, mDynamicInterfaceManagement)},
558bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_LED, INTERFACE_IMPLICIT,
55972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CLEDDevice, mLEDArray)}
560bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
561bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
562a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CLEDDevice_class = {
563bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    LEDDevice_interfaces,
564bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(LEDDevice_interfaces)/sizeof(LEDDevice_interfaces[0]),
565bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_LEDDevice,
566bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"LEDDevice",
56772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CLEDDevice),
568bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_LEDDEVICE,
569bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
57029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
571bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
572bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
573bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
574bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Listener class
575bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
576bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable Listener_interfaces[] = {
577bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
57872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CListener, mObject)},
579bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
58072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CListener, mDynamicInterfaceManagement)},
581bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DDOPPLER, INTERFACE_DYNAMIC_GAME,
58272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DDoppler)},
583bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DLOCATION, INTERFACE_EXPLICIT_GAME,
58472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DLocation)}
585bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
586bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
587a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CListener_class = {
588bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    Listener_interfaces,
589bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(Listener_interfaces)/sizeof(Listener_interfaces[0]),
590bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_Listener,
591bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"Listener",
59272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CListener),
593bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_LISTENER,
594bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
59529b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
596bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
597bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
598bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
599bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// MetadataExtractor class
600bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
601bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable MetadataExtractor_interfaces[] = {
602bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
60372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMetadataExtractor, mObject)},
604bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
60572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMetadataExtractor, mDynamicInterfaceManagement)},
606bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICSOURCE, INTERFACE_IMPLICIT,
60772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMetadataExtractor, mDynamicSource)},
608bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_METADATAEXTRACTION, INTERFACE_IMPLICIT,
60972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMetadataExtractor, mMetadataExtraction)},
610bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_METADATATRAVERSAL, INTERFACE_IMPLICIT,
61172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMetadataExtractor, mMetadataTraversal)}
612bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
613bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
614a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CMetadataExtractor_class = {
615bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MetadataExtractor_interfaces,
616bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(MetadataExtractor_interfaces) /
617bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        sizeof(MetadataExtractor_interfaces[0]),
618bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_MetadataExtractor,
619bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"MetadataExtractor",
62072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CMetadataExtractor),
621bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_METADATAEXTRACTOR,
622bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
62329b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
624bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
625bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
626bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
627bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// MidiPlayer class
628bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
629bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable MidiPlayer_interfaces[] = {
630bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
63172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mObject)},
632bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
63372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mDynamicInterfaceManagement)},
634bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PLAY, INTERFACE_IMPLICIT,
63572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mPlay)},
636bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DDOPPLER, INTERFACE_DYNAMIC_GAME,
63772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(C3DGroup, m3DDoppler)},
638bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DGROUPING, INTERFACE_GAME,
63972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, m3DGrouping)},
640bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DLOCATION, INTERFACE_GAME,
64172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, m3DLocation)},
642bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DSOURCE, INTERFACE_GAME,
64372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, m3DSource)},
644bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_BUFFERQUEUE, INTERFACE_GAME,
64572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mBufferQueue)},
646bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_EFFECTSEND, INTERFACE_GAME,
64772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mEffectSend)},
648bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_MUTESOLO, INTERFACE_GAME,
64972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMuteSolo)},
650bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_METADATAEXTRACTION, INTERFACE_GAME,
65172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMetadataExtraction)},
652bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_METADATATRAVERSAL, INTERFACE_GAME,
65372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMetadataTraversal)},
654bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_MIDIMESSAGE, INTERFACE_PHONE_GAME,
65572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMIDIMessage)},
656bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_MIDITIME, INTERFACE_PHONE_GAME,
65772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMIDITime)},
658bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_MIDITEMPO, INTERFACE_PHONE_GAME,
65972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMIDITempo)},
660bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_MIDIMUTESOLO, INTERFACE_GAME,
66172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mMIDIMuteSolo)},
662bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PREFETCHSTATUS, INTERFACE_PHONE_GAME,
66372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mPrefetchStatus)},
664bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_SEEK, INTERFACE_PHONE_GAME,
66572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mSeek)},
666bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VOLUME, INTERFACE_PHONE_GAME,
66772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mVolume)},
668bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_3DMACROSCOPIC, INTERFACE_OPTIONAL,
66972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, m3DMacroscopic)},
670bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_BASSBOOST, INTERFACE_OPTIONAL,
67172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mBassBoost)},
672bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICSOURCE, INTERFACE_OPTIONAL,
67372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mDynamicSource)},
674bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_ENVIRONMENTALREVERB, INTERFACE_OPTIONAL,
67572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mEnvironmentalReverb)},
676bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_EQUALIZER, INTERFACE_OPTIONAL,
67772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mEqualizer)},
678bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PITCH, INTERFACE_OPTIONAL,
67972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mPitch)},
680bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PRESETREVERB, INTERFACE_OPTIONAL,
68172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mPresetReverb)},
682bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PLAYBACKRATE, INTERFACE_OPTIONAL,
68372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mPlaybackRate)},
684bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VIRTUALIZER, INTERFACE_OPTIONAL,
68572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mVirtualizer)},
686bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VISUALIZATION, INTERFACE_OPTIONAL,
68772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CMidiPlayer, mVisualization)}
688bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
689bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
690a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CMidiPlayer_class = {
691bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MidiPlayer_interfaces,
692bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(MidiPlayer_interfaces)/sizeof(MidiPlayer_interfaces[0]),
693bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_MidiPlayer,
694bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"MidiPlayer",
69572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CMidiPlayer),
696bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_MIDIPLAYER,
697bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
69829b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
699bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
700bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
701bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
702bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// OutputMix class
703bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
704bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable OutputMix_interfaces[] = {
705bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_IMPLICIT,
70672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mObject)},
707bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_IMPLICIT,
70872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mDynamicInterfaceManagement)},
709bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OUTPUTMIX, INTERFACE_IMPLICIT,
71072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mOutputMix)},
711bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifdef USE_OUTPUTMIXEXT
712bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OUTPUTMIXEXT, INTERFACE_IMPLICIT,
71372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mOutputMixExt)},
714bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#else
715bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OUTPUTMIXEXT, INTERFACE_TBD /*NOT AVAIL*/, 0},
716bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
717bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_ENVIRONMENTALREVERB, INTERFACE_DYNAMIC_GAME,
71872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mEnvironmentalReverb)},
719bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_EQUALIZER, INTERFACE_DYNAMIC_MUSIC_GAME,
72072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mEqualizer)},
721bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_PRESETREVERB, INTERFACE_DYNAMIC_MUSIC,
72272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mPresetReverb)},
723bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VIRTUALIZER, INTERFACE_DYNAMIC_MUSIC_GAME,
72472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mVirtualizer)},
725bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VOLUME, INTERFACE_GAME_MUSIC,
72672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mVolume)},
727bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_BASSBOOST, INTERFACE_OPTIONAL_DYNAMIC,
72872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mBassBoost)},
729bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VISUALIZATION, INTERFACE_OPTIONAL,
73072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(COutputMix, mVisualization)}
731bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
732bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
733a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable COutputMix_class = {
734bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    OutputMix_interfaces,
735bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(OutputMix_interfaces)/sizeof(OutputMix_interfaces[0]),
736bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_OutputMix,
737bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"OutputMix",
73872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(COutputMix),
739bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_OUTPUTMIX,
740bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
74129b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
742bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
743bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
744bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
745bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Vibra class
746bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
747bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kastenstatic const struct iid_vtable VibraDevice_interfaces[] = {
748bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_OBJECT, INTERFACE_OPTIONAL,
74972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CVibraDevice, mObject)},
750bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_DYNAMICINTERFACEMANAGEMENT, INTERFACE_OPTIONAL,
75172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CVibraDevice, mDynamicInterfaceManagement)},
752bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    {MPH_VIBRA, INTERFACE_OPTIONAL,
75372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        offsetof(CVibraDevice, mVibra)}
754bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
755bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
756a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kastenstatic const ClassTable CVibraDevice_class = {
757bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    VibraDevice_interfaces,
758bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    sizeof(VibraDevice_interfaces)/sizeof(VibraDevice_interfaces[0]),
759bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    MPH_to_Vibra,
760bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //"VibraDevice",
76172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    sizeof(CVibraDevice),
762bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SL_OBJECTID_VIBRADEVICE,
763bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL,
76429b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    NULL,
765bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    NULL
766bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
767bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
768bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten/* Map SL_OBJECTID to class */
769bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
77072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kastenstatic const ClassTable * const classes[] = {
771bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    // Do not change order of these entries; they are in numerical order
772a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CEngine_class,
773a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CLEDDevice_class,
774a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CAudioPlayer_class,
775a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CAudioRecorder_class,
776a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CMidiPlayer_class,
777a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CListener_class,
778a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &C3DGroup_class,
779a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CVibraDevice_class,
780a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &COutputMix_class,
781a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    &CMetadataExtractor_class
782bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
783bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
78472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kastenstatic const ClassTable *objectIDtoClass(SLuint32 objectID)
785bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
786bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLuint32 objectID0 = classes[0]->mObjectID;
787bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (objectID0 <= objectID &&
788bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        classes[sizeof(classes)/sizeof(classes[0])-1]->mObjectID >= objectID)
789bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        return classes[objectID - objectID0];
790bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    return NULL;
791bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
792bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
793bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// Construct a new instance of the specified class, exposing selected interfaces
794bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
79572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kastenstatic IObject *construct(const ClassTable *class__,
79629b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    unsigned exposedMask, SLEngineItf engine)
797bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten{
79872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    IObject *this;
799bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifndef NDEBUG
80072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    this = (IObject *) malloc(class__->mSize);
801bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#else
80272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    this = (IObject *) calloc(1, class__->mSize);
803bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
804bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    if (NULL != this) {
805bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#ifndef NDEBUG
806bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        // for debugging, to detect uninitialized fields
807bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        memset(this, 0x55, class__->mSize);
808bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif
80929b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten        this->mClass = class__;
81029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten        this->mExposedMask = exposedMask;
81172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        unsigned lossOfControlMask = 0;
81272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        IEngine *thisEngine = (IEngine *) engine;
81372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        if (NULL == thisEngine)
81472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            thisEngine = &((CEngine *) this)->mEngine;
81572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        else if (thisEngine->mLossOfControlGlobal)
81672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            lossOfControlMask = ~0;
81772a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        this->mLossOfControlMask = lossOfControlMask;
818bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        const struct iid_vtable *x = class__->mInterfaces;
819bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        unsigned i;
820bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        for (i = 0; exposedMask; ++i, ++x, exposedMask >>= 1) {
821bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            if (exposedMask & 1) {
82283f93b0afd3607b1570d8473c2f6e45276c133baGlenn Kasten                void *self = (char *) this + x->mOffset;
82372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten                ((IObject **) self)[1] = this;
82483f93b0afd3607b1570d8473c2f6e45276c133baGlenn Kasten                VoidHook init = MPH_init_table[x->mMPH].mInit;
825bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                if (NULL != init)
826bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    (*init)(self);
827bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            }
828bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        }
82972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        // FIXME need a lock
83072a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        if (INSTANCE_MAX > thisEngine->mInstanceCount) {
83172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            // FIXME ignores Destroy
83272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            thisEngine->mInstances[thisEngine->mInstanceCount++] = this;
83372a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        }
83472a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        // FIXME else what
835bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    }
836bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    return this;
837bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten}
838bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
8390b167267bda99b68346045ccab14e810121d5de4Glenn Kasten// Runs every graphics frame (50 Hz) to update audio
840d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
8410b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic void *frame_body(void *arg)
842d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
8430b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    CEngine *this = (CEngine *) arg;
8440b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    for (;;) {
8450b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        usleep(20000*50);
8460b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        unsigned i;
8470b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        for (i = 0; i < INSTANCE_MAX; ++i) {
8480b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            IObject *instance = (IObject *) this->mEngine.mInstances[i];
8490b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            if (NULL == instance)
8500b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                continue;
8510b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            if (instance->mClass != &CAudioPlayer_class)
8520b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                continue;
8530b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            write(1, ".", 1);
8540b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        }
8552045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
8560b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    return NULL;
857d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
858d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
8590b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/* Initial entry points */
860d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
8610b167267bda99b68346045ccab14e810121d5de4Glenn KastenSLresult SLAPIENTRY slCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions,
8620b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    const SLEngineOption *pEngineOptions, SLuint32 numInterfaces,
8630b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
864d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
8650b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == pEngine)
866d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
8670b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    *pEngine = NULL;
8680b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // default values
8690b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLboolean threadSafe = SL_BOOLEAN_TRUE;
8700b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLboolean lossOfControlGlobal = SL_BOOLEAN_FALSE;
8710b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL != pEngineOptions) {
8720b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        SLuint32 i;
8730b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        const SLEngineOption *option = pEngineOptions;
8740b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        for (i = 0; i < numOptions; ++i, ++option) {
8750b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            switch (option->feature) {
8760b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            case SL_ENGINEOPTION_THREADSAFE:
8770b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                threadSafe = (SLboolean) option->data;
8780b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                break;
8790b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            case SL_ENGINEOPTION_LOSSOFCONTROL:
8800b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                lossOfControlGlobal = (SLboolean) option->data;
8810b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                break;
8820b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            default:
8830b167267bda99b68346045ccab14e810121d5de4Glenn Kasten                return SL_RESULT_PARAMETER_INVALID;
8840b167267bda99b68346045ccab14e810121d5de4Glenn Kasten            }
8850b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        }
88629b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    }
8870b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    unsigned exposedMask;
8880b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLresult result = checkInterfaces(&CEngine_class, numInterfaces,
8890b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        pInterfaceIds, pInterfaceRequired, &exposedMask);
8900b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (SL_RESULT_SUCCESS != result)
8910b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        return result;
8920b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    CEngine *this = (CEngine *)
8930b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        construct(&CEngine_class, exposedMask, NULL);
8940b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == this)
8950b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        return SL_RESULT_MEMORY_FAILURE;
8960b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    this->mObject.mLossOfControlMask = lossOfControlGlobal ? ~0 : 0;
8970b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    this->mEngine.mLossOfControlGlobal = lossOfControlGlobal;
8980b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    this->mEngineCapabilities.mThreadSafe = threadSafe;
8990b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    int ok;
9000b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    ok = pthread_create(&this->mFrameThread, (const pthread_attr_t *) NULL,
9010b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        frame_body, this);
9020b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    assert(ok == 0);
9030b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    *pEngine = &this->mObject.mItf;
904d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
905d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
906d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9070b167267bda99b68346045ccab14e810121d5de4Glenn KastenSLresult SLAPIENTRY slQueryNumSupportedEngineInterfaces(
9080b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLuint32 *pNumSupportedInterfaces)
909d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
9100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == pNumSupportedInterfaces)
9112045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_RESULT_PARAMETER_INVALID;
9120b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    *pNumSupportedInterfaces = CEngine_class.mInterfaceCount;
913d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
914d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
915d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9160b167267bda99b68346045ccab14e810121d5de4Glenn KastenSLresult SLAPIENTRY slQuerySupportedEngineInterfaces(SLuint32 index,
9170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLInterfaceID *pInterfaceId)
918d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten{
9190b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (sizeof(Engine_interfaces)/sizeof(Engine_interfaces[0]) < index)
9202045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_RESULT_PARAMETER_INVALID;
9210b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    if (NULL == pInterfaceId)
9222045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        return SL_RESULT_PARAMETER_INVALID;
9230b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    *pInterfaceId = &SL_IID_array[Engine_interfaces[index].mMPH];
924d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten    return SL_RESULT_SUCCESS;
925d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten}
926d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9270b167267bda99b68346045ccab14e810121d5de4Glenn Kasten#ifdef USE_OUTPUTMIXEXT
928d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9290b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/* OutputMixExt implementation */
930d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9310b167267bda99b68346045ccab14e810121d5de4Glenn Kasten// Used by SDL and Android but not specific to or dependent on either platform
932d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
9330b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic void OutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer,
9340b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    SLuint32 size)
9352045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten{
9362045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // Force to be a multiple of a frame, assumes stereo 16-bit PCM
9372045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    size &= ~3;
93872a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    IOutputMixExt *thisExt =
93972a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        (IOutputMixExt *) self;
94029b9008a17cae003590a5ff361e98809f02e3025Glenn Kasten    // FIXME Finding one interface from another, but is it exposed?
94172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    IOutputMix *this =
94272a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        &((COutputMix *) thisExt->mThis)->mOutputMix;
9432045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    unsigned activeMask = this->mActiveMask;
9442045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    struct Track *track = &this->mTracks[0];
9452045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    unsigned i;
9462045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
9472045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // FIXME O(32) loop even when few tracks are active.
9482045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // To avoid loop, use activeMask to check for active track(s)
9492045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // and decide whether we actually need to copy or mix.
9502045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    for (i = 0; 0 != activeMask; ++i, ++track, activeMask >>= 1) {
9512045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        assert(i < 32);
9522045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (!(activeMask & 1))
9532045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            continue;
9542045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        // track is allocated
95572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten        IPlay *play = track->mPlay;
9562045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (NULL == play)
9572045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            continue;
9582045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        // track is initialized
9592045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (SL_PLAYSTATE_PLAYING != play->mState)
9602045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            continue;
9612045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        // track is playing
9622045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        void *dstWriter = pBuffer;
9632045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        unsigned desired = size;
9642045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
9652045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        while (desired > 0) {
96672a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten            IBufferQueue *bufferQueue;
9672045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            const struct BufferHeader *oldFront, *newFront, *rear;
9682045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            unsigned actual = desired;
9692045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            if (track->mAvail < actual)
9702045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                actual = track->mAvail;
9712045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            // force actual to be a frame multiple
9722045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            if (actual > 0) {
9732045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // FIXME check for either mute or volume 0
9742045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // in which case skip the input buffer processing
9752045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                assert(NULL != track->mReader);
9762045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // FIXME && gain == 1.0
9772045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                if (mixBufferHasData) {
978bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    stereo *mixBuffer = (stereo *) dstWriter;
979bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    const stereo *source = (const stereo *) track->mReader;
9802045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    unsigned j;
981bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer,
982bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                        ++source) {
9832045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        // apply gain here
9842045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        mixBuffer->left += source->left;
9852045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        mixBuffer->right += source->right;
9862045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    }
9872045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                } else {
9882045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    memcpy(dstWriter, track->mReader, actual);
9892045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
9902045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                }
9912045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                dstWriter = (char *) dstWriter + actual;
9922045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                desired -= actual;
9932045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                track->mReader = (char *) track->mReader + actual;
9942045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                track->mAvail -= actual;
9952045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                if (track->mAvail == 0) {
9962045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    bufferQueue = track->mBufferQueue;
9972045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    if (NULL != bufferQueue) {
9982045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        oldFront = bufferQueue->mFront;
9992045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        rear = bufferQueue->mRear;
10002045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        assert(oldFront != rear);
10012045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        newFront = oldFront;
1002bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                        if (++newFront ==
1003bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                            &bufferQueue->mArray[bufferQueue->mNumBuffers])
10042045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                            newFront = bufferQueue->mArray;
10052045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        bufferQueue->mFront = (struct BufferHeader *) newFront;
10062045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        assert(0 < bufferQueue->mState.count);
10072045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        --bufferQueue->mState.count;
10082045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        // FIXME here or in Enqueue?
10092045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        ++bufferQueue->mState.playIndex;
1010bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                        // FIXME a good time to do an early warning
10112045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        // callback depending on buffer count
10122045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    }
10132045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                }
10142045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                continue;
10152045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            }
10162045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            // actual == 0
10172045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            bufferQueue = track->mBufferQueue;
10182045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            if (NULL != bufferQueue) {
10192045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                oldFront = bufferQueue->mFront;
10202045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                rear = bufferQueue->mRear;
10212045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                if (oldFront != rear) {
10222045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kastengot_one:
10232045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    assert(0 < bufferQueue->mState.count);
10242045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    track->mReader = oldFront->mBuffer;
10252045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    track->mAvail = oldFront->mSize;
10262045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    continue;
10272045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                }
10282045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // FIXME should be able to configure when to
10292045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // kick off the callback e.g. high/low water-marks etc.
1030bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                // need data but none available, attempt a desperate callback
10312045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                slBufferQueueCallback callback = bufferQueue->mCallback;
10322045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                if (NULL != callback) {
1033bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    (*callback)((SLBufferQueueItf) bufferQueue,
1034bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                        bufferQueue->mContext);
1035bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    // if lucky, the callback enqueued a buffer
10362045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                    if (rear != bufferQueue->mRear)
10372045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                        goto got_one;
1038bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten                    // unlucky, queue still empty, the callback failed
10392045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                }
10402045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // here on underflow due to no callback, or failed callback
10412045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // FIXME underflow, send silence (or previous buffer?)
10422045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // we did a callback to try to kick start again but failed
10432045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                // should log this
10442045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            }
1045bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten            // no buffer queue or underflow, clear out rest of partial buffer
10462045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            if (!mixBufferHasData && trackContributedToMix)
10472045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten                memset(dstWriter, 0, actual);
10482045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            break;
10492045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        }
10502045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        if (trackContributedToMix)
10512045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten            mixBufferHasData = SL_BOOLEAN_TRUE;
10522045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
10532045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // No active tracks, so output silence
10542045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    if (!mixBufferHasData)
10552045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        memset(pBuffer, 0, size);
10562045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten}
10572045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
1058bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten/*static*/ const struct SLOutputMixExtItf_ OutputMixExt_OutputMixExtItf = {
1059bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    OutputMixExt_FillBuffer
1060bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten};
1061bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
1062bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif // USE_OUTPUTMIXEXT
1063bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
10642045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten#ifdef USE_SDL
10652045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
1066bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten// FIXME move to separate source file
1067bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten
10682045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten/* SDL platform implementation */
10692045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
10702045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kastenstatic void SDLCALL SDL_callback(void *context, Uint8 *stream, int len)
10712045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten{
10722045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    assert(len > 0);
1073bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    OutputMixExt_FillBuffer((SLOutputMixExtItf) context, stream,
1074bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten        (SLuint32) len);
10752045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten}
10762045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
10772045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kastenvoid SDL_start(SLObjectItf self)
10782045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten{
1079bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    //assert(self != NULL);
10802045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    // FIXME make this an operation on Object: GetClass
108172a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    //IObject *this = (IObject *) self;
1082a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    //assert(&COutputMix_class == this->mClass);
1083bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLresult result;
1084bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    SLOutputMixExtItf OutputMixExt;
1085bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    result = (*self)->GetInterface(self, SL_IID_OUTPUTMIXEXT, &OutputMixExt);
1086bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    assert(SL_RESULT_SUCCESS == result);
10872045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
10882045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    SDL_AudioSpec fmt;
10892045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    fmt.freq = 44100;
10902045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    fmt.format = AUDIO_S16;
10912045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    fmt.channels = 2;
10922045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    fmt.samples = 256;
10932045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    fmt.callback = SDL_callback;
1094bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    // FIXME should be a GetInterface
109572a04d8e9e059dad969d166a6a70491fe1e65970Glenn Kasten    // fmt.userdata = &((COutputMix *) this)->mOutputMixExt;
1096bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten    fmt.userdata = (void *) OutputMixExt;
10972045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
10982045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    if (SDL_OpenAudio(&fmt, NULL) < 0) {
10992045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
11002045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten        exit(1);
11012045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    }
11022045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten    SDL_PauseAudio(0);
11032045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten}
11042045b02407f6ac0a570faee3157b24317c8a69e0Glenn Kasten
1105bd3cb772fc94c5baf0d1fe1a63693b33ca5fe9e3Glenn Kasten#endif // USE_SDL
1106d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten
11070b167267bda99b68346045ccab14e810121d5de4Glenn Kasten#include "IEngine.c"
11080b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
1109d7143537437acbd4b97761a1c5bf852be9ba485aGlenn Kasten/* End */
1110