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; diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt index 2707ad29d..3c12417ef 100644 --- a/packages/audioplayers_windows/windows/CMakeLists.txt +++ b/packages/audioplayers_windows/windows/CMakeLists.txt @@ -48,13 +48,16 @@ set_target_properties(${PLUGIN_NAME} PROPERTIES target_compile_features(${PLUGIN_NAME} PRIVATE cxx_std_20) 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 "${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 Mfplat) + +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 set(audioplayers_windows_bundled_libraries diff --git a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp index 03631988a..fdb1a0910 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 isMediaFoundationSupported = false; + + void CheckMediaFoundationSupport(); }; // static @@ -118,12 +122,38 @@ AudioplayersWindowsPlugin::AudioplayersWindowsPlugin() {} AudioplayersWindowsPlugin::~AudioplayersWindowsPlugin() {} +// Test if on Windows N without Media Feature Pack installed +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); + isMediaFoundationSupported = 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) { + CheckMediaFoundationSupport(); + if (!isMediaFoundationSupported) { + // 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(); } @@ -168,9 +198,22 @@ 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 isMediaFoundationSupported is false. + playerEventChannels.erase(playerId); + result->Success(); + return; + } + if (isMediaFoundationSupported) { + 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 +318,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 (isMediaFoundationSupported) { + 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