diff --git a/windows/runner/mpv/mpv_core.cpp b/windows/runner/mpv/mpv_core.cpp index c787f196..27a634ed 100644 --- a/windows/runner/mpv/mpv_core.cpp +++ b/windows/runner/mpv/mpv_core.cpp @@ -147,6 +147,11 @@ std::optional MpvCore::WindowProc(HWND hwnd, UINT message, ::RedrawWindow(flutter_window_, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } + } else if (wparam == kPowerResumeTimerId) { + ::KillTimer(flutter_window_, kPowerResumeTimerId); + if (power_resume_cb_) { + power_resume_cb_(); + } } break; } @@ -170,6 +175,14 @@ std::optional MpvCore::WindowProc(HWND hwnd, UINT message, } break; } + case WM_POWERBROADCAST: { + if (wparam == PBT_APMRESUMEAUTOMATIC && power_resume_cb_) { + // Delay audio reload to let WASAPI fully reinitialize after wake. + ::KillTimer(flutter_window_, kPowerResumeTimerId); + ::SetTimer(flutter_window_, kPowerResumeTimerId, kPowerResumeAudioDelay, nullptr); + } + break; + } case WM_CLOSE: { ::SendMessage(container_, WM_CLOSE, 0, 0); for (const auto& [mpv_view, rect] : mpv_views_) { @@ -202,6 +215,10 @@ RECT MpvCore::GetGlobalRect(int32_t left, int32_t top, int32_t right, return rect; } +void MpvCore::SetPowerResumeCallback(PowerResumeCallback callback) { + power_resume_cb_ = std::move(callback); +} + std::unique_ptr MpvCore::instance_ = nullptr; } // namespace mpv diff --git a/windows/runner/mpv/mpv_core.h b/windows/runner/mpv/mpv_core.h index 0deab605..95c25ce9 100644 --- a/windows/runner/mpv/mpv_core.h +++ b/windows/runner/mpv/mpv_core.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,9 @@ namespace mpv { class MpvCore { public: static constexpr auto kPositionAndShowDelay = 300; + static constexpr auto kPowerResumeAudioDelay = 500; static constexpr UINT_PTR kCompositionRestoreTimerId = 1001; + static constexpr UINT_PTR kPowerResumeTimerId = 1002; static MpvCore* GetInstance(); static void SetInstance(std::unique_ptr instance); @@ -42,6 +45,10 @@ class MpvCore { std::optional WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); + // Callback invoked when Windows resumes from sleep/hibernate. + using PowerResumeCallback = std::function; + void SetPowerResumeCallback(PowerResumeCallback callback); + private: RECT GetGlobalRect(int32_t left, int32_t top, int32_t right, int32_t bottom); @@ -53,6 +60,7 @@ class MpvCore { bool was_window_hidden_due_to_minimize_ = false; bool visible_ = true; bool composition_enabled_ = false; + PowerResumeCallback power_resume_cb_; static std::unique_ptr instance_; }; diff --git a/windows/runner/mpv/mpv_plugin.cpp b/windows/runner/mpv/mpv_plugin.cpp index dc785e8d..d74b9b6e 100644 --- a/windows/runner/mpv/mpv_plugin.cpp +++ b/windows/runner/mpv/mpv_plugin.cpp @@ -121,6 +121,16 @@ void MpvPlayerPlugin::HandleMethodCall( RECT rect = {0, 0, 100, 100}; MpvCore::GetInstance()->CreateMpvView(player_->GetHwnd(), rect, 1.0); + // Reload audio output on wake from sleep to recover stale WASAPI sessions. + MpvCore::GetInstance()->SetPowerResumeCallback([this]() { + if (player_ && player_->IsInitialized()) { + auto device = player_->GetProperty("audio-device"); + if (!device.empty()) { + player_->SetProperty("audio-device", device); + } + } + }); + // Start hidden. MpvCore::GetInstance()->SetVisible(false); result->Success(flutter::EncodableValue(true));