MediaEnded Event not firing when video playing in background

Topics: Windows 8 Xaml
Dec 20, 2012 at 8:51 AM
Edited Dec 20, 2012 at 8:58 AM

I have enabled my application for background audio using:

MMPPlayer.AudioCategory = AudioCategory.BackgroundCapableMedia and wiring up the necessary MediaControl events.  All appears to be working as expected.

I am using the MMPPlayer.MediaEnded event to call a method which queues up another video. The MediaEnded event fires properly when the app is in the foreground, however, when the application is backgrounded, the MediaEnded event never fires, and thus my application fails to queue the next video and just sits dormant in the MediaControl.  How can I ensure MediaEnded fires when the application is backgrounded?

Any help on this issue is much appreciated.

-Paul

Dec 28, 2012 at 2:24 AM
Edited Jan 9, 2013 at 7:44 PM

After much tinkering, I wonder if this issue has to do with unprocessed frames in the video buffer. 

I say this for the following reasons:

When not backgrounded, MediaEnded ALWAYS fires (all video frames are processed)

When backgrounded, MediaEnded fires if you fast forward to the last 10 seconds of a video and let it play out (the video frames are not enough to stuff the buffer)

When backgrounded, MediaEnded fires if you use the Media Transport Controls to skip to another video and let it play out (i.e. the video frames for the skipped-to video never actually get processed)

 

Notes:

I am verifying the MediaEnded is firing by supplying the PlayerFramework Source in my project and setting a breakpoint in the OnMediaEnded Method of MediaPlayer.cs

I do not believe this issue has to do with threading and even went so far as to wire events off of the dispatcher just in case.  Further evidence for this not being related to threading is that I have Next and Previous methods wired up to the Media Transport control that are ALWAYS properly called when the associated buttons are clicked on the Media Transport Control.  MediaEnded is very simply, not firing at the end of playback, it's like the MediaElement does not actually think it has ended when it should.

FWIW, I saw this behavior previously in the SMF Player for Windows Phone 7 where I implemented a Video Player that rotated 180 degrees on the y-axis to show the playlist (using Visual States to respectively alter the opacity of the player / playlist depending on which should be shown).  When a video was playing, if I flipped the player 180 degrees to the playlist and kept it playing, the video frames would not be processed.  In fact, you could literally see this if you waited about 30 seconds and flipped back, you would notice the Video Player attempt to catch up by speedily processing frames.  Furthermore, if I played out an entire video while on the playlist, I would have to flip back and wait a good while for all frames to process THEN MediaEnded would fire.  I never solved this issue and instead forced the Video Player to pause when the playlist was visible. 

 

-Paul

Dec 28, 2012 at 3:59 AM
Edited Jan 9, 2013 at 7:48 PM

Here is a dirty workaround:


1. Create a global instance of a DispatcherTimer

private DispatcherTimer dispatcherTimer = new DispatcherTimer();

2. Set up a dispatcher Timer in your page Loaded Event or elsewhere that fires every 5 seconds and calls dispatcherTimer_Tick

dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan (0, 0, 5); 

dispatcherTimer.Start();

 
3. Provide the necessary logic in the callback

private void dispatcherTimer_Tick(object sender, object e)
{
if(VideoPlayer.CurrentState == MediaElementState.Playing && VideoPlayer.TimeRemaining == TimeSpan.Zero)
    DispatcherHelper.InvokeAsync(() => (//YOUR_PLAY_NEXT_METHOD)); 

}

 

If you are also using the MediaEnded event you may want to make a common PlayNext(Method) and call that from both MediaEnded and the Dispatcher Callback and incorporate a lock around this method that is released when the next video has started playing (You can get this from VideoPlayer.CurrentStateChanged and monitor for the when VideoPlayer.CurrentState == MediaElementState.Playing).  This will prevent your NEXT method from firing more than once before a video starts.


 -Paul


Dec 28, 2012 at 4:08 PM

With the MediaEnded not firing workaround, another problem appears.

If an application playing Video is backgrounded while playing and the display turns off (set power options on device to turn off after 1 min for testing), upon awakening the screen, if a Pause is initiated from the Media Transport Control, subsequent attempts to resume Playback from the Media Transport Control fail. 

*This will cause your application to fail marketplace certification.

-Paul

Jan 9, 2013 at 7:42 PM
Edited Jan 9, 2013 at 7:49 PM

I fixed the above issue by resetting the Source of the player and then initiating a MMPPlayer.Play().  If the source is not reset, the MMPPlayer will not respond after the screen goes to sleep.  The drawback of this is that Pause doesn't really pause, but rather stops playback and starts it over again.  I tried seeking to the time of the pause after resetting the player Source but this functionality did not appear to work. 

I am pleaseed to say my app has been certified.  You can find it in the Windows 8 marketplace by looking for 'Searchler'.  The app provides a good example of how to incorporate a custom playlist in the MMPPlayer.  You may note that most apps that exhibit similar custom playlist behavior do not allow seeking in their player(Music Tube, Top Music Videos for example).  It is assumed they are likely using a timer which counts down from the current video length and they can ensure this timing is correct by disabling the timer on Pause.  Using an interval based Dispatcher Timer as I have proposed will allow you to retain seek / scrubbing functionality.

-Paul

Apr 4, 2013 at 12:25 AM
judging from similar issue with SMF (and playing back WAVs from memory) a solution might be to set a MediaMarker at the MediaOpened event (can't set one before that event) and use the MediaElement.NaturalDuration there to specify that the marker is at the end. When you get the MarkerReached event for that specific marker you can stop the mediaelement by code
Apr 17, 2013 at 7:03 PM
I am also seeing this issue. is this fixed yet? Paul nailed the repro in reply (by toolboc
@ Dec 27, 2012 at 7:24 PM).

I am seeing exactly what he described and his work around worked for me (still see some flakiness that I need to figure out).
Coordinator
Apr 22, 2013 at 7:18 PM
fyi: I have a repro and a thread on the MSDN forum about this issue. Note: The issue is not specific to the player framework and can be repro'd with just a MediaElement.

Hoping the Windows team might be able to offer a workaround or explanation leading to one.