Skip to content

Commit

Permalink
feat(windows): Support for BytesSource on Windows (#1601)
Browse files Browse the repository at this point in the history
# Description

This PR will support "setSourceBytes" method for Windows OS.

## Related Issues
#1269 
Closes #1600
Closes #1467

---------

Co-authored-by: Gustl22 <git@reb0.org>
  • Loading branch information
dogukangulyasar and Gustl22 authored Sep 23, 2023
1 parent 1eabe61 commit a9e1471
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 4 deletions.
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

0 comments on commit a9e1471

Please sign in to comment.