未验证 提交 a8158e0d 编写于 作者: M Martin Zikmund 提交者: GitHub

Merge pull request #12724 from unoplatform/dev/ramr/issue12394-playlist

...@@ -29,7 +29,6 @@ public partial class GtkMediaPlayer : FrameworkElement ...@@ -29,7 +29,6 @@ public partial class GtkMediaPlayer : FrameworkElement
private VideoView? _videoView; private VideoView? _videoView;
private Uri? _mediaPath; private Uri? _mediaPath;
private bool _isEnding; private bool _isEnding;
private bool _isLoopingEnabled;
private double _playbackRate; private double _playbackRate;
private Rect _transportControlsBounds; private Rect _transportControlsBounds;
private Windows.UI.Xaml.Media.Stretch _stretch = Windows.UI.Xaml.Media.Stretch.Uniform; private Windows.UI.Xaml.Media.Stretch _stretch = Windows.UI.Xaml.Media.Stretch.Uniform;
...@@ -519,11 +518,6 @@ public partial class GtkMediaPlayer : FrameworkElement ...@@ -519,11 +518,6 @@ public partial class GtkMediaPlayer : FrameworkElement
} }
} }
public void SetIsLoopingEnabled(bool value)
{
_isLoopingEnabled = value;
}
internal void UpdateVideoStretch(Windows.UI.Xaml.Media.Stretch stretch) internal void UpdateVideoStretch(Windows.UI.Xaml.Media.Stretch stretch)
{ {
if (_videoView != null) if (_videoView != null)
......
...@@ -651,10 +651,6 @@ public partial class GtkMediaPlayer ...@@ -651,10 +651,6 @@ public partial class GtkMediaPlayer
UpdateMedia(); UpdateMedia();
OnSourceEnded?.Invoke(this, EventArgs.Empty); OnSourceEnded?.Invoke(this, EventArgs.Empty);
if (_isLoopingEnabled)
{
_mediaPlayer.Play();
}
_videoView.Visible = true; _videoView.Visible = true;
_isEnding = false; _isEnding = false;
}); });
......
...@@ -44,6 +44,7 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -44,6 +44,7 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
private int _playlistIndex; private int _playlistIndex;
private TimeSpan _naturalDuration; private TimeSpan _naturalDuration;
private bool _isLoopingEnabled; private bool _isLoopingEnabled;
private bool _isLoopingAllEnabled;
private double _playbackRate; private double _playbackRate;
public MediaPlayerExtension(object owner) public MediaPlayerExtension(object owner)
...@@ -177,9 +178,16 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -177,9 +178,16 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
switch (_owner.Source) switch (_owner.Source)
{ {
case MediaPlaybackList playlist when playlist.Items.Count > 0 && _playlistItems is not null: case MediaPlaybackList playlist when playlist.Items.Count > 0:
SetPlaylistItems(playlist); SetPlaylistItems(playlist);
_uri = _playlistItems[0]; if (_playlistItems is not null)
{
_uri = _playlistItems[0];
}
else
{
throw new InvalidOperationException("Playlist Items could not be set");
}
break; break;
case MediaPlaybackItem item: case MediaPlaybackItem item:
...@@ -190,6 +198,7 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -190,6 +198,7 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
_uri = source.Uri; _uri = source.Uri;
break; break;
default: default:
throw new InvalidOperationException("Unsupported media source type"); throw new InvalidOperationException("Unsupported media source type");
} }
...@@ -203,6 +212,30 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -203,6 +212,30 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused; _owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused;
} }
public void ReInitializeSource()
{
NaturalDuration = TimeSpan.Zero;
if (Position != TimeSpan.Zero)
{
Position = TimeSpan.Zero;
}
if (_owner.Source == null)
{
return;
}
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Opening;
InitializePlayer();
ApplyVideoSource();
Events?.RaiseSourceChanged();
// Set the player back to the paused state, so that the
// transport controls can be shown properly.
// This may need to be changed when the initialization of libVLC
// can be taken into account, as well as the media status.
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused;
}
private void SetPlaylistItems(MediaPlaybackList playlist) private void SetPlaylistItems(MediaPlaybackList playlist)
{ {
_playlistItems = playlist.Items _playlistItems = playlist.Items
...@@ -281,10 +314,15 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -281,10 +314,15 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
set set
{ {
_isLoopingEnabled = value; _isLoopingEnabled = value;
if (_player is not null) }
{ }
_player.SetIsLoopingEnabled(value);
} public bool IsLoopingAllEnabled
{
get => _isLoopingAllEnabled;
set
{
_isLoopingAllEnabled = value;
} }
} }
...@@ -393,4 +431,26 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -393,4 +431,26 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
_isPlayerPrepared = false; _isPlayerPrepared = false;
} }
} }
public void PreviousTrack()
{
// Play next item in playlist, if any
if (_playlistItems != null && _playlistIndex > 0)
{
_uri = _playlistItems[--_playlistIndex];
ReInitializeSource();
Play();
}
}
public void NextTrack()
{
// Play next item in playlist, if any
if (_playlistItems != null && _playlistIndex < _playlistItems.Count - 1)
{
_uri = _playlistItems[++_playlistIndex];
ReInitializeSource();
Play();
}
}
} }
...@@ -89,12 +89,31 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -89,12 +89,31 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
{ {
Events?.RaiseMediaEnded(); Events?.RaiseMediaEnded();
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.None; _owner.PlaybackSession.PlaybackState = MediaPlaybackState.None;
if (IsLoopingEnabled && !IsLoopingAllEnabled)
// Play next item in playlist, if any {
if (_playlistItems != null && _playlistIndex < _playlistItems.Count - 1) ReInitializeSource();
Play();
}
else
{ {
_uri = _playlistItems[++_playlistIndex]; // Play first item in playlist, if any and repeat all
ApplyVideoSource(); if (_playlistItems != null && _playlistIndex >= _playlistItems.Count - 1 && IsLoopingAllEnabled)
{
_playlistIndex = 0;
_uri = _playlistItems[_playlistIndex];
ReInitializeSource();
Play();
}
else
{
// Play next item in playlist, if any
if (_playlistItems != null && _playlistIndex < _playlistItems.Count - 1)
{
_uri = _playlistItems[++_playlistIndex];
ReInitializeSource();
Play();
}
}
} }
} }
......
...@@ -165,18 +165,13 @@ internal partial class HtmlMediaPlayer : Border ...@@ -165,18 +165,13 @@ internal partial class HtmlMediaPlayer : Border
{ {
add add
{ {
if (_activeElement == null) _htmlVideo.RegisterHtmlEventHandler("timeupdate", value);
{ _htmlAudio.RegisterHtmlEventHandler("timeupdate", value);
return;
}
_activeElement.RegisterHtmlEventHandler("timeupdate", value);
} }
remove remove
{ {
if (_activeElement != null) _htmlVideo.UnregisterHtmlEventHandler("timeupdate", value);
{ _htmlAudio.UnregisterHtmlEventHandler("timeupdate", value);
_activeElement.UnregisterHtmlEventHandler("timeupdate", value);
}
} }
} }
...@@ -187,18 +182,13 @@ internal partial class HtmlMediaPlayer : Border ...@@ -187,18 +182,13 @@ internal partial class HtmlMediaPlayer : Border
{ {
add add
{ {
if (_activeElement == null) _htmlVideo.RegisterHtmlEventHandler("loadedmetadata", value);
{ _htmlAudio.RegisterHtmlEventHandler("loadedmetadata", value);
return;
}
_activeElement.RegisterHtmlEventHandler("loadedmetadata", value);
} }
remove remove
{ {
if (_activeElement != null) _htmlVideo.UnregisterHtmlEventHandler("loadedmetadata", value);
{ _htmlAudio.UnregisterHtmlEventHandler("loadedmetadata", value);
_activeElement.UnregisterHtmlEventHandler("loadedmetadata", value);
}
} }
} }
...@@ -209,18 +199,13 @@ internal partial class HtmlMediaPlayer : Border ...@@ -209,18 +199,13 @@ internal partial class HtmlMediaPlayer : Border
{ {
add add
{ {
if (_activeElement == null) _htmlVideo.RegisterHtmlEventHandler("ended", value);
{ _htmlAudio.RegisterHtmlEventHandler("ended", value);
return;
}
_activeElement.RegisterHtmlEventHandler("ended", value);
} }
remove remove
{ {
if (_activeElement != null) _htmlVideo.UnregisterHtmlEventHandler("ended", value);
{ _htmlAudio.UnregisterHtmlEventHandler("ended", value);
_activeElement.UnregisterHtmlEventHandler("ended", value);
}
} }
} }
...@@ -460,6 +445,7 @@ internal partial class HtmlMediaPlayer : Border ...@@ -460,6 +445,7 @@ internal partial class HtmlMediaPlayer : Border
} }
} }
//player.TimeUpdated += player.OnHtmlTimeUpdated;
} }
} }
...@@ -650,25 +636,4 @@ internal partial class HtmlMediaPlayer : Border ...@@ -650,25 +636,4 @@ internal partial class HtmlMediaPlayer : Border
NativeMethods.SetPlaybackRate(IsAudio ? _htmlAudio.HtmlId : _htmlVideo.HtmlId, value); NativeMethods.SetPlaybackRate(IsAudio ? _htmlAudio.HtmlId : _htmlVideo.HtmlId, value);
} }
} }
private bool _isLoopingEnabled;
public void SetIsLoopingEnabled(bool value)
{
_isLoopingEnabled = value;
if (_activeElement != null)
{
if (_isLoopingEnabled)
{
_activeElement.SetHtmlAttribute("loop", "loop");
}
else
{
_activeElement.ClearHtmlAttribute("loop");
}
if (this.Log().IsEnabled(Uno.Foundation.Logging.LogLevel.Debug))
{
this.Log().Debug($"{_activeElementName} loop {_isLoopingEnabled}: [{Source}]");
}
}
}
} }
...@@ -31,6 +31,8 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -31,6 +31,8 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
private bool _updatingPosition; private bool _updatingPosition;
private bool _isPlayRequested; private bool _isPlayRequested;
private bool _isPlayerPrepared; private bool _isPlayerPrepared;
private bool _isLoopingEnabled;
private bool _isLoopingAllEnabled;
private List<Uri>? _playlistItems; private List<Uri>? _playlistItems;
private int _playlistIndex; private int _playlistIndex;
private TimeSpan _naturalDuration; private TimeSpan _naturalDuration;
...@@ -115,17 +117,21 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -115,17 +117,21 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
} }
} }
private bool _isLoopingEnabled;
public bool IsLoopingEnabled public bool IsLoopingEnabled
{ {
get => _isLoopingEnabled; get => _isLoopingEnabled;
set set
{ {
_isLoopingEnabled = value; _isLoopingEnabled = value;
if (_player is not null) }
{ }
_player.SetIsLoopingEnabled(value);
} public bool IsLoopingAllEnabled
{
get => _isLoopingAllEnabled;
set
{
_isLoopingAllEnabled = value;
} }
} }
...@@ -245,13 +251,14 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -245,13 +251,14 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
if (this.Log().IsEnabled(LogLevel.Debug)) if (this.Log().IsEnabled(LogLevel.Debug))
{ {
this.Log().Debug($"MediaPlayerExtension.OnStatusMediaChanged to state {_player?.PlayerState.ToString()}"); this.Log().Debug($"MediaPlayerExtension.OnStatusMediaChanged to state {_player?.PlayerState.ToString()}");
this.Log().Debug($"MediaPlayerExtension owner PlaybackSession PlaybackState {_owner?.PlaybackSession?.PlaybackState.ToString()}");
} }
if (_player?.PlayerState == HtmlMediaPlayerState.Paused && _owner.PlaybackSession.PlaybackState == MediaPlaybackState.Playing) if (_player?.PlayerState == HtmlMediaPlayerState.Paused && _owner?.PlaybackSession.PlaybackState == MediaPlaybackState.Playing)
{ {
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused; _owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused;
} }
else if (_player?.PlayerState == HtmlMediaPlayerState.Playing && _owner.PlaybackSession.PlaybackState == MediaPlaybackState.Paused) else if (_player?.PlayerState == HtmlMediaPlayerState.Playing && _owner?.PlaybackSession.PlaybackState == MediaPlaybackState.Paused)
{ {
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Playing; _owner.PlaybackSession.PlaybackState = MediaPlaybackState.Playing;
} }
...@@ -292,9 +299,16 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -292,9 +299,16 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
switch (_owner.Source) switch (_owner.Source)
{ {
case MediaPlaybackList playlist when playlist.Items.Count > 0 && _playlistItems is not null: case MediaPlaybackList playlist when playlist.Items.Count > 0:
SetPlaylistItems(playlist); SetPlaylistItems(playlist);
_uri = _playlistItems[0]; if (_playlistItems is not null && _playlistItems.Any())
{
_uri = _playlistItems[0];
}
else
{
throw new InvalidOperationException("Playlist Items could not be set");
}
break; break;
case MediaPlaybackItem item: case MediaPlaybackItem item:
...@@ -320,6 +334,24 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -320,6 +334,24 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
} }
} }
public void ReInitializeSource()
{
NaturalDuration = TimeSpan.Zero;
if (Position != TimeSpan.Zero)
{
Position = TimeSpan.Zero;
}
if (_owner.Source == null)
{
return;
}
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Opening;
InitializePlayer();
ApplyVideoSource();
Events?.RaiseSourceChanged();
}
private void ApplyVideoSource() private void ApplyVideoSource()
{ {
if (this.Log().IsEnabled(LogLevel.Debug)) if (this.Log().IsEnabled(LogLevel.Debug))
...@@ -501,6 +533,23 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -501,6 +533,23 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
} }
} }
private void SetPrepared(HtmlMediaPlayer _player)
{
if (_owner.PlaybackSession.PlaybackState == MediaPlaybackState.Opening)
{
if (_isPlayRequested)
{
_player.Play();
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Playing;
}
else
{
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused;
}
}
_isPlayerPrepared = true;
}
public void OnPrepared(object? sender, object what) public void OnPrepared(object? sender, object what)
{ {
if (sender is HtmlMediaPlayer mp && _player is not null) if (sender is HtmlMediaPlayer mp && _player is not null)
...@@ -527,21 +576,10 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -527,21 +576,10 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
} }
catch { } catch { }
} }
if (NaturalDuration > TimeSpan.Zero)
if (_owner.PlaybackSession.PlaybackState == MediaPlaybackState.Opening)
{ {
if (_isPlayRequested) SetPrepared(_player);
{
_player.Play();
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Playing;
}
else
{
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.Paused;
}
} }
_isPlayerPrepared = true;
} }
if (Events is not null) if (Events is not null)
...@@ -566,6 +604,7 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -566,6 +604,7 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
OnMediaFailed(message: $"MediaPlayer Error: {(string)what}"); OnMediaFailed(message: $"MediaPlayer Error: {(string)what}");
} }
public void OnCompletion(object? sender, object what) public void OnCompletion(object? sender, object what)
{ {
if (this.Log().IsEnabled(LogLevel.Debug)) if (this.Log().IsEnabled(LogLevel.Debug))
...@@ -575,15 +614,34 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -575,15 +614,34 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
Events?.RaiseMediaEnded(); Events?.RaiseMediaEnded();
_owner.PlaybackSession.PlaybackState = MediaPlaybackState.None; _owner.PlaybackSession.PlaybackState = MediaPlaybackState.None;
if (IsLoopingEnabled && !IsLoopingAllEnabled)
// Play next item in playlist, if any
if (_playlistItems != null && _playlistIndex < _playlistItems.Count - 1)
{ {
_uri = _playlistItems[++_playlistIndex]; Play();
ApplyVideoSource(); }
else
{
// Play first item in playlist, if any and repeat all
if (_playlistItems != null && _playlistIndex >= _playlistItems.Count - 1 && IsLoopingAllEnabled)
{
_playlistIndex = 0;
_uri = _playlistItems[_playlistIndex];
ReInitializeSource();
Play();
}
else
{
// Play next item in playlist, if any
if (_playlistItems != null && _playlistIndex < _playlistItems.Count - 1)
{
_uri = _playlistItems[++_playlistIndex];
ReInitializeSource();
Play();
}
}
} }
} }
private void OnMediaFailed(global::System.Exception? ex = null, string? message = null) private void OnMediaFailed(global::System.Exception? ex = null, string? message = null)
{ {
Events?.RaiseMediaFailed(MediaPlayerError.Unknown, message ?? ex?.Message, ex); Events?.RaiseMediaFailed(MediaPlayerError.Unknown, message ?? ex?.Message, ex);
...@@ -645,4 +703,28 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension ...@@ -645,4 +703,28 @@ public partial class MediaPlayerExtension : IMediaPlayerExtension
{ {
// No effect on WebAssembly. // No effect on WebAssembly.
} }
public void PreviousTrack()
{
// Play prev item in playlist, if any
if (_playlistItems != null && _playlistIndex > 0)
{
Pause();
_uri = _playlistItems[--_playlistIndex];
ReInitializeSource();
Play();
}
}
public void NextTrack()
{
// Play next item in playlist, if any
if (_playlistItems != null && _playlistIndex < _playlistItems.Count - 1)
{
Pause();
_uri = _playlistItems[++_playlistIndex];
ReInitializeSource();
Play();
}
}
} }
...@@ -13,13 +13,25 @@ var Uno; ...@@ -13,13 +13,25 @@ var Uno;
return document.getElementById(htmlId.toString()).videoHeight; return document.getElementById(htmlId.toString()).videoHeight;
} }
static getCurrentPosition(htmlId) { static getCurrentPosition(htmlId) {
return document.getElementById(htmlId.toString()).currentTime; const element = document.getElementById(htmlId);
if (element !== null && element !== undefined) {
return element.currentTime;
}
else {
return 0;
}
} }
static getPaused(htmlId) { static getPaused(htmlId) {
return document.getElementById(htmlId.toString()).paused; const element = document.getElementById(htmlId);
if (element !== null && element !== undefined) {
return element.paused;
}
} }
static setCurrentPosition(htmlId, currentTime) { static setCurrentPosition(htmlId, currentTime) {
document.getElementById(htmlId.toString()).currentTime = currentTime; const element = document.getElementById(htmlId);
if (element !== null && element !== undefined) {
element.currentTime = currentTime;
}
} }
static setAttribute(htmlId, name, value) { static setAttribute(htmlId, name, value) {
document.getElementById(htmlId.toString()).setAttribute(name, value); document.getElementById(htmlId.toString()).setAttribute(name, value);
......
...@@ -10,15 +10,26 @@ namespace Uno.UI.Media { ...@@ -10,15 +10,26 @@ namespace Uno.UI.Media {
} }
public static getCurrentPosition(htmlId: number): number { public static getCurrentPosition(htmlId: number): number {
return document.getElementById(htmlId.toString()).currentTime; const element = document.getElementById(htmlId);
if (element !== null && element !== undefined) {
return element.currentTime;
} else {
return 0;
}
} }
public static getPaused(htmlId: number): number { public static getPaused(htmlId: number): number {
return document.getElementById(htmlId.toString()).paused; const element = document.getElementById(htmlId);
if (element !== null && element !== undefined) {
return element.paused;
}
} }
public static setCurrentPosition(htmlId: number, currentTime: number) { public static setCurrentPosition(htmlId: number, currentTime: number) {
document.getElementById(htmlId.toString()).currentTime = currentTime; const element = document.getElementById(htmlId);
if (element !== null && element !== undefined) {
element.currentTime = currentTime;
}
} }
public static setAttribute(htmlId: number, name: string, value: string) { public static setAttribute(htmlId: number, name: string, value: string) {
......
...@@ -3306,6 +3306,10 @@ ...@@ -3306,6 +3306,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Playlist.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Minimal.xaml"> <Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Minimal.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
...@@ -7213,6 +7217,9 @@ ...@@ -7213,6 +7217,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Full.xaml.cs"> <Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Full.xaml.cs">
<DependentUpon>MediaPlayerElement_Full.xaml</DependentUpon> <DependentUpon>MediaPlayerElement_Full.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Playlist.xaml.cs">
<DependentUpon>MediaPlayerElement_Playlist.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Minimal.xaml.cs"> <Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\MediaPlayerElement\MediaPlayerElement_Minimal.xaml.cs">
<DependentUpon>MediaPlayerElement_Minimal.xaml</DependentUpon> <DependentUpon>MediaPlayerElement_Minimal.xaml</DependentUpon>
</Compile> </Compile>
......
<UserControl x:Class="UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Playlist"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="">
<MediaPlayerElement x:Name="mpe"
AreTransportControlsEnabled="True"
AutoPlay="True">
<MediaPlayerElement.TransportControls>
<MediaTransportControls IsRepeatButtonVisible="True"
IsRepeatEnabled="True" />
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
</UserControl>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Uno.UI.Samples.Controls;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Media.Core;
using Windows.Media.Playback;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement
{
[SampleControlInfo("MediaPlayerElement", "Playlist", ignoreInSnapshotTests: true, description: "Test the playlist and the Repeat")]
public sealed partial class MediaPlayerElement_Playlist : UserControl
{
public MediaPlayerElement_Playlist()
{
this.InitializeComponent();
InitializePlaybackList();
}
private void InitializePlaybackList()
{
var mediaPlaybackList = new MediaPlaybackList();
mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("https://uno-assets.platform.uno/tests/videos/Mobile_Development_in_VS_Code_with_Uno_Platform_orDotNetMAUI.mp4"))));
mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("https://uno-assets.platform.uno/tests/audio/Getting_Started_with_Uno_Platform_and_Visual_Studio_Code.mp3"))));
mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("https://uno-assets.platform.uno/tests/videos/Getting_Started_with_Uno_Platform_and_Visual_Studio_Code.mp4"))));
if (mpe.MediaPlayer == null)
{
mpe.SetMediaPlayer(new Windows.Media.Playback.MediaPlayer());
}
mpe.MediaPlayer.Source = mediaPlaybackList;
}
}
}
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
"SamplesApp\\Benchmarks.Shared\\SamplesApp.Benchmarks.shproj", "SamplesApp\\Benchmarks.Shared\\SamplesApp.Benchmarks.shproj",
"SamplesApp\\SamplesApp.Shared\\SamplesApp.Shared.shproj", "SamplesApp\\SamplesApp.Shared\\SamplesApp.Shared.shproj",
"SamplesApp\\SamplesApp.Skia.Gtk\\SamplesApp.Skia.Gtk.csproj", "SamplesApp\\SamplesApp.Skia.Gtk\\SamplesApp.Skia.Gtk.csproj",
"SamplesApp\\SamplesApp.Skia.Tizen\\SamplesApp.Skia.Tizen.csproj",
"SamplesApp\\SamplesApp.Skia.Linux.FrameBuffer\\SamplesApp.Skia.Linux.FrameBuffer.csproj", "SamplesApp\\SamplesApp.Skia.Linux.FrameBuffer\\SamplesApp.Skia.Linux.FrameBuffer.csproj",
"SamplesApp\\SamplesApp.Skia.Wpf\\SamplesApp.Skia.Wpf.csproj", "SamplesApp\\SamplesApp.Skia.Wpf\\SamplesApp.Skia.Wpf.csproj",
"SamplesApp\\SamplesApp.Skia\\SamplesApp.Skia.csproj", "SamplesApp\\SamplesApp.Skia\\SamplesApp.Skia.csproj",
......
...@@ -777,25 +777,71 @@ namespace Windows.UI.Xaml.Controls ...@@ -777,25 +777,71 @@ namespace Windows.UI.Xaml.Controls
{ {
return; return;
} }
#if !(__ANDROID__ || __IOS__ || __MACOS__)
if (_mpe.MediaPlayer.IsLoopingEnabled
&& !_mpe.MediaPlayer.IsLoopingAllEnabled
&& _mpe.MediaPlayer.Source is MediaPlaybackList)
{
_mpe.MediaPlayer.IsLoopingAllEnabled = true;
}
else
{
_mpe.MediaPlayer.IsLoopingEnabled = !_mpe.MediaPlayer.IsLoopingEnabled;
_mpe.MediaPlayer.IsLoopingAllEnabled = false;
}
#else
_mpe.MediaPlayer.IsLoopingEnabled = !_mpe.MediaPlayer.IsLoopingEnabled; _mpe.MediaPlayer.IsLoopingEnabled = !_mpe.MediaPlayer.IsLoopingEnabled;
#endif
UpdateRepeatStates(); UpdateRepeatStates();
} }
private void PreviousTrackButtonTapped(object sender, RoutedEventArgs e) private void PreviousTrackButtonTapped(object sender, RoutedEventArgs e)
{ {
#if !(__ANDROID__ || __IOS__ || __MACOS__)
if (_mpe is not null
&& _mpe.MediaPlayer.Source is MediaPlaybackList)
{
_mpe?.MediaPlayer?.PreviousTrack();
}
else
{
if (_mediaPlayer is not null)
{
_mediaPlayer.PlaybackSession.Position = TimeSpan.Zero;
_mediaPlayer.PlaybackSession.Position = TimeSpan.Zero;
}
}
#else
if (_mediaPlayer is not null) if (_mediaPlayer is not null)
{ {
_mediaPlayer.PlaybackSession.Position = TimeSpan.Zero; _mediaPlayer.PlaybackSession.Position = TimeSpan.Zero;
_mediaPlayer.PlaybackSession.Position = TimeSpan.Zero; _mediaPlayer.PlaybackSession.Position = TimeSpan.Zero;
} }
#endif
} }
private void NextTrackButtonTapped(object sender, RoutedEventArgs e) private void NextTrackButtonTapped(object sender, RoutedEventArgs e)
{ {
#if !(__ANDROID__ || __IOS__ || __MACOS__)
if (_mpe is not null
&& _mpe.MediaPlayer.Source is MediaPlaybackList)
{
_mpe?.MediaPlayer?.NextTrack();
}
else
{
if (_mediaPlayer is not null)
{
_mediaPlayer.PlaybackSession.Position = _mediaPlayer.PlaybackSession.NaturalDuration;
_mediaPlayer.PlaybackSession.Position = _mediaPlayer.PlaybackSession.NaturalDuration;
}
}
#else
if (_mediaPlayer is not null) if (_mediaPlayer is not null)
{ {
_mediaPlayer.PlaybackSession.Position = _mediaPlayer.PlaybackSession.NaturalDuration; _mediaPlayer.PlaybackSession.Position = _mediaPlayer.PlaybackSession.NaturalDuration;
_mediaPlayer.PlaybackSession.Position = _mediaPlayer.PlaybackSession.NaturalDuration; _mediaPlayer.PlaybackSession.Position = _mediaPlayer.PlaybackSession.NaturalDuration;
} }
#endif
} }
private void ZoomButtonTapped(object sender, RoutedEventArgs e) private void ZoomButtonTapped(object sender, RoutedEventArgs e)
{ {
...@@ -1154,16 +1200,31 @@ namespace Windows.UI.Xaml.Controls ...@@ -1154,16 +1200,31 @@ namespace Windows.UI.Xaml.Controls
{ {
return; return;
} }
#if !(__ANDROID__ || __IOS__ || __MACOS__)
var state = _mpe.MediaPlayer.IsLoopingAllEnabled
? VisualState.RepeatStates.RepeatAllState
: _mpe.MediaPlayer.IsLoopingEnabled
? VisualState.RepeatStates.RepeatOneState
: VisualState.RepeatStates.RepeatNoneState;
VisualStateManager.GoToState(this, state, useTransitions);
var uiaKey = _mpe.MediaPlayer.IsLoopingAllEnabled
? UIAKeys.UIA_MEDIA_REPEAT_ALL
: _mpe.MediaPlayer.IsLoopingEnabled
? UIAKeys.UIA_MEDIA_REPEAT_ONE
: UIAKeys.UIA_MEDIA_REPEAT_NONE;
SetAutomationNameAndTooltip(m_tpRepeatButton, uiaKey);
#else
var state = _mpe.MediaPlayer.IsLoopingEnabled var state = _mpe.MediaPlayer.IsLoopingEnabled
? VisualState.RepeatStates.RepeatAllState ? VisualState.RepeatStates.RepeatAllState
: VisualState.RepeatStates.RepeatNoneState; : VisualState.RepeatStates.RepeatNoneState;
VisualStateManager.GoToState(this, state, useTransitions); VisualStateManager.GoToState(this, state, useTransitions);
var uiaKey = _mpe.MediaPlayer.IsLoopingEnabled var uiaKey = _mpe.MediaPlayer.IsLoopingEnabled
? UIAKeys.UIA_MEDIA_REPEAT_ALL ? UIAKeys.UIA_MEDIA_REPEAT_ALL
: UIAKeys.UIA_MEDIA_REPEAT_NONE; : UIAKeys.UIA_MEDIA_REPEAT_NONE;
SetAutomationNameAndTooltip(m_tpRepeatButton, uiaKey); SetAutomationNameAndTooltip(m_tpRepeatButton, uiaKey);
#endif
} }
} }
......
...@@ -17,10 +17,10 @@ namespace Windows.Media.Playback ...@@ -17,10 +17,10 @@ namespace Windows.Media.Playback
throw new global::System.NotImplementedException("The member MediaPlaybackAudioTrackList MediaPlaybackItem.AudioTracks is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=MediaPlaybackAudioTrackList%20MediaPlaybackItem.AudioTracks"); throw new global::System.NotImplementedException("The member MediaPlaybackAudioTrackList MediaPlaybackItem.AudioTracks is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=MediaPlaybackAudioTrackList%20MediaPlaybackItem.AudioTracks");
} }
} }
#endif #endif
#if false || false || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || false #if false || false || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__")] [global::Uno.NotImplemented("IS_UNIT_TESTS", "__NETSTD_REFERENCE__")]
public global::Windows.Media.Core.MediaSource Source public global::Windows.Media.Core.MediaSource Source
{ {
get get
{ {
...@@ -146,7 +146,7 @@ namespace Windows.Media.Playback ...@@ -146,7 +146,7 @@ namespace Windows.Media.Playback
} }
#endif #endif
// Forced skipping of method Windows.Media.Playback.MediaPlaybackItem.MediaPlaybackItem(Windows.Media.Core.MediaSource, System.TimeSpan, System.TimeSpan) // Forced skipping of method Windows.Media.Playback.MediaPlaybackItem.MediaPlaybackItem(Windows.Media.Core.MediaSource, System.TimeSpan, System.TimeSpan)
#if false || false || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || false #if false || false || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__")] [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__")]
public MediaPlaybackItem(global::Windows.Media.Core.MediaSource source) public MediaPlaybackItem(global::Windows.Media.Core.MediaSource source)
{ {
...@@ -171,7 +171,7 @@ namespace Windows.Media.Playback ...@@ -171,7 +171,7 @@ namespace Windows.Media.Playback
// Forced skipping of method Windows.Media.Playback.MediaPlaybackItem.CanSkip.set // Forced skipping of method Windows.Media.Playback.MediaPlaybackItem.CanSkip.set
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ #if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Windows.Media.Playback.MediaItemDisplayProperties GetDisplayProperties() public global::Windows.Media.Playback.MediaItemDisplayProperties GetDisplayProperties()
{ {
throw new global::System.NotImplementedException("The member MediaItemDisplayProperties MediaPlaybackItem.GetDisplayProperties() is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=MediaItemDisplayProperties%20MediaPlaybackItem.GetDisplayProperties%28%29"); throw new global::System.NotImplementedException("The member MediaItemDisplayProperties MediaPlaybackItem.GetDisplayProperties() is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=MediaItemDisplayProperties%20MediaPlaybackItem.GetDisplayProperties%28%29");
} }
......
...@@ -55,10 +55,10 @@ namespace Windows.Media.Playback ...@@ -55,10 +55,10 @@ namespace Windows.Media.Playback
throw new global::System.NotImplementedException("The member uint MediaPlaybackList.CurrentItemIndex is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=uint%20MediaPlaybackList.CurrentItemIndex"); throw new global::System.NotImplementedException("The member uint MediaPlaybackList.CurrentItemIndex is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=uint%20MediaPlaybackList.CurrentItemIndex");
} }
} }
#endif #endif
#if false || false || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || false #if false || false || IS_UNIT_TESTS || false || false || __NETSTD_REFERENCE__ || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__")] [global::Uno.NotImplemented("IS_UNIT_TESTS", "__WASM__", "__NETSTD_REFERENCE__")]
public global::Windows.Foundation.Collections.IObservableVector<global::Windows.Media.Playback.MediaPlaybackItem> Items public global::Windows.Foundation.Collections.IObservableVector<global::Windows.Media.Playback.MediaPlaybackItem> Items
{ {
get get
{ {
......
#if __IOS__ || __ANDROID__ || __MACOS__ #if __IOS__ || __ANDROID__ || __MACOS__ || __SKIA__ || __WASM__
namespace Windows.Media.Playback namespace Windows.Media.Playback
{ {
......
...@@ -29,6 +29,11 @@ namespace Uno.Media.Playback ...@@ -29,6 +29,11 @@ namespace Uno.Media.Playback
/// </summary> /// </summary>
bool IsLoopingEnabled { get; set; } bool IsLoopingEnabled { get; set; }
/// <summary>
/// Gets or sets the looping all mode
/// </summary>
bool IsLoopingAllEnabled { get; set; }
/// <summary> /// <summary>
/// Gets the current player state /// Gets the current player state
/// </summary> /// </summary>
...@@ -173,5 +178,15 @@ namespace Uno.Media.Playback ...@@ -173,5 +178,15 @@ namespace Uno.Media.Playback
/// Notifies the extension that an option has changed /// Notifies the extension that an option has changed
/// </summary> /// </summary>
void OnOptionChanged(string name, object value); void OnOptionChanged(string name, object value);
/// <summary>
/// Previous Track on a Playlist
/// </summary>
void PreviousTrack();
/// <summary>
/// Next Track on a Playlist
/// </summary>
void NextTrack();
} }
} }
#if __ANDROID__ || __IOS__ || __MACOS__ #if __ANDROID__ || __IOS__ || __MACOS__ || __SKIA__ || __WASM__
using Windows.Media.Core; using Windows.Media.Core;
namespace Windows.Media.Playback namespace Windows.Media.Playback
......
#if __ANDROID__ || __IOS__ || __MACOS__ #if __ANDROID__ || __IOS__ || __MACOS__ || __SKIA__ || __WASM__
using Windows.Foundation.Collections; using Windows.Foundation.Collections;
using Windows.Media.Playback;
namespace Windows.Media.Playback namespace Windows.Media.Playback
{ {
......
...@@ -70,6 +70,17 @@ namespace Windows.Media.Playback ...@@ -70,6 +70,17 @@ namespace Windows.Media.Playback
} }
} }
public bool IsLoopingAllEnabled
{
get => _extension?.IsLoopingAllEnabled ?? false;
set
{
if (_extension is not null)
{
_extension.IsLoopingAllEnabled = value;
}
}
}
public MediaPlayerState CurrentState public MediaPlayerState CurrentState
=> _extension?.CurrentState ?? MediaPlayerState.Closed; => _extension?.CurrentState ?? MediaPlayerState.Closed;
...@@ -201,6 +212,11 @@ namespace Windows.Media.Playback ...@@ -201,6 +212,11 @@ namespace Windows.Media.Playback
public void OnVolumeChanged() public void OnVolumeChanged()
=> _extension?.OnVolumeChanged(); => _extension?.OnVolumeChanged();
public void PreviousTrack()
=> _extension?.PreviousTrack();
public void NextTrack()
=> _extension?.NextTrack();
public event TypedEventHandler<MediaPlayer, object> BufferingEnded; public event TypedEventHandler<MediaPlayer, object> BufferingEnded;
public event TypedEventHandler<MediaPlayer, object> BufferingStarted; public event TypedEventHandler<MediaPlayer, object> BufferingStarted;
public event TypedEventHandler<MediaPlayer, object> CurrentStateChanged; public event TypedEventHandler<MediaPlayer, object> CurrentStateChanged;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册