Skip to content

Commit a5482e6

Browse files
committed
Add experimental support for AudioSession Web API
https://bugs.webkit.org/show_bug.cgi?id=248811 rdar://problem/103019883 Reviewed by Eric Carlson. Add experimental support for a Web API to better control AudioSession states, in particular category and interruptions. Covered by added tests. * LayoutTests/fast/dom/navigator-detached-no-crash-expected.txt: * LayoutTests/media/audioSession/audioSessionState-expected.txt: Added. * LayoutTests/media/audioSession/audioSessionState.html: Added. * LayoutTests/media/audioSession/audioSessionType-expected.txt: Added. * LayoutTests/media/audioSession/audioSessionType.html: Added. * LayoutTests/media/audioSession/getUserMedia-expected.txt: Added. * LayoutTests/media/audioSession/getUserMedia.html: Added. * LayoutTests/platform/glib/TestExpectations: * LayoutTests/platform/mac-wk1/TestExpectations: * LayoutTests/platform/mac-wk1/fast/dom/navigator-detached-no-crash-expected.txt: * LayoutTests/platform/mac-wk2/fast/dom/navigator-detached-no-crash-expected.txt: * Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml: * Source/WTF/wtf/PlatformEnableCocoa.h: * Source/WebCore/DerivedSources-input.xcfilelist: * Source/WebCore/DerivedSources-output.xcfilelist: * Source/WebCore/DerivedSources.make: * Source/WebCore/Modules/audiosession/DOMAudioSession.cpp: Added. (WebCore::fromDOMAudioSessionType): (WebCore::DOMAudioSession::create): (WebCore::DOMAudioSession::DOMAudioSession): (WebCore::DOMAudioSession::~DOMAudioSession): (WebCore::DOMAudioSession::setType): (WebCore::DOMAudioSession::type const): (WebCore::DOMAudioSession::state const): (WebCore::DOMAudioSession::stop): (WebCore::DOMAudioSession::activeDOMObjectName const): (WebCore::DOMAudioSession::virtualHasPendingActivity const): (WebCore::DOMAudioSession::beginAudioSessionInterruption): (WebCore::DOMAudioSession::endAudioSessionInterruption): (WebCore::DOMAudioSession::activeStateChanged): (WebCore::DOMAudioSession::scheduleStateChangeEvent): * Source/WebCore/Modules/audiosession/DOMAudioSession.h: Added. * Source/WebCore/Modules/audiosession/DOMAudioSession.idl: Added. * Source/WebCore/Modules/audiosession/Navigator+AudioSession.idl: Added. * Source/WebCore/Modules/audiosession/NavigatorAudioSession.cpp: Added. (WebCore::NavigatorAudioSession::NavigatorAudioSession): (WebCore::NavigatorAudioSession::audioSession): (WebCore::NavigatorAudioSession::from): (WebCore::NavigatorAudioSession::supplementName): * Source/WebCore/Modules/audiosession/NavigatorAudioSession.h: Added. * Source/WebCore/Modules/mediastream/MediaDevices.cpp: (WebCore::MediaDevices::getUserMedia): * Source/WebCore/Modules/mediastream/UserMediaRequest.cpp: (WebCore::UserMediaRequest::allow): * Source/WebCore/Sources.txt: * Source/WebCore/WebCore.xcodeproj/project.pbxproj: * Source/WebCore/bindings/js/WebCoreBuiltinNames.h: * Source/WebCore/dom/ActiveDOMObject.cpp: (WebCore::ActiveDOMObject::queueTaskToDispatchEventInternal): * Source/WebCore/dom/EventTargetFactory.in: * Source/WebCore/platform/audio/AudioSession.cpp: (WebCore::AudioSession::tryToSetActive): (WebCore::AudioSession::activeStateChanged): * Source/WebCore/platform/audio/AudioSession.h: * Source/WebCore/testing/Internals.cpp: (WebCore::Internals::resetToConsistentState): * Source/WebKit/WebProcess/GPU/media/RemoteAudioSession.cpp: (WebKit::RemoteAudioSession::configurationChanged): Canonical link: https://commits.webkit.org/257552@main
1 parent b5f2a68 commit a5482e6

35 files changed

+700
-5
lines changed

LayoutTests/fast/dom/navigator-detached-no-crash-expected.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This tests that the navigator object of a deleted frame is disconnected properly
55
navigator.appCodeName is OK
66
navigator.appName is OK
77
navigator.appVersion is OK
8+
navigator.audioSession is OK
89
navigator.clipboard is OK
910
navigator.contacts is OK
1011
navigator.cookieEnabled is OK
@@ -34,6 +35,7 @@ navigator.xr is OK
3435
navigator.appCodeName is OK
3536
navigator.appName is OK
3637
navigator.appVersion is OK
38+
navigator.audioSession is OK
3739
navigator.clipboard is OK
3840
navigator.contacts is OK
3941
navigator.cookieEnabled is OK
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
PASS AudioSession and interruption
3+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<script src="../../resources/testharness.js"></script>
6+
<script src="../../resources/testharnessreport.js"></script>
7+
<script src="../media-file.js"></script>
8+
<script src="../video-test.js"></script>
9+
</head>
10+
<body>
11+
<audio id="audio"></audio>
12+
<script>
13+
function waitForStateChange()
14+
{
15+
return new Promise((resolve, reject) => {
16+
navigator.audioSession.onstatechange = () => resolve(navigator.audioSession.state);
17+
setTimeout(() => reject("no audio session state change"), 3000);
18+
});
19+
}
20+
21+
promise_test(async (test) => {
22+
assert_equals(navigator.audioSession.type, "auto");
23+
assert_equals(navigator.audioSession.state, "inactive");
24+
25+
let statePromise = waitForStateChange();
26+
27+
audio.src = findMediaFile("audio", "../content/test");
28+
await audio.play();
29+
30+
assert_equals(await statePromise, "active");
31+
32+
if (!window.internals)
33+
return;
34+
35+
statePromise = waitForStateChange();
36+
internals.beginAudioSessionInterruption();
37+
assert_equals(await statePromise, "interrupted");
38+
39+
statePromise = waitForStateChange();
40+
internals.endAudioSessionInterruption();
41+
assert_equals(await statePromise, "active");
42+
}, "AudioSession and interruption");
43+
</script>
44+
</body>
45+
</html>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
PASS AudioSession type
3+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<script src="../../resources/testharness.js"></script>
6+
<script src="../../resources/testharnessreport.js"></script>
7+
<script src="../media-file.js"></script>
8+
<script src="../video-test.js"></script>
9+
</head>
10+
<body>
11+
<audio id="audio"></audio>
12+
<script>
13+
promise_test(async (test) => {
14+
assert_equals(navigator.audioSession.type, "auto");
15+
16+
if (!window.internals)
17+
return;
18+
19+
audio.src = findMediaFile("audio", "../content/test");
20+
await audio.play();
21+
22+
23+
assert_equals(navigator.audioSession.type, "auto");
24+
assert_equals(internals.audioSessionCategory(), "MediaPlayback");
25+
26+
navigator.audioSession.type = "ambient";
27+
assert_equals(internals.audioSessionCategory(), "AmbientSound");
28+
29+
navigator.audioSession.type = "playback";
30+
assert_equals(internals.audioSessionCategory(), "MediaPlayback");
31+
32+
navigator.audioSession.type = "transient";
33+
assert_equals(internals.audioSessionCategory(), "AmbientSound");
34+
35+
navigator.audioSession.type = "play-and-record";
36+
assert_equals(internals.audioSessionCategory(), "PlayAndRecord");
37+
38+
navigator.audioSession.type = "transient-solo";
39+
assert_equals(internals.audioSessionCategory(), "SoloAmbientSound");
40+
41+
navigator.audioSession.type = "auto";
42+
await new Promise(resolve => setTimeout(resolve, 50));
43+
assert_equals(internals.audioSessionCategory(), "MediaPlayback");
44+
}, "AudioSession type");
45+
</script>
46+
</body>
47+
</html>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
PASS getUserMedia and AudioSession type
3+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<script src="../../resources/testharness.js"></script>
6+
<script src="../../resources/testharnessreport.js"></script>
7+
</head>
8+
<body>
9+
<script>
10+
function waitForStateChange()
11+
{
12+
return new Promise((resolve, reject) => {
13+
navigator.audioSession.onstatechange = () => resolve(navigator.audioSession.state);
14+
setTimeout(() => reject("no audio session state change, current audio session state is " + navigator.audioSession.state), 3000);
15+
});
16+
}
17+
18+
promise_test(async (test) => {
19+
assert_equals(navigator.audioSession.type, "auto");
20+
assert_equals(navigator.audioSession.state, "inactive");
21+
22+
let statePromise = waitForStateChange();
23+
24+
let localStream = await navigator.mediaDevices.getUserMedia({audio:true});
25+
localStream.getTracks().forEach(track => track.stop());
26+
27+
assert_equals(await statePromise, "active");
28+
29+
navigator.audioSession.type = "playback";
30+
await navigator.mediaDevices.getUserMedia({audio:true}).then(assert_unreached, () => { });
31+
// Let's verify camera capture work even if audioSession type is playback.
32+
localStream = await navigator.mediaDevices.getUserMedia({video:true});
33+
localStream.getTracks().forEach(track => track.stop());
34+
35+
navigator.audioSession.type = "play-and-record";
36+
localStream = await navigator.mediaDevices.getUserMedia({audio:true});
37+
localStream.getTracks().forEach(track => track.stop());
38+
}, "getUserMedia and AudioSession type");
39+
</script>
40+
</body>
41+
</html>

LayoutTests/platform/glib/TestExpectations

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,17 @@ webkit.org/b/233796 imported/w3c/web-platform-tests/html/browsers/browsing-the-w
12231223
# End of SOUP and Networking-related bugs
12241224
#////////////////////////////////////////////////////////////////////////////////////////
12251225

1226+
#////////////////////////////////////////////////////////////////////////////////////////
1227+
# Media-related bugs
1228+
#////////////////////////////////////////////////////////////////////////////////////////
1229+
1230+
media/audioSession [ Skip ]
1231+
1232+
#////////////////////////////////////////////////////////////////////////////////////////
1233+
# End of Media-related bugs
1234+
#////////////////////////////////////////////////////////////////////////////////////////
1235+
1236+
12261237
#////////////////////////////////////////////////////////////////////////////////////////
12271238
# Streams-related bugs
12281239
#////////////////////////////////////////////////////////////////////////////////////////

LayoutTests/platform/mac-wk1/TestExpectations

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ css-dark-mode [ Skip ]
5959
model-element [ Skip ]
6060
http/tests/model [ Skip ]
6161

62+
media/audioSession [ Skip ]
63+
6264
# Media Stream API testing is not supported for WK1 yet.
6365
fast/mediastream
6466
imported/w3c/web-platform-tests/mediacapture-streams

LayoutTests/platform/mac-wk1/fast/dom/navigator-detached-no-crash-expected.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ This tests that the navigator object of a deleted frame is disconnected properly
33
navigator.appCodeName is OK
44
navigator.appName is OK
55
navigator.appVersion is OK
6+
navigator.audioSession is OK
67
navigator.cookieEnabled is OK
78
navigator.getStorageUpdates() is OK
89
navigator.hardwareConcurrency is OK
@@ -33,6 +34,7 @@ navigator.xr is OK
3334
navigator.appCodeName is OK
3435
navigator.appName is OK
3536
navigator.appVersion is OK
37+
navigator.audioSession is OK
3638
navigator.cookieEnabled is OK
3739
navigator.getStorageUpdates() is OK
3840
navigator.hardwareConcurrency is OK

0 commit comments

Comments
 (0)