Diff
Modified: trunk/LayoutTests/ChangeLog (214720 => 214721)
--- trunk/LayoutTests/ChangeLog 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/LayoutTests/ChangeLog 2017-04-02 00:55:20 UTC (rev 214721)
@@ -1,3 +1,16 @@
+2017-04-01 Chris Dumez <cdu...@apple.com>
+
+ We should pause silent WebAudio rendering in background tabs
+ https://bugs.webkit.org/show_bug.cgi?id=170299
+ <rdar://problem/31289132>
+
+ Reviewed by Eric Carlson.
+
+ Add layout test coverage.
+
+ * webaudio/silent-audio-interrupted-in-background-expected.txt: Added.
+ * webaudio/silent-audio-interrupted-in-background.html: Added.
+
2017-04-01 Alexey Proskuryakov <a...@apple.com>
Rolling back http://trac.webkit.org/r214663 - memory corruption
Modified: trunk/LayoutTests/platform/ios/TestExpectations (214720 => 214721)
--- trunk/LayoutTests/platform/ios/TestExpectations 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/LayoutTests/platform/ios/TestExpectations 2017-04-02 00:55:20 UTC (rev 214721)
@@ -311,6 +311,7 @@
webkit.org/b/165799 svg/animations/animations-paused-page-non-visible.html [ Skip ]
webkit.org/b/165799 svg/animations/animations-paused-in-background-page-iframe.html [ Skip ]
webkit.org/b/165799 svg/animations/animations-paused-in-background-page.html [ Skip ]
+webkit.org/b/165799 webaudio/silent-audio-interrupted-in-background.html [ Skip ]
# AutoFill button is not supported
fast/forms/auto-fill-button/mouse-down-input-mouse-release-auto-fill-button.html
Added: trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt (0 => 214721)
--- trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt (rev 0)
+++ trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt 2017-04-02 00:55:20 UTC (rev 214721)
@@ -0,0 +1,14 @@
+Tests that silent WebAudio rendering gets interrupted in hidden pages.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS context.state became 'running'
+* Setting page visibility to hidden
+PASS context.state became 'interrupted'
+* Setting page visibility to visible
+PASS context.state became 'running'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html (0 => 214721)
--- trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html (rev 0)
+++ trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html 2017-04-02 00:55:20 UTC (rev 214721)
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that silent WebAudio rendering gets interrupted in hidden pages.");
+jsTestIsAsync = true;
+
+document._onvisibilitychange_ = function() {
+ if (document.hidden) {
+ shouldBecomeEqual("context.state", "'interrupted'", showPage);
+ } else {
+ shouldBecomeEqual("context.state", "'running'", finishJSTest);
+ }
+}
+
+function showPage()
+{
+ debug("* Setting page visibility to visible");
+ if (window.testRunner)
+ testRunner.setPageVisibility("visible");
+}
+
+function hidePage()
+{
+ debug("* Setting page visibility to hidden");
+ if (window.testRunner)
+ testRunner.setPageVisibility("hidden");
+}
+
+_onload_ = function() {
+ context = new (window.AudioContext || window.webkitAudioContext)();
+
+ audioElement = document.createElement("audio");
+ audioElement.loop = true;
+ audioElement.muted = true;
+ audioElement.src = ""
+ source = context.createMediaElementSource(audioElement);
+
+ var gainNode = context.createGain();
+ source.connect(gainNode);
+ gainNode.connect(context.destination);
+ gainNode.gain.value = 0; // Mute.
+
+ shouldBecomeEqual("context.state", "'running'", hidePage);
+}
+</script>
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (214720 => 214721)
--- trunk/Source/WebCore/ChangeLog 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/ChangeLog 2017-04-02 00:55:20 UTC (rev 214721)
@@ -1,3 +1,44 @@
+2017-04-01 Chris Dumez <cdu...@apple.com>
+
+ We should pause silent WebAudio rendering in background tabs
+ https://bugs.webkit.org/show_bug.cgi?id=170299
+ <rdar://problem/31289132>
+
+ Reviewed by Eric Carlson.
+
+ We should pause silent WebAudio rendering in background tabs since it uses CPU and is
+ not observable by the user. Such silent WebAudio rendering seems to be used by
+ doubleclick ads.
+
+ Test: webaudio/silent-audio-interrupted-in-background.html
+
+ * Modules/webaudio/AudioContext.cpp:
+ (WebCore::AudioContext::lazyInitialize):
+ (WebCore::AudioContext::uninitialize):
+ Have AudioContext register / unregister itself with the Document to get
+ visibility change notifications, similarly to what HTMLMediaElement was
+ already doing.
+
+ (WebCore::AudioContext::visibilityStateChanged):
+ Begin / End session interruption whenever the page visiblity changes.
+
+ * Modules/webaudio/AudioContext.h:
+ * WebCore.xcodeproj/project.pbxproj:
+
+ * dom/Document.cpp:
+ (WebCore::Document::registerForVisibilityStateChangedCallbacks):
+ (WebCore::Document::unregisterForVisibilityStateChangedCallbacks):
+ (WebCore::Document::visibilityStateChanged):
+ * dom/Document.h:
+ * dom/Element.h:
+ * dom/VisibilityChangeClient.h: Added.
+ (WebCore::VisibilityChangeClient::~VisibilityChangeClient):
+ * html/HTMLMediaElement.h:
+ Introduce a new VisibilityChangeClient interface and have both AudioContext
+ and HTMLMediaElement subclass it. Previously, the visibilityStateChanged()
+ function was on Element but this prevented AudioContext from registering
+ itself since AudioContext is not an Element.
+
2017-04-01 Dan Bernstein <m...@apple.com>
[Cocoa] A couple of UI strings use three periods instead of an ellipsis
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (214720 => 214721)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp 2017-04-02 00:55:20 UTC (rev 214721)
@@ -54,6 +54,7 @@
#include "HRTFDatabaseLoader.h"
#include "HRTFPanner.h"
#include "JSDOMPromise.h"
+#include "Logging.h"
#include "NetworkingContext.h"
#include "OfflineAudioCompletionEvent.h"
#include "OfflineAudioDestinationNode.h"
@@ -104,6 +105,8 @@
const unsigned MaxPeriodicWaveLength = 4096;
namespace WebCore {
+
+#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(document()->page() && document()->page()->isAlwaysOnLoggingAllowed(), Media, "%p - AudioContext::" fmt, this, ##__VA_ARGS__)
bool AudioContext::isSampleRateRangeGood(float sampleRate)
{
@@ -215,6 +218,7 @@
if (!isOfflineContext()) {
document()->addAudioProducer(this);
+ document()->registerForVisibilityStateChangedCallbacks(this);
// This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
// Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
@@ -259,6 +263,7 @@
if (!isOfflineContext()) {
document()->removeAudioProducer(this);
+ document()->unregisterForVisibilityStateChangedCallbacks(this);
ASSERT(s_hardwareContextCount);
--s_hardwareContextCount;
@@ -363,6 +368,25 @@
return emptyString();
}
+void AudioContext::visibilityStateChanged()
+{
+ // Do not suspend if audio is audible.
+ if (mediaState() == MediaProducer::IsPlayingAudio)
+ return;
+
+ if (document()->hidden()) {
+ if (state() == State::Running) {
+ RELEASE_LOG_IF_ALLOWED("visibilityStateChanged() Suspending playback after going to the background");
+ m_mediaSession->beginInterruption(PlatformMediaSession::EnteringBackground);
+ }
+ } else {
+ if (state() == State::Interrupted) {
+ RELEASE_LOG_IF_ALLOWED("visibilityStateChanged() Resuming playback after entering foreground");
+ m_mediaSession->endInterruption(PlatformMediaSession::MayResumePlaying);
+ }
+ }
+}
+
ExceptionOr<Ref<AudioBuffer>> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
{
auto audioBuffer = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (214720 => 214721)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2017-04-02 00:55:20 UTC (rev 214721)
@@ -35,6 +35,7 @@
#include "MediaCanStartListener.h"
#include "MediaProducer.h"
#include "PlatformMediaSession.h"
+#include "VisibilityChangeClient.h"
#include <atomic>
#include <wtf/HashSet.h>
#include <wtf/MainThread.h>
@@ -75,7 +76,7 @@
// AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
// For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism.
-class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted<AudioContext>, public EventTargetWithInlineData, public MediaCanStartListener, public MediaProducer, private PlatformMediaSessionClient {
+class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted<AudioContext>, public EventTargetWithInlineData, public MediaCanStartListener, public MediaProducer, private PlatformMediaSessionClient, private VisibilityChangeClient {
public:
// Create an AudioContext for rendering to the audio hardware.
static RefPtr<AudioContext> create(Document&);
@@ -319,6 +320,8 @@
String sourceApplicationIdentifier() const override;
bool canProduceAudio() const final { return true; }
+ void visibilityStateChanged() final;
+
// EventTarget
void refEventTarget() override { ref(); }
void derefEventTarget() override { deref(); }
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (214720 => 214721)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2017-04-02 00:55:20 UTC (rev 214721)
@@ -3282,6 +3282,7 @@
83120C711C56F3FB001CB112 /* HTMLDataElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B86A71C56E83A00F3F0E3 /* HTMLDataElement.h */; };
832B843419D8E55100B26055 /* SVGAnimateElementBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 832B843319D8E55100B26055 /* SVGAnimateElementBase.h */; };
832B843619D8E57400B26055 /* SVGAnimateElementBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 832B843519D8E57400B26055 /* SVGAnimateElementBase.cpp */; };
+ 83407FC11E8D9C1700E048D3 /* VisibilityChangeClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 83407FC01E8D9C1200E048D3 /* VisibilityChangeClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
834476EE1DA5BC57002B6ED2 /* JSScrollToOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83E9B3001DA5A51E00FFE8F6 /* JSScrollToOptions.cpp */; };
834476EF1DA5BC5E002B6ED2 /* JSScrollToOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E9B3011DA5A51E00FFE8F6 /* JSScrollToOptions.h */; };
8348BFAB1B85729800912F36 /* ClassCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8348BFA91B85729500912F36 /* ClassCollection.cpp */; };
@@ -11261,6 +11262,7 @@
8329DCC21C7A6AE300730B33 /* HTMLHyperlinkElementUtils.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLHyperlinkElementUtils.idl; sourceTree = "<group>"; };
832B843319D8E55100B26055 /* SVGAnimateElementBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimateElementBase.h; sourceTree = "<group>"; };
832B843519D8E57400B26055 /* SVGAnimateElementBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimateElementBase.cpp; sourceTree = "<group>"; };
+ 83407FC01E8D9C1200E048D3 /* VisibilityChangeClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisibilityChangeClient.h; sourceTree = "<group>"; };
8348BFA91B85729500912F36 /* ClassCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassCollection.cpp; sourceTree = "<group>"; };
8348BFAA1B85729500912F36 /* ClassCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassCollection.h; sourceTree = "<group>"; };
834B86A61C56E83A00F3F0E3 /* HTMLDataElement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLDataElement.idl; sourceTree = "<group>"; };
@@ -25687,6 +25689,7 @@
BCDF317A11F8D683003C5BF8 /* UserTypingGestureIndicator.h */,
CEF418CC1179678C009D112C /* ViewportArguments.cpp */,
CEF418CD1179678C009D112C /* ViewportArguments.h */,
+ 83407FC01E8D9C1200E048D3 /* VisibilityChangeClient.h */,
419BC2DC1685329900D64D6D /* VisitedLinkState.cpp */,
419BC2DD1685329900D64D6D /* VisitedLinkState.h */,
31C0FF1B0E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp */,
@@ -29641,6 +29644,7 @@
26F9A83918A046AC00AEB88A /* ViewportConfiguration.h in Headers */,
3FFFF9AE159D9B060020BBD5 /* ViewportStyleResolver.h in Headers */,
93309E20099E64920056E581 /* VisiblePosition.h in Headers */,
+ 83407FC11E8D9C1700E048D3 /* VisibilityChangeClient.h in Headers */,
A883DF280F3D045D00F19BF6 /* VisibleSelection.h in Headers */,
93309E1E099E64920056E581 /* VisibleUnits.h in Headers */,
419BC2DF1685329900D64D6D /* VisitedLinkState.h in Headers */,
Modified: trunk/Source/WebCore/dom/Document.cpp (214720 => 214721)
--- trunk/Source/WebCore/dom/Document.cpp 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/dom/Document.cpp 2017-04-02 00:55:20 UTC (rev 214721)
@@ -1530,21 +1530,21 @@
updateTitleFromTitleElement();
}
-void Document::registerForVisibilityStateChangedCallbacks(Element* element)
+void Document::registerForVisibilityStateChangedCallbacks(VisibilityChangeClient* client)
{
- m_visibilityStateCallbackElements.add(element);
+ m_visibilityStateCallbackClients.add(client);
}
-void Document::unregisterForVisibilityStateChangedCallbacks(Element* element)
+void Document::unregisterForVisibilityStateChangedCallbacks(VisibilityChangeClient* client)
{
- m_visibilityStateCallbackElements.remove(element);
+ m_visibilityStateCallbackClients.remove(client);
}
void Document::visibilityStateChanged()
{
dispatchEvent(Event::create(eventNames().visibilitychangeEvent, false, false));
- for (auto* element : m_visibilityStateCallbackElements)
- element->visibilityStateChanged();
+ for (auto* client : m_visibilityStateCallbackClients)
+ client->visibilityStateChanged();
}
auto Document::visibilityState() const -> VisibilityState
Modified: trunk/Source/WebCore/dom/Document.h (214720 => 214721)
--- trunk/Source/WebCore/dom/Document.h 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/dom/Document.h 2017-04-02 00:55:20 UTC (rev 214721)
@@ -163,6 +163,7 @@
class Text;
class TextResourceDecoder;
class TreeWalker;
+class VisibilityChangeClient;
class VisitedLinkState;
class XPathEvaluator;
class XPathExpression;
@@ -1006,8 +1007,8 @@
void userInterfaceLayoutDirectionChanged();
#endif
- void registerForVisibilityStateChangedCallbacks(Element*);
- void unregisterForVisibilityStateChangedCallbacks(Element*);
+ void registerForVisibilityStateChangedCallbacks(VisibilityChangeClient*);
+ void unregisterForVisibilityStateChangedCallbacks(VisibilityChangeClient*);
#if ENABLE(VIDEO)
void registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(HTMLMediaElement&);
@@ -1520,7 +1521,7 @@
HashSet<HTMLMediaElement*> m_userInterfaceLayoutDirectionChangedElements;
#endif
- HashSet<Element*> m_visibilityStateCallbackElements;
+ HashSet<VisibilityChangeClient*> m_visibilityStateCallbackClients;
#if ENABLE(VIDEO)
HashSet<HTMLMediaElement*> m_allowsMediaDocumentInlinePlaybackElements;
#endif
Modified: trunk/Source/WebCore/dom/Element.h (214720 => 214721)
--- trunk/Source/WebCore/dom/Element.h 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/dom/Element.h 2017-04-02 00:55:20 UTC (rev 214721)
@@ -400,9 +400,6 @@
virtual void didBecomeFullscreenElement() { }
virtual void willStopBeingFullscreenElement() { }
- // Use Document::registerForVisibilityStateChangedCallbacks() to subscribe to this.
- virtual void visibilityStateChanged() { }
-
#if ENABLE(VIDEO_TRACK)
virtual void captionPreferencesChanged() { }
#endif
Added: trunk/Source/WebCore/dom/VisibilityChangeClient.h (0 => 214721)
--- trunk/Source/WebCore/dom/VisibilityChangeClient.h (rev 0)
+++ trunk/Source/WebCore/dom/VisibilityChangeClient.h 2017-04-02 00:55:20 UTC (rev 214721)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+class VisibilityChangeClient {
+public:
+ virtual ~VisibilityChangeClient() { }
+
+ virtual void visibilityStateChanged() = 0;
+};
+
+}
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (214720 => 214721)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2017-04-02 00:55:20 UTC (rev 214721)
@@ -37,6 +37,7 @@
#include "MediaElementSession.h"
#include "MediaProducer.h"
#include "UserInterfaceLayoutDirection.h"
+#include "VisibilityChangeClient.h"
#if ENABLE(VIDEO_TRACK)
#include "AudioTrack.h"
@@ -111,6 +112,7 @@
, private MediaCanStartListener
, private MediaPlayerClient
, private MediaProducer
+ , private VisibilityChangeClient
#if ENABLE(VIDEO_TRACK)
, private AudioTrackClient
, private TextTrackClient