void OfflineAudioContext::fireCompletionEvent() { ASSERT(isMainThread()); // We set the state to closed here so that the oncomplete event handler sees // that the context has been closed. setContextState(Closed); AudioBuffer* renderedBuffer = renderTarget(); ASSERT(renderedBuffer); if (!renderedBuffer) return; // Avoid firing the event if the document has already gone away. if (executionContext()) { // Call the offline rendering completion event listener and resolve the // promise too. dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); m_completeResolver->resolve(renderedBuffer); } else { // The resolver should be rejected when the execution context is gone. m_completeResolver->reject(DOMException::create(InvalidStateError, "the execution context does not exist")); } }
void AudioContext::stopRendering() { ASSERT(isMainThread()); ASSERT(m_destinationNode); ASSERT(!isOfflineContext()); if (m_contextState == Running) { destination()->audioDestinationHandler().stopRendering(); setContextState(Suspended); } }
void AudioContext::startRendering() { // This is called for both online and offline contexts. ASSERT(isMainThread()); ASSERT(m_destinationNode); if (m_contextState == Suspended) { destination()->audioDestinationHandler().startRendering(); setContextState(Running); } }
void AudioContext::stopRendering() { ASSERT(isMainThread()); ASSERT(destination()); if (contextState() == Running) { destination()->audioDestinationHandler().stopRendering(); setContextState(Suspended); deferredTaskHandler().clearHandlersToBeDeleted(); } }
void AudioContext::didClose() { // This is specific to AudioContexts. OfflineAudioContexts // are closed in their completion event. setContextState(Closed); ASSERT(s_hardwareContextCount); --s_hardwareContextCount; if (m_closeResolver) m_closeResolver->resolve(); }
void OfflineAudioContext::resolveSuspendOnMainThread(size_t frame) { ASSERT(isMainThread()); // Suspend the context first. This will fire onstatechange event. setContextState(Suspended); // Wait until the suspend map is available for the removal. AutoLocker locker(this); ASSERT(m_scheduledSuspends.contains(frame)); SuspendMap::iterator it = m_scheduledSuspends.find(frame); it->value->resolve(); m_scheduledSuspends.remove(it); }
ScriptPromise OfflineAudioContext::startOfflineRendering(ScriptState* scriptState) { ASSERT(isMainThread()); // Calling close() on an OfflineAudioContext is not supported/allowed, // but it might well have been stopped by its execution context. // // See: crbug.com/435867 if (isContextClosed()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create( InvalidStateError, "cannot call startRendering on an OfflineAudioContext in a stopped state.")); } // If the context is not in the suspended state (i.e. running), reject the promise. if (contextState() != AudioContextState::Suspended) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create( InvalidStateError, "cannot startRendering when an OfflineAudioContext is " + state())); } // Can't call startRendering more than once. Return a rejected promise now. if (m_isRenderingStarted) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create( InvalidStateError, "cannot call startRendering more than once")); } ASSERT(!m_isRenderingStarted); m_completeResolver = ScriptPromiseResolver::create(scriptState); // Start rendering and return the promise. m_isRenderingStarted = true; setContextState(Running); destinationHandler().startRendering(); return m_completeResolver->promise(); }
void OfflineAudioContext::resolveSuspendOnMainThread(size_t frame) { ASSERT(isMainThread()); // Suspend the context first. This will fire onstatechange event. setContextState(Suspended); // Wait until the suspend map is available for the removal. AutoLocker locker(this); // |frame| must exist in the map. However, it can be removed already in a // very rare case. See: crbug.com/568796 RELEASE_ASSERT(m_scheduledSuspends.contains(frame)); SuspendMap::iterator it = m_scheduledSuspends.find(frame); it->value->resolve(); m_scheduledSuspends.remove(it); }
ScriptPromise OfflineAudioContext::resumeContext(ScriptState* scriptState) { ASSERT(isMainThread()); ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); // If the rendering has not started, reject the promise. if (!m_isRenderingStarted) { resolver->reject(DOMException::create(InvalidStateError, "cannot resume an offline context that has not started")); return promise; } // If the context is in a closed state, reject the promise. if (contextState() == AudioContextState::Closed) { resolver->reject(DOMException::create(InvalidStateError, "cannot resume a closed offline context")); return promise; } // If the context is already running, resolve the promise without altering // the current state or starting the rendering loop. if (contextState() == AudioContextState::Running) { resolver->resolve(); return promise; } ASSERT(contextState() == AudioContextState::Suspended); // If the context is suspended, resume rendering by setting the state to // "Running". and calling startRendering(). Note that resuming is possible // only after the rendering started. setContextState(Running); destinationHandler().startRendering(); // Resolve the promise immediately. resolver->resolve(); return promise; }
void AudioContext::uninitialize() { ASSERT(isMainThread()); if (!isInitialized()) return; m_isInitialized = false; // This stops the audio thread and all audio rendering. if (m_destinationNode) m_destinationNode->handler().uninitialize(); if (!isOfflineContext()) { ASSERT(s_hardwareContextCount); --s_hardwareContextCount; } // Get rid of the sources which may still be playing. derefUnfinishedSourceNodes(); // Reject any pending resolvers before we go away. rejectPendingResolvers(); // For an offline audio context, the completion event will set the state to closed. For an // online context, we need to do it here. We only want to set the closed state once. if (!isOfflineContext()) setContextState(Closed); // Resolve the promise now, if any if (m_closeResolver) m_closeResolver->resolve(); ASSERT(m_listener); m_listener->waitForHRTFDatabaseLoaderThreadCompletion(); clear(); }
void AudioContext::fireCompletionEvent() { ASSERT(isMainThread()); if (!isMainThread()) return; AudioBuffer* renderedBuffer = m_renderTarget.get(); // For an offline context, we set the state to closed here so that the oncomplete handler sees // that the context has been closed. setContextState(Closed); ASSERT(renderedBuffer); if (!renderedBuffer) return; // Avoid firing the event if the document has already gone away. if (executionContext()) { // Call the offline rendering completion event listener and resolve the promise too. dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); m_offlineResolver->resolve(renderedBuffer); } }