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/* DynamicInterfaceManagement implementation */
1861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
1961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten#include "sles_allinclusive.h"
2061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
21ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
22510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous AddInterface.
23510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the DynamicInterface, and MPH specifies which interface to add.
24510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
25cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kastenstatic void HandleAdd(void *self, void *ignored, int MPH)
26510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
27510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
28510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // validate input parameters
29bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
30bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz);
31bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thisObject = InterfaceToIObject(thiz);
32510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != thisObject);
33510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(0 <= MPH && MPH < MPH_MAX);
34bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const ClassTable *clazz = thisObject->mClass;
35bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != clazz);
36bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    int index = clazz->mMPH_to_index[MPH];
37bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 <= index && index < (int) clazz->mInterfaceCount);
38510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
39510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLresult result;
40510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
41510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // check interface state
42510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_exclusive(thisObject);
43276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state = *interfaceStateP;
44510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
45510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
46510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_ADDING_1:    // normal case
47510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        {
48510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // change state to indicate we are now adding the interface
49510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        *interfaceStateP = INTERFACE_ADDING_2;
50510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(thisObject);
51510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
52510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // this section runs with mutex unlocked
53bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        const struct iid_vtable *x = &clazz->mInterfaces[index];
54510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        size_t offset = x->mOffset;
55510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        void *thisItf = (char *) thisObject + offset;
56a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        BoolHook expose = MPH_init_table[MPH].mExpose;
57a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        // call the optional expose hook
58a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        if ((NULL == expose) || (*expose)(thisItf)) {
59a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            result = SL_RESULT_SUCCESS;
60a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        } else {
61a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            result = SL_RESULT_FEATURE_UNSUPPORTED;
62e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten        }
63510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
64510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // re-lock mutex to update state
65510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_lock_exclusive(thisObject);
66510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(INTERFACE_ADDING_2 == *interfaceStateP);
67a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        if (SL_RESULT_SUCCESS == result) {
68a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            ((size_t *) thisItf)[0] ^= ~0;
69a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            state = INTERFACE_ADDED;
70a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        } else {
71a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            state = INTERFACE_INITIALIZED;
72a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        }
73510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
74510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
75510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
76510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_ADDING_1A:   // operation was aborted while on work queue
77510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
78a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        state = INTERFACE_INITIALIZED;
79510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
80510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
81510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                    // impossible
82510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
83510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
84510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
85510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
86510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
87510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
88510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is locked, update state
89510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    *interfaceStateP = state;
90510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
91510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
92bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    slDynamicInterfaceManagementCallback callback = thiz->mCallback;
93bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    void *context = thiz->mContext;
94510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_unlock_exclusive(thisObject);
95510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
96510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Note that the mutex is unlocked during the callback
97510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (NULL != callback) {
98510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
99bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (*callback)(&thiz->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
100510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
101510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
102510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
103510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
104ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1053a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,
1063a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    const SLInterfaceID iid, SLboolean async)
10761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
108ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
109ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
110510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // validate input parameters
111ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == iid) {
112ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
113ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
114bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
115bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IObject *thisObject = InterfaceToIObject(thiz);
116bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        const ClassTable *clazz = thisObject->mClass;
117ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        int MPH, index;
118a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        if ((0 > (MPH = IID_to_MPH(iid))) ||
119a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                // no need to check for an initialization hook
120a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                // (NULL == MPH_init_table[MPH].mInit) ||
121bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                (0 > (index = clazz->mMPH_to_index[MPH]))) {
122ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_FEATURE_UNSUPPORTED;
123ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
124bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            assert(index < (int) clazz->mInterfaceCount);
125ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
126510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
127ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // check interface state
128ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_lock_exclusive(thisObject);
129ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            switch (*interfaceStateP) {
130ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
131a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            case INTERFACE_INITIALIZED: // normal case
132ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                if (async) {
133ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // Asynchronous: mark operation pending and cancellable
134ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    *interfaceStateP = INTERFACE_ADDING_1;
135ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    object_unlock_exclusive(thisObject);
136ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
137ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // this section runs with mutex unlocked
138cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten                    result = ThreadPool_add_ppi(&thisObject->mEngine->mThreadPool, HandleAdd, thiz,
139cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten                        NULL, MPH);
140ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    if (SL_RESULT_SUCCESS != result) {
141ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // Engine was destroyed during add, or insufficient memory,
142ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // so restore mInterfaceStates state to prior value
143ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        object_lock_exclusive(thisObject);
144ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        switch (*interfaceStateP) {
145ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        case INTERFACE_ADDING_1:    // normal
146ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        case INTERFACE_ADDING_1A:   // operation aborted while mutex unlocked
147a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                            *interfaceStateP = INTERFACE_INITIALIZED;
148ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            break;
149ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        default:                    // unexpected
150ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            // leave state alone
151ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            break;
152ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        }
153ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    }
154ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
155ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                } else {
156ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // Synchronous: mark operation pending to prevent duplication
157ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    *interfaceStateP = INTERFACE_ADDING_2;
158ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    object_unlock_exclusive(thisObject);
159ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
160ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // this section runs with mutex unlocked
161bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    const struct iid_vtable *x = &clazz->mInterfaces[index];
162ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    size_t offset = x->mOffset;
163ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    void *thisItf = (char *) thisObject + offset;
164a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // call the optional expose hook
165a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    BoolHook expose = MPH_init_table[MPH].mExpose;
166a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    if ((NULL == expose) || (*expose)(thisItf)) {
167a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                        result = SL_RESULT_SUCCESS;
168a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    } else {
169a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                        result = SL_RESULT_FEATURE_UNSUPPORTED;
170e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                    }
171ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
172ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // re-lock mutex to update state
173ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    object_lock_exclusive(thisObject);
174ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    assert(INTERFACE_ADDING_2 == *interfaceStateP);
175a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    if (SL_RESULT_SUCCESS == result) {
176a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                        *interfaceStateP = INTERFACE_ADDED;
177a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    } else {
178a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                        *interfaceStateP = INTERFACE_INITIALIZED;
179a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    }
180ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                }
181510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
182ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // mutex is still locked
183ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                break;
184ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
185ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            default:    // disallow adding of (partially) initialized interfaces
186ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                result = SL_RESULT_PRECONDITIONS_VIOLATED;
187ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                break;
188510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
189510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            }
190510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
191510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(thisObject);
192510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
19361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
19461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
196ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
19761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
19861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
199ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
20061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IDynamicInterfaceManagement_RemoveInterface(
20161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLDynamicInterfaceManagementItf self, const SLInterfaceID iid)
20261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
203ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
204510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
205711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
206ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    // validate input parameters
207ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == iid) {
208ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
209ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
210bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
211bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IObject *thisObject = InterfaceToIObject(thiz);
212bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        const ClassTable *clazz = thisObject->mClass;
213ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        int MPH, index;
214a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        if ((0 > (MPH = IID_to_MPH(iid))) ||
215a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                // no need to check for an initialization hook
216a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                // (NULL == MPH_init_table[MPH].mInit) ||
217bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                (0 > (index = clazz->mMPH_to_index[MPH]))) {
218ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PRECONDITIONS_VIOLATED;
219ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
220ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
221510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
222ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // check interface state
223ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_lock_exclusive(thisObject);
224ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            switch (*interfaceStateP) {
225ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
226ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            case INTERFACE_ADDED:       // normal cases
227ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            case INTERFACE_SUSPENDED:
228ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                {
229711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                // Compute address of the interface
230bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                const struct iid_vtable *x = &clazz->mInterfaces[index];
231ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                size_t offset = x->mOffset;
232ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                void *thisItf = (char *) thisObject + offset;
233711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten
234711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                // Mark operation pending (not necessary; remove is synchronous with mutex locked)
235711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                *interfaceStateP = INTERFACE_REMOVING;
236711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten
237711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                // Check if application ever called Object::GetInterface
238711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                unsigned mask = 1 << index;
239711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                if (thisObject->mGottenMask & mask) {
240711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                    thisObject->mGottenMask &= ~mask;
241711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                    // This trickery invalidates the v-table
242711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                    ((size_t *) thisItf)[0] ^= ~0;
243711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                }
244711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten
245711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                // The remove hook is called with mutex locked
246a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                VoidHook remove = MPH_init_table[MPH].mRemove;
247a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                if (NULL != remove) {
248a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    (*remove)(thisItf);
249a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                }
250ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                result = SL_RESULT_SUCCESS;
251ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
252ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                assert(INTERFACE_REMOVING == *interfaceStateP);
253a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                *interfaceStateP = INTERFACE_INITIALIZED;
254ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                }
255510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
256ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // mutex is still locked
257ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                break;
258510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            default:
260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // disallow removal of non-dynamic interfaces, or interfaces which are
261ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // currently being resumed (will not auto-cancel an asynchronous resume)
262ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                result = SL_RESULT_PRECONDITIONS_VIOLATED;
263ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                break;
264510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
265ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
266510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
267ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_unlock_exclusive(thisObject);
268ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
26961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
270711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten#else
271711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
272711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten#endif
273510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
274ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
27561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
27661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
277ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
278510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous ResumeInterface.
279510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the DynamicInterface, and MPH specifies which interface to resume.
280510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
281cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kastenstatic void HandleResume(void *self, void *ignored, int MPH)
282510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
283510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
284510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // validate input parameters
285bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
286bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz);
287bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thisObject = InterfaceToIObject(thiz);
288510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(NULL != thisObject);
289510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    assert(0 <= MPH && MPH < MPH_MAX);
290bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const ClassTable *clazz = thisObject->mClass;
291bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != clazz);
292bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    int index = clazz->mMPH_to_index[MPH];
293bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 <= index && index < (int) clazz->mInterfaceCount);
294510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
295510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    SLresult result;
296510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
297510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // check interface state
298510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_lock_exclusive(thisObject);
299276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state = *interfaceStateP;
300510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    switch (state) {
301510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
302510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_RESUMING_1:      // normal case
303510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        {
304510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // change state to indicate we are now resuming the interface
305510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        *interfaceStateP = INTERFACE_RESUMING_2;
306510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_unlock_exclusive(thisObject);
307510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
308510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // this section runs with mutex unlocked
309bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        const struct iid_vtable *x = &clazz->mInterfaces[index];
310510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        size_t offset = x->mOffset;
311510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        void *thisItf = (char *) thisObject + offset;
312510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        VoidHook resume = MPH_init_table[MPH].mResume;
313a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        if (NULL != resume) {
314510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            (*resume)(thisItf);
315a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        }
316510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_SUCCESS;
317510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
318510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        // re-lock mutex to update state
319510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        object_lock_exclusive(thisObject);
320510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(INTERFACE_RESUMING_2 == *interfaceStateP);
321510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = INTERFACE_ADDED;
322510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
323510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
324510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
325510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case INTERFACE_RESUMING_1A:     // operation was aborted while on work queue
326510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
327510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = INTERFACE_SUSPENDED;
328510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
329510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
330510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                        // impossible
331510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
332510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
333510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
334510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
335510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
336510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
337510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is locked, update state
338510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    *interfaceStateP = state;
339510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
340510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
341bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    slDynamicInterfaceManagementCallback callback = thiz->mCallback;
342bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    void *context = thiz->mContext;
343510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    object_unlock_exclusive(thisObject);
344510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
345510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Note that the mutex is unlocked during the callback
346510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (NULL != callback) {
347510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
348bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (*callback)(&thiz->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
349510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
350510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
351510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
352ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3533a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
35461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    const SLInterfaceID iid, SLboolean async)
35561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
356ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
357ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
358510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // validate input parameters
359ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == iid) {
360ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
361ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
362bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
363bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IObject *thisObject = InterfaceToIObject(thiz);
364bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        const ClassTable *clazz = thisObject->mClass;
365ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        int MPH, index;
366a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        if ((0 > (MPH = IID_to_MPH(iid))) ||
367a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                // no need to check for an initialization hook
368a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                // (NULL == MPH_init_table[MPH].mInit) ||
369bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                (0 > (index = clazz->mMPH_to_index[MPH]))) {
370ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PRECONDITIONS_VIOLATED;
371ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
372bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            assert(index < (int) clazz->mInterfaceCount);
373ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
374510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
375ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // check interface state
376ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            object_lock_exclusive(thisObject);
377ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            switch (*interfaceStateP) {
378ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
379ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            case INTERFACE_SUSPENDED:   // normal case
380ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                if (async) {
381ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // Asynchronous: mark operation pending and cancellable
382ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    *interfaceStateP = INTERFACE_RESUMING_1;
383ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    object_unlock_exclusive(thisObject);
384ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
385ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // this section runs with mutex unlocked
386cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten                    result = ThreadPool_add_ppi(&thisObject->mEngine->mThreadPool, HandleResume,
387cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten                        thiz, NULL, MPH);
388ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    if (SL_RESULT_SUCCESS != result) {
389ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // Engine was destroyed during resume, or insufficient memory,
390ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // so restore mInterfaceStates state to prior value
391ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        object_lock_exclusive(thisObject);
392ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        switch (*interfaceStateP) {
393ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        case INTERFACE_RESUMING_1:  // normal
394ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        case INTERFACE_RESUMING_1A: // operation aborted while mutex unlocked
395ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            *interfaceStateP = INTERFACE_SUSPENDED;
396ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            break;
397ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        default:                    // unexpected
398ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            // leave state alone
399ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                            break;
400ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        }
401ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    }
402ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
403ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                } else {
404ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // Synchronous: mark operation pending to prevent duplication
405ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    *interfaceStateP = INTERFACE_RESUMING_2;
406ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    object_unlock_exclusive(thisObject);
407ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
408ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // this section runs with mutex unlocked
409bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    const struct iid_vtable *x = &clazz->mInterfaces[index];
410ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    size_t offset = x->mOffset;
411bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    void *thisItf = (char *) thiz + offset;
412ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    VoidHook resume = MPH_init_table[MPH].mResume;
413a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    if (NULL != resume) {
414ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        (*resume)(thisItf);
415a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    }
416ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    result = SL_RESULT_SUCCESS;
417ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
418ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    // re-lock mutex to update state
419ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    object_lock_exclusive(thisObject);
420ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    assert(INTERFACE_RESUMING_2 == *interfaceStateP);
421ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    *interfaceStateP = INTERFACE_ADDED;
422ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                }
423510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
424711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                // mutex is now locked
425ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                break;
426510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
427ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            default:    // disallow resumption of non-suspended interfaces
428ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                result = SL_RESULT_PRECONDITIONS_VIOLATED;
429ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                break;
430510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            }
431510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
432510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            object_unlock_exclusive(thisObject);
4333a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten        }
4343a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten    }
435510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
436ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
43761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
43861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
439ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
4403a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
44161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    slDynamicInterfaceManagementCallback callback, void *pContext)
44261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
443ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
444ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
445bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
446bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thisObject = InterfaceToIObject(thiz);
44761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_lock_exclusive(thisObject);
448bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = callback;
449bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = pContext;
45061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    object_unlock_exclusive(thisObject);
451ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
452ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
453ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
45461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
45561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
456ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
45761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic const struct SLDynamicInterfaceManagementItf_ IDynamicInterfaceManagement_Itf = {
45861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicInterfaceManagement_AddInterface,
45961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicInterfaceManagement_RemoveInterface,
46061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicInterfaceManagement_ResumeInterface,
46161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IDynamicInterfaceManagement_RegisterCallback
46261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten};
46361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
46461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenvoid IDynamicInterfaceManagement_init(void *self)
46561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
466bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
467bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IDynamicInterfaceManagement_Itf;
468bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = NULL;
469bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = NULL;
47061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
471