restore nuget targets for mono build

This commit is contained in:
Luke Pulverenti 2014-09-02 22:30:24 -04:00
parent a3d553a7fb
commit 60d1d5cdee
27 changed files with 396 additions and 251 deletions

View File

@ -120,12 +120,15 @@ namespace MediaBrowser.Api
/// Called when [transcode beginning].
/// </summary>
/// <param name="path">The path.</param>
/// <param name="transcodingJobId">The transcoding job identifier.</param>
/// <param name="type">The type.</param>
/// <param name="process">The process.</param>
/// <param name="deviceId">The device id.</param>
/// <param name="state">The state.</param>
/// <param name="cancellationTokenSource">The cancellation token source.</param>
public void OnTranscodeBeginning(string path,
/// <returns>TranscodingJob.</returns>
public TranscodingJob OnTranscodeBeginning(string path,
string transcodingJobId,
TranscodingJobType type,
Process process,
string deviceId,
@ -134,22 +137,37 @@ namespace MediaBrowser.Api
{
lock (_activeTranscodingJobs)
{
_activeTranscodingJobs.Add(new TranscodingJob
var job = new TranscodingJob
{
Type = type,
Path = path,
Process = process,
ActiveRequestCount = 1,
DeviceId = deviceId,
CancellationTokenSource = cancellationTokenSource
});
CancellationTokenSource = cancellationTokenSource,
Id = transcodingJobId
};
ReportTranscodingProgress(state, null, null);
_activeTranscodingJobs.Add(job);
ReportTranscodingProgress(job, state, null, null, null, null);
return job;
}
}
public void ReportTranscodingProgress(StreamState state, float? framerate, double? percentComplete)
public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded)
{
var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
if (job != null)
{
job.Framerate = framerate;
job.CompletionPercentage = percentComplete;
job.TranscodingPositionTicks = ticks;
job.BytesTranscoded = bytesTranscoded;
}
var deviceId = state.Request.DeviceId;
if (!string.IsNullOrWhiteSpace(deviceId))
@ -226,12 +244,20 @@ namespace MediaBrowser.Api
}
}
public TranscodingJob GetTranscodingJob(string id)
{
lock (_activeTranscodingJobs)
{
return _activeTranscodingJobs.FirstOrDefault(j => j.Id.Equals(id, StringComparison.OrdinalIgnoreCase));
}
}
/// <summary>
/// Called when [transcode begin request].
/// </summary>
/// <param name="path">The path.</param>
/// <param name="type">The type.</param>
public void OnTranscodeBeginRequest(string path, TranscodingJobType type)
public TranscodingJob OnTranscodeBeginRequest(string path, TranscodingJobType type)
{
lock (_activeTranscodingJobs)
{
@ -239,7 +265,7 @@ namespace MediaBrowser.Api
if (job == null)
{
return;
return null;
}
job.ActiveRequestCount++;
@ -249,40 +275,27 @@ namespace MediaBrowser.Api
job.KillTimer.Dispose();
job.KillTimer = null;
}
return job;
}
}
/// <summary>
/// Called when [transcode end request].
/// </summary>
/// <param name="path">The path.</param>
/// <param name="type">The type.</param>
public void OnTranscodeEndRequest(string path, TranscodingJobType type)
public void OnTranscodeEndRequest(TranscodingJob job)
{
lock (_activeTranscodingJobs)
job.ActiveRequestCount--;
if (job.ActiveRequestCount == 0)
{
var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
// The HLS kill timer is long - 1/2 hr. clients should use the manual kill command when stopping.
var timerDuration = job.Type == TranscodingJobType.Progressive ? 1000 : 1800000;
if (job == null)
if (job.KillTimer == null)
{
return;
job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
}
job.ActiveRequestCount--;
if (job.ActiveRequestCount == 0)
else
{
// The HLS kill timer is long - 1/2 hr. clients should use the manual kill command when stopping.
var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 1800000;
if (job.KillTimer == null)
{
job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
}
else
{
job.KillTimer.Change(timerDuration, Timeout.Infinite);
}
job.KillTimer.Change(timerDuration, Timeout.Infinite);
}
}
}
@ -306,7 +319,6 @@ namespace MediaBrowser.Api
/// <param name="acquireLock">if set to <c>true</c> [acquire lock].</param>
/// <returns>Task.</returns>
/// <exception cref="ArgumentNullException">deviceId</exception>
/// <exception cref="System.ArgumentNullException">sourcePath</exception>
internal Task KillTranscodingJobs(string deviceId, Func<string, bool> deleteFiles, bool acquireLock)
{
if (string.IsNullOrEmpty(deviceId))
@ -324,8 +336,7 @@ namespace MediaBrowser.Api
/// <param name="deleteFiles">The delete files.</param>
/// <param name="acquireLock">if set to <c>true</c> [acquire lock].</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">deviceId</exception>
internal async Task KillTranscodingJobs(Func<TranscodingJob,bool> killJob, Func<string, bool> deleteFiles, bool acquireLock)
internal async Task KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles, bool acquireLock)
{
var jobs = new List<TranscodingJob>();
@ -542,6 +553,17 @@ namespace MediaBrowser.Api
public object ProcessLock = new object();
public bool HasExited { get; set; }
public string Id { get; set; }
public float? Framerate { get; set; }
public double? CompletionPercentage { get; set; }
public long? BytesDownloaded { get; set; }
public long? BytesTranscoded { get; set; }
public long? TranscodingPositionTicks { get; set; }
public long? DownloadPositionTicks { get; set; }
}
/// <summary>

View File

@ -169,7 +169,7 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -90,10 +90,11 @@ namespace MediaBrowser.Api.Playback
/// Gets the command line arguments.
/// </summary>
/// <param name="outputPath">The output path.</param>
/// <param name="transcodingJobId">The transcoding job identifier.</param>
/// <param name="state">The state.</param>
/// <param name="isEncoding">if set to <c>true</c> [is encoding].</param>
/// <returns>System.String.</returns>
protected abstract string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding);
protected abstract string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding);
/// <summary>
/// Gets the type of the transcoding job.
@ -122,7 +123,7 @@ namespace MediaBrowser.Api.Playback
var outputFileExtension = GetOutputFileExtension(state);
var data = GetCommandLineArguments("dummy\\dummy", state, false);
var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
data += "-" + (state.Request.DeviceId ?? string.Empty);
@ -782,9 +783,10 @@ namespace MediaBrowser.Api.Playback
/// <summary>
/// Gets the input argument.
/// </summary>
/// <param name="transcodingJobId">The transcoding job identifier.</param>
/// <param name="state">The state.</param>
/// <returns>System.String.</returns>
protected string GetInputArgument(StreamState state)
protected string GetInputArgument(string transcodingJobId, StreamState state)
{
if (state.InputProtocol == MediaProtocol.File &&
state.RunTimeTicks.HasValue &&
@ -795,6 +797,8 @@ namespace MediaBrowser.Api.Playback
{
var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
url += "&transcodingJobId=" + transcodingJobId;
return string.Format("\"{0}\"", url);
}
}
@ -897,7 +901,7 @@ namespace MediaBrowser.Api.Playback
/// <param name="cancellationTokenSource">The cancellation token source.</param>
/// <returns>Task.</returns>
/// <exception cref="System.InvalidOperationException">ffmpeg was not found at + MediaEncoder.EncoderPath</exception>
protected async Task StartFfMpeg(StreamState state, string outputPath, CancellationTokenSource cancellationTokenSource)
protected async Task<TranscodingJob> StartFfMpeg(StreamState state, string outputPath, CancellationTokenSource cancellationTokenSource)
{
if (!File.Exists(MediaEncoder.EncoderPath))
{
@ -908,7 +912,8 @@ namespace MediaBrowser.Api.Playback
await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
var commandLineArgs = GetCommandLineArguments(outputPath, state, true);
var transcodingId = Guid.NewGuid().ToString("N");
var commandLineArgs = GetCommandLineArguments(outputPath, transcodingId, state, true);
if (ServerConfigurationManager.Configuration.EnableDebugEncodingLogging)
{
@ -938,7 +943,8 @@ namespace MediaBrowser.Api.Playback
EnableRaisingEvents = true
};
ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
transcodingId,
TranscodingJobType,
process,
state.Request.DeviceId,
@ -957,7 +963,7 @@ namespace MediaBrowser.Api.Playback
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine);
await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
process.Exited += (sender, args) => OnFfMpegProcessExited(process, state, outputPath);
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
try
{
@ -976,16 +982,18 @@ namespace MediaBrowser.Api.Playback
process.BeginOutputReadLine();
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream);
StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream);
// Wait for the file to exist before proceeeding
while (!File.Exists(outputPath))
{
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
}
return transcodingJob;
}
private async void StartStreamingLog(StreamState state, Stream source, Stream target)
private async void StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
{
try
{
@ -995,7 +1003,7 @@ namespace MediaBrowser.Api.Playback
{
var line = await reader.ReadLineAsync().ConfigureAwait(false);
ParseLogLine(line, state);
ParseLogLine(line, transcodingJob, state);
var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
@ -1009,10 +1017,12 @@ namespace MediaBrowser.Api.Playback
}
}
private void ParseLogLine(string line, StreamState state)
private void ParseLogLine(string line, TranscodingJob transcodingJob, StreamState state)
{
float? framerate = null;
double? percent = null;
TimeSpan? transcodingPosition = null;
long? bytesTranscoded = null;
var parts = line.Split(' ');
@ -1051,13 +1061,36 @@ namespace MediaBrowser.Api.Playback
var percentVal = currentMs / totalMs;
percent = 100 * percentVal;
transcodingPosition = val;
}
}
else if (part.StartsWith("size=", StringComparison.OrdinalIgnoreCase))
{
var size = part.Split(new[] { '=' }, 2).Last();
int? scale = null;
if (size.IndexOf("kb", StringComparison.OrdinalIgnoreCase) != -1)
{
scale = 1024;
size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase);
}
if (scale.HasValue)
{
long val;
if (long.TryParse(size, NumberStyles.Any, UsCulture, out val))
{
bytesTranscoded = val * scale.Value;
}
}
}
}
if (framerate.HasValue || percent.HasValue)
{
ApiEntryPoint.Instance.ReportTranscodingProgress(state, framerate, percent);
ApiEntryPoint.Instance.ReportTranscodingProgress(transcodingJob, state, transcodingPosition, framerate, percent, bytesTranscoded);
}
}
@ -1170,12 +1203,10 @@ namespace MediaBrowser.Api.Playback
/// Processes the exited.
/// </summary>
/// <param name="process">The process.</param>
/// <param name="job">The job.</param>
/// <param name="state">The state.</param>
/// <param name="outputPath">The output path.</param>
private void OnFfMpegProcessExited(Process process, StreamState state, string outputPath)
private void OnFfMpegProcessExited(Process process, TranscodingJob job, StreamState state)
{
var job = ApiEntryPoint.Instance.GetTranscodingJob(outputPath, TranscodingJobType);
if (job != null)
{
job.HasExited = true;

View File

@ -88,10 +88,11 @@ namespace MediaBrowser.Api.Playback.Hls
}
var playlist = state.OutputFilePath;
TranscodingJob job;
if (File.Exists(playlist))
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
}
else
{
@ -100,14 +101,14 @@ namespace MediaBrowser.Api.Playback.Hls
{
if (File.Exists(playlist))
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
}
else
{
// If the playlist doesn't already exist, startup ffmpeg
try
{
await StartFfMpeg(state, playlist, cancellationTokenSource).ConfigureAwait(false);
job = await StartFfMpeg(state, playlist, cancellationTokenSource).ConfigureAwait(false);
}
catch
{
@ -137,7 +138,10 @@ namespace MediaBrowser.Api.Playback.Hls
}
finally
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
if (job != null)
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
}
}
}
@ -162,7 +166,10 @@ namespace MediaBrowser.Api.Playback.Hls
}
finally
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
if (job != null)
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
}
}
}
@ -241,14 +248,7 @@ namespace MediaBrowser.Api.Playback.Hls
}
}
/// <summary>
/// Gets the command line arguments.
/// </summary>
/// <param name="outputPath">The output path.</param>
/// <param name="state">The state.</param>
/// <param name="isEncoding">if set to <c>true</c> [is encoding].</param>
/// <returns>System.String.</returns>
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
{
var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream;
@ -276,7 +276,7 @@ namespace MediaBrowser.Api.Playback.Hls
var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
itsOffset,
inputModifier,
GetInputArgument(state),
GetInputArgument(transcodingJobId, state),
threads,
GetMapArgs(state),
GetVideoArguments(state),

View File

@ -6,6 +6,7 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@ -107,11 +108,14 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
var segmentPath = GetSegmentPath(playlistPath, index);
var segmentLength = state.SegmentLength;
TranscodingJob job = null;
if (File.Exists(segmentPath))
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
return await GetSegmentResult(playlistPath, segmentPath, index, cancellationToken).ConfigureAwait(false);
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
}
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
@ -119,8 +123,8 @@ namespace MediaBrowser.Api.Playback.Hls
{
if (File.Exists(segmentPath))
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
return await GetSegmentResult(playlistPath, segmentPath, index, cancellationToken).ConfigureAwait(false);
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
}
else
{
@ -141,7 +145,7 @@ namespace MediaBrowser.Api.Playback.Hls
var startSeconds = index * state.SegmentLength;
request.StartTimeTicks = TimeSpan.FromSeconds(startSeconds).Ticks;
await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
}
catch
{
@ -165,7 +169,8 @@ namespace MediaBrowser.Api.Playback.Hls
}
Logger.Info("returning {0}", segmentPath);
return await GetSegmentResult(playlistPath, segmentPath, index, cancellationToken).ConfigureAwait(false);
job = job ?? ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType.Hls);
return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
}
public int? GetCurrentTranscodingIndex(string playlist)
@ -258,12 +263,17 @@ namespace MediaBrowser.Api.Playback.Hls
return Path.Combine(folder, filename + index.ToString(UsCulture) + ".ts");
}
private async Task<object> GetSegmentResult(string playlistPath, string segmentPath, int segmentIndex, CancellationToken cancellationToken)
private async Task<object> GetSegmentResult(string playlistPath,
string segmentPath,
int segmentIndex,
int segmentLength,
TranscodingJob transcodingJob,
CancellationToken cancellationToken)
{
// If all transcoding has completed, just return immediately
if (!IsTranscoding(playlistPath))
{
return ResultFactory.GetStaticFileResult(Request, segmentPath, FileShare.ReadWrite);
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
}
var segmentFilename = Path.GetFileName(segmentPath);
@ -277,7 +287,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If it appears in the playlist, it's done
if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
{
return ResultFactory.GetStaticFileResult(Request, segmentPath, FileShare.ReadWrite);
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
}
}
}
@ -286,7 +296,7 @@ namespace MediaBrowser.Api.Playback.Hls
//var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath);
//if (currentTranscodingIndex > segmentIndex)
//{
// return ResultFactory.GetStaticFileResult(Request, segmentPath, FileShare.ReadWrite);
//return GetSegmentResult(segmentPath, segmentIndex);
//}
// Wait for the file to stop being written to, then stream it
@ -317,7 +327,27 @@ namespace MediaBrowser.Api.Playback.Hls
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
return ResultFactory.GetStaticFileResult(Request, segmentPath, FileShare.ReadWrite);
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
}
private object GetSegmentResult(string segmentPath, int index, int segmentLength, TranscodingJob transcodingJob)
{
var segmentEndingSeconds = (1 + index) * segmentLength;
var segmentEndingPositionTicks = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks;
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
Path = segmentPath,
FileShare = FileShare.ReadWrite,
OnComplete = () =>
{
if (transcodingJob != null)
{
transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
}
}
});
}
private bool IsTranscoding(string playlistPath)
@ -621,14 +651,7 @@ namespace MediaBrowser.Api.Playback.Hls
return args;
}
/// <summary>
/// Gets the command line arguments.
/// </summary>
/// <param name="outputPath">The output path.</param>
/// <param name="state">The state.</param>
/// <param name="isEncoding">if set to <c>true</c> [is encoding].</param>
/// <returns>System.String.</returns>
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
{
var threads = GetNumberOfThreads(state, false);
@ -639,7 +662,7 @@ namespace MediaBrowser.Api.Playback.Hls
var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier,
GetInputArgument(state),
GetInputArgument(transcodingJobId, state),
threads,
GetMapArgs(state),
GetVideoArguments(state),

View File

@ -63,7 +63,17 @@ namespace MediaBrowser.Api.Playback.Hls
public object Get(GetHlsPlaylist request)
{
OnBeginRequest(request.PlaylistId);
var normalizedPlaylistId = request.PlaylistId.Replace("-low", string.Empty);
foreach (var playlist in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*.m3u8")
.Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
.ToList())
{
if (!string.IsNullOrEmpty(playlist))
{
ExtendPlaylistTimer(playlist);
}
}
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
@ -93,32 +103,16 @@ namespace MediaBrowser.Api.Playback.Hls
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
}
/// <summary>
/// Called when [begin request].
/// </summary>
/// <param name="playlistId">The playlist id.</param>
protected void OnBeginRequest(string playlistId)
{
var normalizedPlaylistId = playlistId.Replace("-low", string.Empty);
foreach (var playlist in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*.m3u8")
.Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
.ToList())
{
if (!string.IsNullOrEmpty(playlist))
{
ExtendPlaylistTimer(playlist);
}
}
}
private async void ExtendPlaylistTimer(string playlist)
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
var job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
await Task.Delay(20000).ConfigureAwait(false);
ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
if (job != null)
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
}
}
}
}

View File

@ -81,18 +81,7 @@ namespace MediaBrowser.Api.Playback.Hls
file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file);
OnBeginRequest(request.PlaylistId);
return ResultFactory.GetStaticFileResult(Request, file);
}
/// <summary>
/// Called when [begin request].
/// </summary>
/// <param name="playlistId">The playlist id.</param>
protected void OnBeginRequest(string playlistId)
{
var normalizedPlaylistId = playlistId.Replace("-low", string.Empty);
var normalizedPlaylistId = request.PlaylistId.Replace("-low", string.Empty);
foreach (var playlist in Directory.EnumerateFiles(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, "*.m3u8")
.Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
@ -100,15 +89,20 @@ namespace MediaBrowser.Api.Playback.Hls
{
ExtendPlaylistTimer(playlist);
}
return ResultFactory.GetStaticFileResult(Request, file);
}
private async void ExtendPlaylistTimer(string playlist)
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
var job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
await Task.Delay(20000).ConfigureAwait(false);
ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
if (job != null)
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
}
}
/// <summary>

View File

@ -55,15 +55,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return ProcessRequest(request, true);
}
/// <summary>
/// Gets the command line arguments.
/// </summary>
/// <param name="outputPath">The output path.</param>
/// <param name="state">The state.</param>
/// <param name="isEncoding">if set to <c>true</c> [is encoding].</param>
/// <returns>System.String.</returns>
/// <exception cref="System.InvalidOperationException">Only aac and mp3 audio codecs are supported.</exception>
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
{
var audioTranscodeParams = new List<string>();
@ -92,7 +84,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
inputModifier,
GetInputArgument(state),
GetInputArgument(transcodingJobId, state),
threads,
vn,
string.Join(" ", audioTranscodeParams.ToArray()),

View File

@ -142,10 +142,9 @@ namespace MediaBrowser.Api.Playback.Progressive
var outputPath = state.OutputFilePath;
var outputPathExists = File.Exists(outputPath);
var isStatic = request.Static ||
(outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive));
var isTranscodeCached = outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive);
AddDlnaHeaders(state, responseHeaders, isStatic);
AddDlnaHeaders(state, responseHeaders, request.Static || isTranscodeCached);
// Static stream
if (request.Static)
@ -154,6 +153,10 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state)
{
var job = string.IsNullOrEmpty(request.TranscodingJobId) ?
null :
ApiEntryPoint.Instance.GetTranscodingJob(request.TranscodingJobId);
var limits = new List<long>();
if (state.InputBitrate.HasValue)
{
@ -172,7 +175,13 @@ namespace MediaBrowser.Api.Playback.Progressive
}
// Take the greater of the above to methods, just to be safe
var throttleLimit = limits.Count > 0 ? limits.Max() : 0;
var throttleLimit = limits.Count > 0 ? limits.First() : 0;
// Pad to play it safe
var bytesPerSecond = Convert.ToInt64(1.05 * throttleLimit);
// Don't even start evaluating this until at least two minutes have content have been consumed
var targetGap = throttleLimit * 120;
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
@ -182,17 +191,17 @@ namespace MediaBrowser.Api.Playback.Progressive
Path = state.MediaPath,
Throttle = request.Throttle,
// Pad by 20% to play it safe
ThrottleLimit = Convert.ToInt64(1.2 * throttleLimit),
ThrottleLimit = bytesPerSecond,
// 3.5 minutes
MinThrottlePosition = throttleLimit * 210
MinThrottlePosition = targetGap,
ThrottleCallback = (l1, l2) => ThrottleCallack(l1, l2, bytesPerSecond, job)
});
}
}
// Not static but transcode cache file exists
if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
if (isTranscodeCached)
{
var contentType = state.GetMimeType(outputPath);
@ -225,6 +234,67 @@ namespace MediaBrowser.Api.Playback.Progressive
}
}
private readonly long _gapLengthInTicks = TimeSpan.FromMinutes(3).Ticks;
private long ThrottleCallack(long currentBytesPerSecond, long bytesWritten, long originalBytesPerSecond, TranscodingJob job)
{
var bytesDownloaded = job.BytesDownloaded ?? 0;
var transcodingPositionTicks = job.TranscodingPositionTicks ?? 0;
var downloadPositionTicks = job.DownloadPositionTicks ?? 0;
var path = job.Path;
if (bytesDownloaded > 0 && transcodingPositionTicks > 0)
{
// Progressive Streaming - byte-based consideration
try
{
var bytesTranscoded = job.BytesTranscoded ?? new FileInfo(path).Length;
// Estimate the bytes the transcoder should be ahead
double gapFactor = _gapLengthInTicks;
gapFactor /= transcodingPositionTicks;
var targetGap = bytesTranscoded * gapFactor;
var gap = bytesTranscoded - bytesDownloaded;
if (gap < targetGap)
{
//Logger.Debug("Not throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
return 0;
}
//Logger.Debug("Throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
}
catch
{
//Logger.Error("Error getting output size");
}
}
else if (downloadPositionTicks > 0 && transcodingPositionTicks > 0)
{
// HLS - time-based consideration
var targetGap = _gapLengthInTicks;
var gap = transcodingPositionTicks - downloadPositionTicks;
if (gap < targetGap)
{
//Logger.Debug("Not throttling transcoder gap {0} target gap {1}", gap, targetGap);
return 0;
}
//Logger.Debug("Throttling transcoder gap {0} target gap {1}", gap, targetGap);
}
else
{
//Logger.Debug("No throttle data for " + path);
}
return originalBytesPerSecond;
}
/// <summary>
/// Gets the static remote stream result.
/// </summary>
@ -325,17 +395,18 @@ namespace MediaBrowser.Api.Playback.Progressive
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
try
{
TranscodingJob job;
if (!File.Exists(outputPath))
{
await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
}
else
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
state.Dispose();
}
var job = ApiEntryPoint.Instance.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
var result = new ProgressiveStreamWriter(outputPath, Logger, FileSystem, job);
result.Options["Content-Type"] = contentType;

View File

@ -1,7 +1,8 @@
using System;
using System.Threading;
using MediaBrowser.Common.IO;
using MediaBrowser.Model.Logging;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@ -73,7 +74,10 @@ namespace MediaBrowser.Api.Playback.Progressive
}
finally
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(Path, TranscodingJobType.Progressive);
if (_job != null)
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(_job);
}
}
}
}
@ -83,6 +87,8 @@ namespace MediaBrowser.Api.Playback.Progressive
private readonly IFileSystem _fileSystem;
private readonly TranscodingJob _job;
private long _bytesWritten = 0;
public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job)
{
_fileSystem = fileSystem;
@ -98,7 +104,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{
while (eofCount < 15)
{
await fs.CopyToAsync(outputStream).ConfigureAwait(false);
await CopyToAsyncInternal(fs, outputStream, 81920, CancellationToken.None).ConfigureAwait(false);
var fsPosition = fs.Position;
@ -123,5 +129,22 @@ namespace MediaBrowser.Api.Playback.Progressive
}
}
}
private async Task CopyToAsyncInternal(Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken)
{
byte[] array = new byte[bufferSize];
int count;
while ((count = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(array, 0, count, cancellationToken).ConfigureAwait(false);
_bytesWritten += count;
if (_job != null)
{
_job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
}
}
}
}
}

View File

@ -84,14 +84,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return ProcessRequest(request, true);
}
/// <summary>
/// Gets the command line arguments.
/// </summary>
/// <param name="outputPath">The output path.</param>
/// <param name="state">The state.</param>
/// <param name="isEncoding">if set to <c>true</c> [is encoding].</param>
/// <returns>System.String.</returns>
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
{
// Get the output codec name
var videoCodec = state.OutputVideoCodec;
@ -110,7 +103,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return string.Format("{0} -i {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
inputModifier,
GetInputArgument(state),
GetInputArgument(transcodingJobId, state),
keyFrame,
GetMapArgs(state),
GetVideoArguments(state, videoCodec),

View File

@ -72,6 +72,7 @@ namespace MediaBrowser.Api.Playback
public string Params { get; set; }
public bool Throttle { get; set; }
public string TranscodingJobId { get; set; }
}
public class VideoStreamRequest : StreamRequest

View File

@ -205,7 +205,7 @@ namespace MediaBrowser.Controller.Entities
list.Add(await GetUserView(CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
//list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
return GetResult(list, query);
}
@ -283,7 +283,7 @@ namespace MediaBrowser.Controller.Entities
list.Add(await GetUserView(CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.TvSeries, user, "3", parent).ConfigureAwait(false));
//list.Add(await GetUserView(CollectionType.TvFavorites, user, "4", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
//list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
return GetResult(list, query);
}
@ -301,7 +301,7 @@ namespace MediaBrowser.Controller.Entities
list.Add(await GetUserView(CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
//list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
return GetResult(list, query);
}

View File

@ -363,7 +363,7 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -21,6 +21,9 @@ namespace MediaBrowser.Controller.Net
public bool Throttle { get; set; }
public long ThrottleLimit { get; set; }
public long MinThrottlePosition { get; set; }
public Func<long, long, long> ThrottleCallback { get; set; }
public Action OnComplete { get; set; }
public StaticResultOptions()
{

View File

@ -22,8 +22,6 @@ namespace MediaBrowser.Dlna.Ssdp
/// </summary>
public int SendCount { get; private set; }
public bool HandleBindError { get; set; }
private readonly ILogger _logger;
public Datagram(IPEndPoint toEndPoint, IPEndPoint fromEndPoint, ILogger logger, string message, int totalSendCount)
@ -44,17 +42,7 @@ namespace MediaBrowser.Dlna.Ssdp
if (FromEndPoint != null)
{
try
{
client.Bind(FromEndPoint);
}
catch
{
if (!HandleBindError)
{
throw;
}
}
client.Bind(FromEndPoint);
}
client.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>

View File

@ -124,22 +124,18 @@ namespace MediaBrowser.Dlna.Ssdp
IPEndPoint localAddress,
int sendCount = 1)
{
SendDatagram(header, values, _ssdpEndp, localAddress, false, sendCount);
SendDatagram(header, values, _ssdpEndp, localAddress, sendCount);
}
public void SendDatagram(string header,
Dictionary<string, string> values,
IPEndPoint endpoint,
IPEndPoint localAddress,
bool handleBindError,
int sendCount = 1)
{
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
var dgram = new Datagram(endpoint, localAddress, _logger, msg, sendCount)
{
HandleBindError = handleBindError
};
var dgram = new Datagram(endpoint, localAddress, _logger, msg, sendCount);
if (_messageQueue.Count == 0)
{
@ -175,7 +171,7 @@ namespace MediaBrowser.Dlna.Ssdp
values["ST"] = d.Type;
values["USN"] = d.USN;
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true);
SendDatagram(header, values, endpoint, null);
if (_config.GetDlnaConfiguration().EnableDebugLogging)
{

View File

@ -91,7 +91,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -372,7 +372,7 @@
xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\net45\" /y /d /r /i
)</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<Import Project="Fody.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -211,7 +211,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -378,8 +378,8 @@ namespace MediaBrowser.Server.Implementations.Dto
if (album != null)
{
dto.Album = item.Name;
dto.AlbumId = item.Id.ToString("N");
dto.Album = album.Name;
dto.AlbumId = album.Id.ToString("N");
}
}

View File

@ -102,14 +102,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return result;
}
private bool SupportsCompression
{
get
{
return true;
}
}
/// <summary>
/// Gets the optimized result.
/// </summary>
@ -127,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
throw new ArgumentNullException("result");
}
var optimizedResult = SupportsCompression ? requestContext.ToOptimizedResult(result) : result;
var optimizedResult = requestContext.ToOptimizedResult(result);
if (responseHeaders != null)
{
@ -471,7 +463,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
Throttle = options.Throttle,
ThrottleLimit = options.ThrottleLimit,
MinThrottlePosition = options.MinThrottlePosition
MinThrottlePosition = options.MinThrottlePosition,
ThrottleCallback = options.ThrottleCallback,
OnComplete = options.OnComplete
};
}
@ -488,41 +482,22 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
Throttle = options.Throttle,
ThrottleLimit = options.ThrottleLimit,
MinThrottlePosition = options.MinThrottlePosition
MinThrottlePosition = options.MinThrottlePosition,
ThrottleCallback = options.ThrottleCallback,
OnComplete = options.OnComplete
};
}
string content;
long originalContentLength = 0;
using (var stream = await factoryFn().ConfigureAwait(false))
{
using (var memoryStream = new MemoryStream())
using (var reader = new StreamReader(stream))
{
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0;
originalContentLength = memoryStream.Length;
using (var reader = new StreamReader(memoryStream))
{
content = await reader.ReadToEndAsync().ConfigureAwait(false);
}
content = await reader.ReadToEndAsync().ConfigureAwait(false);
}
}
if (!SupportsCompression)
{
responseHeaders["Content-Length"] = originalContentLength.ToString(UsCulture);
if (isHeadRequest)
{
return GetHttpResult(new byte[] { }, contentType);
}
return new HttpResult(content, contentType);
}
var contents = content.Compress(requestedCompressionType);
responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture);

View File

@ -27,6 +27,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public bool Throttle { get; set; }
public long ThrottleLimit { get; set; }
public long MinThrottlePosition;
public Func<long, long, long> ThrottleCallback { get; set; }
public Action OnComplete { get; set; }
/// <summary>
/// The _options
@ -167,7 +169,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
{
MinThrottlePosition = MinThrottlePosition
MinThrottlePosition = MinThrottlePosition,
ThrottleCallback = ThrottleCallback
};
}
var task = WriteToAsync(responseStream);
@ -182,22 +185,32 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <returns>Task.</returns>
private async Task WriteToAsync(Stream responseStream)
{
// Headers only
if (IsHeadRequest)
try
{
return;
}
using (var source = SourceStream)
{
// If the requested range is "0-", we can optimize by just doing a stream copy
if (RangeEnd >= TotalContentLength - 1)
// Headers only
if (IsHeadRequest)
{
await source.CopyToAsync(responseStream).ConfigureAwait(false);
return;
}
else
using (var source = SourceStream)
{
await CopyToAsyncInternal(source, responseStream, Convert.ToInt32(RangeLength), CancellationToken.None).ConfigureAwait(false);
// If the requested range is "0-", we can optimize by just doing a stream copy
if (RangeEnd >= TotalContentLength - 1)
{
await source.CopyToAsync(responseStream).ConfigureAwait(false);
}
else
{
await CopyToAsyncInternal(source, responseStream, Convert.ToInt32(RangeLength), CancellationToken.None).ConfigureAwait(false);
}
}
}
finally
{
if (OnComplete != null)
{
OnComplete();
}
}
}

View File

@ -39,6 +39,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public bool Throttle { get; set; }
public long ThrottleLimit { get; set; }
public long MinThrottlePosition;
public Func<long, long, long> ThrottleCallback { get; set; }
public Action OnComplete { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
@ -85,7 +87,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
{
MinThrottlePosition = MinThrottlePosition
MinThrottlePosition = MinThrottlePosition,
ThrottleCallback = ThrottleCallback
};
}
var task = WriteToAsync(responseStream);
@ -113,6 +116,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
throw;
}
finally
{
if (OnComplete != null)
{
OnComplete();
}
}
}
}
}

View File

@ -15,6 +15,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// </summary>
public const long Infinite = 0;
public Func<long, long, long> ThrottleCallback { get; set; }
#region Private members
/// <summary>
/// The base stream.
@ -278,6 +280,32 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
#endregion
private bool ThrottleCheck(int bufferSizeInBytes)
{
if (_bytesWritten < MinThrottlePosition)
{
return false;
}
// Make sure the buffer isn't empty.
if (_maximumBytesPerSecond <= 0 || bufferSizeInBytes <= 0)
{
return false;
}
if (ThrottleCallback != null)
{
var val = ThrottleCallback(_maximumBytesPerSecond, _bytesWritten);
if (val == 0)
{
return false;
}
}
return true;
}
#region Protected methods
/// <summary>
/// Throttles for the specified buffer size in bytes.
@ -285,15 +313,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <param name="bufferSizeInBytes">The buffer size in bytes.</param>
protected void Throttle(int bufferSizeInBytes)
{
if (_bytesWritten < MinThrottlePosition)
if (!ThrottleCheck(bufferSizeInBytes))
{
return;
}
// Make sure the buffer isn't empty.
if (_maximumBytesPerSecond <= 0 || bufferSizeInBytes <= 0)
{
return;
return ;
}
_byteCount += bufferSizeInBytes;
@ -332,13 +354,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
protected async Task ThrottleAsync(int bufferSizeInBytes, CancellationToken cancellationToken)
{
if (_bytesWritten < MinThrottlePosition)
{
return;
}
// Make sure the buffer isn't empty.
if (_maximumBytesPerSecond <= 0 || bufferSizeInBytes <= 0)
if (!ThrottleCheck(bufferSizeInBytes))
{
return;
}

View File

@ -501,7 +501,7 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -2136,7 +2136,7 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">