2020-02-25 07:21:06 -07:00
|
|
|
#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 {
|
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
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) {
|
2020-02-25 07:21:06 -07:00
|
|
|
if (auto self = ref.get()) {
|
2021-04-08 11:37:35 -06:00
|
|
|
self->OnMediaOpened(sender, args);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
});
|
|
|
|
m_mediaFailedToken =
|
|
|
|
m_player.MediaFailed(winrt::auto_revoke, [ref = get_weak()](auto const &sender, auto const &args) {
|
2020-02-25 07:21:06 -07:00
|
|
|
if (auto self = ref.get()) {
|
2021-04-08 11:37:35 -06:00
|
|
|
self->OnMediaFailed(sender, args);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
m_bufferingStartedToken = m_player.PlaybackSession().BufferingStarted(
|
|
|
|
winrt::auto_revoke, [ref = get_weak()](auto const &sender, auto const &args) {
|
2020-02-25 07:21:06 -07:00
|
|
|
if (auto self = ref.get()) {
|
2021-04-08 11:37:35 -06:00
|
|
|
self->OnBufferingStarted(sender, args);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
m_bufferingEndedToken = m_player.PlaybackSession().BufferingEnded(
|
|
|
|
winrt::auto_revoke, [ref = get_weak()](auto const &sender, auto const &args) {
|
2020-02-25 07:21:06 -07:00
|
|
|
if (auto self = ref.get()) {
|
2021-04-08 11:37:35 -06:00
|
|
|
self->OnBufferingEnded(sender, args);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
m_seekCompletedToken = m_player.PlaybackSession().SeekCompleted(
|
|
|
|
winrt::auto_revoke, [ref = get_weak()](auto const &sender, auto const &args) {
|
2020-02-25 07:21:06 -07:00
|
|
|
if (auto self = ref.get()) {
|
2021-04-08 11:37:35 -06:00
|
|
|
self->OnSeekCompleted(sender, args);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
eventDataWriter.WriteObjectEnd();
|
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
2023-09-18 19:08:21 -06:00
|
|
|
void ReactVideoView::OnMediaFailed(IInspectable const &, IInspectable const &) {
|
|
|
|
runOnQueue([weak_this{get_weak()}]() {
|
|
|
|
if (auto strong_this{weak_this.get()}) {
|
|
|
|
strong_this->m_reactContext.DispatchEvent(*strong_this, L"topError", nullptr);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
void ReactVideoView::OnBufferingStarted(IInspectable const &, IInspectable const &) {}
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
void ReactVideoView::OnBufferingEnded(IInspectable const &, IInspectable const &) {}
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_ProgressUpdateInterval(int64_t interval) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_timer.Interval(std::chrono::milliseconds{interval});
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_IsLoopingEnabled(bool value) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_isLoopingEnabled = value;
|
|
|
|
if (m_player != nullptr) {
|
|
|
|
m_player.IsLoopingEnabled(m_isLoopingEnabled);
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
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));
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_Paused(bool value) {
|
2021-04-08 11:37:35 -06:00
|
|
|
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();
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
2021-04-08 11:37:35 -06:00
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_AutoPlay(bool autoPlay) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_player.AutoPlay(autoPlay);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_Muted(bool isMuted) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_isMuted = isMuted;
|
|
|
|
if (m_player != nullptr) {
|
|
|
|
m_player.IsMuted(m_isMuted);
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_Controls(bool useControls) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_useControls = useControls;
|
|
|
|
AreTransportControlsEnabled(m_useControls);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_FullScreen(bool fullScreen) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_fullScreen = fullScreen;
|
|
|
|
IsFullWindow(m_fullScreen);
|
2020-02-25 07:21:06 -07:00
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
if (m_fullScreen) {
|
|
|
|
Set_Controls(true); // full window will always have transport control enabled
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_Volume(double volume) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_volume = volume;
|
|
|
|
if (m_player != nullptr) {
|
|
|
|
m_player.Volume(m_volume);
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_Position(double position) {
|
2021-04-08 11:37:35 -06:00
|
|
|
m_position = position;
|
|
|
|
if (m_player != nullptr) {
|
|
|
|
std::chrono::seconds duration(static_cast<int>(m_position));
|
|
|
|
m_player.PlaybackSession().Position(duration);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReactVideoView::Set_PlaybackRate(double rate) {
|
|
|
|
if (m_player != nullptr) {
|
|
|
|
m_player.PlaybackSession().PlaybackRate(rate);
|
|
|
|
}
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ReactVideoView::IsPlaying(MediaPlaybackState currentState) {
|
2021-04-08 11:37:35 -06:00
|
|
|
return (
|
|
|
|
currentState == MediaPlaybackState::Buffering || currentState == MediaPlaybackState::Opening ||
|
|
|
|
currentState == MediaPlaybackState::Playing);
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
2021-04-08 11:37:35 -06:00
|
|
|
void ReactVideoView::runOnQueue(std::function<void()> &&func) {
|
|
|
|
m_uiDispatcher.RunAsync(
|
|
|
|
winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [func = std::move(func)]() { func(); });
|
2020-02-25 07:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace winrt::ReactNativeVideoCPP::implementation
|