/// <summary>
        /// heuristics implementation to select default variant 
        /// </summary>
        /// 
        void IVariantSelector.SelectVariant(HLSVariant previousVariant, HLSVariant heuristicSuggestedVariant, ref HLSVariant nextVariant, List<HLSVariant> availableVariants)
        {
            double avgBandwidth = _bwHistory.GetAverageBandwidth();
            double latestBandwidth = _bwHistory.GetLatestBandwidth();
            int i;

            if (_lastSeekPlaylistPosition == _playback.CurrentPosition)
            {
                // it is the first segment after seek. use a ratio of current bandwidth to speed up start time.
                avgBandwidth = (int)( (float)(avgBandwidth) * _bandwidthUsageRatioForFirstSegment );
            }

            // intialize with lowest bitrate playlist
            nextVariant = availableVariants[0];
            for (i = 0; i < availableVariants.Count; i++)
            {
                if (availableVariants[i].Bitrate >= _minBitrate)
                {
                    nextVariant = availableVariants[i];
                    break;
                }
            }

            // This implements the logic for selecting next variant to download.
            // We go over the variants, in the order of the highest bitrate to lowest bitrate, and calculate the targtet buffer
            // after _lookforwardDuration from current time, and select the first variant that meet these two condition:
            // 1) the end buffer size after _lookforwardDuration is larger than _highHeuristicBufferThreshold
            // 2) the low buffer (the smallest buffer size during the looking forward scan) is higher than _lowHeuristicBufferThreshold or current buffer size
            for (i = availableVariants.Count - 1; i >= 0; i--)
            {
                if (availableVariants[i].Bitrate >= _minBitrate  && availableVariants[i].Bitrate <= _maxBitrate)
                {
                    TimeSpan targetBufferSize;
                    TimeSpan lowBuffer;
                    CalculateTargeBuffer(availableVariants[i], avgBandwidth, out targetBufferSize, out lowBuffer);

                    if ((lowBuffer > _lowHeuristicBufferThreshold || lowBuffer >= BufferLevel) && targetBufferSize > _highHeuristicBufferThreshold)
                    {
                        nextVariant = availableVariants[i];
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// calculate target buffer size for a given bandwidth and HLS variant.
        /// </summary>
        private void CalculateTargeBuffer(HLSVariant nextVariant, double bandwidth, out TimeSpan targetBuffer, out TimeSpan lowbuffer)
        {
            TimeSpan totalDuration = TimeSpan.FromTicks(0);
            int streamIndex = _playback.CurrentPosition;

            if (bandwidth == BandwidthHistory.UnknownBandwidth || bandwidth == 0.00)
            {
                targetBuffer = TimeSpan.FromTicks(0);
                lowbuffer = TimeSpan.FromTicks(0);
                return;
            }

            TimeSpan SegmentDefaultDuration = TimeSpan.FromTicks(0);

            if (nextVariant.IsLoaded)
            {
                // if we cannot get the segment duration from stream, therefore we will use the target
                // duration tag instead. The target duration tag is mandatory according to HLS standard;
                // however, it is yet missing from some HLS sources. If target duration tag is missing,
                // we print out a warning message, and then we attempt to use the last segment duration,
                // and if that fails, we use a default duration _defaultTargetDuration (10 seconds). If
                // the actual segments have a different duration, then this will result in wrong
                // heuristics stream selection.
                try
                {
                    SegmentDefaultDuration = nextVariant.TargetDuration;
                }
                catch (HLSPlaylistException e)
                {
                    HLSTrace.PrintException(e);

                    if (!_targetDurationWarningShown)
                    {
                        Debug.WriteLine("The mandatory EXT-X-TARGETDURATION is missing from the HLS playlist.  \r\n" +
                                        "The heuristics algorithm needs this tag for its buffer calculations.  \r\n" +
                                        "This may result in errors in heuristics calculations.                 \r\n");
                        _targetDurationWarningShown = true;
                    }
                    if (nextVariant.Streams != null && nextVariant.Streams.Count != 0)
                        SegmentDefaultDuration = nextVariant.Streams[nextVariant.Streams.Count - 1].Duration;
                    else
                        SegmentDefaultDuration = _defaultTargetDuration;
                }
            }

            targetBuffer = BufferLevel;
            lowbuffer = BufferLevel;

            while (totalDuration < _lookforwardDuration)
            {
                double segmentSize = 0.00;
                TimeSpan segmentPlaybackDuration = TimeSpan.FromTicks(0);

                if (nextVariant.Streams == null || streamIndex >= nextVariant.Streams.Count)
                {
                    segmentPlaybackDuration = SegmentDefaultDuration;
                }
                else
                {
                    segmentPlaybackDuration = nextVariant.Streams[streamIndex].Duration;
                    segmentSize = nextVariant.Streams[streamIndex].Size;
                    streamIndex++;
                }

                // if duration is missing, use the default
                if (segmentPlaybackDuration.TotalMilliseconds == 0.00)
                    segmentPlaybackDuration = _defaultTargetDuration;

                // if segment size is not specified in playlist, use duration * bitrate
                if (segmentSize == 0)
                    segmentSize = ((double)nextVariant.Bitrate * segmentPlaybackDuration.TotalSeconds) / 8.00;

                TimeSpan segmentDownloadDuration = TimeSpan.FromSeconds((segmentSize * 8.00) / bandwidth);

                targetBuffer += ( segmentPlaybackDuration - segmentDownloadDuration );

                totalDuration += segmentPlaybackDuration;

                if (targetBuffer < lowbuffer)
                    lowbuffer = targetBuffer;
            }
        }