diff --git a/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll index d48defc..4bbc507 100644 Binary files a/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll and b/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll differ diff --git a/Assets/uDesktopDuplication/Scripts/Lib.cs b/Assets/uDesktopDuplication/Scripts/Lib.cs index 78580c0..a628a74 100644 --- a/Assets/uDesktopDuplication/Scripts/Lib.cs +++ b/Assets/uDesktopDuplication/Scripts/Lib.cs @@ -27,6 +27,18 @@ public enum MonitorRotation Rotate270 = 4 } +public enum MonitorState +{ + NotSet = -1, + Available = 0, + InvalidArg = 1, + AccessDenied = 2, + Unsupported = 3, + CurrentlyNotAvailable = 4, + SessionDisconnected = 5, + AccessLost = 6, +} + public static class Lib { public delegate void MessageHandler(Message message); @@ -36,6 +48,8 @@ public static class Lib [DllImport("uDesktopDuplication")] public static extern void FinalizeUDD(); [DllImport("uDesktopDuplication")] + public static extern void Reinitialize(); + [DllImport("uDesktopDuplication")] public static extern void Update(); [DllImport("uDesktopDuplication")] public static extern Message PopMessage(); @@ -50,7 +64,7 @@ public static class Lib [DllImport("uDesktopDuplication")] public static extern IntPtr GetRenderEventFunc(); [DllImport("uDesktopDuplication")] - public static extern bool IsAvailable(int id); + public static extern MonitorState GetState(int id); [DllImport("uDesktopDuplication")] public static extern void GetName(int id, StringBuilder buf, int len); [DllImport("uDesktopDuplication")] diff --git a/Assets/uDesktopDuplication/Scripts/Manager.cs b/Assets/uDesktopDuplication/Scripts/Manager.cs index 6d28681..5764d03 100644 --- a/Assets/uDesktopDuplication/Scripts/Manager.cs +++ b/Assets/uDesktopDuplication/Scripts/Manager.cs @@ -37,10 +37,12 @@ public class Manager : MonoBehaviour } } - [SerializeField, Tooltip("Set Desktop Duplication API timeout (milliseconds).")] - int timeout = 0; + [SerializeField] int desktopDuplicationApiTimeout = 0; + [SerializeField] float retryReinitializationDuration = 0.5f; private Coroutine renderCoroutine_ = null; + private bool shouldReinitialize = false; + private float reinitializationTimer = 0f; void Awake() { @@ -51,7 +53,7 @@ public class Manager : MonoBehaviour CreateMonitors(); - Lib.SetTimeout(timeout); + Lib.SetTimeout(desktopDuplicationApiTimeout); } void OnApplicationQuit() @@ -75,7 +77,35 @@ public class Manager : MonoBehaviour void Update() { Lib.Update(); + ReinitializeIfNeeded(); + UpdateMessage(); + } + void ReinitializeIfNeeded() + { + for (int i = 0; i < monitors.Count; ++i) { + var monitor = monitors[i]; + if (monitor.state == MonitorState.AccessLost || + monitor.state == MonitorState.AccessDenied) { + if (!shouldReinitialize) { + shouldReinitialize = true; + reinitializationTimer = 0f; + break; + } + } + } + + if (shouldReinitialize) { + if (reinitializationTimer > retryReinitializationDuration) { + Lib.Reinitialize(); + shouldReinitialize = false; + } + reinitializationTimer += Time.deltaTime; + } + } + + void UpdateMessage() + { var message = Lib.PopMessage(); while (message != Message.None) { switch (message) { diff --git a/Assets/uDesktopDuplication/Scripts/Monitor.cs b/Assets/uDesktopDuplication/Scripts/Monitor.cs index 3f6466e..b2d2f06 100644 --- a/Assets/uDesktopDuplication/Scripts/Monitor.cs +++ b/Assets/uDesktopDuplication/Scripts/Monitor.cs @@ -21,9 +21,14 @@ public class Monitor get { return id < Manager.monitorCount; } } + public MonitorState state + { + get { return Lib.GetState(id); } + } + public bool available { - get { return Lib.IsAvailable(id); } + get { return state == MonitorState.Available; } } public string name diff --git a/Assets/uDesktopDuplication/Scripts/Texture.cs b/Assets/uDesktopDuplication/Scripts/Texture.cs index ef45cde..168b4bd 100644 --- a/Assets/uDesktopDuplication/Scripts/Texture.cs +++ b/Assets/uDesktopDuplication/Scripts/Texture.cs @@ -50,7 +50,6 @@ public class Texture : MonoBehaviour void Update() { - Debug.Log(monitor.available); monitor.shouldBeUpdated = true; UpdateMaterial(); } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index cde2cef..38c6c5a 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -11,6 +11,7 @@ Monitor::Monitor(int id) { } + HRESULT Monitor::Initialize(IDXGIOutput* output) { output->GetDesc(&outputDesc_); @@ -24,23 +25,27 @@ HRESULT Monitor::Initialize(IDXGIOutput* output) switch (hr) { case S_OK: - available_ = true; + state_ = State::Available; break; case E_INVALIDARG: + state_ = State::InvalidArg; break; case E_ACCESSDENIED: // For example, when the user presses Ctrl + Alt + Delete and the screen // switches to admin screen, this error occurs. - // GetMonitorManager()->RequireReinitilization(); + state_ = State::AccessDenied; break; case DXGI_ERROR_UNSUPPORTED: // If the display adapter on the computer is running under the Microsoft Hybrid system, // this error occurs. + state_ = State::Unsupported; break; case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: // When other application use Desktop Duplication API, this error occurs. + state_ = State::CurrentlyNotAvailable; break; case DXGI_ERROR_SESSION_DISCONNECTED: + state_ = State::SessionDisconnected; break; } @@ -61,7 +66,7 @@ HRESULT Monitor::Render(UINT timeout) { if (deskDupl_ == nullptr) { - return 0; + return S_OK; } if (unityTexture_ == nullptr) return 0; @@ -72,7 +77,13 @@ HRESULT Monitor::Render(UINT timeout) const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource); if (FAILED(hr)) { - return hr; + // If any monitor setting has changed (e.g. monitor size has changed), + // it is necessary to re-initialize monitors. + if (hr == DXGI_ERROR_ACCESS_LOST) + { + state_ = State::AccessLost; + } + return hr; } ID3D11Texture2D* texture; @@ -98,9 +109,9 @@ int Monitor::GetId() const } -bool Monitor::IsAvailable() const +MonitorState Monitor::GetState() const { - return available_; + return state_; } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h index 1cee5a6..a7f35c6 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h @@ -4,9 +4,23 @@ class Cursor; +enum class MonitorState +{ + NotSet = -1, + Available = 0, + InvalidArg = 1, + AccessDenied = 2, + Unsupported = 3, + CurrentlyNotAvailable = 4, + SessionDisconnected = 5, + AccessLost = 6, +}; + class Monitor { public: + using State = MonitorState; + explicit Monitor(int id); ~Monitor(); HRESULT Initialize(IDXGIOutput* output); @@ -15,7 +29,7 @@ public: public: int GetId() const; - bool IsAvailable() const; + State GetState() const; void SetUnityTexture(ID3D11Texture2D* texture); ID3D11Texture2D* GetUnityTexture() const; void GetName(char* buf, int len) const; @@ -32,7 +46,7 @@ public: private: int id_ = -1; - bool available_ = false; + State state_ = State::NotSet; std::unique_ptr cursor_; IDXGIOutputDuplication* deskDupl_ = nullptr; ID3D11Texture2D* unityTexture_ = nullptr; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp index 940edb5..a925126 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp @@ -59,6 +59,12 @@ void MonitorManager::Finalize() } +void MonitorManager::RequireReinitilization() +{ + isReinitializationRequired_ = true; +} + + void MonitorManager::Reinitialize() { Initialize(); @@ -86,24 +92,6 @@ void MonitorManager::Update() } -void MonitorManager::OnRender(int id) -{ - if (auto monitor = GetMonitor(id)) - { - if (!monitor->IsAvailable()) return; - - const auto hr = monitor->Render(timeout_); - - // If any monitor setting has changed (e.g. monitor size has changed), - // it is necessary to re-initialize monitors. - if (hr == DXGI_ERROR_ACCESS_LOST) - { - isReinitializationRequired_ = true; - } - } -} - - void MonitorManager::SetTimeout(int timeout) { timeout_ = timeout; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h index c4d5d6e..959b621 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h @@ -13,9 +13,8 @@ class MonitorManager public: explicit MonitorManager(); ~MonitorManager(); - - void RequireReinitilization() { isReinitializationRequired_ = true; } - + void Reinitialize(); + void RequireReinitilization(); void SetCursorMonitorId(int id) { cursorMonitorId_ = id; } int GetCursorMonitorId() const { return cursorMonitorId_; } std::shared_ptr GetMonitor(int id) const; @@ -23,11 +22,9 @@ public: private: void Initialize(); void Finalize(); - void Reinitialize(); // Setters from Unity public: - void OnRender(int id); void Update(); void SetTimeout(int timeout); int GetTimeout() const; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp index 0719706..4c63e59 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -79,7 +79,10 @@ extern "C" void UNITY_INTERFACE_API OnRenderEvent(int id) { if (!g_manager) return; - g_manager->OnRender(id); + if (auto monitor = g_manager->GetMonitor(id)) + { + monitor->Render(g_manager->GetTimeout()); + } } UNITY_INTERFACE_EXPORT UnityRenderingEvent UNITY_INTERFACE_API GetRenderEventFunc() @@ -87,6 +90,12 @@ extern "C" return OnRenderEvent; } + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Reinitialize() + { + if (!g_manager) return; + return g_manager->Reinitialize(); + } + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update() { if (!g_manager) return; @@ -126,14 +135,14 @@ extern "C" g_manager->SetTimeout(timeout); } - UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsAvailable(int id) + UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id) { - if (!g_manager) return false; + if (!g_manager) return MonitorState::NotSet; if (auto monitor = g_manager->GetMonitor(id)) { - return monitor->IsAvailable(); + return monitor->GetState(); } - return false; + return MonitorState::NotSet; } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)