@@ -39,6 +39,6 @@ | |||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" /> | ||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" /> | ||||
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" /> | ||||
<PackageReference Include="System.Text.Json" Version="5.0.0" /> | |||||
<PackageReference Include="System.Text.Json" Version="5.0.2" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -8,7 +8,6 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" /> | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" /> | ||||
<PackageReference Include="System.IO.Pipelines" Version="5.0.0" /> | |||||
<PackageReference Include="xunit" Version="2.4.1" /> | <PackageReference Include="xunit" Version="2.4.1" /> | ||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> | <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> | ||||
<PrivateAssets>all</PrivateAssets> | <PrivateAssets>all</PrivateAssets> | ||||
@@ -6,12 +6,11 @@ | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="JT1078.Flv" Version="1.1.0" /> | |||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" /> | ||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0" /> | |||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" /> | |||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" /> | ||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" /> | ||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.5" /> | |||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -0,0 +1,100 @@ | |||||
using JT1078.Gateway.Abstractions; | |||||
using JT1078.Gateway.Sessions; | |||||
using JT1078.Flv; | |||||
using Microsoft.Extensions.Hosting; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
using System.Linq; | |||||
using Microsoft.Extensions.Logging; | |||||
using JT1078.Flv.Extensions; | |||||
using Microsoft.Extensions.Caching.Memory; | |||||
using JT1078.Protocol; | |||||
using System.Text.Json; | |||||
using System.Text.Json.Serialization; | |||||
using JT1078.FMp4; | |||||
namespace JT1078.Gateway.TestNormalHosting.Services | |||||
{ | |||||
public class JT1078FMp4NormalMsgHostedService : BackgroundService | |||||
{ | |||||
private IJT1078MsgConsumer JT1078MsgConsumer; | |||||
private JT1078HttpSessionManager HttpSessionManager; | |||||
private FMp4Encoder FM4Encoder; | |||||
private ILogger Logger; | |||||
private IMemoryCache memoryCache; | |||||
private const string ikey = "IKEY"; | |||||
private MessageDispatchDataService messageDispatchDataService; | |||||
public JT1078FMp4NormalMsgHostedService( | |||||
MessageDispatchDataService messageDispatchDataService, | |||||
IMemoryCache memoryCache, | |||||
ILoggerFactory loggerFactory, | |||||
FMp4Encoder fM4Encoder, | |||||
JT1078HttpSessionManager httpSessionManager, | |||||
IJT1078MsgConsumer msgConsumer) | |||||
{ | |||||
Logger = loggerFactory.CreateLogger<JT1078FMp4NormalMsgHostedService>(); | |||||
JT1078MsgConsumer = msgConsumer; | |||||
HttpSessionManager = httpSessionManager; | |||||
FM4Encoder = fM4Encoder; | |||||
this.memoryCache = memoryCache; | |||||
this.messageDispatchDataService = messageDispatchDataService; | |||||
} | |||||
protected async override Task ExecuteAsync(CancellationToken stoppingToken) | |||||
{ | |||||
while (!stoppingToken.IsCancellationRequested) | |||||
{ | |||||
var data = await messageDispatchDataService.FlvChannel.Reader.ReadAsync(); | |||||
try | |||||
{ | |||||
if (Logger.IsEnabled(LogLevel.Debug)) | |||||
{ | |||||
Logger.LogDebug(JsonSerializer.Serialize(HttpSessionManager.GetAll())); | |||||
Logger.LogDebug($"{data.SIM},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||||
} | |||||
string key = $"{data.GetKey()}_{ikey}"; | |||||
if (data.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧) | |||||
{ | |||||
memoryCache.Set(key, data); | |||||
} | |||||
var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber); | |||||
var firstHttpSessions = httpSessions.Where(w => !w.FirstSend).ToList(); | |||||
if (firstHttpSessions.Count > 0) | |||||
{ | |||||
if (memoryCache.TryGetValue(key, out JT1078Package idata)) | |||||
{ | |||||
try | |||||
{ | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||||
} | |||||
} | |||||
} | |||||
var otherHttpSessions = httpSessions.Where(w => w.FirstSend).ToList(); | |||||
if (otherHttpSessions.Count > 0) | |||||
{ | |||||
try | |||||
{ | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Logger.LogError(ex, $"{data.SIM},{false},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||||
} | |||||
} | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Logger.LogError(ex, $"{data.SIM},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||||
} | |||||
} | |||||
await Task.CompletedTask; | |||||
} | |||||
} | |||||
} |
@@ -149,5 +149,30 @@ namespace JT1078.Gateway.Extensions | |||||
{ | { | ||||
await context.WebSocketContext.WebSocket.SendAsync(Hello, WebSocketMessageType.Text, true, CancellationToken.None); | await context.WebSocketContext.WebSocket.SendAsync(Hello, WebSocketMessageType.Text, true, CancellationToken.None); | ||||
} | } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="context"></param> | |||||
/// <param name="jT1078AVInfo"></param> | |||||
/// <returns></returns> | |||||
public static bool TryGetAVInfo(this HttpListenerContext context,out JT1078AVInfo jT1078AVInfo) | |||||
{ | |||||
if (context.Request.QueryString.Count < 2) | |||||
{ | |||||
jT1078AVInfo = default; | |||||
return false; | |||||
} | |||||
string sim = context.Request.QueryString.Get("sim"); | |||||
string channel = context.Request.QueryString.Get("channel"); | |||||
if (string.IsNullOrEmpty(sim) || string.IsNullOrEmpty(channel)) | |||||
{ | |||||
jT1078AVInfo = default; | |||||
return false; | |||||
} | |||||
int.TryParse(channel, out int channelNo); | |||||
jT1078AVInfo = new JT1078AVInfo(sim, channelNo); | |||||
return true; | |||||
} | |||||
} | } | ||||
} | } |
@@ -40,8 +40,10 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="JT1078.Hls" Version="1.1.0-preview2" /> | <PackageReference Include="JT1078.Hls" Version="1.1.0-preview2" /> | ||||
<PackageReference Include="JT1078.Flv" Version="1.1.0" /> | |||||
<PackageReference Include="JT1078.FMp4" Version="1.0.0-preview1" /> | |||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" /> | <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" /> | ||||
<PackageReference Include="System.IO.Pipelines" Version="5.0.0" /> | |||||
<PackageReference Include="System.IO.Pipelines" Version="5.0.1" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -16,10 +16,13 @@ using System.Text; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using JT1078.Gateway.Extensions; | using JT1078.Gateway.Extensions; | ||||
using Microsoft.Extensions.Caching.Memory; | |||||
using JT1078.Gateway.Services; | |||||
namespace JT1078.Gateway | namespace JT1078.Gateway | ||||
{ | { | ||||
/// <summary> | |||||
/// http服务器 | |||||
/// </summary> | |||||
public class JT1078HttpServer : IHostedService | public class JT1078HttpServer : IHostedService | ||||
{ | { | ||||
private readonly ILogger Logger; | private readonly ILogger Logger; | ||||
@@ -31,9 +34,17 @@ namespace JT1078.Gateway | |||||
private HttpListener listener; | private HttpListener listener; | ||||
private JT1078HttpSessionManager SessionManager; | private JT1078HttpSessionManager SessionManager; | ||||
private readonly HLSRequestManager hLSRequestManager; | |||||
private FileSystemWatcher watcher; | |||||
private HLSRequestManager hLSRequestManager; | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="jT1078ConfigurationAccessor"></param> | |||||
/// <param name="authorization"></param> | |||||
/// <param name="sessionManager"></param> | |||||
/// <param name="hLSRequestManager"></param> | |||||
/// <param name="loggerFactory"></param> | |||||
public JT1078HttpServer( | public JT1078HttpServer( | ||||
IOptions<JT1078Configuration> jT1078ConfigurationAccessor, | IOptions<JT1078Configuration> jT1078ConfigurationAccessor, | ||||
IJT1078Authorization authorization, | IJT1078Authorization authorization, | ||||
@@ -48,6 +59,11 @@ namespace JT1078.Gateway | |||||
this.hLSRequestManager = hLSRequestManager; | this.hLSRequestManager = hLSRequestManager; | ||||
} | } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="cancellationToken"></param> | |||||
/// <returns></returns> | |||||
public Task StartAsync(CancellationToken cancellationToken) | public Task StartAsync(CancellationToken cancellationToken) | ||||
{ | { | ||||
if (!HttpListener.IsSupported) | if (!HttpListener.IsSupported) | ||||
@@ -65,21 +81,47 @@ namespace JT1078.Gateway | |||||
catch (System.Net.HttpListenerException ex) | catch (System.Net.HttpListenerException ex) | ||||
{ | { | ||||
Logger.LogWarning(ex, $"{ex.Message}:使用cmd命令[netsh http add urlacl url=http://*:{Configuration.HttpPort}/ user=Everyone]"); | Logger.LogWarning(ex, $"{ex.Message}:使用cmd命令[netsh http add urlacl url=http://*:{Configuration.HttpPort}/ user=Everyone]"); | ||||
return Task.CompletedTask; | |||||
} | } | ||||
Logger.LogInformation($"JT1078 Http Server start at {IPAddress.Any}:{Configuration.HttpPort}."); | Logger.LogInformation($"JT1078 Http Server start at {IPAddress.Any}:{Configuration.HttpPort}."); | ||||
Task.Factory.StartNew(async() => | |||||
Task.Factory.StartNew(async () => | |||||
{ | { | ||||
while (listener.IsListening) | while (listener.IsListening) | ||||
{ | { | ||||
var context = await listener.GetContextAsync(); | var context = await listener.GetContextAsync(); | ||||
try | try | ||||
{ | { | ||||
await Task.Run(async () => | |||||
await Task.Run(async () => | |||||
{ | { | ||||
IPrincipal principal=null; | |||||
if (context.Request.RawUrl.Contains(".ts")||authorization.Authorization(context, out principal)) | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation($"[Http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}-{context.Request.RawUrl}"); | |||||
} | |||||
if (context.Request.RawUrl.StartsWith("/favicon.ico")) | |||||
{ | |||||
context.Http404(); | |||||
return; | |||||
} | |||||
if (context.TryGetAVInfo(out JT1078AVInfo jT1078AVInfo)) | |||||
{ | |||||
await context.Http400(); | |||||
return; | |||||
} | |||||
if (context.Request.RawUrl.Contains(".m3u8")) | |||||
{ | |||||
ProcessM3u8(context, jT1078AVInfo); | |||||
} | |||||
else if (context.Request.RawUrl.Contains(".ts")) | |||||
{ | |||||
ProcessTs(context, jT1078AVInfo); | |||||
} | |||||
else if (context.Request.RawUrl.Contains(".flv")) | |||||
{ | |||||
ProcessFlv(context, jT1078AVInfo); | |||||
} | |||||
else if (context.Request.RawUrl.Contains(".mp4")) | |||||
{ | { | ||||
await ProcessRequestAsync(context, principal); | |||||
ProcessFMp4(context, jT1078AVInfo); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -90,103 +132,125 @@ namespace JT1078.Gateway | |||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
await context.Http500(); | await context.Http500(); | ||||
Logger.LogError(ex, ex.StackTrace); | |||||
Logger.LogError(ex, $"[Http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}-{context.Request.RawUrl}-{ex.StackTrace}"); | |||||
} | } | ||||
} | } | ||||
}, cancellationToken); | }, cancellationToken); | ||||
return Task.CompletedTask; | return Task.CompletedTask; | ||||
} | } | ||||
private async ValueTask ProcessRequestAsync(HttpListenerContext context, IPrincipal principal) | |||||
private void ProcessM3u8(HttpListenerContext context, JT1078AVInfo jT1078AVInfo) | |||||
{ | { | ||||
if(context.Request.RawUrl.StartsWith("/favicon.ico")) | |||||
{ | |||||
context.Http404(); | |||||
return; | |||||
} | |||||
if (context.Request.RawUrl.Contains(".m3u8") || context.Request.RawUrl.Contains(".ts")) | |||||
if (authorization.Authorization(context, out IPrincipal principal)) | |||||
{ | { | ||||
hLSRequestManager.HandleHlsRequest(context, principal); | hLSRequestManager.HandleHlsRequest(context, principal); | ||||
return; | |||||
} | } | ||||
if (Logger.IsEnabled(LogLevel.Trace)) | |||||
{ | |||||
Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}"); | |||||
} | |||||
if (Logger.IsEnabled(LogLevel.Trace)) | |||||
} | |||||
private void ProcessTs(HttpListenerContext context, JT1078AVInfo jT1078AVInfo) | |||||
{ | |||||
//ts 无需验证 | |||||
hLSRequestManager.HandleHlsRequest(context, default); | |||||
} | |||||
private async void ProcessFlv(HttpListenerContext context, JT1078AVInfo jT1078AVInfo) | |||||
{ | |||||
if (authorization.Authorization(context, out IPrincipal principal)) | |||||
{ | { | ||||
Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}"); | |||||
if (context.Request.IsWebSocketRequest) | |||||
{ | |||||
await ProccessWebSocket(context, principal, jT1078AVInfo, RTPVideoType.Ws_Flv); | |||||
} | |||||
else | |||||
{ | |||||
ProccessHttpKeepLive(context, principal, jT1078AVInfo, RTPVideoType.Http_Flv); | |||||
} | |||||
} | } | ||||
string sim = context.Request.QueryString.Get("sim"); | |||||
string channel = context.Request.QueryString.Get("channel"); | |||||
if(string.IsNullOrEmpty(sim) || string.IsNullOrEmpty(channel)) | |||||
} | |||||
private async void ProcessFMp4(HttpListenerContext context, JT1078AVInfo jT1078AVInfo) | |||||
{ | |||||
if (authorization.Authorization(context, out IPrincipal principal)) | |||||
{ | { | ||||
await context.Http400(); | |||||
return; | |||||
if (context.Request.IsWebSocketRequest) | |||||
{ | |||||
await ProccessWebSocket(context, principal, jT1078AVInfo, RTPVideoType.Ws_FMp4); | |||||
} | |||||
else | |||||
{ | |||||
ProccessHttpKeepLive(context, principal, jT1078AVInfo, RTPVideoType.Http_FMp4); | |||||
} | |||||
} | } | ||||
int.TryParse(channel, out int channelNo); | |||||
if (context.Request.IsWebSocketRequest) | |||||
} | |||||
private async ValueTask ProccessWebSocket(HttpListenerContext context, IPrincipal principal, JT1078AVInfo jT1078AVInfo, RTPVideoType videoType) | |||||
{ | |||||
HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null, keepAliveInterval: TimeSpan.FromSeconds(5)); | |||||
var jT1078HttpContext = new JT1078HttpContext(context, wsContext, principal); | |||||
jT1078HttpContext.Sim = jT1078AVInfo.Sim; | |||||
jT1078HttpContext.ChannelNo = jT1078AVInfo.ChannelNo; | |||||
jT1078HttpContext.RTPVideoType = videoType; | |||||
SessionManager.TryAdd(jT1078HttpContext); | |||||
//这个发送出去,flv.js就报错了 | |||||
//await jT1078HttpContext.WebSocketSendHelloAsync(); | |||||
await Task.Factory.StartNew(async (state) => | |||||
{ | { | ||||
HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null, keepAliveInterval:TimeSpan.FromSeconds(5)); | |||||
var jT1078HttpContext = new JT1078HttpContext(context, wsContext,principal); | |||||
jT1078HttpContext.Sim = sim; | |||||
jT1078HttpContext.ChannelNo = channelNo; | |||||
jT1078HttpContext.RTPVideoType = RTPVideoType.Ws_Flv; | |||||
SessionManager.TryAdd(jT1078HttpContext); | |||||
//这个发送出去,flv.js就报错了 | |||||
//await jT1078HttpContext.WebSocketSendHelloAsync(); | |||||
await Task.Factory.StartNew(async(state) => | |||||
//https://www.bejson.com/httputil/websocket/ | |||||
//ws://localhost:15555?token=22&sim=1221&channel=1 | |||||
var websocketContext = state as JT1078HttpContext; | |||||
while (websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Open || | |||||
websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Connecting) | |||||
{ | { | ||||
//https://www.bejson.com/httputil/websocket/ | |||||
//ws://localhost:15555?token=22&sim=1221&channel=1 | |||||
var websocketContext = state as JT1078HttpContext; | |||||
while (websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Open || | |||||
websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Connecting) | |||||
var buffer = ArrayPool<byte>.Shared.Rent(256); | |||||
try | |||||
{ | { | ||||
var buffer = ArrayPool<byte>.Shared.Rent(256); | |||||
try | |||||
//客户端主动断开需要有个线程去接收通知,不然会客户端会卡死直到超时 | |||||
WebSocketReceiveResult receiveResult = await websocketContext.WebSocketContext.WebSocket.ReceiveAsync(buffer, CancellationToken.None); | |||||
if (receiveResult.EndOfMessage) | |||||
{ | { | ||||
//客户端主动断开需要有个线程去接收通知,不然会客户端会卡死直到超时 | |||||
WebSocketReceiveResult receiveResult = await websocketContext.WebSocketContext.WebSocket.ReceiveAsync(buffer, CancellationToken.None); | |||||
if (receiveResult.EndOfMessage) | |||||
if (receiveResult.Count > 0) | |||||
{ | { | ||||
if (receiveResult.Count > 0) | |||||
var data = buffer.AsSpan().Slice(0, receiveResult.Count).ToArray(); | |||||
if (Logger.IsEnabled(LogLevel.Trace)) | |||||
{ | { | ||||
var data = buffer.AsSpan().Slice(0, receiveResult.Count).ToArray(); | |||||
if (Logger.IsEnabled(LogLevel.Trace)) | |||||
{ | |||||
Logger.LogTrace($"[ws receive]:{Encoding.UTF8.GetString(data)}"); | |||||
} | |||||
await websocketContext.WebSocketSendTextAsync(data); | |||||
Logger.LogTrace($"[ws receive]:{Encoding.UTF8.GetString(data)}"); | |||||
} | } | ||||
await websocketContext.WebSocketSendTextAsync(data); | |||||
} | } | ||||
} | } | ||||
finally | |||||
{ | |||||
ArrayPool<byte>.Shared.Return(buffer); | |||||
} | |||||
} | } | ||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
finally | |||||
{ | { | ||||
Logger.LogInformation($"[ws close]:{websocketContext.SessionId}-{websocketContext.Sim}-{websocketContext.ChannelNo}-{websocketContext.StartTime:yyyyMMddhhmmss}"); | |||||
ArrayPool<byte>.Shared.Return(buffer); | |||||
} | } | ||||
SessionManager.TryRemove(websocketContext.SessionId); | |||||
}, jT1078HttpContext); | |||||
} | |||||
else | |||||
{ | |||||
var jT1078HttpContext = new JT1078HttpContext(context,principal); | |||||
jT1078HttpContext.Sim = sim; | |||||
jT1078HttpContext.RTPVideoType = RTPVideoType.Http_Flv; | |||||
jT1078HttpContext.ChannelNo = channelNo; | |||||
SessionManager.TryAdd(jT1078HttpContext); | |||||
} | |||||
} | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation($"[ws close]:{websocketContext.SessionId}-{websocketContext.Sim}-{websocketContext.ChannelNo}-{websocketContext.StartTime:yyyyMMddhhmmss}-{websocketContext.Context.Request.RawUrl}"); | |||||
} | |||||
SessionManager.TryRemove(websocketContext.SessionId); | |||||
}, jT1078HttpContext); | |||||
} | |||||
private void ProccessHttpKeepLive(HttpListenerContext context, IPrincipal principal, JT1078AVInfo jT1078AVInfo, RTPVideoType videoType) | |||||
{ | |||||
var jT1078HttpContext = new JT1078HttpContext(context, principal); | |||||
jT1078HttpContext.RTPVideoType = videoType; | |||||
jT1078HttpContext.Sim = jT1078AVInfo.Sim; | |||||
jT1078HttpContext.ChannelNo = jT1078AVInfo.ChannelNo; | |||||
SessionManager.TryAdd(jT1078HttpContext); | |||||
} | } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="cancellationToken"></param> | |||||
/// <returns></returns> | |||||
public Task StopAsync(CancellationToken cancellationToken) | public Task StopAsync(CancellationToken cancellationToken) | ||||
{ | { | ||||
try | try | ||||
{ | { | ||||
Logger.LogInformation($"JT1078 Http Server stop at {IPAddress.Any}:{Configuration.HttpPort}."); | |||||
SessionManager.TryRemoveAll(); | SessionManager.TryRemoveAll(); | ||||
listener.Stop(); | listener.Stop(); | ||||
} | } | ||||
@@ -196,7 +260,7 @@ namespace JT1078.Gateway | |||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
Logger.LogError(ex, $"JT1078 Http Server error at {IPAddress.Any}:{Configuration.HttpPort}."); | |||||
} | } | ||||
return Task.CompletedTask; | return Task.CompletedTask; | ||||
} | } | ||||
@@ -0,0 +1,39 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT1078.Gateway.Metadata | |||||
{ | |||||
/// <summary> | |||||
/// 音视频信息 | |||||
/// </summary> | |||||
public struct JT1078AVInfo | |||||
{ | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="sim"></param> | |||||
/// <param name="channelNo"></param> | |||||
public JT1078AVInfo(string sim, int channelNo) | |||||
{ | |||||
Sim = sim; | |||||
ChannelNo = channelNo; | |||||
} | |||||
/// <summary> | |||||
/// sim | |||||
/// </summary> | |||||
public string Sim { get; set; } | |||||
/// <summary> | |||||
/// 通道号 | |||||
/// </summary> | |||||
public int ChannelNo { get; set; } | |||||
/// <summary> | |||||
/// key | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
public override string ToString() | |||||
{ | |||||
return $"{Sim}_{ChannelNo}"; | |||||
} | |||||
} | |||||
} |
@@ -8,17 +8,38 @@ using System.Text.Json.Serialization; | |||||
namespace JT1078.Gateway.Metadata | namespace JT1078.Gateway.Metadata | ||||
{ | { | ||||
/// <summary> | |||||
/// http上下文 | |||||
/// </summary> | |||||
public class JT1078HttpContext | public class JT1078HttpContext | ||||
{ | { | ||||
/// <summary> | |||||
/// 会话Id | |||||
/// </summary> | |||||
public string SessionId { get; } | public string SessionId { get; } | ||||
/// <summary> | |||||
/// http上下文 | |||||
/// </summary> | |||||
[JsonIgnore] | [JsonIgnore] | ||||
public HttpListenerContext Context { get; } | public HttpListenerContext Context { get; } | ||||
/// <summary> | |||||
/// ws上下文 | |||||
/// </summary> | |||||
[JsonIgnore] | [JsonIgnore] | ||||
public HttpListenerWebSocketContext WebSocketContext { get; } | public HttpListenerWebSocketContext WebSocketContext { get; } | ||||
/// <summary> | |||||
/// 用户信息 | |||||
/// </summary> | |||||
public IPrincipal User { get; } | public IPrincipal User { get; } | ||||
/// <summary> | |||||
/// 观看视频类型 | |||||
/// </summary> | |||||
public RTPVideoType RTPVideoType { get; set; } | public RTPVideoType RTPVideoType { get; set; } | ||||
public string Sim { get; set; } | public string Sim { get; set; } | ||||
public int ChannelNo { get; set; } | public int ChannelNo { get; set; } | ||||
/// <summary> | |||||
/// 是否是ws协议 | |||||
/// </summary> | |||||
public bool IsWebSocket | public bool IsWebSocket | ||||
{ | { | ||||
get | get | ||||
@@ -26,8 +47,19 @@ namespace JT1078.Gateway.Metadata | |||||
return Context.Request.IsWebSocketRequest; | return Context.Request.IsWebSocketRequest; | ||||
} | } | ||||
} | } | ||||
/// <summary> | |||||
/// 开始时间 | |||||
/// </summary> | |||||
public DateTime StartTime { get; set; } | public DateTime StartTime { get; set; } | ||||
/// <summary> | |||||
/// 是否发送首包视频数据 | |||||
/// </summary> | |||||
public bool FirstSend { get; set; } | public bool FirstSend { get; set; } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="context"></param> | |||||
/// <param name="user"></param> | |||||
public JT1078HttpContext(HttpListenerContext context, IPrincipal user) | public JT1078HttpContext(HttpListenerContext context, IPrincipal user) | ||||
{ | { | ||||
Context = context; | Context = context; | ||||
@@ -36,6 +68,12 @@ namespace JT1078.Gateway.Metadata | |||||
SessionId = Guid.NewGuid().ToString("N"); | SessionId = Guid.NewGuid().ToString("N"); | ||||
FirstSend = false; | FirstSend = false; | ||||
} | } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="context"></param> | |||||
/// <param name="webSocketContext"></param> | |||||
/// <param name="user"></param> | |||||
public JT1078HttpContext(HttpListenerContext context, HttpListenerWebSocketContext webSocketContext, IPrincipal user) | public JT1078HttpContext(HttpListenerContext context, HttpListenerWebSocketContext webSocketContext, IPrincipal user) | ||||
{ | { | ||||
Context = context; | Context = context; | ||||
@@ -46,10 +84,30 @@ namespace JT1078.Gateway.Metadata | |||||
FirstSend = false; | FirstSend = false; | ||||
} | } | ||||
} | } | ||||
/// <summary> | |||||
/// 观看视频类型 | |||||
/// </summary> | |||||
public enum RTPVideoType | public enum RTPVideoType | ||||
{ | { | ||||
/// <summary> | |||||
/// Http_Flv | |||||
/// </summary> | |||||
Http_Flv, | Http_Flv, | ||||
/// <summary> | |||||
/// Ws_Flv | |||||
/// </summary> | |||||
Ws_Flv, | Ws_Flv, | ||||
/// <summary> | |||||
/// Http_Hls | |||||
/// </summary> | |||||
Http_Hls, | Http_Hls, | ||||
/// <summary> | |||||
/// Http_FMp4 | |||||
/// </summary> | |||||
Http_FMp4, | |||||
/// <summary> | |||||
/// Ws_FMp4 | |||||
/// </summary> | |||||
Ws_FMp4, | |||||
} | } | ||||
} | } |
@@ -5,7 +5,7 @@ using System.IO; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Text; | using System.Text; | ||||
namespace JT1078.Gateway | |||||
namespace JT1078.Gateway.Services | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// hls路径是否存在处理,及文件监控处理 | /// hls路径是否存在处理,及文件监控处理 |
@@ -17,7 +17,7 @@ using System.Text; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace JT1078.Gateway | |||||
namespace JT1078.Gateway.Services | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Hls请求管理 | /// Hls请求管理 |