update closing of streams

This commit is contained in:
Luke Pulverenti
2016-09-29 08:55:49 -04:00
parent f5d37ed659
commit 76c7bfcb67
36 changed files with 481 additions and 332 deletions

View File

@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Channels
throw new NotImplementedException();
}
public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
public Task CloseMediaSource(string liveStreamId)
{
throw new NotImplementedException();
}

View File

@@ -355,7 +355,7 @@ namespace MediaBrowser.Server.Implementations.Library
.ToList();
}
private readonly ConcurrentDictionary<string, LiveStreamInfo> _openStreams = new ConcurrentDictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, LiveStreamInfo> _openStreams = new Dictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
@@ -383,7 +383,7 @@ namespace MediaBrowser.Server.Implementations.Library
Id = mediaSource.LiveStreamId,
MediaSource = mediaSource
};
_openStreams.AddOrUpdate(mediaSource.LiveStreamId, info, (key, i) => info);
_openStreams[mediaSource.LiveStreamId] = info;
if (enableAutoClose)
{
@@ -421,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("id");
}
_logger.Debug("Getting live stream {0}", id);
_logger.Debug("Getting already opened live stream {0}", id);
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
@@ -465,17 +465,16 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId, CancellationToken cancellationToken)
private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId)
{
_logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name);
try
{
await provider.CloseMediaSource(streamId, cancellationToken).ConfigureAwait(false);
await provider.CloseMediaSource(streamId).ConfigureAwait(false);
}
catch (NotImplementedException)
{
}
catch (Exception ex)
{
@@ -483,37 +482,35 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
public async Task CloseLiveStream(string id)
{
if (string.IsNullOrWhiteSpace(id))
{
throw new ArgumentNullException("id");
}
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
try
{
LiveStreamInfo current;
if (_openStreams.TryGetValue(id, out current))
{
_openStreams.Remove(id);
current.Closed = true;
if (current.MediaSource.RequiresClosing)
{
var tuple = GetProvider(id);
await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false);
await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false);
}
}
LiveStreamInfo removed;
if (_openStreams.TryRemove(id, out removed))
{
removed.Closed = true;
}
if (_openStreams.Count == 0)
{
StopCloseTimer();
if (_openStreams.Count == 0)
{
StopCloseTimer();
}
}
}
finally
@@ -565,10 +562,20 @@ namespace MediaBrowser.Server.Implementations.Library
private async void CloseTimerCallback(object state)
{
var infos = _openStreams
.Values
.Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
.ToList();
List<LiveStreamInfo> infos;
await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
try
{
infos = _openStreams
.Values
.Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
.ToList();
}
finally
{
_liveStreamSemaphore.Release();
}
foreach (var info in infos)
{
@@ -576,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
try
{
await CloseLiveStream(info.Id, CancellationToken.None).ConfigureAwait(false);
await CloseLiveStream(info.Id).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -608,12 +615,10 @@ namespace MediaBrowser.Server.Implementations.Library
{
foreach (var key in _openStreams.Keys.ToList())
{
var task = CloseLiveStream(key, CancellationToken.None);
var task = CloseLiveStream(key);
Task.WaitAll(task);
}
_openStreams.Clear();
}
}
}

View File

@@ -47,19 +47,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Copying recording stream to file {0}", targetFile);
if (mediaSource.RunTimeTicks.HasValue)
{
// The media source already has a fixed duration
// But add another stop 1 minute later just in case the recording gets stuck for any reason
var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
}
else
{
// The media source if infinite so we need to handle stopping ourselves
var durationToken = new CancellationTokenSource(duration);
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
}
// The media source if infinite so we need to handle stopping ourselves
var durationToken = new CancellationTokenSource(duration);
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
await CopyUntilCancelled(response.Content, output, cancellationToken).ConfigureAwait(false);
}

View File

@@ -340,22 +340,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_timerProvider.Delete(timer);
}
private List<ChannelInfo> _channelCache = null;
private async Task<IEnumerable<ChannelInfo>> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken)
{
if (enableCache && _channelCache != null)
{
return _channelCache.ToList();
}
var list = new List<ChannelInfo>();
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
{
var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false);
var channels = await hostInstance.GetChannels(enableCache, cancellationToken).ConfigureAwait(false);
list.AddRange(channels);
}
@@ -388,7 +381,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
_channelCache = list.ToList();
return list;
}
@@ -400,7 +392,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
try
{
var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false);
var channels = await hostInstance.GetChannels(false, cancellationToken).ConfigureAwait(false);
list.AddRange(channels);
}
@@ -632,6 +624,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
existingTimer.Genres = updatedTimer.Genres;
existingTimer.HomePageUrl = updatedTimer.HomePageUrl;
existingTimer.IsKids = updatedTimer.IsKids;
existingTimer.IsNews = updatedTimer.IsNews;
existingTimer.IsMovie = updatedTimer.IsMovie;
existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries;
existingTimer.IsSports = updatedTimer.IsSports;
@@ -836,32 +829,67 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var result = await GetChannelStreamInternal(channelId, streamId, cancellationToken).ConfigureAwait(false);
return result.Item1.PublicMediaSource;
return result.Item2;
}
private async Task<Tuple<LiveStream, ITunerHost>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId)
{
var json = _jsonSerializer.SerializeToString(mediaSource);
mediaSource = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
mediaSource.Id = consumerId.ToString(CultureInfo.InvariantCulture) + "_" + mediaSource.Id;
return mediaSource;
}
private async Task<Tuple<LiveStream, MediaSourceInfo, ITunerHost>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
foreach (var hostInstance in _liveTvManager.TunerHosts)
await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
var result = _liveStreams.Values.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase));
if (result != null)
{
try
{
var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
//result.ConsumerCount++;
await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false);
_liveStreams[result.Id] = result;
_liveStreamsSemaphore.Release();
//_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
return new Tuple<LiveStream, ITunerHost>(result, hostInstance);
}
catch (FileNotFoundException)
//_liveStreamsSemaphore.Release();
//return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1), result.TunerHost);
}
try
{
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
{
result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
_liveStreams[result.OpenedMediaSource.Id] = result;
result.ConsumerCount++;
result.TunerHost = hostInstance;
result.OriginalStreamId = streamId;
_logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}",
streamId, result.OpenedMediaSource.Id, result.OpenedMediaSource.LiveStreamId);
return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, CloneMediaSource(result.OpenedMediaSource, 0), hostInstance);
}
catch (FileNotFoundException)
{
}
catch (OperationCanceledException)
{
}
}
catch (Exception e)
{
_logger.ErrorException("Error getting channel stream", e);
}
}
finally
{
_liveStreamsSemaphore.Release();
}
throw new ApplicationException("Tuner not found.");
@@ -896,25 +924,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
{
await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false);
// Ignore the consumer id
id = id.Substring(id.IndexOf('_') + 1);
await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
LiveStream stream;
if (_liveStreams.TryGetValue(id, out stream))
{
_liveStreams.Remove(id);
stream.ConsumerCount--;
try
_logger.Info("Live stream {0} consumer count is now {1}", id, stream.ConsumerCount);
if (stream.ConsumerCount <= 0)
{
_liveStreams.Remove(id);
_logger.Info("Closing live stream {0}", id);
await stream.Close().ConfigureAwait(false);
_logger.Info("Live stream {0} closed successfully", id);
}
catch (Exception ex)
{
_logger.ErrorException("Error closing live stream", ex);
}
}
else
{
_logger.Warn("Live stream not found: {0}, unable to close", id);
}
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
_logger.ErrorException("Error closing live stream", ex);
}
finally
{
@@ -1095,20 +1139,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordPath = GetRecordingPath(timer, out seriesPath);
var recordingStatus = RecordingStatus.New;
LiveStream liveStream = null;
string liveStreamId = null;
try
{
var allMediaSources =
await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
var liveStreamInfo =
await
GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
.ConfigureAwait(false);
liveStream = liveStreamInfo.Item1;
var mediaStreamInfo = liveStreamInfo.Item1.PublicMediaSource;
var tunerHost = liveStreamInfo.Item2;
var mediaStreamInfo = liveStreamInfo.Item2;
liveStreamId = mediaStreamInfo.Id;
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
//await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
@@ -1140,15 +1182,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
EnforceKeepUpTo(timer);
};
var pathWithDuration = tunerHost.ApplyDuration(mediaStreamInfo.Path, duration);
// If it supports supplying duration via url
if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase))
{
mediaStreamInfo.Path = pathWithDuration;
mediaStreamInfo.RunTimeTicks = duration.Ticks;
}
await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken)
.ConfigureAwait(false);
@@ -1166,11 +1199,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordingStatus = RecordingStatus.Error;
}
if (liveStream != null)
if (!string.IsNullOrWhiteSpace(liveStreamId))
{
try
{
await CloseLiveStream(liveStream.Id, CancellationToken.None).ConfigureAwait(false);
await CloseLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -1251,7 +1284,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1,1);
private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1, 1);
private async Task DeleteLibraryItemsForTimers(List<TimerInfo> timers)
{
foreach (var timer in timers)
@@ -1295,7 +1328,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
catch (FileNotFoundException)
{
}
}
@@ -1492,6 +1525,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
AddGenre(timer.Genres, "Kids");
}
if (timer.IsNews)
{
AddGenre(timer.Genres, "News");
}
foreach (var genre in timer.Genres)
{

View File

@@ -71,38 +71,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var durationToken = new CancellationTokenSource(duration);
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
await RecordFromFile(mediaSource, mediaSource.Path, targetFile, false, duration, onStarted, cancellationToken).ConfigureAwait(false);
await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false);
_logger.Info("Recording completed to file {0}", targetFile);
}
private async void DeleteTempFile(string path)
{
for (var i = 0; i < 10; i++)
{
try
{
File.Delete(path);
return;
}
catch (FileNotFoundException)
{
return;
}
catch (DirectoryNotFoundException)
{
return;
}
catch (Exception ex)
{
_logger.ErrorException("Error deleting recording temp file", ex);
}
await Task.Delay(1000).ConfigureAwait(false);
}
}
private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, bool deleteInputFileAfterCompletion, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
_targetPath = targetFile;
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
@@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
_logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length);
process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile, deleteInputFileAfterCompletion);
process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile);
process.Start();
@@ -252,7 +226,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
/// <summary>
/// Processes the exited.
/// </summary>
private void OnFfMpegProcessExited(Process process, string inputFile, bool deleteInputFileAfterCompletion)
private void OnFfMpegProcessExited(Process process, string inputFile)
{
_hasExited = true;
@@ -278,11 +252,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Error("FFMpeg recording exited with an error for {0}.", _targetPath);
_taskCompletionSource.TrySetException(new Exception(string.Format("Recording for {0} failed", _targetPath)));
}
if (deleteInputFileAfterCompletion)
{
DeleteTempFile(inputFile);
}
}
private void DisposeLogStream()

View File

@@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
timerInfo.EpisodeNumber = programInfo.EpisodeNumber;
timerInfo.IsMovie = programInfo.IsMovie;
timerInfo.IsKids = programInfo.IsKids;
timerInfo.IsNews = programInfo.IsNews;
timerInfo.IsSports = programInfo.IsSports;
timerInfo.ProductionYear = programInfo.ProductionYear;
timerInfo.EpisodeTitle = programInfo.EpisodeTitle;

View File

@@ -62,9 +62,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly List<ILiveTvService> _services = new List<ILiveTvService>();
private readonly ConcurrentDictionary<string, LiveStreamData> _openStreams =
new ConcurrentDictionary<string, LiveStreamData>();
private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1);
private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>();
@@ -153,6 +150,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var channels = _libraryManager.GetItemList(new InternalItemsQuery
{
IsMovie = query.IsMovie,
IsNews = query.IsNews,
IsKids = query.IsKids,
IsSports = query.IsSports,
IsSeries = query.IsSeries,
IncludeItemTypes = new[] { typeof(LiveTvChannel).Name },
SortBy = new[] { ItemSortBy.SortName },
TopParentIds = new[] { topFolder.Id.ToString("N") }
@@ -407,15 +409,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
Normalize(info, service, isVideo);
var data = new LiveStreamData
{
Info = info,
IsChannel = isChannel,
ItemId = id
};
_openStreams.AddOrUpdate(info.Id, data, (key, i) => data);
return info;
}
catch (Exception ex)
@@ -937,8 +930,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
MaxStartDate = query.MaxStartDate,
ChannelIds = query.ChannelIds,
IsMovie = query.IsMovie,
IsSeries = query.IsSeries,
IsSports = query.IsSports,
IsKids = query.IsKids,
IsNews = query.IsNews,
Genres = query.Genres,
StartIndex = query.StartIndex,
Limit = query.Limit,
@@ -985,7 +980,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
IsAiring = query.IsAiring,
IsNews = query.IsNews,
IsMovie = query.IsMovie,
IsSeries = query.IsSeries,
IsSports = query.IsSports,
IsKids = query.IsKids,
EnableTotalRecordCount = query.EnableTotalRecordCount,
@@ -1014,7 +1011,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var programList = programs.ToList();
var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false);
var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false) || (query.IsNews ?? false) || (query.IsSeries ?? false);
programs = programList.OrderBy(i => i.StartDate.Date)
.ThenByDescending(i => GetRecommendationScore(i, user.Id, factorChannelWatchCount))
@@ -1305,6 +1302,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var start = DateTime.UtcNow.AddHours(-1);
var end = start.AddDays(guideDays);
var isMovie = false;
var isSports = false;
var isNews = false;
var isKids = false;
var iSSeries = false;
var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false);
foreach (var program in channelPrograms)
@@ -1312,7 +1315,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var programItem = await GetProgram(program, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false);
programs.Add(programItem.Id);
if (program.IsMovie)
{
isMovie = true;
}
if (program.IsSeries)
{
iSSeries = true;
}
if (program.IsSports)
{
isSports = true;
}
if (program.IsNews)
{
isNews = true;
}
if (program.IsKids)
{
isKids = true;
}
}
currentChannel.IsMovie = isMovie;
currentChannel.IsNews = isNews;
currentChannel.IsSports = isSports;
currentChannel.IsKids = isKids;
currentChannel.IsSeries = iSSeries;
await currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -1647,6 +1683,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
recordings = recordings.Where(i => i.IsMovie == val);
}
if (query.IsNews.HasValue)
{
var val = query.IsNews.Value;
recordings = recordings.Where(i => i.IsNews == val);
}
if (query.IsSeries.HasValue)
{
var val = query.IsSeries.Value;
@@ -2444,9 +2486,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
internal bool IsChannel;
}
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
public async Task CloseLiveStream(string id)
{
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
try
{
@@ -2461,12 +2503,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
id = parts[1];
LiveStreamData data;
_openStreams.TryRemove(id, out data);
_logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id);
await service.CloseLiveStream(id, cancellationToken).ConfigureAwait(false);
await service.CloseLiveStream(id, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -2500,7 +2539,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
Dispose(true);
}
private readonly object _disposeLock = new object();
private bool _isDisposed = false;
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
@@ -2511,18 +2549,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (dispose)
{
_isDisposed = true;
lock (_disposeLock)
{
foreach (var stream in _openStreams.Values.ToList())
{
var task = CloseLiveStream(stream.Info.Id, CancellationToken.None);
Task.WaitAll(task);
}
_openStreams.Clear();
}
}
}

View File

@@ -204,9 +204,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
public Task CloseMediaSource(string liveStreamId)
{
return _liveTvManager.CloseLiveStream(liveStreamId, cancellationToken);
return _liveTvManager.CloseLiveStream(liveStreamId);
}
}
}

View File

@@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
.ToList();
}
public async Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken)
public async Task<IEnumerable<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken)
{
var list = new List<ChannelInfo>();
@@ -83,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
try
{
var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false);
var channels = await GetChannels(host, enableCache, cancellationToken).ConfigureAwait(false);
var newChannels = channels.Where(i => !list.Any(l => string.Equals(i.Id, l.Id, StringComparison.OrdinalIgnoreCase))).ToList();
list.AddRange(newChannels);

View File

@@ -67,14 +67,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return id;
}
public string ApplyDuration(string streamPath, TimeSpan duration)
{
streamPath += streamPath.IndexOf('?') == -1 ? "?" : "&";
streamPath += "duration=" + Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture);
return streamPath;
}
private async Task<IEnumerable<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
{
var options = new HttpRequestOptions

View File

@@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_appHost = appHost;
}
public override async Task Open(CancellationToken openCancellationToken)
protected override async Task OpenInternal(CancellationToken openCancellationToken)
{
_liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
@@ -54,13 +54,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await taskCompletionSource.Task.ConfigureAwait(false);
PublicMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts";
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts";
PublicMediaSource.Protocol = MediaProtocol.Http;
OpenedMediaSource.Protocol = MediaProtocol.Http;
}
public override Task Close()
{
_logger.Info("Closing HDHR live stream");
_liveStreamCancellationTokenSource.Cancel();
return _liveStreamTaskCompletionSource.Task;

View File

@@ -153,10 +153,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
return Task.FromResult(true);
}
public string ApplyDuration(string streamPath, TimeSpan duration)
{
return streamPath;
}
}
}

View File

@@ -2530,38 +2530,111 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("IsOffline=@IsOffline");
cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline;
}
if (query.IsMovie.HasValue)
{
var alternateTypes = new List<string>();
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
{
alternateTypes.Add(typeof(Movie).FullName);
}
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
{
alternateTypes.Add(typeof(Trailer).FullName);
}
if (alternateTypes.Count == 0)
{
whereClauses.Add("IsMovie=@IsMovie");
}
else
{
whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
}
cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
}
if (query.IsKids.HasValue)
var exclusiveProgramAttribtues = !(query.IsMovie ?? true) ||
!(query.IsSports ?? true) ||
!(query.IsKids ?? true) ||
!(query.IsNews ?? true) ||
!(query.IsSeries ?? true);
if (exclusiveProgramAttribtues)
{
whereClauses.Add("IsKids=@IsKids");
cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids;
if (query.IsMovie.HasValue)
{
var alternateTypes = new List<string>();
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
{
alternateTypes.Add(typeof(Movie).FullName);
}
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
{
alternateTypes.Add(typeof(Trailer).FullName);
}
if (alternateTypes.Count == 0)
{
whereClauses.Add("IsMovie=@IsMovie");
cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
}
else
{
whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
}
}
if (query.IsSeries.HasValue)
{
whereClauses.Add("IsSeries=@IsSeries");
cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = query.IsSeries;
}
if (query.IsNews.HasValue)
{
whereClauses.Add("IsNews=@IsNews");
cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = query.IsNews;
}
if (query.IsKids.HasValue)
{
whereClauses.Add("IsKids=@IsKids");
cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids;
}
if (query.IsSports.HasValue)
{
whereClauses.Add("IsSports=@IsSports");
cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports;
}
}
if (query.IsSports.HasValue)
else
{
whereClauses.Add("IsSports=@IsSports");
cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports;
var programAttribtues = new List<string>();
if (query.IsMovie ?? false)
{
var alternateTypes = new List<string>();
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
{
alternateTypes.Add(typeof(Movie).FullName);
}
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
{
alternateTypes.Add(typeof(Trailer).FullName);
}
if (alternateTypes.Count == 0)
{
programAttribtues.Add("IsMovie=@IsMovie");
}
else
{
programAttribtues.Add("(IsMovie is null OR IsMovie=@IsMovie)");
}
cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = true;
}
if (query.IsSports ?? false)
{
programAttribtues.Add("IsSports=@IsSports");
cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = true;
}
if (query.IsNews ?? false)
{
programAttribtues.Add("IsNews=@IsNews");
cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = true;
}
if (query.IsSeries ?? false)
{
programAttribtues.Add("IsSeries=@IsSeries");
cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = true;
}
if (query.IsKids ?? false)
{
programAttribtues.Add("IsKids=@IsKids");
cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = true;
}
if (programAttribtues.Count > 0)
{
whereClauses.Add("("+string.Join(" OR ", programAttribtues.ToArray())+")");
}
}
if (query.IsFolder.HasValue)
{
whereClauses.Add("IsFolder=@IsFolder");

View File

@@ -818,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
try
{
await _mediaSourceManager.CloseLiveStream(info.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
await _mediaSourceManager.CloseLiveStream(info.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{

View File

@@ -150,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
public Task CloseMediaSource(string liveStreamId)
{
throw new NotImplementedException();
}