/// <summary>
        /// Select the next media bit rate using the minimum value from
        /// 2 criterias:
        /// <para>
        /// Condition 1) The bit rate selected must allow the buffer
        /// fullness to grow at least N times faster than the measured
        /// download bandwidth
        /// </para>
        /// <para>
        /// Condition 2) Using a fraction of the current buffer
        /// fullness, and a fraction of the past download bandwidth
        /// (network bit rate), find the highest bit rate encoding at
        /// which we can download to get as close as possible to the
        /// current target speed content download
        /// </para>
        /// <para>
        /// Condition 3) If in place, will not let the bit rate speed
        /// change be larger than 1 step
        /// </para>
        /// <para>
        /// NOTE speed content download is defined for a given stream
        /// bit rate (actually the bytes size) and network bit rate,
        /// as the amount of seconds worth of content that we can
        /// download per wall clock second
        /// </para>
        /// </summary>
        /// <param name="networkMediaInfo">the network media info to query</param>
        /// <param name="chunkDuration">the duration of the last chunk</param>
        /// <returns>the next bitrate to use</returns>
        private ulong GetNextBitRateUsingBandwidth(NetworkMediaInfo networkMediaInfo, double chunkDuration)
        {
            // If we are using a locked bit rate then our job is easy
            if (networkMediaInfo.LockedBitRate >= 0)
            {
                return networkMediaInfo.BitratesInfo[networkMediaInfo.LockedBitRate].NominalBitrate;
            }

            // Condition 1
            ulong bitRateCond1 = (ulong)(networkMediaInfo.DownloadBandwidthWindow.CurrentKernel / networkMediaInfo.RelativeContentDownloadSpeed);

            // Condition 2
            ulong bitRateCond2 = (ulong)
                (networkMediaInfo.DownloadBandwidthWindow.CurrentKernel
                *
                networkMediaInfo.BufferFullnessWindow.CurrentKernel
                *
                (sm_NetworkHeuristicsParams.DownloadBandwidthFraction *
                sm_NetworkHeuristicsParams.BufferFullnessFraction /
                chunkDuration));

            ulong bitRateFinal =
                bitRateCond2 < bitRateCond1 ? bitRateCond2 : bitRateCond1;

            // Condition 3
            ulong bitRateCond3 = ulong.MaxValue;

            // Only limit bitrate changes to one step at
            // a time (condition 3)
            if (networkMediaInfo.IsLimitBitrateSteps == true)
            {
                int bitRateIndex = networkMediaInfo.FindBitRateIndex(networkMediaInfo.PreviousBitrate) + 1;

                bitRateCond3 = networkMediaInfo.FindClosestBitrateByIndex(bitRateIndex);

                if (bitRateCond3 < bitRateFinal)
                {
                    bitRateFinal = bitRateCond3;
                }
            }

            NhTrace("INFO", networkMediaInfo.StreamId, "C1({0}):{1} C2:{2} C3:{3} final:{4}", networkMediaInfo.RelativeContentDownloadSpeed, bitRateCond1, bitRateCond2, bitRateCond3, bitRateFinal);

            return bitRateFinal;
        }
        /// <summary>
        /// Return the bit rate 1 step above (step > 0) or 1 step
        /// below (step less than 0) the current one
        /// </summary>
        /// <param name="networkMediaInfo">The nextwork media info to query</param>
        /// <param name="step">Increse/decrease bit rate in "step" steps</param>
        /// <returns>next bitrate, in bps</returns>
        private static ulong GetNextBitRate(NetworkMediaInfo networkMediaInfo, int step)
        {
            if (networkMediaInfo.LockedBitRate >= 0)
            {
                return networkMediaInfo.BitratesInfo[networkMediaInfo.LockedBitRate].NominalBitrate;
            }

            int index = 0;

            for (; index < networkMediaInfo.BitratesInfo.Length; index++)
            {
                if (networkMediaInfo.PreviousBitrate == networkMediaInfo.BitratesInfo[index].NominalBitrate)
                {
                    break;
                }
            }

            index += step;

            return networkMediaInfo.FindClosestBitrateByIndex(index);
        }