Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion feature_parity_table.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Note: LLM means Low Latency Mode.
<tr><td>local asset</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td></tr>
<tr><td>external URL file</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td></tr>
<tr><td>external URL stream</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td></tr>
<tr><td>byte array</td><td>SDK >=23</td><td>not yet</td><td>not yet</td><td>not yet</td><td>not yet</td><td>not yet</td></tr>
<tr><td>byte array</td><td>SDK >=23</td><td>not yet</td><td>not yet</td><td>not yet</td><td>yes</td><td>not yet</td></tr>
<tr><td colspan="7"><strong>Audio Config</strong></td></tr>
<tr><td>set url</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td></tr>
<tr><td>audio cache (pre-load)</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td><td>yes</td></tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class PlatformFeatures {
);

static const windowsPlatformFeatures = PlatformFeatures(
hasBytesSource: false,
hasPlaylistSourceType: false,
hasLowLatency: false,
hasReleaseModeRelease: false,
Expand Down
3 changes: 2 additions & 1 deletion packages/audioplayers/lib/src/audio_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions packages/audioplayers_windows/windows/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions packages/audioplayers_windows/windows/audio_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <flutter/event_stream_handler_functions.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <shlwapi.h> // for SHCreateMemStream
#include <shobjidl.h>
#include <windows.h>

Expand Down Expand Up @@ -42,6 +43,34 @@ AudioPlayer::AudioPlayer(
m_mediaEngineWrapper->Initialize();
}

void AudioPlayer::SetSourceBytes(std::vector<uint8_t> bytes) {
size_t size = bytes.size();

try {
winrt::com_ptr<IMFSourceResolver> 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<IMFMediaSource> mediaSource;

IStream* pstm = SHCreateMemStream(bytes.data(), static_cast<unsigned int>( size ));
IMFByteStream *stream = NULL;
MFCreateMFByteStreamOnStream(pstm, &stream);

sourceResolver->CreateObjectFromByteStream(stream, nullptr,
sourceResolutionFlags, nullptr,
&objectType, reinterpret_cast<IUnknown**>(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);
}
}

// This method should be called asynchronously, to avoid freezing UI
void AudioPlayer::SetSourceUrl(std::string url) {
if (_url != url) {
Expand Down
2 changes: 2 additions & 0 deletions packages/audioplayers_windows/windows/audio_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class AudioPlayer {

void SeekTo(double seek);

void SetSourceBytes(std::vector<uint8_t> bytes);

void SetSourceUrl(std::string url);

void OnLog(const std::string& message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::vector<uint8_t>>("bytes", args, std::vector<uint8_t>{});

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)
Expand Down