diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index 87fe543b187b7019a5cfbce38ba383b891f865ff..7f521dd10459ccc5f06d624a34c48ccba4f11bb8 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -123,7 +123,16 @@ std::unique_ptr<content::MediaStreamUI> getDevicesForDesktopCapture(content::Med content::DesktopMediaID getDefaultScreenId() { -#if BUILDFLAG(ENABLE_WEBRTC) + // While this function is executing another thread may also want to create a + // DesktopCapturer [1]. Unfortunately, creating a DesktopCapturer is not + // thread safe on X11 due to the use of webrtc::XErrorTrap. It's safe to + // disable this code on X11 since we don't actually need to create a + // DesktopCapturer to get the screen id anyway + // (ScreenCapturerLinux::GetSourceList always returns 0 as the id). + // + // [1]: webrtc::InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread + +#if BUILDFLAG(ENABLE_WEBRTC) && !defined(USE_X11) // Source id patterns are different across platforms. // On Linux, the hardcoded value "0" is used. // On Windows, the screens are enumerated consecutively in increasing order from 0. diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 47a94374a492d01db9f216bd54dcc09416c06bd2..7bdad1bdaf2642294b0c81cbff5ea08ac6b6c083 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -125,6 +125,8 @@ private Q_SLOTS: void getUserMediaRequest(); void getUserMediaRequestDesktopAudio(); void getUserMediaRequestSettingDisabled(); + void getUserMediaRequestDesktopVideoManyPages(); + void getUserMediaRequestDesktopVideoManyRequests(); void savePage(); void crashTests_LazyInitializationOfMainFrame(); @@ -2447,6 +2449,44 @@ void tst_QWebEnginePage::getUserMediaRequestSettingDisabled() QTRY_VERIFY(!page.jsPromiseFulfilled() && page.jsPromiseRejected()); } +// Try to trigger any possible race condition between the UI thread (permission +// management) and the audio/device thread (desktop capture initialization). +void tst_QWebEnginePage::getUserMediaRequestDesktopVideoManyPages() +{ + const QString constraints = QStringLiteral("{video: { mandatory: { chromeMediaSource: 'desktop' }}}"); + const QWebEnginePage::Feature feature = QWebEnginePage::DesktopVideoCapture; + std::vector<GetUserMediaTestPage> pages(10); + for (GetUserMediaTestPage &page : pages) + QTRY_VERIFY_WITH_TIMEOUT(page.loadSucceeded(), 20000); + for (GetUserMediaTestPage &page : pages) + page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true); + for (GetUserMediaTestPage &page : pages) + page.jsGetUserMedia(constraints); + for (GetUserMediaTestPage &page : pages) + QTRY_VERIFY(page.gotFeatureRequest(feature)); + for (GetUserMediaTestPage &page : pages) + page.acceptPendingRequest(); + for (GetUserMediaTestPage &page : pages) + QTRY_VERIFY(page.jsPromiseFulfilled() || page.jsPromiseRejected()); +} + +// Try to trigger any possible race condition between the UI or audio/device +// threads and the desktop capture thread, where the capture actually happens. +void tst_QWebEnginePage::getUserMediaRequestDesktopVideoManyRequests() +{ + const QString constraints = QStringLiteral("{video: { mandatory: { chromeMediaSource: 'desktop' }}}"); + const QWebEnginePage::Feature feature = QWebEnginePage::DesktopVideoCapture; + GetUserMediaTestPage page; + QTRY_VERIFY_WITH_TIMEOUT(page.loadSucceeded(), 20000); + page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true); + for (int i = 0; i != 100; ++i) { + page.jsGetUserMedia(constraints); + QTRY_VERIFY(page.gotFeatureRequest(feature)); + page.acceptPendingRequest(); + QTRY_VERIFY(page.jsPromiseFulfilled() || page.jsPromiseRejected()); + } +} + void tst_QWebEnginePage::savePage() { QWebEngineView view;