diff --git a/feature_parity_table.md b/feature_parity_table.md
index 0f55fdd71..b1a605d25 100644
--- a/feature_parity_table.md
+++ b/feature_parity_table.md
@@ -31,7 +31,7 @@ Note: LLM means Low Latency Mode.
local asset | yes | yes | yes | yes | yes | yes |
external URL file | yes | yes | yes | yes | yes | yes |
external URL stream | yes | yes | yes | yes | yes | yes |
- byte array | SDK >=23 | not yet | not yet | not yet | not yet | not yet |
+ byte array | SDK >=23 | not yet | not yet | not yet | yes | not yet |
Audio Config |
set url | yes | yes | yes | yes | yes | yes |
audio cache (pre-load) | yes | yes | yes | yes | yes | yes |
diff --git a/packages/audioplayers/example/integration_test/platform_features.dart b/packages/audioplayers/example/integration_test/platform_features.dart
index 9ae8659a0..ff9a83aea 100644
--- a/packages/audioplayers/example/integration_test/platform_features.dart
+++ b/packages/audioplayers/example/integration_test/platform_features.dart
@@ -58,7 +58,6 @@ class PlatformFeatures {
);
static const windowsPlatformFeatures = PlatformFeatures(
- hasBytesSource: false,
hasPlaylistSourceType: false,
hasLowLatency: false,
hasReleaseModeRelease: false,
diff --git a/packages/audioplayers/lib/src/audio_cache.dart b/packages/audioplayers/lib/src/audio_cache.dart
index e95c6a29f..98c76b599 100644
--- a/packages/audioplayers/lib/src/audio_cache.dart
+++ b/packages/audioplayers/lib/src/audio_cache.dart
@@ -125,7 +125,8 @@ class AudioCache {
throw 'This method cannot be used on web!';
}
final uri = await load(fileName);
- return fileSystem.file(uri.toFilePath(windows: false));
+ return fileSystem.file(uri.toFilePath(
+ windows: defaultTargetPlatform == TargetPlatform.windows));
}
/// Loads a single [fileName] to the cache but returns it as a list of bytes.
diff --git a/packages/audioplayers_windows/windows/CMakeLists.txt b/packages/audioplayers_windows/windows/CMakeLists.txt
index 5b269bebb..0943f70ff 100644
--- a/packages/audioplayers_windows/windows/CMakeLists.txt
+++ b/packages/audioplayers_windows/windows/CMakeLists.txt
@@ -52,6 +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)
# 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 a0a8934d8..d9bd6cd41 100644
--- a/packages/audioplayers_windows/windows/audio_player.cpp
+++ b/packages/audioplayers_windows/windows/audio_player.cpp
@@ -6,6 +6,7 @@
#include
#include
#include
+#include // for SHCreateMemStream
#include
#include
@@ -42,6 +43,8 @@ AudioPlayer::AudioPlayer(
m_mediaEngineWrapper->Initialize();
}
+AudioPlayer::~AudioPlayer() {}
+
// This method should be called asynchronously, to avoid freezing UI
void AudioPlayer::SetSourceUrl(std::string url) {
if (_url != url) {
@@ -77,7 +80,36 @@ void AudioPlayer::SetSourceUrl(std::string url) {
}
}
-AudioPlayer::~AudioPlayer() {}
+void AudioPlayer::SetSourceBytes(std::vector bytes) {
+ _isInitialized = false;
+ _url.clear();
+ 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;
+
+ 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
+ this->OnError("WindowsAudioError", "Error setting bytes", nullptr);
+ }
+}
void AudioPlayer::OnMediaError(MF_MEDIA_ENGINE_ERR error, HRESULT hr) {
LOG_HR_MSG(hr, "MediaEngine error (%d)", error);
@@ -199,6 +231,7 @@ void AudioPlayer::ReleaseMediaSource() {
m_mediaEngineWrapper->Pause();
}
m_mediaEngineWrapper->ReleaseMediaSource();
+ _url.clear();
_isInitialized = false;
}
diff --git a/packages/audioplayers_windows/windows/audio_player.h b/packages/audioplayers_windows/windows/audio_player.h
index f9f7137e3..771cad7c7 100644
--- a/packages/audioplayers_windows/windows/audio_player.h
+++ b/packages/audioplayers_windows/windows/audio_player.h
@@ -77,6 +77,8 @@ class AudioPlayer {
void SeekTo(double seek);
+ void SetSourceBytes(std::vector bytes);
+
void SetSourceUrl(std::string url);
void OnLog(const std::string& message);
diff --git a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp
index 8cbd80894..24e6b9b4c 100644
--- a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp
+++ b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp
@@ -178,6 +178,17 @@ void AudioplayersWindowsPlugin::HandleMethodCall(
}
std::thread(&AudioPlayer::SetSourceUrl, player, url).detach();
+ } else if (method_call.method_name().compare("setSourceBytes") == 0) {
+ auto data = GetArgument>("bytes", args,
+ std::vector{});
+
+ if (data.empty()) {
+ result->Error("WindowsAudioError",
+ "Null bytes received on setSourceBytes", nullptr);
+ return;
+ }
+
+ std::thread(&AudioPlayer::SetSourceBytes, player, data).detach();
} else if (method_call.method_name().compare("getDuration") == 0) {
auto duration = player->GetDuration();
result->Success(isnan(duration)