IObject.c revision 8b8875067dd02b79361abb00c5d65b02a8ae72b0
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
21ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
22510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous Object.Realize.
23510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the Object.
24d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
25510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic void HandleRealize(void *self, int unused)
2661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
27510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
28510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // validate input parameters
29510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    IObject *this = (IObject *) self;
30510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != this);
3161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const ClassTable *class__ = this->mClass;
32510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != class__);
333d146e0a31f5ee2a7d9807c4e99994084fdd3283Jean-Michel Trivi    AsyncHook realize = class__->mRealize;
343a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    SLresult result;
35276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state;
36510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
37510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // check object state
3861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
39510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    state = this->mState;
40510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
41510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
42510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1:   // normal case
43510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if (NULL != realize) {
44510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            this->mState = SL_OBJECT_STATE_REALIZING_2;
45510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
46510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Note that the mutex is unlocked during the realize hook
47510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = (*realize)(this, SL_BOOLEAN_TRUE);
48510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
49510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_OBJECT_STATE_REALIZING_2 == this->mState);
50510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
51510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                SL_OBJECT_STATE_UNREALIZED;
52510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
53510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = SL_RESULT_SUCCESS;
54510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_OBJECT_STATE_REALIZED;
55510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
56510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
57510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
58510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1A:  // operation was aborted while on work queue
59510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
60510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_UNREALIZED;
61510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
62510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
63510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                            // impossible
64510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
65510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
66510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
67510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
6861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
69510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
70510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is locked, update state
71d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    this->mState = state;
72510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
73d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
74d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    slObjectCallback callback = this->mCallback;
75d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    void *context = this->mContext;
7661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
77510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
78d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Note that the mutex is unlocked during the callback
798c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != callback) {
80d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
818c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
82d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
83d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
84ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
85d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IObject_Realize(SLObjectItf self, SLboolean async)
86d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
87ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
88ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
89d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    IObject *this = (IObject *) self;
90276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state;
91d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    const ClassTable *class__ = this->mClass;
92d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    object_lock_exclusive(this);
93d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    state = this->mState;
94d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Reject redundant calls to Realize
95d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_OBJECT_STATE_UNREALIZED != state) {
96510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(this);
97ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PRECONDITIONS_VIOLATED;
98d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    } else {
99ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Asynchronous: mark operation pending and cancellable
1008b8875067dd02b79361abb00c5d65b02a8ae72b0Glenn Kasten        if (async && (SL_OBJECTID_ENGINE != class__->mSLObjectID)) {
101ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_REALIZING_1;
102ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Synchronous: mark operation pending and non-cancellable
103ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
104ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_REALIZING_2;
105d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
106d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        this->mState = state;
107d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        object_unlock_exclusive(this);
108ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        switch (state) {
109ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine
110ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(async);
111ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = ThreadPool_add(&this->mEngine->mThreadPool, HandleRealize, this, 0);
112ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            if (SL_RESULT_SUCCESS != result) {
113ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // Engine was destroyed during realize, or insufficient memory
114ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                object_lock_exclusive(this);
115ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                this->mState = SL_OBJECT_STATE_UNREALIZED;
116ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                object_unlock_exclusive(this);
117ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
118ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
119ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine
120ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            {
121ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            AsyncHook realize = class__->mRealize;
122ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // Note that the mutex is unlocked during the realize hook
123ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = (NULL != realize) ? (*realize)(this, async) : SL_RESULT_SUCCESS;
124ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_lock_exclusive(this);
125ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(SL_OBJECT_STATE_REALIZING_2 == this->mState);
126ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
127ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                SL_OBJECT_STATE_UNREALIZED;
128ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            this->mState = state;
129ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            slObjectCallback callback = this->mCallback;
130ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            void *context = this->mContext;
131ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_unlock_exclusive(this);
132ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // asynchronous Realize on an Engine is actually done synchronously, but still has
133ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // callback because there is no thread pool yet to do it asynchronously.
1348c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (async && (NULL != callback)) {
135ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state,
136ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    NULL);
137ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
1388c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
139ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
140ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        default:                          // impossible
141ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(SL_BOOLEAN_FALSE);
142ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
143d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
144d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
145ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
146ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
14761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
14861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
149ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
150510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous Object.Resume.
151510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the Object.
152510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
153510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic void HandleResume(void *self, int unused)
15461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
155510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
156510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // valid input parameters
15761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
158510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != this);
15961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const ClassTable *class__ = this->mClass;
160510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != class__);
161510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    AsyncHook resume = class__->mResume;
1623a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    SLresult result;
163276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state;
164510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
165510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // check object state
16661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
167510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    state = this->mState;
168510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
169510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
170510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1:    // normal case
171510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        if (NULL != resume) {
172510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            this->mState = SL_OBJECT_STATE_RESUMING_2;
173510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(this);
174510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            // Note that the mutex is unlocked during the resume hook
175510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = (*resume)(this, SL_BOOLEAN_TRUE);
176510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_lock_exclusive(this);
177510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_OBJECT_STATE_RESUMING_2 == this->mState);
178510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
179510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                SL_OBJECT_STATE_SUSPENDED;
180510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
181510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = SL_RESULT_SUCCESS;
182510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_OBJECT_STATE_REALIZED;
1833a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten        }
184510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
185510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
186510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1A:   // operation was aborted while on work queue
187510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
188510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_SUSPENDED;
189510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
190510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
191510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                            // impossible
192510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
193510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
194510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
19661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
197510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
198510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is unlocked, update state
199510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    this->mState = state;
200510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
201510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
202510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    slObjectCallback callback = this->mCallback;
203510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    void *context = this->mContext;
20461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
205510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
206510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Note that the mutex is unlocked during the callback
2078c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != callback) {
208510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
2098c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
210510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
211510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
212ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
213510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic SLresult IObject_Resume(SLObjectItf self, SLboolean async)
214510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
215ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
216ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
217510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    IObject *this = (IObject *) self;
218510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    const ClassTable *class__ = this->mClass;
219276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state;
220510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_exclusive(this);
221510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    state = this->mState;
222510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Reject redundant calls to Resume
223510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (SL_OBJECT_STATE_SUSPENDED != state) {
224510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(this);
225ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PRECONDITIONS_VIOLATED;
226510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    } else {
227ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Asynchronous: mark operation pending and cancellable
228ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (async) {
229ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_RESUMING_1;
230ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Synchronous: mark operatio pending and non-cancellable
231ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
232ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_RESUMING_2;
233510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
234ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        this->mState = state;
235510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(this);
236ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        switch (state) {
237ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1: // asynchronous
238ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(async);
239ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = ThreadPool_add(&this->mEngine->mThreadPool, HandleResume, this, 0);
240ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            if (SL_RESULT_SUCCESS != result) {
241ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // Engine was destroyed during resume, or insufficient memory
242ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                object_lock_exclusive(this);
243ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                this->mState = SL_OBJECT_STATE_SUSPENDED;
244ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                object_unlock_exclusive(this);
245ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
246ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
247ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_2: // synchronous
248ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            {
249ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            AsyncHook resume = class__->mResume;
250ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // Note that the mutex is unlocked during the resume hook
251ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = (NULL != resume) ? (*resume)(this, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS;
252ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_lock_exclusive(this);
253ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(SL_OBJECT_STATE_RESUMING_2 == this->mState);
254ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            this->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
255ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                SL_OBJECT_STATE_SUSPENDED;
256ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_unlock_exclusive(this);
257ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
258ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        default:                        // impossible
260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(SL_BOOLEAN_FALSE);
261ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
262510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
263510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
264ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
265ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
26661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
26761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
268ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
26961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState)
27061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
271ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
272ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
273ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pState) {
274ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
275ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
276ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        IObject *this = (IObject *) self;
277ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Note that the state is immediately obsolete, so a peek lock is safe
278ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        object_lock_peek(this);
279ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        SLuint8 state = this->mState;
280ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        object_unlock_peek(this);
281ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Re-map the realizing, resuming, and suspending states
282ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        switch (state) {
283ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1:
284ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1A:
285ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_2:
286928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_DESTROYING:    // application shouldn't call GetState after Destroy
287ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_UNREALIZED;
288ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
289ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1:
290ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1A:
291ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_2:
292ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_SUSPENDING:
293ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_SUSPENDED;
294ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
295ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_UNREALIZED:
296ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZED:
297ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_SUSPENDED:
298ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // These are the "official" object states, return them as is
299ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
300ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        default:
301ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(SL_BOOLEAN_FALSE);
302ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
303ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
304ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pState = state;
305ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
306d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
307ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
308ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
30961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
31061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
3113a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface)
31261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
313ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
314ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
315ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pInterface) {
31661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
317ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
318ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        void *interface = NULL;
319ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == iid) {
320ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
321510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
322ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            IObject *this = (IObject *) self;
323ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            const ClassTable *class__ = this->mClass;
324ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            int MPH, index;
325a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            if ((0 > (MPH = IID_to_MPH(iid))) ||
326a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // no need to check for an initialization hook
327a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // (NULL == MPH_init_table[MPH].mInit) ||
328a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                    (0 > (index = class__->mMPH_to_index[MPH]))) {
329ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                result = SL_RESULT_FEATURE_UNSUPPORTED;
330510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            } else {
331ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                unsigned mask = 1 << index;
332ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                object_lock_exclusive(this);
333104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten                if ((SL_OBJECT_STATE_REALIZED != this->mState) &&
334104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten                        !(INTERFACE_PREREALIZE & class__->mInterfaces[index].mInterface)) {
335104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten                    // Can't get interface on an unrealized object unless pre-realize is ok
336ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    result = SL_RESULT_PRECONDITIONS_VIOLATED;
3378b8875067dd02b79361abb00c5d65b02a8ae72b0Glenn Kasten                } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER ==
3388b8875067dd02b79361abb00c5d65b02a8ae72b0Glenn Kasten                        class__->mSLObjectID) && (1 == ((CAudioPlayer *) this)->mNumChannels)) {
339f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten                    // Can't get the MuteSolo interface of an audio player if the channel count is
340f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten                    // mono, but _can_ get the MuteSolo interface if the channel count is unknown
341f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten                    result = SL_RESULT_FEATURE_UNSUPPORTED;
342ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                } else {
343ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    switch (this->mInterfaceStates[index]) {
344ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    case INTERFACE_EXPOSED:
345ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    case INTERFACE_ADDED:
346e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                        interface = (char *) this + class__->mInterfaces[index].mOffset;
347ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // Note that interface has been gotten,
348ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // for debugger and to detect incorrect use of interfaces
349e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                        if (!(this->mGottenMask & mask)) {
350e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                            this->mGottenMask |= mask;
351711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                            // This trickery validates the v-table
352e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                            ((size_t *) interface)[0] ^= ~0;
353e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                        }
354ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        result = SL_RESULT_SUCCESS;
355ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        break;
356a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // Can't get interface if uninitialized, initialized, suspended,
357a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // suspending, resuming, adding, or removing
358ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    default:
359ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        result = SL_RESULT_FEATURE_UNSUPPORTED;
360ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        break;
361ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    }
362510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                }
363ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                object_unlock_exclusive(this);
36461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            }
36561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
366ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *(void **)pInterface = interface;
36761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
368ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
369ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
37061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
37161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
372ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
37361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_RegisterCallback(SLObjectItf self,
37461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    slObjectCallback callback, void *pContext)
37561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
376ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
377ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
37861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
37961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
38061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mCallback = callback;
38161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mContext = pContext;
38261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
383ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
384ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
385ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
38661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
38761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
388ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
389928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief This is internal common code for Abort and Destroy.
390928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten *  Note: called with mutex unlocked, and returns with mutex locked.
391928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */
392510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
393928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kastenstatic void Abort_internal(IObject *this)
394510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
395510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    const ClassTable *class__ = this->mClass;
396928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    bool anyAsync = false;
397510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_exclusive(this);
398928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
399510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Abort asynchronous operations on the object
400510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (this->mState) {
401510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1:   // Realize
402510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        this->mState = SL_OBJECT_STATE_REALIZING_1A;
403928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = true;
404510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
405510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1:    // Resume
406510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        this->mState = SL_OBJECT_STATE_RESUMING_1A;
407928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = true;
408928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        break;
409928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1A:  // Realize
410928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_REALIZING_2:
411928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1A:   // Resume
412928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_RESUMING_2:
413928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = true;
414928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        break;
415928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_DESTROYING:
416928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        assert(false);
417510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
418510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:
419510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
420510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
421928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
422510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Abort asynchronous operations on interfaces
423510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint8 *interfaceStateP = this->mInterfaceStates;
424510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned index;
425510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) {
426510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        switch (*interfaceStateP) {
427510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1:    // AddInterface
428510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            *interfaceStateP = INTERFACE_ADDING_1A;
429928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
430510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
431510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1:  // ResumeInterface
432510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            *interfaceStateP = INTERFACE_RESUMING_1A;
433928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
434928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
435928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_ADDING_1A:   // AddInterface
436928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_ADDING_2:
437928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_RESUMING_1A: // ResumeInterface
438928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_RESUMING_2:
439711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten        case INTERFACE_REMOVING:    // not observable: RemoveInterface is synchronous & mutex locked
440928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
441510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
442510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        default:
443510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
444510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
445510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
446928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
447928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // Wait until all asynchronous operations either complete normally or recognize the abort
448928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    while (anyAsync) {
449928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        object_unlock_exclusive(this);
450928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        // FIXME should use condition variable instead of polling
451928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        usleep(20000);
452928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = false;
453928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        object_lock_exclusive(this);
454928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        switch (this->mState) {
455928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1:   // state 1 means it cycled during the usleep window
456928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1:
457928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1A:
458928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_REALIZING_2:
459928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1A:
460928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_RESUMING_2:
461928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
462928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
463928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_DESTROYING:
464928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            assert(false);
465928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
466928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        default:
467928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
468928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
469928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interfaceStateP = this->mInterfaceStates;
470928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) {
471928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            switch (*interfaceStateP) {
472928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_ADDING_1:    // state 1 means it cycled during the usleep window
473928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_RESUMING_1:
474928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_ADDING_1A:
475928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_ADDING_2:
476928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_RESUMING_1A:
477928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_RESUMING_2:
478928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_REMOVING:
479928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                anyAsync = true;
480928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                break;
481928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            default:
482928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                break;
483928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            }
484928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
485928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
486928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
487928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // At this point there are no pending asynchronous operations
488510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
489510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
490ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
49161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic void IObject_AbortAsyncOperation(SLObjectItf self)
49261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
493ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE_VOID
494ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
495510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    IObject *this = (IObject *) self;
496928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    Abort_internal(this);
497928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    object_unlock_exclusive(this);
498ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
499ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
50061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
50161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
502ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
503f51dba65751107c930759938775b75531ec1f330Glenn Kastenvoid IObject_Destroy(SLObjectItf self)
50461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
505ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE_VOID
506ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
50761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
508928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // mutex is unlocked
509928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    Abort_internal(this);
510928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // mutex is locked
51161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const ClassTable *class__ = this->mClass;
512928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    BoolHook preDestroy = class__->mPreDestroy;
513928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // The pre-destroy hook is called with mutex locked, and should block until it is safe to
514928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // destroy.  It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex
515928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // before returning.
516928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    if (NULL != preDestroy) {
517928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        bool okToDestroy = (*preDestroy)(this);
518928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        if (!okToDestroy) {
519928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            object_unlock_exclusive(this);
520928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            // unfortunately Destroy doesn't return a result
521928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            SL_LOGE("Object::Destroy(%p) not allowed", this);
522928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            SL_LEAVE_INTERFACE_VOID
523928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
524928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
525928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    this->mState = SL_OBJECT_STATE_DESTROYING;
52661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    VoidHook destroy = class__->mDestroy;
527ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // const, no lock needed
528b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten    IEngine *thisEngine = &this->mEngine->mEngine;
529ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    unsigned i = this->mInstanceID;
530f51dba65751107c930759938775b75531ec1f330Glenn Kasten    assert(MAX_INSTANCE >= i);
531928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // avoid a recursive lock on the engine when destroying the engine itself
532928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    if (thisEngine->mThis != this) {
533928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interface_lock_exclusive(thisEngine);
534928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
535f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // An unpublished object has a slot reserved, but the ID hasn't been chosen yet
536ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    assert(0 < thisEngine->mInstanceCount);
537ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    --thisEngine->mInstanceCount;
538f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // If object is published, then remove it from exposure to sync thread and debugger
539f51dba65751107c930759938775b75531ec1f330Glenn Kasten    if (0 != i) {
540f51dba65751107c930759938775b75531ec1f330Glenn Kasten        --i;
541104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten        unsigned mask = 1 << i;
542104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten        assert(thisEngine->mInstanceMask & mask);
543104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten        thisEngine->mInstanceMask &= ~mask;
544f51dba65751107c930759938775b75531ec1f330Glenn Kasten        assert(thisEngine->mInstances[i] == this);
545f51dba65751107c930759938775b75531ec1f330Glenn Kasten        thisEngine->mInstances[i] = NULL;
54600d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten    }
547928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // avoid a recursive unlock on the engine when destroying the engine itself
548928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    if (thisEngine->mThis != this) {
549928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interface_unlock_exclusive(thisEngine);
550928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
551d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    // The destroy hook is called with mutex locked
5528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != destroy) {
553d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        (*destroy)(this);
5548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
555a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten    // Call the deinitializer for each currently initialized interface,
55661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    // whether it is implicit, explicit, optional, or dynamically added.
5574597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // The deinitializers are called in the reverse order that the
5584597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // initializers were called, so that IObject_deinit is called last.
5594597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    unsigned index = class__->mInterfaceCount;
5604597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    const struct iid_vtable *x = &class__->mInterfaces[index];
5614597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    SLuint8 *interfaceStateP = &this->mInterfaceStates[index];
5624597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    for ( ; index > 0; --index) {
5634597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten        --x;
564711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten        size_t offset = x->mOffset;
565711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten        void *thisItf = (char *) this + offset;
5664597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten        SLuint32 state = *--interfaceStateP;
567510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        switch (state) {
568510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_UNINITIALIZED:
569510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
570510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_EXPOSED:     // quiescent states
571510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDED:
572510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_SUSPENDED:
573711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            // The remove hook is called with mutex locked
574711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            {
575711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            VoidHook remove = MPH_init_table[x->mMPH].mRemove;
576711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            if (NULL != remove) {
577711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                (*remove)(thisItf);
578711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            }
579711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            *interfaceStateP = INTERFACE_INITIALIZED;
580711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            }
581a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            // fall through
582a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        case INTERFACE_INITIALIZED:
583510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            {
58461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            VoidHook deinit = MPH_init_table[x->mMPH].mDeinit;
5858c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (NULL != deinit) {
586a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                (*deinit)(thisItf);
587510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            }
588a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            *interfaceStateP = INTERFACE_UNINITIALIZED;
5898c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
590510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
591510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1:    // active states indicate incorrect use of API
592510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1A:
593510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_2:
594510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1:
595510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1A:
596510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_2:
597510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_REMOVING:
598510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_SUSPENDING:
599a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            SL_LOGE("Object::Destroy(%p) while interface %u active", this, index);
600510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
601510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        default:
602510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_BOOLEAN_FALSE);
603510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
60461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
60561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
6064597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer
607711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten    memset(this, 0x55, class__->mSize); // catch broken applications that continue using interfaces
608711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                                        // was ifdef USE_DEBUG but safer to do this unconditionally
60961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    free(this);
610ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
6118b8875067dd02b79361abb00c5d65b02a8ae72b0Glenn Kasten    if (SL_OBJECTID_ENGINE == class__->mSLObjectID) {
612711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten        CEngine_Destroyed((CEngine *) this);
613711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten    }
614711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten
615ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
61661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
61761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
618ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
6193a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable)
62061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
621ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
622ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
623a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
62461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
62561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(this);
62661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mPriority = priority;
627d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    this->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize
62861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(this);
629ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
6307a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else
6317a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
6327a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
633ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
634ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
63561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
63661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
637ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
6383a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable)
63961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
640ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
641ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
642a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
643ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pPriority || NULL == pPreemptable) {
644ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
645ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
646ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        IObject *this = (IObject *) self;
647ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        object_lock_shared(this);
648ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        SLint32 priority = this->mPriority;
649ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        SLboolean preemptable = this->mPreemptable;
650ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        object_unlock_shared(this);
651ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pPriority = priority;
652ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pPreemptable = preemptable;
653ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
654ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
6557a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else
6567a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
6577a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
658ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
659ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
66061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
66161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
662ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
66361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self,
66461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled)
66561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
666ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
667ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
668a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
669ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
67061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (0 < numInterfaces) {
67161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        SLuint32 i;
672ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == pInterfaceIDs) {
673ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
674ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
675ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            IObject *this = (IObject *) self;
676ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            const ClassTable *class__ = this->mClass;
677ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            unsigned lossOfControlMask = 0;
6787a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten            // The cast is due to a typo in the spec, bug 6482
679ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            for (i = 0; i < (SLuint32) numInterfaces; ++i) {
680ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                SLInterfaceID iid = pInterfaceIDs[i];
681ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                if (NULL == iid) {
682ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    result = SL_RESULT_PARAMETER_INVALID;
683ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    goto out;
684ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                }
685ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                int MPH, index;
6867a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten                // We ignore without error any invalid MPH or index, but spec is unclear
687a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                if ((0 <= (MPH = IID_to_MPH(iid))) &&
688a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                        // no need to check for an initialization hook
689a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                        // (NULL == MPH_init_table[MPH].mInit) ||
690a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                        (0 <= (index = class__->mMPH_to_index[MPH]))) {
691ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    lossOfControlMask |= (1 << index);
692928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                }
693ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
694ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_lock_exclusive(this);
6958c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (enabled) {
696ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                this->mLossOfControlMask |= lossOfControlMask;
6978c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            } else {
698ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                this->mLossOfControlMask &= ~lossOfControlMask;
6998c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
700ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_unlock_exclusive(this);
70161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
70261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
703ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kastenout:
7047a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else
7057a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
7067a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
707ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
708ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
70961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
71061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
711ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
71261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic const struct SLObjectItf_ IObject_Itf = {
71361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Realize,
71461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Resume,
71561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetState,
71661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetInterface,
71761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_RegisterCallback,
71861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_AbortAsyncOperation,
71961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Destroy,
72061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_SetPriority,
72161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetPriority,
72261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_SetLossOfControlInterfaces,
72361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten};
72461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
7254597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
7264597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten/** \brief This must be the first initializer called for an object */
7274597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
72861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenvoid IObject_init(void *self)
72961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
73061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject *this = (IObject *) self;
73161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mItf = &IObject_Itf;
7320b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // initialized in construct:
7330b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // mClass
734ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // mInstanceID
7350b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // mLossOfControlMask
736ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // mEngine
737a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten    // mInterfaceStates
73861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mState = SL_OBJECT_STATE_UNREALIZED;
739510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    this->mGottenMask = 1;  // IObject
740e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    this->mAttributesMask = 0;
74161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mCallback = NULL;
74261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mContext = NULL;
743a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
744d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    this->mPriority = SL_PRIORITY_NORMAL;
74561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    this->mPreemptable = SL_BOOLEAN_FALSE;
7467a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
747928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    this->mStrongRefCount = 0;
74861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    int ok;
74961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    ok = pthread_mutex_init(&this->mMutex, (const pthread_mutexattr_t *) NULL);
75061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    assert(0 == ok);
751fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
752fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    memset(&this->mOwner, 0, sizeof(pthread_t));
753fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    this->mFile = NULL;
754fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    this->mLine = 0;
755fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
75661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    ok = pthread_cond_init(&this->mCond, (const pthread_condattr_t *) NULL);
75761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    assert(0 == ok);
75861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
7594597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
7604597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
7614597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten/** \brief This must be the last deinitializer called for an object */
7624597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
7634597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kastenvoid IObject_deinit(void *self)
7644597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten{
7654597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    IObject *this = (IObject *) self;
7664597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#ifdef USE_DEBUG
7674597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    assert(pthread_equal(pthread_self(), this->mOwner));
7684597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#endif
7694597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    int ok;
7704597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    ok = pthread_cond_destroy(&this->mCond);
7714597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    assert(0 == ok);
7724597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // equivalent to object_unlock_exclusive, but without the rigmarole
7734597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    ok = pthread_mutex_unlock(&this->mMutex);
7744597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    assert(0 == ok);
7754597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    ok = pthread_mutex_destroy(&this->mMutex);
7764597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    assert(0 == ok);
7774597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // redundant: this->mState = SL_OBJECT_STATE_UNREALIZED;
7784597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten}
779f51dba65751107c930759938775b75531ec1f330Glenn Kasten
780f51dba65751107c930759938775b75531ec1f330Glenn Kasten
781f51dba65751107c930759938775b75531ec1f330Glenn Kasten/** \brief Publish a new object after it is fully initialized.
782f51dba65751107c930759938775b75531ec1f330Glenn Kasten *  Publishing will expose the object to sync thread and debugger,
783f51dba65751107c930759938775b75531ec1f330Glenn Kasten *  and make it safe to return the SLObjectItf to the application.
784f51dba65751107c930759938775b75531ec1f330Glenn Kasten */
785f51dba65751107c930759938775b75531ec1f330Glenn Kasten
786f51dba65751107c930759938775b75531ec1f330Glenn Kastenvoid IObject_Publish(IObject *this)
787f51dba65751107c930759938775b75531ec1f330Glenn Kasten{
788b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten    IEngine *thisEngine = &this->mEngine->mEngine;
789f51dba65751107c930759938775b75531ec1f330Glenn Kasten    interface_lock_exclusive(thisEngine);
790f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // construct earlier reserved a pending slot, but did not choose the actual slot number
791f51dba65751107c930759938775b75531ec1f330Glenn Kasten    unsigned availMask = ~thisEngine->mInstanceMask;
792f51dba65751107c930759938775b75531ec1f330Glenn Kasten    assert(availMask);
793f51dba65751107c930759938775b75531ec1f330Glenn Kasten    unsigned i = ctz(availMask);
794f51dba65751107c930759938775b75531ec1f330Glenn Kasten    assert(MAX_INSTANCE > i);
795f51dba65751107c930759938775b75531ec1f330Glenn Kasten    assert(NULL == thisEngine->mInstances[i]);
796f51dba65751107c930759938775b75531ec1f330Glenn Kasten    thisEngine->mInstances[i] = this;
797f51dba65751107c930759938775b75531ec1f330Glenn Kasten    thisEngine->mInstanceMask |= 1 << i;
798f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // avoid zero as a valid instance ID
799f51dba65751107c930759938775b75531ec1f330Glenn Kasten    this->mInstanceID = i + 1;
800f51dba65751107c930759938775b75531ec1f330Glenn Kasten    interface_unlock_exclusive(thisEngine);
801f51dba65751107c930759938775b75531ec1f330Glenn Kasten}
802