Open markoweb2 opened 2 years ago
My bad.
.GetAwaiter().GetResult();
still resulted in deadlocks in certain scenarios.
The correct code to use is instead:
private async void media_MediaEnded(object sender, EventArgs e)
{
await this.CloseVideo();
await this.OpenVideo();
}
private async Task CloseVideo()
{
await this.media.Close();
}
private async Task OpenVideo()
{
await this.media.Open(new Uri(@"C:\Data\VIDEO0081.mp4"));
await this.media.Play();
}
Hmh, I'm going to reopen the issue, because I'm still struggling with UI deadlocks in certain scenarios. And my gut feeling is telling me, it's all because the FFME library uses ConfigureAwait(true)
.
Also, looking at Microsoft's .net source code, they never use this type of method signature:
public ConfiguredTaskAwaitable<bool> Play()
It's always like this public Task<bool> Play()
.
Because of this ,I'm thinking that FFME should change it's public methods to this style:
public async Task<bool> Play()
{
try { return await MediaCore.Play().ConfigureAwait(false); }
catch (Exception ex) { PostMediaFailedEvent(ex); }
return false;
}
And the answers in this link seem to agree with my thinking - https://stackoverflow.com/questions/32551534/is-it-advantageous-to-use-configureawaitfalse-in-a-library-that-directly-retur
I'm also going to ask for a feature request as it is all very related to this issue. Please provide synchronous methods for people who don't want to deal with all these async problems. I for one don't want to waste any more time fighting these UI deadlocks. My videos are played in a separate window that runs in a separate thread with a separate dispatcher, I gain nothing with all these async methods, only headaches.
Also, doing something as simple as media.Close()
inside a Window/Form Closing event handler is impossible with async methods. The only option is to use a hacky workaround of initially canceling the close, with e.cancel = true;
Then fire off a this.Dispatcher.BeginInvoke(async () => { await media.Close(); this.Close(); });
You also need to wire up some logic, that the initial close would be cancelled, but the second time you close, you would actually allow the close...
One option to not cause a breaking change is to create new OpenSync()
, CloseSync()
, etc methods.
But if breaking change is to be caused by fixing the method signatures by using the style public async Task...
, then it's better to use the standard pattern of OpenAsync()
, CloseAsync()
, etc for async methods and Open()
, Close()
, etc for synchronous methods.
Also lock In view model deactive: Maybe lock UI after window closed.
await MediaElement.Close();
I think it is not suitable to use UI thread to await a Play() or Stop() async result. Maybe we can create a new thread to get Player Control state and use TaskCompletionSource
I'm running up to 8 Media simultaneously each in their own window. Play/Pause commands come from a controller as separate tasks for each Media and am experiencing deadlocks more often the more Media elements there are. A play/pause/seek command will take ~15-75ms for each usually. Occasionally (the more Medias the more likely) it will take 1-3 second to complete a Pause. Usually when this happens at least a couple of the Media have paused within the regular time, and all the rest will have had to wait for one of the other commands to complete.
I'm running with: Unosquare.FFME.Library.EnableWpfMultiThreadedVideo = true;
UI deadlock due to async methods
I think that all the async methods in the class MediaElement are incorrectly using
ConfigureAwait(true)
, because I encountered an UI deadlock (details in steps to reproduce section).Take for example in the file MediaElement.cs:
I believe the culprit do be the final outer
ConfigureAwait(true)
. All references to async deadlocks that I found when googling, refered that all libraries should useConfigureAwait(false)
wherever possible instead. For example: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.htmlI will admit, I'm not yet super familiar with all the nuances of async and await, but I do believe that the code used below is perfectly reasonable and should work without having to go through extra hoops.
Issue Categories
Version Information
Steps to Reproduce
private async void CloseVideo() { await this.media.Close(); }
private async void OpenVieo() { await this.media.Open(new Uri(@"C:\Data\VIDEO0081.mp4")); await this.media.Play(); }
C