static SLresult I3DGrouping_Set3DGroup(SL3DGroupingItf self, SLObjectItf group) { SL_ENTER_INTERFACE // validate input parameters C3DGroup *newGroup = (C3DGroup *) group; result = SL_RESULT_SUCCESS; if (NULL != newGroup) { // check that new group has the correct object ID and is realized, and acquire a strong // reference to it. FYI note that a deadlock will occur if application incorrectly // specifies group as this audio player result = AcquireStrongRef(&newGroup->mObject, SL_OBJECTID_3DGROUP); // the new group is left unlocked, but it will be locked again below } if (SL_RESULT_SUCCESS == result) { I3DGrouping *thiz = (I3DGrouping *) self; IObject *thisObject = InterfaceToIObject(thiz); unsigned id = thisObject->mInstanceID; assert(0 != id); // player object must be published by this point --id; assert(MAX_INSTANCE > id); unsigned mask = 1 << id; interface_lock_exclusive(thiz); C3DGroup *oldGroup = thiz->mGroup; if (newGroup != oldGroup) { // remove this object from the old group's set of objects if (NULL != oldGroup) { IObject *oldGroupObject = &oldGroup->mObject; // note that we already have a strong reference to the old group object_lock_exclusive(oldGroupObject); assert(oldGroup->mMemberMask & mask); oldGroup->mMemberMask &= ~mask; ReleaseStrongRefAndUnlockExclusive(oldGroupObject); } // add this object to the new group's set of objects if (NULL != newGroup) { IObject *newGroupObject = &newGroup->mObject; // we already have a strong reference to the new group, but we need to re-lock it // so that we always lock objects in the same nesting order to prevent a deadlock object_lock_exclusive(newGroupObject); assert(!(newGroup->mMemberMask & mask)); newGroup->mMemberMask |= mask; object_unlock_exclusive(newGroupObject); } thiz->mGroup = newGroup; } interface_unlock_exclusive(thiz); } SL_LEAVE_INTERFACE }
static void HandleAdd(void *self, int MPH) { // validate input parameters IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self; assert(NULL != this); IObject *thisObject = InterfaceToIObject(this); assert(NULL != thisObject); assert(0 <= MPH && MPH < MPH_MAX); const ClassTable *class__ = thisObject->mClass; assert(NULL != class__); int index = class__->mMPH_to_index[MPH]; assert(0 <= index && index < (int) class__->mInterfaceCount); SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index]; SLresult result; // check interface state object_lock_exclusive(thisObject); SLuint8 state = *interfaceStateP; switch (state) { case INTERFACE_ADDING_1: // normal case { // change state to indicate we are now adding the interface *interfaceStateP = INTERFACE_ADDING_2; object_unlock_exclusive(thisObject); // this section runs with mutex unlocked const struct iid_vtable *x = &class__->mInterfaces[index]; size_t offset = x->mOffset; void *thisItf = (char *) thisObject + offset; BoolHook expose = MPH_init_table[MPH].mExpose; // call the optional expose hook if ((NULL == expose) || (*expose)(thisItf)) { result = SL_RESULT_SUCCESS; } else { result = SL_RESULT_FEATURE_UNSUPPORTED; } // re-lock mutex to update state object_lock_exclusive(thisObject); assert(INTERFACE_ADDING_2 == *interfaceStateP); if (SL_RESULT_SUCCESS == result) { ((size_t *) thisItf)[0] ^= ~0; state = INTERFACE_ADDED; } else { state = INTERFACE_INITIALIZED; } } break; case INTERFACE_ADDING_1A: // operation was aborted while on work queue result = SL_RESULT_OPERATION_ABORTED; state = INTERFACE_INITIALIZED; break; default: // impossible assert(SL_BOOLEAN_FALSE); result = SL_RESULT_INTERNAL_ERROR; break; } // mutex is locked, update state *interfaceStateP = state; // Make a copy of these, so we can call the callback with mutex unlocked slDynamicInterfaceManagementCallback callback = this->mCallback; void *context = this->mContext; object_unlock_exclusive(thisObject); // Note that the mutex is unlocked during the callback if (NULL != callback) { const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID (*callback)(&this->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid); } }