Chromium Code Reviews| Index: Source/modules/webaudio/OfflineAudioContext.cpp |
| diff --git a/Source/modules/webaudio/OfflineAudioContext.cpp b/Source/modules/webaudio/OfflineAudioContext.cpp |
| index d3488419e947e373d50f13cb105be0fb0604d178..d5165ce6facf6cbb27fc60ce04c0c0a1df0b5fe1 100644 |
| --- a/Source/modules/webaudio/OfflineAudioContext.cpp |
| +++ b/Source/modules/webaudio/OfflineAudioContext.cpp |
| @@ -31,7 +31,10 @@ |
| #include "core/dom/Document.h" |
| #include "core/dom/ExceptionCode.h" |
| #include "core/dom/ExecutionContext.h" |
| +#include "modules/webaudio/OfflineAudioDestinationNode.h" |
| +#include "platform/ThreadSafeFunctional.h" |
| #include "platform/audio/AudioUtilities.h" |
| +#include "public/platform/Platform.h" |
| namespace blink { |
| @@ -99,8 +102,64 @@ OfflineAudioContext::~OfflineAudioContext() |
| { |
| } |
| +OfflineAudioContext::ScheduledSuspendContainer::ScheduledSuspendContainer( |
| + double when, PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) |
| + : m_when(when) |
|
Raymond Toy
2015/05/19 22:04:45
Shouldn't this quantize the time to the rendering
|
| + , m_resolver(resolver) |
| +{ |
| +} |
| + |
| +OfflineAudioContext::ScheduledSuspendContainer::~ScheduledSuspendContainer() |
| +{ |
| +} |
| + |
| +DEFINE_TRACE(OfflineAudioContext::ScheduledSuspendContainer) |
| +{ |
| + visitor->trace(m_resolver); |
| +} |
| + |
| +PassOwnPtr<OfflineAudioContext::ScheduledSuspendContainer> |
| +OfflineAudioContext::ScheduledSuspendContainer::create( |
| + double when, PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) |
| +{ |
| + return adoptPtr(new ScheduledSuspendContainer(when, resolver)); |
| +} |
| + |
| +bool OfflineAudioContext::ScheduledSuspendContainer::shouldBeSuspendedNow(double currentTime) const |
| +{ |
| + return m_when <= currentTime; |
| +} |
| + |
| +bool OfflineAudioContext::suspendIfNecessary() |
| +{ |
| + ASSERT(!isMainThread()); |
| + |
| + // Suspend if necessary and resolve the associated promise. |
| + for (unsigned index = 0; index < m_scheduledSuspends.size(); ++index) { |
| + if (m_scheduledSuspends.at(index)->shouldBeSuspendedNow(currentTime())) { |
| + // Resolve scheduled suspend on the main thread. |
| + Platform::current()->mainThread()->postTask(FROM_HERE, |
| + threadSafeBind( |
| + &OfflineAudioContext::suspendAndResolveOnMainThread, |
| + this, |
| + index)); |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| +bool OfflineAudioContext::isSuspendScheduled() const |
| +{ |
| + return m_scheduledSuspends.size() > 0; |
| +} |
| + |
| ScriptPromise OfflineAudioContext::startOfflineRendering(ScriptState* scriptState) |
| { |
| + ASSERT(isMainThread()); |
| + AutoLocker locker(this); |
| + |
| // Calling close() on an OfflineAudioContext is not supported/allowed, |
| // but it might well have been stopped by its execution context. |
| if (isContextClosed()) { |
| @@ -121,10 +180,73 @@ ScriptPromise OfflineAudioContext::startOfflineRendering(ScriptState* scriptStat |
| } |
| m_offlineResolver = ScriptPromiseResolver::create(scriptState); |
| - startRendering(); |
| + |
| + // This calls AudioContext.startRendering(). It seems to be odd to go up the |
| + // chain and call the parent's method, but the current OAC is basically a |
| + // thin wrapper on AudioContext. (a container-like object.) |
| + // |
| + // If we decide to fix this structural issue completely, we have to touch |
| + // AudioContext and AudioNode. |
| + // startRendering(); |
| + |
| + destination()->audioDestinationHandler().startRendering(); |
| + setContextState(Running); |
| + |
| return m_offlineResolver->promise(); |
| } |
| +ScriptPromise OfflineAudioContext::suspendOfflineRendering(ScriptState* scriptState, double when) |
| +{ |
| + ASSERT(isMainThread()); |
| + AutoLocker locker(this); |
| + |
| + // suspendTime should be greater than currentTime. Note that this is called |
| + // from the main thread, so the currentTime will be one rendering quantum |
| + // behind the actual current time. |
| + if (currentTime() < when) { |
| + RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState); |
| + ScriptPromise promise = resolver->promise(); |
| + m_scheduledSuspends.append(ScheduledSuspendContainer::create(when, resolver)); |
| + return promise; |
| + } |
| + |
| + // If suspendTime is already passed, throw an exception. |
| + return ScriptPromise::rejectWithDOMException( |
| + scriptState, |
| + DOMException::create( |
| + InvalidStateError, |
| + "cannot schedule a suspend in the past")); |
| +} |
| + |
| +ScriptPromise OfflineAudioContext::resumeOfflineRendering(ScriptState* scriptState) |
| +{ |
| + ASSERT(isMainThread()); |
| + AutoLocker locker(this); |
| + |
| + RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState); |
| + ScriptPromise promise = resolver->promise(); |
| + m_resumeResolvers.append(resolver); |
|
Raymond Toy
2015/05/19 22:04:45
Not sure, but I think you can resolve the promise
hongchan
2015/05/20 22:09:40
I agree. This was just to make the structure symme
|
| + |
| + // Calling startRendering() in OfflineAudioDestinationHandler. |
| + destination()->audioDestinationHandler().startRendering(); |
| + setContextState(Running); |
| + |
| + return promise; |
| +} |
| + |
| +void OfflineAudioContext::suspendAndResolveOnMainThread(unsigned index) |
| +{ |
| + ASSERT(isMainThread()); |
| + AutoLocker locker(this); |
| + |
| + setContextState(Suspended); |
| + |
| + m_scheduledSuspends.at(index)->resolver()->resolve(); |
| + |
| + // TO FIX: does this automatically re-arrange the rest of vector? |
| + m_scheduledSuspends.remove(index); |
| +} |
| + |
| } // namespace blink |
| #endif // ENABLE(WEB_AUDIO) |