add migrations for new release

This commit is contained in:
Luke Pulverenti
2015-10-16 14:11:11 -04:00
parent f5f5285306
commit a0b1ddf0a7
9 changed files with 171 additions and 43 deletions

View File

@@ -487,6 +487,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
_logger.Info("Streaming Channel " + channelId);
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
{
var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
result.Item2.Release();
return result.Item1;
}
catch (Exception e)
{
_logger.ErrorException("Error getting channel stream", e);
}
}
throw new ApplicationException("Tuner not found.");
}
private async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
@@ -653,40 +676,56 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
var mediaStreamInfo = await GetChannelStream(timer.ChannelId, null, CancellationToken.None);
var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None);
var mediaStreamInfo = result.Item1;
var isResourceOpen = true;
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
var duration = recordingEndDate - DateTime.UtcNow;
HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
// Unfortunately due to the semaphore we have to have a nested try/finally
try
{
Url = mediaStreamInfo.Path
};
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
recording.Path = recordPath;
recording.Status = RecordingStatus.InProgress;
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.Update(recording);
var duration = recordingEndDate - DateTime.UtcNow;
_logger.Info("Beginning recording.");
httpRequestOptions.BufferContent = false;
var durationToken = new CancellationTokenSource(duration);
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
httpRequestOptions.CancellationToken = linkedToken;
_logger.Info("Writing file to path: " + recordPath);
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
{
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
{
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
Url = mediaStreamInfo.Path
};
recording.Path = recordPath;
recording.Status = RecordingStatus.InProgress;
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.Update(recording);
_logger.Info("Beginning recording.");
httpRequestOptions.BufferContent = false;
var durationToken = new CancellationTokenSource(duration);
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
httpRequestOptions.CancellationToken = linkedToken;
_logger.Info("Writing file to path: " + recordPath);
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
{
using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
result.Item2.Release();
isResourceOpen = false;
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
}
}
recording.Status = RecordingStatus.Completed;
_logger.Info("Recording completed");
}
finally
{
if (isResourceOpen)
{
result.Item2.Release();
}
}
recording.Status = RecordingStatus.Completed;
_logger.Info("Recording completed");
}
catch (OperationCanceledException)
{

View File

@@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv
{
class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
public class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
{
private readonly ILiveTvManager _liveTvManager;
private readonly IConfigurationManager _config;

View File

@@ -141,7 +141,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
protected abstract Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
public async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{
if (IsValidChannelId(channelId))
{
@@ -173,9 +173,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
try
{
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
await AddMediaInfo(stream, false, cancellationToken).ConfigureAwait(false);
return stream;
var resourcePool = GetLock(host.Url);
await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
}
catch (Exception ex)
{
@@ -187,7 +188,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException();
}
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
/// <summary>
/// The _semaphoreLocks
/// </summary>
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets the lock.
/// </summary>
/// <param name="url">The filename.</param>
/// <returns>System.Object.</returns>
private SemaphoreSlim GetLock(string url)
{
return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
}
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
// Leave the resource locked. it will be released upstream
}
catch (Exception)
{
// Release the resource if there's some kind of failure.
resourcePool.Release();
throw;
}
}
private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
{
var originalRuntime = mediaSource.RunTimeTicks;

View File

@@ -1,5 +1,4 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -17,7 +16,7 @@ using MediaBrowser.Controller.Entities.Audio;
namespace MediaBrowser.Server.Implementations.Persistence
{
class CleanDatabaseScheduledTask : IScheduledTask
public class CleanDatabaseScheduledTask : IScheduledTask
{
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;