Skip to content

Commit

Permalink
[ macOS wk2 debug ] fast/mediastream/device-change-event-2.html is a …
Browse files Browse the repository at this point in the history
…flaky failure.

https://bugs.webkit.org/show_bug.cgi?id=261356
rdar://115192271

Reviewed by Jean-Yves Avenard.

We never implemented focus restrictions. The spec has been updated to use inview/visibility restrictions.
We align the implementation and the test with the spec.

* LayoutTests/fast/mediastream/device-change-event-2-expected.txt:
* LayoutTests/fast/mediastream/device-change-event-2.html:
* LayoutTests/platform/ios/TestExpectations:
* Source/WebCore/Modules/mediastream/MediaDevices.cpp:
(WebCore::MediaDevices::scheduledEventTimerFired):

Canonical link: https://commits.webkit.org/270702@main
  • Loading branch information
youennf committed Nov 14, 2023
1 parent 9b5dc3c commit 2d5fd91
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ CONSOLE MESSAGE: A MediaStreamTrack ended due to a capture failure

PASS 'devicechange' event fired when device list changes
PASS 'devicechange' events fired quickly are coalesced
PASS 'devicechange' event is not fired when the document doesn't has focus or permission to capture
PASS 'devicechange' event is fired when the document doesn't has focus but has permission to capture
PASS 'devicechange' event is not fired when the document is not visible

78 changes: 19 additions & 59 deletions LayoutTests/fast/mediastream/device-change-event-2.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,71 +113,31 @@

promise_test(async (test) => {
await setup(test);
assert_equals(document.visibilityState, "visible", "visible1");

await new Promise((resolve, reject) => {
let timeout = setTimeout(() => {
console.log("window.onblur took too long");
resolve();
}, 5000);

window.onblur = () => {
clearTimeout(timeout);
resolve();
}

internals.setPageIsFocusedAndActive(false);
});

await new Promise((resolve, reject) => {
assert_false(document.hasFocus(), "document.hasFocus()");

navigator.mediaDevices.ondevicechange = () => {
assert_true(document.hasFocus(), "devicechange should only fire when the document is focused and active");
resolve();
};

setTimeout(() => {
internals.setPageIsFocusedAndActive(true);
}, 200);

testRunner.addMockMicrophoneDevice("id3", "microphone 2");
});

}, "'devicechange' event is not fired when the document doesn't has focus or permission to capture");
let promise = new Promise(resolve => document.onvisibilitychange = resolve);
testRunner.setPageVisibility("hidden");
await promise;
assert_equals(document.visibilityState, "hidden", "hidden");

promise_test(async (test) => {
await setup(test);
testRunner.addMockMicrophoneDevice("id3", "microphone 2");

await navigator.mediaDevices.getUserMedia({ audio:true, video:true })
.then(s => stream = s);
let testPromise = new Promise(resolve => navigator.mediaDevices.ondevicechange = resolve);
testPromise = testPromise.then(test.step_func(() => {
assert_equals(document.visibilityState, "visible", "devicechange should only fire when the document is focused and active");
}));

await new Promise((resolve, reject) => {
let timeout = setTimeout(() => {
console.log("window.onblur took too long");
resolve();
}, 5000);

window.onblur = () => {
clearTimeout(timeout);
resolve();
}

internals.setPageIsFocusedAndActive(false);
});

await new Promise((resolve, reject) => {
assert_false(document.hasFocus(), "document.hasFocus()");

navigator.mediaDevices.ondevicechange = () => {
assert_false(document.hasFocus(), "devicechange should fire when the document is not focused but can capture");
resolve();
};

testRunner.addMockMicrophoneDevice("id3", "microphone 2");
});
promise = new Promise(resolve => document.onvisibilitychange = resolve);
// Let's delay to give enough time for navigator.mediaDevices.ondevicechange to fire
setTimeout(() => {
testRunner.setPageVisibility("visible");
}, 500);

}, "'devicechange' event is fired when the document doesn't has focus but has permission to capture");
await promise;
assert_equals(document.visibilityState, "visible", "visible2");

return testPromise;
}, "'devicechange' event is not fired when the document is not visible");
</script>
</head>
<body>
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/platform/ios/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ webkit.org/b/165799 svg/animations/animations-paused-in-background-page-iframe.h
webkit.org/b/165799 svg/animations/animations-paused-in-background-page.html [ Skip ]
webkit.org/b/165799 webaudio/silent-audio-interrupted-in-background.html [ Skip ]
webkit.org/b/165799 imported/w3c/web-platform-tests/screen-orientation/hidden_document.html
webkit.org/b/165799 fast/mediastream/device-change-event-2.html [ Skip ]

# AutoFill button is not supported
fast/forms/auto-fill-button/mouse-down-input-mouse-release-auto-fill-button.html
Expand Down
9 changes: 7 additions & 2 deletions Source/WebCore/Modules/mediastream/MediaDevices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,13 @@ MediaTrackSupportedConstraints MediaDevices::getSupportedConstraints()

void MediaDevices::scheduledEventTimerFired()
{
ASSERT(!isContextStopped());
dispatchEvent(Event::create(eventNames().devicechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
RefPtr document = this->document();
if (!document)
return;

document->whenVisible([protectedThis = makePendingActivity(*this), this] {
queueTaskToDispatchEvent(*this, TaskSource::DOMManipulation, Event::create(eventNames().devicechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
});
}

bool MediaDevices::virtualHasPendingActivity() const
Expand Down

0 comments on commit 2d5fd91

Please sign in to comment.