Home | History | Annotate | Download | only in libopensles
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /* Object implementation */
     18 
     19 #include "sles_allinclusive.h"
     20 
     21 
     22 // Called by a worker thread to handle an asynchronous Object.Realize.
     23 // Parameter self is the Object.
     24 
     25 static void HandleRealize(void *self, int unused)
     26 {
     27 
     28     // validate input parameters
     29     IObject *this = (IObject *) self;
     30     assert(NULL != this);
     31     const ClassTable *class__ = this->mClass;
     32     assert(NULL != class__);
     33     AsyncHook realize = class__->mRealize;
     34     SLresult result;
     35     SLuint8 state;
     36 
     37     // check object state
     38     object_lock_exclusive(this);
     39     state = this->mState;
     40     switch (state) {
     41 
     42     case SL_OBJECT_STATE_REALIZING_1:   // normal case
     43         if (NULL != realize) {
     44             this->mState = SL_OBJECT_STATE_REALIZING_2;
     45             object_unlock_exclusive(this);
     46             // Note that the mutex is unlocked during the realize hook
     47             result = (*realize)(this, SL_BOOLEAN_TRUE);
     48             object_lock_exclusive(this);
     49             assert(SL_OBJECT_STATE_REALIZING_2 == this->mState);
     50             state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
     51                 SL_OBJECT_STATE_UNREALIZED;
     52         } else {
     53             result = SL_RESULT_SUCCESS;
     54             state = SL_OBJECT_STATE_REALIZED;
     55         }
     56         break;
     57 
     58     case SL_OBJECT_STATE_REALIZING_1A:  // operation was aborted while on work queue
     59         result = SL_RESULT_OPERATION_ABORTED;
     60         state = SL_OBJECT_STATE_UNREALIZED;
     61         break;
     62 
     63     default:                            // impossible
     64         assert(SL_BOOLEAN_FALSE);
     65         result = SL_RESULT_INTERNAL_ERROR;
     66         break;
     67 
     68     }
     69 
     70     // mutex is locked, update state
     71     this->mState = state;
     72 
     73     // Make a copy of these, so we can call the callback with mutex unlocked
     74     slObjectCallback callback = this->mCallback;
     75     void *context = this->mContext;
     76     object_unlock_exclusive(this);
     77 
     78     // Note that the mutex is unlocked during the callback
     79     if (NULL != callback) {
     80         (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
     81     }
     82 }
     83 
     84 
     85 static SLresult IObject_Realize(SLObjectItf self, SLboolean async)
     86 {
     87     SL_ENTER_INTERFACE
     88 
     89     IObject *this = (IObject *) self;
     90     SLuint8 state;
     91     const ClassTable *class__ = this->mClass;
     92     object_lock_exclusive(this);
     93     state = this->mState;
     94     // Reject redundant calls to Realize
     95     if (SL_OBJECT_STATE_UNREALIZED != state) {
     96         object_unlock_exclusive(this);
     97         result = SL_RESULT_PRECONDITIONS_VIOLATED;
     98     } else {
     99         // Asynchronous: mark operation pending and cancellable
    100         if (async && (SL_OBJECTID_ENGINE != class__->mObjectID)) {
    101             state = SL_OBJECT_STATE_REALIZING_1;
    102         // Synchronous: mark operation pending and non-cancellable
    103         } else {
    104             state = SL_OBJECT_STATE_REALIZING_2;
    105         }
    106         this->mState = state;
    107         object_unlock_exclusive(this);
    108         switch (state) {
    109         case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine
    110             assert(async);
    111             result = ThreadPool_add(&this->mEngine->mThreadPool, HandleRealize, this, 0);
    112             if (SL_RESULT_SUCCESS != result) {
    113                 // Engine was destroyed during realize, or insufficient memory
    114                 object_lock_exclusive(this);
    115                 this->mState = SL_OBJECT_STATE_UNREALIZED;
    116                 object_unlock_exclusive(this);
    117             }
    118             break;
    119         case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine
    120             {
    121             AsyncHook realize = class__->mRealize;
    122             // Note that the mutex is unlocked during the realize hook
    123             result = (NULL != realize) ? (*realize)(this, async) : SL_RESULT_SUCCESS;
    124             object_lock_exclusive(this);
    125             assert(SL_OBJECT_STATE_REALIZING_2 == this->mState);
    126             state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
    127                 SL_OBJECT_STATE_UNREALIZED;
    128             this->mState = state;
    129             slObjectCallback callback = this->mCallback;
    130             void *context = this->mContext;
    131             object_unlock_exclusive(this);
    132             // asynchronous Realize on an Engine is actually done synchronously, but still has
    133             // callback because there is no thread pool yet to do it asynchronously.
    134             if (async && (NULL != callback)) {
    135                 (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state,
    136                     NULL);
    137             }
    138             }
    139             break;
    140         default:                          // impossible
    141             assert(SL_BOOLEAN_FALSE);
    142             break;
    143         }
    144     }
    145 
    146     SL_LEAVE_INTERFACE
    147 }
    148 
    149 
    150 // Called by a worker thread to handle an asynchronous Object.Resume.
    151 // Parameter self is the Object.
    152 
    153 static void HandleResume(void *self, int unused)
    154 {
    155 
    156     // valid input parameters
    157     IObject *this = (IObject *) self;
    158     assert(NULL != this);
    159     const ClassTable *class__ = this->mClass;
    160     assert(NULL != class__);
    161     AsyncHook resume = class__->mResume;
    162     SLresult result;
    163     SLuint8 state;
    164 
    165     // check object state
    166     object_lock_exclusive(this);
    167     state = this->mState;
    168     switch (state) {
    169 
    170     case SL_OBJECT_STATE_RESUMING_1:    // normal case
    171         if (NULL != resume) {
    172             this->mState = SL_OBJECT_STATE_RESUMING_2;
    173             object_unlock_exclusive(this);
    174             // Note that the mutex is unlocked during the resume hook
    175             result = (*resume)(this, SL_BOOLEAN_TRUE);
    176             object_lock_exclusive(this);
    177             assert(SL_OBJECT_STATE_RESUMING_2 == this->mState);
    178             state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
    179                 SL_OBJECT_STATE_SUSPENDED;
    180         } else {
    181             result = SL_RESULT_SUCCESS;
    182             state = SL_OBJECT_STATE_REALIZED;
    183         }
    184         break;
    185 
    186     case SL_OBJECT_STATE_RESUMING_1A:   // operation was aborted while on work queue
    187         result = SL_RESULT_OPERATION_ABORTED;
    188         state = SL_OBJECT_STATE_SUSPENDED;
    189         break;
    190 
    191     default:                            // impossible
    192         assert(SL_BOOLEAN_FALSE);
    193         result = SL_RESULT_INTERNAL_ERROR;
    194         break;
    195 
    196     }
    197 
    198     // mutex is unlocked, update state
    199     this->mState = state;
    200 
    201     // Make a copy of these, so we can call the callback with mutex unlocked
    202     slObjectCallback callback = this->mCallback;
    203     void *context = this->mContext;
    204     object_unlock_exclusive(this);
    205 
    206     // Note that the mutex is unlocked during the callback
    207     if (NULL != callback) {
    208         (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
    209     }
    210 }
    211 
    212 
    213 static SLresult IObject_Resume(SLObjectItf self, SLboolean async)
    214 {
    215     SL_ENTER_INTERFACE
    216 
    217     IObject *this = (IObject *) self;
    218     const ClassTable *class__ = this->mClass;
    219     SLuint8 state;
    220     object_lock_exclusive(this);
    221     state = this->mState;
    222     // Reject redundant calls to Resume
    223     if (SL_OBJECT_STATE_SUSPENDED != state) {
    224         object_unlock_exclusive(this);
    225         result = SL_RESULT_PRECONDITIONS_VIOLATED;
    226     } else {
    227         // Asynchronous: mark operation pending and cancellable
    228         if (async) {
    229             state = SL_OBJECT_STATE_RESUMING_1;
    230         // Synchronous: mark operatio pending and non-cancellable
    231         } else {
    232             state = SL_OBJECT_STATE_RESUMING_2;
    233         }
    234         this->mState = state;
    235         object_unlock_exclusive(this);
    236         switch (state) {
    237         case SL_OBJECT_STATE_RESUMING_1: // asynchronous
    238             assert(async);
    239             result = ThreadPool_add(&this->mEngine->mThreadPool, HandleResume, this, 0);
    240             if (SL_RESULT_SUCCESS != result) {
    241                 // Engine was destroyed during resume, or insufficient memory
    242                 object_lock_exclusive(this);
    243                 this->mState = SL_OBJECT_STATE_SUSPENDED;
    244                 object_unlock_exclusive(this);
    245             }
    246             break;
    247         case SL_OBJECT_STATE_RESUMING_2: // synchronous
    248             {
    249             AsyncHook resume = class__->mResume;
    250             // Note that the mutex is unlocked during the resume hook
    251             result = (NULL != resume) ? (*resume)(this, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS;
    252             object_lock_exclusive(this);
    253             assert(SL_OBJECT_STATE_RESUMING_2 == this->mState);
    254             this->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
    255                 SL_OBJECT_STATE_SUSPENDED;
    256             object_unlock_exclusive(this);
    257             }
    258             break;
    259         default:                        // impossible
    260             assert(SL_BOOLEAN_FALSE);
    261             break;
    262         }
    263     }
    264 
    265     SL_LEAVE_INTERFACE
    266 }
    267 
    268 
    269 static SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState)
    270 {
    271     SL_ENTER_INTERFACE
    272 
    273     if (NULL == pState) {
    274         result = SL_RESULT_PARAMETER_INVALID;
    275     } else {
    276         IObject *this = (IObject *) self;
    277         // Note that the state is immediately obsolete, so a peek lock is safe
    278         object_lock_peek(this);
    279         SLuint8 state = this->mState;
    280         object_unlock_peek(this);
    281         // Re-map the realizing, resuming, and suspending states
    282         switch (state) {
    283         case SL_OBJECT_STATE_REALIZING_1:
    284         case SL_OBJECT_STATE_REALIZING_1A:
    285         case SL_OBJECT_STATE_REALIZING_2:
    286         case SL_OBJECT_STATE_DESTROYING:    // application shouldn't call GetState after Destroy
    287             state = SL_OBJECT_STATE_UNREALIZED;
    288             break;
    289         case SL_OBJECT_STATE_RESUMING_1:
    290         case SL_OBJECT_STATE_RESUMING_1A:
    291         case SL_OBJECT_STATE_RESUMING_2:
    292         case SL_OBJECT_STATE_SUSPENDING:
    293             state = SL_OBJECT_STATE_SUSPENDED;
    294             break;
    295         case SL_OBJECT_STATE_UNREALIZED:
    296         case SL_OBJECT_STATE_REALIZED:
    297         case SL_OBJECT_STATE_SUSPENDED:
    298             // These are the "official" object states, return them as is
    299             break;
    300         default:
    301             assert(SL_BOOLEAN_FALSE);
    302             break;
    303         }
    304         *pState = state;
    305         result = SL_RESULT_SUCCESS;
    306     }
    307 
    308     SL_LEAVE_INTERFACE
    309 }
    310 
    311 static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface)
    312 {
    313     SL_ENTER_INTERFACE
    314 
    315     if (NULL == pInterface) {
    316         result = SL_RESULT_PARAMETER_INVALID;
    317     } else {
    318         void *interface = NULL;
    319         if (NULL == iid) {
    320             result = SL_RESULT_PARAMETER_INVALID;
    321         } else {
    322             IObject *this = (IObject *) self;
    323             const ClassTable *class__ = this->mClass;
    324             int MPH, index;
    325             if ((0 > (MPH = IID_to_MPH(iid))) ||
    326                     // no need to check for an initialization hook
    327                     // (NULL == MPH_init_table[MPH].mInit) ||
    328                     (0 > (index = class__->mMPH_to_index[MPH]))) {
    329                 result = SL_RESULT_FEATURE_UNSUPPORTED;
    330             } else {
    331                 unsigned mask = 1 << index;
    332                 object_lock_exclusive(this);
    333                 if ((SL_OBJECT_STATE_REALIZED != this->mState) &&
    334                         !(INTERFACE_PREREALIZE & class__->mInterfaces[index].mInterface)) {
    335                     // Can't get interface on an unrealized object unless pre-realize is ok
    336                     result = SL_RESULT_PRECONDITIONS_VIOLATED;
    337                 } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER == class__->mObjectID)
    338                         && (1 == ((CAudioPlayer *) this)->mNumChannels)) {
    339                     // Can't get the MuteSolo interface of an audio player if the channel count is
    340                     // mono, but _can_ get the MuteSolo interface if the channel count is unknown
    341                     result = SL_RESULT_FEATURE_UNSUPPORTED;
    342                 } else {
    343                     switch (this->mInterfaceStates[index]) {
    344                     case INTERFACE_EXPOSED:
    345                     case INTERFACE_ADDED:
    346                         interface = (char *) this + class__->mInterfaces[index].mOffset;
    347                         // Note that interface has been gotten,
    348                         // for debugger and to detect incorrect use of interfaces
    349                         if (!(this->mGottenMask & mask)) {
    350                             this->mGottenMask |= mask;
    351                             // This trickery validates the v-table
    352                             ((size_t *) interface)[0] ^= ~0;
    353                         }
    354                         result = SL_RESULT_SUCCESS;
    355                         break;
    356                     // Can't get interface if uninitialized, initialized, suspended,
    357                     // suspending, resuming, adding, or removing
    358                     default:
    359                         result = SL_RESULT_FEATURE_UNSUPPORTED;
    360                         break;
    361                     }
    362                 }
    363                 object_unlock_exclusive(this);
    364             }
    365         }
    366         *(void **)pInterface = interface;
    367     }
    368 
    369     SL_LEAVE_INTERFACE
    370 }
    371 
    372 
    373 static SLresult IObject_RegisterCallback(SLObjectItf self,
    374     slObjectCallback callback, void *pContext)
    375 {
    376     SL_ENTER_INTERFACE
    377 
    378     IObject *this = (IObject *) self;
    379     object_lock_exclusive(this);
    380     this->mCallback = callback;
    381     this->mContext = pContext;
    382     object_unlock_exclusive(this);
    383     result = SL_RESULT_SUCCESS;
    384 
    385     SL_LEAVE_INTERFACE
    386 }
    387 
    388 
    389 /** \brief This is internal common code for Abort and Destroy.
    390  *  Note: called with mutex unlocked, and returns with mutex locked.
    391  */
    392 
    393 static void Abort_internal(IObject *this)
    394 {
    395     const ClassTable *class__ = this->mClass;
    396     bool anyAsync = false;
    397     object_lock_exclusive(this);
    398 
    399     // Abort asynchronous operations on the object
    400     switch (this->mState) {
    401     case SL_OBJECT_STATE_REALIZING_1:   // Realize
    402         this->mState = SL_OBJECT_STATE_REALIZING_1A;
    403         anyAsync = true;
    404         break;
    405     case SL_OBJECT_STATE_RESUMING_1:    // Resume
    406         this->mState = SL_OBJECT_STATE_RESUMING_1A;
    407         anyAsync = true;
    408         break;
    409     case SL_OBJECT_STATE_REALIZING_1A:  // Realize
    410     case SL_OBJECT_STATE_REALIZING_2:
    411     case SL_OBJECT_STATE_RESUMING_1A:   // Resume
    412     case SL_OBJECT_STATE_RESUMING_2:
    413         anyAsync = true;
    414         break;
    415     case SL_OBJECT_STATE_DESTROYING:
    416         assert(false);
    417         break;
    418     default:
    419         break;
    420     }
    421 
    422     // Abort asynchronous operations on interfaces
    423     SLuint8 *interfaceStateP = this->mInterfaceStates;
    424     unsigned index;
    425     for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) {
    426         switch (*interfaceStateP) {
    427         case INTERFACE_ADDING_1:    // AddInterface
    428             *interfaceStateP = INTERFACE_ADDING_1A;
    429             anyAsync = true;
    430             break;
    431         case INTERFACE_RESUMING_1:  // ResumeInterface
    432             *interfaceStateP = INTERFACE_RESUMING_1A;
    433             anyAsync = true;
    434             break;
    435         case INTERFACE_ADDING_1A:   // AddInterface
    436         case INTERFACE_ADDING_2:
    437         case INTERFACE_RESUMING_1A: // ResumeInterface
    438         case INTERFACE_RESUMING_2:
    439         case INTERFACE_REMOVING:    // not observable: RemoveInterface is synchronous & mutex locked
    440             anyAsync = true;
    441             break;
    442         default:
    443             break;
    444         }
    445     }
    446 
    447     // Wait until all asynchronous operations either complete normally or recognize the abort
    448     while (anyAsync) {
    449         object_unlock_exclusive(this);
    450         // FIXME should use condition variable instead of polling
    451         usleep(20000);
    452         anyAsync = false;
    453         object_lock_exclusive(this);
    454         switch (this->mState) {
    455         case SL_OBJECT_STATE_REALIZING_1:   // state 1 means it cycled during the usleep window
    456         case SL_OBJECT_STATE_RESUMING_1:
    457         case SL_OBJECT_STATE_REALIZING_1A:
    458         case SL_OBJECT_STATE_REALIZING_2:
    459         case SL_OBJECT_STATE_RESUMING_1A:
    460         case SL_OBJECT_STATE_RESUMING_2:
    461             anyAsync = true;
    462             break;
    463         case SL_OBJECT_STATE_DESTROYING:
    464             assert(false);
    465             break;
    466         default:
    467             break;
    468         }
    469         interfaceStateP = this->mInterfaceStates;
    470         for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) {
    471             switch (*interfaceStateP) {
    472             case INTERFACE_ADDING_1:    // state 1 means it cycled during the usleep window
    473             case INTERFACE_RESUMING_1:
    474             case INTERFACE_ADDING_1A:
    475             case INTERFACE_ADDING_2:
    476             case INTERFACE_RESUMING_1A:
    477             case INTERFACE_RESUMING_2:
    478             case INTERFACE_REMOVING:
    479                 anyAsync = true;
    480                 break;
    481             default:
    482                 break;
    483             }
    484         }
    485     }
    486 
    487     // At this point there are no pending asynchronous operations
    488 }
    489 
    490 
    491 static void IObject_AbortAsyncOperation(SLObjectItf self)
    492 {
    493     SL_ENTER_INTERFACE_VOID
    494 
    495     IObject *this = (IObject *) self;
    496     Abort_internal(this);
    497     object_unlock_exclusive(this);
    498 
    499     SL_LEAVE_INTERFACE_VOID
    500 }
    501 
    502 
    503 void IObject_Destroy(SLObjectItf self)
    504 {
    505     SL_ENTER_INTERFACE_VOID
    506 
    507     IObject *this = (IObject *) self;
    508     // mutex is unlocked
    509     Abort_internal(this);
    510     // mutex is locked
    511     const ClassTable *class__ = this->mClass;
    512     BoolHook preDestroy = class__->mPreDestroy;
    513     // The pre-destroy hook is called with mutex locked, and should block until it is safe to
    514     // destroy.  It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex
    515     // before returning.
    516     if (NULL != preDestroy) {
    517         bool okToDestroy = (*preDestroy)(this);
    518         if (!okToDestroy) {
    519             object_unlock_exclusive(this);
    520             // unfortunately Destroy doesn't return a result
    521             SL_LOGE("Object::Destroy(%p) not allowed", this);
    522             SL_LEAVE_INTERFACE_VOID
    523         }
    524     }
    525     this->mState = SL_OBJECT_STATE_DESTROYING;
    526     VoidHook destroy = class__->mDestroy;
    527     // const, no lock needed
    528     IEngine *thisEngine = this->mEngine;
    529     unsigned i = this->mInstanceID;
    530     assert(MAX_INSTANCE >= i);
    531     // avoid a recursive lock on the engine when destroying the engine itself
    532     if (thisEngine->mThis != this) {
    533         interface_lock_exclusive(thisEngine);
    534     }
    535     // An unpublished object has a slot reserved, but the ID hasn't been chosen yet
    536     assert(0 < thisEngine->mInstanceCount);
    537     --thisEngine->mInstanceCount;
    538     // If object is published, then remove it from exposure to sync thread and debugger
    539     if (0 != i) {
    540         --i;
    541         unsigned mask = 1 << i;
    542         assert(thisEngine->mInstanceMask & mask);
    543         thisEngine->mInstanceMask &= ~mask;
    544         assert(thisEngine->mInstances[i] == this);
    545         thisEngine->mInstances[i] = NULL;
    546     }
    547     // avoid a recursive unlock on the engine when destroying the engine itself
    548     if (thisEngine->mThis != this) {
    549         interface_unlock_exclusive(thisEngine);
    550     }
    551     // The destroy hook is called with mutex locked
    552     if (NULL != destroy) {
    553         (*destroy)(this);
    554     }
    555     // Call the deinitializer for each currently initialized interface,
    556     // whether it is implicit, explicit, optional, or dynamically added.
    557     // The deinitializers are called in the reverse order that the
    558     // initializers were called, so that IObject_deinit is called last.
    559     unsigned index = class__->mInterfaceCount;
    560     const struct iid_vtable *x = &class__->mInterfaces[index];
    561     SLuint8 *interfaceStateP = &this->mInterfaceStates[index];
    562     for ( ; index > 0; --index) {
    563         --x;
    564         size_t offset = x->mOffset;
    565         void *thisItf = (char *) this + offset;
    566         SLuint32 state = *--interfaceStateP;
    567         switch (state) {
    568         case INTERFACE_UNINITIALIZED:
    569             break;
    570         case INTERFACE_EXPOSED:     // quiescent states
    571         case INTERFACE_ADDED:
    572         case INTERFACE_SUSPENDED:
    573             // The remove hook is called with mutex locked
    574             {
    575             VoidHook remove = MPH_init_table[x->mMPH].mRemove;
    576             if (NULL != remove) {
    577                 (*remove)(thisItf);
    578             }
    579             *interfaceStateP = INTERFACE_INITIALIZED;
    580             }
    581             // fall through
    582         case INTERFACE_INITIALIZED:
    583             {
    584             VoidHook deinit = MPH_init_table[x->mMPH].mDeinit;
    585             if (NULL != deinit) {
    586                 (*deinit)(thisItf);
    587             }
    588             *interfaceStateP = INTERFACE_UNINITIALIZED;
    589             }
    590             break;
    591         case INTERFACE_ADDING_1:    // active states indicate incorrect use of API
    592         case INTERFACE_ADDING_1A:
    593         case INTERFACE_ADDING_2:
    594         case INTERFACE_RESUMING_1:
    595         case INTERFACE_RESUMING_1A:
    596         case INTERFACE_RESUMING_2:
    597         case INTERFACE_REMOVING:
    598         case INTERFACE_SUSPENDING:
    599             SL_LOGE("Object::Destroy(%p) while interface %u active", this, index);
    600             break;
    601         default:
    602             assert(SL_BOOLEAN_FALSE);
    603             break;
    604         }
    605     }
    606     // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer
    607     memset(this, 0x55, class__->mSize); // catch broken applications that continue using interfaces
    608                                         // was ifdef USE_DEBUG but safer to do this unconditionally
    609     free(this);
    610 
    611     if (SL_OBJECTID_ENGINE == class__->mObjectID) {
    612         CEngine_Destroyed((CEngine *) this);
    613     }
    614 
    615     SL_LEAVE_INTERFACE_VOID
    616 }
    617 
    618 
    619 static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable)
    620 {
    621     SL_ENTER_INTERFACE
    622 
    623 #if USE_PROFILES & USE_PROFILES_BASE
    624     IObject *this = (IObject *) self;
    625     object_lock_exclusive(this);
    626     this->mPriority = priority;
    627     this->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize
    628     object_unlock_exclusive(this);
    629     result = SL_RESULT_SUCCESS;
    630 #else
    631     result = SL_RESULT_FEATURE_UNSUPPORTED;
    632 #endif
    633 
    634     SL_LEAVE_INTERFACE
    635 }
    636 
    637 
    638 static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable)
    639 {
    640     SL_ENTER_INTERFACE
    641 
    642 #if USE_PROFILES & USE_PROFILES_BASE
    643     if (NULL == pPriority || NULL == pPreemptable) {
    644         result = SL_RESULT_PARAMETER_INVALID;
    645     } else {
    646         IObject *this = (IObject *) self;
    647         object_lock_shared(this);
    648         SLint32 priority = this->mPriority;
    649         SLboolean preemptable = this->mPreemptable;
    650         object_unlock_shared(this);
    651         *pPriority = priority;
    652         *pPreemptable = preemptable;
    653         result = SL_RESULT_SUCCESS;
    654     }
    655 #else
    656     result = SL_RESULT_FEATURE_UNSUPPORTED;
    657 #endif
    658 
    659     SL_LEAVE_INTERFACE
    660 }
    661 
    662 
    663 static SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self,
    664     SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled)
    665 {
    666     SL_ENTER_INTERFACE
    667 
    668 #if USE_PROFILES & USE_PROFILES_BASE
    669     result = SL_RESULT_SUCCESS;
    670     if (0 < numInterfaces) {
    671         SLuint32 i;
    672         if (NULL == pInterfaceIDs) {
    673             result = SL_RESULT_PARAMETER_INVALID;
    674         } else {
    675             IObject *this = (IObject *) self;
    676             const ClassTable *class__ = this->mClass;
    677             unsigned lossOfControlMask = 0;
    678             // The cast is due to a typo in the spec, bug 6482
    679             for (i = 0; i < (SLuint32) numInterfaces; ++i) {
    680                 SLInterfaceID iid = pInterfaceIDs[i];
    681                 if (NULL == iid) {
    682                     result = SL_RESULT_PARAMETER_INVALID;
    683                     goto out;
    684                 }
    685                 int MPH, index;
    686                 // We ignore without error any invalid MPH or index, but spec is unclear
    687                 if ((0 <= (MPH = IID_to_MPH(iid))) &&
    688                         // no need to check for an initialization hook
    689                         // (NULL == MPH_init_table[MPH].mInit) ||
    690                         (0 <= (index = class__->mMPH_to_index[MPH]))) {
    691                     lossOfControlMask |= (1 << index);
    692                 }
    693             }
    694             object_lock_exclusive(this);
    695             if (enabled) {
    696                 this->mLossOfControlMask |= lossOfControlMask;
    697             } else {
    698                 this->mLossOfControlMask &= ~lossOfControlMask;
    699             }
    700             object_unlock_exclusive(this);
    701         }
    702     }
    703 out:
    704 #else
    705     result = SL_RESULT_FEATURE_UNSUPPORTED;
    706 #endif
    707 
    708     SL_LEAVE_INTERFACE
    709 }
    710 
    711 
    712 static const struct SLObjectItf_ IObject_Itf = {
    713     IObject_Realize,
    714     IObject_Resume,
    715     IObject_GetState,
    716     IObject_GetInterface,
    717     IObject_RegisterCallback,
    718     IObject_AbortAsyncOperation,
    719     IObject_Destroy,
    720     IObject_SetPriority,
    721     IObject_GetPriority,
    722     IObject_SetLossOfControlInterfaces,
    723 };
    724 
    725 
    726 /** \brief This must be the first initializer called for an object */
    727 
    728 void IObject_init(void *self)
    729 {
    730     IObject *this = (IObject *) self;
    731     this->mItf = &IObject_Itf;
    732     // initialized in construct:
    733     // mClass
    734     // mInstanceID
    735     // mLossOfControlMask
    736     // mEngine
    737     // mInterfaceStates
    738     this->mState = SL_OBJECT_STATE_UNREALIZED;
    739     this->mGottenMask = 1;  // IObject
    740     this->mAttributesMask = 0;
    741     this->mCallback = NULL;
    742     this->mContext = NULL;
    743 #if USE_PROFILES & USE_PROFILES_BASE
    744     this->mPriority = SL_PRIORITY_NORMAL;
    745     this->mPreemptable = SL_BOOLEAN_FALSE;
    746 #endif
    747     this->mStrongRefCount = 0;
    748     int ok;
    749     ok = pthread_mutex_init(&this->mMutex, (const pthread_mutexattr_t *) NULL);
    750     assert(0 == ok);
    751 #ifdef USE_DEBUG
    752     memset(&this->mOwner, 0, sizeof(pthread_t));
    753     this->mFile = NULL;
    754     this->mLine = 0;
    755 #endif
    756     ok = pthread_cond_init(&this->mCond, (const pthread_condattr_t *) NULL);
    757     assert(0 == ok);
    758 }
    759 
    760 
    761 /** \brief This must be the last deinitializer called for an object */
    762 
    763 void IObject_deinit(void *self)
    764 {
    765     IObject *this = (IObject *) self;
    766 #ifdef USE_DEBUG
    767     assert(pthread_equal(pthread_self(), this->mOwner));
    768 #endif
    769     int ok;
    770     ok = pthread_cond_destroy(&this->mCond);
    771     assert(0 == ok);
    772     // equivalent to object_unlock_exclusive, but without the rigmarole
    773     ok = pthread_mutex_unlock(&this->mMutex);
    774     assert(0 == ok);
    775     ok = pthread_mutex_destroy(&this->mMutex);
    776     assert(0 == ok);
    777     // redundant: this->mState = SL_OBJECT_STATE_UNREALIZED;
    778 }
    779 
    780 
    781 /** \brief Publish a new object after it is fully initialized.
    782  *  Publishing will expose the object to sync thread and debugger,
    783  *  and make it safe to return the SLObjectItf to the application.
    784  */
    785 
    786 void IObject_Publish(IObject *this)
    787 {
    788     IEngine *thisEngine = this->mEngine;
    789     interface_lock_exclusive(thisEngine);
    790     // construct earlier reserved a pending slot, but did not choose the actual slot number
    791     unsigned availMask = ~thisEngine->mInstanceMask;
    792     assert(availMask);
    793     unsigned i = ctz(availMask);
    794     assert(MAX_INSTANCE > i);
    795     assert(NULL == thisEngine->mInstances[i]);
    796     thisEngine->mInstances[i] = this;
    797     thisEngine->mInstanceMask |= 1 << i;
    798     // avoid zero as a valid instance ID
    799     this->mInstanceID = i + 1;
    800     interface_unlock_exclusive(thisEngine);
    801 }
    802