Teach MediaSessionManager to manage interruptions
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Jan 2014 05:45:55 +0000 (05:45 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Jan 2014 05:45:55 +0000 (05:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=126530

Reviewed by Sam Weinig.

Source/WebCore:

Tests: media/video-interruption-active-when-element-created.html
       media/video-interruption-with-resume-allowing-play.html
       media/video-interruption-with-resume-not-allowing-play.html

* WebCore.exp.in: Export functions needed by Internals.

Add MediaSession and MediaSessionManager.
* CMakeLists.txt:
* GNUmakefile.list.am:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:

Automatically pause/play for interruptions. Move media restriction management to a MediaSession.
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement): Get rid of m_loadInitiatedByUserGesture and m_userStartedPlayback,
    they aren't needed.
(WebCore::HTMLMediaElement::load): Ditto.
(WebCore::HTMLMediaElement::loadInternal): Use the media session to manage restrictions.
(WebCore::HTMLMediaElement::play): Remove redundant iOS code. Postpone playback if called
    during an interruption.
(WebCore::HTMLMediaElement::pause): Remember to not resume playback when it ends if called during
    an interruption.
(WebCore::HTMLMediaElement::potentiallyPlaying): Rearrange code to make it easier to understand.
(WebCore::HTMLMediaElement::couldPlayIfEnoughData): Ditto.
(WebCore::HTMLMediaElement::pausedForUserInteraction): Return true if paused because of an interruption.
(WebCore::HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture): Be explicit about
    which restrictions are removed.
(WebCore::HTMLMediaElement::mediaType): MediaSessionManager::<Type> -> MediaSession::<Type>.
(WebCore::HTMLMediaElement::beginInterruption): New.
(WebCore::HTMLMediaElement::endInterruption): Ditto.
* html/HTMLMediaElement.h:

Pulled MediaSessionManagerToken out of MediaSessionManager.cpp, added functionality to manage interruptions.
* platform/audio/MediaSession.cpp: Added.
(WebCore::MediaSession::create):
(WebCore::MediaSession::MediaSession):
(WebCore::MediaSession::~MediaSession):
(WebCore::MediaSession::beginInterruption): Inform client of interruption state change.
(WebCore::MediaSession::endInterruption): Ditto.
* platform/audio/MediaSession.h: Added.

* platform/audio/MediaSessionManager.cpp:
(WebCore::MediaSessionManager::MediaSessionManager): Initialize interruption counter.
(WebCore::MediaSessionManager::has): MediaType is defined in MediaSession.
(WebCore::MediaSessionManager::count): Ditto.
(WebCore::MediaSessionManager::beginInterruption): Inform all clients of interruption start if
    not already in an interruption.
(WebCore::MediaSessionManager::endInterruption): Inform all clients if interruption has ended.
(WebCore::MediaSessionManager::addSession): Renamed from addToken. Set session interruption state.
(WebCore::MediaSessionManager::removeSession): Renamed from removeToken.
* platform/audio/MediaSessionManager.h:

* platform/audio/mac/AudioDestinationMac.cpp:
(WebCore::AudioDestinationMac::AudioDestinationMac): MediaSessionManagerToken -> MediaSession.
* platform/audio/mac/AudioDestinationMac.h:

* platform/audio/mac/MediaSessionManagerMac.cpp:
(MediaSessionManager::updateSessionState): Ditto.

Make it possible for tests to begin and end interruptions.
* testing/Internals.cpp:
(WebCore::Internals::beginMediaSessionInterruption):
(WebCore::Internals::endMediaSessionInterruption):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit:

* CMakeLists.txt: Add ${WEBCORE_DIR}/platform/animation to WebCore include directories.

Source/WebKit2:

* CMakeLists.txt: Add ${WEBCORE_DIR}/platform/animation to WebCore include directories.

LayoutTests:

* media/video-interruption-active-when-element-created-expected.txt: Added.
* media/video-interruption-active-when-element-created.html: Added.
* media/video-interruption-with-resume-allowing-play-expected.txt: Added.
* media/video-interruption-with-resume-allowing-play.html: Added.
* media/video-interruption-with-resume-not-allowing-play-expected.txt: Added.
* media/video-interruption-with-resume-not-allowing-play.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@161481 268f45cc-cd09-0410-ab3c-d52691b4dbfc

30 files changed:
LayoutTests/ChangeLog
LayoutTests/media/video-interruption-active-when-element-created-expected.txt [new file with mode: 0644]
LayoutTests/media/video-interruption-active-when-element-created.html [new file with mode: 0644]
LayoutTests/media/video-interruption-with-resume-allowing-play-expected.txt [new file with mode: 0644]
LayoutTests/media/video-interruption-with-resume-allowing-play.html [new file with mode: 0644]
LayoutTests/media/video-interruption-with-resume-not-allowing-play-expected.txt [new file with mode: 0644]
LayoutTests/media/video-interruption-with-resume-not-allowing-play.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.exp.in
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/platform/audio/MediaSession.cpp [new file with mode: 0644]
Source/WebCore/platform/audio/MediaSession.h [new file with mode: 0644]
Source/WebCore/platform/audio/MediaSessionManager.cpp
Source/WebCore/platform/audio/MediaSessionManager.h
Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp
Source/WebCore/platform/audio/mac/AudioDestinationMac.h
Source/WebCore/platform/audio/mac/MediaSessionManagerMac.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/CMakeLists.txt
Source/WebKit/ChangeLog
Source/WebKit2/CMakeLists.txt
Source/WebKit2/ChangeLog

index 1a80510..a1fdf32 100644 (file)
@@ -1,3 +1,17 @@
+2014-01-07  Eric Carlson  <eric.carlson@apple.com>
+
+        Teach MediaSessionManager to manage interruptions
+        https://bugs.webkit.org/show_bug.cgi?id=126530
+
+        Reviewed by Sam Weinig.
+
+        * media/video-interruption-active-when-element-created-expected.txt: Added.
+        * media/video-interruption-active-when-element-created.html: Added.
+        * media/video-interruption-with-resume-allowing-play-expected.txt: Added.
+        * media/video-interruption-with-resume-allowing-play.html: Added.
+        * media/video-interruption-with-resume-not-allowing-play-expected.txt: Added.
+        * media/video-interruption-with-resume-not-allowing-play.html: Added.
+
 2014-01-07  Seokju Kwon  <seokju@webkit.org>
 
         Web Inspector: Remove leftover 'device metrics' code
diff --git a/LayoutTests/media/video-interruption-active-when-element-created-expected.txt b/LayoutTests/media/video-interruption-active-when-element-created-expected.txt
new file mode 100644 (file)
index 0000000..42e082c
--- /dev/null
@@ -0,0 +1,15 @@
+Test a <video> element crated during interruption behaves correctly.
+
+RUN(internals.beginMediaSessionInterruption())
+RUN(video = document.createElement('video'))
+RUN(document.body.appendChild(video))
+EVENT(canplaythrough)
+
+RUN(video.play())
+100ms timer fired...
+EXPECTED (video.paused == 'true') OK
+RUN(internals.endMediaSessionInterruption('MayResumePlaying'))
+EVENT(playing)
+
+END OF TEST
+
diff --git a/LayoutTests/media/video-interruption-active-when-element-created.html b/LayoutTests/media/video-interruption-active-when-element-created.html
new file mode 100644 (file)
index 0000000..5c69ab0
--- /dev/null
@@ -0,0 +1,56 @@
+<html>
+    <head>
+        <script src=media-file.js></script>
+        <script src=video-test.js></script>
+        <script>
+            var state = 0;
+
+            function checkState()
+            {
+                consoleWrite("100ms timer fired...");
+                testExpected("video.paused", true);
+                state = "resuming";
+                run("internals.endMediaSessionInterruption('MayResumePlaying')");
+            }
+
+            function playing()
+            {
+                if (state != "resuming")
+                {
+                    consoleWrite("");
+                    failTest("<b>Playback started during interruption.</b>");
+                    return;
+                }
+
+                consoleWrite("");
+                endTest();
+            }
+
+            function canplaythrough()
+            {
+                consoleWrite("");
+                run("video.play()");
+                setTimeout(checkState, 100);
+            }
+
+            function start()
+            {
+                if (!window.internals) {
+                    failTest('This test requires window.internals.');
+                    return;
+                }
+                run("internals.beginMediaSessionInterruption()");;
+                run("video = document.createElement('video')");
+                run("document.body.appendChild(video)");
+                waitForEvent('canplaythrough', canplaythrough);
+                waitForEvent('playing', playing);
+                video.src = findMediaFile("video", "content/test");
+                state = "interrupted";
+            }
+        </script>
+    </head>
+
+    <body onload="start()">
+        <p>Test a &lt;video&gt; element crated during interruption behaves correctly.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/video-interruption-with-resume-allowing-play-expected.txt b/LayoutTests/media/video-interruption-with-resume-allowing-play-expected.txt
new file mode 100644 (file)
index 0000000..b6b91a2
--- /dev/null
@@ -0,0 +1,14 @@
+
+Test that play() during interruption does nothing, ending interruption allows playback to resume.
+
+EVENT(canplaythrough)
+
+RUN(internals.beginMediaSessionInterruption())
+RUN(video.play())
+100ms timer fired...
+EXPECTED (video.paused == 'true') OK
+RUN(internals.endMediaSessionInterruption('MayResumePlaying'))
+EVENT(playing)
+
+END OF TEST
+
diff --git a/LayoutTests/media/video-interruption-with-resume-allowing-play.html b/LayoutTests/media/video-interruption-with-resume-allowing-play.html
new file mode 100644 (file)
index 0000000..0da21c8
--- /dev/null
@@ -0,0 +1,58 @@
+<html>
+    <head>
+        <script src=media-file.js></script>
+        <script src=video-test.js></script>
+        <script>
+            var state = 0;
+
+            function checkState()
+            {
+                consoleWrite("100ms timer fired...");
+                testExpected("video.paused", true);
+                state = "resuming";
+                run("internals.endMediaSessionInterruption('MayResumePlaying')");
+            }
+
+            function playing()
+            {
+                if (state != "resuming")
+                {
+                    consoleWrite("");
+                    failTest("<b>Playback started during interruption.</b>");
+                    return;
+                }
+
+                consoleWrite("");
+                endTest();
+            }
+
+            function canplaythrough()
+            {
+                consoleWrite("");
+
+                run("internals.beginMediaSessionInterruption()");;
+                state = "interrupted";
+                run("video.play()");
+                setTimeout(checkState, 100);
+            }
+
+            function start()
+            {
+                if (!window.internals) {
+                    failTest('This test requires window.internals.');
+                    return;
+                }
+
+                findMediaElement();
+                waitForEvent('canplaythrough', canplaythrough);
+                waitForEvent('playing', playing);
+                video.src = findMediaFile("video", "content/test");
+            }
+        </script>
+    </head>
+
+    <body onload="start()">
+        <video controls ></video>
+        <p>Test that play() during interruption does nothing, ending interruption allows playback to resume.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/video-interruption-with-resume-not-allowing-play-expected.txt b/LayoutTests/media/video-interruption-with-resume-not-allowing-play-expected.txt
new file mode 100644 (file)
index 0000000..77f1788
--- /dev/null
@@ -0,0 +1,15 @@
+
+Test that play() during interruption does nothing, ending interruption does not allow playback to resume.
+
+EVENT(canplaythrough)
+
+RUN(internals.beginMediaSessionInterruption())
+RUN(video.play())
+100ms timer fired...
+EXPECTED (video.paused == 'true') OK
+RUN(internals.endMediaSessionInterruption(''))
+100ms timer fired...
+EXPECTED (video.paused == 'true') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/video-interruption-with-resume-not-allowing-play.html b/LayoutTests/media/video-interruption-with-resume-not-allowing-play.html
new file mode 100644 (file)
index 0000000..ea5a188
--- /dev/null
@@ -0,0 +1,62 @@
+<html>
+    <head>
+        <script src=media-file.js></script>
+        <script src=video-test.js></script>
+        <script>
+            var state = 0;
+
+            function playing()
+            {
+                if (state == "resuming")
+                    failTest("<b>Playback started after interruption.</b>");
+                else
+                    failTest("<b>Playback started during interruption.</b>");
+            }
+
+            function checkState()
+            {
+                consoleWrite("100ms timer fired...");
+                testExpected("video.paused", true);
+                switch (state) {
+                case "interrupted":
+                    state = "resuming";
+                    setTimeout(checkState, 100);
+                    run("internals.endMediaSessionInterruption('')");
+                    break;
+                case "resuming":
+                    consoleWrite("");
+                    endTest();
+                    break;
+                }
+            }
+
+            function canplaythrough()
+            {
+                consoleWrite("");
+
+                run("internals.beginMediaSessionInterruption()");;
+                state = "interrupted";
+                run("video.play()");
+                setTimeout(checkState, 100);
+            }
+
+            function start()
+            {
+                if (!window.internals) {
+                    failTest('This test requires window.internals.');
+                    return;
+                }
+
+                findMediaElement();
+                waitForEvent('canplaythrough', canplaythrough);
+                waitForEvent('playing', playing);
+                video.src = findMediaFile("video", "content/test");
+            }
+        </script>
+    </head>
+
+    <body onload="start()">
+        <video controls ></video>
+        <p>Test that play() during interruption does nothing, ending interruption does not allow playback to resume.</p>
+    </body>
+</html>
index 41ebcb4..a6ee8a3 100644 (file)
@@ -1876,6 +1876,8 @@ set(WebCore_SOURCES
     platform/audio/HRTFElevation.cpp
     platform/audio/HRTFKernel.cpp
     platform/audio/HRTFPanner.cpp
+    platform/audio/MediaSession.cpp
+    platform/audio/MediaSessionManager.cpp
     platform/audio/MultiChannelResampler.cpp
     platform/audio/Panner.cpp
     platform/audio/Reverb.cpp
index c7579db..9288ee0 100644 (file)
@@ -1,3 +1,77 @@
+2014-01-07  Eric Carlson  <eric.carlson@apple.com>
+
+        Teach MediaSessionManager to manage interruptions
+        https://bugs.webkit.org/show_bug.cgi?id=126530
+
+        Reviewed by Sam Weinig.
+
+        Tests: media/video-interruption-active-when-element-created.html
+               media/video-interruption-with-resume-allowing-play.html
+               media/video-interruption-with-resume-not-allowing-play.html
+
+        * WebCore.exp.in: Export functions needed by Internals.
+
+        Add MediaSession and MediaSessionManager.
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        Automatically pause/play for interruptions. Move media restriction management to a MediaSession.
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement): Get rid of m_loadInitiatedByUserGesture and m_userStartedPlayback,
+            they aren't needed.
+        (WebCore::HTMLMediaElement::load): Ditto.
+        (WebCore::HTMLMediaElement::loadInternal): Use the media session to manage restrictions.
+        (WebCore::HTMLMediaElement::play): Remove redundant iOS code. Postpone playback if called 
+            during an interruption.
+        (WebCore::HTMLMediaElement::pause): Remember to not resume playback when it ends if called during
+            an interruption.
+        (WebCore::HTMLMediaElement::potentiallyPlaying): Rearrange code to make it easier to understand.
+        (WebCore::HTMLMediaElement::couldPlayIfEnoughData): Ditto.
+        (WebCore::HTMLMediaElement::pausedForUserInteraction): Return true if paused because of an interruption.
+        (WebCore::HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture): Be explicit about
+            which restrictions are removed.
+        (WebCore::HTMLMediaElement::mediaType): MediaSessionManager::<Type> -> MediaSession::<Type>.
+        (WebCore::HTMLMediaElement::beginInterruption): New.
+        (WebCore::HTMLMediaElement::endInterruption): Ditto.
+        * html/HTMLMediaElement.h:
+
+        Pulled MediaSessionManagerToken out of MediaSessionManager.cpp, added functionality to manage interruptions.
+        * platform/audio/MediaSession.cpp: Added.
+        (WebCore::MediaSession::create):
+        (WebCore::MediaSession::MediaSession):
+        (WebCore::MediaSession::~MediaSession):
+        (WebCore::MediaSession::beginInterruption): Inform client of interruption state change.
+        (WebCore::MediaSession::endInterruption): Ditto.
+        * platform/audio/MediaSession.h: Added.
+
+        * platform/audio/MediaSessionManager.cpp:
+        (WebCore::MediaSessionManager::MediaSessionManager): Initialize interruption counter.
+        (WebCore::MediaSessionManager::has): MediaType is defined in MediaSession.
+        (WebCore::MediaSessionManager::count): Ditto.
+        (WebCore::MediaSessionManager::beginInterruption): Inform all clients of interruption start if
+            not already in an interruption.
+        (WebCore::MediaSessionManager::endInterruption): Inform all clients if interruption has ended.
+        (WebCore::MediaSessionManager::addSession): Renamed from addToken. Set session interruption state.
+        (WebCore::MediaSessionManager::removeSession): Renamed from removeToken.
+        * platform/audio/MediaSessionManager.h:
+
+        * platform/audio/mac/AudioDestinationMac.cpp:
+        (WebCore::AudioDestinationMac::AudioDestinationMac): MediaSessionManagerToken -> MediaSession.
+        * platform/audio/mac/AudioDestinationMac.h:
+
+        * platform/audio/mac/MediaSessionManagerMac.cpp:
+        (MediaSessionManager::updateSessionState): Ditto.
+
+        Make it possible for tests to begin and end interruptions.
+        * testing/Internals.cpp:
+        (WebCore::Internals::beginMediaSessionInterruption):
+        (WebCore::Internals::endMediaSessionInterruption):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2014-01-07  Seokju Kwon  <seokju@webkit.org>
 
         Web Inspector: Remove leftover 'device metrics' code
index 2da1bb6..45b876e 100644 (file)
@@ -5350,6 +5350,10 @@ webcore_platform_sources += \
        Source/WebCore/platform/audio/HRTFPanner.h \
        Source/WebCore/platform/audio/Panner.cpp \
        Source/WebCore/platform/audio/Panner.h \
+       Source/WebCore/platform/audio/MediaSession.cpp \
+       Source/WebCore/platform/audio/MediaSession.h \
+       Source/WebCore/platform/audio/MediaSessionManager.cpp \
+       Source/WebCore/platform/audio/MediaSessionManager.h \
        Source/WebCore/platform/CalculationValue.cpp \
        Source/WebCore/platform/CalculationValue.h \
        Source/WebCore/platform/CrossThreadCopier.cpp \
index 86d748f..0c1fd2c 100644 (file)
@@ -756,6 +756,9 @@ __ZN7WebCore19LayerFlushSchedulerC1EPNS_25LayerFlushSchedulerClientE
 __ZN7WebCore19LayerFlushSchedulerC2EPNS_25LayerFlushSchedulerClientE
 __ZN7WebCore19LayerFlushSchedulerD1Ev
 __ZN7WebCore19LayerFlushSchedulerD2Ev
+__ZN7WebCore19MediaSessionManager13sharedManagerEv
+__ZN7WebCore19MediaSessionManager15endInterruptionENS_12MediaSession20EndInterruptionFlagsE
+__ZN7WebCore19MediaSessionManager17beginInterruptionEv
 __ZN7WebCore19ResourceRequestBase11setHTTPBodyEN3WTF10PassRefPtrINS_8FormDataEEE
 __ZN7WebCore19ResourceRequestBase13setHTTPMethodERKN3WTF6StringE
 __ZN7WebCore19ResourceRequestBase18setHTTPHeaderFieldEPKcRKN3WTF6StringE
index 8d1acb5..796e3a0 100644 (file)
     <ClCompile Include="..\platform\FileStream.cpp" />
     <ClCompile Include="..\platform\FileSystem.cpp" />
     <ClCompile Include="..\platform\audio\AudioSession.cpp" />
+    <ClCompile Include="..\platform\audio\MediaSession.cpp" />
+    <ClCompile Include="..\platform\audio\MediaSessionManager.cpp" />
     <ClCompile Include="..\platform\graphics\ANGLEWebKitBridge.cpp" />
     <ClCompile Include="..\platform\graphics\avfoundation\cf\InbandTextTrackPrivateAVCF.cpp" />
     <ClCompile Include="..\platform\graphics\avfoundation\cf\InbandTextTrackPrivateLegacyAVCF.cpp" />
     <ClInclude Include="..\platform\FloatConversion.h" />
     <ClInclude Include="..\platform\audio\AudioSession.h" />
     <ClInclude Include="..\platform\audio\AudioSessionListener.h" />
+    <ClInclude Include="..\platform\audio\MediaSession.h" />
+    <ClInclude Include="..\platform\audio\MediaSessionManager.h" />
     <ClInclude Include="..\platform\graphics\ANGLEWebKitBridge.h" />
     <ClInclude Include="..\platform\graphics\AudioTrackPrivate.h" />
     <ClInclude Include="..\platform\graphics\avfoundation\cf\InbandTextTrackPrivateAVCF.h" />
index 308bda7..a76ea04 100644 (file)
     <ClInclude Include="..\platform\audio\AudioSessionListener.h">
       <Filter>platform\audio</Filter>
     </ClInclude>
+    <ClInclude Include="..\platform\audio\MediaSession.h">
+      <Filter>platform\audio</Filter>
+    </ClInclude>
+    <ClInclude Include="..\platform\audio\MediaSessionManager.h">
+      <Filter>platform\audio</Filter>
+    </ClInclude>
     <ClInclude Include="..\platform\graphics\ANGLEWebKitBridge.h">
       <Filter>platform\graphics</Filter>
     </ClInclude>
index 45d42a2..15e73ce 100644 (file)
                070756DF14239B4E00414161 /* JSTextTrackCueList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 070756D914239B4C00414161 /* JSTextTrackCueList.cpp */; };
                070756E014239B4E00414161 /* JSTextTrackCueList.h in Headers */ = {isa = PBXBuildFile; fileRef = 070756DA14239B4E00414161 /* JSTextTrackCueList.h */; };
                0709FC4E1025DEE30059CDBA /* AccessibilitySlider.h in Headers */ = {isa = PBXBuildFile; fileRef = 0709FC4D1025DEE30059CDBA /* AccessibilitySlider.h */; };
+               070E09191875EEFC003A1D3C /* MediaSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 070E09181875ED93003A1D3C /* MediaSession.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               070E091B1875EF71003A1D3C /* MediaSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 070E091A1875EF71003A1D3C /* MediaSession.cpp */; };
                070F549817F12F6B00169E04 /* MediaStreamConstraintsValidationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 070F549717F12F6B00169E04 /* MediaStreamConstraintsValidationClient.h */; };
                070F549E17F2402700169E04 /* AudioDestinationConsumer.h in Headers */ = {isa = PBXBuildFile; fileRef = 070F549D17F2402700169E04 /* AudioDestinationConsumer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0711589117DF6F6600EDFE2B /* MediaStreamPrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0711588F17DF633700EDFE2B /* MediaStreamPrivate.cpp */; };
                070756DA14239B4E00414161 /* JSTextTrackCueList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTextTrackCueList.h; sourceTree = "<group>"; };
                0709FC4D1025DEE30059CDBA /* AccessibilitySlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilitySlider.h; sourceTree = "<group>"; };
                070DD8F50F01868000727DEB /* mediaControls.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mediaControls.css; sourceTree = "<group>"; };
+               070E09181875ED93003A1D3C /* MediaSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSession.h; sourceTree = "<group>"; };
+               070E091A1875EF71003A1D3C /* MediaSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaSession.cpp; sourceTree = "<group>"; };
                070F549717F12F6B00169E04 /* MediaStreamConstraintsValidationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaStreamConstraintsValidationClient.h; sourceTree = "<group>"; };
                070F549D17F2402700169E04 /* AudioDestinationConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioDestinationConsumer.h; sourceTree = "<group>"; };
                0711588F17DF633700EDFE2B /* MediaStreamPrivate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaStreamPrivate.cpp; sourceTree = "<group>"; };
                                CDA79822170A24F400D45C55 /* AudioSessionListener.h */,
                                CDAE8C071746B95700532D78 /* MediaSessionManager.cpp */,
                                CDAE8C081746B95700532D78 /* MediaSessionManager.h */,
+                               070E09181875ED93003A1D3C /* MediaSession.h */,
+                               070E091A1875EF71003A1D3C /* MediaSession.cpp */,
                                FD31605312B026F700C1A359 /* AudioSourceProvider.h */,
                                FD62F52D145898D80094B0ED /* AudioSourceProviderClient.h */,
                                FD31605412B026F700C1A359 /* AudioUtilities.cpp */,
                                436708C712D9CA4B00044234 /* RenderSVGHiddenContainer.h in Headers */,
                                436708C912D9CA4B00044234 /* RenderSVGImage.h in Headers */,
                                0854B0151255E4E600B9CDD0 /* RenderSVGInline.h in Headers */,
+                               070E09191875EEFC003A1D3C /* MediaSession.h in Headers */,
                                0854B0171255E4E600B9CDD0 /* RenderSVGInlineText.h in Headers */,
                                CD3A496217A9D01B00274E42 /* SourceBuffer.h in Headers */,
                                436708CB12D9CA4B00044234 /* RenderSVGModelObject.h in Headers */,
                                93309E11099E64920056E581 /* SplitElementCommand.cpp in Sources */,
                                93309E13099E64920056E581 /* SplitTextNodeCommand.cpp in Sources */,
                                078E094B17D1709600420AA1 /* MediaStreamAudioDestinationNode.cpp in Sources */,
+                               070E091B1875EF71003A1D3C /* MediaSession.cpp in Sources */,
                                93309E15099E64920056E581 /* SplitTextNodeContainingElementCommand.cpp in Sources */,
                                A1E1154813015C5D0054AC8C /* SpotLightSource.cpp in Sources */,
                                97BC6A3E1505F081001B74AC /* SQLException.cpp in Sources */,
index 5ee883f..aab88c4 100644 (file)
 #include "ApplicationCacheHost.h"
 #include "ApplicationCacheResource.h"
 #include "Attribute.h"
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
 #include "ChromeClient.h"
 #include "ClientRect.h"
 #include "ClientRectList.h"
 #include "ContentSecurityPolicy.h"
 #include "ContentType.h"
-#include "CSSPropertyNames.h"
-#include "CSSValueKeywords.h"
 #include "DiagnosticLoggingKeys.h"
 #include "DocumentLoader.h"
 #include "ElementIterator.h"
@@ -50,6 +50,7 @@
 #include "JSHTMLMediaElement.h"
 #include "Language.h"
 #include "Logging.h"
+#include "MIMETypeRegistry.h"
 #include "MainFrame.h"
 #include "MediaController.h"
 #include "MediaControls.h"
@@ -59,7 +60,7 @@
 #include "MediaKeyEvent.h"
 #include "MediaList.h"
 #include "MediaQueryEvaluator.h"
-#include "MIMETypeRegistry.h"
+#include "MediaSessionManager.h"
 #include "PageActivityAssertionToken.h"
 #include "PageGroup.h"
 #include "ProgressTracker.h"
 #include "PlatformTextTrack.h"
 #endif
 
-#if USE(AUDIO_SESSION)
-#include "MediaSessionManager.h"
-#endif
-
 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
 #include "JSMediaControlsHost.h"
 #include "MediaControlsHost.h"
@@ -317,7 +314,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     , m_needWidgetUpdate(false)
 #endif
-    , m_loadInitiatedByUserGesture(false)
     , m_completelyLoaded(false)
     , m_havePreparedToPlay(false)
     , m_parsingInProgress(createdByParser)
@@ -326,7 +322,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
 #endif
 #if PLATFORM(IOS)
     , m_requestingPlay(false)
-    , m_userStartedPlayback(false)
 #endif
 #if ENABLE(VIDEO_TRACK)
     , m_tracksAreReady(true)
@@ -342,9 +337,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
 #if ENABLE(WEB_AUDIO)
     , m_audioSourceNode(0)
 #endif
-#if USE(AUDIO_SESSION)
-    , m_mediaSessionManagerToken(MediaSessionManagerToken::create(*this))
-#endif
+    , m_mediaSession(MediaSession::create(*this))
     , m_reportedExtraMemoryCost(0)
 #if ENABLE(MEDIA_STREAM)
     , m_mediaStreamSrcObject(nullptr)
@@ -374,8 +367,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
 #if ENABLE(IOS_AIRPLAY)
         addBehaviorRestriction(RequireUserGestureToShowPlaybackTargetPicker);
 #endif
-    } else
-        m_restrictions = NoRestrictions;
+    }
 #endif // !PLATFORM(IOS)
 
     addElementToDocumentMap(*this, document);
@@ -903,21 +895,11 @@ void HTMLMediaElement::load()
     
     if (userGestureRequiredForLoad() && !ScriptController::processingUserGesture())
         return;
-    
-    m_loadInitiatedByUserGesture = ScriptController::processingUserGesture();
-    if (m_loadInitiatedByUserGesture)
+    if (ScriptController::processingUserGesture())
         removeBehaviorsRestrictionsAfterFirstUserGesture();
+
     prepareForLoad();
     loadInternal();
-
-#if PLATFORM(IOS)
-    // Unless this method was called directly by the user or the application allows any script to trigger playback,
-    // return now because prepareToPlay() tells the media engine to start loading data as soon as the movie validates.
-    Settings* settings = document().settings();
-    if (!m_loadInitiatedByUserGesture && (!settings || settings->mediaPlaybackRequiresUserGesture()))
-        return;
-#endif
-
     prepareToPlay();
 }
 
@@ -2657,10 +2639,11 @@ void HTMLMediaElement::play()
     if (ScriptController::processingUserGesture())
         removeBehaviorsRestrictionsAfterFirstUserGesture();
 
-#if PLATFORM(IOS)
-    userRequestsMediaLoading();
-#endif
-
+    if (m_mediaSession->state() == MediaSession::Interrupted) {
+        m_resumePlaybackAfterInterruption = true;
+        return;
+    }
+    
     playInternal();
 }
 
@@ -2703,6 +2686,11 @@ void HTMLMediaElement::pause()
     if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
         return;
 
+    if (m_mediaSession->state() == MediaSession::Interrupted) {
+        m_resumePlaybackAfterInterruption = false;
+        return;
+    }
+    
     pauseInternal();
 }
 
@@ -4122,12 +4110,28 @@ bool HTMLMediaElement::potentiallyPlaying() const
     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
     // checks in couldPlayIfEnoughData().
     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
-    return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData() && !isBlockedOnMediaController();
+    
+    if (!pausedToBuffer && m_readyState < HAVE_FUTURE_DATA)
+        return false;
+
+    return couldPlayIfEnoughData() && !isBlockedOnMediaController();
 }
 
 bool HTMLMediaElement::couldPlayIfEnoughData() const
 {
-    return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
+    if (paused())
+        return false;
+
+    if (endedPlayback())
+        return false;
+
+    if (stoppedDueToErrors())
+        return false;
+
+    if (pausedForUserInteraction())
+        return false;
+
+    return true;
 }
 
 bool HTMLMediaElement::endedPlayback() const
@@ -4171,7 +4175,9 @@ bool HTMLMediaElement::stoppedDueToErrors() const
 
 bool HTMLMediaElement::pausedForUserInteraction() const
 {
-//    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
+    if (m_mediaSession->state() == MediaSession::Interrupted)
+        return true;
+
     return false;
 }
 
@@ -4558,7 +4564,7 @@ void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType noti
 {
     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
 #if PLATFORM(IOS)
-        userRequestsMediaLoading();
+        removeBehaviorsRestrictionsAfterFirstUserGesture();
 #endif
         togglePlayState();
         return;
@@ -5299,16 +5305,6 @@ AudioSourceProvider* HTMLMediaElement::audioSourceProvider()
 }
 #endif
 
-#if PLATFORM(IOS)
-void HTMLMediaElement::userRequestsMediaLoading()
-{
-    // The user is requesting data loading and/or playback, so remove the "only change playback in response
-    // to a user gesture" restriction on this movie.
-    m_userStartedPlayback = true;
-    m_restrictions = NoRestrictions;
-}
-#endif
-
 const String& HTMLMediaElement::mediaGroup() const
 {
     return m_mediaGroup;
@@ -5601,7 +5597,12 @@ bool HTMLMediaElement::mediaPlayerShouldWaitForResponseToAuthenticationChallenge
 
 void HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture()
 {
-    m_restrictions = NoRestrictions;
+    removeBehaviorRestriction(RequireUserGestureForLoadRestriction);
+    removeBehaviorRestriction(RequireUserGestureForRateChangeRestriction);
+    removeBehaviorRestriction(RequireUserGestureForFullscreenRestriction);
+#if ENABLE(IOS_AIRPLAY)
+    removeBehaviorRestriction(RequireUserGestureToShowPlaybackTargetPickerRestriction);
+#endif
 }
 
 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
@@ -5724,15 +5725,34 @@ unsigned long long HTMLMediaElement::fileSize() const
     return 0;
 }
 
-#if USE(AUDIO_SESSION)
-MediaSessionManager::MediaType HTMLMediaElement::mediaType() const
+MediaSession::MediaType HTMLMediaElement::mediaType() const
 {
     if (hasTagName(HTMLNames::videoTag))
-        return MediaSessionManager::Video;
+        return MediaSession::Video;
 
-    return MediaSessionManager::Audio;
+    return MediaSession::Audio;
+}
+
+void HTMLMediaElement::beginInterruption()
+{
+    LOG(Media, "HTMLMediaElement::beginInterruption");
+    
+    m_resumePlaybackAfterInterruption = !paused();
+    if (m_resumePlaybackAfterInterruption)
+        pause();
+}
+
+void HTMLMediaElement::endInterruption(MediaSession::EndInterruptionFlags flags)
+{
+    bool shouldResumePlayback = m_resumePlaybackAfterInterruption;
+    m_resumePlaybackAfterInterruption = false;
+
+    if (!flags & MediaSession::MayResumePlaying)
+        return;
+
+    if (shouldResumePlayback)
+        play();
 }
-#endif
 
 }
 
index f7d840d..4185ba5 100644 (file)
@@ -33,6 +33,7 @@
 #include "MediaCanStartListener.h"
 #include "MediaControllerInterface.h"
 #include "MediaPlayer.h"
+#include "MediaSession.h"
 
 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 #include "HTMLFrameOwnerElement.h"
@@ -53,9 +54,6 @@
 #include "MediaStream.h"
 #endif
 
-#if USE(AUDIO_SESSION)
-#include "MediaSessionManager.h"
-#endif
 
 namespace WebCore {
 
@@ -105,7 +103,7 @@ class HTMLMediaElement
 #else
     : public HTMLElement
 #endif
-    , private MediaPlayerClient, public MediaPlayerSupportsTypeClient, private MediaCanStartListener, public ActiveDOMObject, public MediaControllerInterface
+    , private MediaPlayerClient, public MediaPlayerSupportsTypeClient, private MediaCanStartListener, public ActiveDOMObject, public MediaControllerInterface , public MediaSessionClient
 #if ENABLE(VIDEO_TRACK)
     , private AudioTrackClient
     , private TextTrackClient
@@ -114,9 +112,6 @@ class HTMLMediaElement
 #if USE(PLATFORM_TEXT_TRACK_MENU)
     , public PlatformTextTrackMenuClient
 #endif
-#if USE(AUDIO_SESSION)
-    , public MediaSessionManagerClient
-#endif
 {
 public:
     MediaPlayer* player() const { return m_player.get(); }
@@ -481,6 +476,8 @@ protected:
 
     virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) OVERRIDE;
 
+    MediaSession& mediaSession() const { return *m_mediaSession; }
+
 private:
     void createMediaPlayer();
 
@@ -654,7 +651,6 @@ private:
 
 #if PLATFORM(IOS)
     bool parseMediaPlayerAttribute(const QualifiedName&, const AtomicString&);
-    void userRequestsMediaLoading();
 #endif
 
     // Pauses playback without changing any states or generating events
@@ -697,9 +693,10 @@ private:
     bool ensureMediaControlsInjectedScript();
 #endif
 
-#if USE(AUDIO_SESSION)
-    virtual MediaSessionManager::MediaType mediaType() const OVERRIDE;
-#endif
+    virtual MediaSession::MediaType mediaType() const OVERRIDE;
+
+    virtual void beginInterruption() OVERRIDE;
+    virtual void endInterruption(MediaSession::EndInterruptionFlags) OVERRIDE;
 
     Timer<HTMLMediaElement> m_loadTimer;
     Timer<HTMLMediaElement> m_progressEventTimer;
@@ -796,7 +793,6 @@ private:
     bool m_needWidgetUpdate : 1;
 #endif
 
-    bool m_loadInitiatedByUserGesture : 1;
     bool m_completelyLoaded : 1;
     bool m_havePreparedToPlay : 1;
     bool m_parsingInProgress : 1;
@@ -806,9 +802,10 @@ private:
 
 #if PLATFORM(IOS)
     bool m_requestingPlay : 1;
-    bool m_userStartedPlayback : 1;
 #endif
 
+    bool m_resumePlaybackAfterInterruption : 1;
+
 #if ENABLE(VIDEO_TRACK)
     bool m_tracksAreReady : 1;
     bool m_haveVisibleTextTrack : 1;
@@ -855,10 +852,7 @@ private:
     RefPtr<PlatformTextTrackMenuInterface> m_platformMenu;
 #endif
 
-#if USE(AUDIO_SESSION)
-    std::unique_ptr<MediaSessionManagerToken> m_mediaSessionManagerToken;
-#endif
-
+    std::unique_ptr<MediaSession> m_mediaSession;
     std::unique_ptr<PageActivityAssertionToken> m_activityToken;
     size_t m_reportedExtraMemoryCost;
 
diff --git a/Source/WebCore/platform/audio/MediaSession.cpp b/Source/WebCore/platform/audio/MediaSession.cpp
new file mode 100644 (file)
index 0000000..70f76d5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "config.h"
+#include "MediaSession.h"
+
+#include "HTMLMediaElement.h"
+#include "Logging.h"
+#include "MediaSessionManager.h"
+#include "Page.h"
+#include "ScriptController.h"
+
+namespace WebCore {
+
+std::unique_ptr<MediaSession> MediaSession::create(MediaSessionClient& client)
+{
+    return std::make_unique<MediaSession>(client);
+}
+
+MediaSession::MediaSession(MediaSessionClient& client)
+    : m_client(client)
+    , m_state(Running)
+{
+    m_type = m_client.mediaType();
+    ASSERT(m_type >= None && m_type <= WebAudio);
+    MediaSessionManager::sharedManager().addSession(*this);
+}
+
+MediaSession::~MediaSession()
+{
+    MediaSessionManager::sharedManager().removeSession(*this);
+}
+
+void MediaSession::beginInterruption()
+{
+    m_state = Interrupted;
+    m_client.beginInterruption();
+}
+
+void MediaSession::endInterruption(EndInterruptionFlags flags)
+{
+    m_state = Running;
+    m_client.endInterruption(flags);
+}
+
+}
diff --git a/Source/WebCore/platform/audio/MediaSession.h b/Source/WebCore/platform/audio/MediaSession.h
new file mode 100644 (file)
index 0000000..7460f4e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef MediaSession_h
+#define MediaSession_h
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class MediaSessionClient;
+class HTMLMediaElement;
+
+class MediaSession {
+public:
+    static std::unique_ptr<MediaSession> create(MediaSessionClient&);
+
+    MediaSession(MediaSessionClient&);
+    ~MediaSession();
+
+    enum MediaType {
+        None,
+        Video,
+        Audio,
+        WebAudio,
+    };
+    
+    MediaType mediaType() const { return m_type; }
+
+    enum State {
+        Running,
+        Interrupted,
+    };
+    State state() const { return m_state; }
+    void setState(State state) { m_state = state; }
+
+    enum EndInterruptionFlags {
+        NoFlags = 0,
+        MayResumePlaying = 1 << 0,
+    };
+    void beginInterruption();
+    void endInterruption(EndInterruptionFlags);
+
+private:
+    MediaSessionClient& m_client;
+    MediaType m_type;
+    State m_state;
+};
+
+class MediaSessionClient {
+    WTF_MAKE_NONCOPYABLE(MediaSessionClient);
+public:
+    MediaSessionClient() { }
+    
+    virtual MediaSession::MediaType mediaType() const = 0;
+    
+    virtual void beginInterruption() { }
+    virtual void endInterruption(MediaSession::EndInterruptionFlags) { }
+    
+protected:
+    virtual ~MediaSessionClient() { }
+};
+
+}
+
+#endif // MediaSession_h
index d2f6a15..40677bf 100644 (file)
 #include "config.h"
 #include "MediaSessionManager.h"
 
-using namespace WebCore;
+#include "MediaSession.h"
 
-
-std::unique_ptr<MediaSessionManagerToken> MediaSessionManagerToken::create(MediaSessionManagerClient& client)
-{
-    return std::make_unique<MediaSessionManagerToken>(client);
-}
-
-MediaSessionManagerToken::MediaSessionManagerToken(MediaSessionManagerClient& client)
-    : m_client(client)
-{
-    m_type = m_client.mediaType();
-    MediaSessionManager::sharedManager().addToken(*this);
-}
-
-MediaSessionManagerToken::~MediaSessionManagerToken()
-{
-    MediaSessionManager::sharedManager().removeToken(*this);
-}
+namespace WebCore {
 
 MediaSessionManager& MediaSessionManager::sharedManager()
 {
@@ -53,48 +37,69 @@ MediaSessionManager& MediaSessionManager::sharedManager()
 }
 
 MediaSessionManager::MediaSessionManager()
+    : m_interruptions(0)
 {
 }
 
-bool MediaSessionManager::has(MediaSessionManager::MediaType type) const
+bool MediaSessionManager::has(MediaSession::MediaType type) const
 {
-    ASSERT(type >= MediaSessionManager::None && type <= MediaSessionManager::WebAudio);
+    ASSERT(type >= MediaSession::None && type <= MediaSession::WebAudio);
 
-    for (auto it = m_tokens.begin(), end = m_tokens.end(); it != end; ++it) {
-        if ((*it)->mediaType() == type)
+    for (auto* session : m_sessions) {
+        if (session->mediaType() == type)
             return true;
     }
-    
+
     return false;
 }
 
-int MediaSessionManager::count(MediaSessionManager::MediaType type) const
+int MediaSessionManager::count(MediaSession::MediaType type) const
 {
-    ASSERT(type >= MediaSessionManager::None && type <= MediaSessionManager::WebAudio);
+    ASSERT(type >= MediaSession::None && type <= MediaSession::WebAudio);
     
     int count = 0;
-    for (auto it = m_tokens.begin(), end = m_tokens.end(); it != end; ++it) {
-        if ((*it)->mediaType() == type)
+    for (auto* session : m_sessions) {
+        if (session->mediaType() == type)
             ++count;
     }
-    
+
     return count;
 }
 
-void MediaSessionManager::addToken(MediaSessionManagerToken& token)
+void MediaSessionManager::beginInterruption()
 {
-    m_tokens.append(&token);
+    if (++m_interruptions > 1)
+        return;
+
+    for (auto* session : m_sessions)
+        session->beginInterruption();
+}
+
+void MediaSessionManager::endInterruption(MediaSession::EndInterruptionFlags flags)
+{
+    ASSERT(m_interruptions > 0);
+    if (--m_interruptions)
+        return;
+    
+    for (auto* session : m_sessions)
+        session->endInterruption(flags);
+}
+
+void MediaSessionManager::addSession(MediaSession& session)
+{
+    m_sessions.append(&session);
+    session.setState(m_interruptions ? MediaSession::Interrupted : MediaSession::Running);
     updateSessionState();
 }
 
-void MediaSessionManager::removeToken(MediaSessionManagerToken& token)
+void MediaSessionManager::removeSession(MediaSession& session)
 {
-    size_t index = m_tokens.find(&token);
+    size_t index = m_sessions.find(&session);
     ASSERT(index != notFound);
     if (index == notFound)
         return;
 
-    m_tokens.remove(index);
+    m_sessions.remove(index);
     updateSessionState();
 }
 
@@ -103,3 +108,5 @@ void MediaSessionManager::updateSessionState()
 {
 }
 #endif
+
+}
index 4437cf2..06d06e4 100644 (file)
 #ifndef MediaSessionManager_h
 #define MediaSessionManager_h
 
-#include <wtf/PassOwnPtr.h>
+#include "MediaSession.h"
+#include "Settings.h"
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
-class MediaSessionManagerToken;
+class HTMLMediaElement;
+class MediaSession;
 
 class MediaSessionManager {
 public:
     static MediaSessionManager& sharedManager();
 
-    enum MediaType {
-        None,
-        Video,
-        Audio,
-        WebAudio,
-    };
+    bool has(MediaSession::MediaType) const;
+    int count(MediaSession::MediaType) const;
 
-    bool has(MediaType) const;
-    int count(MediaType) const;
+    void beginInterruption();
+    void endInterruption(MediaSession::EndInterruptionFlags);
 
 protected:
-    friend class MediaSessionManagerToken;
-    void addToken(MediaSessionManagerToken&);
-    void removeToken(MediaSessionManagerToken&);
+    friend class MediaSession;
+    void addSession(MediaSession&);
+    void removeSession(MediaSession&);
 
 private:
     MediaSessionManager();
 
     void updateSessionState();
 
-    Vector<MediaSessionManagerToken*> m_tokens;
-};
-
-class MediaSessionManagerClient {
-    WTF_MAKE_NONCOPYABLE(MediaSessionManagerClient);
-public:
-    MediaSessionManagerClient() { }
-
-    virtual MediaSessionManager::MediaType mediaType() const = 0;
-
-protected:
-    virtual ~MediaSessionManagerClient() { }
-};
-
-class MediaSessionManagerToken {
-public:
-    static std::unique_ptr<MediaSessionManagerToken> create(MediaSessionManagerClient&);
-
-    MediaSessionManagerToken(MediaSessionManagerClient&);
-    ~MediaSessionManagerToken();
-
-    MediaSessionManager::MediaType mediaType() const { return m_type; }
-
-private:
-
-    MediaSessionManagerClient& m_client;
-    MediaSessionManager::MediaType m_type;
+    Vector<MediaSession*> m_sessions;
+    int m_interruptions;
 };
 
 }
index f651339..b0eda81 100644 (file)
@@ -83,7 +83,7 @@ AudioDestinationMac::AudioDestinationMac(AudioIOCallback& callback, float sample
     , m_renderBus(AudioBus::create(2, kBufferSize, false))
     , m_sampleRate(sampleRate)
     , m_isPlaying(false)
-    , m_mediaSessionManagerToken(MediaSessionManagerToken::create(*this))
+    , m_mediaSession(MediaSession::create(*this))
 {
     // Open and initialize DefaultOutputUnit
     AudioComponent comp;
index 4b028ae..99cab33 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "AudioBus.h"
 #include "AudioDestination.h"
-#include "MediaSessionManager.h"
+#include "MediaSession.h"
 #include <AudioUnit/AudioUnit.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/RefPtr.h>
@@ -40,7 +40,7 @@ namespace WebCore {
 
 // An AudioDestination using CoreAudio's default output AudioUnit
 
-class AudioDestinationMac : public AudioDestination, public MediaSessionManagerClient {
+class AudioDestinationMac : public AudioDestination, public MediaSessionClient {
 public:
     AudioDestinationMac(AudioIOCallback&, float sampleRate);
     virtual ~AudioDestinationMac();
@@ -59,7 +59,7 @@ private:
 
     OSStatus render(UInt32 numberOfFrames, AudioBufferList* ioData);
 
-    virtual MediaSessionManager::MediaType mediaType() const { return MediaSessionManager::WebAudio; }
+    virtual MediaSession::MediaType mediaType() const { return MediaSession::WebAudio; }
 
     AudioUnit m_outputUnit;
     AudioIOCallback& m_callback;
@@ -69,7 +69,7 @@ private:
     bool m_isPlaying;
 
 #if USE(AUDIO_SESSION)
-    std::unique_ptr<MediaSessionManagerToken> m_mediaSessionManagerToken;
+    std::unique_ptr<MediaSession> m_mediaSession;
 #endif
 };
 
index ef2dd57..da082a6 100644 (file)
@@ -42,14 +42,14 @@ static const size_t kLowPowerVideoBufferSize = 4096;
 
 void MediaSessionManager::updateSessionState()
 {
-    LOG(Media, "MediaSessionManager::updateSessionState() - types: Video(%d), Audio(%d), WebAudio(%d)", count(Video), count(Audio), count(WebAudio));
+    LOG(Media, "MediaSessionManager::updateSessionState() - types: Video(%d), Audio(%d), WebAudio(%d)", count(MediaSession::Video), count(MediaSession::Audio), count(MediaSession::WebAudio));
 
-    if (has(WebAudio))
+    if (has(MediaSession::WebAudio))
         AudioSession::sharedSession().setPreferredBufferSize(kWebAudioBufferSize);
     // FIXME: <http://webkit.org/b/116725> Figure out why enabling the code below
     // causes media LayoutTests to fail on 10.8.
 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-    else if ((has(Video) || has(Audio)) && Settings::lowPowerVideoAudioBufferSizeEnabled())
+    else if ((has(MediaSession::Video) || has(MediaSession::Audio)) && Settings::lowPowerVideoAudioBufferSizeEnabled())
         AudioSession::sharedSession().setPreferredBufferSize(kLowPowerVideoBufferSize);
 #endif
 }
index a796e8f..38539ee 100644 (file)
@@ -70,6 +70,7 @@
 #include "MainFrame.h"
 #include "MallocStatistics.h"
 #include "MediaPlayer.h"
+#include "MediaSessionManager.h"
 #include "MemoryCache.h"
 #include "MemoryInfo.h"
 #include "Page.h"
@@ -2271,4 +2272,19 @@ void Internals::initializeMockMediaSource()
 }
 #endif
 
+void Internals::beginMediaSessionInterruption()
+{
+    MediaSessionManager::sharedManager().beginInterruption();
+}
+
+void Internals::endMediaSessionInterruption(const String& flagsString)
+{
+    MediaSession::EndInterruptionFlags flags = MediaSession::NoFlags;
+
+    if (equalIgnoringCase(flagsString, "MayResumePlaying"))
+        flags = MediaSession::MayResumePlaying;
+    
+    MediaSessionManager::sharedManager().endInterruption(flags);
+}
+
 }
index 10925ef..6ab64e8 100644 (file)
@@ -332,6 +332,9 @@ public:
     void initializeMockMediaSource();
 #endif
 
+    void beginMediaSessionInterruption();
+    void endMediaSessionInterruption(const String&);
+
 private:
     explicit Internals(Document*);
     Document* contextDocument() const;
index 07693b4..1c0f9d4 100644 (file)
     [RaisesException] ClientRect selectionBounds();
     
     [Conditional=MEDIA_SOURCE] void initializeMockMediaSource();
+
+    void beginMediaSessionInterruption();
+    void endMediaSessionInterruption(DOMString flags);
 };
index b1c39d7..fb4ad95 100644 (file)
@@ -38,6 +38,7 @@ set(WebKit_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/page/scrolling"
     "${WEBCORE_DIR}/platform"
     "${WEBCORE_DIR}/platform/animation"
+    "${WEBCORE_DIR}/platform/audio"
     "${WEBCORE_DIR}/platform/graphics"
     "${WEBCORE_DIR}/platform/graphics/filters"
     "${WEBCORE_DIR}/platform/graphics/harfbuzz"
index 8fb0fc8..c90616e 100644 (file)
@@ -1,3 +1,12 @@
+2014-01-07  Eric Carlson  <eric.carlson@apple.com>
+
+        Teach MediaSessionManager to manage interruptions
+        https://bugs.webkit.org/show_bug.cgi?id=126530
+
+        Reviewed by Sam Weinig.
+
+        * CMakeLists.txt: Add ${WEBCORE_DIR}/platform/animation to WebCore include directories.
+
 2014-01-06  Martin Robinson  <mrobinson@igalia.com>
 
         Small build fix for the GTK+ CMake port
index 9369b42..2a78124 100644 (file)
@@ -93,6 +93,7 @@ set(WebKit2_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/page/scrolling/coordinatedgraphics"
     "${WEBCORE_DIR}/platform"
     "${WEBCORE_DIR}/platform/animation"
+    "${WEBCORE_DIR}/platform/audio"
     "${WEBCORE_DIR}/platform/graphics"
     "${WEBCORE_DIR}/platform/graphics/filters"
     "${WEBCORE_DIR}/platform/graphics/harfbuzz"
index ea2e7bd..55ba879 100644 (file)
@@ -1,3 +1,12 @@
+2014-01-07  Eric Carlson  <eric.carlson@apple.com>
+
+        Teach MediaSessionManager to manage interruptions
+        https://bugs.webkit.org/show_bug.cgi?id=126530
+
+        Reviewed by Sam Weinig.
+
+        * CMakeLists.txt: Add ${WEBCORE_DIR}/platform/animation to WebCore include directories.
+
 2014-01-07  Jinwoo Song  <jinwoo7.song@samsung.com>
 
         [EFL][WK2] Fix failing ewk_view_page_contents_get() API test