Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(windows): Support for BytesSource on Windows #1601

Merged
merged 8 commits into from
Sep 23, 2023
Merged
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
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
35 changes: 34 additions & 1 deletion 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,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) {
Expand Down Expand Up @@ -77,7 +80,36 @@ void AudioPlayer::SetSourceUrl(std::string url) {
}
}

AudioPlayer::~AudioPlayer() {}
void AudioPlayer::SetSourceBytes(std::vector<uint8_t> bytes) {
_isInitialized = false;
_url.clear();
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);
}
}

void AudioPlayer::OnMediaError(MF_MEDIA_ENGINE_ERR error, HRESULT hr) {
LOG_HR_MSG(hr, "MediaEngine error (%d)", error);
Expand Down Expand Up @@ -199,6 +231,7 @@ void AudioPlayer::ReleaseMediaSource() {
m_mediaEngineWrapper->Pause();
}
m_mediaEngineWrapper->ReleaseMediaSource();
_url.clear();
_isInitialized = false;
}

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