update recording stoppage

This commit is contained in:
Luke Pulverenti 2016-02-29 23:24:42 -05:00
parent c3eb571d1d
commit 2eb492f865
5 changed files with 73 additions and 36 deletions

View file

@ -23,7 +23,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_fileSystem = fileSystem;
}
public async Task Record(MediaSourceInfo mediaSource, string targetFile, Action onStarted, CancellationToken cancellationToken)
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
var httpRequestOptions = new HttpRequestOptions()
{
@ -42,7 +42,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Copying recording stream to file stream");
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
var durationToken = new CancellationTokenSource(duration);
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken).ConfigureAwait(false);
}
}
}

View file

@ -103,8 +103,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
private readonly ConcurrentDictionary<string, CancellationTokenSource> _activeRecordings =
new ConcurrentDictionary<string, CancellationTokenSource>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
public string Name
{
@ -268,11 +268,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
_timerProvider.Delete(remove);
}
CancellationTokenSource cancellationTokenSource;
ActiveRecordingInfo activeRecordingInfo;
if (_activeRecordings.TryGetValue(timerId, out cancellationTokenSource))
if (_activeRecordings.TryGetValue(timerId, out activeRecordingInfo))
{
cancellationTokenSource.Cancel();
activeRecordingInfo.CancellationTokenSource.Cancel();
}
}
@ -653,11 +653,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return;
}
var cancellationTokenSource = new CancellationTokenSource();
if (_activeRecordings.TryAdd(timer.Id, cancellationTokenSource))
var activeRecordingInfo = new ActiveRecordingInfo
{
await RecordStream(timer, recordingEndDate, cancellationTokenSource.Token).ConfigureAwait(false);
CancellationTokenSource = new CancellationTokenSource(),
TimerId = timer.Id
};
if (_activeRecordings.TryAdd(timer.Id, activeRecordingInfo))
{
await RecordStream(timer, recordingEndDate, activeRecordingInfo, activeRecordingInfo.CancellationTokenSource.Token).ConfigureAwait(false);
}
else
{
@ -674,7 +678,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, CancellationToken cancellationToken)
private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
{
if (timer == null)
{
@ -729,8 +733,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts";
recordPath = Path.Combine(recordPath, recordingFileName);
recordPath = EnsureFileUnique(recordPath);
_fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
var recordingId = info.Id.GetMD5().ToString("N");
var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, recordingId, StringComparison.OrdinalIgnoreCase));
@ -788,6 +790,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
recordPath = Path.ChangeExtension(recordPath, ".mp4");
}
recordPath = EnsureFileUnique(recordPath, timer.Id);
_fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
activeRecordingInfo.Path = recordPath;
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
@ -798,9 +803,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
var durationToken = new CancellationTokenSource(duration);
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
_logger.Info("Writing file to path: " + recordPath);
_logger.Info("Opening recording stream from tuner provider");
@ -810,10 +812,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
isResourceOpen = false;
};
await recorder.Record(mediaStreamInfo, recordPath, onStarted, linkedToken).ConfigureAwait(false);
await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);
recording.Status = RecordingStatus.Completed;
_logger.Info("Recording completed");
_logger.Info("Recording completed: {0}", recordPath);
}
finally
{
@ -827,17 +829,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
catch (OperationCanceledException)
{
_logger.Info("Recording stopped");
_logger.Info("Recording stopped: {0}", recordPath);
recording.Status = RecordingStatus.Completed;
}
catch (Exception ex)
{
_logger.ErrorException("Error recording", ex);
_logger.ErrorException("Error recording to {0}", ex, recordPath);
recording.Status = RecordingStatus.Error;
}
finally
{
CancellationTokenSource removed;
ActiveRecordingInfo removed;
_activeRecordings.TryRemove(timer.Id, out removed);
}
@ -863,12 +865,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
private string EnsureFileUnique(string path)
private string EnsureFileUnique(string path, string timerId)
{
var originalPath = path;
var index = 1;
while (_fileSystem.FileExists(path))
while (FileExists(path, timerId))
{
var parent = Path.GetDirectoryName(originalPath);
var name = Path.GetFileNameWithoutExtension(originalPath);
@ -881,6 +883,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return path;
}
private bool FileExists(string path, string timerId)
{
if (_fileSystem.FileExists(path))
{
return true;
}
var hasRecordingAtPath = _activeRecordings.Values.ToList().Any(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.TimerId, timerId, StringComparison.OrdinalIgnoreCase));
if (hasRecordingAtPath)
{
return true;
}
return false;
}
private async Task<IRecorder> GetRecorder()
{
if (GetConfiguration().EnableRecordingEncoding)
@ -1064,7 +1082,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
foreach (var pair in _activeRecordings.ToList())
{
pair.Value.Cancel();
pair.Value.CancellationTokenSource.Cancel();
}
}
@ -1081,5 +1099,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
IsRegistered = true
});
}
class ActiveRecordingInfo
{
public string Path { get; set; }
public string TimerId { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
}
}
}

View file

@ -38,7 +38,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_json = json;
}
public async Task Record(MediaSourceInfo mediaSource, string targetFile, Action onStarted, CancellationToken cancellationToken)
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
_targetPath = targetFile;
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
@ -56,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
RedirectStandardInput = true,
FileName = _mediaEncoder.EncoderPath,
Arguments = GetCommandLineArgs(mediaSource, targetFile),
Arguments = GetCommandLineArgs(mediaSource, targetFile, duration),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
@ -100,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
private string GetCommandLineArgs(MediaSourceInfo mediaSource, string targetFile)
private string GetCommandLineArgs(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration)
{
string videoArgs;
if (EncodeVideo(mediaSource))
@ -116,14 +116,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
videoArgs = "-codec:v:0 copy";
}
var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\" -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\" -t {4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
if (mediaSource.ReadAtNativeFramerate)
{
commandLineArgs = "-re " + commandLineArgs;
}
commandLineArgs = string.Format(commandLineArgs, mediaSource.Path, targetFile, videoArgs, GetAudioArgs(mediaSource));
commandLineArgs = string.Format(commandLineArgs, mediaSource.Path, targetFile, videoArgs, GetAudioArgs(mediaSource), _mediaEncoder.GetTimeParameter(duration.Ticks));
return commandLineArgs;
}

View file

@ -7,6 +7,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public interface IRecorder
{
Task Record(MediaSourceInfo mediaSource, string targetFile, Action onStarted, CancellationToken cancellationToken);
/// <summary>
/// Records the specified media source.
/// </summary>
/// <param name="mediaSource">The media source.</param>
/// <param name="targetFile">The target file.</param>
/// <param name="duration">The duration.</param>
/// <param name="onStarted">The on started.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken);
}
}

View file

@ -56,13 +56,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
name += " " + info.OriginalAirDate.Value.ToString("yyyy-MM-dd");
}
if (addHyphen)
{
name += " -";
}
if (!string.IsNullOrWhiteSpace(info.EpisodeTitle))
{
if (addHyphen)
{
name += " -";
}
name += " " + info.EpisodeTitle;
}
}