Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/audioplayers_windows/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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))
Expand Down
2 changes: 1 addition & 1 deletion packages/audioplayers_windows/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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

Expand Down
8 changes: 6 additions & 2 deletions packages/audioplayers_windows/windows/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ 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
"${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.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
Expand Down
107 changes: 89 additions & 18 deletions packages/audioplayers_windows/windows/audio_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,58 @@ AudioPlayer::AudioPlayer(
: _playerId(playerId),
_methodChannel(methodChannel),
_eventHandler(eventHandler) {
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<media::MediaEngineWrapper>(
onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB,
onSeekCompletedCB);

m_mediaEngineWrapper->Initialize();
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<media::MediaEngineWrapper>(
onLoadedCB, onError, onBufferingStateChanged, onPlaybackEndedCB,
onSeekCompletedCB);

m_mediaEngineWrapper->Initialize();
} catch (...) {
m_mediaFoundationFailed = true;
}
}

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;
Expand Down Expand Up @@ -90,6 +119,14 @@ void AudioPlayer::SetSourceUrl(std::string url) {
}

void AudioPlayer::SetSourceBytes(std::vector<uint8_t> 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();
Expand Down Expand Up @@ -181,6 +218,8 @@ void AudioPlayer::OnPlaybackEnded() {
}

void AudioPlayer::OnDurationUpdate() {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;
auto duration = m_mediaEngineWrapper->GetDuration();
if (this->_eventHandler) {
this->_eventHandler->Success(
Expand Down Expand Up @@ -214,6 +253,8 @@ void AudioPlayer::OnLog(const std::string& message) {
}

void AudioPlayer::SendInitialized() {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;
if (!this->_isInitialized) {
this->_isInitialized = true;
OnPrepared(true);
Expand All @@ -222,6 +263,8 @@ void AudioPlayer::SendInitialized() {
}

void AudioPlayer::ReleaseMediaSource() {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;
if (_isInitialized) {
m_mediaEngineWrapper->Pause();
}
Expand All @@ -231,13 +274,21 @@ void AudioPlayer::ReleaseMediaSource() {
}

void AudioPlayer::Dispose() {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper) {
_methodChannel = nullptr;
_eventHandler = nullptr;
return;
}

ReleaseMediaSource();
m_mediaEngineWrapper->Shutdown();
_methodChannel = nullptr;
_eventHandler = nullptr;
}

void AudioPlayer::SetReleaseMode(ReleaseMode releaseMode) {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;
m_mediaEngineWrapper->SetLooping(releaseMode == ReleaseMode::loop);
_releaseMode = releaseMode;
}
Expand All @@ -247,6 +298,9 @@ ReleaseMode AudioPlayer::GetReleaseMode() {
}

void AudioPlayer::SetVolume(double volume) {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;

if (volume > 1) {
volume = 1;
} else if (volume < 0) {
Expand All @@ -256,23 +310,33 @@ 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();
if (GetReleaseMode() == ReleaseMode::release) {
ReleaseMediaSource();
Expand All @@ -282,21 +346,28 @@ void AudioPlayer::Stop() {
}

void AudioPlayer::Resume() {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;
m_mediaEngineWrapper->Resume();
OnDurationUpdate();
}

double AudioPlayer::GetPosition() {
if (!_isInitialized) {
if (m_mediaFoundationFailed || !_isInitialized) {
return std::numeric_limits<double>::quiet_NaN();
}
return m_mediaEngineWrapper->GetMediaTime();
}

double AudioPlayer::GetDuration() {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper) {
return std::numeric_limits<double>::quiet_NaN();
}
return m_mediaEngineWrapper->GetDuration();
}

void AudioPlayer::SeekTo(double seek) {
if (m_mediaFoundationFailed || !m_mediaEngineWrapper)
return;
m_mediaEngineWrapper->SeekTo(seek);
}
1 change: 1 addition & 0 deletions packages/audioplayers_windows/windows/audio_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class AudioPlayer {
winrt::com_ptr<media::MediaEngineWrapper> m_mediaEngineWrapper;

bool _isInitialized = false;
bool m_mediaFoundationFailed = false;
ReleaseMode _releaseMode = ReleaseMode::release;
std::string _url{};

Expand Down
Loading