From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../video_engine/platform_uithread.cc | 198 +++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 dom/media/systemservices/video_engine/platform_uithread.cc (limited to 'dom/media/systemservices/video_engine/platform_uithread.cc') diff --git a/dom/media/systemservices/video_engine/platform_uithread.cc b/dom/media/systemservices/video_engine/platform_uithread.cc new file mode 100644 index 0000000000..701a989a18 --- /dev/null +++ b/dom/media/systemservices/video_engine/platform_uithread.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if defined(WEBRTC_WIN) + +# include "platform_uithread.h" + +namespace rtc { + +// timer id used in delayed callbacks +static const UINT_PTR kTimerId = 1; +static const wchar_t kThisProperty[] = L"ThreadWindowsUIPtr"; +static const wchar_t kThreadWindow[] = L"WebrtcWindowsUIThread"; + +PlatformUIThread::~PlatformUIThread() { + CritScope scoped_lock(&cs_); + switch (state_) { + case State::STARTED: { + MOZ_DIAGNOSTIC_ASSERT( + false, "PlatformUIThread must be stopped before destruction"); + break; + } + case State::STOPPED: + break; + case State::UNSTARTED: + break; + } +} + +bool PlatformUIThread::InternalInit() { + // Create an event window for use in generating callbacks to capture + // objects. + CritScope scoped_lock(&cs_); + switch (state_) { + // We have already started there is nothing todo. Should this be assert? + case State::STARTED: + break; + // Stop() has already been called so there is likewise nothing to do. + case State::STOPPED: + break; + // Stop() has not been called yet, setup the UI thread, and set our + // state to STARTED. + case State::UNSTARTED: { + WNDCLASSW wc; + HMODULE hModule = GetModuleHandle(NULL); + if (!GetClassInfoW(hModule, kThreadWindow, &wc)) { + ZeroMemory(&wc, sizeof(WNDCLASSW)); + wc.hInstance = hModule; + wc.lpfnWndProc = EventWindowProc; + wc.lpszClassName = kThreadWindow; + RegisterClassW(&wc); + } + hwnd_ = CreateWindowW(kThreadWindow, L"", 0, 0, 0, 0, 0, NULL, NULL, + hModule, NULL); + // Added in review of bug 1760843, follow up to remove 1767861 + MOZ_RELEASE_ASSERT(hwnd_); + // Expected to always work but if it doesn't we should still fulfill the + // contract of always running the process loop at least a single + // iteration. + // This could be rexamined in the future. + if (hwnd_) { + SetPropW(hwnd_, kThisProperty, this); + // state_ needs to be STARTED before we request the initial timer + state_ = State::STARTED; + if (timeout_) { + // if someone set the timer before we started + RequestCallbackTimer(timeout_); + } + } + break; + } + }; + return state_ == State::STARTED; +} + +bool PlatformUIThread::RequestCallbackTimer(unsigned int milliseconds) { + CritScope scoped_lock(&cs_); + + switch (state_) { + // InternalInit() has yet to run so we do not have a UI thread to use as a + // target of the timer. We should just remember what timer interval was + // requested and let InternalInit() call this function again when it is + // ready. + case State::UNSTARTED: { + timeout_ = milliseconds; + return false; + } + // We have already stopped, do not schedule a new timer. + case State::STOPPED: + return false; + case State::STARTED: { + if (timerid_) { + KillTimer(hwnd_, timerid_); + } + timeout_ = milliseconds; + timerid_ = SetTimer(hwnd_, kTimerId, milliseconds, NULL); + return !!timerid_; + } + } + // UNREACHABLE +} + +void PlatformUIThread::Stop() { + { + RTC_DCHECK_RUN_ON(&thread_checker_); + CritScope scoped_lock(&cs_); + // Shut down the dispatch loop and let the background thread exit. + if (timerid_) { + MOZ_ASSERT(hwnd_); + KillTimer(hwnd_, timerid_); + timerid_ = 0; + } + switch (state_) { + // If we haven't started yet there is nothing to do, we will go into + // the STOPPED state at the end of the function and InternalInit() + // will not move us to STARTED. + case State::UNSTARTED: + break; + // If we have started, that means that InternalInit() has run and the + // message wait loop has or will run. We need to signal it to stop. wich + // will allow PlatformThread::Stop to join that thread. + case State::STARTED: { + MOZ_ASSERT(hwnd_); + PostMessage(hwnd_, WM_CLOSE, 0, 0); + break; + } + // We have already stopped. There is nothing to do. + case State::STOPPED: + break; + } + // Always set our state to STOPPED + state_ = State::STOPPED; + } + monitor_thread_.Finalize(); +} + +void PlatformUIThread::Run() { + // InternalInit() will return false when the thread is already in shutdown. + // otherwise we must run until we get a Windows WM_QUIT msg. + const bool runUntilQuitMsg = InternalInit(); + // The interface contract of Start/Stop is that for a successful call to + // Start, there should be at least one call to the run function. + NativeEventCallback(); + while (runUntilQuitMsg) { + // Alertable sleep to receive WM_QUIT (following a WM_CLOSE triggering a + // WM_DESTROY) + if (MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLINPUT, + MWMO_ALERTABLE | MWMO_INPUTAVAILABLE) == + WAIT_OBJECT_0) { + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + // THE ONLY WAY to exit the thread loop + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } +} + +void PlatformUIThread::NativeEventCallback() { native_event_callback_(); } + +/* static */ +LRESULT CALLBACK PlatformUIThread::EventWindowProc(HWND hwnd, UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + if (uMsg == WM_DESTROY) { + RemovePropW(hwnd, kThisProperty); + PostQuitMessage(0); + return 0; + } + + PlatformUIThread* twui = + static_cast(GetPropW(hwnd, kThisProperty)); + if (!twui) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + if (uMsg == WM_TIMER && wParam == kTimerId) { + twui->NativeEventCallback(); + return 0; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +} // namespace rtc + +#endif -- cgit v1.2.3