diff options
Diffstat (limited to 'Emby.Server.Implementations')
4 files changed, 437 insertions, 84 deletions
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 50c01110f..86084a114 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -169,6 +169,7 @@ <Compile Include="LiveTv\RecordingImageProvider.cs" /> <Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" /> <Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" /> + <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" /> <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunDiscovery.cs" /> <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" /> <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunLiveStream.cs" /> diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 2e70e1ac1..a847d7430 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -28,13 +28,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; private readonly IServerApplicationHost _appHost; + private readonly ISocketFactory _socketFactory; - public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost) + public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost, ISocketFactory socketFactory) : base(config, logger, jsonSerializer, mediaEncoder) { _httpClient = httpClient; _fileSystem = fileSystem; _appHost = appHost; + _socketFactory = socketFactory; } public string Name @@ -104,14 +106,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>(); - private async Task<string> GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken) + private async Task<DiscoverResponse> GetModelInfo(TunerHostInfo info, bool throwAllExceptions, CancellationToken cancellationToken) { lock (_modelCache) { DiscoverResponse response; if (_modelCache.TryGetValue(info.Url, out response)) { - return response.ModelNumber; + return response; } } @@ -135,67 +137,57 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun _modelCache[info.Id] = response; } - return response.ModelNumber; + return response; } } catch (HttpException ex) { - if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound) + if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound) { var defaultValue = "HDHR"; + var response = new DiscoverResponse + { + ModelNumber = defaultValue + }; // HDHR4 doesn't have this api lock (_modelCache) { - _modelCache[info.Id] = new DiscoverResponse - { - ModelNumber = defaultValue - }; + _modelCache[info.Id] = response; } - return defaultValue; + return response; } throw; } } - public async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + private async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) { - var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false); - using (var stream = await _httpClient.Get(new HttpRequestOptions() - { - Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)), - CancellationToken = cancellationToken, - TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds), - BufferContent = false + var tuners = new List<LiveTvTunerInfo>(); - }).ConfigureAwait(false)) + using (var manager = new HdHomerunManager(_socketFactory)) { - var tuners = new List<LiveTvTunerInfo>(); - using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) + // Legacy HdHomeruns are IPv4 only + var ipInfo = new IpAddressInfo(info.Url, IpAddressFamily.InterNetwork); + + for (int i = 0; i < model.TunerCount; ++i) { - while (!sr.EndOfStream) + var name = String.Format("Tuner {0}", i + 1); + var currentChannel = "none"; /// @todo Get current channel and map back to Station Id + var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false); + LiveTvTunerStatus status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv; + tuners.Add(new LiveTvTunerInfo { - string line = StripXML(sr.ReadLine()); - if (line.Contains("Channel")) - { - LiveTvTunerStatus status; - var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase); - var name = line.Substring(0, index - 1); - var currentChannel = line.Substring(index + 7); - if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; } - tuners.Add(new LiveTvTunerInfo - { - Name = name, - SourceType = string.IsNullOrWhiteSpace(model) ? Name : model, - ProgramName = currentChannel, - Status = status - }); - } - } + Name = name, + SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber, + ProgramName = currentChannel, + Status = status + }); } - return tuners; } + return tuners; } public async Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken) @@ -244,34 +236,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return uri.AbsoluteUri.TrimEnd('/'); } - private static string StripXML(string source) - { - char[] buffer = new char[source.Length]; - int bufferIndex = 0; - bool inside = false; - - for (int i = 0; i < source.Length; i++) - { - char let = source[i]; - if (let == '<') - { - inside = true; - continue; - } - if (let == '>') - { - inside = false; - continue; - } - if (!inside) - { - buffer[bufferIndex] = let; - bufferIndex++; - } - } - return new string(buffer, 0, bufferIndex); - } - private class Channels { public string GuideNumber { get; set; } @@ -455,8 +419,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun try { - var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); - model = model ?? string.Empty; + var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false); + var model = modelInfo == null ? string.Empty : (modelInfo.ModelNumber ?? string.Empty); if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)) { @@ -531,18 +495,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun try { // Test it by pulling down the lineup - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = string.Format("{0}/discover.json", GetApiUrl(info, false)), - CancellationToken = CancellationToken.None, - BufferContent = false - - }).ConfigureAwait(false)) - { - var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream); - - info.DeviceId = response.DeviceID; - } + var modelInfo = await GetModelInfo(info, true, CancellationToken.None).ConfigureAwait(false); + info.DeviceId = modelInfo.DeviceID; } catch (HttpException ex) { @@ -573,6 +527,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun public string DeviceAuth { get; set; } public string BaseURL { get; set; } public string LineupURL { get; set; } + public int TunerCount { get; set; } } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs new file mode 100644 index 000000000..53405e9de --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -0,0 +1,397 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Net; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public class HdHomerunManager : IDisposable + { + public static int HdHomeRunPort = 65001; + // Message constants + private static byte GetSetName = 3; + private static byte GetSetValue = 4; + private static byte GetSetLockkey = 21; + private static ushort GetSetRequest = 4; + private static ushort GetSetReply = 5; + + private uint? _lockkey = null; + private int _activeTuner = 0; + private readonly ISocketFactory _socketFactory; + private IpAddressInfo _remoteIp; + + public HdHomerunManager(ISocketFactory socketFactory) + { + _socketFactory = socketFactory; + } + + public void Dispose() + { + var task = StopStreaming(); + + Task.WaitAll(task); + } + + public async Task<bool> CheckTunerAvailability(IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken) + { + var ipEndPoint = new IpEndPointInfo(remoteIp, HdHomeRunPort); + var tcpClient = _socketFactory.CreateTcpSocket(remoteIp, HdHomeRunPort); + var lockkeyMsg = CreateGetMessage(tuner, "lockkey"); + await tcpClient.SendAsync(lockkeyMsg, lockkeyMsg.Length, ipEndPoint, cancellationToken); + var response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); + string returnVal; + ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal); + + return (returnVal == "none"); + } + + public async Task StartStreaming(IpAddressInfo remoteIp, IpAddressInfo localIp, int localPort, string url, int numTuners, CancellationToken cancellationToken) + { + _remoteIp = remoteIp; + // parse url for channel and program + string frequency, program; + if (!ParseUrl(url, out frequency, out program)) + { + return; + } + + var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort); + + if (!_lockkey.HasValue) + { + var rand = new Random(); + _lockkey = (uint)rand.Next(); + } + + var ipEndPoint = new IpEndPointInfo(_remoteIp, HdHomeRunPort); + + for (int i = 0; i < numTuners; ++i) + { + if (!await CheckTunerAvailability(_remoteIp, i, cancellationToken).ConfigureAwait(false)) + continue; + + _activeTuner = i; + var lockKeyString = String.Format("{0:d}", _lockkey.Value); + var lockkeyMsg = CreateSetMessage(i, "lockkey", lockKeyString, null); + await tcpClient.SendAsync(lockkeyMsg, lockkeyMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false); + var response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); + string returnVal; + // parse response to make sure it worked + if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal)) + continue; + + var channelMsg = CreateSetMessage(i, "channel", frequency, _lockkey.Value); + await tcpClient.SendAsync(channelMsg, channelMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false); + await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); + // parse response to make sure it worked + if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal)) + { + await ReleaseLockkey(tcpClient).ConfigureAwait(false); + continue; + } + + if (program != String.Empty) + { + var programMsg = CreateSetMessage(i, "program", program, _lockkey.Value); + await tcpClient.SendAsync(programMsg, programMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false); + await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); + // parse response to make sure it worked + if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal)) + { + await ReleaseLockkey(tcpClient).ConfigureAwait(false); + continue; + } + } + + var targetValue = String.Format("rtp://{0}:{1}", localIp, localPort); + var targetMsg = CreateSetMessage(i, "target", targetValue, _lockkey.Value); + + await tcpClient.SendAsync(targetMsg, targetMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false); + response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); + // parse response to make sure it worked + if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal)) + { + await ReleaseLockkey(tcpClient).ConfigureAwait(false); + continue; + } + + break; + } + } + + public async Task StopStreaming() + { + if (!_lockkey.HasValue) + return; + + using (var socket = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort)) + { + await ReleaseLockkey(socket).ConfigureAwait(false); + } + } + + private async Task ReleaseLockkey(ISocket tcpClient) + { + var releaseTarget = CreateSetMessage(_activeTuner, "target", "none", _lockkey); + await tcpClient.SendAsync(releaseTarget, releaseTarget.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false); + await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false); + var releaseKeyMsg = CreateSetMessage(_activeTuner, "lockkey", "none", _lockkey); + _lockkey = null; + await tcpClient.SendAsync(releaseKeyMsg, releaseKeyMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false); + await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false); + } + + private static bool ParseUrl(string url, out string frequency, out string program) + { + frequency = String.Empty; + program = String.Empty; + var regExp = new Regex(@"\/ch(\d+)-?(\d*)"); + var match = regExp.Match(url); + if (match.Success) + { + frequency = match.Groups[1].Value; + program = match.Groups[2].Value; + return true; + } + + return false; + } + + private static byte[] CreateGetMessage(int tuner, string name) + { + var byteName = Encoding.UTF8.GetBytes(String.Format("/tuner{0}/{1}\0", tuner, name)); + int messageLength = byteName.Length + 10; // 4 bytes for header + 4 bytes for crc + 2 bytes for tag name and length + + var message = new byte[messageLength]; + + int offset = InsertHeaderAndName(byteName, messageLength, message); + + bool flipEndian = BitConverter.IsLittleEndian; + + // calculate crc and insert at the end of the message + var crcBytes = BitConverter.GetBytes(HdHomerunCrc.GetCrc32(message, messageLength - 4)); + if (flipEndian) + Array.Reverse(crcBytes); + Buffer.BlockCopy(crcBytes, 0, message, offset, 4); + + return message; + } + + private static byte[] CreateSetMessage(int tuner, String name, String value, uint? lockkey) + { + var byteName = Encoding.UTF8.GetBytes(String.Format("/tuner{0}/{1}\0", tuner, name)); + var byteValue = Encoding.UTF8.GetBytes(String.Format("{0}\0", value)); + + int messageLength = byteName.Length + byteValue.Length + 12; + if (lockkey.HasValue) + messageLength += 6; + + var message = new byte[messageLength]; + + int offset = InsertHeaderAndName(byteName, messageLength, message); + + bool flipEndian = BitConverter.IsLittleEndian; + + message[offset] = GetSetValue; + offset++; + message[offset] = Convert.ToByte(byteValue.Length); + offset++; + Buffer.BlockCopy(byteValue, 0, message, offset, byteValue.Length); + offset += byteValue.Length; + if (lockkey.HasValue) + { + message[offset] = GetSetLockkey; + offset++; + message[offset] = (byte)4; + offset++; + var lockKeyBytes = BitConverter.GetBytes(lockkey.Value); + if (flipEndian) + Array.Reverse(lockKeyBytes); + Buffer.BlockCopy(lockKeyBytes, 0, message, offset, 4); + offset += 4; + } + + // calculate crc and insert at the end of the message + var crcBytes = BitConverter.GetBytes(HdHomerunCrc.GetCrc32(message, messageLength - 4)); + if (flipEndian) + Array.Reverse(crcBytes); + Buffer.BlockCopy(crcBytes, 0, message, offset, 4); + + return message; + } + + private static int InsertHeaderAndName(byte[] byteName, int messageLength, byte[] message) + { + // check to see if we need to flip endiannes + bool flipEndian = BitConverter.IsLittleEndian; + int offset = 0; + + // create header bytes + var getSetBytes = BitConverter.GetBytes(GetSetRequest); + var msgLenBytes = BitConverter.GetBytes((ushort)(messageLength - 8)); // Subtrace 4 bytes for header and 4 bytes for crc + + if (flipEndian) + { + Array.Reverse(getSetBytes); + Array.Reverse(msgLenBytes); + } + + // insert header bytes into message + Buffer.BlockCopy(getSetBytes, 0, message, offset, 2); + offset += 2; + Buffer.BlockCopy(msgLenBytes, 0, message, offset, 2); + offset += 2; + + // insert tag name and length + message[offset] = GetSetName; + offset++; + message[offset] = Convert.ToByte(byteName.Length); + offset++; + + // insert name string + Buffer.BlockCopy(byteName, 0, message, offset, byteName.Length); + offset += byteName.Length; + + return offset; + } + + private static bool ParseReturnMessage(byte[] buf, int numBytes, out string returnVal) + { + returnVal = String.Empty; + + if (numBytes < 4) + return false; + + var flipEndian = BitConverter.IsLittleEndian; + int offset = 0; + byte[] msgTypeBytes = new byte[2]; + Buffer.BlockCopy(buf, offset, msgTypeBytes, 0, msgTypeBytes.Length); + + if (flipEndian) + Array.Reverse(msgTypeBytes); + + var msgType = BitConverter.ToUInt16(msgTypeBytes, 0); + offset += 2; + + if (msgType != GetSetReply) + return false; + + byte[] msgLengthBytes = new byte[2]; + Buffer.BlockCopy(buf, offset, msgLengthBytes, 0, msgLengthBytes.Length); + if (flipEndian) + Array.Reverse(msgLengthBytes); + + var msgLength = BitConverter.ToUInt16(msgLengthBytes, 0); + offset += 2; + + if (numBytes < msgLength + 8) + return false; + + var nameTag = buf[offset]; + offset++; + + var nameLength = buf[offset]; + offset++; + + // skip the name field to get to value for return + offset += nameLength; + + var valueTag = buf[offset]; + offset++; + + var valueLength = buf[offset]; + offset++; + + returnVal = Encoding.UTF8.GetString(buf, offset, valueLength - 1); // remove null terminator + return true; + } + + private class HdHomerunCrc + { + private static UInt32[] crc_table = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; + + public static UInt32 GetCrc32(byte[] bytes, int numBytes) + { + var hash = 0xffffffff; + for (var i = 0; i < numBytes; i++) + hash = (hash >> 8) ^ crc_table[(hash ^ bytes[i]) & 0xff]; + + var tmp = ~hash & 0xffffffff; + var b0 = tmp & 0xff; + var b1 = (tmp >> 8) & 0xff; + var b2 = (tmp >> 16) & 0xff; + var b3 = (tmp >> 24) & 0xff; + hash = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; + return hash; + } + } + } +} diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index 691ff0699..bb303d8fa 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -128,7 +128,7 @@ namespace Emby.Server.Implementations.Udp /// <summary> /// The _udp client /// </summary> - private IUdpSocket _udpClient; + private ISocket _udpClient; private readonly ISocketFactory _socketFactory; /// <summary> @@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.Udp { try { - var result = await _udpClient.ReceiveAsync().ConfigureAwait(false); + var result = await _udpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false); OnMessageReceived(result); } |
