/// <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> /// When attempt to move the selected bit rate 1 step up, the /// condition is that at least a certain amount of time has /// elapsed since the last time bit rate was raised, the /// change happens provided the measured network trhoughput is /// larger than the measured media bit rate for the potential /// new bit rate to select, if no history exists for the /// target bit rate, use its nominal value /// </summary> /// <param name="networkMediaInfo">the network media info to query</param> /// <returns>New selected bit rate (may be the one used so far)</returns> private ulong AttemptImprovingBitRate(NetworkMediaInfo networkMediaInfo) { // Locked bitrate scenario is trivial if (networkMediaInfo.LockedBitRate >= 0) { return networkMediaInfo.BitratesInfo[networkMediaInfo.LockedBitRate].NominalBitrate; } // Try to improve bit rate. First get the elapsed time since // we last improved it double elapsedTimeSinceLastAttempt = networkMediaInfo.TotalStreamDownloaded - networkMediaInfo.PreviousAttempt; // Remember the previous bitrate we used ulong newBitRate = networkMediaInfo.PreviousBitrate; // Only try to improve it if our period has expired if (elapsedTimeSinceLastAttempt >= Configuration.Heuristics.Network.TryImprovingBitratePeriod) { // Move 1 step above the current one newBitRate = GetNextBitRate(networkMediaInfo, 1); // Are we actually better than before? if (newBitRate > networkMediaInfo.PreviousBitrate) { // Get the index for the new bitrate int newBitRateIndex = networkMediaInfo.FindBitRateIndex(newBitRate); // Get the encoded bit rate because we need to check if // the encoded bitrate for the new bitrate is higher than // our bandwidth window double mediaBitRate = networkMediaInfo.BitratesInfo[newBitRateIndex].EncodedBitrateWindow.CurrentKernel; // We might not have any data on this media yet if (mediaBitRate == 0) { // We don't have yet any history for this // particular bit rate, use the nominal media bit // rate mediaBitRate = networkMediaInfo.BitratesInfo[newBitRateIndex].NominalBitrate; } // If our new bitrate is larger than our bandwidth window, // then don't use it if (mediaBitRate >= networkMediaInfo.DownloadBandwidthWindow.CurrentKernel) { // Don't move up as we would exceed the network // capability newBitRate = networkMediaInfo.PreviousBitrate; } else { // Remember the current point only if moving up networkMediaInfo.PreviousAttempt = networkMediaInfo.TotalStreamDownloaded; NhTrace( "INFO", networkMediaInfo.StreamId, "mediaBitRate:{0}/{1} < downloadBandwidth:{2}, can go there", newBitRate, mediaBitRate, networkMediaInfo.DownloadBandwidthWindow.CurrentKernel); } } else { // Apparently we weren't, so use the old one newBitRate = networkMediaInfo.PreviousBitrate; } } return networkMediaInfo.FindClosestBitrateByValue(newBitRate); }