Maui icon indicating copy to clipboard operation
Maui copied to clipboard

Implement MediaElement

Open jfversluis opened this issue 3 years ago • 2 comments

Description of Change

TBD

Linked Issues

  • Fixes #113

PR Checklist

  • [x] Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • [ ] Has tests (if omitted, state reason in description)
  • [x] Has samples (if omitted, state reason in description)
  • [ ] Rebased on top of main at time of PR
  • [ ] Changes adhere to coding standard
  • [ ] Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pull/XYZ

Additional information

jfversluis avatar Oct 01 '22 19:10 jfversluis

Can one of the maintainers take a look at this PR for Android MediaElement: https://github.com/xamarin/XamarinCommunityToolkit/pull/1913 before you port it to Maui toolkit? It's a fix for a critical bug that both xamarin and maui users can benefit from.

I'm also willing to fix this issue https://github.com/xamarin/XamarinCommunityToolkit/issues/408 (only for Android), but I am waiting for my previous PR to get merged to avoid annoying merge conflicts. If someone can fix it for iOS too, we can close that issue.

anvuks avatar Oct 12 '22 05:10 anvuks

@anvuks don't worry about that, the implementation will be a new code here (if I'm not wrong), so there's no chance of conflicts. I'll take a look to your PR soon-sh, don't have the time to checkout and test on my end yet.

pictos avatar Oct 12 '22 16:10 pictos

I am not 100% sure yet - still testing - but could anyone of you please have a look at the MediaElementState implementation for Android?

Here's the thing: I am using an ImageButton that shows a Pause icon when the stream is currently playing and a Play icon when it is paused. I implemented that behaviour with DataTriggers like this:

<ImageButton Grid.Row="2"
  BindingContext="{x:Reference mediaElement}"
  x:Name="playButton"     
  Clicked="OnPlayPauseButtonClicked"
  HeightRequest="64"
  HorizontalOptions="CenterAndExpand"
  Source="player_pause.png"
  VerticalOptions="Center"
  WidthRequest="64">
  <ImageButton.Triggers>
    <DataTrigger
      Binding="{Binding CurrentState}"
      TargetType="ImageButton"
      Value="{x:Static media:MediaElementState.Playing}">
      <Setter Property="Source" Value="player_pause.png" />
    </DataTrigger>                  
    <DataTrigger
      Binding="{Binding CurrentState}"
      TargetType="ImageButton"
      Value="{x:Static media:MediaElementState.Paused}">
      <Setter Property="Source" Value="player_play.png" />
    </DataTrigger>                   
  </ImageButton.Triggers>
</ImageButton>

This works amazingly well on iOS. On Android however, the State seems to be always "Playing".

I looked at the code, and the Method PlatformUpdateStatus (MediaManager.android.cs) checks the players' PlaybackState which is always PlaybackStateCode.Playing (value 3) even when its paused. The funny thing is, I tried to get a deeper understanding of how ExoPlayer works internally and this state seems to actually refer to its inner Player.State which is like "STATE_READY" for play all the time... which is - coincidantally the value 3.

Maybe I am mixing something up here. All I can say that there's something wrong and I didn't figure it out on my own (yet).

UPDATE: It seems as if I am right. Referring to this post here: https://stackoverflow.com/questions/47731779/detect-pause-resume-in-exoplayer you cannot detect if the state is actually playing only by checking the PlaybackState. You also need to check the PlayWhenReady property.

I altered the code in my copy of this branch so that it now says:

switch ((PlaybackStateCode)player.PlaybackState)
{
  case PlaybackStateCode.Playing:
    videoStatus = player.PlayWhenReady ? MediaElementState.Playing : MediaElementState.Paused;
    break;

Now everything works as expected.

Mephisztoe avatar Nov 27 '22 22:11 Mephisztoe

Please remember that this is work in progress. One of the things that is very much in progress is the reporting of the states, so please don't focus on that as it will probably drastically change.

Additionally, I appreciate the PRs coming in, but please try to stick every change in a separate PR. As mentioned: the states will probably changed and now your PR is potentially blocked from merging because I do want the bugfix for the duration, but I don't want the change for the state.

jfversluis avatar Nov 29 '22 09:11 jfversluis

I have my Tizen implementation for MediaElement now :)

JoonghyunCho avatar Dec 29 '22 06:12 JoonghyunCho

Just wanted to drop a comment that I am unable to see the playback controls on iOS, even with ShowsPlaybackControls set to True. Thanks for all your hard work so far!

AnthonyIacono avatar Jan 02 '23 15:01 AnthonyIacono

Just wanted to drop a comment that I am unable to see the playback controls on iOS, even with ShowsPlaybackControls set to True. Thanks for all your hard work so far!

What version of iOS? What version of this package?

jfversluis avatar Jan 02 '23 15:01 jfversluis

Just wanted to drop a comment that I am unable to see the playback controls on iOS, even with ShowsPlaybackControls set to True. Thanks for all your hard work so far!

What version of iOS? What version of this package?

iOS 16.2 Using these packages:

        <PackageReference Include="CommunityToolkit.Maui" Version="[1.0.0-build-667.84928]" />
        <PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="[1.0.0-build-667.84928]" />

AnthonyIacono avatar Jan 02 '23 17:01 AnthonyIacono

That's strange because on iOS 16.2 and the latest code in this PR it works fine for me.

jfversluis avatar Jan 02 '23 19:01 jfversluis

That's strange because on iOS 16.2 and the latest code in this PR it works fine for me.

Have you tried when the MediaElement is inside a StackLayout? For example:

<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand">
    <mediaElement:MediaElement x:Name="MediaElement" WidthRequest="300" HeightRequest="300" ShowsPlaybackControls="True" />
</StackLayout>

I am setting the Source in the code-behind file.

AnthonyIacono avatar Jan 02 '23 20:01 AnthonyIacono

@AnthonyIacono this looks like something that will demand more time... Can you please open an issue or a discussion with a repro project?

pictos avatar Jan 02 '23 23:01 pictos

@pictos I could, but before I do I just want to make sure that is what @jfversluis wishes. I fear that if I create a separate issue, it might just make it harder to track the changes.

AnthonyIacono avatar Jan 03 '23 00:01 AnthonyIacono

I believe it will be easier to solve that on an issue than here. Where the flow and focus are on the code-review. But I'm ok to wait for Gerald's input

pictos avatar Jan 03 '23 00:01 pictos

@AnthonyIacono With just this the playback controls show fine for me

<VerticalStackLayout>
        <media:MediaElement
            WidthRequest="300"
            HeightRequest="300"
                x:Name="mediaElement"
                AutoPlay="True"
                Source="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" />

    </VerticalStackLayout>

Can you please provide a reproduction where you don't see the playback controls where they should be visible?

jfversluis avatar Jan 07 '23 09:01 jfversluis

in toolkit:MediaPlayer ShouldShowPlaybackControls="True" blocks swipe gestures. Disabling playback controls remediates the issue.

ne0rrmatrix avatar Jan 20 '23 06:01 ne0rrmatrix

in toolkit:MediaPlayer ShouldShowPlaybackControls="True" blocks swipe gestures. Disabling playback controls remediates the issue.

On which platform? Does that also happen on the platform without using .NET MAUI?

jfversluis avatar Jan 20 '23 09:01 jfversluis

in toolkit:MediaPlayer ShouldShowPlaybackControls="True" blocks swipe gestures. Disabling playback controls remediates the issue.

On which platform? Does that also happen on the platform without using .NET MAUI?

Android only. Works as expected in Windows. And it is only affected when playback controls are true. Otherwise it works in android when playback controls disabled.

ne0rrmatrix avatar Jan 20 '23 09:01 ne0rrmatrix

@ne0rrmatrix What I would be interested in is if this also happens on a Android project without .NET MAUI. I would assume it does. I can totally see how showing these controls will impact gestures. Either way, this will not be fixed with this merge. I can have a look at it later.

jfversluis avatar Jan 20 '23 09:01 jfversluis

@ne0rrmatrix What I would be interested in is if this also happens on a Android project without .NET MAUI. I would assume it does. I can totally see how showing these controls will impact gestures. Either way, this will not be fixed with this merge. I can have a look at it later.

Sample repo to reproduce issue with comments showing mitigations. https://github.com/ne0rrmatrix/MediaPlayerBugSwipeGestures Sounds good. I have a minimal sample repo for this exact problem. I will investigate further. BTW how do we test this without using maui?

ne0rrmatrix avatar Jan 20 '23 09:01 ne0rrmatrix

@ne0rrmatrix make sure to open an issue for it because we won't be monitoring this PR after it's done.

You can create a .NET 6 Android app by doing dotnet new android and you'll want to use the ExoPlayer bindings that I'm also using: https://github.com/Baseflow/ExoPlayerXamarin

jfversluis avatar Jan 20 '23 09:01 jfversluis

@ne0rrmatrix make sure to open an issue for it because we won't be monitoring this PR after it's done.

You can create a .NET 6 Android app by doing dotnet new android and you'll want to use the ExoPlayer bindings that I'm also using: https://github.com/Baseflow/ExoPlayerXamarin

I have started an issue so it can be tracked. TY for the suggestion. I have created an android app and added the exoplayer nuget package. I have the video player working. But now I need to add a main page and then navigate to player. Then add swipe gesture to test. That should keep me busy till after it gets patched. TY for the help so far. I enjoy the challenge. I am learning a lot and I will do my best to verify if the issue exists in android with just exoplayer and xamarin and nothing else. Now I have to go learn xamarin enough to do the test.

ne0rrmatrix avatar Jan 20 '23 11:01 ne0rrmatrix

@ne0rrmatrix make sure to open an issue for it because we won't be monitoring this PR after it's done. You can create a .NET 6 Android app by doing dotnet new android and you'll want to use the ExoPlayer bindings that I'm also using: https://github.com/Baseflow/ExoPlayerXamarin

I have started an issue so it can be tracked. TY for the suggestion. I have created an android app and added the exoplayer nuget package. I have the video player working. But now I need to add a main page and then navigate to player. Then add swipe gesture to test. That should keep me busy till after it gets patched. TY for the help so far. I enjoy the challenge. I am learning a lot and I will do my best to verify if the issue exists in android with just exoplayer and xamarin and nothing else. Now I have to go learn xamarin enough to do the test.

@ne0rrmatrix make sure to open an issue for it because we won't be monitoring this PR after it's done.

You can create a .NET 6 Android app by doing dotnet new android and you'll want to use the ExoPlayer bindings that I'm also using: https://github.com/Baseflow/ExoPlayerXamarin

I checked the ExoPlayer github and gestures was listed as a closed issue. It is blocked by player controls and this is intended behavior. The only way for it to work would be to add a custom handler to implement it. I am thinking of just adjusting how my app works to deal with this. The media player that you are merging is not bugged. It is working as intended in android. I just wish i knew enough to implement the change myself. It is a new project for me now. I have to learn enough to implement the feature myself or hope someone here does it for me. I think doing it myself will be a good project for me to learn new things.

ne0rrmatrix avatar Jan 20 '23 16:01 ne0rrmatrix

@ne0rrmatrix awesome investigation, thank you so much and that was kind of what I expected. Thank you for letting me know!

jfversluis avatar Jan 20 '23 16:01 jfversluis

in toolkit:MediaPlayer ShouldShowPlaybackControls="True" blocks swipe gestures. Disabling playback controls remediates the issue.

On which platform? Does that also happen on the platform without using .NET MAUI?

Android only. Works as expected in Windows. And it is only affected when playback controls are true. Otherwise it works in android when playback controls disabled.

Can you try to put it in a Frame tag?

mhrastegari avatar Jan 20 '23 16:01 mhrastegari

Custom Headers Hello this is my fist time, this is my proporsal for custom headers request in Android. MediaElement.shared.cs /// <summary> /// Backing store for the <see cref="CustomHeaders"/> property. /// </summary> public static readonly BindableProperty CustomHeadersProperty = BindableProperty.Create(nameof(CustomHeaders), typeof(Dictionary<string, string>), typeof(MediaElement), null);

/// <inheritdoc cref="IMediaElement.CustomHeaders"/> public Dictionary<string, string> CustomHeaders { get => (Dictionary<string, string>)GetValue(CustomHeadersProperty); set => SetValue(CustomHeadersProperty, value); }

IMediaElement.cs

/// <summary> /// Gets or sets headers custom headers /// </summary> Dictionary<string,string> CustomHeaders { get; set; }

MauiMediaElement.android.cs

using Com.Google.Android.Exoplayer2.Source; using Com.Google.Android.Exoplayer2.Upstream;

if (MediaElement.Source is UriMediaSource uriMediaSource) { var uri = uriMediaSource.Uri; if (!string.IsNullOrWhiteSpace(uri?.AbsoluteUri)) { if (MediaElement.CustomHeaders != null) { var httpDataSoureFactory = new DefaultHttpDataSource.Factory(); httpDataSoureFactory.SetDefaultRequestProperties(MediaElement.CustomHeaders); httpDataSoureFactory.SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0"); var mediaSource = new DefaultMediaSourceFactory(httpDataSoureFactory).CreateMediaSource(MediaItem.FromUri(uri?.AbsoluteUri)); Player.SetMediaSource(mediaSource); Player.Prepare(); hasSetSource = true; } else { Player.SetMediaItem(MediaItem.FromUri(uri.AbsoluteUri)); Player.Prepare(); hasSetSource = true; } } }

I test this implementation woking fine. Maybe if Maui Team wants, i can add User Agent. P.D: Sorry for my English. @jfversluis

Phantom-KNA avatar Aug 06 '23 00:08 Phantom-KNA

@Phantom-KNA please open a discussion and add your proposal there. This PR is already close, thanks

pictos avatar Aug 06 '23 02:08 pictos