Просмотр исходного кода

调整http服务器增加fmp4

master
SmallChi(Koike) 4 лет назад
Родитель
Сommit
33363cda5f
11 измененных файлов: 368 добавлений и 82 удалений
  1. +1
    -1
      src/JT1078.Gateway.Abstractions/JT1078.Gateway.Abstractions.csproj
  2. +0
    -1
      src/JT1078.Gateway.Tests/JT1078.Gateway.Test/JT1078.Gateway.Test.csproj
  3. +2
    -3
      src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/JT1078.Gateway.TestNormalHosting.csproj
  4. +100
    -0
      src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/JT1078FMp4NormalMsgHostedService.cs
  5. +25
    -0
      src/JT1078.Gateway/Extensions/JT1078HttpContextExtensions.cs
  6. +3
    -1
      src/JT1078.Gateway/JT1078.Gateway.csproj
  7. +138
    -74
      src/JT1078.Gateway/JT1078HttpServer.cs
  8. +39
    -0
      src/JT1078.Gateway/Metadata/JT1078AVInfo.cs
  9. +58
    -0
      src/JT1078.Gateway/Metadata/JT1078HttpContext.cs
  10. +1
    -1
      src/JT1078.Gateway/Services/HLSPathStorage.cs
  11. +1
    -1
      src/JT1078.Gateway/Services/HLSRequestManager.cs

+ 1
- 1
src/JT1078.Gateway.Abstractions/JT1078.Gateway.Abstractions.csproj Просмотреть файл

@@ -39,6 +39,6 @@
<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" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="5.0.2" />
</ItemGroup>
</Project>

+ 0
- 1
src/JT1078.Gateway.Tests/JT1078.Gateway.Test/JT1078.Gateway.Test.csproj Просмотреть файл

@@ -8,7 +8,6 @@

<ItemGroup>
<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.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>


+ 2
- 3
src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/JT1078.Gateway.TestNormalHosting.csproj Просмотреть файл

@@ -6,12 +6,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JT1078.Flv" Version="1.1.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.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>


+ 100
- 0
src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/JT1078FMp4NormalMsgHostedService.cs Просмотреть файл

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

+ 25
- 0
src/JT1078.Gateway/Extensions/JT1078HttpContextExtensions.cs Просмотреть файл

@@ -149,5 +149,30 @@ namespace JT1078.Gateway.Extensions
{
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;
}
}
}

+ 3
- 1
src/JT1078.Gateway/JT1078.Gateway.csproj Просмотреть файл

@@ -40,8 +40,10 @@

<ItemGroup>
<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="System.IO.Pipelines" Version="5.0.0" />
<PackageReference Include="System.IO.Pipelines" Version="5.0.1" />
</ItemGroup>

<ItemGroup>


+ 138
- 74
src/JT1078.Gateway/JT1078HttpServer.cs Просмотреть файл

@@ -16,10 +16,13 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JT1078.Gateway.Extensions;
using Microsoft.Extensions.Caching.Memory;
using JT1078.Gateway.Services;

namespace JT1078.Gateway
{
/// <summary>
/// http服务器
/// </summary>
public class JT1078HttpServer : IHostedService
{
private readonly ILogger Logger;
@@ -31,9 +34,17 @@ namespace JT1078.Gateway
private HttpListener listener;

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(
IOptions<JT1078Configuration> jT1078ConfigurationAccessor,
IJT1078Authorization authorization,
@@ -48,6 +59,11 @@ namespace JT1078.Gateway
this.hLSRequestManager = hLSRequestManager;
}

/// <summary>
///
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task StartAsync(CancellationToken cancellationToken)
{
if (!HttpListener.IsSupported)
@@ -65,21 +81,47 @@ namespace JT1078.Gateway
catch (System.Net.HttpListenerException ex)
{
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}.");
Task.Factory.StartNew(async() =>
Task.Factory.StartNew(async () =>
{
while (listener.IsListening)
{
var context = await listener.GetContextAsync();
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
{
@@ -90,103 +132,125 @@ namespace JT1078.Gateway
catch (Exception ex)
{
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);
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);
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)
{
try
{
Logger.LogInformation($"JT1078 Http Server stop at {IPAddress.Any}:{Configuration.HttpPort}.");
SessionManager.TryRemoveAll();
listener.Stop();
}
@@ -196,7 +260,7 @@ namespace JT1078.Gateway
}
catch (Exception ex)
{
Logger.LogError(ex, $"JT1078 Http Server error at {IPAddress.Any}:{Configuration.HttpPort}.");
}
return Task.CompletedTask;
}


+ 39
- 0
src/JT1078.Gateway/Metadata/JT1078AVInfo.cs Просмотреть файл

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

+ 58
- 0
src/JT1078.Gateway/Metadata/JT1078HttpContext.cs Просмотреть файл

@@ -8,17 +8,38 @@ using System.Text.Json.Serialization;

namespace JT1078.Gateway.Metadata
{
/// <summary>
/// http上下文
/// </summary>
public class JT1078HttpContext
{
/// <summary>
/// 会话Id
/// </summary>
public string SessionId { get; }
/// <summary>
/// http上下文
/// </summary>
[JsonIgnore]
public HttpListenerContext Context { get; }
/// <summary>
/// ws上下文
/// </summary>
[JsonIgnore]
public HttpListenerWebSocketContext WebSocketContext { get; }
/// <summary>
/// 用户信息
/// </summary>
public IPrincipal User { get; }
/// <summary>
/// 观看视频类型
/// </summary>
public RTPVideoType RTPVideoType { get; set; }
public string Sim { get; set; }
public int ChannelNo { get; set; }
/// <summary>
/// 是否是ws协议
/// </summary>
public bool IsWebSocket
{
get
@@ -26,8 +47,19 @@ namespace JT1078.Gateway.Metadata
return Context.Request.IsWebSocketRequest;
}
}
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 是否发送首包视频数据
/// </summary>
public bool FirstSend { get; set; }
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="user"></param>
public JT1078HttpContext(HttpListenerContext context, IPrincipal user)
{
Context = context;
@@ -36,6 +68,12 @@ namespace JT1078.Gateway.Metadata
SessionId = Guid.NewGuid().ToString("N");
FirstSend = false;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="webSocketContext"></param>
/// <param name="user"></param>
public JT1078HttpContext(HttpListenerContext context, HttpListenerWebSocketContext webSocketContext, IPrincipal user)
{
Context = context;
@@ -46,10 +84,30 @@ namespace JT1078.Gateway.Metadata
FirstSend = false;
}
}
/// <summary>
/// 观看视频类型
/// </summary>
public enum RTPVideoType
{
/// <summary>
/// Http_Flv
/// </summary>
Http_Flv,
/// <summary>
/// Ws_Flv
/// </summary>
Ws_Flv,
/// <summary>
/// Http_Hls
/// </summary>
Http_Hls,
/// <summary>
/// Http_FMp4
/// </summary>
Http_FMp4,
/// <summary>
/// Ws_FMp4
/// </summary>
Ws_FMp4,
}
}

src/JT1078.Gateway/HLSPathStorage.cs → src/JT1078.Gateway/Services/HLSPathStorage.cs Просмотреть файл

@@ -5,7 +5,7 @@ using System.IO;
using System.Linq;
using System.Text;

namespace JT1078.Gateway
namespace JT1078.Gateway.Services
{
/// <summary>
/// hls路径是否存在处理,及文件监控处理

src/JT1078.Gateway/HLSRequestManager.cs → src/JT1078.Gateway/Services/HLSRequestManager.cs Просмотреть файл

@@ -17,7 +17,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JT1078.Gateway
namespace JT1078.Gateway.Services
{
/// <summary>
/// Hls请求管理

Загрузка…
Отмена
Сохранить