Diff
Modified: trunk/LayoutTests/ChangeLog (244824 => 244825)
--- trunk/LayoutTests/ChangeLog 2019-05-01 16:34:31 UTC (rev 244824)
+++ trunk/LayoutTests/ChangeLog 2019-05-01 17:09:20 UTC (rev 244825)
@@ -1,5 +1,17 @@
2019-05-01 Youenn Fablet <[email protected]>
+ Reject/throw when calling AudioContext methods on a stopped AudioContext
+ https://bugs.webkit.org/show_bug.cgi?id=197391
+
+ Reviewed by Eric Carlson.
+
+ * http/wpt/webaudio/audiocontext-stopped-expected.txt: Added.
+ * http/wpt/webaudio/audiocontext-stopped.html: Added.
+ * http/wpt/webaudio/resources/audiocontext-stopped-iframe.html: Added.
+ * platform/win/TestExpectations: Skip test for win.
+
+2019-05-01 Youenn Fablet <[email protected]>
+
Enable Fetch Keep Alive by default
https://bugs.webkit.org/show_bug.cgi?id=197331
Added: trunk/LayoutTests/http/wpt/webaudio/audiocontext-stopped-expected.txt (0 => 244825)
--- trunk/LayoutTests/http/wpt/webaudio/audiocontext-stopped-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/webaudio/audiocontext-stopped-expected.txt 2019-05-01 17:09:20 UTC (rev 244825)
@@ -0,0 +1,21 @@
+
+
+PASS Load test iframe
+PASS createBufferSource
+PASS createMediaElementSource
+PASS createMediaStreamDestination
+PASS createGain
+PASS createDelay
+PASS createBiquadFilter
+PASS createWaveShapper
+PASS createPanner
+PASS createConvolver
+PASS createDynamicsCompressor
+PASS createAnalyser
+PASS createScriptProcessor
+PASS createOscillator
+PASS createPeriodicWave
+PASS suspend
+PASS resume
+PASS close
+
Added: trunk/LayoutTests/http/wpt/webaudio/audiocontext-stopped.html (0 => 244825)
--- trunk/LayoutTests/http/wpt/webaudio/audiocontext-stopped.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webaudio/audiocontext-stopped.html 2019-05-01 17:09:20 UTC (rev 244825)
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<video id="video"></video>
+<script>
+function with_iframe(url) {
+ return new Promise(function(resolve) {
+ var frame = document.createElement('iframe');
+ frame.className = 'test-iframe';
+ frame.src = ""
+ frame._onload_ = function() { resolve(frame); };
+ document.body.appendChild(frame);
+ });
+}
+
+var context;
+promise_test(async () => {
+ const iframe = await with_iframe("resources/audiocontext-stopped-iframe.html");
+ context = iframe.contentWindow.audioContext;
+ iframe.remove();
+
+ runTests();
+}, "Load test iframe");
+
+function runTests()
+{
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createBufferSource());
+ }, "createBufferSource");
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createMediaElementSource(video));
+ }, "createMediaElementSource");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createMediaStreamDestination());
+ }, "createMediaStreamDestination");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createGain());
+ }, "createGain");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createDelay());
+ }, "createDelay");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createBiquadFilter());
+ }, "createBiquadFilter");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createWaveShaper());
+ }, "createWaveShapper");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createPanner());
+ }, "createPanner");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createConvolver());
+ }, "createConvolver");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createDynamicsCompressor());
+ }, "createDynamicsCompressor");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createAnalyser());
+ }, "createAnalyser");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createScriptProcessor());
+ }, "createScriptProcessor");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createOscillator());
+ }, "createOscillator");
+
+ test(() => {
+ assert_throws('InvalidStateError', () => context.createPeriodicWave(new Float32Array(1), new Float32Array(1)));
+ }, "createPeriodicWave");
+
+ promise_test((test) => {
+ return promise_rejects(test, 'InvalidStateError', context.suspend());
+ }, "suspend");
+
+ promise_test((test) => {
+ return promise_rejects(test, 'InvalidStateError', context.resume());
+ }, "resume");
+
+ promise_test((test) => {
+ return promise_rejects(test, 'InvalidStateError', context.close());
+ }, "close");
+}
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/http/wpt/webaudio/resources/audiocontext-stopped-iframe.html (0 => 244825)
--- trunk/LayoutTests/http/wpt/webaudio/resources/audiocontext-stopped-iframe.html (rev 0)
+++ trunk/LayoutTests/http/wpt/webaudio/resources/audiocontext-stopped-iframe.html 2019-05-01 17:09:20 UTC (rev 244825)
@@ -0,0 +1,3 @@
+<script>
+window.audioContext = new webkitAudioContext();
+</script>
Modified: trunk/LayoutTests/platform/win/TestExpectations (244824 => 244825)
--- trunk/LayoutTests/platform/win/TestExpectations 2019-05-01 16:34:31 UTC (rev 244824)
+++ trunk/LayoutTests/platform/win/TestExpectations 2019-05-01 17:09:20 UTC (rev 244825)
@@ -494,6 +494,7 @@
# TODO For now, Web Audio tests are disabled
webkit.org/b/86914 webaudio/ [ Skip ]
+webkit.org/b/86914 http/wpt/webaudio/ [ Skip ]
webkit.org/b/86914 fast/history/page-cache-closed-audiocontext.html [ Skip ]
webkit.org/b/86914 fast/history/page-cache-running-audiocontext.html [ Skip ]
webkit.org/b/86914 fast/history/page-cache-suspended-audiocontext.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (244824 => 244825)
--- trunk/Source/WebCore/ChangeLog 2019-05-01 16:34:31 UTC (rev 244824)
+++ trunk/Source/WebCore/ChangeLog 2019-05-01 17:09:20 UTC (rev 244825)
@@ -1,3 +1,42 @@
+2019-05-01 Youenn Fablet <[email protected]>
+
+ Reject/throw when calling AudioContext methods on a stopped AudioContext
+ https://bugs.webkit.org/show_bug.cgi?id=197391
+
+ Reviewed by Eric Carlson.
+
+ Return InvalidStateError in that case.
+ ASSERT that we do not call lazyInitialize after being stopped
+ since this would mean we are doing unneeded processing.
+
+ Test: http/wpt/webaudio/audiocontext-stopped.html
+
+ * Modules/webaudio/AudioContext.cpp:
+ (WebCore::AudioContext::lazyInitialize):
+ (WebCore::AudioContext::createBufferSource):
+ (WebCore::AudioContext::createMediaElementSource):
+ (WebCore::AudioContext::createMediaStreamSource):
+ (WebCore::AudioContext::createMediaStreamDestination):
+ (WebCore::AudioContext::createScriptProcessor):
+ (WebCore::AudioContext::createBiquadFilter):
+ (WebCore::AudioContext::createWaveShaper):
+ (WebCore::AudioContext::createPanner):
+ (WebCore::AudioContext::createConvolver):
+ (WebCore::AudioContext::createDynamicsCompressor):
+ (WebCore::AudioContext::createAnalyser):
+ (WebCore::AudioContext::createGain):
+ (WebCore::AudioContext::createDelay):
+ (WebCore::AudioContext::createChannelSplitter):
+ (WebCore::AudioContext::createChannelMerger):
+ (WebCore::AudioContext::createOscillator):
+ (WebCore::AudioContext::createPeriodicWave):
+ (WebCore::AudioContext::startRendering):
+ (WebCore::AudioContext::suspend):
+ (WebCore::AudioContext::resume):
+ (WebCore::AudioContext::close):
+ * Modules/webaudio/AudioContext.h:
+ * Modules/webaudio/AudioContext.idl:
+
2019-05-01 Eric Carlson <[email protected]>
XMLHttpRequest should propagate user gestures for media playback
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (244824 => 244825)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp 2019-05-01 16:34:31 UTC (rev 244824)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp 2019-05-01 17:09:20 UTC (rev 244825)
@@ -216,6 +216,8 @@
void AudioContext::lazyInitialize()
{
+ ASSERT(!m_isStopScheduled);
+
if (m_isInitialized)
return;
@@ -430,11 +432,15 @@
m_audioDecoder.decodeAsync(WTFMove(audioData), sampleRate(), WTFMove(successCallback), WTFMove(errorCallback));
}
-Ref<AudioBufferSourceNode> AudioContext::createBufferSource()
+ExceptionOr<Ref<AudioBufferSourceNode>> AudioContext::createBufferSource()
{
ALWAYS_LOG(LOGIDENTIFIER);
-
+
ASSERT(isMainThread());
+
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
Ref<AudioBufferSourceNode> node = AudioBufferSourceNode::create(*this, m_destinationNode->sampleRate());
@@ -450,13 +456,14 @@
ExceptionOr<Ref<MediaElementAudioSourceNode>> AudioContext::createMediaElementSource(HTMLMediaElement& mediaElement)
{
ALWAYS_LOG(LOGIDENTIFIER);
-
+
ASSERT(isMainThread());
- lazyInitialize();
-
- if (mediaElement.audioSourceNode())
+
+ if (m_isStopScheduled || mediaElement.audioSourceNode())
return Exception { InvalidStateError };
+ lazyInitialize();
+
auto node = MediaElementAudioSourceNode::create(*this, mediaElement);
mediaElement.setAudioSourceNode(node.ptr());
@@ -475,6 +482,9 @@
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
auto audioTracks = mediaStream.getAudioTracks();
if (audioTracks.isEmpty())
return Exception { InvalidStateError };
@@ -498,8 +508,11 @@
return node;
}
-Ref<MediaStreamAudioDestinationNode> AudioContext::createMediaStreamDestination()
+ExceptionOr<Ref<MediaStreamAudioDestinationNode>> AudioContext::createMediaStreamDestination()
{
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
// FIXME: Add support for an optional argument which specifies the number of channels.
// FIXME: The default should probably be stereo instead of mono.
return MediaStreamAudioDestinationNode::create(*this, 1);
@@ -512,6 +525,10 @@
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
// W3C Editor's Draft 06 June 2017
@@ -567,65 +584,87 @@
return node;
}
-Ref<BiquadFilterNode> AudioContext::createBiquadFilter()
+ExceptionOr<Ref<BiquadFilterNode>> AudioContext::createBiquadFilter()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
+
return BiquadFilterNode::create(*this, m_destinationNode->sampleRate());
}
-Ref<WaveShaperNode> AudioContext::createWaveShaper()
+ExceptionOr<Ref<WaveShaperNode>> AudioContext::createWaveShaper()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return WaveShaperNode::create(*this);
}
-Ref<PannerNode> AudioContext::createPanner()
+ExceptionOr<Ref<PannerNode>> AudioContext::createPanner()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return PannerNode::create(*this, m_destinationNode->sampleRate());
}
-Ref<ConvolverNode> AudioContext::createConvolver()
+ExceptionOr<Ref<ConvolverNode>> AudioContext::createConvolver()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return ConvolverNode::create(*this, m_destinationNode->sampleRate());
}
-Ref<DynamicsCompressorNode> AudioContext::createDynamicsCompressor()
+ExceptionOr<Ref<DynamicsCompressorNode>> AudioContext::createDynamicsCompressor()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return DynamicsCompressorNode::create(*this, m_destinationNode->sampleRate());
}
-Ref<AnalyserNode> AudioContext::createAnalyser()
+ExceptionOr<Ref<AnalyserNode>> AudioContext::createAnalyser()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return AnalyserNode::create(*this, m_destinationNode->sampleRate());
}
-Ref<GainNode> AudioContext::createGain()
+ExceptionOr<Ref<GainNode>> AudioContext::createGain()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return GainNode::create(*this, m_destinationNode->sampleRate());
}
@@ -635,6 +674,9 @@
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
return DelayNode::create(*this, m_destinationNode->sampleRate(), maxDelayTime);
}
@@ -644,6 +686,9 @@
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
auto node = ChannelSplitterNode::create(*this, m_destinationNode->sampleRate(), numberOfOutputs);
if (!node)
@@ -656,6 +701,9 @@
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
auto node = ChannelMergerNode::create(*this, m_destinationNode->sampleRate(), numberOfInputs);
if (!node)
@@ -663,11 +711,14 @@
return node.releaseNonNull();
}
-Ref<OscillatorNode> AudioContext::createOscillator()
+ExceptionOr<Ref<OscillatorNode>> AudioContext::createOscillator()
{
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
lazyInitialize();
Ref<OscillatorNode> node = OscillatorNode::create(*this, m_destinationNode->sampleRate());
@@ -684,6 +735,9 @@
ALWAYS_LOG(LOGIDENTIFIER);
ASSERT(isMainThread());
+ if (m_isStopScheduled)
+ return Exception { InvalidStateError };
+
if (real.length() != imaginary.length() || (real.length() > MaxPeriodicWaveLength) || !real.length())
return Exception { IndexSizeError };
lazyInitialize();
@@ -1078,7 +1132,7 @@
void AudioContext::startRendering()
{
ALWAYS_LOG(LOGIDENTIFIER);
- if (!willBeginPlayback())
+ if (m_isStopScheduled || !willBeginPlayback())
return;
destination()->startRendering();
@@ -1150,7 +1204,7 @@
void AudioContext::suspend(DOMPromiseDeferred<void>&& promise)
{
- if (isOfflineContext()) {
+ if (isOfflineContext() || m_isStopScheduled) {
promise.reject(InvalidStateError);
return;
}
@@ -1179,7 +1233,7 @@
void AudioContext::resume(DOMPromiseDeferred<void>&& promise)
{
- if (isOfflineContext()) {
+ if (isOfflineContext() || m_isStopScheduled) {
promise.reject(InvalidStateError);
return;
}
@@ -1208,7 +1262,7 @@
void AudioContext::close(DOMPromiseDeferred<void>&& promise)
{
- if (isOfflineContext()) {
+ if (isOfflineContext() || m_isStopScheduled) {
promise.reject(InvalidStateError);
return;
}
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (244824 => 244825)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2019-05-01 16:34:31 UTC (rev 244824)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2019-05-01 17:09:20 UTC (rev 244825)
@@ -134,26 +134,26 @@
bool wouldTaintOrigin(const URL&) const;
// The AudioNode create methods are called on the main thread (from _javascript_).
- Ref<AudioBufferSourceNode> createBufferSource();
+ ExceptionOr<Ref<AudioBufferSourceNode>> createBufferSource();
#if ENABLE(VIDEO)
ExceptionOr<Ref<MediaElementAudioSourceNode>> createMediaElementSource(HTMLMediaElement&);
#endif
#if ENABLE(MEDIA_STREAM)
ExceptionOr<Ref<MediaStreamAudioSourceNode>> createMediaStreamSource(MediaStream&);
- Ref<MediaStreamAudioDestinationNode> createMediaStreamDestination();
+ ExceptionOr<Ref<MediaStreamAudioDestinationNode>> createMediaStreamDestination();
#endif
- Ref<GainNode> createGain();
- Ref<BiquadFilterNode> createBiquadFilter();
- Ref<WaveShaperNode> createWaveShaper();
+ ExceptionOr<Ref<GainNode>> createGain();
+ ExceptionOr<Ref<BiquadFilterNode>> createBiquadFilter();
+ ExceptionOr<Ref<WaveShaperNode>> createWaveShaper();
ExceptionOr<Ref<DelayNode>> createDelay(double maxDelayTime);
- Ref<PannerNode> createPanner();
- Ref<ConvolverNode> createConvolver();
- Ref<DynamicsCompressorNode> createDynamicsCompressor();
- Ref<AnalyserNode> createAnalyser();
+ ExceptionOr<Ref<PannerNode>> createPanner();
+ ExceptionOr<Ref<ConvolverNode>> createConvolver();
+ ExceptionOr<Ref<DynamicsCompressorNode>> createDynamicsCompressor();
+ ExceptionOr<Ref<AnalyserNode>> createAnalyser();
ExceptionOr<Ref<ScriptProcessorNode>> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels);
ExceptionOr<Ref<ChannelSplitterNode>> createChannelSplitter(size_t numberOfOutputs);
ExceptionOr<Ref<ChannelMergerNode>> createChannelMerger(size_t numberOfInputs);
- Ref<OscillatorNode> createOscillator();
+ ExceptionOr<Ref<OscillatorNode>> createOscillator();
ExceptionOr<Ref<PeriodicWave>> createPeriodicWave(Float32Array& real, Float32Array& imaginary);
// When a source node has no more processing to do (has finished playing), then it tells the context to dereference it.
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.idl (244824 => 244825)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.idl 2019-05-01 16:34:31 UTC (rev 244824)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.idl 2019-05-01 17:09:20 UTC (rev 244825)
@@ -69,24 +69,24 @@
void decodeAudioData(ArrayBuffer audioData, AudioBufferCallback? successCallback, optional AudioBufferCallback? errorCallback);
// Sources
- AudioBufferSourceNode createBufferSource();
+ [MayThrowException] AudioBufferSourceNode createBufferSource();
[Conditional=VIDEO, MayThrowException] MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
[Conditional=MEDIA_STREAM, MayThrowException] MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
- [Conditional=MEDIA_STREAM] MediaStreamAudioDestinationNode createMediaStreamDestination();
+ [Conditional=MEDIA_STREAM, MayThrowException] MediaStreamAudioDestinationNode createMediaStreamDestination();
// Processing nodes
- GainNode createGain();
+ [MayThrowException] GainNode createGain();
[MayThrowException] DelayNode createDelay(optional unrestricted double maxDelayTime = 1);
- BiquadFilterNode createBiquadFilter();
- WaveShaperNode createWaveShaper();
- PannerNode createPanner();
- ConvolverNode createConvolver();
- DynamicsCompressorNode createDynamicsCompressor();
- AnalyserNode createAnalyser();
+ [MayThrowException] BiquadFilterNode createBiquadFilter();
+ [MayThrowException] WaveShaperNode createWaveShaper();
+ [MayThrowException] PannerNode createPanner();
+ [MayThrowException] ConvolverNode createConvolver();
+ [MayThrowException] DynamicsCompressorNode createDynamicsCompressor();
+ [MayThrowException] AnalyserNode createAnalyser();
[MayThrowException] ScriptProcessorNode createScriptProcessor(optional unsigned long bufferSize = 0, optional unsigned long numberOfInputChannels = 2, optional unsigned long numberOfOutputChannels = 2);
- OscillatorNode createOscillator();
+ [MayThrowException] OscillatorNode createOscillator();
[MayThrowException] PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag);
// Channel splitting and merging