Merge pull request #2548 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-03-26 20:28:04 -04:00 committed by GitHub
commit 1d6a27c38d
4 changed files with 163 additions and 65 deletions

View File

@ -49,7 +49,7 @@ namespace Emby.Common.Implementations.Net
private void InitReceiveSocketAsyncEventArgs() private void InitReceiveSocketAsyncEventArgs()
{ {
var receiveBuffer = new byte[8192]; var receiveBuffer = new byte[81920];
_receiveSocketAsyncEventArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); _receiveSocketAsyncEventArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
_receiveSocketAsyncEventArgs.Completed += _receiveSocketAsyncEventArgs_Completed; _receiveSocketAsyncEventArgs.Completed += _receiveSocketAsyncEventArgs_Completed;
@ -119,20 +119,29 @@ namespace Emby.Common.Implementations.Net
public Task<SocketReceiveResult> ReceiveAsync(CancellationToken cancellationToken) public Task<SocketReceiveResult> ReceiveAsync(CancellationToken cancellationToken)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
var tcs = new TaskCompletionSource<SocketReceiveResult>(); var tcs = new TaskCompletionSource<SocketReceiveResult>();
EndPoint receivedFromEndPoint = new IPEndPoint(IPAddress.Any, 0); EndPoint receivedFromEndPoint = new IPEndPoint(IPAddress.Any, 0);
var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
state.TaskCompletionSource = tcs;
cancellationToken.Register(() => tcs.TrySetCanceled()); cancellationToken.Register(() => tcs.TrySetCanceled());
_receiveSocketAsyncEventArgs.RemoteEndPoint = receivedFromEndPoint; _receiveSocketAsyncEventArgs.RemoteEndPoint = receivedFromEndPoint;
_currentReceiveTaskCompletionSource = tcs; _currentReceiveTaskCompletionSource = tcs;
var willRaiseEvent = _Socket.ReceiveFromAsync(_receiveSocketAsyncEventArgs); try
if (!willRaiseEvent)
{ {
_receiveSocketAsyncEventArgs_Completed(this, _receiveSocketAsyncEventArgs); var willRaiseEvent = _Socket.ReceiveFromAsync(_receiveSocketAsyncEventArgs);
if (!willRaiseEvent)
{
_receiveSocketAsyncEventArgs_Completed(this, _receiveSocketAsyncEventArgs);
}
}
catch (Exception ex)
{
tcs.TrySetException(ex);
} }
return tcs.Task; return tcs.Task;
@ -145,31 +154,82 @@ namespace Emby.Common.Implementations.Net
if (buffer == null) throw new ArgumentNullException("messageData"); if (buffer == null) throw new ArgumentNullException("messageData");
if (endPoint == null) throw new ArgumentNullException("endPoint"); if (endPoint == null) throw new ArgumentNullException("endPoint");
cancellationToken.ThrowIfCancellationRequested(); var ipEndPoint = NetworkManager.ToIPEndPoint(endPoint);
var tcs = new TaskCompletionSource<int>(); #if NETSTANDARD1_6
cancellationToken.Register(() => tcs.TrySetCanceled()); if (size != buffer.Length)
_sendSocketAsyncEventArgs.SetBuffer(buffer, 0, size);
_sendSocketAsyncEventArgs.RemoteEndPoint = NetworkManager.ToIPEndPoint(endPoint);
_currentSendTaskCompletionSource = tcs;
var willRaiseEvent = _Socket.SendAsync(_sendSocketAsyncEventArgs);
if (!willRaiseEvent)
{ {
_sendSocketAsyncEventArgs_Completed(this, _sendSocketAsyncEventArgs); byte[] copy = new byte[size];
Buffer.BlockCopy(buffer, 0, copy, 0, size);
buffer = copy;
} }
return tcs.Task; cancellationToken.ThrowIfCancellationRequested();
_Socket.SendTo(buffer, ipEndPoint);
return Task.FromResult(true);
#else
var taskSource = new TaskCompletionSource<bool>();
try
{
_Socket.BeginSendTo(buffer, 0, size, SocketFlags.None, ipEndPoint, result =>
{
if (cancellationToken.IsCancellationRequested)
{
taskSource.TrySetCanceled();
return;
}
try
{
_Socket.EndSend(result);
taskSource.TrySetResult(true);
}
catch (Exception ex)
{
taskSource.TrySetException(ex);
}
}, null);
}
catch (Exception ex)
{
taskSource.TrySetException(ex);
}
return taskSource.Task;
#endif
//ThrowIfDisposed();
//if (buffer == null) throw new ArgumentNullException("messageData");
//if (endPoint == null) throw new ArgumentNullException("endPoint");
//cancellationToken.ThrowIfCancellationRequested();
//var tcs = new TaskCompletionSource<int>();
//cancellationToken.Register(() => tcs.TrySetCanceled());
//_sendSocketAsyncEventArgs.SetBuffer(buffer, 0, size);
//_sendSocketAsyncEventArgs.RemoteEndPoint = NetworkManager.ToIPEndPoint(endPoint);
//_currentSendTaskCompletionSource = tcs;
//var willRaiseEvent = _Socket.SendAsync(_sendSocketAsyncEventArgs);
//if (!willRaiseEvent)
//{
// _sendSocketAsyncEventArgs_Completed(this, _sendSocketAsyncEventArgs);
//}
//return tcs.Task;
} }
public async Task SendWithLockAsync(byte[] buffer, int size, IpEndPointInfo endPoint, CancellationToken cancellationToken) public async Task SendWithLockAsync(byte[] buffer, int size, IpEndPointInfo endPoint, CancellationToken cancellationToken)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
await _sendLock.WaitAsync(cancellationToken).ConfigureAwait(false); //await _sendLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try try
{ {
@ -177,7 +237,7 @@ namespace Emby.Common.Implementations.Net
} }
finally finally
{ {
_sendLock.Release(); //_sendLock.Release();
} }
} }
@ -213,5 +273,52 @@ namespace Emby.Common.Implementations.Net
return NetworkManager.ToIpEndPointInfo(endpoint); return NetworkManager.ToIpEndPointInfo(endpoint);
} }
private void ProcessResponse(IAsyncResult asyncResult)
{
#if NET46
var state = asyncResult.AsyncState as AsyncReceiveState;
try
{
var bytesRead = state.Socket.EndReceiveFrom(asyncResult, ref state.RemoteEndPoint);
var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
state.TaskCompletionSource.SetResult(
new SocketReceiveResult
{
Buffer = state.Buffer,
ReceivedBytes = bytesRead,
RemoteEndPoint = ToIpEndPointInfo(ipEndPoint),
LocalIPAddress = LocalIPAddress
}
);
}
catch (ObjectDisposedException)
{
state.TaskCompletionSource.SetCanceled();
}
catch (Exception ex)
{
state.TaskCompletionSource.SetException(ex);
}
#endif
}
private class AsyncReceiveState
{
public AsyncReceiveState(Socket socket, EndPoint remoteEndPoint)
{
this.Socket = socket;
this.RemoteEndPoint = remoteEndPoint;
}
public EndPoint RemoteEndPoint;
public byte[] Buffer = new byte[8192];
public Socket Socket { get; private set; }
public TaskCompletionSource<SocketReceiveResult> TaskCompletionSource { get; set; }
}
} }
} }

View File

@ -677,20 +677,7 @@ namespace Emby.Server.Implementations.FileOrganization
var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options); var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options);
// MAX_PATH - trailing <NULL> charachter - drive component: 260 - 1 - 3 = 256 var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options);
// Usually newPath would include the drive component, but use 256 to be sure
var maxFilenameLength = 256 - newPath.Length;
if (!newPath.EndsWith(@"\"))
{
// Remove 1 for missing backslash combining path and filename
maxFilenameLength--;
}
// Remove additional 4 chars to prevent PathTooLongException for downloaded subtitles (eg. filename.ext.eng.srt)
maxFilenameLength -= 4;
var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options, maxFilenameLength);
if (string.IsNullOrEmpty(episodeFileName)) if (string.IsNullOrEmpty(episodeFileName))
{ {
@ -742,7 +729,7 @@ namespace Emby.Server.Implementations.FileOrganization
return Path.Combine(path, _fileSystem.GetValidFilename(seasonFolderName)); return Path.Combine(path, _fileSystem.GetValidFilename(seasonFolderName));
} }
private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options, int? maxLength) private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options)
{ {
seriesName = _fileSystem.GetValidFilename(seriesName).Trim(); seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
@ -786,32 +773,15 @@ namespace Emby.Server.Implementations.FileOrganization
.Replace("%0e", episodeNumber.ToString("00", _usCulture)) .Replace("%0e", episodeNumber.ToString("00", _usCulture))
.Replace("%00e", episodeNumber.ToString("000", _usCulture)); .Replace("%00e", episodeNumber.ToString("000", _usCulture));
if (maxLength.HasValue && result.Contains("%#")) if (result.Contains("%#"))
{ {
// Substract 3 for the temp token length (%#1, %#2 or %#3) result = result.Replace("%#1", episodeTitle)
int maxRemainingTitleLength = maxLength.Value - result.Length + 3; .Replace("%#2", episodeTitle.Replace(" ", "."))
string shortenedEpisodeTitle = string.Empty; .Replace("%#3", episodeTitle.Replace(" ", "_"));
if (maxRemainingTitleLength > 5)
{
// A title with fewer than 5 letters wouldn't be of much value
shortenedEpisodeTitle = episodeTitle.Substring(0, Math.Min(maxRemainingTitleLength, episodeTitle.Length));
}
result = result.Replace("%#1", shortenedEpisodeTitle)
.Replace("%#2", shortenedEpisodeTitle.Replace(" ", "."))
.Replace("%#3", shortenedEpisodeTitle.Replace(" ", "_"));
} }
if (maxLength.HasValue && result.Length > maxLength.Value) // Finally, call GetValidFilename again in case user customized the episode expression with any invalid filename characters
{ return _fileSystem.GetValidFilename(result).Trim();
// There may be cases where reducing the title length may still not be sufficient to
// stay below maxLength
var msg = string.Format("Unable to generate an episode file name shorter than {0} characters to constrain to the max path limit", maxLength);
throw new Exception(msg);
}
return result;
} }
private bool IsSameEpisode(string sourcePath, string newPath) private bool IsSameEpisode(string sourcePath, string newPath)

View File

@ -20,6 +20,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
@ -30,8 +31,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
private readonly ISocketFactory _socketFactory; private readonly ISocketFactory _socketFactory;
private readonly INetworkManager _networkManager; private readonly INetworkManager _networkManager;
private readonly IEnvironmentInfo _environment;
public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager) public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment)
: base(config, logger, jsonSerializer, mediaEncoder) : base(config, logger, jsonSerializer, mediaEncoder)
{ {
_httpClient = httpClient; _httpClient = httpClient;
@ -39,6 +41,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_appHost = appHost; _appHost = appHost;
_socketFactory = socketFactory; _socketFactory = socketFactory;
_networkManager = networkManager; _networkManager = networkManager;
_environment = environment;
} }
public string Name public string Name
@ -503,11 +506,29 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager); return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
} }
else
// The UDP method is not working reliably on OSX, and on BSD it hasn't been tested yet
var enableHttpStream = _environment.OperatingSystem == OperatingSystem.OSX ||
_environment.OperatingSystem == OperatingSystem.BSD;
if (enableHttpStream)
{ {
//return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost); mediaSource.Protocol = MediaProtocol.Http;
return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
var httpUrl = GetApiUrl(info, true) + "/auto/v" + hdhrId;
// If raw was used, the tuner doesn't support params
if (!string.IsNullOrWhiteSpace(profile)
&& !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
{
httpUrl += "?transcode=" + profile;
}
mediaSource.Path = httpUrl;
return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
} }
return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
} }
public async Task Validate(TunerHostInfo info) public async Task Validate(TunerHostInfo info)

View File

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.8.14")] [assembly: AssemblyVersion("3.2.8.15")]