private async Task FirstPacketWait() { logger.Info( $"{StreamType.Audio}: Waiting for {StreamType.Video} first data packet"); try { await esStreams[(int)StreamType.Video].GetFirstDataPacketNotificationTask(); logger.Info( $"{StreamType.Audio}: {StreamType.Video} first data packet processed"); if (!activeTaskCts.Token.IsCancellationRequested) { esStreams[(int)StreamType.Audio].Start(); return; } } catch (OperationCanceledException) { logger.Info( $"{StreamType.Audio}: Wait for {StreamType.Video} first data packet cancelled"); } // Issue EOS if Player Async Operation (seek/prepare) is in progress if (IsAsyncOpRunning()) { logger.Info("Terminating player async operation by A/V EOS"); player.SubmitEosPacket(ESPlayer.StreamType.Video); player.SubmitEosPacket(ESPlayer.StreamType.Audio); } }
/// <summary> /// Pushes EOS packet to ESPlayer /// </summary> /// <param name="dataPacket">Packet</param> /// <param name="token">CancellationToken</param> /// <exception cref="PacketSubmitException"> /// Exception thrown on submit error /// </exception> private void PushEosPacket(CancellationToken token) { logger.Info(""); bool doRetry; // Continue pushing packet till success or terminal failure do { var res = player.SubmitEosPacket(streamType.ESStreamType()); doRetry = ShouldRetry(res, token); } while (doRetry && !token.IsCancellationRequested); }
public async Task Seek(TimeSpan time) { logger.Info($"Seek to {time}"); var token = activeTaskCts.Token; using (await asyncOpSerializer.LockAsync(token)) { _pendingPosition = time; logger.Info($"Seeking to {_pendingPosition}"); try { // Don't cancel FlushStreams() or its internal operations. In case of cancellation // stream controller will be in less then defined state. await FlushStreams(); // DashDataProvider - does not care about cancellation token. // HLSDataProvider - when cancelled, effectively terminates demuxer operation. // - Playback termination - no issue. // - Suspend - no way to resume demuxer other then restarting entire stream playback. var seekToTime = await Client.Seek(time, CancellationToken.None); _dataClock.Clock = seekToTime; EnableInput(); var isCompleted = await ExecuteSeek(seekToTime, token); _pendingPosition = null; if (isCompleted) { // UI, when paused, does not issue Seeks till resumed. No need to // handle seek while paused in player. SubscribeBufferingEvent(); logger.Info("End"); return; } } catch (SeekException e) { var msg = $"Seeking to {time} Failed, reason \"{e.Message}\""; logger.Error(msg); playbackErrorSubject.OnNext(msg); // Propagate subject content. await Task.Yield(); } catch (Exception e) when(e is TaskCanceledException || e is OperationCanceledException) { logger.Info($"Seeking to {time} Cancelled"); } catch (Exception e) { logger.Error(e); playbackErrorSubject.OnNext($"Seeking to {time} Failed"); throw; } // SeekException or Cancellation occurred. player.SubmitEosPacket(ESPlayer.StreamType.Audio); player.SubmitEosPacket(ESPlayer.StreamType.Video); logger.Info("EOS Sent"); } }