<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[174353] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/174353">174353</a></dd>
<dt>Author</dt> <dd>adachan@apple.com</dd>
<dt>Date</dt> <dd>2014-10-06 11:22:27 -0700 (Mon, 06 Oct 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Implement Page::isPlayingAudio().
https://bugs.webkit.org/show_bug.cgi?id=137218

Reviewed by Eric Carlson.

- Add a hasMediaCharacteristics() method to MediaSession. There are three characteristics:
audible, visual, and legible. MediaSession gets the media characteristics information from
its MediaSessionClient.
- Add a mediaStateDidChange() method to MediaSessionClient that MediaSession can call when its
state changes.
- Each Document keeps a set of MediaSessions it contains. When that set changes, or when a MediaSession
changes state, or when its characteristics change, Document::updateIsPlayingAudio() is called. That method
iterates through all its MediaSessions to check if the overall isPlayingAudio state has changed in the Document.
- Each Page caches its overall isPlayingAudio state. Whenever a Document's isPlayingAudio state changes,
it calls Page::updateIsPlayingAudio() which iterates through its frames' documents to calculate its
overall isPlayingAudio state.

No new tests, no behavior change.

* dom/Document.cpp:
(WebCore::Document::Document):
Initialize m_isPlayingAudio.
(WebCore::Document::registerMediaSession):
Add the MediaSession to m_mediaSessions. Call updateIsPlayingAudio().
(WebCore::Document::unregisterMediaSession):
Remove the MediaSession from m_mediaSessions. Call updateIsPlayingAudio().
(WebCore::Document::updateIsPlayingAudio):
Go through all the MediaSessions in this Document and check if any has the Audible characteristic
and is playing. If the overall isPlayingAudio state changes, call Page::updateIsPlayingAudio().
* dom/Document.h:
(WebCore::Document::isPlayingAudio):

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::registerWithDocument):
Call Document::registerMediaSession().
(WebCore::HTMLMediaElement::unregisterWithDocument):
Call Document::unregisterMediaSession().
(WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged):
Call Document::updateIsPlayingAudio().
(WebCore::HTMLMediaElement::stop):
Call MediaSession::clientWillPausePlayback() so the MediaSession's state can be set back to Paused.
(WebCore::HTMLMediaElement::hasMediaCharacteristics):
Call hasAudio() to check if the HTMLMediaElement has the Audible characteristic. Call hasVideo()
to check if it has the Visual characteristic. Call hasClosedCaptions() to check if it has the
Legible characteristic.
(WebCore::HTMLMediaElement::mediaStateDidChange):
Call Document::updateIsPlayingAudio().
* html/HTMLMediaElement.h:

* page/Page.cpp:
(WebCore::Page::Page):
Initialize m_isPlayingAudio.
(WebCore::Page::updateIsPlayingAudio):
Iterate through all its frames' documents to check if any has audio playing. If the overall isPlayingAudio
state has changed, update m_isPlayingAudio.
* page/Page.h:
(WebCore::Page::isPlayingAudio):

* platform/audio/MediaSession.cpp:
(WebCore::MediaSession::setState):
If the MediaSession's state has changed, call Document::updateIsPlayingAudio().
(WebCore::MediaSession::hasMediaCharacteristics):
Call MediaSessionClient::hasMediaCharacteristics().
* platform/audio/MediaSession.h:
(WebCore::MediaSessionClient::mediaStateDidChange):

* platform/audio/mac/AudioDestinationMac.h:
AudioDestination only has the Audible characteristic.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomDocumentcpp">trunk/Source/WebCore/dom/Document.cpp</a></li>
<li><a href="#trunkSourceWebCoredomDocumenth">trunk/Source/WebCore/dom/Document.h</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementh">trunk/Source/WebCore/html/HTMLMediaElement.h</a></li>
<li><a href="#trunkSourceWebCorepagePagecpp">trunk/Source/WebCore/page/Page.cpp</a></li>
<li><a href="#trunkSourceWebCorepagePageh">trunk/Source/WebCore/page/Page.h</a></li>
<li><a href="#trunkSourceWebCoreplatformaudioMediaSessioncpp">trunk/Source/WebCore/platform/audio/MediaSession.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformaudioMediaSessionh">trunk/Source/WebCore/platform/audio/MediaSession.h</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacAudioDestinationMach">trunk/Source/WebCore/platform/audio/mac/AudioDestinationMac.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/ChangeLog        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -1,3 +1,74 @@
</span><ins>+2014-10-06  Ada Chan  &lt;adachan@apple.com&gt;
+
+        Implement Page::isPlayingAudio().
+        https://bugs.webkit.org/show_bug.cgi?id=137218
+
+        Reviewed by Eric Carlson.
+
+        - Add a hasMediaCharacteristics() method to MediaSession. There are three characteristics:
+        audible, visual, and legible. MediaSession gets the media characteristics information from
+        its MediaSessionClient.
+        - Add a mediaStateDidChange() method to MediaSessionClient that MediaSession can call when its
+        state changes.
+        - Each Document keeps a set of MediaSessions it contains. When that set changes, or when a MediaSession
+        changes state, or when its characteristics change, Document::updateIsPlayingAudio() is called. That method
+        iterates through all its MediaSessions to check if the overall isPlayingAudio state has changed in the Document.
+        - Each Page caches its overall isPlayingAudio state. Whenever a Document's isPlayingAudio state changes,
+        it calls Page::updateIsPlayingAudio() which iterates through its frames' documents to calculate its
+        overall isPlayingAudio state.
+
+        No new tests, no behavior change.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        Initialize m_isPlayingAudio.
+        (WebCore::Document::registerMediaSession):
+        Add the MediaSession to m_mediaSessions. Call updateIsPlayingAudio().
+        (WebCore::Document::unregisterMediaSession):
+        Remove the MediaSession from m_mediaSessions. Call updateIsPlayingAudio().
+        (WebCore::Document::updateIsPlayingAudio):
+        Go through all the MediaSessions in this Document and check if any has the Audible characteristic
+        and is playing. If the overall isPlayingAudio state changes, call Page::updateIsPlayingAudio().
+        * dom/Document.h:
+        (WebCore::Document::isPlayingAudio):
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::registerWithDocument):
+        Call Document::registerMediaSession().
+        (WebCore::HTMLMediaElement::unregisterWithDocument):
+        Call Document::unregisterMediaSession().
+        (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged):
+        Call Document::updateIsPlayingAudio().
+        (WebCore::HTMLMediaElement::stop):
+        Call MediaSession::clientWillPausePlayback() so the MediaSession's state can be set back to Paused.
+        (WebCore::HTMLMediaElement::hasMediaCharacteristics):
+        Call hasAudio() to check if the HTMLMediaElement has the Audible characteristic. Call hasVideo()
+        to check if it has the Visual characteristic. Call hasClosedCaptions() to check if it has the
+        Legible characteristic.
+        (WebCore::HTMLMediaElement::mediaStateDidChange):
+        Call Document::updateIsPlayingAudio().
+        * html/HTMLMediaElement.h:
+
+        * page/Page.cpp:
+        (WebCore::Page::Page):
+        Initialize m_isPlayingAudio.
+        (WebCore::Page::updateIsPlayingAudio):
+        Iterate through all its frames' documents to check if any has audio playing. If the overall isPlayingAudio
+        state has changed, update m_isPlayingAudio.
+        * page/Page.h:
+        (WebCore::Page::isPlayingAudio):
+
+        * platform/audio/MediaSession.cpp:
+        (WebCore::MediaSession::setState):
+        If the MediaSession's state has changed, call Document::updateIsPlayingAudio().
+        (WebCore::MediaSession::hasMediaCharacteristics):
+        Call MediaSessionClient::hasMediaCharacteristics().
+        * platform/audio/MediaSession.h:
+        (WebCore::MediaSessionClient::mediaStateDidChange):
+
+        * platform/audio/mac/AudioDestinationMac.h:
+        AudioDestination only has the Audible characteristic.
+
</ins><span class="cx"> 2014-10-06  Christophe Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Use is&lt;&gt;() / downcast&lt;&gt;() for ScrollingTree subclasses
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.cpp (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.cpp        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/dom/Document.cpp        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -99,6 +99,7 @@
</span><span class="cx"> #include &quot;MediaCanStartListener.h&quot;
</span><span class="cx"> #include &quot;MediaQueryList.h&quot;
</span><span class="cx"> #include &quot;MediaQueryMatcher.h&quot;
</span><ins>+#include &quot;MediaSession.h&quot;
</ins><span class="cx"> #include &quot;MouseEventWithHitTestResults.h&quot;
</span><span class="cx"> #include &quot;NameNodeList.h&quot;
</span><span class="cx"> #include &quot;NestingLevelIncrementer.h&quot;
</span><span class="lines">@@ -519,6 +520,7 @@
</span><span class="cx">     , m_renderTreeBeingDestroyed(false)
</span><span class="cx">     , m_hasPreparedForDestruction(false)
</span><span class="cx">     , m_hasStyleWithViewportUnits(false)
</span><ins>+    , m_isPlayingAudio(false)
</ins><span class="cx"> {
</span><span class="cx">     allDocuments().add(this);
</span><span class="cx"> 
</span><span class="lines">@@ -3274,6 +3276,37 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Document::registerMediaSession(MediaSession&amp; mediaSession)
+{
+    m_mediaSessions.add(&amp;mediaSession);
+    updateIsPlayingAudio();
+}
+
+void Document::unregisterMediaSession(MediaSession&amp; mediaSession)
+{
+    m_mediaSessions.remove(&amp;mediaSession);
+    updateIsPlayingAudio();
+}
+
+void Document::updateIsPlayingAudio()
+{
+    bool isPlayingAudio = false;
+    for (auto mediaSession : m_mediaSessions) {
+        if (mediaSession-&gt;hasMediaCharacteristics(MediaSession::MediaCharacteristicAudible) &amp;&amp; mediaSession-&gt;state() == MediaSession::Playing) {
+            isPlayingAudio = true;
+            break;
+        }
+    }
+
+    if (isPlayingAudio == m_isPlayingAudio)
+        return;
+
+    m_isPlayingAudio = isPlayingAudio;
+
+    if (page())
+        page()-&gt;updateIsPlayingAudio();
+}
+
</ins><span class="cx"> void Document::styleResolverChanged(StyleResolverUpdateFlag updateFlag)
</span><span class="cx"> {
</span><span class="cx">     if (m_optimizedStyleSheetUpdateTimer.isActive())
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.h (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.h        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/dom/Document.h        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -123,6 +123,7 @@
</span><span class="cx"> class MediaCanStartListener;
</span><span class="cx"> class MediaQueryList;
</span><span class="cx"> class MediaQueryMatcher;
</span><ins>+class MediaSession;
</ins><span class="cx"> class MouseEventWithHitTestResults;
</span><span class="cx"> class NamedFlowCollection;
</span><span class="cx"> class NodeFilter;
</span><span class="lines">@@ -1288,6 +1289,11 @@
</span><span class="cx">     bool hasStyleWithViewportUnits() const { return m_hasStyleWithViewportUnits; }
</span><span class="cx">     void updateViewportUnitsOnResize();
</span><span class="cx"> 
</span><ins>+    void registerMediaSession(MediaSession&amp;);
+    void unregisterMediaSession(MediaSession&amp;);
+    bool isPlayingAudio() const { return m_isPlayingAudio; }
+    void updateIsPlayingAudio();
+
</ins><span class="cx"> protected:
</span><span class="cx">     enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 &lt;&lt; 1 };
</span><span class="cx">     Document(Frame*, const URL&amp;, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);
</span><span class="lines">@@ -1717,6 +1723,9 @@
</span><span class="cx">     bool m_hasPreparedForDestruction;
</span><span class="cx"> 
</span><span class="cx">     bool m_hasStyleWithViewportUnits;
</span><ins>+
+    HashSet&lt;MediaSession*&gt; m_mediaSessions;
+    bool m_isPlayingAudio;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline void Document::notifyRemovePendingSheetIfNeeded()
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -444,6 +444,7 @@
</span><span class="cx">         document.registerForPageScaleFactorChangedCallbacks(this);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    document.registerMediaSession(*m_mediaSession);
</ins><span class="cx">     addElementToDocumentMap(*this, document);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -468,6 +469,7 @@
</span><span class="cx">         document.unregisterForPageScaleFactorChangedCallbacks(this);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    document.unregisterMediaSession(*m_mediaSession);
</ins><span class="cx">     removeElementFromDocumentMap(*this, document);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -4320,6 +4322,9 @@
</span><span class="cx">         mediaControls()-&gt;reset();
</span><span class="cx">     if (renderer())
</span><span class="cx">         renderer()-&gt;updateFromElement();
</span><ins>+
+    document().updateIsPlayingAudio();
+
</ins><span class="cx">     endProcessingMediaPlayerCallback();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -4667,6 +4672,7 @@
</span><span class="cx">     // Stop the playback without generating events
</span><span class="cx">     m_playing = false;
</span><span class="cx">     setPausedInternal(true);
</span><ins>+    m_mediaSession-&gt;clientWillPausePlayback();
</ins><span class="cx"> 
</span><span class="cx">     userCancelledLoad();
</span><span class="cx"> 
</span><span class="lines">@@ -5987,6 +5993,23 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool HTMLMediaElement::hasMediaCharacteristics(MediaSession::MediaCharacteristics characteristics) const
+{
+    if ((characteristics &amp; MediaSession::MediaCharacteristicAudible) &amp;&amp; !hasAudio())
+        return false;
+    if ((characteristics &amp; MediaSession::MediaCharacteristicVisual) &amp;&amp; !hasVideo())
+        return false;
+    if ((characteristics &amp; MediaSession::MediaCharacteristicLegible) &amp;&amp; !hasClosedCaptions())
+        return false;
+
+    return true;
+}
+
+void HTMLMediaElement::mediaStateDidChange()
+{
+    document().updateIsPlayingAudio();
+}
+
</ins><span class="cx"> bool HTMLMediaElement::doesHaveAttribute(const AtomicString&amp; attribute, AtomicString* value) const
</span><span class="cx"> {
</span><span class="cx">     QualifiedName attributeName(nullAtom, attribute, nullAtom);
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.h        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -701,6 +701,8 @@
</span><span class="cx">     virtual bool canReceiveRemoteControlCommands() const override { return true; }
</span><span class="cx">     virtual void didReceiveRemoteControlCommand(MediaSession::RemoteControlCommandType) override;
</span><span class="cx">     virtual bool overrideBackgroundPlaybackRestriction() const override;
</span><ins>+    virtual bool hasMediaCharacteristics(MediaSession::MediaCharacteristics) const override;
+    virtual void mediaStateDidChange() override;
</ins><span class="cx"> 
</span><span class="cx">     void registerWithDocument(Document&amp;);
</span><span class="cx">     void unregisterWithDocument(Document&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCorepagePagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Page.cpp (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Page.cpp        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/page/Page.cpp        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -204,6 +204,7 @@
</span><span class="cx">     , m_visitedLinkStore(WTF::move(pageClients.visitedLinkStore))
</span><span class="cx">     , m_sessionID(SessionID::defaultSessionID())
</span><span class="cx">     , m_isClosing(false)
</span><ins>+    , m_isPlayingAudio(false)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_editorClient);
</span><span class="cx">     
</span><span class="lines">@@ -1192,6 +1193,25 @@
</span><span class="cx">     setSessionID(privateBrowsingEnabled ? SessionID::legacyPrivateSessionID() : SessionID::defaultSessionID());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Page::updateIsPlayingAudio()
+{
+    bool isPlayingAudio = false;
+    for (Frame* frame = &amp;mainFrame(); frame; frame = frame-&gt;tree().traverseNext()) {
+        if (frame-&gt;document()-&gt;isPlayingAudio()) {
+            isPlayingAudio = true;
+            break;
+        }
+    }
+
+    if (isPlayingAudio == m_isPlayingAudio)
+        return;
+
+    m_isPlayingAudio = isPlayingAudio;
+
+    // FIXME: Notify the ChromeClient that the isPlayingAudio state has changed.
+    // https://bugs.webkit.org/show_bug.cgi?id=137220
+}
+
</ins><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx"> void Page::checkSubframeCountConsistency() const
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCorepagePageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Page.h (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Page.h        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/page/Page.h        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -436,6 +436,9 @@
</span><span class="cx">     WEBCORE_EXPORT void enableLegacyPrivateBrowsing(bool privateBrowsingEnabled);
</span><span class="cx">     bool usesEphemeralSession() const { return m_sessionID.isEphemeral(); }
</span><span class="cx"> 
</span><ins>+    bool isPlayingAudio() const { return m_isPlayingAudio; }
+    void updateIsPlayingAudio();
+
</ins><span class="cx"> private:
</span><span class="cx">     WEBCORE_EXPORT void initGroup();
</span><span class="cx"> 
</span><span class="lines">@@ -595,6 +598,8 @@
</span><span class="cx">     SessionID m_sessionID;
</span><span class="cx"> 
</span><span class="cx">     bool m_isClosing;
</span><ins>+
+    bool m_isPlayingAudio;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline PageGroup&amp; Page::group()
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudioMediaSessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/MediaSession.cpp (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/MediaSession.cpp        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/platform/audio/MediaSession.cpp        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -76,7 +76,13 @@
</span><span class="cx"> void MediaSession::setState(State state)
</span><span class="cx"> {
</span><span class="cx">     LOG(Media, &quot;MediaSession::setState(%p) - %s&quot;, this, stateName(state));
</span><ins>+
+    if (m_state == state)
+        return;
+
</ins><span class="cx">     m_state = state;
</span><ins>+
+    client().mediaStateDidChange();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MediaSession::beginInterruption(InterruptionType type)
</span><span class="lines">@@ -107,6 +113,11 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool MediaSession::hasMediaCharacteristics(MediaSession::MediaCharacteristics mediaCharacteristics) const
+{
+    return client().hasMediaCharacteristics(mediaCharacteristics);
+}
+
</ins><span class="cx"> bool MediaSession::clientWillBeginPlayback()
</span><span class="cx"> {
</span><span class="cx">     setState(Playing);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudioMediaSessionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/MediaSession.h (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/MediaSession.h        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/platform/audio/MediaSession.h        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -71,6 +71,14 @@
</span><span class="cx">     void beginInterruption(InterruptionType);
</span><span class="cx">     void endInterruption(EndInterruptionFlags);
</span><span class="cx"> 
</span><ins>+    enum MediaCharacteristicFlags {
+        MediaCharacteristicAudible = 1,
+        MediaCharacteristicVisual = 1 &lt;&lt; 1,
+        MediaCharacteristicLegible = 1 &lt;&lt; 2,
+    };
+    typedef unsigned MediaCharacteristics;
+    bool hasMediaCharacteristics(MediaCharacteristics) const;
+
</ins><span class="cx">     void applicationWillEnterForeground() const;
</span><span class="cx">     void applicationWillEnterBackground() const;
</span><span class="cx"> 
</span><span class="lines">@@ -136,6 +144,9 @@
</span><span class="cx"> 
</span><span class="cx">     virtual bool overrideBackgroundPlaybackRestriction() const = 0;
</span><span class="cx"> 
</span><ins>+    virtual bool hasMediaCharacteristics(MediaSession::MediaCharacteristics) const = 0;
+    virtual void mediaStateDidChange() { }
+
</ins><span class="cx"> protected:
</span><span class="cx">     virtual ~MediaSessionClient() { }
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacAudioDestinationMach"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/AudioDestinationMac.h (174352 => 174353)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/AudioDestinationMac.h        2014-10-06 18:09:20 UTC (rev 174352)
+++ trunk/Source/WebCore/platform/audio/mac/AudioDestinationMac.h        2014-10-06 18:22:27 UTC (rev 174353)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx">     virtual bool canReceiveRemoteControlCommands() const override { return false; }
</span><span class="cx">     virtual void didReceiveRemoteControlCommand(MediaSession::RemoteControlCommandType) override { }
</span><span class="cx">     virtual bool overrideBackgroundPlaybackRestriction() const override { return false; }
</span><ins>+    virtual bool hasMediaCharacteristics(MediaSession::MediaCharacteristics characteristics) const override { return characteristics == MediaSession::MediaCharacteristicAudible; }
</ins><span class="cx"> 
</span><span class="cx">     virtual void start() override;
</span><span class="cx">     virtual void stop() override;
</span></span></pre>
</div>
</div>

</body>
</html>