update socket interfaces

This commit is contained in:
Luke Pulverenti
2017-03-02 15:50:09 -05:00
parent 9f7ee6d34c
commit 9776ca09db
209 changed files with 565 additions and 12071 deletions

View File

@@ -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" />

View File

@@ -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; }
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}