Add support for react-native Windows Cpp/WinRT (#1893)

This also deprecates the old react-native windows implementation
This commit is contained in:
Di Da
2020-02-25 06:21:06 -08:00
committed by GitHub
parent 4f07aab8b1
commit a4fec8eb99
34 changed files with 778 additions and 1551 deletions

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>

View File

@@ -0,0 +1,3 @@
EXPORTS
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
<MinimalCoreWin>true</MinimalCoreWin>
<ProjectGuid>{765365e4-9553-4900-9f69-e26d4309c8da}</ProjectGuid>
<ProjectName>ReactNativeVideoCPP</ProjectName>
<RootNamespace>ReactNativeVideoCPP</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.15063.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
<Import Project="..\..\..\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems" Label="Shared" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<!--Temporarily disable cppwinrt heap enforcement to work around xaml compiler generated std::shared_ptr use -->
<AdditionalOptions Condition="'$(CppWinRTHeapEnforcement)'==''">/DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateWindowsMetadata>true</GenerateWindowsMetadata>
<ModuleDefinitionFile>ReactNativeVideoCPP.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ReactVideoView.h">
<DependentUpon>ReactVideoView.idl</DependentUpon>
</ClInclude>
<ClInclude Include="ReactVideoViewManager.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ReactPackageProvider.h">
<DependentUpon>ReactPackageProvider.idl</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ReactVideoView.cpp">
<DependentUpon>ReactVideoView.idl</DependentUpon>
</ClCompile>
<ClCompile Include="ReactVideoViewManager.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ReactPackageProvider.cpp">
<DependentUpon>ReactPackageProvider.idl</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
</ItemGroup>
<ItemGroup>
<Midl Include="ReactVideoView.idl" />
<Midl Include="ReactPackageProvider.idl" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="ReactNativeVideoCPP.def" />
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj">
<Project>{f7d32bd0-2749-483e-9a0d-1635ef7e3136}</Project>
<Private>false</Private>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.190730.2\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resources">
<UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="ReactPackageProvider.cpp" />
<ClCompile Include="ReactVideoView.cpp" />
<ClCompile Include="ReactVideoViewManager.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="ReactPackageProvider.h" />
<ClInclude Include="ReactVideoView.h" />
<ClInclude Include="ReactVideoViewManager.h" />
</ItemGroup>
<ItemGroup>
<None Include="ReactNativeVideoCPP.def" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
</ItemGroup>
<ItemGroup>
<Text Include="readme.txt" />
</ItemGroup>
<ItemGroup>
<Midl Include="ReactPackageProvider.idl" />
<Midl Include="ReactVideoView.idl" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,17 @@
#include "pch.h"
#include "ReactPackageProvider.h"
#if __has_include("ReactPackageProvider.g.cpp")
#include "ReactPackageProvider.g.cpp"
#endif
#include "ReactVideoViewManager.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::ReactNativeVideoCPP::implementation {
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
packageBuilder.AddViewManager(L"ReactVideoViewManager", []() { return winrt::make<ReactVideoViewManager>(); });
}
} // namespace winrt::ReactNativeVideoCPP::implementation

View File

@@ -0,0 +1,20 @@
#pragma once
#include "ReactPackageProvider.g.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::ReactNativeVideoCPP::implementation {
struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider> {
ReactPackageProvider() = default;
void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
};
} // namespace winrt::ReactNativeVideoCPP::implementation
namespace winrt::ReactNativeVideoCPP::factory_implementation {
struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider, implementation::ReactPackageProvider> {};
} // namespace winrt::ReactNativeVideoCPP::factory_implementation

View File

@@ -0,0 +1,7 @@
namespace ReactNativeVideoCPP {
[webhosthidden]
[default_interface]
runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider {
ReactPackageProvider();
};
} // namespace ReactNativeVideoCPP

View File

@@ -0,0 +1,244 @@
#include "pch.h"
#include "ReactVideoView.h"
#include "ReactVideoView.g.cpp"
#include "NativeModules.h"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Core;
using namespace Windows::Media::Core;
using namespace Windows::Media::Playback;
namespace winrt::ReactNativeVideoCPP::implementation {
ReactVideoView::ReactVideoView(winrt::Microsoft::ReactNative::IReactContext const& reactContext)
: m_reactContext(reactContext){
// always create and set the player here instead of depending on auto-create logic
// in the MediaPlayerElement (only when auto play is on or URI is set)
m_player = winrt::Windows::Media::Playback::MediaPlayer();
SetMediaPlayer(m_player);
m_uiDispatcher = CoreWindow::GetForCurrentThread().Dispatcher();
m_mediaOpenedToken = m_player.MediaOpened(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get()) {
self->OnMediaOpened(sender, args);
}
});
m_mediaFailedToken = m_player.MediaFailed(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get()) {
self->OnMediaFailed(sender, args);
}
});
m_mediaEndedToken = m_player.MediaEnded(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get()) {
self->OnMediaEnded(sender, args);
}
});
m_bufferingStartedToken =
m_player.PlaybackSession().BufferingStarted(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get()) {
self->OnBufferingStarted(sender, args);
}
});
m_bufferingEndedToken =
m_player.PlaybackSession().BufferingEnded(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get()) {
self->OnBufferingEnded(sender, args);
}
});
m_seekCompletedToken =
m_player.PlaybackSession().SeekCompleted(winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get()) {
self->OnSeekCompleted(sender, args);
}
});
m_timer = Windows::UI::Xaml::DispatcherTimer();
m_timer.Interval(std::chrono::milliseconds{ 250 });
m_timer.Start();
auto token = m_timer.Tick([ref = get_weak()](auto const&, auto const&) {
if (auto self = ref.get()){
if (auto mediaPlayer = self->m_player) {
if (mediaPlayer.PlaybackSession().PlaybackState() ==
winrt::Windows::Media::Playback::MediaPlaybackState::Playing) {
auto currentTimeInSeconds = mediaPlayer.PlaybackSession().Position().count() / 10000000;
self->m_reactContext.DispatchEvent(
*self,
L"topProgress",
[&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
eventDataWriter.WriteObjectBegin();
{
WriteProperty(eventDataWriter, L"currentTime", currentTimeInSeconds);
WriteProperty(eventDataWriter, L"playableDuration", 0.0);
}
eventDataWriter.WriteObjectEnd();
});
}
}
}
});
}
void ReactVideoView::OnMediaOpened(IInspectable const&, IInspectable const&) {
runOnQueue([weak_this{ get_weak() }]() {
if (auto strong_this{ weak_this.get() }) {
if (auto mediaPlayer = strong_this->m_player) {
auto width = mediaPlayer.PlaybackSession().NaturalVideoWidth();
auto height = mediaPlayer.PlaybackSession().NaturalVideoHeight();
auto orientation = (width > height) ? L"landscape" : L"portrait";
auto durationInSeconds = mediaPlayer.PlaybackSession().NaturalDuration().count() / 10000000;
auto currentTimeInSeconds = mediaPlayer.PlaybackSession().Position().count() / 10000000;
strong_this->m_reactContext.DispatchEvent(
*strong_this,
L"topLoad",
[&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
eventDataWriter.WriteObjectBegin();
{
WriteProperty(eventDataWriter, L"duration", durationInSeconds);
WriteProperty(eventDataWriter, L"currentTime", currentTimeInSeconds);
eventDataWriter.WritePropertyName(L"naturalSize");
{
eventDataWriter.WriteObjectBegin();
WriteProperty(eventDataWriter, L"width", width);
WriteProperty(eventDataWriter, L"height", height);
WriteProperty(eventDataWriter, L"orientation", orientation);
WriteProperty(eventDataWriter, L"orientation", orientation);
eventDataWriter.WriteObjectEnd();
}
WriteProperty(eventDataWriter, L"canPlayFastForward", false);
WriteProperty(eventDataWriter, L"canPlaySlowForward", false);
WriteProperty(eventDataWriter, L"canPlaySlow", false);
WriteProperty(eventDataWriter, L"canStepBackward", false);
WriteProperty(eventDataWriter, L"canStepForward", false);
}
eventDataWriter.WriteObjectEnd();
});
}
}
});
}
void ReactVideoView::OnMediaFailed(IInspectable const&, IInspectable const&) {}
void ReactVideoView::OnMediaEnded(IInspectable const&, IInspectable const&) {
runOnQueue([weak_this{ get_weak() }]() {
if (auto strong_this{ weak_this.get() }) {
strong_this->m_reactContext.DispatchEvent(*strong_this, L"topEnd", nullptr);
}
});
}
void ReactVideoView::OnBufferingStarted(IInspectable const&, IInspectable const&) {}
void ReactVideoView::OnBufferingEnded(IInspectable const&, IInspectable const&) {}
void ReactVideoView::OnSeekCompleted(IInspectable const&, IInspectable const&) {
runOnQueue([weak_this{ get_weak() }]() {
if (auto strong_this{ weak_this.get() }) {
strong_this->m_reactContext.DispatchEvent(*strong_this, L"topSeek", nullptr);
}
});
}
void ReactVideoView::Set_ProgressUpdateInterval(int64_t interval) {
m_timer.Interval(std::chrono::milliseconds{ interval });
}
void ReactVideoView::Set_IsLoopingEnabled(bool value) {
m_isLoopingEnabled = value;
if (m_player != nullptr) {
m_player.IsLoopingEnabled(m_isLoopingEnabled);
}
}
void ReactVideoView::Set_UriString(hstring const& value) {
m_uriString = value;
if (m_player != nullptr) {
auto uri = Uri(m_uriString);
m_player.Source(MediaSource::CreateFromUri(uri));
}
}
void ReactVideoView::Set_Paused(bool value) {
m_isPaused = value;
if (m_player != nullptr) {
if (m_isPaused) {
if (IsPlaying(m_player.PlaybackSession().PlaybackState())) {
m_player.Pause();
}
}
else {
if (!IsPlaying(m_player.PlaybackSession().PlaybackState())) {
m_player.Play();
}
}
}
}
void ReactVideoView::Set_AutoPlay(bool autoPlay) {
m_player.AutoPlay(autoPlay);
}
void ReactVideoView::Set_Muted(bool isMuted) {
m_isMuted = isMuted;
if (m_player != nullptr) {
m_player.IsMuted(m_isMuted);
}
}
void ReactVideoView::Set_Controls(bool useControls) {
m_useControls = useControls;
AreTransportControlsEnabled(m_useControls);
}
void ReactVideoView::Set_FullScreen(bool fullScreen) {
m_fullScreen = fullScreen;
IsFullWindow(m_fullScreen);
if (m_fullScreen)
{
Set_Controls(true); // full window will always have transport control enabled
}
}
void ReactVideoView::Set_Volume(double volume) {
m_volume = volume;
if (m_player != nullptr) {
m_player.Volume(m_volume);
}
}
void ReactVideoView::Set_Position(double position) {
m_position = position;
if (m_player != nullptr) {
std::chrono::seconds duration(static_cast<int>(m_position));
m_player.PlaybackSession().Position(duration);
}
}
bool ReactVideoView::IsPlaying(MediaPlaybackState currentState) {
return (
currentState == MediaPlaybackState::Buffering ||
currentState == MediaPlaybackState::Opening ||
currentState == MediaPlaybackState::Playing
);
}
void ReactVideoView::runOnQueue(std::function<void()>&& func) {
m_uiDispatcher.RunAsync(
winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [func = std::move(func)]() { func(); });
}
} // namespace winrt::ReactNativeVideoCPP::implementation

View File

@@ -0,0 +1,56 @@
#pragma once
#include "ReactVideoView.g.h"
#include <functional>
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::ReactNativeVideoCPP::implementation {
struct ReactVideoView : ReactVideoViewT<ReactVideoView> {
public:
ReactVideoView(winrt::Microsoft::ReactNative::IReactContext const &reactContext);
void Set_UriString(hstring const &value);
void Set_IsLoopingEnabled(bool value);
void Set_Paused(bool isPaused);
void Set_Muted(bool isMuted);
void Set_Volume(double volume);
void Set_Position(double position);
void Set_Controls(bool useControls);
void Set_FullScreen(bool fullScreen);
void Set_ProgressUpdateInterval(int64_t interval);
void Set_AutoPlay(bool autoPlay);
private:
hstring m_uriString;
bool m_isLoopingEnabled = false;
bool m_isPaused = true;
bool m_isMuted = false;
bool m_useControls = false;
bool m_fullScreen = false;
double m_volume = 0;
double m_position = 0;
Windows::UI::Xaml::DispatcherTimer m_timer;
Windows::Media::Playback::MediaPlayer m_player = nullptr;
Windows::UI::Core::CoreDispatcher m_uiDispatcher = nullptr;
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
Windows::Media::Playback::MediaPlayer::MediaOpened_revoker m_mediaOpenedToken{};
Windows::Media::Playback::MediaPlayer::MediaFailed_revoker m_mediaFailedToken{};
Windows::Media::Playback::MediaPlayer::MediaEnded_revoker m_mediaEndedToken{};
Windows::Media::Playback::MediaPlaybackSession::BufferingStarted_revoker m_bufferingStartedToken{};
Windows::Media::Playback::MediaPlaybackSession::BufferingEnded_revoker m_bufferingEndedToken{};
Windows::Media::Playback::MediaPlaybackSession::SeekCompleted_revoker m_seekCompletedToken{};
bool IsPlaying(Windows::Media::Playback::MediaPlaybackState currentState);
void OnMediaOpened(IInspectable const &sender, IInspectable const &args);
void OnMediaFailed(IInspectable const &sender, IInspectable const &args);
void OnMediaEnded(IInspectable const &sender, IInspectable const &);
void OnBufferingStarted(IInspectable const &sender, IInspectable const &);
void OnBufferingEnded(IInspectable const &sender, IInspectable const &);
void OnSeekCompleted(IInspectable const &sender, IInspectable const &);
void runOnQueue(std::function<void()> &&func);
};
} // namespace winrt::ReactNativeVideoCPP::implementation
namespace winrt::ReactNativeVideoCPP::factory_implementation {
struct ReactVideoView : ReactVideoViewT<ReactVideoView, implementation::ReactVideoView> {};
} // namespace winrt::ReactNativeVideoCPP::factory_implementation

View File

@@ -0,0 +1,16 @@
namespace ReactNativeVideoCPP {
[default_interface] runtimeclass ReactVideoView : Windows.UI.Xaml.Controls.MediaPlayerElement {
ReactVideoView(Microsoft.ReactNative.IReactContext context);
void Set_UriString(String uri);
void Set_IsLoopingEnabled(Boolean isLoopingEnabled);
void Set_Paused(Boolean isPaused);
void Set_Muted(Boolean isMuted);
void Set_Volume(Double volume);
void Set_Position(Double position);
void Set_Controls(Boolean useControls);
void Set_FullScreen(Boolean fullScreen);
void Set_ProgressUpdateInterval(Int64 interval);
void Set_AutoPlay(Boolean autoPlay);
};
} // namespace ReactNativeVideoCPP

View File

@@ -0,0 +1,110 @@
#include "pch.h"
#include "ReactVideoViewManager.h"
#include "NativeModules.h"
#include "ReactVideoView.h"
namespace winrt::ReactNativeVideoCPP::implementation {
ReactVideoViewManager::ReactVideoViewManager() {}
// IViewManager
hstring ReactVideoViewManager::Name() noexcept {
return L"RCTVideo";
}
FrameworkElement ReactVideoViewManager::CreateView() noexcept {
auto reactVideoView = winrt::ReactNativeVideoCPP::ReactVideoView(m_reactContext);
return reactVideoView;
}
// IViewManagerWithReactContext
IReactContext ReactVideoViewManager::ReactContext() noexcept {
return m_reactContext;
}
void ReactVideoViewManager::ReactContext(IReactContext reactContext) noexcept {
m_reactContext = reactContext;
}
// IViewManagerWithExportedViewConstants
winrt::Microsoft::ReactNative::ConstantProviderDelegate ReactVideoViewManager::ExportedViewConstants() noexcept {
return [](winrt::Microsoft::ReactNative::IJSValueWriter const &constantWriter) {
WriteProperty(constantWriter, L"ScaleNone", to_hstring(std::to_string((int)Stretch::None)));
WriteProperty(constantWriter, L"ScaleToFill", to_hstring(std::to_string((int)Stretch::UniformToFill)));
WriteProperty(constantWriter, L"ScaleAspectFit", to_hstring(std::to_string((int)Stretch::Uniform)));
WriteProperty(constantWriter, L"ScaleAspectFill", to_hstring(std::to_string((int)Stretch::Fill)));
};
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> ReactVideoViewManager::NativeProps() noexcept {
auto nativeProps = winrt::single_threaded_map<hstring, ViewManagerPropertyType>();
nativeProps.Insert(L"src", ViewManagerPropertyType::Map);
nativeProps.Insert(L"resizeMode", ViewManagerPropertyType::String);
nativeProps.Insert(L"repeat", ViewManagerPropertyType::Boolean);
nativeProps.Insert(L"paused", ViewManagerPropertyType::Boolean);
nativeProps.Insert(L"muted", ViewManagerPropertyType::Boolean);
nativeProps.Insert(L"volume", ViewManagerPropertyType::Number);
nativeProps.Insert(L"seek", ViewManagerPropertyType::Number);
nativeProps.Insert(L"controls", ViewManagerPropertyType::Boolean);
nativeProps.Insert(L"fullscreen", ViewManagerPropertyType::Boolean);
nativeProps.Insert(L"progressUpdateInterval", ViewManagerPropertyType::Number);
return nativeProps.GetView();
}
void ReactVideoViewManager::UpdateProperties(
FrameworkElement const &view,
IJSValueReader const &propertyMapReader) noexcept {
if (auto reactVideoView = view.try_as<winrt::ReactNativeVideoCPP::ReactVideoView>()) {
const JSValueObject &propertyMap = JSValue::ReadObjectFrom(propertyMapReader);
for (auto const &pair : propertyMap) {
auto const &propertyName = pair.first;
auto const &propertyValue = pair.second;
if (!propertyValue.IsNull()) {
if (propertyName == "src") {
auto const &srcMap = propertyValue.Object();
auto const &uri = srcMap.at("uri");
reactVideoView.Set_UriString(to_hstring(uri.String()));
} else if (propertyName == "resizeMode") {
reactVideoView.Stretch(static_cast<Stretch>(std::stoul(propertyValue.String())));
} else if (propertyName == "repeat") {
reactVideoView.Set_IsLoopingEnabled(propertyValue.Boolean());
} else if (propertyName == "paused") {
m_paused = propertyValue.Boolean();
reactVideoView.Set_Paused(m_paused);
} else if (propertyName == "muted") {
reactVideoView.Set_Muted(propertyValue.Boolean());
} else if (propertyName == "volume") {
reactVideoView.Set_Volume(propertyValue.Double());
} else if (propertyName == "seek") {
reactVideoView.Set_Position(propertyValue.Double());
} else if (propertyName == "controls") {
reactVideoView.Set_Controls(propertyValue.Boolean());
} else if (propertyName == "fullscreen") {
reactVideoView.Set_FullScreen(propertyValue.Boolean());
} else if (propertyName == "progressUpdateInterval") {
reactVideoView.Set_ProgressUpdateInterval(propertyValue.Int64());
}
}
}
reactVideoView.Set_AutoPlay(!m_paused); // auto play on pause false or not set.
}
}
// IViewManagerWithExportedEventTypeConstants
ConstantProviderDelegate ReactVideoViewManager::ExportedCustomBubblingEventTypeConstants() noexcept {
return nullptr;
}
ConstantProviderDelegate ReactVideoViewManager::ExportedCustomDirectEventTypeConstants() noexcept {
return [](winrt::Microsoft::ReactNative::IJSValueWriter const &constantWriter) {
WriteCustomDirectEventTypeConstant(constantWriter, "Load");
WriteCustomDirectEventTypeConstant(constantWriter, "End");
WriteCustomDirectEventTypeConstant(constantWriter, "Seek");
WriteCustomDirectEventTypeConstant(constantWriter, "Progress");
};
}
} // namespace winrt::ReactNativeVideoCPP::implementation

View File

@@ -0,0 +1,55 @@
#pragma once
#include "winrt/Microsoft.ReactNative.h"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::Media::Core;
namespace winrt::ReactNativeVideoCPP::implementation {
struct ReactVideoViewManager : winrt::implements<
ReactVideoViewManager,
winrt::Microsoft::ReactNative::IViewManager,
winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
winrt::Microsoft::ReactNative::IViewManagerWithExportedViewConstants,
winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties,
winrt::Microsoft::ReactNative::IViewManagerWithExportedEventTypeConstants> {
public:
ReactVideoViewManager();
// IViewManager
winrt::hstring Name() noexcept;
FrameworkElement CreateView() noexcept;
// IViewManagerWithReactContext
winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;
// IViewManagerWithNativeProperties
winrt::Windows::Foundation::Collections::
IMapView<winrt::hstring, winrt::Microsoft::ReactNative::ViewManagerPropertyType>
NativeProps() noexcept;
void UpdateProperties(
winrt::Windows::UI::Xaml::FrameworkElement const &view,
winrt::Microsoft::ReactNative::IJSValueReader const &propertyMapReader) noexcept;
// IViewManagerWithExportedViewConstants
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedViewConstants() noexcept;
// IViewManagerWithExportedEventTypeConstants
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomBubblingEventTypeConstants() noexcept;
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomDirectEventTypeConstants() noexcept;
private:
winrt::Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
bool m_paused = false;
};
} // namespace winrt::ReactNativeVideoCPP::implementation

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.190730.2" targetFramework="native" />
</packages>

View File

@@ -0,0 +1 @@
#include "pch.h"

View File

@@ -0,0 +1,20 @@
#pragma once
#include <unknwn.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Media.Core.h>
#include <winrt/Windows.Media.Playback.h>
#include <winrt/Windows.System.Threading.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.ViewManagement.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Data.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <winrt/Windows.UI.Xaml.Navigation.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Input.h>
#include <winrt/Microsoft.ReactNative.h>