/// <summary> /// Calls the execution of the given command instance /// and wait for its completion without blocking the dispatcher /// </summary> /// <param name="command">The command.</param> private void ExecuteAndWaitFor(MediaCommand command) { var executeTask = Task.Run(() => { if (command.HasCompleted) { return; } command.Execute(); }); var waitTask = Task.Run(async() => { while (command.HasCompleted == false) { await Task.Delay(10); } }); while (waitTask.IsCompleted == false) { // Pump invoke Dispatcher.CurrentDispatcher.Invoke( DispatcherPriority.Background, new Action(() => { })); } }
/// <summary> /// Opens the specified URI. /// The command is processed in a Thread Pool Thread. /// </summary> /// <param name="uri">The URI.</param> /// <returns>The awaitable Open operation</returns> public DispatcherOperation Open(Uri uri) { // Check Uri Argument if (uri == null) { MediaElement?.Logger.Log( MediaLogMessageType.Warning, $"{nameof(MediaCommandManager)}.{nameof(Open)}: '{nameof(uri)}' cannot be null"); return(Dispatcher.CurrentDispatcher.CreatePumpOperation()); } if (CanExecuteCommands == false) { return(Dispatcher.CurrentDispatcher.CreatePumpOperation()); } else { IsOpening.Value = true; } var command = new OpenCommand(this, uri); ExecutingCommand = command; ClearCommandQueue(); var backgroundTask = Task.Run(() => { try { if (command.HasCompleted) { return; } command.Execute(); } catch (Exception ex) { MediaElement?.Logger.Log( MediaLogMessageType.Error, $"{nameof(MediaCommandManager)}.{nameof(Open)}: {ex.GetType()} - {ex.Message}"); } finally { ExecutingCommand?.Complete(); ExecutingCommand = null; IsOpening.Value = false; } System.Diagnostics.Debug.Assert( MediaElement.IsOpen == true && MediaElement.IsOpening == false && command.HasCompleted, "Synchronous conditions not met"); }); var operation = Dispatcher.CurrentDispatcher.CreateAsynchronousPumpWaiter(backgroundTask); return(operation); }
/// <summary> /// Enqueues the command for execution. /// </summary> /// <param name="command">The command.</param> private void EnqueueCommand(MediaCommand command) { if (MediaCore.IsOpen == false) { command.Complete(); return; } lock (SyncLock) Commands.Add(command); }
/// <summary> /// Opens the specified URI. /// This command gets processed in a threadpool thread asynchronously. /// </summary> /// <param name="uri">The URI.</param> /// <returns>The asynchronous task</returns> public async Task OpenAsync(Uri uri) { // Check Uri Argument if (uri == null) { MediaCore?.Log( MediaLogMessageType.Warning, $"{nameof(MediaCommandManager)}.{nameof(OpenAsync)}: '{nameof(uri)}' cannot be null"); return; // Task.CompletedTask; } if (CanExecuteCommands == false) { return; // Task.CompletedTask; } else { IsOpening.Value = true; } var command = new OpenCommand(this, uri); ExecutingCommand = command; ClearCommandQueue(); var action = new Action(() => { try { if (command.HasCompleted) { return; } command.RunSynchronously(); } catch (Exception ex) { MediaCore?.Log( MediaLogMessageType.Error, $"{nameof(MediaCommandManager)}.{nameof(OpenAsync)}: {ex.GetType()} - {ex.Message}"); } finally { ExecutingCommand?.Complete(); ExecutingCommand = null; IsOpening.Value = false; } }); await TaskEx.Run(action); }
/// <summary> /// Processes the next command in the command queue. /// This method is called in every block rendering cycle. /// </summary> public async Task ProcessNext() { MediaCommand command = null; lock (SyncLock) { if (Commands.Count == 0) return; command = Commands[0]; Commands.RemoveAt(0); } await command.ExecuteAsync(); }
/// <summary> /// Opens the specified custom input stream. /// This command gets processed in a threadpool thread asynchronously. /// </summary> /// <param name="stream">The custom input stream.</param> /// <returns> /// The asynchronous task /// </returns> public async Task OpenAsync(IMediaInputStream stream) { // Check Uri Argument if (stream == null) { MediaCore?.Log( MediaLogMessageType.Warning, $"{nameof(MediaCommandManager)}.{nameof(OpenAsync)}: '{nameof(stream)}' cannot be null"); return; } if (CanExecuteCommands == false) { return; } else { IsOpening.Value = true; } var command = new OpenCommand(this, stream); ExecutingCommand = command; ClearCommandQueue(); try { if (command.HasCompleted) { return; } await command.StartAsync(); } catch (Exception ex) { MediaCore?.Log( MediaLogMessageType.Error, $"{nameof(MediaCommandManager)}.{nameof(OpenAsync)}: {ex.GetType()} - {ex.Message}"); } finally { ExecutingCommand?.Complete(); ExecutingCommand = null; IsOpening.Value = false; } }
/// <summary> /// Processes the next command in the command queue. /// This method is called in every block rendering cycle. /// </summary> public void ProcessNext() { MediaCommand command = null; lock (SyncLock) { if (Commands.Count == 0) { return; } command = Commands[0]; Commands.RemoveAt(0); } command.Execute(); }
/// <summary> /// Waits for the command to complete execution. /// </summary> /// <param name="command">The command.</param> private void WaitFor(MediaCommand command) { var waitTask = Task.Run(async() => { while (command.HasCompleted == false && MediaElement.IsOpen) { await Task.Delay(10); } }); while (waitTask.IsCompleted == false) { // Pump invoke Dispatcher.CurrentDispatcher.Invoke( DispatcherPriority.Background, new Action(() => { })); } }
/// <summary> /// Closes the specified media. /// This command gets processed in a threadpool thread. /// </summary> /// <returns>The awaitable close operation</returns> public DispatcherOperation Close() { if (CanExecuteCommands == false) { return(Dispatcher.CurrentDispatcher.CreatePumpOperation()); } else { IsClosing.Value = true; } var command = new CloseCommand(this); ExecutingCommand = command; ClearCommandQueue(); var backgroundTask = Task.Run(() => { try { if (command.HasCompleted) { return; } command.Execute(); } catch (Exception ex) { MediaElement?.Logger.Log( MediaLogMessageType.Error, $"{nameof(MediaCommandManager)}.{nameof(Close)}: {ex.GetType()} - {ex.Message}"); } finally { ExecutingCommand?.Complete(); ExecutingCommand = null; IsClosing.Value = false; } }); var operation = Dispatcher.CurrentDispatcher.CreateAsynchronousPumpWaiter(backgroundTask); return(operation); }
/// <summary> /// Closes the specified media. /// This command gets processed in a threadpool thread asynchronously. /// </summary> /// <returns>Returns the background task.</returns> public async Task CloseAsync() { if (CanExecuteCommands == false) { return; } else { IsClosing.Value = true; } var command = new CloseCommand(this); ExecutingCommand = command; ClearCommandQueue(); var action = new Action(() => { try { if (command.HasCompleted) { return; } command.RunSynchronously(); } catch (Exception ex) { MediaCore?.Log( MediaLogMessageType.Error, $"{nameof(MediaCommandManager)}.{nameof(CloseAsync)}: {ex.GetType()} - {ex.Message}"); } finally { ExecutingCommand?.Complete(); ExecutingCommand = null; IsClosing.Value = false; } }); await TaskEx.Run(action); }
/// <summary> /// Processes the next command in the command queue. /// This method is called in every block rendering cycle. /// </summary> public void ProcessNext() { DumpQueue($"Before {nameof(ProcessNext)}", false); if (MediaCore.IsTaskCancellationPending) { return; } MediaCommand command = null; lock (SyncLock) { if (Commands.Count == 0) { return; } command = Commands[0]; Commands.RemoveAt(0); } try { ExecutingCommand = command; command.RunSynchronously(); DumpQueue($"After {nameof(ProcessNext)}", false); } catch (Exception ex) { MediaCore?.Log(MediaLogMessageType.Error, $"{ex.GetType()}: {ex.Message}"); throw; } finally { ExecutingCommand = null; } }