void AudioNode::deref(RefType refType) { // The actually work for deref happens completely within the audio context's graph lock. // In the case of the audio thread, we must use a tryLock to avoid glitches. bool hasLock = false; bool mustReleaseLock = false; if (context()->isAudioThread()) { // Real-time audio thread must not contend lock (to avoid glitches). hasLock = context()->tryLock(mustReleaseLock); } else { context()->lock(mustReleaseLock); hasLock = true; } if (hasLock) { // This is where the real deref work happens. finishDeref(refType); if (mustReleaseLock) context()->unlock(); } else { // We were unable to get the lock, so put this in a list to finish up later. ASSERT(context()->isAudioThread()); context()->addDeferredFinishDeref(this, refType); } // Once AudioContext::uninitialize() is called there's no more chances for deleteMarkedNodes() to get called, so we call here. // We can't call in AudioContext::~AudioContext() since it will never be called as long as any AudioNode is alive // because AudioNodes keep a reference to the context. if (context()->isAudioThreadFinished()) context()->deleteMarkedNodes(); }
// This method could be called both by the main thread because // (1) a RefCounted ptr has been deleted or from the audio thread // because (2) of a disconnect or the deletion of a node that was // connected to us. void AudioNode::decrementRefCount(RefType refType) { bool hasLock; if (!m_context->canUpdateGraph()) { m_context->lock(); hasLock = true; } else { hasLock = m_context->tryLock(); } if (hasLock) { finishDeref(refType); m_context->unlock(); } else { assert(m_context->isAudioThread()); m_context->deferFinishDeref(this); } }