From 095efe57179f9fd782d25048df52c293b3225eae Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:49:56 +0200 Subject: [PATCH 01/20] Fixed crash related to missing Media Feature Pack --- packages/audioplayers_windows/CHANGELOG.md | 4 ++++ packages/audioplayers_windows/pubspec.yaml | 2 +- .../windows/CMakeLists.txt | 2 +- .../windows/audio_player.cpp | 24 +++++++++++++++++++ .../windows/audio_player.h | 1 + 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/audioplayers_windows/CHANGELOG.md b/packages/audioplayers_windows/CHANGELOG.md index 633a1e45d..71e501306 100644 --- a/packages/audioplayers_windows/CHANGELOG.md +++ b/packages/audioplayers_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.2.2 + +- **FIX**: Fixed app crash on startup on Windows with missing Media Feature Pack + ## 4.2.1 - **FIX**: Migrate to Melos v7 and Pub Workspaces ([#1929](https://github.com/bluefireteam/audioplayers/issues/1929)). ([9d0bfe0b](https://github.com/bluefireteam/audioplayers/commit/9d0bfe0be5cba0ce4fb3a75912b41117a8996bfe)) diff --git a/packages/audioplayers_windows/pubspec.yaml b/packages/audioplayers_windows/pubspec.yaml index de0432291..22abdaa23 100644 --- a/packages/audioplayers_windows/pubspec.yaml +++ b/packages/audioplayers_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: audioplayers_windows resolution: workspace description: Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously -version: 4.2.1 +version: 4.2.2 homepage: https://github.com/bluefireteam/audioplayers repository: https://github.com/bluefireteam/audioplayers/tree/master/packages/audioplayers_windows diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 0943f70ff..03dd6cfa9 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -46,7 +46,7 @@ set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.ImplementationLibrary/build/native/Microsoft.Windows.ImplementationLibrary.targets) -target_link_libraries(${PLUGIN_NAME} PRIVATE Mfplat windowsapp) +target_link_libraries(${PLUGIN_NAME} PRIVATE windowsapp) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 778b38775..1f2ed2558 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -25,6 +25,14 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { + HMODULE hMfPlat = LoadLibrary(L"MFPlat.dll"); + HMODULE hMfReadWrite = LoadLibrary(L"mfreadwrite.dll"); + + if (hMfPlat == NULL || hMfReadWrite == NULL) m_mediaFoundationFailed = true; + if (hMfPlat) FreeLibrary(hMfPlat); + if (hMfReadWrite) FreeLibrary(hMfReadWrite); + if (m_mediaFoundationFailed) return; + m_mfPlatform.Startup(); // Callbacks invoked by the media engine wrapper @@ -48,6 +56,14 @@ AudioPlayer::~AudioPlayer() {} // This method should be called asynchronously, to avoid freezing UI void AudioPlayer::SetSourceUrl(std::string url) { + if (m_mediaFoundationFailed) { + this->OnError("WindowsAudioError", + "Media Feature Pack not found. Please install it from " + "Windows Settings > Optional Features.", + nullptr); + return; + } + if (_url != url) { _url = url; _isInitialized = false; @@ -90,6 +106,14 @@ void AudioPlayer::SetSourceUrl(std::string url) { } void AudioPlayer::SetSourceBytes(std::vector bytes) { + if (m_mediaFoundationFailed) { + this->OnError("WindowsAudioError", + "Media Feature Pack not found. Please install it from " + "Windows Settings > Optional Features.", + nullptr); + return; + } + _isInitialized = false; _url.clear(); size_t size = bytes.size(); diff --git a/packages/audioplayers_windows/windows/audio_player.h b/packages/audioplayers_windows/windows/audio_player.h index 3254f0454..1c3eac082 100644 --- a/packages/audioplayers_windows/windows/audio_player.h +++ b/packages/audioplayers_windows/windows/audio_player.h @@ -104,6 +104,7 @@ class AudioPlayer { winrt::com_ptr m_mediaEngineWrapper; bool _isInitialized = false; + bool m_mediaFoundationFailed = false; ReleaseMode _releaseMode = ReleaseMode::release; std::string _url{}; From 400e4d49a0fbea6121c99f2fdd1b6d24860c2979 Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:01:41 +0200 Subject: [PATCH 02/20] Fixed build and functions usage --- .../audioplayers_windows/windows/CMakeLists.txt | 2 +- .../windows/audio_player.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 03dd6cfa9..9688136f5 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -52,7 +52,7 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi) +target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mf.lib) # List of absolute paths to libraries that should be bundled with the plugin set(audioplayers_windows_bundled_libraries diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 1f2ed2558..8233d33c1 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -238,6 +238,7 @@ void AudioPlayer::OnLog(const std::string& message) { } void AudioPlayer::SendInitialized() { + if (m_mediaFoundationFailed) return; if (!this->_isInitialized) { this->_isInitialized = true; OnPrepared(true); @@ -246,6 +247,7 @@ void AudioPlayer::SendInitialized() { } void AudioPlayer::ReleaseMediaSource() { + if (m_mediaFoundationFailed) return; if (_isInitialized) { m_mediaEngineWrapper->Pause(); } @@ -255,6 +257,7 @@ void AudioPlayer::ReleaseMediaSource() { } void AudioPlayer::Dispose() { + if (m_mediaFoundationFailed) return; ReleaseMediaSource(); m_mediaEngineWrapper->Shutdown(); _methodChannel = nullptr; @@ -262,6 +265,7 @@ void AudioPlayer::Dispose() { } void AudioPlayer::SetReleaseMode(ReleaseMode releaseMode) { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->SetLooping(releaseMode == ReleaseMode::loop); _releaseMode = releaseMode; } @@ -271,6 +275,8 @@ ReleaseMode AudioPlayer::GetReleaseMode() { } void AudioPlayer::SetVolume(double volume) { + if (m_mediaFoundationFailed) return; + if (volume > 1) { volume = 1; } else if (volume < 0) { @@ -280,23 +286,28 @@ void AudioPlayer::SetVolume(double volume) { } void AudioPlayer::SetPlaybackSpeed(double playbackSpeed) { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->SetPlaybackRate(playbackSpeed); } void AudioPlayer::SetBalance(double balance) { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->SetBalance(balance); } void AudioPlayer::Play() { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->StartPlayingFrom(m_mediaEngineWrapper->GetMediaTime()); OnDurationUpdate(); } void AudioPlayer::Pause() { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->Pause(); } void AudioPlayer::Stop() { + if (m_mediaFoundationFailed) return; Pause(); if (GetReleaseMode() == ReleaseMode::release) { ReleaseMediaSource(); @@ -306,21 +317,24 @@ void AudioPlayer::Stop() { } void AudioPlayer::Resume() { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->Resume(); OnDurationUpdate(); } double AudioPlayer::GetPosition() { - if (!_isInitialized) { + if (!_isInitialized || m_mediaFoundationFailed) { return std::numeric_limits::quiet_NaN(); } return m_mediaEngineWrapper->GetMediaTime(); } double AudioPlayer::GetDuration() { + if (m_mediaFoundationFailed) return std::numeric_limits::quiet_NaN(); return m_mediaEngineWrapper->GetDuration(); } void AudioPlayer::SeekTo(double seek) { + if (m_mediaFoundationFailed) return; m_mediaEngineWrapper->SeekTo(seek); } From e94e91fbbb0f33e48c4260a4631132cfc6207ef7 Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:17:56 +0200 Subject: [PATCH 03/20] Try delayed load approach --- .../windows/CMakeLists.txt | 6 ++- .../windows/audio_player.cpp | 53 ++++++++++--------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 9688136f5..f284a5470 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -52,7 +52,11 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mf.lib) +target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mf.lib Mfplat.lib) + +target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mfplat.dll") +target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mf.dll") +target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:mfreadwrite.dll") # List of absolute paths to libraries that should be bundled with the plugin set(audioplayers_windows_bundled_libraries diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 8233d33c1..afcdb2364 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include "audioplayers_helpers.h" #define STR_LINK_TROUBLESHOOTING \ @@ -25,31 +27,34 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { - HMODULE hMfPlat = LoadLibrary(L"MFPlat.dll"); - HMODULE hMfReadWrite = LoadLibrary(L"mfreadwrite.dll"); - if (hMfPlat == NULL || hMfReadWrite == NULL) m_mediaFoundationFailed = true; - if (hMfPlat) FreeLibrary(hMfPlat); - if (hMfReadWrite) FreeLibrary(hMfReadWrite); - if (m_mediaFoundationFailed) return; - - m_mfPlatform.Startup(); - - // Callbacks invoked by the media engine wrapper - auto onError = std::bind(&AudioPlayer::OnMediaError, this, - std::placeholders::_1, std::placeholders::_2); - auto onBufferingStateChanged = - std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); - auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); - auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); - auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - - // Create and initialize the MediaEngineWrapper which manages media playback - m_mediaEngineWrapper = winrt::make_self( - onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, - onSeekCompletedCB); - - m_mediaEngineWrapper->Initialize(); + __try { + m_mfPlatform.Startup(); + + // Callbacks invoked by the media engine wrapper + auto onError = std::bind(&AudioPlayer::OnMediaError, this, + std::placeholders::_1, std::placeholders::_2); + auto onBufferingStateChanged = + std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); + auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); + auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); + auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); + + // Create and initialize the MediaEngineWrapper which manages media playback + m_mediaEngineWrapper = winrt::make_self( + onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, + onSeekCompletedCB); + + m_mediaEngineWrapper->Initialize(); + } __except (EXCEPTION_EXECUTE_HANDLER) { + DWORD exceptionCode = GetExceptionCode(); + if (exceptionCode == VcppException(ERROR_MOD_NOT_FOUND) || + exceptionCode == VcppException(ERROR_PROC_NOT_FOUND)) { + m_mediaFoundationFailed = true; + } else { + throw; + } + } } AudioPlayer::~AudioPlayer() {} From 8416488eebccbad1a3fc8fb9e42d4d65179b84ff Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:33:36 +0200 Subject: [PATCH 04/20] Fixed build --- .../windows/CMakeLists.txt | 3 +- .../windows/audio_player.cpp | 79 ++++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index f284a5470..1b61a46a1 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -52,10 +52,9 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mf.lib Mfplat.lib) +target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mfplat.lib) target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mfplat.dll") -target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mf.dll") target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:mfreadwrite.dll") # List of absolute paths to libraries that should be bundled with the plugin diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index afcdb2364..9cc96f01e 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -28,9 +28,6 @@ AudioPlayer::AudioPlayer( _methodChannel(methodChannel), _eventHandler(eventHandler) { - __try { - m_mfPlatform.Startup(); - // Callbacks invoked by the media engine wrapper auto onError = std::bind(&AudioPlayer::OnMediaError, this, std::placeholders::_1, std::placeholders::_2); @@ -39,17 +36,19 @@ AudioPlayer::AudioPlayer( auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - + // Create and initialize the MediaEngineWrapper which manages media playback m_mediaEngineWrapper = winrt::make_self( onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, onSeekCompletedCB); + __try { + m_mfPlatform.Startup(); m_mediaEngineWrapper->Initialize(); } __except (EXCEPTION_EXECUTE_HANDLER) { DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == VcppException(ERROR_MOD_NOT_FOUND) || - exceptionCode == VcppException(ERROR_PROC_NOT_FOUND)) { + if (exceptionCode == 0xC06D007E || + exceptionCode == 0xC06D007F) { m_mediaFoundationFailed = true; } else { throw; @@ -79,17 +78,29 @@ void AudioPlayer::SetSourceUrl(std::string url) { // playback. An application can skip this step and instantiate a custom // IMFMediaSource implementation instead. winrt::com_ptr sourceResolver; - THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); - constexpr uint32_t sourceResolutionFlags = + winrt::com_ptr mediaSource; + MF_OBJECT_TYPE objectType = {}; + + __try { + THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); + constexpr uint32_t sourceResolutionFlags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ; - MF_OBJECT_TYPE objectType = {}; - winrt::com_ptr mediaSource; - THROW_IF_FAILED(sourceResolver->CreateObjectFromURL( - winrt::to_hstring(url).c_str(), sourceResolutionFlags, nullptr, - &objectType, reinterpret_cast(mediaSource.put_void()))); + THROW_IF_FAILED(sourceResolver->CreateObjectFromURL( + winrt::to_hstring(url).c_str(), sourceResolutionFlags, nullptr, + &objectType, reinterpret_cast(mediaSource.put_void()))); + } __except (EXCEPTION_EXECUTE_HANDLER) { + DWORD exceptionCode = GetExceptionCode(); + if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { + m_mediaFoundationFailed = true; + this->OnError("WindowsAudioError", "Media Feature Pack not found (delay-load failed).", nullptr); + return; + } else { + throw; + } + } m_mediaEngineWrapper->SetMediaSource(mediaSource.get()); } catch (const std::exception& ex) { @@ -125,23 +136,35 @@ void AudioPlayer::SetSourceBytes(std::vector bytes) { try { winrt::com_ptr sourceResolver; - THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); - constexpr uint32_t sourceResolutionFlags = - MF_RESOLUTION_MEDIASOURCE | - MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | - MF_RESOLUTION_READ; - MF_OBJECT_TYPE objectType = {}; - winrt::com_ptr mediaSource; + MF_OBJECT_TYPE objectType = {}; - IStream* pstm = - SHCreateMemStream(bytes.data(), static_cast(size)); - IMFByteStream* stream = NULL; - MFCreateMFByteStreamOnStream(pstm, &stream); - - sourceResolver->CreateObjectFromByteStream( - stream, nullptr, sourceResolutionFlags, nullptr, &objectType, - reinterpret_cast(mediaSource.put_void())); + __try { + THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); + constexpr uint32_t sourceResolutionFlags = + MF_RESOLUTION_MEDIASOURCE | + MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | + MF_RESOLUTION_READ; + + IStream* pstm = + SHCreateMemStream(bytes.data(), static_cast(size)); + IMFByteStream* stream = NULL; + THROW_IF_FAILED(MFCreateMFByteStreamOnStream(pstm, &stream)); + + sourceResolver->CreateObjectFromByteStream( + stream, nullptr, sourceResolutionFlags, nullptr, &objectType, + reinterpret_cast(mediaSource.put_void())); + + } __except (EXCEPTION_EXECUTE_HANDLER) { + DWORD exceptionCode = GetExceptionCode(); + if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { + m_mediaFoundationFailed = true; + this->OnError("WindowsAudioError", "Media Feature Pack not found (delay-load failed).", nullptr); + return; + } else { + throw; + } + } m_mediaEngineWrapper->SetMediaSource(mediaSource.get()); } catch (...) { // Forward errors to event stream, as this is called asynchronously From dbc516c2fcf82d73b72ae77e78f5b13fcc5dbf64 Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:38:45 +0200 Subject: [PATCH 05/20] Fixed build --- .../windows/audio_player.cpp | 191 +++++++++++------- 1 file changed, 113 insertions(+), 78 deletions(-) diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 9cc96f01e..2c43a4086 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -20,6 +20,70 @@ using namespace winrt; +// SEH C-wrapper functions to solve C2712 +HRESULT InitializeMediaFoundation_SEH(media::MediaEngineWrapper* wrapper) { + __try { + THROW_IF_FAILED(MFStartup(MF_VERSION, MFSTARTUP_FULL)); + wrapper->Initialize(); + } __except (EXCEPTION_EXECUTE_HANDLER) { + DWORD exceptionCode = GetExceptionCode(); + if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { + return exceptionCode; + } + return E_FAIL; + } + return S_OK; +} + +HRESULT CreateSourceFromUrl_SEH(std::string url, IMFMediaSource** ppMediaSource) { + __try { + winrt::com_ptr sourceResolver; + THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); + constexpr uint32_t sourceResolutionFlags = + MF_RESOLUTION_MEDIASOURCE | + MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | + MF_RESOLUTION_READ; + MF_OBJECT_TYPE objectType = {}; + THROW_IF_FAILED(sourceResolver->CreateObjectFromURL( + winrt::to_hstring(url).c_str(), sourceResolutionFlags, nullptr, + &objectType, reinterpret_cast(ppMediaSource))); + } __except (EXCEPTION_EXECUTE_HANDLER) { + DWORD exceptionCode = GetExceptionCode(); + if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { + return exceptionCode; + } + return E_FAIL; + } + return S_OK; +} + +HRESULT CreateSourceFromBytes_SEH(std::vector bytes, + IMFMediaSource** ppMediaSource) { + __try { + winrt::com_ptr sourceResolver; + THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); + constexpr uint32_t sourceResolutionFlags = + MF_RESOLUTION_MEDIASOURCE | + MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | + MF_RESOLUTION_READ; + MF_OBJECT_TYPE objectType = {}; + IStream* pstm = + SHCreateMemStream(bytes.data(), static_cast(bytes.size())); + IMFByteStream* stream = NULL; + THROW_IF_FAILED(MFCreateMFByteStreamOnStream(pstm, &stream)); + sourceResolver->CreateObjectFromByteStream( + stream, nullptr, sourceResolutionFlags, nullptr, &objectType, + reinterpret_cast(ppMediaSource)); + } __except (EXCEPTION_EXECUTE_HANDLER) { + DWORD exceptionCode = GetExceptionCode(); + if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { + return exceptionCode; + } + return E_FAIL; + } + return S_OK; +} + AudioPlayer::AudioPlayer( std::string playerId, flutter::MethodChannel* methodChannel, @@ -27,32 +91,26 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { - - // Callbacks invoked by the media engine wrapper - auto onError = std::bind(&AudioPlayer::OnMediaError, this, - std::placeholders::_1, std::placeholders::_2); - auto onBufferingStateChanged = - std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); - auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); - auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); - auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - - // Create and initialize the MediaEngineWrapper which manages media playback - m_mediaEngineWrapper = winrt::make_self( - onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, - onSeekCompletedCB); - - __try { - m_mfPlatform.Startup(); - m_mediaEngineWrapper->Initialize(); - } __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == 0xC06D007E || - exceptionCode == 0xC06D007F) { - m_mediaFoundationFailed = true; - } else { - throw; - } + // Callbacks invoked by the media engine wrapper + auto onError = std::bind(&AudioPlayer::OnMediaError, this, + std::placeholders::_1, std::placeholders::_2); + auto onBufferingStateChanged = + std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); + auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); + auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); + auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); + + // Create and initialize the MediaEngineWrapper which manages media playback + m_mediaEngineWrapper = winrt::make_self( + onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, + onSeekCompletedCB); + + HRESULT hr = InitializeMediaFoundation_SEH(m_mediaEngineWrapper.get()); + if (FAILED(hr)) { + if (hr == 0xC06D007E || hr == 0xC06D007F) { + m_mediaFoundationFailed = true; + } + return; } } @@ -73,34 +131,22 @@ void AudioPlayer::SetSourceUrl(std::string url) { _isInitialized = false; try { - // Create a source resolver to create an IMFMediaSource for the content - // URL. This will create an instance of an inbuilt OS media source for - // playback. An application can skip this step and instantiate a custom - // IMFMediaSource implementation instead. - winrt::com_ptr sourceResolver; winrt::com_ptr mediaSource; - MF_OBJECT_TYPE objectType = {}; - __try { - THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); - constexpr uint32_t sourceResolutionFlags = - MF_RESOLUTION_MEDIASOURCE | - MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | - MF_RESOLUTION_READ; + HRESULT hr = CreateSourceFromUrl_SEH(url, mediaSource.put()); - THROW_IF_FAILED(sourceResolver->CreateObjectFromURL( - winrt::to_hstring(url).c_str(), sourceResolutionFlags, nullptr, - &objectType, reinterpret_cast(mediaSource.put_void()))); - } __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { - m_mediaFoundationFailed = true; - this->OnError("WindowsAudioError", "Media Feature Pack not found (delay-load failed).", nullptr); - return; + if (FAILED(hr)) { + if (hr == 0xC06D007E || hr == 0xC06D007F) { + m_mediaFoundationFailed = true; + this->OnError("WindowsAudioError", + "Media Feature Pack not found (delay-load failed).", + nullptr); } else { - throw; + this->OnError("WindowsAudioError", "Failed to create source from URL.", + nullptr); } - } + return; + } m_mediaEngineWrapper->SetMediaSource(mediaSource.get()); } catch (const std::exception& ex) { @@ -135,36 +181,23 @@ void AudioPlayer::SetSourceBytes(std::vector bytes) { size_t size = bytes.size(); try { - winrt::com_ptr sourceResolver; winrt::com_ptr mediaSource; - MF_OBJECT_TYPE objectType = {}; - __try { - THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); - constexpr uint32_t sourceResolutionFlags = - MF_RESOLUTION_MEDIASOURCE | - MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | - MF_RESOLUTION_READ; - - IStream* pstm = - SHCreateMemStream(bytes.data(), static_cast(size)); - IMFByteStream* stream = NULL; - THROW_IF_FAILED(MFCreateMFByteStreamOnStream(pstm, &stream)); - - sourceResolver->CreateObjectFromByteStream( - stream, nullptr, sourceResolutionFlags, nullptr, &objectType, - reinterpret_cast(mediaSource.put_void())); - - } __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { - m_mediaFoundationFailed = true; - this->OnError("WindowsAudioError", "Media Feature Pack not found (delay-load failed).", nullptr); - return; - } else { - throw; - } + HRESULT hr = CreateSourceFromBytes_SEH(bytes, mediaSource.put()); + + if (FAILED(hr)) { + if (hr == 0xC06D007E || hr == 0xC06D007F) { + m_mediaFoundationFailed = true; + this->OnError("WindowsAudioError", + "Media Feature Pack not found (delay-load failed).", + nullptr); + } else { + this->OnError("WindowsAudioError", "Failed to create source from bytes.", + nullptr); + } + return; } + m_mediaEngineWrapper->SetMediaSource(mediaSource.get()); } catch (...) { // Forward errors to event stream, as this is called asynchronously @@ -351,14 +384,16 @@ void AudioPlayer::Resume() { } double AudioPlayer::GetPosition() { - if (!_isInitialized || m_mediaFoundationFailed) { + if (m_mediaFoundationFailed || !_isInitialized) { return std::numeric_limits::quiet_NaN(); } return m_mediaEngineWrapper->GetMediaTime(); } double AudioPlayer::GetDuration() { - if (m_mediaFoundationFailed) return std::numeric_limits::quiet_NaN(); + if (m_mediaFoundationFailed) { + return std::numeric_limits::quiet_NaN(); + } return m_mediaEngineWrapper->GetDuration(); } From c34af478774238ca805eecf1f859091391a516c9 Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:08:04 +0200 Subject: [PATCH 06/20] Fixed build? --- .../windows/CMakeLists.txt | 1 + .../windows/audio_player.cpp | 207 +++++++----------- 2 files changed, 81 insertions(+), 127 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 1b61a46a1..c0241c09d 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -54,6 +54,7 @@ target_include_directories(${PLUGIN_NAME} INTERFACE target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mfplat.lib) +target_link_libraries(${PLUGIN_NAME} PRIVATE delayimp.lib) target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mfplat.dll") target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:mfreadwrite.dll") diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 2c43a4086..b6945fa92 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -10,8 +10,6 @@ #include #include -#include -#include #include "audioplayers_helpers.h" #define STR_LINK_TROUBLESHOOTING \ @@ -20,70 +18,6 @@ using namespace winrt; -// SEH C-wrapper functions to solve C2712 -HRESULT InitializeMediaFoundation_SEH(media::MediaEngineWrapper* wrapper) { - __try { - THROW_IF_FAILED(MFStartup(MF_VERSION, MFSTARTUP_FULL)); - wrapper->Initialize(); - } __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { - return exceptionCode; - } - return E_FAIL; - } - return S_OK; -} - -HRESULT CreateSourceFromUrl_SEH(std::string url, IMFMediaSource** ppMediaSource) { - __try { - winrt::com_ptr sourceResolver; - THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); - constexpr uint32_t sourceResolutionFlags = - MF_RESOLUTION_MEDIASOURCE | - MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | - MF_RESOLUTION_READ; - MF_OBJECT_TYPE objectType = {}; - THROW_IF_FAILED(sourceResolver->CreateObjectFromURL( - winrt::to_hstring(url).c_str(), sourceResolutionFlags, nullptr, - &objectType, reinterpret_cast(ppMediaSource))); - } __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { - return exceptionCode; - } - return E_FAIL; - } - return S_OK; -} - -HRESULT CreateSourceFromBytes_SEH(std::vector bytes, - IMFMediaSource** ppMediaSource) { - __try { - winrt::com_ptr sourceResolver; - THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); - constexpr uint32_t sourceResolutionFlags = - MF_RESOLUTION_MEDIASOURCE | - MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | - MF_RESOLUTION_READ; - MF_OBJECT_TYPE objectType = {}; - IStream* pstm = - SHCreateMemStream(bytes.data(), static_cast(bytes.size())); - IMFByteStream* stream = NULL; - THROW_IF_FAILED(MFCreateMFByteStreamOnStream(pstm, &stream)); - sourceResolver->CreateObjectFromByteStream( - stream, nullptr, sourceResolutionFlags, nullptr, &objectType, - reinterpret_cast(ppMediaSource)); - } __except (EXCEPTION_EXECUTE_HANDLER) { - DWORD exceptionCode = GetExceptionCode(); - if (exceptionCode == 0xC06D007E || exceptionCode == 0xC06D007F) { - return exceptionCode; - } - return E_FAIL; - } - return S_OK; -} - AudioPlayer::AudioPlayer( std::string playerId, flutter::MethodChannel* methodChannel, @@ -91,27 +25,39 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { - // Callbacks invoked by the media engine wrapper - auto onError = std::bind(&AudioPlayer::OnMediaError, this, - std::placeholders::_1, std::placeholders::_2); - auto onBufferingStateChanged = - std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); - auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); - auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); - auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - - // Create and initialize the MediaEngineWrapper which manages media playback - m_mediaEngineWrapper = winrt::make_self( - onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, - onSeekCompletedCB); - - HRESULT hr = InitializeMediaFoundation_SEH(m_mediaEngineWrapper.get()); - if (FAILED(hr)) { - if (hr == 0xC06D007E || hr == 0xC06D007F) { + HMODULE hMfplat = LoadLibraryEx(L"Mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + HMODULE hMfreadwrite = LoadLibraryEx(L"mfreadwrite.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + + if (!hMfplat || !hMfreadwrite) { + m_mediaFoundationFailed = true; + if (hMfplat) FreeLibrary(hMfplat); + if (hMfreadwrite) FreeLibrary(hMfreadwrite); + return; + } + FreeLibrary(hMfplat); + FreeLibrary(hMfreadwrite); + + try { + m_mfPlatform.Startup(); + + // Callbacks invoked by the media engine wrapper + auto onError = std::bind(&AudioPlayer::OnMediaError, this, + std::placeholders::_1, std::placeholders::_2); + auto onBufferingStateChanged = + std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); + auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); + auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); + auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); + + // Create and initialize the MediaEngineWrapper which manages media playback + m_mediaEngineWrapper = winrt::make_self( + onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, + onSeekCompletedCB); + + m_mediaEngineWrapper->Initialize(); + } catch (...) { m_mediaFoundationFailed = true; } - return; - } } AudioPlayer::~AudioPlayer() {} @@ -131,22 +77,22 @@ void AudioPlayer::SetSourceUrl(std::string url) { _isInitialized = false; try { - winrt::com_ptr mediaSource; + // Create a source resolver to create an IMFMediaSource for the content + // URL. This will create an instance of an inbuilt OS media source for + // playback. An application can skip this step and instantiate a custom + // IMFMediaSource implementation instead. + winrt::com_ptr sourceResolver; + THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); + constexpr uint32_t sourceResolutionFlags = + MF_RESOLUTION_MEDIASOURCE | + MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | + MF_RESOLUTION_READ; + MF_OBJECT_TYPE objectType = {}; - HRESULT hr = CreateSourceFromUrl_SEH(url, mediaSource.put()); - - if (FAILED(hr)) { - if (hr == 0xC06D007E || hr == 0xC06D007F) { - m_mediaFoundationFailed = true; - this->OnError("WindowsAudioError", - "Media Feature Pack not found (delay-load failed).", - nullptr); - } else { - this->OnError("WindowsAudioError", "Failed to create source from URL.", - nullptr); - } - return; - } + winrt::com_ptr mediaSource; + THROW_IF_FAILED(sourceResolver->CreateObjectFromURL( + winrt::to_hstring(url).c_str(), sourceResolutionFlags, nullptr, + &objectType, reinterpret_cast(mediaSource.put_void()))); m_mediaEngineWrapper->SetMediaSource(mediaSource.get()); } catch (const std::exception& ex) { @@ -181,23 +127,24 @@ void AudioPlayer::SetSourceBytes(std::vector bytes) { size_t size = bytes.size(); try { + winrt::com_ptr sourceResolver; + THROW_IF_FAILED(MFCreateSourceResolver(sourceResolver.put())); + constexpr uint32_t sourceResolutionFlags = + MF_RESOLUTION_MEDIASOURCE | + MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | + MF_RESOLUTION_READ; + MF_OBJECT_TYPE objectType = {}; + winrt::com_ptr mediaSource; - HRESULT hr = CreateSourceFromBytes_SEH(bytes, mediaSource.put()); - - if (FAILED(hr)) { - if (hr == 0xC06D007E || hr == 0xC06D007F) { - m_mediaFoundationFailed = true; - this->OnError("WindowsAudioError", - "Media Feature Pack not found (delay-load failed).", - nullptr); - } else { - this->OnError("WindowsAudioError", "Failed to create source from bytes.", - nullptr); - } - return; - } + IStream* pstm = + SHCreateMemStream(bytes.data(), static_cast(size)); + IMFByteStream* stream = NULL; + MFCreateMFByteStreamOnStream(pstm, &stream); + sourceResolver->CreateObjectFromByteStream( + stream, nullptr, sourceResolutionFlags, nullptr, &objectType, + reinterpret_cast(mediaSource.put_void())); m_mediaEngineWrapper->SetMediaSource(mediaSource.get()); } catch (...) { // Forward errors to event stream, as this is called asynchronously @@ -266,6 +213,7 @@ void AudioPlayer::OnPlaybackEnded() { } void AudioPlayer::OnDurationUpdate() { + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; auto duration = m_mediaEngineWrapper->GetDuration(); if (this->_eventHandler) { this->_eventHandler->Success( @@ -299,7 +247,7 @@ void AudioPlayer::OnLog(const std::string& message) { } void AudioPlayer::SendInitialized() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; if (!this->_isInitialized) { this->_isInitialized = true; OnPrepared(true); @@ -308,7 +256,7 @@ void AudioPlayer::SendInitialized() { } void AudioPlayer::ReleaseMediaSource() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; if (_isInitialized) { m_mediaEngineWrapper->Pause(); } @@ -318,7 +266,12 @@ void AudioPlayer::ReleaseMediaSource() { } void AudioPlayer::Dispose() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) { + _methodChannel = nullptr; + _eventHandler = nullptr; + return; + } + ReleaseMediaSource(); m_mediaEngineWrapper->Shutdown(); _methodChannel = nullptr; @@ -326,7 +279,7 @@ void AudioPlayer::Dispose() { } void AudioPlayer::SetReleaseMode(ReleaseMode releaseMode) { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->SetLooping(releaseMode == ReleaseMode::loop); _releaseMode = releaseMode; } @@ -336,7 +289,7 @@ ReleaseMode AudioPlayer::GetReleaseMode() { } void AudioPlayer::SetVolume(double volume) { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; if (volume > 1) { volume = 1; @@ -347,28 +300,28 @@ void AudioPlayer::SetVolume(double volume) { } void AudioPlayer::SetPlaybackSpeed(double playbackSpeed) { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->SetPlaybackRate(playbackSpeed); } void AudioPlayer::SetBalance(double balance) { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->SetBalance(balance); } void AudioPlayer::Play() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->StartPlayingFrom(m_mediaEngineWrapper->GetMediaTime()); OnDurationUpdate(); } void AudioPlayer::Pause() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->Pause(); } void AudioPlayer::Stop() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; Pause(); if (GetReleaseMode() == ReleaseMode::release) { ReleaseMediaSource(); @@ -378,7 +331,7 @@ void AudioPlayer::Stop() { } void AudioPlayer::Resume() { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->Resume(); OnDurationUpdate(); } @@ -391,13 +344,13 @@ double AudioPlayer::GetPosition() { } double AudioPlayer::GetDuration() { - if (m_mediaFoundationFailed) { + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) { return std::numeric_limits::quiet_NaN(); } return m_mediaEngineWrapper->GetDuration(); } void AudioPlayer::SeekTo(double seek) { - if (m_mediaFoundationFailed) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; m_mediaEngineWrapper->SeekTo(seek); } From 1d50aa6b4b25c7f7ed39e41b055c4443f877ff56 Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 17:03:50 +0200 Subject: [PATCH 07/20] clang-formatted --- .../windows/audio_player.cpp | 107 +++++++++++------- 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index b6945fa92..934dbb058 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -25,39 +25,46 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { - HMODULE hMfplat = LoadLibraryEx(L"Mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - HMODULE hMfreadwrite = LoadLibraryEx(L"mfreadwrite.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - - if (!hMfplat || !hMfreadwrite) { - m_mediaFoundationFailed = true; - if (hMfplat) FreeLibrary(hMfplat); - if (hMfreadwrite) FreeLibrary(hMfreadwrite); - return; - } - FreeLibrary(hMfplat); - FreeLibrary(hMfreadwrite); + HMODULE hMfplat = + LoadLibraryEx(L"Mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + HMODULE hMfreadwrite = + LoadLibraryEx(L"mfreadwrite.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + + if (!hMfplat || !hMfreadwrite) { + m_mediaFoundationFailed = true; + if (hMfplat) + FreeLibrary(hMfplat); + if (hMfreadwrite) + FreeLibrary(hMfreadwrite); + return; + } + FreeLibrary(hMfplat); + FreeLibrary(hMfreadwrite); - try { - m_mfPlatform.Startup(); - - // Callbacks invoked by the media engine wrapper - auto onError = std::bind(&AudioPlayer::OnMediaError, this, - std::placeholders::_1, std::placeholders::_2); - auto onBufferingStateChanged = - std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); - auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); - auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); - auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - - // Create and initialize the MediaEngineWrapper which manages media playback - m_mediaEngineWrapper = winrt::make_self( - onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, - onSeekCompletedCB); - - m_mediaEngineWrapper->Initialize(); - } catch (...) { - m_mediaFoundationFailed = true; - } + try { + m_mfPlatform.Startup(); + + // Callbacks invoked by the media engine wrapper + auto onError = + std::bind(&AudioPlayer::OnMediaError, this, std::placeholders::_1, + std::placeholders::_2); + auto onBufferingStateChanged = + std::bind(&AudioPlayer::OnMediaStateChange, this, + std::placeholders::_1); + auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); + auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); + auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); + + // Create and initialize the MediaEngineWrapper which manages media + // playback + m_mediaEngineWrapper = winrt::make_self( + onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB, + onSeekCompletedCB); + + m_mediaEngineWrapper->Initialize(); + } catch (...) { + m_mediaFoundationFailed = true; + } } AudioPlayer::~AudioPlayer() {} @@ -213,7 +220,8 @@ void AudioPlayer::OnPlaybackEnded() { } void AudioPlayer::OnDurationUpdate() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; auto duration = m_mediaEngineWrapper->GetDuration(); if (this->_eventHandler) { this->_eventHandler->Success( @@ -247,7 +255,8 @@ void AudioPlayer::OnLog(const std::string& message) { } void AudioPlayer::SendInitialized() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; if (!this->_isInitialized) { this->_isInitialized = true; OnPrepared(true); @@ -256,7 +265,8 @@ void AudioPlayer::SendInitialized() { } void AudioPlayer::ReleaseMediaSource() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; if (_isInitialized) { m_mediaEngineWrapper->Pause(); } @@ -279,7 +289,8 @@ void AudioPlayer::Dispose() { } void AudioPlayer::SetReleaseMode(ReleaseMode releaseMode) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->SetLooping(releaseMode == ReleaseMode::loop); _releaseMode = releaseMode; } @@ -289,7 +300,8 @@ ReleaseMode AudioPlayer::GetReleaseMode() { } void AudioPlayer::SetVolume(double volume) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; if (volume > 1) { volume = 1; @@ -300,28 +312,33 @@ void AudioPlayer::SetVolume(double volume) { } void AudioPlayer::SetPlaybackSpeed(double playbackSpeed) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->SetPlaybackRate(playbackSpeed); } void AudioPlayer::SetBalance(double balance) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->SetBalance(balance); } void AudioPlayer::Play() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->StartPlayingFrom(m_mediaEngineWrapper->GetMediaTime()); OnDurationUpdate(); } void AudioPlayer::Pause() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->Pause(); } void AudioPlayer::Stop() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; Pause(); if (GetReleaseMode() == ReleaseMode::release) { ReleaseMediaSource(); @@ -331,7 +348,8 @@ void AudioPlayer::Stop() { } void AudioPlayer::Resume() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->Resume(); OnDurationUpdate(); } @@ -351,6 +369,7 @@ double AudioPlayer::GetDuration() { } void AudioPlayer::SeekTo(double seek) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) return; + if (m_mediaFoundationFailed || !m_mediaEngineWrapper) + return; m_mediaEngineWrapper->SeekTo(seek); } From d6b227942817d46078daf837d2e64f2f6e785fdb Mon Sep 17 00:00:00 2001 From: krll-kov <63228361+krll-kov@users.noreply.github.com> Date: Tue, 21 Oct 2025 17:12:58 +0200 Subject: [PATCH 08/20] clang-formatted --- packages/audioplayers_windows/windows/audio_player.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 934dbb058..3914adcea 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -45,12 +45,10 @@ AudioPlayer::AudioPlayer( m_mfPlatform.Startup(); // Callbacks invoked by the media engine wrapper - auto onError = - std::bind(&AudioPlayer::OnMediaError, this, std::placeholders::_1, - std::placeholders::_2); - auto onBufferingStateChanged = - std::bind(&AudioPlayer::OnMediaStateChange, this, - std::placeholders::_1); + auto onError = std::bind(&AudioPlayer::OnMediaError, this, + std::placeholders::_1, std::placeholders::_2); + auto onBufferingStateChanged = std::bind(&AudioPlayer::OnMediaStateChange, + this, std::placeholders::_1); auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); From 1efadb87181b7f38342e5147547d652b7ac546fa Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Fri, 22 May 2026 15:57:07 +0200 Subject: [PATCH 09/20] Update WIL version to 1.0.260126.7 Fixed this issue: https://github.com/bluefireteam/audioplayers/issues/1985 --- packages/audioplayers_windows/windows/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index c0241c09d..7df19d85e 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) set(PROJECT_NAME "audioplayers_windows") -set(WIL_VERSION "1.0.210803.1") +set(WIL_VERSION "1.0.260126.7") project(${PROJECT_NAME} LANGUAGES CXX) include(FetchContent) From 5f48550a986893058bafc1077cb4787f342edb86 Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Sat, 23 May 2026 05:40:38 +0200 Subject: [PATCH 10/20] Restore WIL version in CMakeLists.txt (New version makes plugin a malware on VirusTotal (False positive)) --- packages/audioplayers_windows/windows/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 7df19d85e..c0241c09d 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) set(PROJECT_NAME "audioplayers_windows") -set(WIL_VERSION "1.0.260126.7") +set(WIL_VERSION "1.0.210803.1") project(${PROJECT_NAME} LANGUAGES CXX) include(FetchContent) From 25c988fc2f24c462faa5ebcd606c23be190aa0bf Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Sun, 21 Jun 2026 13:20:43 +0200 Subject: [PATCH 11/20] Restore WIL version in CMakeLists.txt (New version makes plugin a malware on VirusTotal (False positive)) --- packages/audioplayers_windows/windows/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index ff96d7dc3..29c375aec 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.15) set(PROJECT_NAME "audioplayers_windows") cmake_policy(VERSION 3.15...3.24) -set(WIL_VERSION "1.0.260126.7") +set(WIL_VERSION "1.0.210803.1") project(${PROJECT_NAME} LANGUAGES CXX) include(FetchContent) @@ -57,7 +57,6 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mfplat.lib) target_link_libraries(${PLUGIN_NAME} PRIVATE delayimp.lib) target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mfplat.dll") -target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:mfreadwrite.dll") # List of absolute paths to libraries that should be bundled with the plugin set(audioplayers_windows_bundled_libraries From 0b7ea815f6a4fe03d06c1c94cdf3d503a7fc9f83 Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:28:44 +0200 Subject: [PATCH 12/20] Temporary sync pubspeck with original repo --- packages/audioplayers_windows/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/audioplayers_windows/pubspec.yaml b/packages/audioplayers_windows/pubspec.yaml index 750caed2c..eac71d7ae 100644 --- a/packages/audioplayers_windows/pubspec.yaml +++ b/packages/audioplayers_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: audioplayers_windows resolution: workspace description: Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously -version: 4.3.2 +version: 4.4.0 homepage: https://github.com/bluefireteam/audioplayers repository: https://github.com/bluefireteam/audioplayers/tree/master/packages/audioplayers_windows @@ -13,7 +13,7 @@ flutter: pluginClass: AudioplayersWindowsPlugin dependencies: - audioplayers_platform_interface: ^7.1.1 + audioplayers_platform_interface: ^7.2.0 flutter: sdk: flutter From 227c77d825962ef7f40f65e2b3a9885704961dd1 Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:29:35 +0200 Subject: [PATCH 13/20] Temporary sync pubspeck with original repo --- packages/audioplayers_windows/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/audioplayers_windows/CHANGELOG.md b/packages/audioplayers_windows/CHANGELOG.md index 9cd2ffb16..93d664c7f 100644 --- a/packages/audioplayers_windows/CHANGELOG.md +++ b/packages/audioplayers_windows/CHANGELOG.md @@ -1,7 +1,7 @@ +## 4.4.0 -## 4.3.2 - -- **FIX**: Fixed app crash on startup on Windows with missing Media Feature Pack + - **FIX**(windows): Update to C++23 & Windows Implementation Lib ([#2004](https://github.com/bluefireteam/audioplayers/issues/2004)). ([faa84312](https://github.com/bluefireteam/audioplayers/commit/faa843121c89625a5469dd517d39aae3a50cd1b8)) + - **FEAT**(android): Compatibility with Built-In Kotlin ([#1991](https://github.com/bluefireteam/audioplayers/issues/1991)). ([687218b9](https://github.com/bluefireteam/audioplayers/commit/687218b96682a7bcadd9490572db692dbc9a2f07)) ## 4.3.1 From 8b0aa0af966af481dc705c95dfbe467ff2d63240 Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:30:26 +0200 Subject: [PATCH 14/20] Bump version from 4.4.0 to 4.5.0 --- packages/audioplayers_windows/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/audioplayers_windows/pubspec.yaml b/packages/audioplayers_windows/pubspec.yaml index eac71d7ae..7249c1967 100644 --- a/packages/audioplayers_windows/pubspec.yaml +++ b/packages/audioplayers_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: audioplayers_windows resolution: workspace description: Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously -version: 4.4.0 +version: 4.5.0 homepage: https://github.com/bluefireteam/audioplayers repository: https://github.com/bluefireteam/audioplayers/tree/master/packages/audioplayers_windows From b9e52c8d45293057c2225f3f18a312dd74ea8c32 Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:32:41 +0200 Subject: [PATCH 15/20] Add changelog entry for version 4.5.0 --- packages/audioplayers_windows/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/audioplayers_windows/CHANGELOG.md b/packages/audioplayers_windows/CHANGELOG.md index 93d664c7f..1b9307d08 100644 --- a/packages/audioplayers_windows/CHANGELOG.md +++ b/packages/audioplayers_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.5.0 + +- **FIX**: Fixed app crash on startup on Windows with missing Media Feature Pack + ## 4.4.0 - **FIX**(windows): Update to C++23 & Windows Implementation Lib ([#2004](https://github.com/bluefireteam/audioplayers/issues/2004)). ([faa84312](https://github.com/bluefireteam/audioplayers/commit/faa843121c89625a5469dd517d39aae3a50cd1b8)) From 2c3a1c0bfeb6c9dd3bea5aa3c968b0fbe43fccf8 Mon Sep 17 00:00:00 2001 From: "Kyrylo K." <63228361+krll-kov@users.noreply.github.com> Date: Sat, 27 Jun 2026 16:15:48 +0200 Subject: [PATCH 16/20] temporary downgrade version from 4.5.0 to 4.4.0 --- packages/audioplayers_windows/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/audioplayers_windows/pubspec.yaml b/packages/audioplayers_windows/pubspec.yaml index 7249c1967..eac71d7ae 100644 --- a/packages/audioplayers_windows/pubspec.yaml +++ b/packages/audioplayers_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: audioplayers_windows resolution: workspace description: Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously -version: 4.5.0 +version: 4.4.0 homepage: https://github.com/bluefireteam/audioplayers repository: https://github.com/bluefireteam/audioplayers/tree/master/packages/audioplayers_windows From f94f16ff6fc0240137a4d158260a4c98c1c35b2f Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Wed, 22 Jul 2026 21:23:12 +0200 Subject: [PATCH 17/20] improvements --- .../windows/CMakeLists.txt | 2 +- .../windows/audio_player.cpp | 106 +++--------------- .../windows/audioplayers_windows_plugin.cpp | 55 ++++++++- 3 files changed, 68 insertions(+), 95 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index d790df376..387c498ec 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.15) set(PROJECT_NAME "audioplayers_windows") cmake_policy(VERSION 3.15...3.24) -set(WIL_VERSION "1.0.210803.1") +set(WIL_VERSION "1.0.260126.7") project(${PROJECT_NAME} LANGUAGES CXX) include(FetchContent) diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index e68663070..56b5f27a8 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -25,60 +25,32 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { - HMODULE hMfplat = - LoadLibraryEx(L"Mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - HMODULE hMfreadwrite = - LoadLibraryEx(L"mfreadwrite.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - - if (!hMfplat || !hMfreadwrite) { - m_mediaFoundationFailed = true; - if (hMfplat) - FreeLibrary(hMfplat); - if (hMfreadwrite) - FreeLibrary(hMfreadwrite); - return; - } - FreeLibrary(hMfplat); - FreeLibrary(hMfreadwrite); - - try { m_mfPlatform.Startup(); - // Callbacks invoked by the media engine wrapper - auto onError = std::bind(&AudioPlayer::OnMediaError, this, - std::placeholders::_1, std::placeholders::_2); - auto onBufferingStateChanged = std::bind(&AudioPlayer::OnMediaStateChange, - this, std::placeholders::_1); - auto onPlayingStateUpdateCB = std::bind(&AudioPlayer::OnPlayingStateUpdate, + // Callbacks invoked by the media engine wrapper + auto onError = std::bind(&AudioPlayer::OnMediaError, this, + std::placeholders::_1, std::placeholders::_2); + auto onBufferingStateChanged = std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); - auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); - auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); - auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - - // Create and initialize the MediaEngineWrapper which manages media - // playback - m_mediaEngineWrapper = winrt::make_self( - onLoadedCB, onError, onBufferingStateChanged, onPlayingStateUpdateCB, - onPlaybackEndedCB, onSeekCompletedCB); - - m_mediaEngineWrapper->Initialize(); - } catch (...) { - m_mediaFoundationFailed = true; - } + auto onPlayingStateUpdateCB = std::bind(&AudioPlayer::OnPlayingStateUpdate, + this, std::placeholders::_1); + auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); + auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); + auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); + + // Create and initialize the MediaEngineWrapper which manages media + // playback + m_mediaEngineWrapper = winrt::make_self( + onLoadedCB, onError, onBufferingStateChanged, onPlayingStateUpdateCB, + onPlaybackEndedCB, onSeekCompletedCB); + + m_mediaEngineWrapper->Initialize(); } AudioPlayer::~AudioPlayer() {} // This method should be called asynchronously, to avoid freezing UI void AudioPlayer::SetSourceUrl(std::string url) { - if (m_mediaFoundationFailed) { - this->OnError("WindowsAudioError", - "Media Feature Pack not found. Please install it from " - "Windows Settings > Optional Features.", - nullptr); - return; - } - if (_url != url) { _url = url; _isInitialized = false; @@ -121,14 +93,6 @@ void AudioPlayer::SetSourceUrl(std::string url) { } void AudioPlayer::SetSourceBytes(std::vector bytes) { - if (m_mediaFoundationFailed) { - this->OnError("WindowsAudioError", - "Media Feature Pack not found. Please install it from " - "Windows Settings > Optional Features.", - nullptr); - return; - } - _isInitialized = false; _url.clear(); size_t size = bytes.size(); @@ -235,8 +199,6 @@ void AudioPlayer::OnPlaybackEnded() { } void AudioPlayer::OnDurationUpdate() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; auto duration = m_mediaEngineWrapper->GetDuration(); if (this->_eventHandler) { this->_eventHandler->Success( @@ -270,8 +232,6 @@ void AudioPlayer::OnLog(const std::string& message) { } void AudioPlayer::SendInitialized() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; if (!this->_isInitialized) { this->_isInitialized = true; OnPrepared(true); @@ -280,8 +240,6 @@ void AudioPlayer::SendInitialized() { } void AudioPlayer::ReleaseMediaSource() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; if (_isInitialized) { m_mediaEngineWrapper->Pause(); } @@ -291,12 +249,6 @@ void AudioPlayer::ReleaseMediaSource() { } void AudioPlayer::Dispose() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) { - _methodChannel = nullptr; - _eventHandler = nullptr; - return; - } - ReleaseMediaSource(); m_mediaEngineWrapper->Shutdown(); _methodChannel = nullptr; @@ -304,8 +256,6 @@ void AudioPlayer::Dispose() { } void AudioPlayer::SetReleaseMode(ReleaseMode releaseMode) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->SetLooping(releaseMode == ReleaseMode::loop); _releaseMode = releaseMode; } @@ -315,9 +265,6 @@ ReleaseMode AudioPlayer::GetReleaseMode() { } void AudioPlayer::SetVolume(double volume) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; - if (volume > 1) { volume = 1; } else if (volume < 0) { @@ -327,60 +274,43 @@ void AudioPlayer::SetVolume(double volume) { } void AudioPlayer::SetPlaybackSpeed(double playbackSpeed) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->SetPlaybackRate(playbackSpeed); } void AudioPlayer::SetBalance(double balance) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->SetBalance(balance); } void AudioPlayer::Play() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->StartPlayingFrom(m_mediaEngineWrapper->GetMediaTime()); OnDurationUpdate(); } void AudioPlayer::Pause() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->Pause(); } void AudioPlayer::Stop() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; Pause(); SeekTo(0); } void AudioPlayer::Resume() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->Resume(); OnDurationUpdate(); } double AudioPlayer::GetPosition() { - if (m_mediaFoundationFailed || !_isInitialized) { + if (!_isInitialized) { return std::numeric_limits::quiet_NaN(); } return m_mediaEngineWrapper->GetMediaTime(); } double AudioPlayer::GetDuration() { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) { - return std::numeric_limits::quiet_NaN(); - } return m_mediaEngineWrapper->GetDuration(); } void AudioPlayer::SeekTo(double seek) { - if (m_mediaFoundationFailed || !m_mediaEngineWrapper) - return; m_mediaEngineWrapper->SeekTo(seek); } diff --git a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp index 03631988a..2610b7ab4 100644 --- a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp +++ b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp @@ -75,6 +75,10 @@ class AudioplayersWindowsPlugin : public Plugin { AudioPlayer* GetPlayer(std::string playerId); void OnGlobalLog(const std::string& message); + + bool isMediaPackSupported = false; + + void CheckMediaPackSupport(); }; // static @@ -118,12 +122,34 @@ AudioplayersWindowsPlugin::AudioplayersWindowsPlugin() {} AudioplayersWindowsPlugin::~AudioplayersWindowsPlugin() {} +// Test if on Windows N without Media Feature Pack installed +void AudioplayersWindowsPlugin::CheckMediaPackSupport() { + HMODULE hMfplat = + LoadLibraryEx(L"Mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + HMODULE hMfreadwrite = + LoadLibraryEx(L"mfreadwrite.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + isMediaPackSupported = hMfplat && hMfreadwrite; + if (hMfplat) + FreeLibrary(hMfplat); + if (hMfreadwrite) + FreeLibrary(hMfreadwrite); +} + void AudioplayersWindowsPlugin::HandleGlobalMethodCall( const MethodCall& method_call, std::unique_ptr> result) { auto args = method_call.arguments(); if (method_call.method_name().compare("init") == 0) { + CheckMediaPackSupport(); + if (!isMediaPackSupported) { + // Just log without returning an error: the global channel works fine nontheless. + if (globalEvents) { + globalEvents->Error("WindowsAudioError", "Media Feature Pack not found. Please install it from " + "Windows Settings > Optional Features.", nullptr); + } + } + for (const auto& entry : audioPlayers) { entry.second->Dispose(); } @@ -151,6 +177,7 @@ void AudioplayersWindowsPlugin::HandleGlobalMethodCall( void AudioplayersWindowsPlugin::HandleMethodCall( const MethodCall& method_call, std::unique_ptr> result) { + auto args = method_call.arguments(); auto playerId = GetArgument("playerId", args, std::string()); @@ -168,9 +195,23 @@ void AudioplayersWindowsPlugin::HandleMethodCall( auto player = GetPlayer(playerId); if (!player) { - result->Error( - "WindowsAudioError", - "Player has not yet been created or has already been disposed."); + if (method_call.method_name().compare("dispose") == 0) { + // If no player is available, still can dispose the event channel, + // e.g. when isMediaPackSupported is false. + playerEventChannels.erase(playerId); + result->Success(); + return; + } + if (isMediaPackSupported) { + result->Error( + "WindowsAudioError", + "Player has not yet been created or has already been disposed."); + } else { + result->Error( + "WindowsAudioError", + "Media Feature Pack not found. Please install it from " + "Windows Settings > Optional Features."); + } return; } @@ -275,9 +316,11 @@ void AudioplayersWindowsPlugin::CreatePlayer(std::string playerId) { EventStreamHandler* eventHandlerPtr = eventHandler.get(); eventChannel->SetStreamHandler(std::move(eventHandler)); - auto player = - std::make_unique(playerId, methods.get(), eventHandlerPtr); - audioPlayers.insert(std::make_pair(playerId, std::move(player))); + if (isMediaPackSupported) { + auto player = + std::make_unique(playerId, methods.get(), eventHandlerPtr); + audioPlayers.insert(std::make_pair(playerId, std::move(player))); + } // Keep the event channel and handler alive as long as the plugin/player // exists From 8b5f7b7fd0e51dba5c054acb08d4318761c4ed15 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Wed, 22 Jul 2026 21:43:49 +0200 Subject: [PATCH 18/20] format --- packages/audioplayers_windows/CHANGELOG.md | 4 ---- packages/audioplayers_windows/pubspec.yaml | 2 +- .../windows/audio_player.cpp | 8 ++++---- .../windows/audioplayers_windows_plugin.cpp | 20 ++++++++++--------- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/audioplayers_windows/CHANGELOG.md b/packages/audioplayers_windows/CHANGELOG.md index 5a1839e37..965cecd8b 100644 --- a/packages/audioplayers_windows/CHANGELOG.md +++ b/packages/audioplayers_windows/CHANGELOG.md @@ -1,7 +1,3 @@ -## 4.5.0 - -- **FIX**: Fixed app crash on startup on Windows with missing Media Feature Pack - ## 4.4.1 - **FIX**(windows): Compatibility with Visual Studio 18 (2026) ([#2011](https://github.com/bluefireteam/audioplayers/issues/2011)). ([ae5f4b96](https://github.com/bluefireteam/audioplayers/commit/ae5f4b965ef886f08b903a7a9386bc283db458c5))\ diff --git a/packages/audioplayers_windows/pubspec.yaml b/packages/audioplayers_windows/pubspec.yaml index 7249c1967..599a372d4 100644 --- a/packages/audioplayers_windows/pubspec.yaml +++ b/packages/audioplayers_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: audioplayers_windows resolution: workspace description: Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously -version: 4.5.0 +version: 4.4.1 homepage: https://github.com/bluefireteam/audioplayers repository: https://github.com/bluefireteam/audioplayers/tree/master/packages/audioplayers_windows diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 56b5f27a8..8b3848b5c 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -25,13 +25,13 @@ AudioPlayer::AudioPlayer( : _playerId(playerId), _methodChannel(methodChannel), _eventHandler(eventHandler) { - m_mfPlatform.Startup(); + m_mfPlatform.Startup(); // Callbacks invoked by the media engine wrapper auto onError = std::bind(&AudioPlayer::OnMediaError, this, - std::placeholders::_1, std::placeholders::_2); - auto onBufferingStateChanged = std::bind(&AudioPlayer::OnMediaStateChange, - this, std::placeholders::_1); + std::placeholders::_1, std::placeholders::_2); + auto onBufferingStateChanged = + std::bind(&AudioPlayer::OnMediaStateChange, this, std::placeholders::_1); auto onPlayingStateUpdateCB = std::bind(&AudioPlayer::OnPlayingStateUpdate, this, std::placeholders::_1); auto onPlaybackEndedCB = std::bind(&AudioPlayer::OnPlaybackEnded, this); diff --git a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp index 2610b7ab4..7d4b8a7ad 100644 --- a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp +++ b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp @@ -133,7 +133,7 @@ void AudioplayersWindowsPlugin::CheckMediaPackSupport() { FreeLibrary(hMfplat); if (hMfreadwrite) FreeLibrary(hMfreadwrite); -} +} void AudioplayersWindowsPlugin::HandleGlobalMethodCall( const MethodCall& method_call, @@ -143,10 +143,14 @@ void AudioplayersWindowsPlugin::HandleGlobalMethodCall( if (method_call.method_name().compare("init") == 0) { CheckMediaPackSupport(); if (!isMediaPackSupported) { - // Just log without returning an error: the global channel works fine nontheless. + // Just log without returning an error: the global channel works fine + // nontheless. if (globalEvents) { - globalEvents->Error("WindowsAudioError", "Media Feature Pack not found. Please install it from " - "Windows Settings > Optional Features.", nullptr); + globalEvents->Error( + "WindowsAudioError", + "Media Feature Pack not found. Please install it from " + "Windows Settings > Optional Features.", + nullptr); } } @@ -177,7 +181,6 @@ void AudioplayersWindowsPlugin::HandleGlobalMethodCall( void AudioplayersWindowsPlugin::HandleMethodCall( const MethodCall& method_call, std::unique_ptr> result) { - auto args = method_call.arguments(); auto playerId = GetArgument("playerId", args, std::string()); @@ -207,10 +210,9 @@ void AudioplayersWindowsPlugin::HandleMethodCall( "WindowsAudioError", "Player has not yet been created or has already been disposed."); } else { - result->Error( - "WindowsAudioError", - "Media Feature Pack not found. Please install it from " - "Windows Settings > Optional Features."); + result->Error("WindowsAudioError", + "Media Feature Pack not found. Please install it from " + "Windows Settings > Optional Features."); } return; } From 79623d75a2b6082fd7fb47ff68eb0132bee437de Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Wed, 22 Jul 2026 21:49:46 +0200 Subject: [PATCH 19/20] rename --- .../windows/CMakeLists.txt | 4 ++-- .../windows/audio_player.cpp | 3 +-- .../windows/audio_player.h | 1 - .../windows/audioplayers_windows_plugin.cpp | 18 +++++++++--------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 387c498ec..3c12417ef 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -54,9 +54,9 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mfplat.lib) +target_link_libraries(${PLUGIN_NAME} PRIVATE shlwapi Mfplat) -target_link_libraries(${PLUGIN_NAME} PRIVATE delayimp.lib) +target_link_libraries(${PLUGIN_NAME} PRIVATE delayimp) target_link_options(${PLUGIN_NAME} PRIVATE "/DELAYLOAD:Mfplat.dll") # List of absolute paths to libraries that should be bundled with the plugin diff --git a/packages/audioplayers_windows/windows/audio_player.cpp b/packages/audioplayers_windows/windows/audio_player.cpp index 8b3848b5c..c4bbac4cd 100644 --- a/packages/audioplayers_windows/windows/audio_player.cpp +++ b/packages/audioplayers_windows/windows/audio_player.cpp @@ -38,8 +38,7 @@ AudioPlayer::AudioPlayer( auto onSeekCompletedCB = std::bind(&AudioPlayer::OnSeekCompleted, this); auto onLoadedCB = std::bind(&AudioPlayer::SendInitialized, this); - // Create and initialize the MediaEngineWrapper which manages media - // playback + // Create and initialize the MediaEngineWrapper which manages media playback m_mediaEngineWrapper = winrt::make_self( onLoadedCB, onError, onBufferingStateChanged, onPlayingStateUpdateCB, onPlaybackEndedCB, onSeekCompletedCB); diff --git a/packages/audioplayers_windows/windows/audio_player.h b/packages/audioplayers_windows/windows/audio_player.h index 46cde1cc1..22b49f633 100644 --- a/packages/audioplayers_windows/windows/audio_player.h +++ b/packages/audioplayers_windows/windows/audio_player.h @@ -106,7 +106,6 @@ class AudioPlayer { winrt::com_ptr m_mediaEngineWrapper; bool _isInitialized = false; - bool m_mediaFoundationFailed = false; ReleaseMode _releaseMode = ReleaseMode::release; std::string _url{}; diff --git a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp index 7d4b8a7ad..fdb1a0910 100644 --- a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp +++ b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp @@ -76,9 +76,9 @@ class AudioplayersWindowsPlugin : public Plugin { void OnGlobalLog(const std::string& message); - bool isMediaPackSupported = false; + bool isMediaFoundationSupported = false; - void CheckMediaPackSupport(); + void CheckMediaFoundationSupport(); }; // static @@ -123,12 +123,12 @@ AudioplayersWindowsPlugin::AudioplayersWindowsPlugin() {} AudioplayersWindowsPlugin::~AudioplayersWindowsPlugin() {} // Test if on Windows N without Media Feature Pack installed -void AudioplayersWindowsPlugin::CheckMediaPackSupport() { +void AudioplayersWindowsPlugin::CheckMediaFoundationSupport() { HMODULE hMfplat = LoadLibraryEx(L"Mfplat.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); HMODULE hMfreadwrite = LoadLibraryEx(L"mfreadwrite.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - isMediaPackSupported = hMfplat && hMfreadwrite; + isMediaFoundationSupported = hMfplat && hMfreadwrite; if (hMfplat) FreeLibrary(hMfplat); if (hMfreadwrite) @@ -141,8 +141,8 @@ void AudioplayersWindowsPlugin::HandleGlobalMethodCall( auto args = method_call.arguments(); if (method_call.method_name().compare("init") == 0) { - CheckMediaPackSupport(); - if (!isMediaPackSupported) { + CheckMediaFoundationSupport(); + if (!isMediaFoundationSupported) { // Just log without returning an error: the global channel works fine // nontheless. if (globalEvents) { @@ -200,12 +200,12 @@ void AudioplayersWindowsPlugin::HandleMethodCall( if (!player) { if (method_call.method_name().compare("dispose") == 0) { // If no player is available, still can dispose the event channel, - // e.g. when isMediaPackSupported is false. + // e.g. when isMediaFoundationSupported is false. playerEventChannels.erase(playerId); result->Success(); return; } - if (isMediaPackSupported) { + if (isMediaFoundationSupported) { result->Error( "WindowsAudioError", "Player has not yet been created or has already been disposed."); @@ -318,7 +318,7 @@ void AudioplayersWindowsPlugin::CreatePlayer(std::string playerId) { EventStreamHandler* eventHandlerPtr = eventHandler.get(); eventChannel->SetStreamHandler(std::move(eventHandler)); - if (isMediaPackSupported) { + if (isMediaFoundationSupported) { auto player = std::make_unique(playerId, methods.get(), eventHandlerPtr); audioPlayers.insert(std::make_pair(playerId, std::move(player))); From 1dab3825cba3b21fd2fe2ec0cf333271da6c49e6 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Wed, 22 Jul 2026 23:18:30 +0200 Subject: [PATCH 20/20] fix platform tests --- .../audioplayers/example/integration_test/platform_test.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/audioplayers/example/integration_test/platform_test.dart b/packages/audioplayers/example/integration_test/platform_test.dart index 69b3ac68c..beb264573 100644 --- a/packages/audioplayers/example/integration_test/platform_test.dart +++ b/packages/audioplayers/example/integration_test/platform_test.dart @@ -35,6 +35,9 @@ void main() async { isAndroid && await PlatformFeatures.usesAndroidMediaPlayerImpl(); final audioTestDataList = await getAudioTestDataList(); + // Ensure global platform scope is initialized. + await AudioPlayer.global.ensureInitialized(); + group('Platform method channel', () { late AudioplayersPlatformInterface platform; late String playerId;