diff --git a/Xamarin.Forms.Controls/GalleryPages/MediaElementDemoPage.cs b/Xamarin.Forms.Controls/GalleryPages/MediaElementDemoPage.cs index 47fc35e49..4be47d13c 100644 --- a/Xamarin.Forms.Controls/GalleryPages/MediaElementDemoPage.cs +++ b/Xamarin.Forms.Controls/GalleryPages/MediaElementDemoPage.cs @@ -93,6 +93,15 @@ namespace Xamarin.Forms.Controls aspectStack.Children.Add(aspectFillButton); aspectStack.Children.Add(fillButton); + var volumeSlider = new Slider() + { + Minimum = 0, + Maximum = 1 + }; + volumeSlider.Value = 0.1; + + volumeSlider.ValueChanged += VolumeSlider_ValueChanged; + var stack = new StackLayout(); stack.Padding = new Thickness(10); stack.Spacing = 10; @@ -104,9 +113,17 @@ namespace Xamarin.Forms.Controls stack.Children.Add(mediaControlStack); stack.Children.Add(aspectStack); stack.Children.Add(consoleLabel); + stack.Children.Add(new Label() { Text = "Volume:" }); + stack.Children.Add(volumeSlider); + element.Volume = 0.1; Content = stack; } + private void VolumeSlider_ValueChanged(object sender, ValueChangedEventArgs e) + { + element.Volume = (sender as Slider).Value; + } + void Element_MediaOpened(object sender, EventArgs e) { consoleLabel.Text += "Media opened" + Environment.NewLine; diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/MediaElementRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/MediaElementRenderer.cs index b3588b457..26ec848d0 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/MediaElementRenderer.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/MediaElementRenderer.cs @@ -70,6 +70,18 @@ namespace Xamarin.Forms.Platform.Android ViewRenderer.MeasureExactly(this, Element, Context); } + void UnsubscribeFromEvents(MediaElement element) + { + if (element == null) + return; + + element.PropertyChanged -= OnElementPropertyChanged; + element.SeekRequested -= SeekRequested; + element.StateRequested -= StateRequested; + element.PositionRequested -= OnPositionRequested; + + } + void IVisualElementRenderer.SetElement(VisualElement element) { if (element is null) @@ -85,9 +97,7 @@ namespace Xamarin.Forms.Platform.Android if (oldElement != null) { - oldElement.PropertyChanged -= OnElementPropertyChanged; - oldElement.SeekRequested -= SeekRequested; - oldElement.StateRequested -= StateRequested; + UnsubscribeFromEvents(oldElement); } Color currentColor = oldElement?.BackgroundColor ?? Color.Default; @@ -96,9 +106,13 @@ namespace Xamarin.Forms.Platform.Android UpdateBackgroundColor(); } - MediaElement.PropertyChanged += OnElementPropertyChanged; - MediaElement.SeekRequested += SeekRequested; - MediaElement.StateRequested += StateRequested; + if (MediaElement != null) + { + MediaElement.PropertyChanged += OnElementPropertyChanged; + MediaElement.SeekRequested += SeekRequested; + MediaElement.StateRequested += StateRequested; + MediaElement.PositionRequested += OnPositionRequested; + } if (_tracker is null) { @@ -115,6 +129,9 @@ namespace Xamarin.Forms.Platform.Android void StateRequested(object sender, StateRequested e) { + if (_view == null) + return; + switch (e.State) { case MediaElementState.Playing: @@ -142,8 +159,19 @@ namespace Xamarin.Forms.Platform.Android Controller.Position = _view.Position; } + void OnPositionRequested(object sender, EventArgs e) + { + if (_view == null) + return; + + Controller.Position = _view.Position; + } + void SeekRequested(object sender, SeekRequested e) { + if (_view == null) + return; + Controller.Position = _view.Position; } @@ -190,7 +218,7 @@ namespace Xamarin.Forms.Platform.Android if (Element != null) { - Element.PropertyChanged -= OnElementPropertyChanged; + UnsubscribeFromEvents(Element as MediaElement); if (Platform.GetRenderer(Element) == this) Element.ClearValue(Platform.RendererProperty); @@ -226,6 +254,9 @@ namespace Xamarin.Forms.Platform.Android void MetadataRetrieved(object sender, EventArgs e) { + if (_view == null) + return; + Controller.Duration = _view.DurationTimeSpan; Controller.VideoHeight = _view.VideoHeight; Controller.VideoWidth = _view.VideoWidth; @@ -276,22 +307,34 @@ namespace Xamarin.Forms.Platform.Android void UpdateKeepScreenOn() { + if (_view == null) + return; + _view.KeepScreenOn = MediaElement.KeepScreenOn; } void UpdateShowPlaybackControls() { + if (_controller == null) + return; + _controller.Visibility = MediaElement.ShowsPlaybackControls ? ViewStates.Visible : ViewStates.Gone; } void UpdateSource() { + if (_view == null) + return; + if (MediaElement.Source != null) { if (MediaElement.Source is UriMediaSource uriSource) { if (uriSource.Uri.Scheme == "ms-appx") { + if (uriSource.Uri.LocalPath.Length <= 1) + return; + // video resources should be in the raw folder with Build Action set to AndroidResource string uri = "android.resource://" + Context.PackageName + "/raw/" + uriSource.Uri.LocalPath.Substring(1, uriSource.Uri.LocalPath.LastIndexOf('.') - 1).ToLower(); _view.SetVideoURI(global::Android.Net.Uri.Parse(uri)); @@ -339,12 +382,18 @@ namespace Xamarin.Forms.Platform.Android void MediaPlayer.IOnCompletionListener.OnCompletion(MediaPlayer mp) { + if (Controller == null) + return; + Controller.Position = TimeSpan.FromMilliseconds(_mediaPlayer.CurrentPosition); Controller.OnMediaEnded(); } void MediaPlayer.IOnPreparedListener.OnPrepared(MediaPlayer mp) { + if (Controller == null) + return; + Controller.OnMediaOpened(); UpdateLayoutParameters(); @@ -366,6 +415,9 @@ namespace Xamarin.Forms.Platform.Android void UpdateLayoutParameters() { + if (_view == null) + return; + if (_view.VideoWidth == 0 || _view.VideoHeight == 0) { _view.LayoutParameters = new FrameLayout.LayoutParams(Width, Height, GravityFlags.Fill); @@ -442,13 +494,18 @@ namespace Xamarin.Forms.Platform.Android bool MediaPlayer.IOnErrorListener.OnError(MediaPlayer mp, MediaError what, int extra) { + if (Controller == null) + return false; + Controller.OnMediaFailed(); return false; } bool MediaPlayer.IOnInfoListener.OnInfo(MediaPlayer mp, MediaInfo what, int extra) { - System.Diagnostics.Debug.WriteLine(what); + if (_view == null) + return false; + switch (what) { case MediaInfo.BufferingStart: diff --git a/Xamarin.Forms.Platform.UAP/MediaElementRenderer.cs b/Xamarin.Forms.Platform.UAP/MediaElementRenderer.cs index 28eca95d6..03bbd3e24 100644 --- a/Xamarin.Forms.Platform.UAP/MediaElementRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/MediaElementRenderer.cs @@ -152,6 +152,8 @@ namespace Xamarin.Forms.Platform.UWP Controller.Duration = Control.NaturalDuration.HasTimeSpan ? Control.NaturalDuration.TimeSpan : (TimeSpan?)null; Controller.VideoHeight = Control.NaturalVideoHeight; Controller.VideoWidth = Control.NaturalVideoWidth; + Control.Volume = Element.Volume; + Control.Stretch = Element.Aspect.ToStretch(); Controller.OnMediaOpened(); } diff --git a/Xamarin.Forms.Platform.iOS/Renderers/MediaElementRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/MediaElementRenderer.cs index 86fdd670b..47bc62d61 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/MediaElementRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/MediaElementRenderer.cs @@ -56,6 +56,9 @@ namespace Xamarin.Forms.Platform.iOS { if (uriSource.Uri.Scheme == "ms-appx") { + if (uriSource.Uri.LocalPath.Length <= 1) + return; + // used for a file embedded in the application package asset = AVAsset.FromUrl(NSUrl.FromFilename(uriSource.Uri.LocalPath.Substring(1))); }