microsoft / Windows-universal-samples

API samples for the Universal Windows Platform.
MIT License
9.56k stars 7.97k forks source link

SystemMediaTransportControls - Seek bar operates in auto mode regardless of whether CommandManager is enabled #477

Closed planetarian closed 8 years ago

planetarian commented 8 years ago

I'm kind of new to all this, so please forgive any poor etiquette on my part, but here we go. I discovered this problem within my own project where I'm trying to design a player for a streaming radio service that can detect when song changes occur and update the transport controls automatically. I ended up looking at this sample as a reference for manually controlling the seek bar, and found this issue when trying the method myself in my own project. Wondering if maybe I wasn't doing anything wrong, and if perhaps the sample exhibited the same problem, I tried running it and sure enough, it has the same issue. This perhaps suggests it's a framework issue, and not necessarily a problem with the sample itself, but I'm not sure where else to inquire about this.

Tested on two PCs running 14393.82, and my Lumia 950XL running 14905 Insider. Going to install the cumulative update on the non-insider desktop and see if the behavior changes (I'm guessing not).

Procedure: 1) clone https://github.com/Microsoft/Windows-universal-samples 2) open SystemMediaTransportControls.sln 3) in Scenario1.xaml.cs, comment out the line systemMediaControls.UpdateTimelineProperties(timelineProperties); 4) change target to x64 and start debugging 5) click 'select files' and open an mp3 Expected result: MediaPlayerElement seek bar should not function, as CommandManager is disabled and no timeline updates are being sent to the transport controls. Actual Result: MediaPlayerElement seek bar continues to operate automatically.

other related issue: https://github.com/Microsoft/Windows-universal-samples/issues/476

related forum post: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/fa6a9b91-a154-4467-ae80-73293454a218/uwp143938214905-mediaelement-playpause-controls-grayed-out-when-commandmanagerisenabled-?forum=wpdevelop

edit: said MediaElement, meant MediaPlayerElement.

aarononeal commented 8 years ago

Thanks for reporting this! I've asked the team to investigate.

aarononeal commented 8 years ago

The team pointed out to me you said MediaElement continues to update. This is by design.

Latest version of the sample uses MediaPlayerElement instead but this aspect is the same.

The difference here is between SystemMediaTransportControls which are global and drawn by the Windows shell, and MediaTransportControls which are instanced per UI element and updated as part of app UI when the app draws.

The line you disabled only stops updating the global system controls. There is no way to stop updating the controls on the element (only through CommandManager.PositionBehavior). If you want a special behavior here, you need to disable our controls by setting AreTransportControlsEnabled=false and draw your own custom controls.

You can also use ours but then customize it visually through re-templating or walking the visual tree and making updates.

Can you tell me, how is it you want to customize the seek bar behavior? If you just want to hide it, set MediaTransportControls.IsSeekBarVisible=false.

aarononeal commented 8 years ago

Minor update.

If CommandManager is enabled, you should be able to disable position updates to both SMTC and MTC controls by setting the PositionBehavior to disabled.

https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.playback.mediaplaybackcommandmanager.positionbehavior

Note: As of Anniversary Update there may be a platform bug where MTC continues to update even if PositionBehavior is disabled.

planetarian commented 8 years ago

The goal is not to disable the seek bar (the current version of my project already does that, since I haven't figured the rest of this out yet), but rather to cause it to actually use the correct values based on what's playing on the stream. If possible, this data should be sent over bluetooth as well, so my vehicle stereo shows the correct position and length. Also, as it's a radio stream, I intend on having a read-only seek bar (basically just a progressbar) for display purposes only. Trying to actually seek in a radio stream just interrupts it, after all.

For example, when you first connect to the stream in the middle of a song, the current position should display the current position in that song as retrieved from the stream metadata, not the actual position in the stream as the player sees it. When the song ends and a new one begins, the position should reset to zero.

I could easily implement a custom progress-bar based solution for display, however that doesn't really work with the requirement of having correct values sent via BT, so I was hoping to be able to apply values directly to the MediaPlayer somehow, thinking those values would be used for bluetooth communication, etc.. I have had a hard time finding decent documentation for things, so the best thing I could find so far was the mediaplayer's transport controls.

I found that setting MediaStreamSource.Duration affects the end time as desired, but I can find no mechanism that affects the value sent as position, and any references I have found to it either had no effect or actually tried to make the player seek to a new position, which naturally interrupts the stream.

Meanwhile, I guess at this point I'm confused as to what effect the line I commented in the sample was having at all. And yeah, sorry, I use MediaPlayerElement in my own project as well, so I'm not really sure why I said MediaElement up there.

aarononeal commented 8 years ago

Thanks for the additional scenario details, that helps.

Let me try to clarify a few things. There are 2 sets of controls:

  1. SystemMediaTransportControls (SMTC): These are global controls, drawn by the system shell, and are also how you integrate with Bluetooth.
  2. MediaTransportControls (MTC): These are XAML controls that get attached to an element and drawn in your app.

Ideally you want them to have the same visual state, but ultimately they're separate controls so they both have to be updated.

MTC updates entirely from the content played by the MediaPlayer. In this case it sounds like you're using a MediaStreamSource (MSS). The MTC will match whatever Duration and Position you report through MSS. So if those are accurate, the visual display should be accurate. The MediaStreamSample.Timestamp is what determines the position within the presentation timeline.

The SMTC can also be updated automatically from the MediaPlayer just like the MTC. That's what happens if you set MediaPlayer.CommandManager.IsEnabled = true which is the default setting. If you set it to false then that means you're planning to update all the visual state of the SMTC control yourself, such as by calling UpdateTimelineProperties.

planetarian commented 8 years ago

So, from what I gather, the only way to do this properly is to have the MSS provide the values itself and leaving the transport controls alone. I did look into this, which is where I discovered the effect of setting .Duration, but I couldn't find any way to get it to report the position at the time, and I hadn't thought of involving MediaStreamSample. It looks like I'll need to add some logic to SampleRequested, which should be doable. Thanks for the extra info.

aarononeal commented 8 years ago

Yes, the easiest way to do this would be to make sure you report the values you want shown through MSS. If using our default control settings then both SMTC and MTC will match what MSS reports since the source tells us what to draw.

If for some reason you want the controls to show something different than the source MediaPlayer is playing, then you would have to disable CommandManager, update SMTC yourself, and disable at least the seek bar of MTC and draw it yourself.