Diff
Modified: trunk/LayoutTests/ChangeLog (252388 => 252389)
--- trunk/LayoutTests/ChangeLog 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/LayoutTests/ChangeLog 2019-11-13 02:07:30 UTC (rev 252389)
@@ -1,3 +1,15 @@
+2019-11-12 Keith Miller <[email protected]>
+
+ AudioScheduledSourceNodes leak if they have an attached onended EventTarget
+ https://bugs.webkit.org/show_bug.cgi?id=204087
+
+ Reviewed by Jer Noble.
+
+ * webaudio/audiobuffersource-not-gced-until-ended-expected.txt: Added.
+ * webaudio/audiobuffersource-not-gced-until-ended.html: Added.
+ * webaudio/finished-audio-buffer-source-nodes-should-be-collectable-expected.txt: Added.
+ * webaudio/finished-audio-buffer-source-nodes-should-be-collectable.html: Added.
+
2019-11-12 Wenson Hsieh <[email protected]>
[iOS] WKWebView does not respect system spellchecking preference
Added: trunk/LayoutTests/webaudio/audiobuffersource-not-gced-until-ended-expected.txt (0 => 252389)
--- trunk/LayoutTests/webaudio/audiobuffersource-not-gced-until-ended-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-not-gced-until-ended-expected.txt 2019-11-13 02:07:30 UTC (rev 252389)
@@ -0,0 +1,6 @@
+Tests that AudioBufferSourceNode calls its onended EventListener, even after a GC.
+PASS source.onended called.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/webaudio/audiobuffersource-not-gced-until-ended.html (0 => 252389)
--- trunk/LayoutTests/webaudio/audiobuffersource-not-gced-until-ended.html (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-not-gced-until-ended.html 2019-11-13 02:07:30 UTC (rev 252389)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<head>
+ <script src=""
+ <script src=""
+ <script src=""
+ <script>
+ var context;
+
+ function runTest()
+ {
+ jsTestIsAsync = true;
+
+ var sampleRate = 44100.0;
+ var numberOfFrames = 32;
+ context = new webkitOfflineAudioContext(1, numberOfFrames, sampleRate);
+ var source = context.createBufferSource();
+ source.buffer = createTestBuffer(context, numberOfFrames);
+ source.connect(context.destination);
+ source._onended_ = function()
+ {
+ testPassed("source.onended called.");
+ finishJSTest();
+ }
+ source.start(0);
+ context.startRendering();
+ // trigger a GC in the next micro task to try and collect source.
+ Promise.resolve().then(gc);
+ }
+ </script>
+
+</head>
+<body _onload_="runTest()">
+ <div>Tests that AudioBufferSourceNode calls its onended EventListener, even after a GC.</div>
+ <div id="console"></div>
+</body>
Added: trunk/LayoutTests/webaudio/finished-audio-buffer-source-nodes-should-be-collectable-expected.txt (0 => 252389)
--- trunk/LayoutTests/webaudio/finished-audio-buffer-source-nodes-should-be-collectable-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/finished-audio-buffer-source-nodes-should-be-collectable-expected.txt 2019-11-13 02:07:30 UTC (rev 252389)
@@ -0,0 +1,12 @@
+Tests that AudioBufferSourceNodes are collectable after they trigger their onended event.
+PASS source.onended called.
+PASS source.onended called.
+PASS source.onended called.
+PASS source.onended called.
+PASS source.onended called.
+PASS source.onended called.
+PASS AudioBufferSourceNode was collected after calling onended.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/webaudio/finished-audio-buffer-source-nodes-should-be-collectable.html (0 => 252389)
--- trunk/LayoutTests/webaudio/finished-audio-buffer-source-nodes-should-be-collectable.html (rev 0)
+++ trunk/LayoutTests/webaudio/finished-audio-buffer-source-nodes-should-be-collectable.html 2019-11-13 02:07:30 UTC (rev 252389)
@@ -0,0 +1,66 @@
+<!DOCTYPE html><!-- webkit-test-runner [ jscOptions=--useWeakRefs=true ] -->
+<head>
+ <script src=""
+ <script src=""
+ <script src=""
+ <script>
+ var context;
+ var source;
+ var promises = [];
+ var refs = [];
+ const sampleRate = 44100.0;
+ const numberOfFrames = 32;
+
+ function create(mergerNode, index)
+ {
+ jsTestIsAsync = true;
+
+ source = context.createBufferSource();
+ source.buffer = createTestBuffer(context, numberOfFrames);
+ source.connect(mergerNode, 0, index);
+
+ let resolve;
+ let promise = new Promise((r) => resolve = r);
+ promises.push(promise);
+ refs.push(new WeakRef(source));
+
+ source._onended_ = function()
+ {
+ testPassed("source.onended called.");
+ gc();
+ resolve();
+ }
+ source.start(0);
+ }
+
+ function runTest()
+ {
+ context = new webkitOfflineAudioContext(1, numberOfFrames, sampleRate);
+ // FIXME: Passing more than 6 seems to fail. 6 is the default value so I'm guessing there's a bug there...
+ const count = 6;
+ let merger = context.createChannelMerger(count);
+ for (let i = 0; i < count; ++i)
+ create(merger, i);
+ merger.connect(context.destination);
+ context.startRendering();
+
+ Promise.all(promises).then(() => {
+ for (ref of refs) {
+ if (!ref.deref()) {
+ testPassed("AudioBufferSourceNode was collected after calling onended.");
+ finishJSTest();
+ return;
+ }
+ }
+
+ testFailed("No AudioBufferSourceNode was collected.");
+ finishJSTest();
+ });
+ }
+ </script>
+
+</head>
+<body _onload_="runTest()">
+ <div>Tests that AudioBufferSourceNodes are collectable after they trigger their onended event.</div>
+ <div id="console"></div>
+</body>
Modified: trunk/Source/WebCore/ChangeLog (252388 => 252389)
--- trunk/Source/WebCore/ChangeLog 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/ChangeLog 2019-11-13 02:07:30 UTC (rev 252389)
@@ -1,3 +1,62 @@
+2019-11-12 Keith Miller <[email protected]>
+
+ AudioScheduledSourceNodes leak if they have an attached onended EventTarget
+ https://bugs.webkit.org/show_bug.cgi?id=204087
+ <rdar://problem/56772102>
+
+ Reviewed by Jer Noble.
+
+ Previously, if an AudioNode had any attributes that were event
+ targets we would leak the node as long as the AudioContext was
+ alive. This patch makes all the AudioNodes with EventTarget
+ attributes subclasses of ActiveDOMObject. For,
+ AudioScheduledSourceNodes we will mark the node as non-active when
+ either the node becomes eligible for deletion from the graph or
+ the onended event fires. For, ScriptProcessorNodes we mark the
+ node as non-active when the node becomes eligible for deletion.
+
+ Tests: webaudio/finished-audio-buffer-source-nodes-should-be-collectable.html
+ webaudio/audiobuffersource-not-gced-until-ended.html
+
+ * Modules/webaudio/AudioBufferSourceNode.cpp:
+ (WebCore::AudioBufferSourceNode::startLater):
+ (WebCore::AudioBufferSourceNode::start): Deleted.
+ * Modules/webaudio/AudioBufferSourceNode.h:
+ * Modules/webaudio/AudioBufferSourceNode.idl:
+ * Modules/webaudio/AudioContext.h:
+ * Modules/webaudio/AudioNode.cpp:
+ (WebCore::AudioNode::deref):
+ (WebCore::AudioNode::finishDeref):
+ * Modules/webaudio/AudioNode.h:
+ (WebCore::AudioNode::didBecomeMarkedForDeletion):
+ * Modules/webaudio/AudioNode.idl:
+ * Modules/webaudio/AudioScheduledSourceNode.cpp:
+ (WebCore::AudioScheduledSourceNode::AudioScheduledSourceNode):
+ (WebCore::AudioScheduledSourceNode::startLater):
+ (WebCore::AudioScheduledSourceNode::stopLater):
+ (WebCore::AudioScheduledSourceNode::didBecomeMarkedForDeletion):
+ (WebCore::AudioScheduledSourceNode::finish):
+ (WebCore::AudioScheduledSourceNode::start): Deleted.
+ (WebCore::AudioScheduledSourceNode::stop): Deleted.
+ (WebCore::AudioScheduledSourceNode::addEventListener): Deleted.
+ (WebCore::AudioScheduledSourceNode::removeEventListener): Deleted.
+ (WebCore::AudioScheduledSourceNode::removeAllEventListeners): Deleted.
+ * Modules/webaudio/AudioScheduledSourceNode.h:
+ * Modules/webaudio/OscillatorNode.h:
+ * Modules/webaudio/OscillatorNode.idl:
+ * Modules/webaudio/ScriptProcessorNode.cpp:
+ (WebCore::ScriptProcessorNode::ScriptProcessorNode):
+ (WebCore::ScriptProcessorNode::~ScriptProcessorNode):
+ (WebCore::ScriptProcessorNode::didBecomeMarkedForDeletion):
+ (WebCore::ScriptProcessorNode::process):
+ (WebCore::ScriptProcessorNode::addEventListener): Deleted.
+ (WebCore::ScriptProcessorNode::removeEventListener): Deleted.
+ (WebCore::ScriptProcessorNode::removeAllEventListeners): Deleted.
+ * Modules/webaudio/ScriptProcessorNode.h:
+ * Modules/webaudio/ScriptProcessorNode.idl:
+ * Sources.txt:
+ * bindings/js/JSAudioNodeCustom.cpp: Removed.
+
2019-11-12 Zalan Bujtas <[email protected]>
[LFC] InlineFormattingState::addInlineRun should take a unique_ptr<Display::Run>
Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp 2019-11-13 02:07:30 UTC (rev 252389)
@@ -441,7 +441,7 @@
return output(0)->numberOfChannels();
}
-ExceptionOr<void> AudioBufferSourceNode::start(double when, double grainOffset, Optional<double> optionalGrainDuration)
+ExceptionOr<void> AudioBufferSourceNode::startLater(double when, double grainOffset, Optional<double> optionalGrainDuration)
{
double grainDuration = 0;
if (optionalGrainDuration)
Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h 2019-11-13 02:07:30 UTC (rev 252389)
@@ -57,7 +57,7 @@
unsigned numberOfChannels();
// Play-state
- ExceptionOr<void> start(double when, double grainOffset, Optional<double> grainDuration);
+ ExceptionOr<void> startLater(double when, double grainOffset, Optional<double> grainDuration);
// Note: the attribute was originally exposed as .looping, but to be more consistent in naming with <audio>
// and with how it's described in the specification, the proper attribute name is .loop
@@ -88,6 +88,8 @@
// AudioScheduledSourceNode
void finish() final;
+ const char* activeDOMObjectName() const override { return "AudioBufferSourceNode"; }
+
private:
AudioBufferSourceNode(AudioContext&, float sampleRate);
Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.idl (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.idl 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.idl 2019-11-13 02:07:30 UTC (rev 252389)
@@ -26,6 +26,7 @@
[
Conditional=WEB_AUDIO,
JSGenerateToJSObject,
+ ActiveDOMObject,
] interface AudioBufferSourceNode : AudioNode {
attribute AudioBuffer? buffer;
@@ -44,8 +45,8 @@
attribute unrestricted double loopStart;
attribute unrestricted double loopEnd;
- [MayThrowException] void start(optional unrestricted double when = 0, optional unrestricted double grainOffset = 0, optional unrestricted double grainDuration);
- [MayThrowException] void stop(optional unrestricted double when = 0);
+ [MayThrowException, ImplementedAs=startLater] void start(optional unrestricted double when = 0, optional unrestricted double grainOffset = 0, optional unrestricted double grainDuration);
+ [MayThrowException, ImplementedAs=stopLater] void stop(optional unrestricted double when = 0);
attribute EventHandler onended;
};
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2019-11-13 02:07:30 UTC (rev 252389)
@@ -291,6 +291,9 @@
const SecurityOrigin* origin() const;
void addConsoleMessage(MessageSource, MessageLevel, const String& message);
+ // EventTarget
+ ScriptExecutionContext* scriptExecutionContext() const final;
+
protected:
explicit AudioContext(Document&);
AudioContext(Document&, AudioBuffer* renderTarget);
@@ -320,7 +323,6 @@
void mediaCanStart(Document&) override;
// EventTarget
- ScriptExecutionContext* scriptExecutionContext() const final;
void dispatchEvent(Event&) final;
// MediaProducer
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp 2019-11-13 02:07:30 UTC (rev 252389)
@@ -509,7 +509,7 @@
context().lock(mustReleaseLock);
hasLock = true;
}
-
+
if (hasLock) {
// This is where the real deref work happens.
finishDeref(refType);
@@ -561,6 +561,7 @@
// Mark for deletion at end of each render quantum or when context shuts down.
context().markForDeletion(*this);
m_isMarkedForDeletion = true;
+ didBecomeMarkedForDeletion();
}
} else if (refType == RefTypeConnection)
disableOutputsIfNecessary();
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNode.h (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioNode.h 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNode.h 2019-11-13 02:07:30 UTC (rev 252389)
@@ -105,6 +105,7 @@
// Can be called from main thread or context's audio thread. It must be called while the context's graph lock is held.
void finishDeref(RefType refType);
+ virtual void didBecomeMarkedForDeletion() { }
// The AudioNodeInput(s) (if any) will already have their input data available when process() is called.
// Subclasses will take this input data and put the results in the AudioBus(s) of its AudioNodeOutput(s) (if any).
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNode.idl (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioNode.idl 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNode.idl 2019-11-13 02:07:30 UTC (rev 252389)
@@ -24,7 +24,6 @@
[
Conditional=WEB_AUDIO,
- CustomIsReachable,
] interface AudioNode : EventTarget {
readonly attribute AudioContext context;
readonly attribute unsigned long numberOfInputs;
Modified: trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.cpp (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.cpp 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.cpp 2019-11-13 02:07:30 UTC (rev 252389)
@@ -37,6 +37,7 @@
#include <algorithm>
#include <wtf/IsoMallocInlines.h>
#include <wtf/MathExtras.h>
+#include <wtf/Scope.h>
#if PLATFORM(IOS_FAMILY)
#include "ScriptController.h"
@@ -50,8 +51,11 @@
AudioScheduledSourceNode::AudioScheduledSourceNode(AudioContext& context, float sampleRate)
: AudioNode(context, sampleRate)
+ , ActiveDOMObject(context.scriptExecutionContext())
, m_endTime(UnknownTime)
{
+ suspendIfNeeded();
+ m_pendingActivity = makePendingActivity(*this);
}
void AudioScheduledSourceNode::updateSchedulingInfo(size_t quantumFrameSize, AudioBus& outputBus, size_t& quantumFrameOffset, size_t& nonSilentFramesToProcess)
@@ -132,7 +136,7 @@
}
}
-ExceptionOr<void> AudioScheduledSourceNode::start(double when)
+ExceptionOr<void> AudioScheduledSourceNode::startLater(double when)
{
ASSERT(isMainThread());
ALWAYS_LOG(LOGIDENTIFIER, when);
@@ -150,7 +154,7 @@
return { };
}
-ExceptionOr<void> AudioScheduledSourceNode::stop(double when)
+ExceptionOr<void> AudioScheduledSourceNode::stopLater(double when)
{
ASSERT(isMainThread());
ALWAYS_LOG(LOGIDENTIFIER, when);
@@ -165,19 +169,27 @@
return { };
}
+void AudioScheduledSourceNode::didBecomeMarkedForDeletion()
+{
+ ASSERT(context().isGraphOwner());
+ m_pendingActivity = nullptr;
+ ASSERT(!hasPendingActivity());
+}
+
void AudioScheduledSourceNode::finish()
{
- if (m_playbackState != FINISHED_STATE) {
- // Let the context dereference this AudioNode.
- context().notifyNodeFinishedProcessing(this);
- m_playbackState = FINISHED_STATE;
- context().decrementActiveSourceCount();
- }
+ ASSERT(!hasFinished());
+ // Let the context dereference this AudioNode.
+ context().notifyNodeFinishedProcessing(this);
+ m_playbackState = FINISHED_STATE;
+ context().decrementActiveSourceCount();
- if (!m_hasEndedListener)
- return;
-
context().postTask([this, protectedThis = makeRef(*this)] {
+ auto release = makeScopeExit([&] () {
+ AudioContext::AutoLocker locker(context());
+ m_pendingActivity = nullptr;
+ ASSERT(!hasPendingActivity());
+ });
if (context().isStopped())
return;
this->dispatchEvent(Event::create(eventNames().endedEvent, Event::CanBubble::No, Event::IsCancelable::No));
@@ -184,28 +196,6 @@
});
}
-bool AudioScheduledSourceNode::addEventListener(const AtomString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
-{
- bool success = AudioNode::addEventListener(eventType, WTFMove(listener), options);
- if (success && eventType == eventNames().endedEvent)
- m_hasEndedListener = hasEventListeners(eventNames().endedEvent);
- return success;
-}
-
-bool AudioScheduledSourceNode::removeEventListener(const AtomString& eventType, EventListener& listener, const ListenerOptions& options)
-{
- bool success = AudioNode::removeEventListener(eventType, listener, options);
- if (success && eventType == eventNames().endedEvent)
- m_hasEndedListener = hasEventListeners(eventNames().endedEvent);
- return success;
-}
-
-void AudioScheduledSourceNode::removeAllEventListeners()
-{
- m_hasEndedListener = false;
- AudioNode::removeAllEventListeners();
-}
-
} // namespace WebCore
#endif // ENABLE(WEB_AUDIO)
Modified: trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.h (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.h 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.h 2019-11-13 02:07:30 UTC (rev 252389)
@@ -28,11 +28,12 @@
#pragma once
+#include "ActiveDOMObject.h"
#include "AudioNode.h"
namespace WebCore {
-class AudioScheduledSourceNode : public AudioNode {
+class AudioScheduledSourceNode : public AudioNode, public ActiveDOMObject {
WTF_MAKE_ISO_ALLOCATED(AudioScheduledSourceNode);
public:
// These are the possible states an AudioScheduledSourceNode can be in:
@@ -54,9 +55,11 @@
AudioScheduledSourceNode(AudioContext&, float sampleRate);
- ExceptionOr<void> start(double when);
- ExceptionOr<void> stop(double when);
+ ExceptionOr<void> startLater(double when);
+ ExceptionOr<void> stopLater(double when);
+ void didBecomeMarkedForDeletion() override;
+
unsigned short playbackState() const { return static_cast<unsigned short>(m_playbackState); }
bool isPlayingOrScheduled() const { return m_playbackState == PLAYING_STATE || m_playbackState == SCHEDULED_STATE; }
bool hasFinished() const { return m_playbackState == FINISHED_STATE; }
@@ -75,6 +78,7 @@
PlaybackState m_playbackState { UNSCHEDULED_STATE };
+ RefPtr<PendingActivity<AudioScheduledSourceNode>> m_pendingActivity;
// m_startTime is the time to start playing based on the context's timeline (0 or a time less than the context's current time means "now").
double m_startTime { 0 }; // in seconds
@@ -83,14 +87,7 @@
// has been reached.
double m_endTime; // in seconds
- bool m_hasEndedListener { false };
-
static const double UnknownTime;
-
-private:
- bool addEventListener(const AtomString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) override;
- bool removeEventListener(const AtomString& eventType, EventListener&, const ListenerOptions&) override;
- void removeAllEventListeners() override;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/webaudio/OscillatorNode.h (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/OscillatorNode.h 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/OscillatorNode.h 2019-11-13 02:07:30 UTC (rev 252389)
@@ -49,6 +49,8 @@
virtual ~OscillatorNode();
+ const char* activeDOMObjectName() const override { return "OscillatorNode"; }
+
Type type() const { return m_type; }
ExceptionOr<void> setType(Type);
Modified: trunk/Source/WebCore/Modules/webaudio/OscillatorNode.idl (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/OscillatorNode.idl 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/OscillatorNode.idl 2019-11-13 02:07:30 UTC (rev 252389)
@@ -34,6 +34,7 @@
[
Conditional=WEB_AUDIO,
JSGenerateToJSObject,
+ ActiveDOMObject,
] interface OscillatorNode : AudioNode {
attribute OscillatorType type;
@@ -48,8 +49,8 @@
readonly attribute AudioParam frequency; // in Hertz
readonly attribute AudioParam detune; // in Cents
- [MayThrowException] void start(optional unrestricted double when = 0);
- [MayThrowException] void stop(optional unrestricted double when = 0);
+ [MayThrowException, ImplementedAs=startLater] void start(optional unrestricted double when = 0);
+ [MayThrowException, ImplementedAs=stopLater] void stop(optional unrestricted double when = 0);
void setPeriodicWave(PeriodicWave? wave); // FIXME: The parameter should not be nullable.
Modified: trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.cpp (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.cpp 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.cpp 2019-11-13 02:07:30 UTC (rev 252389)
@@ -51,6 +51,7 @@
ScriptProcessorNode::ScriptProcessorNode(AudioContext& context, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
: AudioNode(context, sampleRate)
+ , ActiveDOMObject(context.scriptExecutionContext())
, m_doubleBufferIndex(0)
, m_doubleBufferIndexForEvent(0)
, m_bufferSize(bufferSize)
@@ -59,7 +60,6 @@
, m_numberOfInputChannels(numberOfInputChannels)
, m_numberOfOutputChannels(numberOfOutputChannels)
, m_internalInputBus(AudioBus::create(numberOfInputChannels, AudioNode::ProcessingSizeInFrames, false))
- , m_hasAudioProcessListener(false)
{
// Regardless of the allowed buffer sizes, we still need to process at the granularity of the AudioNode.
if (m_bufferSize < AudioNode::ProcessingSizeInFrames)
@@ -72,10 +72,13 @@
addOutput(makeUnique<AudioNodeOutput>(this, numberOfOutputChannels));
initialize();
+ suspendIfNeeded();
+ m_pendingActivity = makePendingActivity(*this);
}
ScriptProcessorNode::~ScriptProcessorNode()
{
+ ASSERT(!hasPendingActivity());
uninitialize();
}
@@ -110,6 +113,13 @@
AudioNode::uninitialize();
}
+void ScriptProcessorNode::didBecomeMarkedForDeletion()
+{
+ ASSERT(context().isGraphOwner());
+ m_pendingActivity = nullptr;
+ ASSERT(!hasPendingActivity());
+}
+
void ScriptProcessorNode::process(size_t framesToProcess)
{
// Discussion about inputs and outputs:
@@ -118,10 +128,6 @@
// This node is the producer for inputBuffer and the consumer for outputBuffer.
// The _javascript_ code is the consumer of inputBuffer and the producer for outputBuffer.
- // Check if audioprocess listener is set.
- if (!m_hasAudioProcessListener)
- return;
-
// Get input and output busses.
AudioBus* inputBus = this->input(0)->bus();
AudioBus* outputBus = this->output(0)->bus();
@@ -192,9 +198,6 @@
m_isRequestOutstanding = true;
callOnMainThread([this] {
- if (!m_hasAudioProcessListener)
- return;
-
fireProcessEvent();
// De-reference to match the ref() call in process().
@@ -256,28 +259,6 @@
return std::numeric_limits<double>::infinity();
}
-bool ScriptProcessorNode::addEventListener(const AtomString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
-{
- bool success = AudioNode::addEventListener(eventType, WTFMove(listener), options);
- if (success && eventType == eventNames().audioprocessEvent)
- m_hasAudioProcessListener = hasEventListeners(eventNames().audioprocessEvent);
- return success;
-}
-
-bool ScriptProcessorNode::removeEventListener(const AtomString& eventType, EventListener& listener, const ListenerOptions& options)
-{
- bool success = AudioNode::removeEventListener(eventType, listener, options);
- if (success && eventType == eventNames().audioprocessEvent)
- m_hasAudioProcessListener = hasEventListeners(eventNames().audioprocessEvent);
- return success;
-}
-
-void ScriptProcessorNode::removeAllEventListeners()
-{
- m_hasAudioProcessListener = false;
- AudioNode::removeAllEventListeners();
-}
-
} // namespace WebCore
#endif // ENABLE(WEB_AUDIO)
Modified: trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.h (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.h 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.h 2019-11-13 02:07:30 UTC (rev 252389)
@@ -24,6 +24,7 @@
#pragma once
+#include "ActiveDOMObject.h"
#include "AudioBus.h"
#include "AudioNode.h"
#include "EventListener.h"
@@ -44,7 +45,7 @@
// The "onaudioprocess" attribute is an event listener which will get called periodically with an AudioProcessingEvent which has
// AudioBuffers for each input and output.
-class ScriptProcessorNode final : public AudioNode {
+class ScriptProcessorNode final : public AudioNode, public ActiveDOMObject {
WTF_MAKE_ISO_ALLOCATED(ScriptProcessorNode);
public:
// bufferSize must be one of the following values: 256, 512, 1024, 2048, 4096, 8192, 16384.
@@ -55,11 +56,14 @@
virtual ~ScriptProcessorNode();
+ const char* activeDOMObjectName() const override { return "ScriptProcessorNode"; }
+
// AudioNode
void process(size_t framesToProcess) override;
void reset() override;
void initialize() override;
void uninitialize() override;
+ void didBecomeMarkedForDeletion() override;
size_t bufferSize() const { return m_bufferSize; }
@@ -71,10 +75,6 @@
void fireProcessEvent();
- bool addEventListener(const AtomString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) override;
- bool removeEventListener(const AtomString& eventType, EventListener&, const ListenerOptions&) override;
- void removeAllEventListeners() override;
-
// Double buffering
unsigned doubleBufferIndex() const { return m_doubleBufferIndex; }
void swapBuffers() { m_doubleBufferIndex = 1 - m_doubleBufferIndex; }
@@ -91,7 +91,7 @@
unsigned m_numberOfOutputChannels;
RefPtr<AudioBus> m_internalInputBus;
- bool m_hasAudioProcessListener;
+ RefPtr<PendingActivity<ScriptProcessorNode>> m_pendingActivity;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.idl (252388 => 252389)
--- trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.idl 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Modules/webaudio/ScriptProcessorNode.idl 2019-11-13 02:07:30 UTC (rev 252389)
@@ -26,7 +26,8 @@
[
Conditional=WEB_AUDIO,
JSGenerateToJSObject,
- JSGenerateToNativeObject
+ JSGenerateToNativeObject,
+ ActiveDOMObject,
] interface ScriptProcessorNode : AudioNode {
// Rendering callback
attribute EventHandler onaudioprocess;
Modified: trunk/Source/WebCore/Sources.txt (252388 => 252389)
--- trunk/Source/WebCore/Sources.txt 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/Sources.txt 2019-11-13 02:07:30 UTC (rev 252389)
@@ -458,7 +458,6 @@
animation/KeyframeEffect.cpp
animation/WebAnimation.cpp
-bindings/js/JSAudioNodeCustom.cpp
bindings/js/CachedModuleScriptLoader.cpp
bindings/js/CachedScriptFetcher.cpp
bindings/js/CallTracer.cpp
Deleted: trunk/Source/WebCore/bindings/js/JSAudioNodeCustom.cpp (252388 => 252389)
--- trunk/Source/WebCore/bindings/js/JSAudioNodeCustom.cpp 2019-11-13 01:48:00 UTC (rev 252388)
+++ trunk/Source/WebCore/bindings/js/JSAudioNodeCustom.cpp 2019-11-13 02:07:30 UTC (rev 252389)
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if ENABLE(WEB_AUDIO)
-
-#include "AudioContext.h"
-#include "JSAudioNode.h"
-
-namespace WebCore {
-using namespace JSC;
-
-bool JSAudioNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
-{
- auto& node = jsCast<JSAudioNode*>(handle.slot()->asCell())->wrapped();
-
- if (node.isFiringEventListeners()) {
- if (UNLIKELY(reason))
- *reason = "AudioNode is firing event listeners";
- return true;
- }
-
- if (!node.context().hasPendingActivity() || node.context().isClosed())
- return false;
-
- if (node.hasEventListeners()) {
- if (UNLIKELY(reason))
- *reason = "AudioNode has event listeners";
- return true;
- }
-
- return visitor.containsOpaqueRoot(&node);
-}
-
-} // namespace WebCore
-
-#endif