/// <summary>
        /// Provides the implementation for the Play Media Command.
        /// </summary>
        /// <returns>True if the command was successful</returns>
        private bool CommandPlayMedia()
        {
            if (!CanResumeMedia)
            {
                return(false);
            }

            foreach (var renderer in MediaCore.Renderers.Values)
            {
                renderer.Play();
            }

            MediaCore.ResumePlayback();

            return(true);
        }
Exemple #2
0
        /// <inheritdoc />
        protected override void ExecuteCycleLogic(CancellationToken ct)
        {
            #region Setup the Decoding Cycle

            // Update state properties -- this must be done on every cycle
            // because a direct command might have changed the components
            var wallClock = MediaCore.WallClock;
            var main      = Container.Components.MainMediaType;
            MediaBlockBuffer blocks;
            DecodedFrameCount = 0;
            var rangePercent = 0d;

            #endregion

            try
            {
                // The 2-part logic blocks detect a sync-buffering scenario
                // and then decodes the necessary frames.
                if (MediaCore.HasDecodingEnded || ct.IsCancellationRequested)
                {
                    return;
                }

                #region Sync-Buffering Detection

                // Capture the blocks for easier readability
                blocks = MediaCore.Blocks[main];

                // If we are not in range then we need to enter the sync-buffering state
                if (NeedsMorePackets && !MediaCore.IsSyncBuffering && blocks.IsInRange(wallClock) == false)
                {
                    // Enter sync-buffering scenario
                    MediaCore.Clock.Pause();
                    wallClock = MediaCore.WallClock;
                    MediaCore.IsSyncBuffering = true;
                    SyncBufferStartTime       = DateTime.UtcNow;
                    this.LogInfo(Aspects.DecodingWorker, $"SYNC-BUFFER: Started. Buffer: {State.BufferingProgress:p}. Clock: {wallClock.Format()}");
                }

                #endregion

                #region Component Decoding

                // We need to add blocks if the wall clock is over 75%
                // for each of the components so that we have some buffer.
                foreach (var t in Container.Components.MediaTypes)
                {
                    if (ct.IsCancellationRequested)
                    {
                        break;
                    }

                    // Capture a reference to the blocks and the current Range Percent
                    const double rangePercentThreshold = 0.75d;
                    blocks       = MediaCore.Blocks[t];
                    rangePercent = blocks.GetRangePercent(wallClock);

                    // Read as much as we can for this cycle but always within range.
                    while (blocks.IsFull == false || rangePercent > rangePercentThreshold)
                    {
                        if (ct.IsCancellationRequested || AddNextBlock(t) == false)
                        {
                            break;
                        }

                        DecodedFrameCount += 1;
                        rangePercent       = blocks.GetRangePercent(wallClock);

                        // Determine break conditions to save CPU time
                        if (rangePercent > 0 &&
                            rangePercent <= rangePercentThreshold &&
                            blocks.IsFull == false &&
                            blocks.CapacityPercent >= 0.25d &&
                            blocks.IsInRange(wallClock))
                        {
                            break;
                        }
                    }

                    #endregion
                }
            }
            finally
            {
                // Provide updates to decoding stats
                State.UpdateDecodingBitRate(
                    MediaCore.Blocks.Values.Sum(b => b.IsInRange(wallClock) ? b.RangeBitRate : 0));

                // Detect End of Decoding Scenarios
                // The Rendering will check for end of media when this
                // condition is set.
                var hasDecodingEnded = DetectHasDecodingEnded(wallClock, DecodedFrameCount, main);
                MediaCore.HasDecodingEnded = hasDecodingEnded;

                // Detect if an exit from Sync Buffering is required
                var mustExitSyncBuffering = MediaCore.IsSyncBuffering &&
                                            (ct.IsCancellationRequested || hasDecodingEnded || State.BufferingProgress >= 0.95);

                // Detect if we need an immediate exit from sync buffering
                if (mustExitSyncBuffering || (MediaCore.IsSyncBuffering && !NeedsMorePackets))
                {
                    blocks = MediaCore.Blocks[main];
                    if (blocks.Count > 0 && !blocks.IsInRange(wallClock))
                    {
                        wallClock = blocks[wallClock].StartTime;
                    }

                    MediaCore.ChangePosition(wallClock);
                    MediaCore.IsSyncBuffering = false;
                    this.LogInfo(Aspects.DecodingWorker, $"SYNC-BUFFER: Completed in {DateTime.UtcNow.Subtract(SyncBufferStartTime).TotalMilliseconds:0.0} ms");

                    if (State.MediaState == PlaybackStatus.Play)
                    {
                        MediaCore.ResumePlayback();
                    }
                }
            }
        }