[iOS] Video occasionally mixes with other system audio instead of interrupting
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 9 Jun 2017 17:57:06 +0000 (17:57 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 9 Jun 2017 17:57:06 +0000 (17:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173127

Reviewed by Eric Carlson.

Source/WebCore:

Tests: platform/mac/audio-session-category-video-track-change.html

When an HTMLMediaElement's tracks change their enabled state, make sure to update
the PlatformMediaElement, for canProduceAudio() may have changed.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged):
* platform/audio/cocoa/MediaSessionManagerCocoa.cpp:
(PlatformMediaSessionManager::updateSessionState):

The rest of the changes in this revision are to allow the above to be testable.

* page/Settings.cpp:
* page/Settings.h:
* platform/audio/AudioSession.h:
* platform/audio/mac/AudioSessionMac.cpp:
(WebCore::AudioSession::category):
(WebCore::AudioSession::setCategory):
* testing/InternalSettings.cpp:
(WebCore::InternalSettings::Backup::Backup):
(WebCore::InternalSettings::Backup::restoreTo):
(WebCore::InternalSettings::setShouldManageAudioSessionCategory):
* testing/InternalSettings.h:
* testing/InternalSettings.idl:
* testing/Internals.cpp:
(WebCore::Internals::audioSessionCategory):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* platform/mac/media/audio-session-category-video-track-change-expected.txt: Added.
* platform/mac/media/audio-session-category-video-track-change.html: Added.

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/media/audio-session-category-video-track-change-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/media/audio-session-category-video-track-change.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/page/Settings.cpp
Source/WebCore/page/Settings.h
Source/WebCore/platform/audio/AudioSession.h
Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.cpp
Source/WebCore/platform/audio/mac/AudioSessionMac.cpp
Source/WebCore/testing/InternalSettings.cpp
Source/WebCore/testing/InternalSettings.h
Source/WebCore/testing/InternalSettings.idl
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl

index 258eff0..556d036 100644 (file)
@@ -1,3 +1,13 @@
+2017-06-09  Jer Noble  <jer.noble@apple.com>
+
+        [iOS] Video occasionally mixes with other system audio instead of interrupting
+        https://bugs.webkit.org/show_bug.cgi?id=173127
+
+        Reviewed by Eric Carlson.
+
+        * platform/mac/media/audio-session-category-video-track-change-expected.txt: Added.
+        * platform/mac/media/audio-session-category-video-track-change.html: Added.
+
 2017-06-09  Chris Dumez  <cdumez@apple.com>
 
         CSS transitions added while page is not visible do not start when the page becomes visible
diff --git a/LayoutTests/platform/mac/media/audio-session-category-video-track-change-expected.txt b/LayoutTests/platform/mac/media/audio-session-category-video-track-change-expected.txt
new file mode 100644 (file)
index 0000000..ca12a81
--- /dev/null
@@ -0,0 +1,19 @@
+
+RUN(internals.settings.setShouldManageAudioSessionCategory(true))
+RUN(video.src = findMediaFile("video", "../../../media/content/test"))
+EVENT(canplay)
+EXPECTED (internals.audioSessionCategory() == 'None') OK
+RUN(video.audioTracks[0].enabled = false)
+EVENT(change)
+EXPECTED (internals.audioSessionCategory() == 'None') OK
+RUN(video.muted = false)
+EVENT(volumechange)
+EXPECTED (internals.audioSessionCategory() == 'None') OK
+RUN(video.play())
+EVENT(playing)
+EXPECTED (internals.audioSessionCategory() == 'None') OK
+RUN(video.audioTracks[0].enabled = true)
+EVENT(change)
+EXPECTED (internals.audioSessionCategory() == 'MediaPlayback') OK
+END OF TEST
+
diff --git a/LayoutTests/platform/mac/media/audio-session-category-video-track-change.html b/LayoutTests/platform/mac/media/audio-session-category-video-track-change.html
new file mode 100644 (file)
index 0000000..9112290
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>audio-session-category-track-change</title>
+    <script src="../../../media/video-test.js"></script>
+    <script src="../../../media/media-file.js"></script>
+    <script>
+    function go() {
+        findMediaElement();
+        run('internals.settings.setShouldManageAudioSessionCategory(true)');
+        run('video.src = findMediaFile("video", "../../../media/content/test")');
+        waitForEvent('canplay', canplay);
+    }
+
+    function canplay() {
+        testExpected('internals.audioSessionCategory()', 'None');
+        run('video.audioTracks[0].enabled = false');
+        waitForEventOnceOn(video.audioTracks, 'change', trackDisabled);
+    }
+
+    function trackDisabled() {
+        testExpected('internals.audioSessionCategory()', 'None');
+        run('video.muted = false');
+        waitForEvent('volumechange', volumechange);
+    }
+
+    function volumechange() {
+        testExpected('internals.audioSessionCategory()', 'None');
+        run('video.play()');
+        waitForEvent('playing', playing);
+    }
+
+    function playing() {
+        testExpected('internals.audioSessionCategory()', 'None');
+        run('video.audioTracks[0].enabled = true');
+        waitForEventOnceOn(video.audioTracks, 'change', trackEnabled);
+    }
+
+    function trackEnabled() {
+        testExpected('internals.audioSessionCategory()', 'MediaPlayback');
+        endTest();
+    }
+    </script>
+</head>
+<body onload="go()">
+    <video controls muted></video>
+</body>
+</html>
\ No newline at end of file
index 706e1eb..669f4a4 100644 (file)
@@ -1,3 +1,39 @@
+2017-06-09  Jer Noble  <jer.noble@apple.com>
+
+        [iOS] Video occasionally mixes with other system audio instead of interrupting
+        https://bugs.webkit.org/show_bug.cgi?id=173127
+
+        Reviewed by Eric Carlson.
+
+        Tests: platform/mac/audio-session-category-video-track-change.html
+
+        When an HTMLMediaElement's tracks change their enabled state, make sure to update
+        the PlatformMediaElement, for canProduceAudio() may have changed. 
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged):
+        * platform/audio/cocoa/MediaSessionManagerCocoa.cpp:
+        (PlatformMediaSessionManager::updateSessionState):
+
+        The rest of the changes in this revision are to allow the above to be testable.
+
+        * page/Settings.cpp:
+        * page/Settings.h:
+        * platform/audio/AudioSession.h:
+        * platform/audio/mac/AudioSessionMac.cpp:
+        (WebCore::AudioSession::category):
+        (WebCore::AudioSession::setCategory):
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::Backup::Backup):
+        (WebCore::InternalSettings::Backup::restoreTo):
+        (WebCore::InternalSettings::setShouldManageAudioSessionCategory):
+        * testing/InternalSettings.h:
+        * testing/InternalSettings.idl:
+        * testing/Internals.cpp:
+        (WebCore::Internals::audioSessionCategory):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-06-09  Chris Dumez  <cdumez@apple.com>
 
         CSS transitions added while page is not visible do not start when the page becomes visible
index c6c914f..7bdb91c 100644 (file)
@@ -4770,6 +4770,8 @@ void HTMLMediaElement::mediaPlayerCharacteristicChanged(MediaPlayer*)
     m_hasEverHadAudio |= hasAudio();
     m_hasEverHadVideo |= hasVideo();
 
+    m_mediaSession->canProduceAudioChanged();
+
     endProcessingMediaPlayerCallback();
 }
 
index 562d575..668f2c1 100644 (file)
@@ -113,8 +113,8 @@ bool Settings::gAllowsAnySSLCertificate = false;
 bool Settings::gNetworkDataUsageTrackingEnabled = false;
 bool Settings::gAVKitEnabled = false;
 bool Settings::gShouldOptOutOfNetworkStateObservation = false;
-bool Settings::gManageAudioSession = false;
 #endif
+bool Settings::gManageAudioSession = false;
 
 // NOTEs
 //  1) EditingMacBehavior comprises Tiger, Leopard, SnowLeopard and iOS builds, as well as QtWebKit when built on Mac;
index b9d3e73..d8f0940 100644 (file)
@@ -291,7 +291,9 @@ public:
 
     static void setShouldOptOutOfNetworkStateObservation(bool flag) { gShouldOptOutOfNetworkStateObservation = flag; }
     static bool shouldOptOutOfNetworkStateObservation() { return gShouldOptOutOfNetworkStateObservation; }
+#endif
 
+#if USE(AUDIO_SESSION)
     static void setShouldManageAudioSessionCategory(bool flag) { gManageAudioSession = flag; }
     static bool shouldManageAudioSessionCategory() { return gManageAudioSession; }
 #endif
@@ -409,8 +411,8 @@ private:
     static bool gNetworkDataUsageTrackingEnabled;
     WEBCORE_EXPORT static bool gAVKitEnabled;
     WEBCORE_EXPORT static bool gShouldOptOutOfNetworkStateObservation;
-    WEBCORE_EXPORT static bool gManageAudioSession;
 #endif
+    WEBCORE_EXPORT static bool gManageAudioSession;
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     String m_mediaKeysStorageDirectory;
index aa64dc3..65a4d70 100644 (file)
@@ -54,7 +54,7 @@ public:
         AudioProcessing,
     };
     WEBCORE_EXPORT void setCategory(CategoryType);
-    CategoryType category() const;
+    WEBCORE_EXPORT CategoryType category() const;
 
     void setCategoryOverride(CategoryType);
     CategoryType categoryOverride() const;
index ae6d4d6..e4b9193 100644 (file)
@@ -57,16 +57,15 @@ void PlatformMediaSessionManager::updateSessionState()
         AudioSession::sharedSession().setPreferredBufferSize(bufferSize);
     }
 
-#if PLATFORM(IOS)
     if (!Settings::shouldManageAudioSessionCategory())
         return;
 
-    bool hasAudioMediaType = false;
+    bool hasWebAudioType = false;
     bool hasAudibleAudioOrVideoMediaType = false;
-    bool hasAudioCapture = anyOfSessions([this, &hasAudioMediaType, &hasAudibleAudioOrVideoMediaType] (PlatformMediaSession& session, size_t) mutable {
+    bool hasAudioCapture = anyOfSessions([this, &hasWebAudioType, &hasAudibleAudioOrVideoMediaType] (PlatformMediaSession& session, size_t) mutable {
         auto type = session.mediaType();
-        if (type == PlatformMediaSession::VideoAudio || type == PlatformMediaSession::Audio || type == PlatformMediaSession::WebAudio)
-            hasAudioMediaType = true;
+        if (type == PlatformMediaSession::WebAudio)
+            hasWebAudioType = true;
         if ((type == PlatformMediaSession::VideoAudio || type == PlatformMediaSession::Audio) && session.canProduceAudio())
             hasAudibleAudioOrVideoMediaType = true;
         return (type == PlatformMediaSession::MediaStreamCapturingAudio);
@@ -76,11 +75,10 @@ void PlatformMediaSessionManager::updateSessionState()
         AudioSession::sharedSession().setCategory(AudioSession::PlayAndRecord);
     else if (hasAudibleAudioOrVideoMediaType)
         AudioSession::sharedSession().setCategory(AudioSession::MediaPlayback);
-    else if (hasAudioMediaType)
+    else if (hasWebAudioType)
         AudioSession::sharedSession().setCategory(AudioSession::AmbientSound);
     else
         AudioSession::sharedSession().setCategory(AudioSession::None);
-#endif
 }
 
 #endif // USE(AUDIO_SESSION)
index 0cb71c3..d0a5e83 100644 (file)
@@ -56,6 +56,7 @@ public:
     AudioSessionPrivate(bool mutedState)
         : lastMutedState(mutedState) { }
     bool lastMutedState;
+    AudioSession::CategoryType category { AudioSession::None };
 };
 
 AudioSession::AudioSession()
@@ -69,13 +70,12 @@ AudioSession::~AudioSession()
 
 AudioSession::CategoryType AudioSession::category() const
 {
-    notImplemented();
-    return None;
+    return m_private->category;
 }
 
-void AudioSession::setCategory(CategoryType)
+void AudioSession::setCategory(CategoryType category)
 {
-    notImplemented();
+    m_private->category = category;
 }
 
 AudioSession::CategoryType AudioSession::categoryOverride() const
index c9fcab9..74b2713 100644 (file)
@@ -111,6 +111,9 @@ InternalSettings::Backup::Backup(Settings& settings)
     , m_webGPUEnabled(RuntimeEnabledFeatures::sharedFeatures().webGPUEnabled())
 #endif
     , m_shouldMockBoldSystemFontForAccessibility(RenderTheme::singleton().shouldMockBoldSystemFontForAccessibility())
+#if USE(AUDIO_SESSION)
+    , m_shouldManageAudioSessionCategory(Settings::shouldManageAudioSessionCategory())
+#endif
 {
 }
 
@@ -201,6 +204,10 @@ void InternalSettings::Backup::restoreTo(Settings& settings)
 #if ENABLE(WEBGPU)
     RuntimeEnabledFeatures::sharedFeatures().setWebGPUEnabled(m_webGPUEnabled);
 #endif
+
+#if USE(AUDIO_SESSION)
+    Settings::setShouldManageAudioSessionCategory(m_shouldManageAudioSessionCategory);
+#endif
 }
 
 class InternalSettingsWrapper : public Supplement<Page> {
@@ -804,6 +811,16 @@ ExceptionOr<void> InternalSettings::setDeferredCSSParserEnabled(bool enabled)
     return { };
 }
 
+ExceptionOr<void> InternalSettings::setShouldManageAudioSessionCategory(bool should)
+{
+#if USE(AUDIO_SESSION)
+    Settings::setShouldManageAudioSessionCategory(should);
+    return { };
+#else
+    return Exception { INVALID_ACCESS_ERR };
+#endif
+}
+
 static InternalSettings::ForcedAccessibilityValue settingsToInternalSettingsValue(Settings::ForcedAccessibilityValue value)
 {
     switch (value) {
index 0fe1615..b9947b7 100644 (file)
@@ -96,6 +96,7 @@ public:
     ExceptionOr<String> systemLayoutDirection();
     ExceptionOr<void> setSystemLayoutDirection(const String&);
     ExceptionOr<void> setShouldMockBoldSystemFontForAccessibility(bool);
+    ExceptionOr<void> setShouldManageAudioSessionCategory(bool);
     
     static void setAllowsAnySSLCertificate(bool);
 
@@ -194,6 +195,9 @@ private:
         bool m_webGPUEnabled;
         
         bool m_shouldMockBoldSystemFontForAccessibility;
+#if USE(AUDIO_SESSION)
+        bool m_shouldManageAudioSessionCategory;
+#endif
     };
 
     Page* m_page;
index 6d28cc1..83176db 100644 (file)
@@ -101,5 +101,7 @@ enum ForcedAccessibilityValue { "system", "on", "off" };
     attribute ForcedAccessibilityValue forcedColorsAreInvertedAccessibilityValue;
     attribute ForcedAccessibilityValue forcedDisplayIsMonochromeAccessibilityValue;
     attribute ForcedAccessibilityValue forcedPrefersReducedMotionAccessibilityValue;
+
+    [MayThrowException] void setShouldManageAudioSessionCategory(boolean should);
 };
 
index 7d1c8a1..0de12be 100644 (file)
@@ -30,6 +30,7 @@
 #include "AXObjectCache.h"
 #include "ActiveDOMCallbackMicrotask.h"
 #include "ApplicationCacheStorage.h"
+#include "AudioSession.h"
 #include "Autofill.h"
 #include "BackForwardController.h"
 #include "BitmapImage.h"
@@ -4100,4 +4101,27 @@ void Internals::removeMediaStreamTrack(MediaStream& stream, MediaStreamTrack& tr
 
 #endif
 
+String Internals::audioSessionCategory() const
+{
+#if USE(AUDIO_SESSION)
+    switch (AudioSession::sharedSession().category()) {
+    case AudioSession::AmbientSound:
+        return ASCIILiteral("AmbientSound");
+    case AudioSession::SoloAmbientSound:
+        return ASCIILiteral("SoloAmbientSound");
+    case AudioSession::MediaPlayback:
+        return ASCIILiteral("MediaPlayback");
+    case AudioSession::RecordAudio:
+        return ASCIILiteral("RecordAudio");
+    case AudioSession::PlayAndRecord:
+        return ASCIILiteral("PlayAndRecord");
+    case AudioSession::AudioProcessing:
+        return ASCIILiteral("AudioProcessing");
+    case AudioSession::None:
+        return ASCIILiteral("None");
+    }
+#endif
+    return emptyString();
+}
+
 } // namespace WebCore
index f82dbf1..a5cb515 100644 (file)
@@ -589,6 +589,8 @@ public:
     void removeMediaStreamTrack(MediaStream&, MediaStreamTrack&);
 #endif
 
+    String audioSessionCategory() const;
+
 private:
     explicit Internals(Document&);
     Document* contextDocument() const;
index 7f866ed..dc2d119 100644 (file)
@@ -545,4 +545,6 @@ enum EventThrottlingBehavior {
     [Conditional=MEDIA_STREAM] void delayMediaStreamTrackSamples(MediaStreamTrack track, float delay);
     [Conditional=MEDIA_STREAM] void setMediaStreamTrackMuted(MediaStreamTrack track, boolean muted);
     [Conditional=MEDIA_STREAM] void removeMediaStreamTrack(MediaStream stream, MediaStreamTrack track);
+
+    DOMString audioSessionCategory();
 };