IObject.c revision 510f3671f716f6835282e4b0fd0275c20e9dadd8
161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/*
261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *
461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * you may not use this file except in compliance with the License.
661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * You may obtain a copy of the License at
761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *
861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten *
1061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Unless required by applicable law or agreed to in writing, software
1161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
1261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * See the License for the specific language governing permissions and
1461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * limitations under the License.
1561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten */
1661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
1761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/* Object implementation */
1861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
1961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten#include "sles_allinclusive.h"
2061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
21510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous Object.Realize.
22510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the Object.
23d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
24510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic void HandleRealize(void *self, int unused)
2561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
26510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
27510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // validate input parameters
28510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    IObject *this = (IObject *) self;
29510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != this);
3061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const ClassTable *class__ = this->mClass;
31510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != class__);
323d146e0a31f5ee2a7d9807c4e99994084fdd3283Jean-Michel Trivi    AsyncHook realize = class__->mRealize;
333a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    SLresult result;
34d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    SLuint32 state;
35510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
36510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // check object state
3761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
38510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    state = this->mState;
39510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
40510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
41510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1:   // normal case
42510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if (NULL != realize) {
43510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            this->mState = SL_OBJECT_STATE_REALIZING_2;
44510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
45510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Note that the mutex is unlocked during the realize hook
46510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = (*realize)(this, SL_BOOLEAN_TRUE);
47510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
48510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_OBJECT_STATE_REALIZING_2 == this->mState);
49510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
50510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                SL_OBJECT_STATE_UNREALIZED;
51510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
52510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = SL_RESULT_SUCCESS;
53510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_OBJECT_STATE_REALIZED;
54510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
55510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
56510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
57510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1A:  // operation was aborted while on work queue
58510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
59510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_UNREALIZED;
60510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
61510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
62510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                            // impossible
63510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
64510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
65510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
66510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
6761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
68510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
69510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is locked, update state
70d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    this->mState = state;
71510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
72d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
73d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    slObjectCallback callback = this->mCallback;
74d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    void *context = this->mContext;
7561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
76510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
77d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Note that the mutex is unlocked during the callback
783a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    if (NULL != callback)
79d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
80d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
81d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
82d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IObject_Realize(SLObjectItf self, SLboolean async)
83d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
84d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    IObject *this = (IObject *) self;
85d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    SLuint32 state;
86d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    const ClassTable *class__ = this->mClass;
87d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    object_lock_exclusive(this);
88d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    state = this->mState;
89d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Reject redundant calls to Realize
90d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_OBJECT_STATE_UNREALIZED != state) {
91510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(this);
92510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        return SL_RESULT_PRECONDITIONS_VIOLATED;
93510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
94d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Asynchronous: mark operation pending and cancellable
95510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (async && (SL_OBJECTID_ENGINE != class__->mObjectID)) {
96d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        state = SL_OBJECT_STATE_REALIZING_1;
97d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Synchronous: mark operation pending and non-cancellable
98d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    } else {
99d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        state = SL_OBJECT_STATE_REALIZING_2;
100d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
101510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    this->mState = state;
102d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    object_unlock_exclusive(this);
103510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLresult result;
104d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    switch (state) {
105d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine
106d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(async);
107510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = ThreadPool_add(&this->mEngine->mThreadPool, HandleRealize, this, 0);
108510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if (SL_RESULT_SUCCESS != result) {
109510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Engine was destroyed during realize, or insufficient memory
110510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
111510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            this->mState = SL_OBJECT_STATE_UNREALIZED;
112510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
113d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
114d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
115d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine
116d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        {
117d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        AsyncHook realize = class__->mRealize;
118d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        // Note that the mutex is unlocked during the realize hook
119510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = (NULL != realize) ? (*realize)(this, async) : SL_RESULT_SUCCESS;
120d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        object_lock_exclusive(this);
121d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        assert(SL_OBJECT_STATE_REALIZING_2 == this->mState);
122510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
123510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            SL_OBJECT_STATE_UNREALIZED;
124d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        this->mState = state;
125d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        slObjectCallback callback = this->mCallback;
126d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        void *context = this->mContext;
127d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        object_unlock_exclusive(this);
128d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        // asynchronous Realize on an Engine is actually done synchronously, but still has callback
129d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        // This is because there is no thread pool yet to do it asynchronously.
130d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        if (async && (NULL != callback))
131510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state,
132510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                NULL);
133d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
134d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
135510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                          // impossible
136510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
137d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
138d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
13961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return result;
14061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
14161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
142510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous Object.Resume.
143510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the Object.
144510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
145510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic void HandleResume(void *self, int unused)
14661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
147510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
148510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // valid input parameters
14961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
150510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != this);
15161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const ClassTable *class__ = this->mClass;
152510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != class__);
153510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    AsyncHook resume = class__->mResume;
1543a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    SLresult result;
155510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint32 state;
156510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
157510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // check object state
15861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
159510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    state = this->mState;
160510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
161510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
162510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1:    // normal case
163510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if (NULL != resume) {
164510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            this->mState = SL_OBJECT_STATE_RESUMING_2;
165510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
166510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Note that the mutex is unlocked during the resume hook
167510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = (*resume)(this, SL_BOOLEAN_TRUE);
168510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
169510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_OBJECT_STATE_RESUMING_2 == this->mState);
170510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
171510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                SL_OBJECT_STATE_SUSPENDED;
172510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
173510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = SL_RESULT_SUCCESS;
174510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_OBJECT_STATE_REALIZED;
1753a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten        }
176510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
177510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
178510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1A:   // operation was aborted while on work queue
179510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
180510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_SUSPENDED;
181510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
182510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
183510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                            // impossible
184510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
185510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
186510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
187510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
18861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
189510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
190510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is unlocked, update state
191510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    this->mState = state;
192510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
193510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
194510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    slObjectCallback callback = this->mCallback;
195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    void *context = this->mContext;
19661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
197510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
198510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Note that the mutex is unlocked during the callback
1993a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    if (NULL != callback)
200510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
201510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
202510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
203510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic SLresult IObject_Resume(SLObjectItf self, SLboolean async)
204510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
205510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    IObject *this = (IObject *) self;
206510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    const ClassTable *class__ = this->mClass;
207510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLresult result;
208510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint32 state;
209510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_exclusive(this);
210510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    state = this->mState;
211510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Reject redundant calls to Resume
212510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (SL_OBJECT_STATE_SUSPENDED != state) {
213510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(this);
214510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        return SL_RESULT_PRECONDITIONS_VIOLATED;
215510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
216510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Asynchronous: mark operation pending and cancellable
217510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (async) {
218510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_RESUMING_1;
219510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Synchronous: mark operatio pending and non-cancellable
220510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    } else {
221510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_RESUMING_2;
222510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
223510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    this->mState = state;
224510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_unlock_exclusive(this);
225510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
226510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1: // asynchronous
227510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(async);
228510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = ThreadPool_add(&this->mEngine->mThreadPool, HandleResume, this, 0);
229510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if (SL_RESULT_SUCCESS != result) {
230510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Engine was destroyed during resume, or insufficient memory
231510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
232510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            this->mState = SL_OBJECT_STATE_SUSPENDED;
233510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
234510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
235510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
236510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_2: // synchronous
237510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        {
238510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        AsyncHook resume = class__->mResume;
239510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // Note that the mutex is unlocked during the resume hook
240510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = (NULL != resume) ? (*resume)(this, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS;
241510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_lock_exclusive(this);
242510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_OBJECT_STATE_RESUMING_2 == this->mState);
243510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        this->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
244510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            SL_OBJECT_STATE_SUSPENDED;
245510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(this);
246510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
247510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
248510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                        // impossible
249510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
250510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
251510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
25261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return result;
25361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
25461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
25561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState)
25661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
25761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pState)
25861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
25961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
2603a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    // Note that the state is immediately obsolete, so a peek lock is safe
2613a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    object_lock_peek(this);
26261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLuint32 state = this->mState;
2633a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    object_unlock_peek(this);
264510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Re-map the realizing and suspended states
265d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    switch (state) {
266d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1:
267510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1A:
268d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    case SL_OBJECT_STATE_REALIZING_2:
269d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        state = SL_OBJECT_STATE_UNREALIZED;
270d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
271510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1:
272510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1A:
273510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_2:
274510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_SUSPENDING:
275510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_SUSPENDED;
276510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
277510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_UNREALIZED:
278510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZED:
279510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_SUSPENDED:
280510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // These are the "official" object states, return them as is
281510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
282d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    default:
283510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
284d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        break;
285d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
28661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    *pState = state;
28761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_SUCCESS;
28861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
28961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
2903a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface)
29161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
29261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pInterface)
29361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
29461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLresult result;
29561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    void *interface = NULL;
29661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == iid)
29761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
29861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    else {
29961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        IObject *this = (IObject *) self;
30061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        const ClassTable *class__ = this->mClass;
30161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        int MPH, index;
302510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH]))) {
30361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            result = SL_RESULT_FEATURE_UNSUPPORTED;
304510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
30561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            unsigned mask = 1 << index;
306510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
307510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Can't get interface on a suspended/suspending/resuming object
308510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            if (SL_OBJECT_STATE_REALIZED != this->mState) {
30961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                result = SL_RESULT_PRECONDITIONS_VIOLATED;
310510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            } else {
311510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                switch (this->mInterfaceStates[index]) {
312510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                case INTERFACE_EXPOSED:
313510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                case INTERFACE_ADDED:
314510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    // Note that interface has been gotten,
315510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    // for debugger and to detect incorrect use of interfaces
316510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    this->mGottenMask |= mask;
317510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    interface = (char *) this + class__->mInterfaces[index].mOffset;
318510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    result = SL_RESULT_SUCCESS;
319510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    break;
320510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                // Can't get interface if uninitialized/suspend(ed,ing)/resuming/adding/removing
321510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                default:
322510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    result = SL_RESULT_FEATURE_UNSUPPORTED;
323510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                    break;
324510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                }
32561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            }
326510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
32761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
32861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
32961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    *(void **)pInterface = interface;
33061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_SUCCESS;
33161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
33261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
33361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_RegisterCallback(SLObjectItf self,
33461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    slObjectCallback callback, void *pContext)
33561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
33661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
33761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
33861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mCallback = callback;
33961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mContext = pContext;
34061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
34161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_SUCCESS;
34261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
34361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
344510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// internal common code for Abort and Destroy
345510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
346510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic void Abort_internal(IObject *this, SLboolean shutdown)
347510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
348510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // FIXME Aborting asynchronous operations during phase 2 is not yet implemented
349510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    const ClassTable *class__ = this->mClass;
350510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_exclusive(this);
351510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Abort asynchronous operations on the object
352510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (this->mState) {
353510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1:   // Realize
354510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        this->mState = SL_OBJECT_STATE_REALIZING_1A;
355510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
356510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1:    // Resume
357510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        this->mState = SL_OBJECT_STATE_RESUMING_1A;
358510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
359510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:
360510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
361510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
362510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Abort asynchronous operations on interfaces
363510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // FIXME O(n), could be O(1) using a generation count
364510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint8 *interfaceStateP = this->mInterfaceStates;
365510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned index;
366510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) {
367510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        switch (*interfaceStateP) {
368510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1:    // AddInterface
369510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            *interfaceStateP = INTERFACE_ADDING_1A;
370510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
371510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1:  // ResumeInterface
372510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            *interfaceStateP = INTERFACE_RESUMING_1A;
373510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
374510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        default:
375510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
376510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
377510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
378510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten#if 0
379510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // FIXME Not fully implemented, the intention is to advise other threads to exit from sync ops
380510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // FIXME Also need to wait for async ops to recognize the shutdown
381510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (shutdown)
382510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        this->mShutdown = SL_BOOLEAN_TRUE;
383510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten#endif
384510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_unlock_exclusive(this);
385510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
386510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
38761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic void IObject_AbortAsyncOperation(SLObjectItf self)
38861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
389510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    IObject *this = (IObject *) self;
390510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    Abort_internal(this, SL_BOOLEAN_FALSE);
39161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
39261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
39361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic void IObject_Destroy(SLObjectItf self)
39461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
395ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // FIXME Check for dependencies, e.g. destroying an output mix with attached players,
396ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    //       destroying an engine with extant objects, etc.
3973a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    // FIXME The abort should be atomic w.r.t. destroy, so another async can't be started in window
398ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // FIXME Destroy may need to be made asynchronous to permit safe cleanup of resources
39961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
400510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    Abort_internal(this, SL_BOOLEAN_TRUE);
40161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const ClassTable *class__ = this->mClass;
40261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    VoidHook destroy = class__->mDestroy;
40361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const struct iid_vtable *x = class__->mInterfaces;
404ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // const, no lock needed
405ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    IEngine *thisEngine = this->mEngine;
406ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    unsigned i = this->mInstanceID;
407ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    assert(0 < i && i <= INSTANCE_MAX);
408ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    --i;
409510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // remove object from exposure to sync thread and debugger
410ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    interface_lock_exclusive(thisEngine);
411ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    assert(0 < thisEngine->mInstanceCount);
412ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    --thisEngine->mInstanceCount;
413ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    assert(0 != thisEngine->mInstanceMask);
414ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    thisEngine->mInstanceMask &= ~(1 << i);
415ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    assert(thisEngine->mInstances[i] == this);
416ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    thisEngine->mInstances[i] = NULL;
41700d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten#ifdef USE_SDL
41800d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten    if (SL_OBJECTID_OUTPUTMIX == class__->mObjectID && (COutputMix *) this == thisEngine->mOutputMix) {
41900d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten        SDL_PauseAudio(1);
42000d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten        thisEngine->mOutputMix = NULL;
42100d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten        // Note we don't attempt to connect another output mix to SDL
42200d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten    }
42300d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten#endif
424ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    interface_unlock_exclusive(thisEngine);
42561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
426d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (NULL != destroy)
427d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (*destroy)(this);
42861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    // Call the deinitializer for each currently exposed interface,
42961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    // whether it is implicit, explicit, optional, or dynamically added.
430510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned incorrect = 0;
431510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint8 *interfaceStateP = this->mInterfaceStates;
432510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned index;
433510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    for (index = 0; index < class__->mInterfaceCount; ++index, ++x, ++interfaceStateP) {
434510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        SLuint32 state = *interfaceStateP;
435510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        switch (state) {
436510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_UNINITIALIZED:
437510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
438510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_EXPOSED:     // quiescent states
439510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDED:
440510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_SUSPENDED:
441510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            {
44261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            VoidHook deinit = MPH_init_table[x->mMPH].mDeinit;
44361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            if (NULL != deinit)
44461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                (*deinit)((char *) this + x->mOffset);
445510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            }
446510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
447510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1:    // active states indicate incorrect use of API
448510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1A:
449510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_2:
450510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1:
451510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1A:
452510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_2:
453510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_REMOVING:
454510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_SUSPENDING:
455510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            ++incorrect;
456510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
457510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        default:
458510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_BOOLEAN_FALSE);
459510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
46061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
46161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
46261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    // redundant: this->mState = SL_OBJECT_STATE_UNREALIZED;
46361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
46461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten#ifndef NDEBUG
46561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    memset(this, 0x55, class__->mSize);
46661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten#endif
46761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    free(this);
468510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // one or more interfaces was actively changing at time of Destroy
469510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(incorrect == 0);
470510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // FIXME assert might be the wrong thing to do; instead block until active ops complete?
47161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
47261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
4733a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable)
47461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
47561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
47661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
47761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mPriority = priority;
478d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    this->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize
47961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
48061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_SUCCESS;
48161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
48261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
4833a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable)
48461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
48561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (NULL == pPriority || NULL == pPreemptable)
48661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        return SL_RESULT_PARAMETER_INVALID;
48761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
48861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_shared(this);
48961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLint32 priority = this->mPriority;
49061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLboolean preemptable = this->mPreemptable;
49161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_shared(this);
49261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    *pPriority = priority;
49361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    *pPreemptable = preemptable;
49461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_SUCCESS;
49561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
49661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
49761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self,
49861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled)
49961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
50061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (0 < numInterfaces) {
50161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        SLuint32 i;
50261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        if (NULL == pInterfaceIDs)
50361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            return SL_RESULT_PARAMETER_INVALID;
50461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        IObject *this = (IObject *) self;
50561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        const ClassTable *class__ = this->mClass;
50661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        unsigned lossOfControlMask = 0;
50761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        // FIXME The cast is due to a typo in the spec
50861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        for (i = 0; i < (SLuint32) numInterfaces; ++i) {
50961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            SLInterfaceID iid = pInterfaceIDs[i];
51061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            if (NULL == iid)
51161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                return SL_RESULT_PARAMETER_INVALID;
51261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            int MPH, index;
513510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            if ((0 <= (MPH = IID_to_MPH(iid))) && (0 <= (index = class__->mMPH_to_index[MPH])))
51461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten                lossOfControlMask |= (1 << index);
51561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
51661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        object_lock_exclusive(this);
51761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        if (enabled)
51861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            this->mLossOfControlMask |= lossOfControlMask;
51961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        else
52061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            this->mLossOfControlMask &= ~lossOfControlMask;
52161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        object_unlock_exclusive(this);
52261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
52361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    return SL_RESULT_SUCCESS;
52461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
52561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
52661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic const struct SLObjectItf_ IObject_Itf = {
52761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Realize,
52861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Resume,
52961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetState,
53061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetInterface,
53161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_RegisterCallback,
53261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_AbortAsyncOperation,
53361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Destroy,
53461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_SetPriority,
53561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetPriority,
53661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_SetLossOfControlInterfaces,
53761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten};
53861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
53961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenvoid IObject_init(void *self)
54061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
54161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
54261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mItf = &IObject_Itf;
5430b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // initialized in construct:
5440b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // mClass
545ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // mInstanceID
5460b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // mLossOfControlMask
547ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // mEngine
548510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mInstanceStates
54961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mState = SL_OBJECT_STATE_UNREALIZED;
550510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    this->mGottenMask = 1;  // IObject
55161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mCallback = NULL;
55261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mContext = NULL;
553d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    this->mPriority = SL_PRIORITY_NORMAL;
55461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mPreemptable = SL_BOOLEAN_FALSE;
55561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    int ok;
55661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    ok = pthread_mutex_init(&this->mMutex, (const pthread_mutexattr_t *) NULL);
55761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    assert(0 == ok);
55861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    ok = pthread_cond_init(&this->mCond, (const pthread_condattr_t *) NULL);
55961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    assert(0 == ok);
56061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
561