Exemple #1
0
        /// <summary>
        /// Handles PlaybackTrackChanged for our SSMEs
        /// </summary>
        private void SSME_PlaybackTrackChanged(object sender, TrackChangedEventArgs e)
        {
            var ssme =
                sender as SmoothStreamingMediaElement;

            Debug.Assert(ssme != null);

            if (ssme != null)
            {
                // work around a bug in the SSME where it raises events on a non-UI thread
                // TODO: this code can be removed once that bug is fixed
                if (!ssme.Dispatcher.CheckAccess())
                {
                    ssme.Dispatcher.BeginInvoke(() => SSME_PlaybackTrackChanged(sender, e));
                    return;
                }

                if (e.StreamType == MediaStreamType.Video)
                {
                    SSMEStateInfo ssmeStateInfo = GetSSMEStateInfoBySSME(ssme);

                    ulong lastPlaybackBitrate = e.NewTrack != null ? e.NewTrack.Bitrate : 0;
                    ssmeStateInfo.LastPlaybackTrackBitrate = lastPlaybackBitrate;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Returns the last observed DownloadTrack.Bitrate
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        public ulong GetLastDownloadBitrate(SmoothStreamingMediaElement smoothStreamingMediaElement)
        {
            SSMEStateInfo ssmeStateInfo =
                GetSSMEStateInfoThrowIfNotFound(smoothStreamingMediaElement);

            return(ssmeStateInfo.LastDownloadTrackBitrate);
        }
Exemple #3
0
        /// <summary>
        /// Updates the AverageRenderedFramesPerSecond for the SSME
        /// </summary>
        /// <param name="ssmeStateInfo"></param>
        private void UpdateAverageFramesPerSecond(SSMEStateInfo ssmeStateInfo)
        {
            double averageFPS = ssmeStateInfo.AverageRenderedFramesPerSecond;

            averageFPS = ((averageFPS + ssmeStateInfo.SmoothStreamingMediaElement.RenderedFramesPerSecond) / 2);
            ssmeStateInfo.AverageRenderedFramesPerSecond = averageFPS;
        }
Exemple #4
0
        /// <summary>
        /// GetMinimumPlaybackBitrate - gets the bitrate set during the call to SetMinimumPlaybackBitrate
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        public ulong GetMinimumPlaybackBitrate(SmoothStreamingMediaElement smoothStreamingMediaElement)
        {
            SSMEStateInfo ssmeStateInfo =
                GetSSMEStateInfoThrowIfNotFound(smoothStreamingMediaElement);

            return(ssmeStateInfo.MinimumPlaybackBitrate);
        }
Exemple #5
0
        /// <summary>
        /// Returns the last observed RenderedFramesPerSecond
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        public double GetAverageRenderedFramesPerSecond(SmoothStreamingMediaElement smoothStreamingMediaElement)
        {
            SSMEStateInfo ssmeStateInfo =
                GetSSMEStateInfoThrowIfNotFound(smoothStreamingMediaElement);

            return(ssmeStateInfo.AverageRenderedFramesPerSecond);
        }
Exemple #6
0
        /// <summary>
        /// SetMinimumPlaybackBitrate
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        /// <param name="minimumPlaybackBitrate">
        ///     The minimum bitrate (in bps) this SmoothStreamingMediaElement
        ///     must be capable of playing before the next SmoothStreamingMediaElement
        ///     should be enabled
        /// </param>
        public void SetMinimumPlaybackBitrate(SmoothStreamingMediaElement smoothStreamingMediaElement,
                                              ulong minimumPlaybackBitrate)
        {
            SSMEStateInfo ssmeStateInfo =
                GetSSMEStateInfoThrowIfNotFound(smoothStreamingMediaElement);

            ssmeStateInfo.MinimumPlaybackBitrate = minimumPlaybackBitrate;
        }
Exemple #7
0
        /// <summary>
        /// Removes a SmoothStreamingMediaElement
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        public void RemoveSmoothStreamingMediaElement(SmoothStreamingMediaElement smoothStreamingMediaElement)
        {
            SSMEStateInfo ssmeStateInfo =
                GetSSMEStateInfoThrowIfNotFound(smoothStreamingMediaElement);

            UnhookEvents(ssmeStateInfo.SmoothStreamingMediaElement);
            _ssmeStateInfoList.Remove(ssmeStateInfo);
        }
Exemple #8
0
        /// <summary>
        /// GetSSMEStateInfoThrowIfNotFound
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        private SSMEStateInfo GetSSMEStateInfoThrowIfNotFound(SmoothStreamingMediaElement smoothStreamingMediaElement)
        {
            SSMEStateInfo ssmeStateInfo = GetSSMEStateInfoBySSME(smoothStreamingMediaElement);

            if (ssmeStateInfo == null)
            {
                throw new ArgumentException(
                          "smoothStreamingMediaElement is not known to this MultiSmoothStreamingMediaElementHeuristicsManager",
                          "smoothStreamingMediaElement");
            }
            return(ssmeStateInfo);
        }
Exemple #9
0
        // clear reenable count every tick.
        private void _clearReEnableTimer_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < _ssmeStateInfoList.Count; i++)
            {
                SSMEStateInfo ssmeStateInfo = _ssmeStateInfoList[i];

                if (ssmeStateInfo.ReEnableCount >= _maxReEnableAttempts)
                {
                    ssmeStateInfo.ReEnableCount = -1;
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// SetMinimumRenderedFramesPerSecond specifies the minimum RenderedFramesPerSecond
        /// each SmoothStreamingMediaElement should sustain before the next
        /// SmoothStreamingMediaElement is enabled
        /// </summary>
        /// <param name="smoothStreamingMediaElement">smoothStreamingMediaElement</param>
        /// <param name="minimumRenderedFramesPerSecond">minimumRenderedFramesPerSecond</param>
        public void SetMinimumRenderedFramesPerSecond(SmoothStreamingMediaElement smoothStreamingMediaElement,
                                                      double minimumRenderedFramesPerSecond)
        {
            if (minimumRenderedFramesPerSecond < 0.0)
            {
                throw new ArgumentOutOfRangeException("minimumRenderedFramesPerSecond");
            }
            SSMEStateInfo ssmeStateInfo =
                GetSSMEStateInfoThrowIfNotFound(smoothStreamingMediaElement);

            ssmeStateInfo.MinimumRenderedFramesPerSecond = minimumRenderedFramesPerSecond;
        }
Exemple #11
0
        /// <summary>
        /// AddSmoothStreamingMediaElement
        /// </summary>
        /// <param name="smoothStreamingMediaElement">the SmoothStreamingMediaElement</param>
        /// <param name="minimumPlaybackBitrate">
        ///     The minimum bitrate (in bps) this SmoothStreamingMediaElement
        ///     must be capable of playing before the next SmoothStreamingMediaElement
        ///     should be enabled
        /// </param>
        /// <param name="minimumRenderedFramesPerSecond">
        ///     The minimum RenderedFramesPerSecond this SmoothStreamingMediaElement
        ///     must be achieving at the minimum bitrate before the next
        ///     SmoothStreamingMediaElement should be enabled
        /// </param>
        public void AddSmoothStreamingMediaElement(SmoothStreamingMediaElement smoothStreamingMediaElement,
                                                   ulong minimumPlaybackBitrate,
                                                   double minimumRenderedFramesPerSecond)
        {
            if (ContainsSmoothStreamingMediaElement(smoothStreamingMediaElement))
            {
                throw new ArgumentException("SmoothStreamingMediaElement has already been added",
                                            "smoothStreamingMediaElement");
            }
            if (smoothStreamingMediaElement == null)
            {
                throw new ArgumentNullException("smoothStreamingMediaElement");
            }
            if (minimumRenderedFramesPerSecond < 0.0)
            {
                throw new ArgumentOutOfRangeException("minimumRenderedFramesPerSecond");
            }

            //finally, add to our collection
            var ssmeStateInfo = new SSMEStateInfo();

            ssmeStateInfo.SmoothStreamingMediaElement    = smoothStreamingMediaElement;
            ssmeStateInfo.MinimumPlaybackBitrate         = minimumPlaybackBitrate;
            ssmeStateInfo.MinimumRenderedFramesPerSecond = minimumRenderedFramesPerSecond;

            // TODOL: workaround to get the initial download and playback bitrates,
            // this can be removed when the SSME control exposes the properties
            SmoothStreamingMediaElement coreSmoothStreamingMediaElement = smoothStreamingMediaElement;

            if (coreSmoothStreamingMediaElement != null)
            {
                ssmeStateInfo.LastDownloadTrackBitrate = coreSmoothStreamingMediaElement.VideoDownloadTrack != null
                                                             ? coreSmoothStreamingMediaElement.VideoDownloadTrack.
                                                         Bitrate
                                                             : 0;
                ssmeStateInfo.LastPlaybackTrackBitrate = coreSmoothStreamingMediaElement.VideoPlaybackTrack != null
                                                             ? coreSmoothStreamingMediaElement.VideoPlaybackTrack.
                                                         Bitrate
                                                             : 0;
            }

            _ssmeStateInfoList.Add(ssmeStateInfo);

            HookEvents(smoothStreamingMediaElement);
        }
Exemple #12
0
        /// <summary>
        /// Main heuristics logic
        /// </summary>
        private void Dispatcher_Tick(object sender, EventArgs e)
        {
            _intervalDelta += 1000;

            if (_intervalDelta < _monitorIntervalInMilliseconds)
            {
                // just update the FPS averages
                for (int i = 0; i < _ssmeStateInfoList.Count; i++)
                {
                    UpdateAverageFramesPerSecond(_ssmeStateInfoList[i]);
                }
            }
            else
            {
                _intervalDelta = 0;
                MatchPlaySpeeds();

                var enable =
                    new List <SmoothStreamingMediaElement>();

                var disable =
                    new List <SmoothStreamingMediaElement>();

                // Simple algoritm for determining which SSMEs to enable
                // or disable
                // 1) SSME 0 is always enabled
                // 2) If SSME 0 can't meet the minimum bitrate, disable
                //    all of the other SSME's
                // 3) If SSME 0 can meet the minimum bitrate, enable
                //    the next disabled SSME
                // 4) When enabling the next disabled SSME, check
                //    all of the intermediate SSMEs and make sure they
                //    are keeping up and disable them if they are not
                bool disableRest = false;
                bool enableNext  = false;
                for (int i = 0; i < _ssmeStateInfoList.Count; i++)
                {
                    SSMEStateInfo ssmeStateInfo = _ssmeStateInfoList[i];

                    if (disableRest)
                    {
                        ssmeStateInfo.RecommendedEnable = false;
                        disable.Add(ssmeStateInfo.SmoothStreamingMediaElement);
                        continue;
                    }

                    // if we're not disabling the rest, see how the
                    // current SSME is doing
                    ulong  minBitrateRequested = ssmeStateInfo.MinimumPlaybackBitrate;
                    double minRenderedFPS      = ssmeStateInfo.MinimumRenderedFramesPerSecond;
                    ulong  playbackBitrate     = ssmeStateInfo.LastPlaybackTrackBitrate;
                    ulong  downloadBitrate     = ssmeStateInfo.LastDownloadTrackBitrate;
                    UpdateAverageFramesPerSecond(ssmeStateInfo);

                    double renderedFPS = ssmeStateInfo.AverageRenderedFramesPerSecond;


                    // this next section can be replaced with a call to
                    // Math.Min(downloadTrack.Bitrate, playbackTrack.Bitrate)
                    // but I've expanded it for clarity (and to allow
                    // special tweaks for things like ads, etc)
                    ulong effectiveBitrate = 0;
                    if (downloadBitrate < playbackBitrate)
                    {
                        // we're downloading a lower bitrate than
                        // we're playing - so we're scaling down
                        // which means we can't handle this bitrate
                        effectiveBitrate = downloadBitrate;
                    }
                    else if (downloadBitrate > playbackBitrate)
                    {
                        // we're downloading a higher bitrate, so we can
                        // handle playing this bitrate.  We're still not
                        // sure if we can handle playing this bitrate, so
                        // use the bitrate we know we can handle
                        effectiveBitrate = playbackBitrate;
                    }
                    else
                    {
                        effectiveBitrate = playbackBitrate;
                    }

                    if (effectiveBitrate == 0)
                    {
                        // we can get into this state if downloadBitrate
                        // has never been updated
                        effectiveBitrate = Math.Max(playbackBitrate, downloadBitrate);
                    }

                    if (enableNext)
                    {
                        // The previous SSME was playing or downloading at or above
                        // the minBitrate - enable the next disabled SSME
                        // but check enabled SSME's along the way and make sure
                        // they can still handle playback
                        if (ssmeStateInfo.RecommendedEnable)
                        {
                            // we previously recommended enabling this
                            // SSME - let's check in and make sure
                            // it should still be enabled
                            if (effectiveBitrate < minBitrateRequested ||
                                (renderedFPS < minRenderedFPS && !GetIsMinimized(renderedFPS)))
                            {
                                // this enabled SSME is not keeping up
                                ssmeStateInfo.RecommendedEnable = false;
                                disable.Add(ssmeStateInfo.SmoothStreamingMediaElement);
                                disableRest = true;
                            }
                            else
                            {
                                // continue recommeding this SSME be enabled
                                enable.Add(ssmeStateInfo.SmoothStreamingMediaElement);
                            }
                        }
                        else
                        {
                            // we were asked to enable the next disabled
                            // SSME, and along our way to find it we have
                            // validated the all of the other enabled SSME's
                            // should still be enabled.  It's time to turn on
                            // a disabled SSME (if it hasn't been re-enabled
                            // too many times)
                            ssmeStateInfo.ReEnableCount++;
                            if (ssmeStateInfo.ReEnableCount > MaxReenableAttempts)
                            {
                                // changed our mind
                                ssmeStateInfo.RecommendedEnable = false;
                                disable.Add(ssmeStateInfo.SmoothStreamingMediaElement);

                                // since we disable SSME's in a cascading fashion
                                // if index 1 is being turned off, we're disabling all
                                // of the secondary SSMEs - set our flag
                                if (i == 1)
                                {
                                    _recommendPermanentlyDisableAllSecondary = true;
                                }
                            }
                            else
                            {
                                // go ahead and turn this SSME back on
                                ssmeStateInfo.RecommendedEnable = true;
                                enable.Add(ssmeStateInfo.SmoothStreamingMediaElement);
                            }

                            // either way - the rest of you can just chill out
                            disableRest = true;
                        }
                    }

                    if (i == 0)
                    {
                        // this is our first pass through the heuristics loop and it
                        // is a special one because we treat the primary SSME special.
                        // It is never disabled and if it can't keep up, it can
                        // disable all of the secondary SSMEs
                        enable.Add(ssmeStateInfo.SmoothStreamingMediaElement);
                        ssmeStateInfo.RecommendedEnable = true;

                        bool browserIsMinimized = GetIsMinimized(renderedFPS);

                        // if we're minimized we need to disable our secondary SSMEs
                        if (effectiveBitrate < minBitrateRequested ||
                            renderedFPS < minRenderedFPS ||
                            browserIsMinimized)
                        {
                            // we're not keeping up (or are minimized), disable the other SSMEs
                            disableRest = true;

                            if (browserIsMinimized)
                            {
                                // if the browser is minimized we're disabling the secondary
                                // SSME's to prevent a slideshow, but we don't want
                                // this disabling to count against the ReEnable counts
                                for (int j = 1; j < _ssmeStateInfoList.Count; j++)
                                {
                                    _ssmeStateInfoList[j].DecrementReEnableCount();
                                }
                            }
                        }

                        else
                        {
                            // we're keeping up - evaluating enabling the next SSME
                            enableNext = true;
                        }
                    }
                }

                //raise our event
                RaiseRecommendationChanged(enable, disable);
            }
        }
        /// <summary>
        /// AddSmoothStreamingMediaElement
        /// </summary>
        /// <param name="smoothStreamingMediaElement">the SmoothStreamingMediaElement</param>
        /// <param name="minimumPlaybackBitrate">
        ///     The minimum bitrate (in bps) this SmoothStreamingMediaElement
        ///     must be capable of playing before the next SmoothStreamingMediaElement
        ///     should be enabled
        /// </param>
        /// <param name="minimumRenderedFramesPerSecond">
        ///     The minimum RenderedFramesPerSecond this SmoothStreamingMediaElement
        ///     must be achieving at the minimum bitrate before the next 
        ///     SmoothStreamingMediaElement should be enabled
        /// </param>
        public void AddSmoothStreamingMediaElement(SmoothStreamingMediaElement smoothStreamingMediaElement,
                                                   ulong minimumPlaybackBitrate,
                                                   double minimumRenderedFramesPerSecond)
        {
            if (ContainsSmoothStreamingMediaElement(smoothStreamingMediaElement))
            {
                throw new ArgumentException("SmoothStreamingMediaElement has already been added",
                                            "smoothStreamingMediaElement");
            }
            if (smoothStreamingMediaElement == null)
            {
                throw new ArgumentNullException("smoothStreamingMediaElement");
            }
            if (minimumRenderedFramesPerSecond < 0.0)
            {
                throw new ArgumentOutOfRangeException("minimumRenderedFramesPerSecond");
            }

            //finally, add to our collection
            var ssmeStateInfo = new SSMEStateInfo();
            ssmeStateInfo.SmoothStreamingMediaElement = smoothStreamingMediaElement;
            ssmeStateInfo.MinimumPlaybackBitrate = minimumPlaybackBitrate;
            ssmeStateInfo.MinimumRenderedFramesPerSecond = minimumRenderedFramesPerSecond;

            // TODOL: workaround to get the initial download and playback bitrates,
            // this can be removed when the SSME control exposes the properties
            SmoothStreamingMediaElement coreSmoothStreamingMediaElement = smoothStreamingMediaElement;
            if (coreSmoothStreamingMediaElement != null)
            {
                ssmeStateInfo.LastDownloadTrackBitrate = coreSmoothStreamingMediaElement.VideoDownloadTrack != null
                                                             ? coreSmoothStreamingMediaElement.VideoDownloadTrack.
                                                                   Bitrate
                                                             : 0;
                ssmeStateInfo.LastPlaybackTrackBitrate = coreSmoothStreamingMediaElement.VideoPlaybackTrack != null
                                                             ? coreSmoothStreamingMediaElement.VideoPlaybackTrack.
                                                                   Bitrate
                                                             : 0;
            }

            _ssmeStateInfoList.Add(ssmeStateInfo);

            HookEvents(smoothStreamingMediaElement);
        }
 /// <summary>
 /// Updates the AverageRenderedFramesPerSecond for the SSME
 /// </summary>
 /// <param name="ssmeStateInfo"></param>
 private void UpdateAverageFramesPerSecond(SSMEStateInfo ssmeStateInfo)
 {
     double averageFPS = ssmeStateInfo.AverageRenderedFramesPerSecond;
     averageFPS = ((averageFPS + ssmeStateInfo.SmoothStreamingMediaElement.RenderedFramesPerSecond)/2);
     ssmeStateInfo.AverageRenderedFramesPerSecond = averageFPS;
 }