diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 00000000..bf986cda --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,28 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: .NET + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal diff --git a/.gitignore b/.gitignore index ece108b7..24b9738b 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ ehthumbs.db Thumbs.db .DS_Store */.DS_Store +.vscode/** +.vs/** +*.csproj.user diff --git a/AKStreamKeeper/AKStream.ldb b/AKStreamKeeper/AKStream.ldb index 507b8653..f09d9d81 100644 Binary files a/AKStreamKeeper/AKStream.ldb and b/AKStreamKeeper/AKStream.ldb differ diff --git a/AKStreamKeeper/AKStreamKeeper.csproj b/AKStreamKeeper/AKStreamKeeper.csproj index 716b28d5..d88e3ad9 100644 --- a/AKStreamKeeper/AKStreamKeeper.csproj +++ b/AKStreamKeeper/AKStreamKeeper.csproj @@ -1,17 +1,9 @@ - net6.0 - default - - - - bin\Debug\net6.0\AKStreamKeeper.xml - portable - - - - bin\Debug\net5.0\AKStreamKeeper.xml + net6.0 + default + True @@ -21,9 +13,15 @@ - - - + + + + + + + + Always + diff --git a/AKStreamKeeper/AutoTask/DiskUseableChecker.cs b/AKStreamKeeper/AutoTask/DiskUseableChecker.cs new file mode 100644 index 00000000..6370ba5e --- /dev/null +++ b/AKStreamKeeper/AutoTask/DiskUseableChecker.cs @@ -0,0 +1,55 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using LibCommon; + +namespace AKStreamKeeper.AutoTask; + +public class DiskUseableChecker +{ + public DiskUseableChecker() + { + if (Common.AkStreamKeeperConfig.CheckLinuxDiskMount == true && + RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && + Common.AkStreamKeeperConfig.CustomRecordPathList != null && + Common.AkStreamKeeperConfig.CustomRecordPathList.Count > 0) + { + new Thread(new ThreadStart(delegate + { + try + { + Checker(); + } + catch + { + } + })).Start(); + } + } + + private void Checker() + { + while (true) + { + try + { + lock (Common.DisksUseable) + { + Common.DisksUseable.Clear(); + foreach (var path in Common.AkStreamKeeperConfig + .CustomRecordPathList) + { + var ret = UtilsHelper.DirAreMounttedAndWriteableForLinux(path); + Common.DisksUseable.Add(path, ret); + } + } + } + catch (Exception ex) + { + GCommon.Logger.Error($"[{Common.LoggerHead}]->执行磁盘挂载检测时出现异常->{ex.Message}\r\n{ex.StackTrace}"); + } + + Thread.Sleep(5000); + } + } +} \ No newline at end of file diff --git a/AKStreamKeeper/Common.cs b/AKStreamKeeper/Common.cs index bf72eb57..c0d9b62f 100644 --- a/AKStreamKeeper/Common.cs +++ b/AKStreamKeeper/Common.cs @@ -35,6 +35,8 @@ public static class Common private static DateTime _sendDataTick = DateTime.Now; private static ulong _timerCount = 0; private static string _oldMediaServerId = ""; + private static Dictionary _disksUseable = new Dictionary(); + private static DiskUseableChecker _diskUseableChecker; public static string OldMediaServerId { @@ -79,6 +81,15 @@ public static Timer PerFormanceInfoTimer public static MediaServerInstance MediaServerInstance; + /// + /// 挂载的硬盘是否可用 + /// + public static Dictionary DisksUseable + { + get => _disksUseable; + set => _disksUseable = value; + } + static Common() { #if (DEBUG) @@ -546,6 +557,7 @@ private static bool ReadConfig(out ResponseStruct rs) KeeperPerformanceInfo = _keeperSystemInfo.GetSystemInfoObject(); } + if (!File.Exists(_configPath)) { //创建文件 @@ -570,6 +582,7 @@ private static bool ReadConfig(out ResponseStruct rs) var text = File.ReadAllText("/etc/hostname").Trim().ToLower(); if (text.Contains("gdn") || text.Contains("guardian") || text.Contains("rasp")) { + _akStreamKeeperConfig.CheckLinuxDiskMount = true; _akStreamKeeperConfig.RecordSec = 120; var _jsonText = JsonHelper.ToJson(_akStreamKeeperConfig, Formatting.Indented); if (!string.IsNullOrEmpty(_jsonText)) @@ -742,6 +755,22 @@ private static void OnTimedEvent(object source, ElapsedEventArgs e) tmpKeepAlive.MediaServerIsRunning = MediaServerInstance.IsRunning; tmpKeepAlive.Version = Version; tmpKeepAlive.ZlmBuildDateTime = MediaServerInstance.ZlmBuildDateTime; + tmpKeepAlive.CutMergeFilePath = _akStreamKeeperConfig.CutMergeFilePath; + lock (DisksUseable) + { + if (DisksUseable != null && DisksUseable.Count > 0) + { + tmpKeepAlive.DisksUseable = new Dictionary(); + foreach (var dic in DisksUseable) + { + tmpKeepAlive.DisksUseable.Add(dic.Key, dic.Value); + } + } + else + { + tmpKeepAlive.DisksUseable = null; + } + } string reqData = JsonHelper.ToJson(tmpKeepAlive, Formatting.Indented); @@ -806,6 +835,8 @@ public static void Init() _configPath = GCommon.OutConfigPath + "AKStreamKeeper.json"; } + _configPath = UtilsHelper.FindPreferredConfigFile(_configPath); //查找优先使用的配置文件 + GCommon.Logger.Info( $"[{LoggerHead}]->Let's Go..."); GCommon.Logger.Info( @@ -853,6 +884,7 @@ public static void Init() $"[{LoggerHead}]->流媒体服务器启动成功->进程ID:{MediaServerInstance.GetPid()}"); AutoRtpPortClean = new AutoRtpPortClean(); //启动不使用rtp端口自动清理 + _diskUseableChecker = new DiskUseableChecker(); //启动磁盘挂载监控 if (!string.IsNullOrEmpty(AkStreamKeeperConfig.CutMergeFilePath)) { diff --git a/AKStreamKeeper/Config/AKStreamKeeper.json b/AKStreamKeeper/Config/AKStreamKeeper.json index 74175d7e..61e94d9e 100644 --- a/AKStreamKeeper/Config/AKStreamKeeper.json +++ b/AKStreamKeeper/Config/AKStreamKeeper.json @@ -1,9 +1,9 @@ { - "IpV4Address": "192.168.2.94", + "IpV4Address": "127.0.0.1", "IpV6Address": "fe80::8:807:2143:28a1%5", - "Candidate":"192.168.2.94", + "Candidate":"127.0.0.1", "WebApiPort": 6880, - "MediaServerPath": "/Users/qiuzhouwei/SourceTemp/ZLMediaKit/release/darwin/Debug/MediaServer", + "MediaServerPath": "/Users/qiuzhouwei/Sources/ZLMediaKit/release/darwin/Debug/MediaServer", "AkStreamWebRegisterUrl": "http://127.0.0.1:5800/MediaServer/WebHook/MediaServerKeepAlive", "CutMergeFilePath": "/Users/qiuzhouwei/Downloads/CutMergeFile", "CustomRecordPathList": [ @@ -15,10 +15,13 @@ "MinSendRtpPort": 20002, "MaxSendRtpPort": 20200, "RandomPort": false, - "FFmpegPath": "/usr/local/bin/ffmpeg", - "AccessKey": "O7O4S089-PGDW6HTM-T4CV6K74-V6RIP1I6-9300G54F-Z03TI40Q", + "FFmpegPath": "/opt/homebrew/bin/ffmpeg", + "AccessKey": "047I4WS1-U51UBO6W-1J4BT21P-MF17IT99-92J8WIHU-944Q4KIW", "RtpPortCdTime": 3600, "HttpClientTimeoutSec": 5, - "DisableShell": true, - "ZLMediakitSSLFilePath": "./sslfiles/" + "DisableShell": false, + "CheckLinuxDiskMount": false, + "ZLMediakitSSLFilePath": "./sslfiles/", + "ListenIp": "127.0.0.1", + "EnableRtspAuth": true } diff --git a/AKStreamKeeper/Config/logconfig.xml b/AKStreamKeeper/Config/logconfig.xml index 6da3aa52..e539b58a 100644 --- a/AKStreamKeeper/Config/logconfig.xml +++ b/AKStreamKeeper/Config/logconfig.xml @@ -21,7 +21,7 @@ - + diff --git a/AKStreamKeeper/Controllers/ApiServiceController.cs b/AKStreamKeeper/Controllers/ApiServiceController.cs index 15008b43..650a32e3 100644 --- a/AKStreamKeeper/Controllers/ApiServiceController.cs +++ b/AKStreamKeeper/Controllers/ApiServiceController.cs @@ -10,6 +10,9 @@ namespace AKStreamKeeper.Controllers { + /// + /// 流媒体服务器相关接口 + /// [Log] [AuthVerify] [ApiController] diff --git a/AKStreamKeeper/Controllers/CutMergeServiceController.cs b/AKStreamKeeper/Controllers/CutMergeServiceController.cs index 0c414468..a93847d4 100644 --- a/AKStreamKeeper/Controllers/CutMergeServiceController.cs +++ b/AKStreamKeeper/Controllers/CutMergeServiceController.cs @@ -8,6 +8,9 @@ namespace AKStreamKeeper.Controllers { + /// + /// 裁剪与合并视频相关接口 + /// [Log] [AuthVerify] [ApiController] diff --git a/AKStreamKeeper/MediaServerInstance.cs b/AKStreamKeeper/MediaServerInstance.cs index 590d93d1..1789e77c 100644 --- a/AKStreamKeeper/MediaServerInstance.cs +++ b/AKStreamKeeper/MediaServerInstance.cs @@ -316,17 +316,18 @@ public bool CheckDiskWritable(string dirPath, out ResponseStruct rs) Code = ErrorNumber.None, Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - if (Directory.Exists(dirPath)) + + if (_akStreamKeeperConfig.CheckLinuxDiskMount == null || _akStreamKeeperConfig.CheckLinuxDiskMount == false) + { + return true; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - string filePath = dirPath + "/test.txt"; + int ret = -1; try { - File.WriteAllText(filePath, "ok"); - var msg = File.ReadAllText(filePath); - if (!string.IsNullOrEmpty(msg) && msg.Trim().Equals("ok")) - { - return true; - } + ret = UtilsHelper.DirAreMounttedAndWriteableForLinux(dirPath); } catch (Exception ex) { @@ -339,16 +340,34 @@ public bool CheckDiskWritable(string dirPath, out ResponseStruct rs) }; return false; } - finally + + if (ret != 0) { - if (File.Exists(filePath)) + switch (ret) { - File.Delete(filePath); + case -1: + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_DiskExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_DiskExcept], + ExceptMessage = $"{dirPath}所在磁盘未挂载或未就绪", + }; + return false; + break; + case -2: + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_DiskExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_DiskExcept], + ExceptMessage = $"{dirPath}所在磁盘已挂载,但不可写入", + }; + return false; + break; } } } - return false; + return true; } /// @@ -754,8 +773,19 @@ public bool SetConfig(out ResponseStruct rs) $"http://{h}:{p}/MediaServer/WebHook/OnRecordMp4"; //当录制mp4完成时 data["hook"]["on_record_ts"] = $"http://{h}:{p}/MediaServer/WebHook/OnRecordTs"; //当录制ts完成时 - data["hook"]["on_rtsp_auth"] = ""; - data["hook"]["on_rtsp_realm"] = ""; + if (Common.AkStreamKeeperConfig.EnableRtspAuth == true) + { + data["hook"]["on_rtsp_auth"] = $"http://{h}:{p}/MediaServer/WebHook/OnRtspAuth"; + data["hook"]["on_rtsp_realm"] = $"http://{h}:{p}/MediaServer/WebHook/OnRtspRealm"; + data["rtsp"]["authBasic"] = "0"; + } + else + { + data["hook"]["on_rtsp_auth"] = ""; + data["hook"]["on_rtsp_realm"] = ""; + data["rtsp"]["authBasic"] = "1"; + } + data["hook"]["on_shell_login"] = $"http://{h}:{p}/MediaServer/WebHook/OnShellLogin"; //shell鉴权 data["hook"]["on_stream_changed"] = @@ -786,6 +816,14 @@ public bool SetConfig(out ResponseStruct rs) } parser.WriteFile(_configPath, data); + + var fileByte = File.ReadAllBytes(_configPath); + if (UtilsHelper.IsBomHeader(fileByte)) + { + UtilsHelper.WithOutBomHeader(_configPath); + } + + return true; } catch (Exception ex) @@ -880,8 +918,19 @@ public bool SetConfig(out ResponseStruct rs) _zlmNewConfig.Hook.On_Record_Mp4 = $"http://{h}:{p}/MediaServer/WebHook/OnRecordMp4"; //当录制mp4完成时 _zlmNewConfig.Hook.On_Record_Ts = $"http://{h}:{p}/MediaServer/WebHook/OnRecordTs"; //当录制ts完成时 - _zlmNewConfig.Hook.On_Rtsp_Auth = ""; - _zlmNewConfig.Hook.On_Rtsp_Realm = ""; + if (Common.AkStreamKeeperConfig.EnableRtspAuth == true) + { + _zlmNewConfig.Hook.On_Rtsp_Auth = $"http://{h}:{p}/MediaServer/WebHook/OnRtspAuth"; + _zlmNewConfig.Hook.On_Rtsp_Realm = $"http://{h}:{p}/MediaServer/WebHook/OnRtspRealm"; + _zlmNewConfig.Rtsp.AuthBasic = 0; + } + else + { + _zlmNewConfig.Hook.On_Rtsp_Auth = ""; + _zlmNewConfig.Hook.On_Rtsp_Realm = ""; + _zlmNewConfig.Rtsp.AuthBasic = 1; + } + _zlmNewConfig.Hook.On_Shell_Login = $"http://{h}:{p}/MediaServer/WebHook/OnShellLogin"; //shell鉴权 _zlmNewConfig.Hook.On_Stream_Changed = @@ -912,6 +961,11 @@ public bool SetConfig(out ResponseStruct rs) _zlmNewConfig.Record.FastStart = 1; } + if (string.IsNullOrEmpty(_zlmNewConfig.Api.Secret) || _zlmNewConfig.Api.Secret.Trim().ToLower() + .Equals("035c73f7-bb6b-4889-a715-d9eb2d1925cc")) + { + _zlmNewConfig.Api.Secret = UtilsHelper.GeneralGuid(); + } var ok = _zlmNewConfig.SetConfig(_configPath); var parser = new FileIniDataParser(); @@ -942,6 +996,15 @@ public bool SetConfig(out ResponseStruct rs) } parser.WriteFile(_configPath, data); + + + var fileByte = File.ReadAllBytes(_configPath); + if (UtilsHelper.IsBomHeader(fileByte)) + { + UtilsHelper.WithOutBomHeader(_configPath); + } + + return ok; } catch (Exception ex) @@ -1541,6 +1604,7 @@ public bool GetConfig(out ResponseStruct rs) { } + return true; } diff --git a/AKStreamKeeper/Misc/AKStreamKeeperConfig.cs b/AKStreamKeeper/Misc/AKStreamKeeperConfig.cs index edff5a09..a349b4bb 100644 --- a/AKStreamKeeper/Misc/AKStreamKeeperConfig.cs +++ b/AKStreamKeeper/Misc/AKStreamKeeperConfig.cs @@ -26,10 +26,13 @@ public class AKStreamKeeperConfig private ushort _maxSendRtpPort = 20200; private bool _randomPort = false; private int? _recordSec = 120; + private bool? _checkLinuxDiskMount = false; private int _rtpPortCDTime; private bool _useSSL = false; private ushort _webApiPort; private string? _zLMediakitSSLFilePath; + private string? _listenIP = "127.0.0.1"; + private bool? _enableRtspAuth = false; /// @@ -223,5 +226,32 @@ public ushort MaxSendRtpPort get => _maxSendRtpPort; set => _maxSendRtpPort = value; } + + /// + /// linux下是否检查存储盘挂载情况 + /// + public bool? CheckLinuxDiskMount + { + get => _checkLinuxDiskMount; + set => _checkLinuxDiskMount = value; + } + + /// + /// 监听ip地址 + /// + public string ListenIp + { + get => _listenIP; + set => _listenIP = value; + } + + /// + /// 是否开启rtsp鉴权 + /// + public bool? EnableRtspAuth + { + get => _enableRtspAuth; + set => _enableRtspAuth = value; + } } } \ No newline at end of file diff --git a/AKStreamKeeper/Program.cs b/AKStreamKeeper/Program.cs index 00f6a1cd..74ae96c3 100644 --- a/AKStreamKeeper/Program.cs +++ b/AKStreamKeeper/Program.cs @@ -47,7 +47,16 @@ public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { - webBuilder.UseStartup().UseUrls($"http://*:{Common.AkStreamKeeperConfig.WebApiPort}"); + if (string.IsNullOrEmpty(Common.AkStreamKeeperConfig.ListenIp)) + { + webBuilder.UseStartup().UseUrls($"http://*:{Common.AkStreamKeeperConfig.WebApiPort}"); + } + else + { + var url = + $"http://{Common.AkStreamKeeperConfig.ListenIp}:{Common.AkStreamKeeperConfig.WebApiPort}"; + webBuilder.UseStartup().UseUrls(url); + } }); } } \ No newline at end of file diff --git a/AKStreamKeeper/Services/CutMergeService.cs b/AKStreamKeeper/Services/CutMergeService.cs index 56e1fea8..ab80c38b 100644 --- a/AKStreamKeeper/Services/CutMergeService.cs +++ b/AKStreamKeeper/Services/CutMergeService.cs @@ -54,6 +54,7 @@ static CutMergeService() taskStatus.PlayUrl = taskReturn.Uri; } + GCommon.Logger.Debug( $"[{Common.LoggerHead}]->一个裁剪合并任务执行回调->TaskId:{taskReturn.Task.TaskId}->TaskStatus:{taskReturn.Status}->TimeConsuming:{taskReturn.TimeConsuming}->CallbakUrl:{taskReturn.Task.CallbakUrl}"); var postDate = JsonHelper.ToJson(taskReturn); diff --git a/AKStreamKeeper/Startup.cs b/AKStreamKeeper/Startup.cs index 1ea01295..fff478be 100644 --- a/AKStreamKeeper/Startup.cs +++ b/AKStreamKeeper/Startup.cs @@ -87,20 +87,22 @@ public void ConfigureServices(IServiceCollection services) .AllowAnyMethod() ); }); +#if(DEBUG) // 注册Swagger服务 services.AddSwaggerGen(c => { // 添加文档信息 c.SwaggerDoc("v1", new OpenApiInfo { Title = "AKStreamKeeper", Version = "v1" }); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "AKStreamKeeper.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "AKStreamKeeper.xml")); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "LibCommon.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "LibCommon.xml")); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "LibZLMediaKitMediaServer.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "LibZLMediaKitMediaServer.xml")); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "LibSystemInfo.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "LibSystemInfo.xml")); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "AKStreamKeeper.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AKStreamKeeper.xml"), true); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "LibCommon.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LibCommon.xml"), true); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "LibZLMediaKitMediaServer.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LibZLMediaKitMediaServer.xml"), true); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "LibSystemInfo.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LibSystemInfo.xml"), true); }); +#endif services.AddSingleton(); services.AddControllers().AddNewtonsoftJson(options => @@ -128,11 +130,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseHttpsRedirection(); +#if(DEBUG) // 启用Swagger中间件 app.UseSwagger(); // 配置SwaggerUI app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "AKStreamKeeper"); } ); +#endif app.UseRouting(); app.UseCors("cors"); app.UseMiddleware(); //ExceptionMiddleware 加入管道 diff --git a/AKStreamWeb/AKStream.ldb b/AKStreamWeb/AKStream.ldb index 1e310876..ce59d371 100644 Binary files a/AKStreamWeb/AKStream.ldb and b/AKStreamWeb/AKStream.ldb differ diff --git a/AKStreamWeb/AKStreamWeb.csproj b/AKStreamWeb/AKStreamWeb.csproj index 8fbee4c8..bc1afff7 100644 --- a/AKStreamWeb/AKStreamWeb.csproj +++ b/AKStreamWeb/AKStreamWeb.csproj @@ -1,16 +1,9 @@ - + - net6.0 - default - - - - bin\Debug\net6.0\AKStreamWeb.xml - - - - bin\Release\net5.0\AKStreamWeb.xml + net6.0 + default + True @@ -22,9 +15,9 @@ - - - + + + @@ -38,4 +31,10 @@ <_ContentIncludedByDefault Remove="Views\_ViewImports.cshtml" /> + + + Always + + + diff --git a/AKStreamWeb/AutoTask/AutoRecord.cs b/AKStreamWeb/AutoTask/AutoRecord.cs index 76591883..3921e106 100644 --- a/AKStreamWeb/AutoTask/AutoRecord.cs +++ b/AKStreamWeb/AutoTask/AutoRecord.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Threading; using AKStreamWeb.Services; using LibCommon; @@ -264,6 +262,7 @@ private void KeepRecord() { while (true) { + bool diskuseage = true; try { ResponseStruct rs = null; @@ -300,6 +299,65 @@ private void KeepRecord() { if (obj != null && obj.MediaServerStreamInfo != null) { + var MediaServerTmp = + Common.MediaServerList.FindLast(x => + x.MediaServerId.Equals(obj.MediaServerId)); + if (MediaServerTmp != null) + { + if (MediaServerTmp.DisksUseable != null && + MediaServerTmp.DisksUseable.Count > 0) + { + foreach (var disk in MediaServerTmp.DisksUseable) + { + if (disk.Value != 0) + { + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->{disk.Key}所在的磁盘挂载有异常,异常值为:{disk.Value},将中断{obj.MainId}的录制计划,待磁盘挂载正常后恢复录制计划"); + diskuseage = false; + ResponseStruct rs2 = new ResponseStruct(); + + if (obj.MediaServerStreamInfo.IsRecorded != null && + obj.MediaServerStreamInfo.IsRecorded == true) + { + try + { + var ret = MediaServerService.StopRecord( + obj.MediaServerId, + obj.MainId, + out rs2); + if (!ret.Result || ret.Code != 0 || + rs.Code != ErrorNumber.None) + { + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->因磁盘挂载异常停止{obj.MainId}的录制计划失败->{JsonHelper.ToJson(rs2)}"); + } + else + { + GCommon.Logger.Info( + $"[{Common.LoggerHead}]->因磁盘挂载异常停止{obj.MainId}的录制计划成功->{JsonHelper.ToJson(rs2)}"); + } + } + catch (Exception ex) + { + GCommon.Logger.Error( + $"[{Common.LoggerHead}]->因磁盘挂载异常停止{obj.MainId}的录制计划失败->{ex.Message}->{ex.StackTrace}"); + } + } + + break; + } + + diskuseage = true; + } + } + } + + if (!diskuseage) + { + Thread.Sleep(100); + continue; + } + var videoChannel = videoChannelList.FindLast(x => x.MainId.Equals(obj.MainId)); if (videoChannel != null) { @@ -365,75 +423,43 @@ private void KeepRecord() } else { - var diskUseage = true; - string dirName = ""; - if (Environment.OSVersion.Platform == PlatformID.Unix || - Environment.OSVersion.Platform == PlatformID.MacOSX) + string info2 = + $"自动删除录制文件条件被触发->{obj.MediaServerId}->{obj.MainId}->{videoChannel.RecordPlanName}"; + info2 += (recordPlan.LimitDays < fileDateList.Count) + ? $"限制录制文件天数:{recordPlan.LimitDays}<实际录制文件天数:{fileDateList.Count}" + : ""; + info2 += + $"->限制录制空间:{recordPlan.LimitSpace}Bytes<实际录制空间:{fileSize}Bytes"; + GCommon.Logger.Info( + $"[{Common.LoggerHead}]->{info2}"); + bool p = false; + if (recordPlan.LimitDays < fileDateList.Count) //先一天一天删除 { - diskUseage = false; - var mediaServer = Common.MediaServerList.FindLast(x => - x.MediaServerId.Equals(obj.MediaServerId)); - if (mediaServer != null && - mediaServer.RecordPathList != null && - mediaServer.RecordPathList.Count > 0) - { - var tmpPath = mediaServer.RecordPathList[0]; - dirName = tmpPath.Value.TrimEnd('/'); - diskUseage = - mediaServer.KeeperWebApi.CheckDiskWriteable( - dirName, out rs); - if (rs.Code != ErrorNumber.None) - { - diskUseage = false; - } - } - } + int? loopCount = fileDateList.Count - + recordPlan.LimitDays; - if (diskUseage) - { - string info2 = - $"自动删除录制文件条件被触发->{obj.MediaServerId}->{obj.MainId}->{videoChannel.RecordPlanName}"; - info2 += (recordPlan.LimitDays < fileDateList.Count) - ? $"限制录制文件天数:{recordPlan.LimitDays}<实际录制文件天数:{fileDateList.Count}" - : ""; - info2 += - $"->限制录制空间:{recordPlan.LimitSpace}Bytes<实际录制空间:{fileSize}Bytes"; - GCommon.Logger.Info( - $"[{Common.LoggerHead}]->{info2}"); - bool p = false; - if (recordPlan.LimitDays < fileDateList.Count) //先一天一天删除 + List willDeleteDays = new List(); + for (int i = 0; i < loopCount; i++) { - int? loopCount = fileDateList.Count - - recordPlan.LimitDays; - - List willDeleteDays = new List(); - for (int i = 0; i < loopCount; i++) - { - willDeleteDays.Add(fileDateList[i]!); - } - - DeleteFileByDay(willDeleteDays, - obj.MediaServerStreamInfo); - p = true; + willDeleteDays.Add(fileDateList[i]!); } - if (p) - { - fileSize = GetRecordFileSize(videoChannel - .MainId); //删除完一天以后再取一下文件总长度 - } + DeleteFileByDay(willDeleteDays, + obj.MediaServerStreamInfo); + p = true; + } - if (recordPlan.LimitSpace < fileSize) //还大,再删除一个文件 - { - DeleteFileOneByOne(fileSize, - obj.MediaServerStreamInfo, - recordPlan); - } + if (p) + { + fileSize = GetRecordFileSize(videoChannel + .MainId); //删除完一天以后再取一下文件总长度 } - else + + if (recordPlan.LimitSpace < fileSize) //还大,再删除一个文件 { - GCommon.Logger.Error( - $"[{Common.LoggerHead}]->当前磁盘{dirName}不可写,暂时不执行文件删除操作"); + DeleteFileOneByOne(fileSize, + obj.MediaServerStreamInfo, + recordPlan); } } @@ -455,87 +481,56 @@ private void KeepRecord() } else if (stopIt && obj.MediaServerStreamInfo.IsRecorded == false) { - var diskUseage = true; - string dirName = ""; - if (Environment.OSVersion.Platform == PlatformID.Unix || - Environment.OSVersion.Platform == PlatformID.MacOSX) + //既没启动录制,又不让启动录制,这时要查一下有没有需要删除的文件 + if (recordPlan.OverStepPlan == OverStepPlan.DeleteFile) { - diskUseage = false; - var mediaServer = Common.MediaServerList.FindLast(x => - x.MediaServerId.Equals(obj.MediaServerId)); - if (mediaServer != null && mediaServer.RecordPathList != null && - mediaServer.RecordPathList.Count > 0) + if (recordPlan.LimitDays < fileDateList.Count) { - var tmpPath = mediaServer.RecordPathList[0]; - dirName = tmpPath.Value.TrimEnd('/'); - diskUseage = - mediaServer.KeeperWebApi.CheckDiskWriteable(dirName, - out rs); - if (rs.Code != ErrorNumber.None) + string info2 = + $"自动删除录制文件条件被触发->{obj.MediaServerId}->{obj.MainId}->{videoChannel.RecordPlanName}"; + info2 += (recordPlan.LimitDays < fileDateList.Count) + ? $"限制录制文件天数:{recordPlan.LimitDays}<实际录制文件天数:{fileDateList.Count}" + : ""; + info2 += + $"->限制录制空间:{recordPlan.LimitSpace}Bytes<实际录制空间:{fileSize}Bytes"; + GCommon.Logger.Info( + $"[{Common.LoggerHead}]->{info2}"); + bool p = false; + if (recordPlan.LimitDays < fileDateList.Count) //先一天一天删除 { - diskUseage = false; - } - } - } + int? loopCount = fileDateList.Count - + recordPlan.LimitDays; - if (diskUseage) - { - //既没启动录制,又不让启动录制,这时要查一下有没有需要删除的文件 - if (recordPlan.OverStepPlan == OverStepPlan.DeleteFile) - { - if (recordPlan.LimitDays < fileDateList.Count) - { - string info2 = - $"自动删除录制文件条件被触发->{obj.MediaServerId}->{obj.MainId}->{videoChannel.RecordPlanName}"; - info2 += (recordPlan.LimitDays < fileDateList.Count) - ? $"限制录制文件天数:{recordPlan.LimitDays}<实际录制文件天数:{fileDateList.Count}" - : ""; - info2 += - $"->限制录制空间:{recordPlan.LimitSpace}Bytes<实际录制空间:{fileSize}Bytes"; - GCommon.Logger.Info( - $"[{Common.LoggerHead}]->{info2}"); - bool p = false; - if (recordPlan.LimitDays < fileDateList.Count) //先一天一天删除 + List willDeleteDays = new List(); + for (int i = 0; i < loopCount; i++) { - int? loopCount = fileDateList.Count - - recordPlan.LimitDays; - - List willDeleteDays = new List(); - for (int i = 0; i < loopCount; i++) - { - willDeleteDays.Add(fileDateList[i]!); - } - - DeleteFileByDay(willDeleteDays, - obj.MediaServerStreamInfo); - p = true; + willDeleteDays.Add(fileDateList[i]!); } - if (p) - { - fileSize = GetRecordFileSize(videoChannel - .MainId); //删除完一天以后再取一下文件总长度 - } + DeleteFileByDay(willDeleteDays, + obj.MediaServerStreamInfo); + p = true; + } - if (recordPlan.LimitSpace < fileSize) //还大,再删除一个文件 - { - DeleteFileOneByOne(fileSize, - obj.MediaServerStreamInfo, - recordPlan); - } + if (p) + { + fileSize = GetRecordFileSize(videoChannel + .MainId); //删除完一天以后再取一下文件总长度 } - else if (recordPlan.LimitSpace < fileSize) + + if (recordPlan.LimitSpace < fileSize) //还大,再删除一个文件 { - //如果文件天数不足,则删除一个文件 - DeleteFileOneByOne(fileSize, obj.MediaServerStreamInfo, + DeleteFileOneByOne(fileSize, + obj.MediaServerStreamInfo, recordPlan); } } - } - else - { - GCommon.Logger.Error( - $"[{Common.LoggerHead}]->当前磁盘{dirName}不可写,暂时不执行文件删除操作"); + else if (recordPlan.LimitSpace < fileSize) + { + //如果文件天数不足,则删除一个文件 + DeleteFileOneByOne(fileSize, obj.MediaServerStreamInfo, + recordPlan); + } } } } diff --git a/AKStreamWeb/AutoTask/AutoTaskOther.cs b/AKStreamWeb/AutoTask/AutoTaskOther.cs index 0448f55a..6302998a 100644 --- a/AKStreamWeb/AutoTask/AutoTaskOther.cs +++ b/AKStreamWeb/AutoTask/AutoTaskOther.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; +using AKStreamWeb.Services; using LibCommon; +using LibCommon.Enums; using LibCommon.Structs.DBModels; using LibZLMediaKitMediaServer.Structs.WebRequest.ZLMediaKit; @@ -14,6 +17,10 @@ public class AutoTaskOther private DateTime _deleteOldVideoTick = DateTime.Now; private DateTime _cleanUpEmptyDirTick = DateTime.Now; private DateTime _mediaListCleanTick = DateTime.Now; + private Thread RunDeleteOrphanDataHandle = null; + private bool canSuspend = true; + private bool setSuspend = false; + private bool oldState = false; public AutoTaskOther() { @@ -27,6 +34,299 @@ public AutoTaskOther() { } })).Start(); + + ThreadStart entry = new ThreadStart(RunDeleteOrphanData); + RunDeleteOrphanDataHandle = new Thread(entry); + RunDeleteOrphanDataHandle.Start(); + + new Thread(new ThreadStart(delegate + { + try + { + CheckIdleRun(); + } + catch + { + } + })).Start(); + } + + + /// + /// 检测资源是否空闲,cpu占用率低于35%时认为是空闲状态 + /// + private void CheckIdleRun() + { + ResponseStruct rs = null; + var oldStatus = false; + + while (true) + { + try + { + if (Common.WebPerformanceInfo != null && Common.WebPerformanceInfo.CpuLoad < 35f && + RunDeleteOrphanDataHandle != null) + { + setSuspend = false; + // RunDeleteOrphanDataHandle.Resume(); //linux平台不支持此方法 + } + else + { + while (!canSuspend) + { + Thread.Sleep(100); + } + + if (RunDeleteOrphanDataHandle != null) + { + setSuspend = true; + // RunDeleteOrphanDataHandle.Suspend(); //linux平台不支持此方法 + } + } + + if (oldState != setSuspend) + { + oldState = setSuspend; + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->当前双向清理孤立数据功能状态为:{(setSuspend ? "挂起" : "运行")}->CPUUsage:{Common.WebPerformanceInfo.CpuLoad}%"); + } + } + catch (Exception ex) + { + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->发生异常情况:{ex.Message}->{ex.StackTrace}"); + } + + Thread.Sleep(1000); + } + } + + /// + /// 当相对空闲时双向清理孤立数据,(双向孤立数据:mysql中存在而磁盘不存在,磁盘存在而mysql不存在的数据) + /// + private void RunDeleteOrphanData() + { + canSuspend = true; + int i = 0; + DeleteOrphanDataDir.DataDir dir; + while (true) + { + i++; + dir = UtilsHelper.IsOdd(i) ? (DeleteOrphanDataDir.DataDir.MySql) : (DeleteOrphanDataDir.DataDir.Disk); + switch (dir) + { + case DeleteOrphanDataDir.DataDir.Disk: + try + { + List fileRecordDropList = new List(); + foreach (var mediaServer in Common.MediaServerList) + { + canSuspend = false; + if (mediaServer != null && mediaServer.IsKeeperRunning) + { + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + if (mediaServer.RecordPathList != null && mediaServer.RecordPathList.Count > 0) + { + foreach (var recordPath in mediaServer.RecordPathList) + { + var dirPath = recordPath.Value; + if (Directory.Exists(dirPath)) + { + DirectoryInfo di = new DirectoryInfo(dirPath); + canSuspend = false; + FileInfo[] fis = di.GetFiles("*.mp4", SearchOption.AllDirectories); + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + if (fis != null && fis.Length > 0) + { + foreach (var f in fis) + { + if (f.Exists && !f.Name.StartsWith(".") && + !f.FullName.StartsWith(mediaServer.CutMergeFilePath)) + { + canSuspend = false; + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Select() + .Where(x => x.VideoPath.Equals(f.FullName.Trim())) + .ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->RunDeleteOrphanData->执行SQL:->{sql}"); + } + + var exists = ORMHelper.Db.Select() + .Where(x => x.VideoPath.Equals(f.FullName.Trim())) + .ToOne(); + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + if (exists == null || (exists.Deleted == true && + exists.Undo == false)) //记录不存在,或者被硬删除 + { + fileRecordDropList.Add(f.FullName); + } + } + + Thread.Sleep(200); + } + + if (fileRecordDropList != null && fileRecordDropList.Count > 0) + { + foreach (var file in fileRecordDropList) + { + canSuspend = false; + var s = mediaServer.KeeperWebApi.DeleteFile(out _, file); + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->双向清理孤立数据->Disk->{file}->{(s ? "成功" : "失败")}"); + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + Thread.Sleep(200); + } + } + } + } + + Thread.Sleep(200); + } + } + } + + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + Thread.Sleep(200); + } + } + catch (Exception ex) + { + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + GCommon.Logger.Debug($"{ex.Message}\r\n{ex.StackTrace}"); + } + + break; + case DeleteOrphanDataDir.DataDir.MySql: + try + { + List mysqlRecordDropList = new List(); + canSuspend = false; + var recordList = ORMHelper.Db.Select().Where(x => x.Deleted == false).ToList(); + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + foreach (var record in recordList) + { + if (record != null) + { + var filePath = record.VideoPath; + var mediaserver2 = Common.MediaServerList.FindLast(x => + x.MediaServerId.Equals(record.MediaServerId)); + if (mediaserver2 != null && mediaserver2.IsKeeperRunning && + !string.IsNullOrEmpty(filePath)) + { + canSuspend = false; + + var exists = mediaserver2.KeeperWebApi.FileExists(out _, filePath); + Thread.Sleep(150); + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + if (!exists) + { + mysqlRecordDropList.Add(record.Id); + } + } + } + + Thread.Sleep(200); + } + + if (mysqlRecordDropList != null && mysqlRecordDropList.Count > 0) + { + foreach (var id in mysqlRecordDropList) + { + canSuspend = false; + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Delete().Where(x => x.Id.Equals(id)) + .ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->RunDeleteOrphanData->执行SQL:->{sql}"); + } + + var s2 = ORMHelper.Db.Delete().Where(x => x.Id.Equals(id)) + .ExecuteAffrows(); + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->双向清理孤立数据->MySQL->{id}->{(s2 > 0 ? "成功" : "失败")}"); + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + Thread.Sleep(200); + } + } + + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + } + catch (Exception ex) + { + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + GCommon.Logger.Debug($"{ex.Message}\r\n{ex.StackTrace}"); + } + + break; + } + + canSuspend = true; + while (setSuspend) + { + Thread.Sleep(1000); + } + + Thread.Sleep(10000); + } } private void Run() @@ -94,7 +394,7 @@ private void Run() { ResponseStruct rs = null; var mediaList = - mediaServer.WebApiHelper.GetMediaList(new ResZLMediaKitGetMediaList(), + mediaServer.WebApiHelper.GetMediaList(new ReqZLMediaKitGetMediaList(), out rs); if (mediaList.Data == null && mediaList != null && mediaList.Code == 0 && rs.Code.Equals(ErrorNumber.None)) @@ -251,7 +551,21 @@ private void DoDeleteFor24HourAgo() Common.MediaServerList.FindLast(x => x.MediaServerId.Equals(retList[0].MediaServerId)); if (mediaServer != null && mediaServer.IsKeeperRunning) { - var delRet = mediaServer.KeeperWebApi.DeleteFileList(out _, deleteFileList); + ResponseStruct rs = new ResponseStruct() + { + Code = ErrorNumber.None, + Message = ErrorMessage.ErrorDic![ErrorNumber.None], + }; + var delRet = + AKStreamKeeperService.DeleteFileList(mediaServer.MediaServerId, deleteFileList, out rs); + // var delRet = mediaServer.KeeperWebApi.DeleteFileList(out _, deleteFileList); + + if (rs.Code == ErrorNumber.MediaServer_DiskExcept) + { + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除24小时前被软删除记录文件时发生异常->{JsonHelper.ToJson(rs)}"); + return; + } #region debug sql output diff --git a/AKStreamWeb/Common.cs b/AKStreamWeb/Common.cs index 82ab7190..6bc3d34d 100644 --- a/AKStreamWeb/Common.cs +++ b/AKStreamWeb/Common.cs @@ -88,6 +88,8 @@ static Common() _configPath = GCommon.OutConfigPath + "AKStreamWeb.json"; } + _configPath = UtilsHelper.FindPreferredConfigFile(_configPath); //查找优先使用的配置文件 + StartupDateTime = DateTime.Now; string supportDataBaseList = "MySql\r\n" + "SqlServer\r\n" + diff --git a/AKStreamWeb/Config/AKStreamWeb.json b/AKStreamWeb/Config/AKStreamWeb.json index 78d36dad..1e15a4c4 100644 --- a/AKStreamWeb/Config/AKStreamWeb.json +++ b/AKStreamWeb/Config/AKStreamWeb.json @@ -10,5 +10,7 @@ "DeletedRecordsExpiredDays" : 30, "EnableGB28181Server": true, "EnableGB28181Client": false, - "ZlmFlvPrefix" : "live" + "ZlmFlvPrefix" : "live", + "ListenIp": "127.0.0.1" + } diff --git a/AKStreamWeb/Config/SipServerConfig.json b/AKStreamWeb/Config/SipServerConfig.json index 3ee0e9fd..23185e38 100644 --- a/AKStreamWeb/Config/SipServerConfig.json +++ b/AKStreamWeb/Config/SipServerConfig.json @@ -1,5 +1,5 @@ { - "SipIpAddress": "192.168.2.92", + "SipIpAddress": "0.0.0.0", "SipIpV6Address": "fe80::8:807:2143:28a1%5", "ServerSipDeviceId": "33020000021180000001", "SipPort": 5060, @@ -14,6 +14,7 @@ "IpV6Enable": true, "EncodingType": "UTF8", "IsPassive": true, + "ListenIp" : "0.0.0.0", "NoAuthenticationRequireds": [ { "IpV4Address": "192.168.2.92", diff --git a/AKStreamWeb/Controllers/AKStreamKeeperController.cs b/AKStreamWeb/Controllers/AKStreamKeeperController.cs index 6e3a8fed..9ed275fa 100644 --- a/AKStreamWeb/Controllers/AKStreamKeeperController.cs +++ b/AKStreamWeb/Controllers/AKStreamKeeperController.cs @@ -8,6 +8,9 @@ namespace AKStreamWeb.Controllers { + /// + /// 流媒体服务器治理的相关接口 + /// [Log] [AuthVerify] [ApiController] diff --git a/AKStreamWeb/Controllers/MediaServerController.cs b/AKStreamWeb/Controllers/MediaServerController.cs index bf4ecf91..7c910302 100644 --- a/AKStreamWeb/Controllers/MediaServerController.cs +++ b/AKStreamWeb/Controllers/MediaServerController.cs @@ -16,12 +16,80 @@ namespace AKStreamWeb.Controllers { + /// + /// 流媒体相关接口 + /// [Log] [ApiController] [Route("/MediaServer")] [SwaggerTag("流媒体相关接口")] public class MediaServerController : ControllerBase { + /// + /// 添加一个rtsp鉴权记录 + /// + /// + /// + /// + [Route("AddRtspAuthData")] + [HttpPost] + [AuthVerify] + public bool AddRtspAuthData([FromHeader(Name = "AccessKey")] UserAuth req) + { + ResponseStruct rs; + var ret = MediaServerService.AddRtspAuthData(req, out rs); + if (!rs.Code.Equals(ErrorNumber.None)) + { + throw new AkStreamException(rs); + } + + return ret; + } + + /// + /// 删除一个rtsp鉴权记录 + /// + /// + /// + /// + [Route("DeleteRtspAuthData")] + [HttpPost] + [AuthVerify] + public bool DeleteRtspAuthData([FromHeader(Name = "AccessKey")] UserAuth req) + { + ResponseStruct rs; + var ret = MediaServerService.DeleteRtspAuthData(req, out rs); + if (!rs.Code.Equals(ErrorNumber.None)) + { + throw new AkStreamException(rs); + } + + return ret; + } + + + /// + /// 获取rtsp鉴权列表 + /// + /// + /// + /// + [Route("GetRtspAuthData")] + [HttpPost] + [AuthVerify] + public List GetRtspAuthData([FromHeader(Name = "AccessKey")] UserAuth? req) + { + ResponseStruct rs; + var ret = MediaServerService.GetRtspAuthData(req, out rs); + if (!rs.Code.Equals(ErrorNumber.None)) + { + throw new AkStreamException(rs); + } + + return ret; + } + + /// /// 获取当前的开放的rtpServer列表 /// diff --git a/AKStreamWeb/Controllers/SipClientController.cs b/AKStreamWeb/Controllers/SipClientController.cs index 033a8ace..a2c620a6 100644 --- a/AKStreamWeb/Controllers/SipClientController.cs +++ b/AKStreamWeb/Controllers/SipClientController.cs @@ -8,6 +8,9 @@ namespace AKStreamWeb.Controllers { + /// + /// Sip客户端需要用的接口,第三方应用不需要关心此类接口 + /// [Log] [ApiController] [Route("/SipClient")] diff --git a/AKStreamWeb/Controllers/SipServerController.cs b/AKStreamWeb/Controllers/SipServerController.cs index 683f0099..d9ed9548 100644 --- a/AKStreamWeb/Controllers/SipServerController.cs +++ b/AKStreamWeb/Controllers/SipServerController.cs @@ -10,6 +10,9 @@ namespace AKStreamWeb.Controllers { + /// + /// Sip网关相关接口 + /// [Log] [AuthVerify] [ApiController] diff --git a/AKStreamWeb/Controllers/SystemServiceController.cs b/AKStreamWeb/Controllers/SystemServiceController.cs index bcaec053..2d017707 100644 --- a/AKStreamWeb/Controllers/SystemServiceController.cs +++ b/AKStreamWeb/Controllers/SystemServiceController.cs @@ -9,6 +9,9 @@ namespace AKStreamWeb.Controllers { + /// + /// 系统相关API + /// [Log] [AuthVerify] [ApiController] @@ -93,7 +96,7 @@ public PerformanceInfo GetSystemPerformanceInfo([FromHeader(Name = "AccessKey")] /// /// 获取部门信息 - /// + /// /// /// /// diff --git a/AKStreamWeb/Controllers/WebHookController.cs b/AKStreamWeb/Controllers/WebHookController.cs index eec24618..14254aeb 100644 --- a/AKStreamWeb/Controllers/WebHookController.cs +++ b/AKStreamWeb/Controllers/WebHookController.cs @@ -10,12 +10,39 @@ namespace AKStreamWeb.Controllers { + /// + /// WebHook相关接口,第三方应用不需要关心此类接口 + /// [Log] [ApiController] [Route("/MediaServer/WebHook")] [SwaggerTag("WebHook相关接口,第三方应用不需要关心此类接口")] public class WebHookController : ControllerBase { + /// + /// rtsprealm事件 + /// + /// + /// + [Route("OnRtspRealm")] + [HttpPost] + public ResToWebHookOnRtspRealm OnRtspRealm(ReqForWebHookOnRtspRealm req) + { + return WebHookService.OnRtspRealm(req); + } + + /// + /// rtspauth事件 + /// + /// + /// + [Route("OnRtspAuth")] + [HttpPost] + public ResToWebHookOnRtspAuth OnRtspAuth(ReqForWebHookOnRtspAuth req) + { + return WebHookService.OnRtspAuth(req); + } + /// /// 当有TS文件录制时 /// diff --git a/AKStreamWeb/Misc/AKStreamWebConfig.cs b/AKStreamWeb/Misc/AKStreamWebConfig.cs index db0d22b8..a0c14ee2 100644 --- a/AKStreamWeb/Misc/AKStreamWebConfig.cs +++ b/AKStreamWeb/Misc/AKStreamWebConfig.cs @@ -17,6 +17,8 @@ public class AKStreamWebConfig private bool _enableGB28181Client = false; private bool? _enableGB28181Server = false; private string? _ZlmFlvPrefix = "live"; + private string? _listenIP = "127.0.0.1"; + private bool _localizationKingBaseDB = false; /// @@ -128,5 +130,24 @@ public string? ZlmFlvPrefix get => _ZlmFlvPrefix; set => _ZlmFlvPrefix = value; } + + /// + /// 监听ip地址 + /// + public string ListenIp + { + get => _listenIP; + set => _listenIP = value; + } + + + /// + /// 是否使用国产化的Kingbase数据库(人大金仓) + /// + public bool LocalizationKingBaseDb + { + get => _localizationKingBaseDB; + set => _localizationKingBaseDB = value; + } } } \ No newline at end of file diff --git a/AKStreamWeb/Program.cs b/AKStreamWeb/Program.cs index dc9adf43..2c556a58 100644 --- a/AKStreamWeb/Program.cs +++ b/AKStreamWeb/Program.cs @@ -42,7 +42,15 @@ public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { - webBuilder.UseStartup().UseUrls($"http://*:{Common.AkStreamWebConfig.WebApiPort}"); + if (string.IsNullOrEmpty(Common.AkStreamWebConfig.ListenIp)) + { + webBuilder.UseStartup().UseUrls($"http://*:{Common.AkStreamWebConfig.WebApiPort}"); + } + else + { + var url = $"http://{Common.AkStreamWebConfig.ListenIp}:{Common.AkStreamWebConfig.WebApiPort}"; + webBuilder.UseStartup().UseUrls(url); + } }); } } \ No newline at end of file diff --git a/AKStreamWeb/Services/AKStreamKeeperService.cs b/AKStreamWeb/Services/AKStreamKeeperService.cs index c840e6f1..69f155ad 100644 --- a/AKStreamWeb/Services/AKStreamKeeperService.cs +++ b/AKStreamWeb/Services/AKStreamKeeperService.cs @@ -883,6 +883,90 @@ public static ushort GuessAnRtpPortForSender(string mediaServerId, out ResponseS return ret; } + + /// + /// 删除一个文件不经过磁盘有效性校验 + /// + /// + /// + /// + /// + public static bool DeleteFileWithoutCheckDiskUseage(string mediaServerId, string filePath, + out ResponseStruct rs) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.None, + Message = ErrorMessage.ErrorDic![ErrorNumber.None], + }; + if (UtilsHelper.StringIsNullEx(mediaServerId)) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_ParamsIsNotRight, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_ParamsIsNotRight], + }; + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件失败->{mediaServerId}->{filePath}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return false; + } + + if (UtilsHelper.StringIsNullEx(filePath)) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_ParamsIsNotRight, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_ParamsIsNotRight], + }; + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件失败->{mediaServerId}->{filePath}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return false; + } + + var mediaServer = Common.MediaServerList.FindLast(x => x.MediaServerId.Trim().Equals(mediaServerId.Trim())); + if (mediaServer == null) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_InstanceIsNull, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_InstanceIsNull], + }; + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件失败->{mediaServerId}->{filePath}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return false; + } + + if (mediaServer.KeeperWebApi == null || mediaServer.IsKeeperRunning == false || + mediaServer.IsMediaServerRunning == false || mediaServer.WebApiHelper == null) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_NotRunning, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_NotRunning], + }; + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件失败->{mediaServerId}->{filePath}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return false; + } + + var ret = mediaServer.KeeperWebApi.DeleteFile(out rs, filePath); + if (!rs.Code.Equals(ErrorNumber.None)) + { + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件失败->{mediaServerId}->{filePath}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return false; + } + + GCommon.Logger.Info($"[{Common.LoggerHead}]->删除指定文件成功->{mediaServerId}->{filePath}"); + + return ret; + } + /// /// 删除一个指定文件 /// @@ -951,6 +1035,26 @@ public static bool DeleteFile(string mediaServerId, string filePath, out Respons return false; } + + if (mediaServer.DisksUseable != null && mediaServer.DisksUseable.Count > 0) + { + foreach (var disk in mediaServer.DisksUseable) + { + if (disk.Value != 0) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_DiskExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_DiskExcept], + }; + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件失败->{mediaServerId}->{filePath}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return false; + } + } + } + var ret = mediaServer.KeeperWebApi.DeleteFile(out rs, filePath); if (!rs.Code.Equals(ErrorNumber.None)) { @@ -1184,6 +1288,26 @@ public static ResKeeperDeleteFileList DeleteFileList(string mediaServerId, List< return null; } + + if (mediaServer.DisksUseable != null && mediaServer.DisksUseable.Count > 0) + { + foreach (var disk in mediaServer.DisksUseable) + { + if (disk.Value != 0) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_DiskExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_DiskExcept], + }; + GCommon.Logger.Warn( + $"[{Common.LoggerHead}]->删除指定文件列表失败->{mediaServerId}->{JsonHelper.ToJson(fileList)}->{JsonHelper.ToJson(rs, Formatting.Indented)}"); + + return null; + } + } + } + var ret = mediaServer.KeeperWebApi.DeleteFileList(out rs, fileList); if (ret == null || !rs.Code.Equals(ErrorNumber.None)) { diff --git a/AKStreamWeb/Services/MediaServerService.cs b/AKStreamWeb/Services/MediaServerService.cs index a82635e3..de9cc7d5 100644 --- a/AKStreamWeb/Services/MediaServerService.cs +++ b/AKStreamWeb/Services/MediaServerService.cs @@ -23,6 +23,209 @@ namespace AKStreamWeb.Services { public static class MediaServerService { + /// + /// 获取rtsp鉴权列表 + /// + /// + /// + /// + public static List GetRtspAuthData(UserAuth? req, out ResponseStruct rs) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.None, + Message = ErrorMessage.ErrorDic![ErrorNumber.None], + }; + + List list = null; + if (req != null) + { + try + { + #region debug sql output + + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Select().WhereIf(!string.IsNullOrEmpty(req.MediaServerId), + x => x.MediaServerId.Equals(req.MediaServerId)) + .WhereIf(!string.IsNullOrEmpty(req.Username), x => x.Username.Equals(req.Username)) + .WhereIf(!string.IsNullOrEmpty(req.Password), x => x.Password.Equals(req.Password)) + .WhereIf(req.Id > 0, x => x.Id.Equals(req.Id)).ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->GetRtspAuthData->执行SQL:->{sql}"); + } + + #endregion + + + list = ORMHelper.Db.Select().WhereIf(!string.IsNullOrEmpty(req.MediaServerId), + x => x.MediaServerId.Equals(req.MediaServerId)) + .WhereIf(!string.IsNullOrEmpty(req.Username), x => x.Username.Equals(req.Username)) + .WhereIf(!string.IsNullOrEmpty(req.Password), x => x.Password.Equals(req.Password)) + .WhereIf(req.Id > 0, x => x.Id.Equals(req.Id)).ToList(); + } + catch (Exception ex) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_DataBaseExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_DataBaseExcept], + ExceptMessage = ex.Message, + ExceptStackTrace = ex.StackTrace + }; + return null; + } + } + else + { + try + { + list = ORMHelper.Db.Select().ToList(); + } + catch (Exception ex) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_DataBaseExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_DataBaseExcept], + ExceptMessage = ex.Message, + ExceptStackTrace = ex.StackTrace + }; + return null; + } + } + + return list; + } + + /// + /// 删除rtsp鉴权数据 + /// + /// + /// + /// + public static bool DeleteRtspAuthData(UserAuth req, out ResponseStruct rs) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.None, + Message = ErrorMessage.ErrorDic![ErrorNumber.None], + }; + + int ret = 0; + try + { + #region debug sql output + + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Delete().Where(x => x.MediaServerId.Equals(req.MediaServerId)) + .Where(x => x.Username.Equals(req.Username)).ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->DeleteRtspAuthData->执行SQL:->{sql}"); + } + + #endregion + + + ret = ORMHelper.Db.Delete().Where(x => x.MediaServerId.Equals(req.MediaServerId)) + .Where(x => x.Username.Equals(req.Username)).ExecuteAffrows(); + } + catch (Exception ex) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_DataBaseExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_DataBaseExcept], + ExceptMessage = ex.Message, + ExceptStackTrace = ex.StackTrace + }; + return false; + } + + if (ret > 0) + { + return true; + } + + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_DB_RecordNotExists, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_DB_RecordNotExists], + }; + + return false; + } + + /// + /// 添加rtsp授权数据 + /// + /// + /// + /// + public static bool AddRtspAuthData(UserAuth req, out ResponseStruct rs) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.None, + Message = ErrorMessage.ErrorDic![ErrorNumber.None], + }; + var mediaServer = CheckMediaServer(req.MediaServerId, out rs); + if (mediaServer != null) + { + int ret = 0; + try + { + var auth = new UserAuth() + { + MediaServerId = req.MediaServerId, + Username = req.Username, + Password = UtilsHelper.Md5New($"{req.Username}:default:{req.Password}"), + }; + + #region debug sql output + + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Insert(auth).ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->AddRtspAuthData->执行SQL:->{sql}"); + } + + #endregion + + ret = ORMHelper.Db.Insert(auth).ExecuteAffrows(); + } + catch (Exception ex) + { + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_DataBaseExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_DataBaseExcept], + ExceptMessage = ex.Message, + ExceptStackTrace = ex.StackTrace + }; + return false; + } + + if (ret > 0) + { + return true; + } + + rs = new ResponseStruct() + { + Code = ErrorNumber.Sys_DB_UserAuthAlreadyExists, + Message = ErrorMessage.ErrorDic![ErrorNumber.Sys_DB_UserAuthAlreadyExists], + }; + } + + return false; + } + /// /// 获取rtpServer列表 /// @@ -97,12 +300,14 @@ private static List AnalysisVideoFile(ReqKeeperCutOrMergeVideoFi DateTime _start = DateTime.Parse(rcmv.StartTime.ToString("yyyy-MM-dd HH:mm:ss")); DateTime _end = DateTime.Parse(rcmv.EndTime.ToString("yyyy-MM-dd HH:mm:ss")); var videoList = ORMHelper.Db.Select() - .Where(x => x.StartTime > _start.AddMinutes(-60) && x.EndTime <= _end.AddMinutes(60)) + .Where(x => (x.StartTime <= _start && x.EndTime >= _start) + || (x.StartTime <= _end && x.EndTime >= _end) || + (x.StartTime >= _start && x.EndTime <= _end)) .WhereIf(!string.IsNullOrEmpty(rcmv.MediaServerId), x => x.MediaServerId!.Trim().ToLower().Equals(rcmv.MediaServerId!.Trim().ToLower())) .WhereIf(!string.IsNullOrEmpty(rcmv.MainId), x => x.Streamid!.Trim().ToLower().Equals(rcmv.MainId!.Trim().ToLower())).OrderBy(x => x.StartTime) - .ToList(); //取条件范围的前60分钟及后60分钟内的所有数据 + .ToList(); List cutMegerList = new List(); if (videoList != null && videoList.Count > 0) @@ -1900,7 +2105,7 @@ public static MediaServerStreamInfo AddStreamProxy(string mediaServerId, string req.Enable_Mp4 = 0; //录制mp4要关 req.Rtp_Type = videoChannel.RtpWithTcp == true ? 0 : 1; //rtsp拉流时,是否使用tcp,0为tcp,1为udp,2为组播 req.Timeout_Sec = Common.AkStreamWebConfig.WaitEventTimeOutMSec / 1000; //超时时间 - req.Retry_Count = -1; //无限重试 + req.Retry_Count = 0; //不成功则不重试拉流 var ret = mediaServer.WebApiHelper.AddStreamProxy(req, out rs); if (ret == null || !rs.Code.Equals(ErrorNumber.None) || ret.Code != 0) { @@ -2428,7 +2633,8 @@ public static ResDeleteFileList DeleteRecordFileList(List dbIdList, out Re continue; } - var deleted = mediaServer.KeeperWebApi.DeleteFile(out rs, dbRet.VideoPath); + //var deleted = mediaServer.KeeperWebApi.DeleteFile(out rs, dbRet.VideoPath); + var deleted = AKStreamKeeperService.DeleteFile(mediaServer.MediaServerId, dbRet.VideoPath, out rs); if (!rs.Code.Equals(ErrorNumber.None) || !deleted) { result.PathList.Add(new KeyValuePair(dbRet.Id, dbRet.VideoPath)); @@ -2568,7 +2774,8 @@ public static bool DeleteRecordFile(long dbId, out ResponseStruct rs) return false; } - var deleted = mediaServer.KeeperWebApi.DeleteFile(out rs, row.VideoPath); + // var deleted = mediaServer.KeeperWebApi.DeleteFile(out rs, row.VideoPath); + var deleted = AKStreamKeeperService.DeleteFile(mediaServer.MediaServerId, row.VideoPath, out rs); if (!rs.Code.Equals(ErrorNumber.None) || !deleted) { GCommon.Logger.Warn( @@ -5499,7 +5706,6 @@ public static ServerInstance CheckMediaServer(string mediaServerId, out Response GCommon.Logger.Debug( $"[{Common.LoggerHead}]->检查流媒体服务器状态成功->{mediaServerId}->{JsonHelper.ToJson(mediaServer)}"); - return mediaServer; } } diff --git a/AKStreamWeb/Services/SipServerService.cs b/AKStreamWeb/Services/SipServerService.cs index e0b4ca54..0b114d86 100644 --- a/AKStreamWeb/Services/SipServerService.cs +++ b/AKStreamWeb/Services/SipServerService.cs @@ -754,7 +754,7 @@ record = row.RecItems.FindLast(x => x.SsrcId.Equals(ssrcId)); try { var mediaList = - mediaServer.WebApiHelper.GetMediaList(new ResZLMediaKitGetMediaList(), out rs); + mediaServer.WebApiHelper.GetMediaList(new ReqZLMediaKitGetMediaList(), out rs); if (mediaList != null && mediaList.Code == 0 && mediaList.Data != null && mediaList.Data.Count > 0) { var media = mediaList.Data.FindLast(x => x.App.Equals(record.App) && @@ -1165,7 +1165,7 @@ public static MediaServerStreamInfo LiveVideo(string deviceId, string channelId, sipChannel.Vhost = videoChannel.Vhost; sipChannel.PushStatus = PushStatus.IDLE; var mediaList = - mediaServer.WebApiHelper.GetMediaList(new ResZLMediaKitGetMediaList(), out rs); + mediaServer.WebApiHelper.GetMediaList(new ReqZLMediaKitGetMediaList(), out rs); if (mediaList != null && mediaList.Code == 0 && mediaList.Data != null && mediaList.Data.Count > 0) { var media = mediaList.Data.FindLast(x => x.App.Equals(videoChannel.App) && @@ -1712,7 +1712,7 @@ record = row.RecItems.FindLast(x => x.SsrcId.Equals(ssrcId.ToString())); videoChannel.RtpWithTcp == true ? PushStreamSocketType.TCP : PushStreamSocketType.UDP; try { - SipMethodProxy sipMethodProxy = new SipMethodProxy(Common.AkStreamWebConfig.WaitSipRequestTimeOutMSec); + SipMethodProxy sipMethodProxy = new SipMethodProxy(Common.AkStreamWebConfig.WaitSipRequestTimeOutMSec); liveVideoRet = sipMethodProxy.InviteRecordPosition(record, pushMediaInfo, time, out rs); } catch (Exception ex) @@ -1744,7 +1744,7 @@ record = row.RecItems.FindLast(x => x.SsrcId.Equals(ssrcId.ToString())); else { GCommon.Logger.Warn( - $"[{Common.LoggerHead}]->拖拽Sip回放流失败->{record.SipDevice.DeviceId}-{record.SipChannel.DeviceId}-{record.Stream}->liveVideoRet:{liveVideoRet}"); + $"[{Common.LoggerHead}]->拖拽Sip回放流失败->{record.SipDevice.DeviceId}-{record.SipChannel.DeviceId}-{record.Stream}->liveVideoRet:{liveVideoRet}"); } return liveVideoRet; diff --git a/AKStreamWeb/Services/WebHookService.cs b/AKStreamWeb/Services/WebHookService.cs index 0a13665d..17e94826 100644 --- a/AKStreamWeb/Services/WebHookService.cs +++ b/AKStreamWeb/Services/WebHookService.cs @@ -42,6 +42,95 @@ private static bool IsRecordStream(string stream, out VideoChannelRecordInfo out } + /// + /// 当需要rtsp鉴权时,返回该rtsp鉴权的专用盐(盐就是项目名称) + /// + /// + /// + public static ResToWebHookOnRtspRealm OnRtspRealm(ReqForWebHookOnRtspRealm req) + { + GCommon.Logger.Info($"[{Common.LoggerHead}]->收到WebHook-OnRtspRealm回调->{JsonHelper.ToJson(req)}"); + if (req != null && !string.IsNullOrEmpty(req.MediaServerId)) + { + #region debug sql output + + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Select() + .Where(x => x.MediaServerId.Equals(req.MediaServerId.Trim())) + .ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->OnRtspRealm->执行SQL:->{sql}"); + } + + #endregion + + var ret = ORMHelper.Db.Select() + .Where(x => x.MediaServerId.Equals(req.MediaServerId.Trim())).First(); + if (ret != null) + { + return new ResToWebHookOnRtspRealm() + { + Code = 0, + Realm = "default" + }; + } + } + + return new ResToWebHookOnRtspRealm() + { + Code = -1, + Realm = "error" + }; + } + + /// + /// rtsp鉴权事件处理 + /// + /// + /// + public static ResToWebHookOnRtspAuth OnRtspAuth(ReqForWebHookOnRtspAuth req) + { + GCommon.Logger.Info($"[{Common.LoggerHead}]->收到WebHook-OnRtspAuth回调->{JsonHelper.ToJson(req)}"); + if (req != null && !string.IsNullOrEmpty(req.MediaServerId)) + { + var username = req.User_Name; + var realm = req.Realm; + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Select() + .Where(x => x.MediaServerId.Equals(req.MediaServerId.Trim())) + .Where(x => x.Username.Equals(username.Trim())) + .ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->OnRtspRealm->执行SQL:->{sql}"); + } + + var ret = ORMHelper.Db.Select() + .Where(x => x.MediaServerId.Equals(req.MediaServerId.Trim())) + .Where(x => x.Username.Equals(username.Trim())) + .First(); + if (ret != null && !string.IsNullOrEmpty(ret.Password)) + { + return new ResToWebHookOnRtspAuth() + { + Code = 0, + Encrypted = true, + Passwd = ret.Password, + Msg = "success" + }; + } + } + + return new ResToWebHookOnRtspAuth() + { + Code = -1, + Msg = "failed" + }; + } + public static ResToWebHookOnRecordMP4 OnRecordMp4(ReqForWebHookOnRecordMP4 req) { GCommon.Logger.Info($"[{Common.LoggerHead}]->收到WebHook-OnRecordMp4回调->{JsonHelper.ToJson(req)}"); @@ -98,6 +187,55 @@ public static ResToWebHookOnRecordMP4 OnRecordMp4(ReqForWebHookOnRecordMP4 req) #endregion + bool diskuseage = true; + if (mediaServer.DisksUseable != null && mediaServer.DisksUseable.Count > 0) + { + foreach (var disk in mediaServer.DisksUseable) + { + if (disk.Value != 0) + { + diskuseage = false; + GCommon.Logger.Error( + $"[{Common.LoggerHead}]->磁盘挂载异常->{disk.Key}->异常代码:{disk.Value}->{JsonHelper.ToJson(req)}"); + break; + } + } + } + + if (!diskuseage) + { + ResponseStruct rs = null; + try + { + try + { + AKStreamKeeperService.DeleteFileWithoutCheckDiskUseage(mediaServer.MediaServerId, req.File_Path, + out _); + } + catch + { + } + + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_DiskExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_DiskExcept], + ExceptMessage = "录制文件异常,磁盘挂载异常", + ExceptStackTrace = + $"磁盘挂载异常不能实现文件录制功能->{JsonHelper.ToJson(req)}", + }; + return new ResToWebHookOnRecordMP4() + { + Code = 0, + Msg = "success" + }; + } + + finally + { + throw new AkStreamException(rs); + } + } var recordInfo = ORMHelper.Db.Select().Where(x => x.Streamid.Equals(req.Stream) && x.VideoPath.Equals(req.File_Path) && @@ -133,11 +271,23 @@ public static ResToWebHookOnRecordMP4 OnRecordMp4(ReqForWebHookOnRecordMP4 req) int _intLen = (int)Math.Ceiling(_len); //四舍五入后取整 tmpDvrVideo.EndTime = st.AddSeconds(_intLen); tmpDvrVideo.Duration = _intLen; + + if (tmpDvrVideo.Duration <= 0 || req.File_Size > 103881427200) //大概720p下60个小时的录制量,单文件超过这个值,就不再保存 { ResponseStruct rs = null; try { + try + { + AKStreamKeeperService.DeleteFileWithoutCheckDiskUseage(mediaServer.MediaServerId, + tmpDvrVideo.VideoPath, out _); + // mediaServer.KeeperWebApi.DeleteFile(out _, tmpDvrVideo.VideoPath); //从磁盘中删除这个文件 + } + catch + { + } + rs = new ResponseStruct() { Code = ErrorNumber.MediaServer_RecordFileExcept, @@ -809,8 +959,8 @@ public static ResToWebHookOnPublish OnPublish(ReqForWebHookOnPublish req) return new ResToWebHookOnPublish() { Code = -1, - EnableHls = false, - EnableMP4 = false, + Enable_Hls = false, + Enable_Mp4 = false, Msg = "failed", }; } @@ -838,8 +988,8 @@ public static ResToWebHookOnPublish OnPublish(ReqForWebHookOnPublish req) return new ResToWebHookOnPublish() { Code = -1, - EnableHls = false, - EnableMP4 = false, + Enable_Hls = false, + Enable_Mp4 = false, Msg = "failed", }; } @@ -849,8 +999,8 @@ public static ResToWebHookOnPublish OnPublish(ReqForWebHookOnPublish req) return new ResToWebHookOnPublish() { Code = -1, - EnableHls = false, - EnableMP4 = false, + Enable_Hls = false, + Enable_Mp4 = false, Msg = "failed", }; } @@ -896,17 +1046,33 @@ public static ResToWebHookOnPublish OnPublish(ReqForWebHookOnPublish req) ResToWebHookOnPublish result = new ResToWebHookOnPublish(); result.Code = 0; - result.EnableHls = true; result.Msg = "success"; - result.EnableMP4 = false; + result.Enable_Hls = true; + result.Enable_Mp4 = false; + result.Enable_Hls_Fmp4 = true; + result.Enable_Rtsp = true; + result.Enable_Rtmp = true; + result.Enable_Ts = true; + result.Enable_Fmp4 = true; + result.Hls_Demand = true; + result.Rtsp_Demand = false; + result.Rtmp_Demand = false; + result.Ts_Demand = true; + result.Fmp4_Demand = true; + result.Enable_Audio = true; + result.Add_Mute_Audio = true; + result.Mp4_Save_Path = ""; + result.Mp4_As_Player = false; + result.Hls_Save_Path = ""; + result.Auto_Close = false; return result; } return new ResToWebHookOnPublish() { Code = -1, - EnableHls = false, - EnableMP4 = false, + Enable_Hls = false, + Enable_Mp4 = false, Msg = "failed", }; } @@ -1008,6 +1174,7 @@ public static ResMediaServerKeepAlive MediaServerKeepAlive(ReqMediaServerKeepAli return result; } + mediaServer.Candidate = req.Candidate; mediaServer.Secret = req.Secret; mediaServer.IpV4Address = req.IpV4Address; @@ -1034,12 +1201,61 @@ public static ResMediaServerKeepAlive MediaServerKeepAlive(ReqMediaServerKeepAli mediaServer.RecordSec = req.RecordSec; mediaServer.ZlmBuildDateTime = req.ZlmBuildDateTime; mediaServer.AKStreamKeeperVersion = req.Version; + mediaServer.CutMergeFilePath = req.CutMergeFilePath; + mediaServer.DisksUseable.Clear(); + if (req.DisksUseable != null && req.DisksUseable.Count > 0) + { + foreach (var disk in req.DisksUseable) + { + mediaServer.DisksUseable.Add(disk.Key, disk.Value); + } + } + if (req.PerformanceInfo != null) //更新性能信息 { mediaServer.PerformanceInfo = req.PerformanceInfo; } + if (mediaServer.IsInitRtspAuthData == false) + { + #region debug sql output + + if (Common.IsDebug) + { + var sql = ORMHelper.Db.Select() + .Where(x => x.MediaServerId.Equals(mediaServer.MediaServerId)).ToSql(); + + GCommon.Logger.Debug( + $"[{Common.LoggerHead}]->MediaServerKeepAlive->执行SQL:->{sql}"); + } + + #endregion + + var tmp_list_count = ORMHelper.Db.Select() + .Where(x => x.MediaServerId.Equals(mediaServer.MediaServerId)).Count(); + if (tmp_list_count <= 0) + { + UserAuth auth = new UserAuth() + { + MediaServerId = mediaServer.MediaServerId, + Username = "defaultuser", + Password = UtilsHelper.Md5New($"defaultuser:default:defaultpasswd"), + }; + var b = ORMHelper.Db.Insert(auth).ExecuteAffrows(); + // var b = MediaServerService.AddRtspAuthData(auth, out _); + if (b > 0) + { + mediaServer.IsInitRtspAuthData = true; + } + } + else + { + mediaServer.IsInitRtspAuthData = true; + } + } + + result = new ResMediaServerKeepAlive() { Rs = rs, @@ -1077,7 +1293,15 @@ public static ResMediaServerKeepAlive MediaServerKeepAlive(ReqMediaServerKeepAli tmpMediaServer.RecordSec = req.RecordSec; tmpMediaServer.AKStreamKeeperVersion = req.Version; tmpMediaServer.ZlmBuildDateTime = req.ZlmBuildDateTime; - + tmpMediaServer.CutMergeFilePath = req.CutMergeFilePath; + tmpMediaServer.DisksUseable.Clear(); + if (req.DisksUseable != null && req.DisksUseable.Count > 0) + { + foreach (var disk in req.DisksUseable) + { + tmpMediaServer.DisksUseable.Add(disk.Key, disk.Value); + } + } if (req.PerformanceInfo != null) //更新性能信息 { @@ -1091,6 +1315,8 @@ public static ResMediaServerKeepAlive MediaServerKeepAlive(ReqMediaServerKeepAli tmpMediaServer.KeeperWebApi = new KeeperWebApi(tmpMediaServer.IpV4Address, tmpMediaServer.KeeperPort, tmpMediaServer.AccessKey, Common.AkStreamWebConfig.HttpClientTimeoutSec); + + Common.MediaServerList.Add(tmpMediaServer); result = new ResMediaServerKeepAlive() { @@ -1105,6 +1331,7 @@ public static ResMediaServerKeepAlive MediaServerKeepAlive(ReqMediaServerKeepAli } } + return result; } } diff --git a/AKStreamWeb/Startup.cs b/AKStreamWeb/Startup.cs index bd113abc..957bf9e6 100644 --- a/AKStreamWeb/Startup.cs +++ b/AKStreamWeb/Startup.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Net; -using LibCommon; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -86,20 +85,22 @@ public void ConfigureServices(IServiceCollection services) .AllowAnyMethod() ); }); +#if(DEBUG) // 注册Swagger服务 services.AddSwaggerGen(c => { // 添加文档信息 c.SwaggerDoc("v1", new OpenApiInfo { Title = "AKStreamWeb", Version = "v1" }); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "AKStreamWeb.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "AKStreamWeb.xml")); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "LibCommon.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "LibCommon.xml")); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "LibZLMediaKitMediaServer.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "LibZLMediaKitMediaServer.xml")); - if (File.Exists(Path.Combine(GCommon.BaseStartPath, "LibSystemInfo.xml"))) - c.IncludeXmlComments(Path.Combine(GCommon.BaseStartPath, "LibSystemInfo.xml")); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "AKStreamWeb.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AKStreamWeb.xml"), true); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "LibCommon.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LibCommon.xml"), true); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "LibZLMediaKitMediaServer.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LibZLMediaKitMediaServer.xml"), true); + if (File.Exists(Path.Combine(AppContext.BaseDirectory, "LibSystemInfo.xml"))) + c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LibSystemInfo.xml"), true); }); +#endif services.AddSingleton(); services.AddControllersWithViews().AddNewtonsoftJson(options => @@ -132,11 +133,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseHttpsRedirection(); app.UseStaticFiles(); +#if(DEBUG) // 启用Swagger中间件 app.UseSwagger(); // 配置SwaggerUI app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "AKStreamWeb"); }); - +#endif app.UseRouting(); app.UseCors("cors"); diff --git a/Dockerfile-Web b/Dockerfile-Web index fdd0641b..88465fb4 100644 --- a/Dockerfile-Web +++ b/Dockerfile-Web @@ -1,14 +1,21 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -#(author):Զ(auto-chang) -#΢ź(WeChat):Զ(auto-chang) -#ں(WeChat official account)˸Ƽ(IT-chang) -#ʱ(Time)2023422գ(Saturday, April 22, 2023) -#(DescribeΪ(Power Generation for Love) +#作者(author):自动畅(auto-chang) +#微信号(WeChat):自动畅(auto-chang) +#公众号(WeChat official account):畅聊了个科技(IT-chang) +#时间(Time):2023年4月22日,星期六(Saturday, April 22, 2023) +#描述(Describe:为爱发电(Power Generation for Love) FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app -RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN apt-get update && apt-get install -q -y --no-install-recommends \ + procps \ + net-tools \ + && rm -rf /var/lib/apt/lists/* + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + ln -s /sbin/route /usr/sbin/route && \ + ln -s /sbin/ifconfig /usr/sbin/ifconfig EXPOSE 80 EXPOSE 443 @@ -34,4 +41,4 @@ RUN dotnet publish "AKStreamWeb.csproj" -c Release -o /app/publish /p:UseAppHost FROM base AS final WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "AKStreamWeb.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "AKStreamWeb.dll"] diff --git a/LibCommon/Enums/DeleteOrphanDataDir.cs b/LibCommon/Enums/DeleteOrphanDataDir.cs new file mode 100644 index 00000000..dd2ae483 --- /dev/null +++ b/LibCommon/Enums/DeleteOrphanDataDir.cs @@ -0,0 +1,16 @@ +using System; + +namespace LibCommon.Enums; + +public class DeleteOrphanDataDir +{ + /// + /// 清理方向 + /// + [Serializable] + public enum DataDir + { + MySql = 0, + Disk = 1, + } +} \ No newline at end of file diff --git a/LibCommon/Enums/SipChnnelType.cs b/LibCommon/Enums/SipChnnelType.cs index 5e2ae34c..aa2d1e27 100644 --- a/LibCommon/Enums/SipChnnelType.cs +++ b/LibCommon/Enums/SipChnnelType.cs @@ -2,10 +2,10 @@ namespace LibCommon.Enums { - [Serializable] /// /// Sip通道类型 /// + [Serializable] public enum SipChannelType { /// diff --git a/LibCommon/ErrorNumber.cs b/LibCommon/ErrorNumber.cs index a3abe4b0..5460bc26 100644 --- a/LibCommon/ErrorNumber.cs +++ b/LibCommon/ErrorNumber.cs @@ -44,6 +44,7 @@ public enum ErrorNumber : int Sys_DvrCutMergeFileNotFound = -1031, //时间周期内没有找到相关视频文件 Sys_DvrCutProcessQueueLimit = -1032, //处理队列已满,请稍后再试 Sys_AutoResetEventExcept = -1033, //AutoResetEventExcept + Sys_DB_UserAuthAlreadyExists = -1034, //数据库中指定鉴权记录已经存在 Sip_StartExcept = -2000, //启动Sip服务异常 Sip_StopExcept = -2001, //停止Sip服务异常 Sip_Except_DisposeSipDevice = -2002, //Sip网关内部异常(销毁Sip设备时) @@ -169,6 +170,7 @@ public static void Init() ErrorDic[ErrorNumber.MediaServer_ObjectNotExists] = "指定对象不存在"; ErrorDic[ErrorNumber.MediaServer_RecordFileExcept] = "录制文件异常"; ErrorDic[ErrorNumber.MediaServer_DiskExcept] = "磁盘异常"; + ErrorDic[ErrorNumber.Sys_DB_UserAuthAlreadyExists] = "数据库中指定鉴权记录已存在"; ErrorDic[ErrorNumber.Other] = "未知错误"; } } diff --git a/LibCommon/LibCommon.csproj b/LibCommon/LibCommon.csproj index 27d5168a..badfd9bb 100644 --- a/LibCommon/LibCommon.csproj +++ b/LibCommon/LibCommon.csproj @@ -1,24 +1,17 @@ - net6.0 - disable - default - - - - bin/Debug/net5.0/LibCommon.xml - - - - bin/Release/net5.0/LibCommon.xml - + net6.0 + enable + default + True + - + - - + + diff --git a/LibCommon/ProcessHelper.cs b/LibCommon/ProcessHelper.cs index 54f044f6..8c962359 100644 --- a/LibCommon/ProcessHelper.cs +++ b/LibCommon/ProcessHelper.cs @@ -103,6 +103,8 @@ public bool RunProcess(string filePath, string args, int milliseconds, out strin using (Process process = new Process()) { + string errorData = ""; + string outputData = ""; process.StartInfo.FileName = filePath; process.StartInfo.UseShellExecute = false; //不使用shell以免出现操作系统shell出错 process.StartInfo.CreateNoWindow = true; //不显示窗口 @@ -110,7 +112,20 @@ public bool RunProcess(string filePath, string args, int milliseconds, out strin process.StartInfo.RedirectStandardError = true; process.StartInfo.Arguments = escapedArgs; + process.EnableRaisingEvents = true; + process.ErrorDataReceived += (sender, eventArgs) => + { + errorData += eventArgs.Data; + }; + process.OutputDataReceived += (sender, eventArgs) => + { + outputData += eventArgs.Data; + }; + bool result = process.Start(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + if (result) { result = process.WaitForExit(milliseconds); @@ -118,8 +133,12 @@ public bool RunProcess(string filePath, string args, int milliseconds, out strin if (result) { - stdOutput = process.StandardOutput.ReadToEnd(); - stdError = process.StandardError.ReadToEnd()!; + stdOutput = outputData; + stdError = errorData!; + } + else + { + stdError = errorData!; } return result; diff --git a/LibCommon/Structs/DBModels/UserAuth.cs b/LibCommon/Structs/DBModels/UserAuth.cs new file mode 100644 index 00000000..3083ceb8 --- /dev/null +++ b/LibCommon/Structs/DBModels/UserAuth.cs @@ -0,0 +1,43 @@ +using System; +using FreeSql.DataAnnotations; +using Newtonsoft.Json; + +namespace LibCommon.Structs.DBModels; + +/// +/// 用户鉴权表 +/// +[Serializable] +[Table(Name = "UserAuth")] +[Index("idx_uah_msid", "MediaServerId", false)] +[Index("idx_uah_puser", "Username", false)] +/// +/// 用于每周的记录时间 +/// +public class UserAuth +{ + /// + /// 数据库主键 + /// + [Column(IsPrimary = true, IsIdentity = true)] + [JsonIgnore] + public int Id { get; set; } + + /// + /// 流媒体服务器id + /// + public string MediaServerId { get; set; } + + /// + /// projectName + /// 为md5的盐,也是on_rtsp_realm的值 + /// + + public string Username { get; set; } + + /// + /// 密码 MD5(Username:ProjectName:Password) + /// 其中ProjectName为md5的盐,也是on_rtsp_realm的值 + /// + public string Password { get; set; } +} \ No newline at end of file diff --git a/LibCommon/Structs/GB28181/SipDevice.cs b/LibCommon/Structs/GB28181/SipDevice.cs index d3ebde10..78e0ab29 100644 --- a/LibCommon/Structs/GB28181/SipDevice.cs +++ b/LibCommon/Structs/GB28181/SipDevice.cs @@ -32,6 +32,7 @@ public class SipDevice : IDisposable private List _sipChannels = new List(); private SipServerConfig _sipServerConfig; private string? _username; + private double? _keepAliveTimeSpentMS; /// @@ -240,6 +241,15 @@ public bool IsReday set => _isReday = value; } + /// + /// 两次心跳的间隔时间,可以认为是设备的心跳周期(毫秒) + /// + public double? KeepAliveTimeSpentMS + { + get => _keepAliveTimeSpentMS; + set => _keepAliveTimeSpentMS = value; + } + public void Dispose() { if (_keepAliveCheckTimer != null) diff --git a/LibCommon/Structs/GB28181/SipServerConfig.cs b/LibCommon/Structs/GB28181/SipServerConfig.cs index 77fedf48..850108b7 100644 --- a/LibCommon/Structs/GB28181/SipServerConfig.cs +++ b/LibCommon/Structs/GB28181/SipServerConfig.cs @@ -30,7 +30,7 @@ public class SipServerConfig private EncodingType _encodingType; private Encoding _encoding; private bool? _isPassive = true; - + private string? _listenIp = "127.0.0.1"; /// @@ -211,5 +211,14 @@ public Encoding Encoding return _en; } } + + /// + /// 监听ip地址 + /// + public string ListenIp + { + get => _listenIp; + set => _listenIp = value; + } } } \ No newline at end of file diff --git a/LibCommon/Structs/GB28181/Sys/AppState.cs b/LibCommon/Structs/GB28181/Sys/AppState.cs index b14c811c..7fb2af3f 100644 --- a/LibCommon/Structs/GB28181/Sys/AppState.cs +++ b/LibCommon/Structs/GB28181/Sys/AppState.cs @@ -52,7 +52,7 @@ static AppState() // Initialise the string dictionary to hold the application settings. m_appConfigSettings = new StringDictionary(); - CurrentDirectory = Regex.Replace(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase), + CurrentDirectory = Regex.Replace(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"^file:\\", ""); // There's undoubtedly a better way! } catch (Exception excp) @@ -112,7 +112,7 @@ public static string GetConfigSetting(string key) setting = setting.Substring(2); byte[] encryptedBytes = Convert.FromBase64String(setting); RSACryptoServiceProvider rsa = - (RSACryptoServiceProvider)encryptedSettingsCertificate.PrivateKey; + (RSACryptoServiceProvider)encryptedSettingsCertificate.GetRSAPrivateKey(); byte[] plainTextBytes = rsa.Decrypt(encryptedBytes, false); setting = Encoding.ASCII.GetString(plainTextBytes); } diff --git a/LibCommon/Structs/WebRequest/ReqMediaServerKeepAlive.cs b/LibCommon/Structs/WebRequest/ReqMediaServerKeepAlive.cs index 6f2a299e..f82a352d 100644 --- a/LibCommon/Structs/WebRequest/ReqMediaServerKeepAlive.cs +++ b/LibCommon/Structs/WebRequest/ReqMediaServerKeepAlive.cs @@ -36,6 +36,8 @@ public class ReqMediaServerKeepAlive private ushort _zlmRtspsPort; private int? _recordSec; private DateTime? _zlmBuildDateTime; + private Dictionary? _disksUseable; + private string? _cutMergeFilePath; /// @@ -254,5 +256,24 @@ public DateTime? ZlmBuildDateTime get => _zlmBuildDateTime; set => _zlmBuildDateTime = value; } + + + /// + /// 挂载的磁盘是否可用 + /// + public Dictionary? DisksUseable + { + get => _disksUseable; + set => _disksUseable = value; + } + + /// + /// 裁剪合并的文件目录 + /// + public string? CutMergeFilePath + { + get => _cutMergeFilePath; + set => _cutMergeFilePath = value; + } } } \ No newline at end of file diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew.cs index 28c375ee..c4f4f84e 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew.cs @@ -222,6 +222,11 @@ public bool SetConfig(string configPath) data["protocol"]["add_mute_audio"] = Protocol.Add_Mute_Audio.ToString(); } + if (Protocol.Auto_Close != null && UtilsHelper.IsInteger(Protocol.Auto_Close.ToString())) + { + data["protocol"]["auto_close"] = Protocol.Auto_Close.ToString(); + } + if (Protocol.Continue_Push_Ms != null && UtilsHelper.IsInteger(Protocol.Continue_Push_Ms.ToString())) { data["protocol"]["continue_push_ms"] = Protocol.Continue_Push_Ms.ToString(); @@ -232,6 +237,11 @@ public bool SetConfig(string configPath) data["protocol"]["enable_hls"] = Protocol.Enable_Hls.ToString(); } + if (Protocol.Enable_Hls_Fmp4 != null && UtilsHelper.IsInteger(Protocol.Enable_Hls_Fmp4.ToString())) + { + data["protocol"]["enable_hls_fmp4"] = Protocol.Enable_Hls_Fmp4.ToString(); + } + if (Protocol.Enable_Mp4 != null && UtilsHelper.IsInteger(Protocol.Enable_Mp4.ToString())) { data["protocol"]["enable_mp4"] = Protocol.Enable_Mp4.ToString(); @@ -406,9 +416,9 @@ public bool SetConfig(string configPath) if (Hook != null) { - if (!string.IsNullOrEmpty(Hook.Admin_Params)) + if (!string.IsNullOrEmpty(Hook.On_Server_Exited)) { - data["hook"]["admin_params"] = Hook.Admin_Params.Trim(); + data["hook"]["on_server_exited"] = Hook.On_Server_Exited.Trim(); } if (Hook.Enable != null && UtilsHelper.IsInteger(Hook.Enable.ToString())) @@ -604,6 +614,16 @@ public bool SetConfig(string configPath) { data["http"]["forwarded_ip_header"] = Http.Forwarded_Ip_Header.Trim(); } + + if (!string.IsNullOrEmpty(Http.Allow_Cross_Domains)) + { + data["http"]["allow_cross_domains"] = Http.Allow_Cross_Domains.Trim(); + } + + if (!string.IsNullOrEmpty(Http.Allow_Ip_Range)) + { + data["http"]["allow_ip_range"] = Http.Allow_Ip_Range.Trim(); + } } #endregion @@ -662,7 +682,7 @@ public bool SetConfig(string configPath) #endregion - #region MyRegion + #region Rtmp部分 if (Rtmp != null) { @@ -676,11 +696,6 @@ public bool SetConfig(string configPath) data["rtmp"]["keepAliveSecond"] = Rtmp.KeepAliveSecond.ToString(); } - if (Rtmp.ModifyStamp != null && UtilsHelper.IsInteger(Rtmp.ModifyStamp.ToString())) - { - data["rtmp"]["modifyStamp"] = Rtmp.ModifyStamp.ToString(); - } - if (Rtmp.Port != null && UtilsHelper.IsUShort(Rtmp.Port.ToString())) { data["rtmp"]["port"] = Rtmp.Port.ToString(); @@ -717,6 +732,11 @@ public bool SetConfig(string configPath) { data["rtp"]["lowLatency"] = Rtp.LowLatency.ToString(); } + + if (Rtp.H264_Stap_A != null && UtilsHelper.IsInteger(Rtp.H264_Stap_A.ToString())) + { + data["rtp"]["h264_stap_a"] = Rtp.H264_Stap_A.ToString(); + } } #endregion @@ -760,24 +780,14 @@ public bool SetConfig(string configPath) data["rtp_proxy"]["ps_pt"] = Rtp_Proxy.Ps_Pt.Trim(); } - if (!string.IsNullOrEmpty(Rtp_Proxy.Ts_Pt)) - { - data["rtp_proxy"]["ts_pt"] = Rtp_Proxy.Ts_Pt.Trim(); - } - if (!string.IsNullOrEmpty(Rtp_Proxy.Opus_Pt)) { data["rtp_proxy"]["opus_pt"] = Rtp_Proxy.Opus_Pt.Trim(); } - if (!string.IsNullOrEmpty(Rtp_Proxy.G711U_Pt)) + if (Rtp_Proxy.Gop_Cache != null && UtilsHelper.IsUShort(Rtp_Proxy.Gop_Cache.ToString())) { - data["rtp_proxy"]["g711u_pt"] = Rtp_Proxy.G711U_Pt.Trim(); - } - - if (!string.IsNullOrEmpty(Rtp_Proxy.G711A_Pt)) - { - data["rtp_proxy"]["g711a_pt"] = Rtp_Proxy.G711A_Pt.Trim(); + data["rtp_proxy"]["gop_cache"] = Rtp_Proxy.Gop_Cache.ToString(); } } @@ -890,6 +900,11 @@ public bool SetConfig(string configPath) { data["rtsp"]["lowLatency"] = Rtsp.LowLatency.ToString(); } + + if (Rtsp.RtpTransportType != null && UtilsHelper.IsInteger(Rtsp.RtpTransportType.ToString())) + { + data["rtsp"]["rtpTransportType"] = Rtsp.RtpTransportType.ToString(); + } } #endregion @@ -908,7 +923,7 @@ public bool SetConfig(string configPath) #endregion - parser.WriteFile(configPath, data); + parser.WriteFile(configPath, data, Encoding.UTF8); return true; } catch (Exception ex) @@ -1066,6 +1081,13 @@ public ZLMediaKitConfigNew(string configPath) Protocol.Add_Mute_Audio = int.Parse(add_mute_audio); } + var auto_close = data["protocol"]["auto_close"]; + if (auto_close != null && !string.IsNullOrEmpty(auto_close) && + UtilsHelper.IsInteger(auto_close)) + { + Protocol.Auto_Close = int.Parse(auto_close); + } + var continue_push_ms = data["protocol"]["continue_push_ms"]; if (continue_push_ms != null && !string.IsNullOrEmpty(continue_push_ms) && UtilsHelper.IsInteger(continue_push_ms)) @@ -1079,6 +1101,13 @@ public ZLMediaKitConfigNew(string configPath) Protocol.Enable_Hls = int.Parse(enable_hls); } + var enable_hls_fmp4 = data["protocol"]["enable_hls_fmp4"]; + if (enable_hls_fmp4 != null && !string.IsNullOrEmpty(enable_hls_fmp4) && + UtilsHelper.IsInteger(enable_hls_fmp4)) + { + Protocol.Enable_Hls_Fmp4 = int.Parse(enable_hls_fmp4); + } + var enable_mp4 = data["protocol"]["enable_mp4"]; if (enable_mp4 != null && !string.IsNullOrEmpty(enable_mp4) && UtilsHelper.IsInteger(enable_mp4)) { @@ -1242,6 +1271,20 @@ public ZLMediaKitConfigNew(string configPath) General.Unready_Frame_Cache = int.Parse(unready_frame_cache); } + var check_nvidia_dev = data["general"]["check_nvidia_dev"]; + if (check_nvidia_dev != null && !string.IsNullOrEmpty(check_nvidia_dev) && + UtilsHelper.IsInteger(check_nvidia_dev)) + { + General.Check_Nvidia_Dev = int.Parse(check_nvidia_dev); + } + + var enable_ffmpeg_log = data["general"]["enable_ffmpeg_log"]; + if (enable_ffmpeg_log != null && !string.IsNullOrEmpty(enable_ffmpeg_log) && + UtilsHelper.IsInteger(enable_ffmpeg_log)) + { + General.Enable_FFmpeg_Log = int.Parse(enable_ffmpeg_log); + } + #endregion #region hls部分 @@ -1304,10 +1347,10 @@ public ZLMediaKitConfigNew(string configPath) Hook = new ZLMediaKitConfigNew_Hook(); } - var admin_params = data["hook"]["admin_params"]; - if (admin_params != null && !string.IsNullOrEmpty(admin_params)) + var on_server_exited = data["hook"]["on_server_exited"]; + if (on_server_exited != null && !string.IsNullOrEmpty(on_server_exited)) { - Hook.Admin_Params = admin_params.Trim(); + Hook.On_Server_Exited = on_server_exited.Trim(); } var enable = data["hook"]["enable"]; @@ -1546,6 +1589,18 @@ public ZLMediaKitConfigNew(string configPath) Http.Forwarded_Ip_Header = forwarded_ip_header.Trim(); } + var allow_cross_domains = data["http"]["allow_cross_domains"]; + if (allow_cross_domains != null && !string.IsNullOrEmpty(allow_cross_domains)) + { + Http.Allow_Cross_Domains = allow_cross_domains.Trim(); + } + + var allow_ip_range = data["http"]["allow_ip_range"]; + if (allow_ip_range != null && !string.IsNullOrEmpty(allow_ip_range)) + { + Http.Allow_Ip_Range = allow_ip_range.Trim(); + } + #endregion #region multicast 部分 @@ -1636,12 +1691,6 @@ public ZLMediaKitConfigNew(string configPath) Rtmp.KeepAliveSecond = int.Parse(rtmp_keepAliveSecond); } - var modifyStamp = data["rtmp"]["modifyStamp"]; - if (modifyStamp != null && !string.IsNullOrEmpty(modifyStamp) && UtilsHelper.IsInteger(modifyStamp)) - { - Rtmp.ModifyStamp = int.Parse(modifyStamp); - } - var rtmp_port = data["rtmp"]["port"]; if (rtmp_port != null && !string.IsNullOrEmpty(rtmp_port) && UtilsHelper.IsUShort(rtmp_port)) { @@ -1690,6 +1739,12 @@ public ZLMediaKitConfigNew(string configPath) Rtp.LowLatency = int.Parse(lowLatency); } + var h264_stap_a = data["rtp"]["h264_stap_a"]; + if (h264_stap_a != null && !string.IsNullOrEmpty(h264_stap_a) && UtilsHelper.IsInteger(h264_stap_a)) + { + Rtp.H264_Stap_A = int.Parse(h264_stap_a); + } + #endregion #region rtp_proxy 部分 @@ -1743,28 +1798,16 @@ public ZLMediaKitConfigNew(string configPath) Rtp_Proxy.Ps_Pt = ps_pt.Trim(); } - var ts_pt = data["rtp_proxy"]["ts_pt"]; - if (ts_pt != null && !string.IsNullOrEmpty(ts_pt)) - { - Rtp_Proxy.Ts_Pt = ts_pt.Trim(); - } - var opus_pt = data["rtp_proxy"]["opus_pt"]; if (opus_pt != null && !string.IsNullOrEmpty(opus_pt)) { Rtp_Proxy.Opus_Pt = opus_pt.Trim(); } - var g711u_pt = data["rtp_proxy"]["g711u_pt"]; - if (g711u_pt != null && !string.IsNullOrEmpty(g711u_pt)) - { - Rtp_Proxy.G711A_Pt = g711u_pt.Trim(); - } - - var g711a_pt = data["rtp_proxy"]["g711a_pt"]; - if (g711a_pt != null && !string.IsNullOrEmpty(g711a_pt)) + var gop_cache = data["rtp_proxy"]["gop_cache"]; + if (gop_cache != null && !string.IsNullOrEmpty(gop_cache) && UtilsHelper.IsInteger(gop_cache)) { - Rtp_Proxy.G711A_Pt = g711a_pt.Trim(); + Rtp_Proxy.Gop_Cache = int.Parse(gop_cache); } #endregion @@ -1908,6 +1951,13 @@ public ZLMediaKitConfigNew(string configPath) Rtsp.LowLatency = int.Parse(rtsp_lowLatency); } + var rtpTransportType = data["rtsp"]["rtpTransportType"]; + if (rtpTransportType != null && !string.IsNullOrEmpty(rtpTransportType) && + UtilsHelper.IsInteger(rtpTransportType)) + { + Rtsp.RtpTransportType = int.Parse(rtpTransportType); + } + #endregion #region shell部分 diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_General.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_General.cs index 0bfa3175..3d757c18 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_General.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_General.cs @@ -15,6 +15,9 @@ public class ZLMediaKitConfigNew_General private int? _wait_track_ready_ms; private int? _wait_add_track_ms; private int? _unready_frame_cache; + private int? _check_nvidia_dev; + private int? _enable_ffmpeg_log; + /// /// 是否启用虚拟主机 @@ -114,4 +117,22 @@ public int? Unready_Frame_Cache get => _unready_frame_cache; set => _unready_frame_cache = value; } + + /// + /// 是否检测nvidia设备 + /// + public int? Check_Nvidia_Dev + { + get => _check_nvidia_dev; + set => _check_nvidia_dev = value; + } + + /// + /// 是否开启ffmpeg日志 + /// + public int? Enable_FFmpeg_Log + { + get => _enable_ffmpeg_log; + set => _enable_ffmpeg_log = value; + } } \ No newline at end of file diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_HLS.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_HLS.cs index 00dc8c56..96b25a24 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_HLS.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_HLS.cs @@ -13,6 +13,7 @@ public class ZLMediaKitConfigNew_HLS private int? _deleteDelaySec; private int? _segKeep; + /// /// hls写文件的buf大小,调整参数可以提高文件io性能 /// diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Hook.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Hook.cs index 412f5a70..25f95ef0 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Hook.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Hook.cs @@ -5,7 +5,7 @@ namespace LibCommon.Structs.ZLMediaKitConfig; [Serializable] public class ZLMediaKitConfigNew_Hook { - private string? _admin_params; + private float? _alive_interval; private int? _enable; private string? _on_flow_report; private string? _on_http_access; @@ -13,30 +13,21 @@ public class ZLMediaKitConfigNew_Hook private string? _on_publish; private string? _on_record_mp4; private string? _on_record_ts; + private string? _on_rtp_server_timeout; private string? _on_rtsp_auth; private string? _on_rtsp_realm; + private string? _on_send_rtp_stopped; + private string? _on_server_exited; + private string? _on_server_keepalive; + private string? _on_server_started; private string? _on_shell_login; private string? _on_stream_changed; private string? _on_stream_none_reader; private string? _on_stream_not_found; - private string? _on_server_started; - private string? _on_server_keepalive; - private string? _on_send_rtp_stopped; - private string? _on_rtp_server_timeout; - private int? _timeoutSec; - private float? _alive_interval; private int? _retry; private float? _retry_delay; + private int? _timeoutSec; - /// - /// #在推流时,如果url参数匹对admin_params,那么可以不经过hook鉴权直接推流成功,播放时亦然 - /// 该配置项的目的是为了开发者自己调试测试,该参数暴露后会有泄露隐私的安全隐患 - /// - public string Admin_Params - { - get => _admin_params; - set => _admin_params = value; - } /// /// 是否启用hook事件,启用后,推拉流都将进行鉴权 @@ -184,6 +175,16 @@ public string On_Send_Rtp_Stopped set => _on_send_rtp_stopped = value; } + /// + /// 服务器退出报告,当服务器正常退出时触发 + /// + public string? On_Server_Exited + { + get => _on_server_exited; + set => _on_server_exited = value; + } + + /// /// rtp server 超时未收到数据 /// diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Http.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Http.cs index 45798f36..96834450 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Http.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Http.cs @@ -5,7 +5,12 @@ namespace LibCommon.Structs.ZLMediaKitConfig; [Serializable] public class ZLMediaKitConfigNew_Http { + private string? _allow_cross_domains; + private string? _allow_ip_range; private string? _charSet; + private int? _dirMenu; + private string? _forbidCacheSuffix; + private string? _forwarded_ip_header; private int? _keepAliveSecond; private int? _maxReqSize; private string? _notFound; @@ -13,10 +18,8 @@ public class ZLMediaKitConfigNew_Http private string? _rootPath; private int? _sendBufSize; private ushort? _sslport; - private int? _dirMenu; private string? _virtualPath; - private string? _forbidCacheSuffix; - private string? _forwarded_ip_header; + /// /// http服务器字符编码,windows上默认gb2312 @@ -133,4 +136,22 @@ public string Forwarded_Ip_Header get => _forwarded_ip_header; set => _forwarded_ip_header = value; } + + /// + /// 默认允许所有跨域请求 + /// + public string? Allow_Cross_Domains + { + get => _allow_cross_domains; + set => _allow_cross_domains = value; + } + + /// + /// 允许访问http api和http文件索引的ip地址范围白名单,置空情况下不做限制 + /// + public string? Allow_Ip_Range + { + get => _allow_ip_range; + set => _allow_ip_range = value; + } } \ No newline at end of file diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Protocol.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Protocol.cs index 93d85bb8..126c17b4 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Protocol.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Protocol.cs @@ -8,25 +8,27 @@ namespace LibCommon.Structs.ZLMediaKitConfig; [Serializable] public class ZLMediaKitConfigNew_Protocol { - private int? _modify_stamp; - private int? _enable_audio; private int? _add_mute_audio; + private int? _auto_close; private int? _continue_push_ms; + private int? _enable_audio; + private int? _enable_fmp4; private int? _enable_hls; + private int? _enable_hls_fmp4; private int? _enable_mp4; - private int? _enable_rtsp; private int? _enable_rtmp; + private int? _enable_rtsp; private int? _enable_ts; - private int? _enable_fmp4; + private int? _fmp4_demand; + private int? _hls_demand; + private string? _hls_save_path; + private int? _modify_stamp; private int? _mp4_as_player; private int? _mp4_max_second; private string? _mp4_save_path; - private string? _hls_save_path; - private int? _hls_demand; - private int? _rtsp_demand; private int? _rtmp_demand; + private int? _rtsp_demand; private int? _ts_demand; - private int? _fmp4_demand; /// /// 转协议时,是否开启帧级时间戳覆盖 @@ -55,6 +57,19 @@ public int? Add_Mute_Audio set => _add_mute_audio = value; } + /// + /// 无人观看时,是否直接关闭(而不是通过on_none_reader hook返回close) + /// 此配置置1时,此流如果无人观看,将不触发on_none_reader hook回调, + /// 而是将直接关闭流 + /// + /// + public int? Auto_Close + { + get => _auto_close; + set => _auto_close = value; + } + + /// /// 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 /// 置0关闭此特性(推流断开会导致立即断开播放器) @@ -75,6 +90,16 @@ public int? Enable_Hls set => _enable_hls = value; } + /// + /// 是否开启转换为hls(fmp4) + /// + /// + public int? Enable_Hls_Fmp4 + { + get => _enable_hls_fmp4; + set => _enable_hls_fmp4 = value; + } + /// /// 是否开启MP4录制 /// @@ -156,11 +181,11 @@ public string Hls_Save_Path set => _hls_save_path = value; } -/* -以下是按需转协议的开关,在测试ZLMediaKit的接收推流性能时,请把下面开关置1 -如果某种协议你用不到,你可以把以下开关置1以便节省资源(但是还是可以播放,只是第一个播放者体验稍微差点), - 如果某种协议你想获取最好的用户体验,请置0(第一个播放者可以秒开,且不花屏) -*/ + /* + 以下是按需转协议的开关,在测试ZLMediaKit的接收推流性能时,请把下面开关置1 + 如果某种协议你用不到,你可以把以下开关置1以便节省资源(但是还是可以播放,只是第一个播放者体验稍微差点), + 如果某种协议你想获取最好的用户体验,请置0(第一个播放者可以秒开,且不花屏) + */ /// /// hls协议是否按需生成,如果hls.segNum配置为0(意味着hls录制),那么hls将一直生成(不管此开关) diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTC.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTC.cs index 430d1112..0dc7db56 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTC.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTC.cs @@ -5,13 +5,13 @@ namespace LibCommon.Structs.ZLMediaKitConfig; [Serializable] public class ZLMediaKitConfigNew_RTC { - private int? _timeoutSec; private string? _externIP; private ushort? _port; - private ushort? _tcpPort; - private int? _rembBitRate; private string? _preferredCodecA; private string? _preferredCodecV; + private int? _rembBitRate; + private ushort? _tcpPort; + private int? _timeoutSec; /// /// rtc播放推流、播放超时时间 diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTMP.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTMP.cs index fb2a5f58..72f389a5 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTMP.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTMP.cs @@ -7,7 +7,6 @@ public class ZLMediaKitConfigNew_RTMP { private int? _handshakeSecond; private int? _keepAliveSecond; - private int? _modifyStamp; private ushort? _port; private ushort? _sslport; @@ -30,15 +29,6 @@ public int? KeepAliveSecond set => _keepAliveSecond = value; } - /// - /// 在接收rtmp推流时,是否重新生成时间戳(很多推流器的时间戳着实很烂) - /// - public int? ModifyStamp - { - get => _modifyStamp; - set => _modifyStamp = value; - } - /// /// rtmp服务器监听端口 /// diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTP.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTP.cs index 02d88035..1833c5d3 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTP.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTP.cs @@ -6,9 +6,11 @@ namespace LibCommon.Structs.ZLMediaKitConfig; public class ZLMediaKitConfigNew_RTP { private int? _audioMtuSize; - private int? _videoMtuSize; - private int? _rtpMaxSize; + private int? _h264_stap_a; private int? _lowLatency; + private int? _rtpMaxSize; + private int? _videoMtuSize; + /// /// 音频mtu大小,该参数限制rtp最大字节数,推荐不要超过1400 @@ -46,4 +48,15 @@ public int? LowLatency get => _lowLatency; set => _lowLatency = value; } + + /// + /// H264 rtp打包模式是否采用stap-a模式(为了在老版本浏览器上兼容webrtc)还是采用Single NAL unit packet per H.264 模式 + /// 有些老的rtsp设备不支持stap-a rtp,设置此配置为0可提高兼容性 + /// + /// + public int? H264_Stap_A + { + get => _h264_stap_a; + set => _h264_stap_a = value; + } } \ No newline at end of file diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTSP.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTSP.cs index d341ddb8..f62a2d40 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTSP.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_RTSP.cs @@ -9,9 +9,11 @@ public class ZLMediaKitConfigNew_RTSP private int? _directProxy; private int? _handshakeSecond; private int? _keepAliveSecond; + private int? _lowLatency; private ushort? _port; + private int? _rtpTransportType; private ushort? _sslport; - private int? _lowLatency; + /// /// rtsp专有鉴权方式是采用base64还是md5方式 @@ -82,4 +84,16 @@ public int? LowLatency get => _lowLatency; set => _lowLatency = value; } + + /// + /// 强制协商rtp传输方式 (0:TCP,1:UDP,2:MULTICAST,-1:不限制) + /// 当客户端发起RTSP SETUP的时候如果传输类型和此配置不一致则返回461 Unsupported transport + /// 迫使客户端重新SETUP并切换到对应协议。目前支持FFMPEG和VLC + /// + /// + public int? RtpTransportType + { + get => _rtpTransportType; + set => _rtpTransportType = value; + } } \ No newline at end of file diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Record.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Record.cs index 908df1f4..d37b40b2 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Record.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Record.cs @@ -6,10 +6,10 @@ namespace LibCommon.Structs.ZLMediaKitConfig; public class ZLMediaKitConfigNew_Record { private string? _appName; - private int? _fileBufSize; - private int? _sampleMS; private int? _fastStart; + private int? _fileBufSize; private int? _fileRepeat; + private int? _sampleMS; /// /// mp4录制或mp4点播的应用名,通过限制应用名,可以防止随意点播 diff --git a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Rtp_Proxy.cs b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Rtp_Proxy.cs index 0949b42c..93d28f2f 100644 --- a/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Rtp_Proxy.cs +++ b/LibCommon/Structs/ZLMediaKitConfig/ZLMediaKitConfigNew_Rtp_Proxy.cs @@ -6,16 +6,15 @@ namespace LibCommon.Structs.ZLMediaKitConfig; public class ZLMediaKitConfigNew_Rtp_Proxy { private string? _dumpDir; - private ushort? _port; - private int? _timeoutSec; - private string? _port_range; + private int? _gop_cache; private string? _h264_pt; private string? _h265_pt; - private string? _ps_pt; - private string? _ts_pt; private string? _opus_pt; - private string? _g711u_pt; - private string? _g711a_pt; + private ushort? _port; + private string? _port_range; + private string? _ps_pt; + private int? _timeoutSec; + /// /// 导出调试数据(包括rtp/ps/h264)至该目录,置空则关闭数据导出 @@ -81,15 +80,6 @@ public string Ps_Pt set => _ps_pt = value; } - /// - /// rtp ts 负载的pt - /// - public string Ts_Pt - { - get => _ts_pt; - set => _ts_pt = value; - } - /// /// rtp opus 负载的pt /// @@ -99,21 +89,12 @@ public string Opus_Pt set => _opus_pt = value; } - /// - /// rtp g711u 负载的pt - /// - public string G711U_Pt - { - get => _g711u_pt; - set => _g711u_pt = value; - } - /// /// rtp g711a 负载的pt /// - public string G711A_Pt + public int? Gop_Cache { - get => _g711a_pt; - set => _g711a_pt = value; + get => _gop_cache; + set => _gop_cache = value; } } \ No newline at end of file diff --git a/LibCommon/UtilsHelper.cs b/LibCommon/UtilsHelper.cs index 089d1cb6..9c88bd10 100644 --- a/LibCommon/UtilsHelper.cs +++ b/LibCommon/UtilsHelper.cs @@ -6,6 +6,7 @@ using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -21,6 +22,226 @@ namespace LibCommon /// public static class UtilsHelper { + /// + /// 查找优先使用的config文件 + /// Config文件名同名,但后缀包含.local的将被优先使用 + /// 比如:AKStreamKeeperConfig.json这个配置文件,如果在同目录下发现有AKStreamKeeperConfig.json.local文件 + /// 将被优先使用 + /// 不存在.lcaol文件,将使用本文件,如上述例子将使用AKStreamKeeperConfig.json文件 + /// + /// + /// + public static string FindPreferredConfigFile(string configPath) + { + var path = Path.GetDirectoryName(configPath); + var fileName = Path.GetFileName(configPath); + var isWindows = false; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + path = path.Trim().TrimEnd('\\'); + isWindows = true; + } + else + { + path = path.Trim().TrimEnd('/'); + } + + if (Directory.Exists(path) && File.Exists(configPath)) + { + if (isWindows) + { + if (File.Exists($"{path}\\{fileName}.local")) + { + return $"{path}\\{fileName}.local"; + } + } + else + { + if (File.Exists($"{path}/{fileName}.local")) + { + return $"{path}/{fileName}.local"; + } + } + } + + return configPath; + } + + /// + /// 移除bom头 + /// + /// + /// + public static bool WithOutBomHeader(string filePath) + { + string config = File.ReadAllText(filePath); + var utf8WithoutBom = new UTF8Encoding(false); //使用构造函数布尔参数指定是否含BOM头,示例false为不含。 + using (var sink = new StreamWriter(filePath, false, utf8WithoutBom)) + { + sink.WriteLine(config); + return true; + } + } + + /// + /// 是否有bom头 + /// + /// + /// + public static bool IsBomHeader(byte[] bs) + { + int len = bs.Length; + if (len >= 3 && bs[0] == 0xEF && bs[1] == 0xBB && bs[2] == 0xBF) + { + return true; + } + + return false; + } + + + /// + /// 目录是否为外部挂载,并且可写状态 + /// + /// + /// + /// 0:挂载并可写 + /// -1:未挂载 + /// -2:挂载但不可写 + /// + public static int DirAreMounttedAndWriteableForLinux(string dir) + { + #region 获取挂载列表 + + ProcessHelper ps = new ProcessHelper(); + List> dirDevList = new List>(); + string std; + string err; + try + { + var cmd = " -h " + dir; + ps.RunProcess("/bin/df", cmd, 1000, out std, out err); + if (!string.IsNullOrEmpty(std)) + { + string[] tmpStrArr = std.Split('\n', StringSplitOptions.RemoveEmptyEntries); + if (tmpStrArr != null && tmpStrArr.Length > 0) + { + foreach (var str in tmpStrArr) + { + if (str.ToLower().Trim().Contains("filesystem") || str.ToLower().Trim().Contains("size") || + str.ToLower().Trim().Contains("mount")) + { + continue; + } + + if (str.Trim().ToLower().StartsWith("df:")) //如果报错,则说明没挂载 + { + return -1; + } + + string driverName = ""; + string rootPath = ""; + if (str.Trim().ToLower().StartsWith("/dev/sd")) + { + var tmpStrArr2 = str.Split(" ", StringSplitOptions.RemoveEmptyEntries); + if (tmpStrArr2 != null && tmpStrArr2.Length >= 6) + { + driverName = tmpStrArr2[0]; + rootPath = tmpStrArr2[5]; + } + + if (string.IsNullOrEmpty(rootPath) || string.IsNullOrEmpty(driverName)) + { + return -1; + } + + try + { + File.WriteAllText(dir.TrimEnd('/') + "/check.txt", "ok"); + var tmp = File.ReadAllText(dir.TrimEnd('/') + "/check.txt"); + if (tmp.Trim().Equals("ok")) + { + File.Delete(dir.TrimEnd('/') + "/check.txt"); + return 0; + } + } + catch + { + return -2; + } + + return 0; + } + } + } + } + + if (!string.IsNullOrEmpty(err)) + { + string[] tmpStrArr = err.Split('\n', StringSplitOptions.RemoveEmptyEntries); + if (tmpStrArr != null && tmpStrArr.Length > 0) + { + foreach (var str in tmpStrArr) + { + if (str.ToLower().Trim().Contains("filesystem") || str.ToLower().Trim().Contains("size") || + str.ToLower().Trim().Contains("mount")) + { + continue; + } + + if (str.Trim().ToLower().StartsWith("df:")) //如果报错,则说明没挂载 + { + return -1; + } + + string driverName = ""; + string rootPath = ""; + if (str.Trim().ToLower().StartsWith("/dev/sd")) + { + var tmpStrArr2 = str.Split(" ", StringSplitOptions.RemoveEmptyEntries); + if (tmpStrArr2 != null && tmpStrArr2.Length >= 6) + { + driverName = tmpStrArr2[0]; + rootPath = tmpStrArr2[5]; + } + + if (string.IsNullOrEmpty(rootPath) || string.IsNullOrEmpty(driverName)) + { + return -1; + } + + try + { + File.WriteAllText(dir.TrimEnd('/') + "/check.txt", "ok"); + var tmp = File.ReadAllText(dir.TrimEnd('/') + "/check.txt"); + if (tmp.Trim().Equals("ok")) + { + File.Delete(dir.TrimEnd('/') + "/check.txt"); + return 0; + } + } + catch + { + return -2; + } + + return 0; + } + } + } + } + } + catch (Exception ex) + { + throw ex; + } + + #endregion + + return -1; + } + + /// /// 是否为ushort类型 /// @@ -344,8 +565,7 @@ public static string Md5WithFile(string fileName) try { FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read); - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] retVal = md5.ComputeHash(file); + byte[] retVal = MD5.Create().ComputeHash(file); file.Close(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < retVal.Length; i++) @@ -361,6 +581,26 @@ public static string Md5WithFile(string fileName) } } + /// + /// 获取MD5加密码值,用于和zlm交互 + /// + /// + /// + public static string Md5New(string source) + + { + string rule = ""; + MD5 md5 = MD5.Create(); + byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(source)); + // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得 + for (int i = 0; i < s.Length; i++) + { + rule = rule + s[i].ToString("x2"); // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 + } + + return rule; + } + /// /// 获取MD5加密码值 /// @@ -370,11 +610,9 @@ public static string Md5(string str) { try { - MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); byte[] bytValue, bytHash; bytValue = Encoding.UTF8.GetBytes(str); - bytHash = md5.ComputeHash(bytValue); - md5.Clear(); + bytHash = MD5.Create().ComputeHash(bytValue); string sTemp = ""; for (int i = 0; i < bytHash.Length; i++) { diff --git a/LibGB28181SipClient/Common.cs b/LibGB28181SipClient/Common.cs index 8de4b875..cd92ad30 100644 --- a/LibGB28181SipClient/Common.cs +++ b/LibGB28181SipClient/Common.cs @@ -92,15 +92,15 @@ private static SipClientConfig InitSipClientConfig(out ResponseStruct rs) sipClientConfig.SipDeviceId = "33020000021190000002"; sipClientConfig.SipServerDeviceId = "33020000021180000001"; /*SipDeviceID 20位编码规则 - *1-2省级 33 浙江省 - *3-4市级 02 宁波市 - *5-6区级 00 宁波市区 - *7-8村级 00 宁波市区 - *9-10行业 02 社会治安内部接入 - *11-13设备类型 118 NVR - *14 网络类型 0 监控专用网 - *15-20 设备序号 000001 1号设备 - */ + *1-2省级 33 浙江省 + *3-4市级 02 宁波市 + *5-6区级 00 宁波市区 + *7-8村级 00 宁波市区 + *9-10行业 02 社会治安内部接入 + *11-13设备类型 118 NVR + *14 网络类型 0 监控专用网 + *15-20 设备序号 000001 1号设备 + */ sipClientConfig.Realm = sipClientConfig.SipDeviceId.Substring(0, 10); sipClientConfig.LocalPort = 5061; sipClientConfig.SipPassword = "123#@!qwe"; diff --git a/LibGB28181SipClient/SipClient.cs b/LibGB28181SipClient/SipClient.cs index 7b608a3a..4c84f186 100644 --- a/LibGB28181SipClient/SipClient.cs +++ b/LibGB28181SipClient/SipClient.cs @@ -1004,6 +1004,7 @@ public SipClient(string outConfigPath = "") Common.SipClientConfigPath = outConfigPath + "SipClientConfig.json"; } + Common.SipClientConfigPath = UtilsHelper.FindPreferredConfigFile(Common.SipClientConfigPath); //查找优先使用的配置文件 var ret = Common.ReadSipClientConfig(out rs); if (ret < 0 || !rs.Code.Equals(ErrorNumber.None)) { diff --git a/LibGB28181SipServer/Common.cs b/LibGB28181SipServer/Common.cs index f0e5e23b..e31dbb74 100644 --- a/LibGB28181SipServer/Common.cs +++ b/LibGB28181SipServer/Common.cs @@ -162,15 +162,15 @@ private static SipServerConfig InitSipServerConfig(out ResponseStruct rs) sipServerConfig.KeepAliveInterval = 5; sipServerConfig.KeepAliveLostNumber = 3; /*SipDeviceID 20位编码规则 - *1-2省级 33 浙江省 - *3-4市级 02 宁波市 - *5-6区级 00 宁波市区 - *7-8村级 00 宁波市区 - *9-10行业 02 社会治安内部接入 - *11-13设备类型 118 NVR - *14 网络类型 0 监控专用网 - *15-20 设备序号 000001 1号设备 - */ + *1-2省级 33 浙江省 + *3-4市级 02 宁波市 + *5-6区级 00 宁波市区 + *7-8村级 00 宁波市区 + *9-10行业 02 社会治安内部接入 + *11-13设备类型 118 NVR + *14 网络类型 0 监控专用网 + *15-20 设备序号 000001 1号设备 + */ sipServerConfig.ServerSipDeviceId = "33020000021180000001"; if (sipServerConfig.NoAuthenticationRequireds == null) { diff --git a/LibGB28181SipServer/SipMsgProcess.cs b/LibGB28181SipServer/SipMsgProcess.cs index 56d4177c..6d0fc805 100644 --- a/LibGB28181SipServer/SipMsgProcess.cs +++ b/LibGB28181SipServer/SipMsgProcess.cs @@ -357,6 +357,12 @@ private static async Task MessageProcess(SIPChannel localSipChannel, SIPEndPoint OnKeepaliveReceived?.Invoke(sipDeviceId, time, tmpSipDevice.KeepAliveLostTime); }); //抛线程出去处理 + if (tmpSipDevice.KeepAliveTime != null) //获取设备的实际心跳周期 + { + tmpSipDevice.KeepAliveTimeSpentMS = + (time - tmpSipDevice.KeepAliveTime).TotalMilliseconds; + } + tmpSipDevice.KeepAliveTime = time; if (tmpSipDevice.RemoteEndPoint != null && tmpSipDevice.RemoteEndPoint != remoteEndPoint && @@ -667,6 +673,7 @@ private static async Task RegisterProcess(SIPChannel localSipChannel, SIPEndPoin unAuthorizedResponse.Header.Allow = null; unAuthorizedResponse.Header.Expires = 7200; + await Common.SipServer.SipTransport.SendResponseAsync(unAuthorizedResponse); return; } diff --git a/LibGB28181SipServer/SipServer.cs b/LibGB28181SipServer/SipServer.cs index 4f848711..975ee1da 100644 --- a/LibGB28181SipServer/SipServer.cs +++ b/LibGB28181SipServer/SipServer.cs @@ -54,6 +54,8 @@ public SipServer(string outConfigPath = "") Common.SipServerConfigPath = outConfigPath + "SipServerConfig.json"; } + Common.SipServerConfigPath = UtilsHelper.FindPreferredConfigFile(Common.SipServerConfigPath); //查找优先使用的配置文件 + var ret = Common.ReadSipServerConfig(out rs); if (ret < 0 || !rs.Code.Equals(ErrorNumber.None)) @@ -489,16 +491,19 @@ private string MediaSdpCreate(RecordInfo.RecItem record, PushMediaInfo pushMedia media.MediaFormats.Add(psFormat); media.MediaFormats.Add(h264Format); media.AddExtra("a=recvonly"); - if (Common.SipServerConfig.IsPassive != null && Common.SipServerConfig.IsPassive == false) - { - media.AddExtra("a=setup:active"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 - } - else - { - media.AddExtra("a=setup:passive"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 - } + + if (pushMediaInfo.PushStreamSocketType == PushStreamSocketType.TCP) { + if (Common.SipServerConfig.IsPassive != null && Common.SipServerConfig.IsPassive == false) + { + media.AddExtra("a=setup:active"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 + } + else + { + media.AddExtra("a=setup:passive"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 + } + media.Transport = "TCP/RTP/AVP"; media.AddExtra("a=connection:new"); } @@ -554,16 +559,17 @@ private string MediaSdpCreate(SipChannel sipChannel, PushMediaInfo pushMediaInfo media.MediaFormats.Add(h264Format); media.AddExtra("a=recvonly"); - if (Common.SipServerConfig.IsPassive != null && Common.SipServerConfig.IsPassive == false) - { - media.AddExtra("a=setup:active"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 - } - else - { - media.AddExtra("a=setup:passive"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 - } if (pushMediaInfo.PushStreamSocketType == PushStreamSocketType.TCP) { + if (Common.SipServerConfig.IsPassive != null && Common.SipServerConfig.IsPassive == false) + { + media.AddExtra("a=setup:active"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 + } + else + { + media.AddExtra("a=setup:passive"); //active:主动模式,由摄像头告知服务器监听哪个端口,passive:被动模式,服务器告知摄像头连接端口 + } + media.Transport = "TCP/RTP/AVP"; media.AddExtra("a=connection:new"); } @@ -1878,13 +1884,32 @@ public void Start(out ResponseStruct rs) // _sipTransport = new SIPTransport(); // 创建ipv4 udp传输层 - _sipUdpIpV4Channel = new SIPUDPChannel(new IPEndPoint(IPAddress.Any, - Common.SipServerConfig.SipPort)); + if (string.IsNullOrEmpty(Common.SipServerConfig.ListenIp)) + { + _sipUdpIpV4Channel = new SIPUDPChannel(new IPEndPoint(IPAddress.Any, + Common.SipServerConfig.SipPort)); + } + else + { + _sipUdpIpV4Channel = new SIPUDPChannel(new IPEndPoint( + IPAddress.Parse(Common.SipServerConfig.ListenIp.Trim()), + Common.SipServerConfig.SipPort)); + } if (Common.SipServerConfig.MsgProtocol.Trim().ToUpper().Equals("TCP")) { - _sipTcpIpV4Channel = new SIPTCPChannel(new IPEndPoint(IPAddress.Any, - Common.SipServerConfig.SipPort)); + if (string.IsNullOrEmpty(Common.SipServerConfig.ListenIp)) + { + _sipTcpIpV4Channel = new SIPTCPChannel(new IPEndPoint(IPAddress.Any, + Common.SipServerConfig.SipPort)); + } + else + { + _sipTcpIpV4Channel = new SIPTCPChannel(new IPEndPoint( + IPAddress.Parse(Common.SipServerConfig.ListenIp.Trim()), + Common.SipServerConfig.SipPort)); + } + _sipTransport.AddSIPChannel(_sipTcpIpV4Channel); GCommon.Logger.Info( $"[{Common.LoggerHead}]->监听端口成功,监听情况->{_sipTcpIpV4Channel.ListeningEndPoint.Address}:{_sipTcpIpV4Channel.ListeningEndPoint.Port}(TCP via IPV4)"); diff --git a/LibSystemInfo/LibSystemInfo.csproj b/LibSystemInfo/LibSystemInfo.csproj index bda24e1f..d1e550bd 100644 --- a/LibSystemInfo/LibSystemInfo.csproj +++ b/LibSystemInfo/LibSystemInfo.csproj @@ -1,26 +1,19 @@ - + - net6.0 - disable - default - + net6.0 + disable + default + True + - - bin/Debug/net5.0/LibSystemInfo.xml - - - - bin/Release/net5.0/LibSystemInfo.xml - - - + - + diff --git a/LibZLMediaKitMediaServer/KeeperWebApi.cs b/LibZLMediaKitMediaServer/KeeperWebApi.cs index 1dd057c2..88beef3a 100644 --- a/LibZLMediaKitMediaServer/KeeperWebApi.cs +++ b/LibZLMediaKitMediaServer/KeeperWebApi.cs @@ -4,7 +4,6 @@ using LibCommon; using LibCommon.Structs.WebRequest.AKStreamKeeper; using LibCommon.Structs.WebResponse.AKStreamKeeper; -using Org.BouncyCastle.Bcpg.OpenPgp; namespace LibZLMediaKitMediaServer { diff --git a/LibZLMediaKitMediaServer/LibZLMediaKitMediaServer.csproj b/LibZLMediaKitMediaServer/LibZLMediaKitMediaServer.csproj index 1d67883c..512fbc93 100644 --- a/LibZLMediaKitMediaServer/LibZLMediaKitMediaServer.csproj +++ b/LibZLMediaKitMediaServer/LibZLMediaKitMediaServer.csproj @@ -1,17 +1,10 @@ - net6.0 - LibMediaServer - default - - - - bin\Debug\LibMediaServer.xml - - - - bin\Release\LibMediaServer.xml + net6.0 + LibMediaServer + default + True diff --git a/LibZLMediaKitMediaServer/ServerInstance.cs b/LibZLMediaKitMediaServer/ServerInstance.cs index 674004aa..24d57394 100644 --- a/LibZLMediaKitMediaServer/ServerInstance.cs +++ b/LibZLMediaKitMediaServer/ServerInstance.cs @@ -54,6 +54,9 @@ public class ServerInstance : IDisposable private int? _recordSec; private DateTime? _zlmBuildDateTime; private string? _akstreamKeeperVersion; + private Dictionary? _disksUseable = new Dictionary(); + private bool? _isInitRtspAuthData = false; + private string? _cutMergeFilePath; public ServerInstance() @@ -302,6 +305,34 @@ public DateTime? ZlmBuildDateTime set => _zlmBuildDateTime = value; } + /// + /// 挂载硬盘是否可用 + /// + public Dictionary DisksUseable + { + get => _disksUseable; + set => _disksUseable = value; + } + + /// + /// 初始化过rtspAuth数据 + /// + public bool? IsInitRtspAuthData + { + get => _isInitRtspAuthData; + set => _isInitRtspAuthData = value; + } + + /// + /// 裁剪合并文件目录地址 + /// + public string CutMergeFilePath + { + get => _cutMergeFilePath; + set => _cutMergeFilePath = value; + } + + public void Dispose() { if (_keepAliveCheckTimer != null) diff --git a/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnRtspAuth.cs b/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnRtspAuth.cs new file mode 100644 index 00000000..d24a4ed4 --- /dev/null +++ b/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnRtspAuth.cs @@ -0,0 +1,128 @@ +using System; + +namespace LibZLMediaKitMediaServer.Structs.WebHookRequest; + +[Serializable] +public class ReqForWebHookOnRtspAuth +{ + private string? _mediaServerId; + private string? _app; + private string? _id; + private string? _ip; + private string? _must_no_encrypt; + private string? _params; + private ushort? _port; + private string? _realm; + private string? _schema; + private string? _stream; + private string? _user_name; + private string? _vhost; + + /// + /// 流媒体服务器id + /// + public string MediaServerId + { + get => _mediaServerId; + set => _mediaServerId = value; + } + + /// + /// app + /// + public string App + { + get => _app; + set => _app = value; + } + + /// + /// TCP链接唯一ID + /// + public string Id + { + get => _id; + set => _id = value; + } + + /// + /// rtsp播放器ip + /// + public string Ip + { + get => _ip; + set => _ip = value; + } + + /// + /// 请求的密码是否必须为明文(base64鉴权需要明文密码) + /// + public string Must_No_Encrypt + { + get => _must_no_encrypt; + set => _must_no_encrypt = value; + } + + /// + /// rtsp url参数 + /// + public string Params + { + get => _params; + set => _params = value; + } + + /// + /// 端口 + /// + public ushort? Port + { + get => _port; + set => _port = value; + } + + /// + /// rtsp播放鉴权加密realm + /// + public string Realm + { + get => _realm; + set => _realm = value; + } + + /// + /// rtsp或rtsps + /// + public string Schema + { + get => _schema; + set => _schema = value; + } + + /// + /// streamid + /// + public string Stream + { + get => _stream; + set => _stream = value; + } + + /// + /// 用户名 + /// + public string User_Name + { + get => _user_name; + set => _user_name = value; + } + + /// + /// vhost + /// + public string Vhost + { + get => _vhost; + set => _vhost = value; + } +} \ No newline at end of file diff --git a/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnRtspRealm.cs b/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnRtspRealm.cs new file mode 100644 index 00000000..8dfa038c --- /dev/null +++ b/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnRtspRealm.cs @@ -0,0 +1,85 @@ +namespace LibZLMediaKitMediaServer.Structs.WebHookRequest; + +public class ReqForWebHookOnRtspRealm +{ + private string? _mediaServerId; + private string? _app; + private string? _id; + private string? _params; + private ushort? _port; + private string? _schema; + private string? _stream; + private string? _vhost; + + /// + /// 流媒体服务器id + /// + public string MediaServerId + { + get => _mediaServerId; + set => _mediaServerId = value; + } + + /// + /// app + /// + public string App + { + get => _app; + set => _app = value; + } + + /// + /// TCP链接唯一ID + /// + public string Id + { + get => _id; + set => _id = value; + } + + /// + /// 播放rtsp url参数 + /// + public string Params + { + get => _params; + set => _params = value; + } + + /// + /// rtsp播放器端口号 + /// + public ushort? Port + { + get => _port; + set => _port = value; + } + + /// + /// rtsp或rtsps + /// + public string Schema + { + get => _schema; + set => _schema = value; + } + + /// + /// streamid + /// + public string Stream + { + get => _stream; + set => _stream = value; + } + + /// + /// vhost + /// + public string Vhost + { + get => _vhost; + set => _vhost = value; + } +} \ No newline at end of file diff --git a/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnServerStarted.cs b/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnServerStarted.cs new file mode 100644 index 00000000..67b5a744 --- /dev/null +++ b/LibZLMediaKitMediaServer/Structs/WebHookRequest/ReqForWebHookOnServerStarted.cs @@ -0,0 +1,1125 @@ +using System; +using LibCommon; +using Newtonsoft.Json; + +namespace LibZLMediaKitMediaServer.Structs.WebHookRequest; + +[Serializable] +public class ReqForWebHookOnServerStarted +{ + private bool? _api_apiDebug; + private string? _api_defaultSnap; + private string? _api_secret; + private string? _api_snapRoot; + private string? _cluster_origin_url; + private int? _cluster_retry_count; + private int? _cluster_timeout_sec; + private string? _ffmpeg_bin; + private string? _ffmpeg_cmd; + private string? _ffmpeg_log; + private int? _ffmpeg_restart_sec; + private string? _ffmpeg_snap; + private string? _ffmpeg_templete_ffmpeg2flv; + private string? _ffmpeg_templete_rtsp_tcp2flv; + private bool? _general_check_nvidia_dev; + private bool? _general_enableVhost; + private bool? _general_enable_ffmpeg_log; + private int? _general_flowThreshold; + private int? _general_maxStreamWaitMS; + private string? _general_mediaServerId; + private int? _general_mergeWriteMS; + private bool? _general_resetWhenRePlay; + private int? _general_streamNoneReaderDelayMS; + private int? _general_unready_frame_cache; + private int? _general_wait_add_track_ms; + private int? _general_wait_track_ready_ms; + private bool? _hls_broadcastRecordTs; + private int? _hls_deleteDelaySec; + private int? _hls_fileBufSize; + private int? _hls_segDur; + private int? _hls_segKeep; + private int? _hls_segNum; + private int? _hls_segRetain; + private string? _hook_admin_params; + private float? _hook_alive_interval; + private bool? _hook_enable; + private string? _hook_on_flow_report; + private string? _hook_on_http_access; + private string? _hook_on_play; + private string? _hook_on_publish; + private string? _hook_on_record_mp4; + private string? _hook_on_record_ts; + private string? _hook_on_rtp_server_timeout; + private string? _hook_on_rtsp_auth; + private string? _hook_on_rtsp_realm; + private string? _hook_on_send_rtp_stopped; + private string? _hook_on_server_keepalive; + private string? _hook_on_server_started; + private string? _hook_on_shell_login; + private string? _hook_on_stream_changed; + private string? _hook_on_stream_none_reader; + private string? _hook_on_stream_not_found; + private int? _hook_retry; + private float? _hook_retry_delay; + private int? _hook_timeoutSec; + private bool? _http_allow_cross_domains; + private string? _http_charSet; + private bool? _http_dirMenu; + private string? _http_forbidCacheSuffix; + private string? _http_forwarded_ip_header; + private int? _http_keepAliveSecond; + private int? _http_maxReqSize; + private string? _http_notFound; + private ushort? _http_port; + private string? _http_rootPath; + private int? _http_sendBufSize; + private ushort? _http_sslport; + private string? _http_virtualPath; + private string? _mediaServerId; + private string? _multicast_addrMax; + private string? _multicast_addrMin; + private int? _multicast_udpTTL; + private bool? _protocol_add_mute_audio; + private int? _protocol_continue_push_ms; + private bool? _protocol_enable_audio; + private bool? _protocol_enable_fmp4; + private bool? _protocol_enable_hls; + private bool? _protocol_enable_mp4; + private bool? _protocol_enable_rtmp; + private bool? _protocol_enable_rtsp; + private bool? _protocol_enable_ts; + private bool? _protocol_fmp4_demand; + private bool? _protocol_hls_demand; + private string? _protocol_hls_save_path; + private int? _protocol_modify_stamp; + private bool? _protocol_mp4_as_player; + private int? _protocol_mp4_max_second; + private string? _protocol_mp4_save_path; + private bool? _protocol_rtmp_demand; + private bool? _protocol_rtsp_demand; + private bool? _protocol_ts_demand; + private string? _record_appName; + private bool? _record_fastStart; + private int? _record_fileBufSize; + private bool? _record_fileRepeat; + private int? _record_sampleMS; + private string? _rtc_externIP; + private ushort? _rtc_port; + private string? _rtc_preferredCodecA; + private string? _rtc_preferredCodecV; + private int? _rtc_rembBitRate; + private ushort? _rtc_tcpPort; + private int? _rtc_timeoutSec; + private int? _rtmp_handshakeSecond; + private int? _rtmp_keepAliveSecond; + private bool? _rtmp_modifyStamp; + private ushort? _rtmp_port; + private ushort? _rtmp_sslport; + private int? _rtp_audioMtuSize; + private bool? _rtp_lowLatency; + private int? _rtp_rtpMaxSize; + private int? _rtp_videoMtuSize; + private string? _rtp_Proxy_dumpDir; + private bool? _rtp_proxy_gop_cache; + private string? _rtp_proxy_h264_pt; + private string? _rtp_proxy_h265_pt; + private string? _rtp_proxy_opus_pt; + private ushort? _rtp_proxy_port; + private string? _rtp_proxy_port_range; + private string? _rtp_proxy_ps_pt; + private int? _rtp_proxy_timeoutSec; + private bool? _rtsp_authBasic; + private bool? _rtsp_directProxy; + private int? _rtsp_handshakeSecond; + private int? _rtsp_keepAliveSecond; + private bool? _rtsp_lowLatency; + private ushort? _rtsp_port; + private ushort? _rtsp_sslport; + private int? _shell_maxReqSize; + private ushort? _shell_port; + private int? _srt_latencyMul; + private int? _srt_pktBufSize; + private ushort? _srt_port; + private int? _srt_timeoutSec; + + [JsonProperty("mediaServerId")] + public string? MediaServerId + { + get => _mediaServerId; + set => _mediaServerId = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("api.apiDebug")] + public bool? Api_ApiDebug + { + get => _api_apiDebug; + set => _api_apiDebug = value; + } + + [JsonProperty("api.defaultSnap")] + public string? Api_DefaultSnap + { + get => _api_defaultSnap; + set => _api_defaultSnap = value; + } + + + [JsonProperty("api.secret")] + public string? Api_Secret + { + get => _api_secret; + set => _api_secret = value; + } + + [JsonProperty("api.snapRoot")] + public string? Api_SnapRoot + { + get => _api_snapRoot; + set => _api_snapRoot = value; + } + + [JsonProperty("cluster.origin_url")] + public string Cluster_Origin_Url + { + get => _cluster_origin_url; + set => _cluster_origin_url = value; + } + + [JsonProperty("cluster.retry_count")] + public int? Cluster_Retry_Count + { + get => _cluster_retry_count; + set => _cluster_retry_count = value; + } + + [JsonProperty("cluster.timeout_sec")] + public int? Cluster_Timeout_Sec + { + get => _cluster_timeout_sec; + set => _cluster_timeout_sec = value; + } + + [JsonProperty("ffmpeg.bin")] + public string? Ffmpeg_Bin + { + get => _ffmpeg_bin; + set => _ffmpeg_bin = value; + } + + [JsonProperty("ffmpeg.cmd")] + public string? Ffmpeg_Cmd + { + get => _ffmpeg_cmd; + set => _ffmpeg_cmd = value; + } + + [JsonProperty("ffmpeg.log")] + public string? Ffmpeg_Log + { + get => _ffmpeg_log; + set => _ffmpeg_log = value; + } + + [JsonProperty("ffmpeg.snap")] + public string? Ffmpeg_Snap + { + get => _ffmpeg_snap; + set => _ffmpeg_snap = value; + } + + [JsonProperty("ffmpeg.restart_sec")] + public int? FFmpeg_Restart_Sec + { + get => _ffmpeg_restart_sec; + set => _ffmpeg_restart_sec = value; + } + + [JsonProperty("ffmpeg_templete.ffmpeg2flv")] + public string? Ffmpeg_Templete_Ffmpeg2Flv + { + get => _ffmpeg_templete_ffmpeg2flv; + set => _ffmpeg_templete_ffmpeg2flv = value; + } + + [JsonProperty("ffmpeg_templete.rtsp_tcp2flv")] + public string? Ffmpeg_Templete_RtspTcp2Flv + { + get => _ffmpeg_templete_rtsp_tcp2flv; + set => _ffmpeg_templete_rtsp_tcp2flv = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("general.check_nvidia_dev")] + public bool? General_Check_Nvidia_Dev + { + get => _general_check_nvidia_dev; + set => _general_check_nvidia_dev = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("general.enable_ffmpeg_log")] + public bool? General_Enable_FFmpeg_Log + { + get => _general_enable_ffmpeg_log; + set => _general_enable_ffmpeg_log = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("general.enableVhost")] + public bool? General_EnableVhost + { + get => _general_enableVhost; + set => _general_enableVhost = value; + } + + [JsonProperty("general.flowThreshold")] + public int? General_FlowThreshold + { + get => _general_flowThreshold; + set => _general_flowThreshold = value; + } + + + [JsonProperty("general.maxStreamWaitMS")] + public int? General_MaxStreamWaitMs + { + get => _general_maxStreamWaitMS; + set => _general_maxStreamWaitMS = value; + } + + [JsonProperty("general.mediaServerId")] + public string? General_MediaServerId + { + get => _general_mediaServerId; + set => _general_mediaServerId = value; + } + + [JsonProperty("general.mergeWriteMs")] + public int? General_MergeWriteMs + { + get => _general_mergeWriteMS; + set => _general_mergeWriteMS = value; + } + + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("general.resetWhenRePlay")] + public bool? General_ResetWhenRePlay + { + get => _general_resetWhenRePlay; + set => _general_resetWhenRePlay = value; + } + + [JsonProperty("general.streamNoneReaderDelayMS")] + public int? General_StreamNoneReaderDelayMs + { + get => _general_streamNoneReaderDelayMS; + set => _general_streamNoneReaderDelayMS = value; + } + + + [JsonProperty("general.unready_frame_cache")] + + public int? General_Unready_Frame_Cache + { + get => _general_unready_frame_cache; + set => _general_unready_frame_cache = value; + } + + [JsonProperty("general.wait_add_track_ms")] + public int? General_Wait_Add_Track_Ms + { + get => _general_wait_add_track_ms; + set => _general_wait_add_track_ms = value; + } + + [JsonProperty("general.wait_track_ready_ms")] + public int? General_Wait_Track_Ready_Ms + { + get => _general_wait_track_ready_ms; + set => _general_wait_track_ready_ms = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("hls.broadcastRecordTs")] + public bool? Hls_BroadcastRecordTs + { + get => _hls_broadcastRecordTs; + set => _hls_broadcastRecordTs = value; + } + + [JsonProperty("hls.deleteDelaySec")] + public int? Hls_DeleteDelaySec + { + get => _hls_deleteDelaySec; + set => _hls_deleteDelaySec = value; + } + + [JsonProperty("hls.fileBufSize")] + public int? Hls_FileBufSize + { + get => _hls_fileBufSize; + set => _hls_fileBufSize = value; + } + + + [JsonProperty("hls.segDur")] + public int? Hls_SegDur + { + get => _hls_segDur; + set => _hls_segDur = value; + } + + [JsonProperty("hls.segKeep")] + public int? Hls_SegKeep + { + get => _hls_segKeep; + set => _hls_segKeep = value; + } + + [JsonProperty("hls.segNum")] + public int? Hls_SegNum + { + get => _hls_segNum; + set => _hls_segNum = value; + } + + [JsonProperty("hls.segRetain")] + public int? Hls_SegRetain + { + get => _hls_segRetain; + set => _hls_segRetain = value; + } + + [JsonProperty("hook.admin_params")] + public string? Hook_Admin_Params + { + get => _hook_admin_params; + set => _hook_admin_params = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("hook.enable")] + public bool? Hook_Enable + { + get => _hook_enable; + set => _hook_enable = value; + } + + [JsonProperty("hook.on_flow_report")] + public string? Hook_On_Flow_Report + { + get => _hook_on_flow_report; + set => _hook_on_flow_report = value; + } + + [JsonProperty("hook.on_http_access")] + public string? Hook_On_Http_Access + { + get => _hook_on_http_access; + set => _hook_on_http_access = value; + } + + [JsonProperty("hook.on_play")] + public string? Hook_On_Play + { + get => _hook_on_play; + set => _hook_on_play = value; + } + + [JsonProperty("hook.on_publish")] + public string? Hook_On_Publish + { + get => _hook_on_publish; + set => _hook_on_publish = value; + } + + [JsonProperty("hook.on_record_mp4")] + public string? Hook_On_Record_Mp4 + { + get => _hook_on_record_mp4; + set => _hook_on_record_mp4 = value; + } + + [JsonProperty("hook.on_record_ts")] + public string? Hook_On_Record_Ts + { + get => _hook_on_record_ts; + set => _hook_on_record_ts = value; + } + + [JsonProperty("hook.on_rtsp_auth")] + public string? Hook_On_Rtsp_Auth + { + get => _hook_on_rtsp_auth; + set => _hook_on_rtsp_auth = value; + } + + [JsonProperty("hook.on_rtsp_realm")] + public string? HookOnRtspRealm + { + get => _hook_on_rtsp_realm; + set => _hook_on_rtsp_realm = value; + } + + [JsonProperty("hook.on_server_started")] + public string? Hook_On_Server_Started + { + get => _hook_on_server_started; + set => _hook_on_server_started = value; + } + + [JsonProperty("hook.on_shell_login")] + public string? Hook_On_Shell_Login + { + get => _hook_on_shell_login; + set => _hook_on_shell_login = value; + } + + [JsonProperty("hook.on_stream_changed")] + public string? Hook_On_Stream_Changed + { + get => _hook_on_stream_changed; + set => _hook_on_stream_changed = value; + } + + [JsonProperty("hook.on_stream_none_reader")] + public string? Hook_On_Stream_None_Reader + { + get => _hook_on_stream_none_reader; + set => _hook_on_stream_none_reader = value; + } + + [JsonProperty("hook.on_stream_not_found")] + public string? Hook_On_Stream_Not_Found + { + get => _hook_on_stream_not_found; + set => _hook_on_stream_not_found = value; + } + + [JsonProperty("hook.timeoutSec")] + public int? Hook_TimeoutSec + { + get => _hook_timeoutSec; + set => _hook_timeoutSec = value; + } + + [JsonProperty("hook.retry")] + public int? Hook_Retry + { + get => _hook_retry; + set => _hook_retry = value; + } + + [JsonProperty("hook.retry_delay")] + public float? Hook_Retry_Delay + { + get => _hook_retry_delay; + set => _hook_retry_delay = value; + } + + [JsonProperty("hook.on_send_rtp_stopped")] + public string Hook_On_Send_Rtp_Stopped + { + get => _hook_on_send_rtp_stopped; + set => _hook_on_send_rtp_stopped = value; + } + + [JsonProperty("hook.on_server_keepalive")] + public string Hook_On_Server_Keepalive + { + get => _hook_on_server_keepalive; + set => _hook_on_server_keepalive = value; + } + + [JsonProperty("hook.on_rtp_server_timeout")] + public string Hook_On_Rtp_Server_Timeout + { + get => _hook_on_rtp_server_timeout; + set => _hook_on_rtp_server_timeout = value; + } + + [JsonProperty("hook.alive_interval")] + public float? Hook_Alive_Interval + { + get => _hook_alive_interval; + set => _hook_alive_interval = value; + } + + + [JsonProperty("http.charSet")] + public string? Http_CharSet + { + get => _http_charSet; + set => _http_charSet = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("http.dirMenu")] + public bool? Http_DirMenu + { + get => _http_dirMenu; + set => _http_dirMenu = value; + } + + [JsonProperty("http.keepAliveSecond")] + public int? Http_KeepAliveSecond + { + get => _http_keepAliveSecond; + set => _http_keepAliveSecond = value; + } + + [JsonProperty("http.maxReqSize")] + public int? Http_MaxReqSize + { + get => _http_maxReqSize; + set => _http_maxReqSize = value; + } + + [JsonProperty("http.notFound")] + public string? Http_NotFound + { + get => _http_notFound; + set => _http_notFound = value; + } + + [JsonProperty("http.port")] + public ushort? Http_Port + { + get => _http_port; + set => _http_port = value; + } + + [JsonProperty("http.rootPath")] + public string? Http_RootPath + { + get => _http_rootPath; + set => _http_rootPath = value; + } + + [JsonProperty("http.sendBufSize")] + public int? Http_SendBufSize + { + get => _http_sendBufSize; + set => _http_sendBufSize = value; + } + + [JsonProperty("http.sslport")] + public ushort? Http_Sslport + { + get => _http_sslport; + set => _http_sslport = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("http.allow_cross_domains")] + public bool? Http_Allow_Cross_Domains + { + get => _http_allow_cross_domains; + set => _http_allow_cross_domains = value; + } + + [JsonProperty("http.forbidCacheSuffix")] + public string Http_ForbidCacheSuffix + { + get => _http_forbidCacheSuffix; + set => _http_forbidCacheSuffix = value; + } + + [JsonProperty("http.forwarded_ip_header")] + public string Http_Forwarded_Ip_Header + { + get => _http_forwarded_ip_header; + set => _http_forwarded_ip_header = value; + } + + [JsonProperty("http.virtualPath")] + public string Http_VirtualPath + { + get => _http_virtualPath; + set => _http_virtualPath = value; + } + + [JsonProperty("multicast.addrMax")] + public string? Multicast_AddrMax + { + get => _multicast_addrMax; + set => _multicast_addrMax = value; + } + + [JsonProperty("multicast.addrMin")] + public string? Multicast_AddrMin + { + get => _multicast_addrMin; + set => _multicast_addrMin = value; + } + + [JsonProperty("multicast.udpTTL")] + public int? Multicast_UdpTtl + { + get => _multicast_udpTTL; + set => _multicast_udpTTL = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.add_mute_audio")] + public bool? Protocol_AddMute_Audio + { + get => _protocol_add_mute_audio; + set => _protocol_add_mute_audio = value; + } + + [JsonProperty("protocol.continue_push_ms")] + public int? Protocol_Continue_Push_Ms + { + get => _protocol_continue_push_ms; + set => _protocol_continue_push_ms = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_audio")] + public bool? Protocol_Enable_Audio + { + get => _protocol_enable_audio; + set => _protocol_enable_audio = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_fmp4")] + public bool? Protocol_Enable_Fmp4 + { + get => _protocol_enable_fmp4; + set => _protocol_enable_fmp4 = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_hls")] + public bool? Protocol_Enable_Hls + { + get => _protocol_enable_hls; + set => _protocol_enable_hls = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_mp4")] + public bool? Protocol_Enable_Mp4 + { + get => _protocol_enable_mp4; + set => _protocol_enable_mp4 = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_rtmp")] + public bool? Protocol_Enable_Rtmp + { + get => _protocol_enable_rtmp; + set => _protocol_enable_rtmp = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_rtsp")] + public bool? Protocol_Enable_Rtsp + { + get => _protocol_enable_rtsp; + set => _protocol_enable_rtsp = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.enable_ts")] + public bool? Protocol_Enable_Ts + { + get => _protocol_enable_ts; + set => _protocol_enable_ts = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.fmp4_demand")] + public bool? Protocol_Fmp4_Demand + { + get => _protocol_fmp4_demand; + set => _protocol_fmp4_demand = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.hls_demand")] + public bool? Protocol_Hls_Demand + { + get => _protocol_hls_demand; + set => _protocol_hls_demand = value; + } + + [JsonProperty("protocol.hls_save_path")] + public string Protocol_Hls_Save_Path + { + get => _protocol_hls_save_path; + set => _protocol_hls_save_path = value; + } + + [JsonProperty("protocol.modify_stamp")] + public int? Protocol_Modify_Stamp + { + get => _protocol_modify_stamp; + set => _protocol_modify_stamp = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.mp4_as_player")] + public bool? Protocol_Mp4_As_Player + { + get => _protocol_mp4_as_player; + set => _protocol_mp4_as_player = value; + } + + [JsonProperty("protocol.mp4_max_second")] + public int? Protocol_Mp4_Max_Second + { + get => _protocol_mp4_max_second; + set => _protocol_mp4_max_second = value; + } + + [JsonProperty("protocol.mp4_save_path")] + public string Protocol_Mp4_Save_Path + { + get => _protocol_mp4_save_path; + set => _protocol_mp4_save_path = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.rtmp_demand")] + public bool? Protocol_Rtmp_Demand + { + get => _protocol_rtmp_demand; + set => _protocol_rtmp_demand = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.rtsp_demand")] + public bool? Protocol_Rtsp_Demand + { + get => _protocol_rtsp_demand; + set => _protocol_rtsp_demand = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("protocol.ts_demand")] + public bool? Protocol_Ts_Demand + { + get => _protocol_ts_demand; + set => _protocol_ts_demand = value; + } + + [JsonProperty("record.appName")] + public string? Record_AppName + { + get => _record_appName; + set => _record_appName = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("record.fastStart")] + public bool? Record_FastStart + { + get => _record_fastStart; + set => _record_fastStart = value; + } + + [JsonProperty("record.fileBufSize")] + public int? Record_FileBufSize + { + get => _record_fileBufSize; + set => _record_fileBufSize = value; + } + + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("record.fileRepeat")] + public bool? Record_FileRepeat + { + get => _record_fileRepeat; + set => _record_fileRepeat = value; + } + + + [JsonProperty("record.sampleMS")] + public int? Record_SampleMs + { + get => _record_sampleMS; + set => _record_sampleMS = value; + } + + [JsonProperty("rtc.externIP")] + public string Rtc_ExternIp + { + get => _rtc_externIP; + set => _rtc_externIP = value; + } + + [JsonProperty("rtc.port")] + public ushort? Rtc_Port + { + get => _rtc_port; + set => _rtc_port = value; + } + + [JsonProperty("rtc.preferredCodecA")] + public string Rtc_PreferredCodecA + { + get => _rtc_preferredCodecA; + set => _rtc_preferredCodecA = value; + } + + [JsonProperty("rtc.preferredCodecV")] + public string Rtc_PreferredCodecV + { + get => _rtc_preferredCodecV; + set => _rtc_preferredCodecV = value; + } + + [JsonProperty("rtc.rembBitRate")] + public int? Rtc_RembBitRate + { + get => _rtc_rembBitRate; + set => _rtc_rembBitRate = value; + } + + [JsonProperty("rtc.tcpPort")] + public ushort? Rtc_TcpPort + { + get => _rtc_tcpPort; + set => _rtc_tcpPort = value; + } + + [JsonProperty("rtc.timeoutSec")] + public int? Rtc_TimeoutSec + { + get => _rtc_timeoutSec; + set => _rtc_timeoutSec = value; + } + + [JsonProperty("rtmp.handshakeSecond")] + public int? Rtmp_HandshakeSecond + { + get => _rtmp_handshakeSecond; + set => _rtmp_handshakeSecond = value; + } + + [JsonProperty("rtmp.keepAliveSecond")] + public int? Rtmp_KeepAliveSecond + { + get => _rtmp_keepAliveSecond; + set => _rtmp_keepAliveSecond = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("rtmp.modifyStamp")] + public bool? Rtmp_ModifyStamp + { + get => _rtmp_modifyStamp; + set => _rtmp_modifyStamp = value; + } + + [JsonProperty("rtmp.port")] + public ushort? Rtmp_Port + { + get => _rtmp_port; + set => _rtmp_port = value; + } + + [JsonProperty("rtmp.sslport")] + public ushort? Rtmp_Sslport + { + get => _rtmp_sslport; + set => _rtmp_sslport = value; + } + + [JsonProperty("rtp.audioMtuSize")] + public int? Rtp_AudioMtuSize + { + get => _rtp_audioMtuSize; + set => _rtp_audioMtuSize = value; + } + + + [JsonProperty("rtp.videoMtuSize")] + public int? Rtp_VideoMtuSize + { + get => _rtp_videoMtuSize; + set => _rtp_videoMtuSize = value; + } + + + [JsonProperty("rtp_proxy.dumpDir")] + public string? Rtp_Proxy_DumpDir + { + get => _rtp_Proxy_dumpDir; + set => _rtp_Proxy_dumpDir = value; + } + + [JsonProperty("rtp_proxy.port")] + public ushort? Rtp_Proxy_Port + { + get => _rtp_proxy_port; + set => _rtp_proxy_port = value; + } + + [JsonProperty("rtp_proxy.timeoutSec")] + public int? Rtp_Proxy_TimeoutSec + { + get => _rtp_proxy_timeoutSec; + set => _rtp_proxy_timeoutSec = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("rtp.lowLatency")] + public bool? Rtp_LowLatency + { + get => _rtp_lowLatency; + set => _rtp_lowLatency = value; + } + + [JsonProperty("rtp.rtpMaxSize")] + public int? Rtp_RtpMaxSize + { + get => _rtp_rtpMaxSize; + set => _rtp_rtpMaxSize = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("rtp_proxy.gop_cache")] + public bool? Rtp_Proxy_Gop_Cache + { + get => _rtp_proxy_gop_cache; + set => _rtp_proxy_gop_cache = value; + } + + [JsonProperty("rtp_proxy.h264_pt")] + public string Rtp_Proxy_H264_Pt + { + get => _rtp_proxy_h264_pt; + set => _rtp_proxy_h264_pt = value; + } + + [JsonProperty("rtp_proxy.h265_pt")] + public string Rtp_Proxy_H265_Pt + { + get => _rtp_proxy_h265_pt; + set => _rtp_proxy_h265_pt = value; + } + + [JsonProperty("rtp_proxy.opus_pt")] + public string Rtp_Proxy_Opus_Pt + { + get => _rtp_proxy_opus_pt; + set => _rtp_proxy_opus_pt = value; + } + + [JsonProperty("rtp_proxy.ps_pt")] + public string Rtp_Proxy_Ps_Pt + { + get => _rtp_proxy_ps_pt; + set => _rtp_proxy_ps_pt = value; + } + + [JsonProperty("rtp_proxy.port_range")] + public string Rtp_Proxy_Port_Range + { + get => _rtp_proxy_port_range; + set => _rtp_proxy_port_range = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("rtsp.authBasic")] + public bool? Rtsp_AuthBasic + { + get => _rtsp_authBasic; + set => _rtsp_authBasic = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("rtsp.directProxy")] + public bool? RtspDirectProxy + { + get => _rtsp_directProxy; + set => _rtsp_directProxy = value; + } + + [JsonProperty("rtsp.handshakeSecond")] + public int? Rtsp_HandshakeSecond + { + get => _rtsp_handshakeSecond; + set => _rtsp_handshakeSecond = value; + } + + [JsonProperty("rtsp.keepAliveSecond")] + public int? Rtsp_KeepAliveSecond + { + get => _rtsp_keepAliveSecond; + set => _rtsp_keepAliveSecond = value; + } + + [JsonProperty("rtsp.port")] + public ushort? Rtsp_Port + { + get => _rtsp_port; + set => _rtsp_port = value; + } + + [JsonProperty("rtsp.sslport")] + public ushort? Rtsp_Sslport + { + get => _rtsp_sslport; + set => _rtsp_sslport = value; + } + + [JsonConverter(typeof(BoolConvert))] + [JsonProperty("rtsp.lowLatency")] + public bool? Rtsp_LowLatency + { + get => _rtsp_lowLatency; + set => _rtsp_lowLatency = value; + } + + + [JsonProperty("shell.maxReqSize")] + public int? Shell_MaxReqSize + { + get => _shell_maxReqSize; + set => _shell_maxReqSize = value; + } + + [JsonProperty("shell.port")] + public ushort? Shell_Port + { + get => _shell_port; + set => _shell_port = value; + } + + [JsonProperty("srt.latencyMul")] + public int? Srt_LatencyMul + { + get => _srt_latencyMul; + set => _srt_latencyMul = value; + } + + [JsonProperty("srt.pktBufSize")] + public int? Srt_PktBufSize + { + get => _srt_pktBufSize; + set => _srt_pktBufSize = value; + } + + [JsonProperty("srt.port")] + public ushort? Srt_Port + { + get => _srt_port; + set => _srt_port = value; + } + + [JsonProperty("srt.timeoutSec")] + public int? Srt_TimeoutSec + { + get => _srt_timeoutSec; + set => _srt_timeoutSec = value; + } +} \ No newline at end of file diff --git a/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnPublish.cs b/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnPublish.cs index d3b77cc0..4bb46986 100644 --- a/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnPublish.cs +++ b/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnPublish.cs @@ -6,22 +6,230 @@ namespace LibZLMediaKitMediaServer.Structs.WebHookResponse [Serializable] public class ResToWebHookOnPublish : ResZLMediaKitResponseBase { - private bool? _enableHls; - private bool? _enableMP4; + // private bool? _enableHls; + // private bool? _enableMP4; private string? _msg; - public bool? EnableHls + private bool? _enable_hls; + private bool? _enable_hls_fmp4; + private bool? _enable_mp4; + private bool? _enable_rtsp; + private bool? _enable_rtmp; + private bool? _enable_ts; + private bool? _enable_fmp4; + private bool? _hls_demand; + private bool? _rtsp_demand; + private bool? _rtmp_demand; + private bool? _ts_demand; + private bool? _fmp4_demand; + private bool? _enable_audio; + private bool? _add_mute_audio; + private string? _mp4_save_path; + private int? _mp4_max_second; + private bool? _mp4_as_player; + private string? _hls_save_path; + private int? _modify_stamp; + private UInt32? _continue_push_ms; + private bool? _auto_close; + private string _stream_replace; + + /// + /// 是否转换成hls-mpegts协议 + /// + public bool? Enable_Hls + { + get => _enable_hls; + set => _enable_hls = value; + } + + /// + /// 是否转换成hls-fmp4协议 + /// + public bool? Enable_Hls_Fmp4 + { + get => _enable_hls_fmp4; + set => _enable_hls_fmp4 = value; + } + + /// + /// 是否允许录制mp4文件 + /// + public bool? Enable_Mp4 + { + get => _enable_mp4; + set => _enable_mp4 = value; + } + + /// + /// 是否转换rtsp协议 + /// + public bool? Enable_Rtsp + { + get => _enable_rtsp; + set => _enable_rtsp = value; + } + + /// + /// 是否转换rtmp/flv协议 + /// + public bool? Enable_Rtmp + { + get => _enable_rtmp; + set => _enable_rtmp = value; + } + + /// + /// 是否转换http-ts/ws-ts协议 + /// + public bool? Enable_Ts + { + get => _enable_ts; + set => _enable_ts = value; + } + + /// + /// 是否转换http-fmp4/ws-fmp4协议 + /// + public bool? Enable_Fmp4 + { + get => _enable_fmp4; + set => _enable_fmp4 = value; + } + + /// + /// 是否有人观看才生成 + /// + public bool? Hls_Demand + { + get => _hls_demand; + set => _hls_demand = value; + } + + /// + ///是否有人观看才生成 + /// + public bool? Rtsp_Demand + { + get => _rtsp_demand; + set => _rtsp_demand = value; + } + + /// + /// 是否有人观看才生成 + /// + public bool? Rtmp_Demand + { + get => _rtmp_demand; + set => _rtmp_demand = value; + } + + /// + /// 是否有人观看才生成 + /// + public bool? Ts_Demand + { + get => _ts_demand; + set => _ts_demand = value; + } + + /// + /// 是否有人观看才生成 + /// + public bool? Fmp4_Demand + { + get => _fmp4_demand; + set => _fmp4_demand = value; + } + + /// + /// 转协议时是否开启音频 + /// + public bool? Enable_Audio + { + get => _enable_audio; + set => _enable_audio = value; + } + + /// + /// 转协议时,无音频是否添加静音aac音频 + /// + public bool? Add_Mute_Audio + { + get => _add_mute_audio; + set => _add_mute_audio = value; + } + + /// + /// mp4录制文件保存地址,置空使用默认 + /// + public string Mp4_Save_Path + { + get => _mp4_save_path; + set => _mp4_save_path = value; + } + + /// + /// 录制切片大小,单位秒 + /// + public int? Mp4_Max_Second + { + get => _mp4_max_second; + set => _mp4_max_second = value; + } + + /// + /// mp4录制是否当作观看者参与播放人数统计 + /// + public bool? Mp4_As_Player { - get => _enableHls; - set => _enableHls = value; + get => _mp4_as_player; + set => _mp4_as_player = value; } - public bool? EnableMP4 + /// + /// hls文件保存根目录,置空使用默认 + /// + public string Hls_Save_Path { - get => _enableMP4; - set => _enableMP4 = value; + get => _hls_save_path; + set => _hls_save_path = value; } + /// + /// 是否开启时间戳覆盖,0:绝对时间戳 1:系统时间戳 2:相对时间戳 + /// + public int? Modify_Stamp + { + get => _modify_stamp; + set => _modify_stamp = value; + } + + /// + /// 断连续推延迟时间,单位毫秒,置空使用配置文件默认值 + /// + public uint? Continue_Push_Ms + { + get => _continue_push_ms; + set => _continue_push_ms = value; + } + + /// + /// 无关观看是否自动关闭流,不会触 发无人观看hook + /// + public bool? Auto_Close + { + get => _auto_close; + set => _auto_close = value; + } + + /// + /// 是否修改流id,通过此参数可以自定义流id,比如替换ssrc值 + /// + public string Stream_Replace + { + get => _stream_replace; + set => _stream_replace = value; + } public string? Msg { diff --git a/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnRtspAuth.cs b/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnRtspAuth.cs new file mode 100644 index 00000000..9044d03a --- /dev/null +++ b/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnRtspAuth.cs @@ -0,0 +1,37 @@ +using LibZLMediaKitMediaServer.Structs.WebResponse.ZLMediaKit; + +namespace LibZLMediaKitMediaServer.Structs.WebHookResponse; + +public class ResToWebHookOnRtspAuth : ResZLMediaKitResponseBase +{ + private bool? _encrypted; + private string? _passwd; + private string? _msg; + + /// + /// 是否加密过 + /// + public bool? Encrypted + { + get => _encrypted; + set => _encrypted = value; + } + + /// + /// password + /// + public string Passwd + { + get => _passwd; + set => _passwd = value; + } + + /// + /// message + /// + public string Msg + { + get => _msg; + set => _msg = value; + } +} \ No newline at end of file diff --git a/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnRtspRealm.cs b/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnRtspRealm.cs new file mode 100644 index 00000000..031bcab5 --- /dev/null +++ b/LibZLMediaKitMediaServer/Structs/WebHookResponse/ResToWebHookOnRtspRealm.cs @@ -0,0 +1,14 @@ +using LibZLMediaKitMediaServer.Structs.WebResponse.ZLMediaKit; + +namespace LibZLMediaKitMediaServer.Structs.WebHookResponse; + +public class ResToWebHookOnRtspRealm : ResZLMediaKitResponseBase +{ + private string? _realm; + + public string Realm + { + get => _realm; + set => _realm = value; + } +} \ No newline at end of file diff --git a/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitAddStreamProxy.cs b/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitAddStreamProxy.cs index ded88ca0..b4b354c7 100644 --- a/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitAddStreamProxy.cs +++ b/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitAddStreamProxy.cs @@ -14,7 +14,186 @@ public class ReqZLMediaKitAddStreamProxy : ReqZLMediaKitRequestBase private string _url; private string _vhost; private int? _retry_count = -1; //拉流失败时的重试拉流次数,-1为无限重试 + private int? _enable_hls_fmp4; //是否转成hls-fmp4协议 + private int? _enable_rtsp; //是否转rtsp协议 + private int? _enable_rtmp; //是否转rtmp协议 + private int? _enable_ts; //是否转http-ts/ws-ts协议 + private int? _enable_fmp4; //是否转http-fmp4/ws-fmp4协议 + private int? _hls_demand; //该协议是否有人观看才生成 + private int? _rtsp_demand; + private int? _rtmp_demand; + private int? _ts_demand; + private int? _fmp4_demand; + private int? _enable_audio; + private int? _add_mute_audio; //转协议时,无音频是否添加静音acc音频 + private string? _mp4_save_path; //mp4录制文件保存的根目录,置空使用默认 + private int? _mp4_max_second; //mp4录制切片大小,单位为秒 + private int? _mp4_as_player; //mp4录制是否当作观看者参与播放人数计数 + private string? _hls_save_path; //hls文件保存目录,置空使用默认 + private int? modify_stamp; //该流是否开启时间戳覆盖(0:绝对时间戳/1:系统时间戳/2:相对时间戳) + private int? _auto_close; //无人观看是否自动关闭流(不触发无人观看hook) + /// + /// 是否转成hls-fmp4协议 + /// + public int? Enable_Hls_Fmp4 + { + get => _enable_hls_fmp4; + set => _enable_hls_fmp4 = value; + } + + /// + /// 是否转rtsp协议 + /// + public int? Enable_Rtsp + { + get => _enable_rtsp; + set => _enable_rtsp = value; + } + + /// + /// 是否转rtmp协议 + /// + public int? Enable_Rtmp + { + get => _enable_rtmp; + set => _enable_rtmp = value; + } + + /// + /// 是否转http-ts/ws-ts协议 + /// + public int? Enable_Ts + { + get => _enable_ts; + set => _enable_ts = value; + } + + /// + /// 是否转http-fmp4/ws-fmp4协议 + /// + public int? Enable_Fmp4 + { + get => _enable_fmp4; + set => _enable_fmp4 = value; + } + + /// + /// 该协议是否有人观看才生成 + /// + public int? Hls_Demand + { + get => _hls_demand; + set => _hls_demand = value; + } + + /// + /// 该协议是否有人观看才生成 + /// + public int? Rtsp_Demand + { + get => _rtsp_demand; + set => _rtsp_demand = value; + } + + /// + /// 该协议是否有人观看才生成 + /// + public int? Rtmp_Demand + { + get => _rtmp_demand; + set => _rtmp_demand = value; + } + + /// + /// 该协议是否有人观看才生成 + /// + public int? Ts_Demand + { + get => _ts_demand; + set => _ts_demand = value; + } + + /// + /// 该协议是否有人观看才生成 + /// + public int? Fmp4_Demand + { + get => _fmp4_demand; + set => _fmp4_demand = value; + } + + /// + /// 允许音频 + /// + public int? Enable_Audio + { + get => _enable_audio; + set => _enable_audio = value; + } + + /// + /// 转协议时,无音频是否添加静音acc音频 + /// + public int? Add_Mute_Audio + { + get => _add_mute_audio; + set => _add_mute_audio = value; + } + + /// + /// mp4录制文件保存的根目录,置空使用默认 + /// + public string Mp4_Save_Path + { + get => _mp4_save_path; + set => _mp4_save_path = value; + } + + /// + /// mp4录制切片大小,单位为秒 + /// + public int? Mp4_Max_Second + { + get => _mp4_max_second; + set => _mp4_max_second = value; + } + + /// + /// mp4录制是否当作观看者参与播放人数计数 + /// + public int? Mp4_As_Player + { + get => _mp4_as_player; + set => _mp4_as_player = value; + } + + /// + /// hls文件保存目录,置空使用默认 + /// + public string Hls_Save_Path + { + get => _hls_save_path; + set => _hls_save_path = value; + } + + /// + /// 该流是否开启时间戳覆盖(0:绝对时间戳/1:系统时间戳/2:相对时间戳) + /// + public int? Modify_Stamp + { + get => modify_stamp; + set => modify_stamp = value; + } + + /// + /// 无人观看是否自动关闭流(不触发无人观看hook) + /// + public int? Auto_Close + { + get => _auto_close; + set => _auto_close = value; + } /// /// vhost diff --git a/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ResZLMediaKitGetMediaList.cs b/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitGetMediaList.cs similarity index 92% rename from LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ResZLMediaKitGetMediaList.cs rename to LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitGetMediaList.cs index d23e626d..7c34f168 100644 --- a/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ResZLMediaKitGetMediaList.cs +++ b/LibZLMediaKitMediaServer/Structs/WebRequest/ZLMediaKit/ReqZLMediaKitGetMediaList.cs @@ -6,7 +6,7 @@ namespace LibZLMediaKitMediaServer.Structs.WebRequest.ZLMediaKit /// 请求zlmediakit的流列表结构 /// [Serializable] - public class ResZLMediaKitGetMediaList : ReqZLMediaKitRequestBase + public class ReqZLMediaKitGetMediaList : ReqZLMediaKitRequestBase { private string? _app; private string? _schema; diff --git a/LibZLMediaKitMediaServer/WebApiHelper.cs b/LibZLMediaKitMediaServer/WebApiHelper.cs index 72821d33..c5cc761e 100644 --- a/LibZLMediaKitMediaServer/WebApiHelper.cs +++ b/LibZLMediaKitMediaServer/WebApiHelper.cs @@ -44,7 +44,7 @@ public ResZLMediaKitGetThreadsLoad GetThreadsLoad(out ResponseStruct rs) Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}getThreadsLoad"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}getThreadsLoad"; try { var httpRet = NetHelper.HttpGetRequest(url, null, "utf-8", _httpClientTimeout); @@ -112,7 +112,7 @@ public ResZLMediaKitGetThreadsLoad GetWorkThreadsLoad(out ResponseStruct rs) Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}getWorkThreadsLoad"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}getWorkThreadsLoad"; try { var httpRet = NetHelper.HttpGetRequest(url, null, "utf-8", _httpClientTimeout); @@ -180,7 +180,7 @@ public ResZLMediaKitConfig GetServerConfig(out ResponseStruct rs) Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}getServerConfig"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}getServerConfig"; try { var req = new ReqZLMediaKitGetSystemConfig(); @@ -251,7 +251,7 @@ public ResZLMediaKitRestartServer RestartServer(out ResponseStruct rs) Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}restartServer"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}restartServer"; try { var req = new ReqZLMediaKitRequestBase(); @@ -315,7 +315,7 @@ public ResZLMediaKitRestartServer RestartServer(out ResponseStruct rs) /// /// /// - public ResZLMediaKitMediaList GetMediaList(ResZLMediaKitGetMediaList req, out ResponseStruct rs) + public ResZLMediaKitMediaList GetMediaList(ReqZLMediaKitGetMediaList req, out ResponseStruct rs) { rs = new ResponseStruct() { @@ -323,7 +323,7 @@ public ResZLMediaKitMediaList GetMediaList(ResZLMediaKitGetMediaList req, out Re Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}getMediaList"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}getMediaList"; try { req.Secret = this._secret; @@ -394,7 +394,9 @@ public ResZLMediaKitCloseStreams CloseStreams(ReqZLMediaKitCloseStreams req, out Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}close_streams"; + + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}close_streams"; + try { req.Secret = this._secret; @@ -464,7 +466,7 @@ public ResZLMediaKitGetAllSession GetAllSession(ReqZLMediaKitGetAllSession req, Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}getAllSession"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}getAllSession"; try { req.Secret = this._secret; @@ -535,7 +537,7 @@ public ResZLMediaKitKickSession KickSession(ReqZLMediaKitGetAllSession req, out Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}kick_session"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}kick_session"; try { req.Secret = this._secret; @@ -605,7 +607,7 @@ public ResZLMediaKitKickSessions KickSessions(ReqZLMediaKitKickSessions req, out Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}kick_sessions"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}kick_sessions"; try { req.Secret = this._secret; @@ -676,7 +678,7 @@ public ResZLMediaKitAddStreamProxy AddStreamProxy(ReqZLMediaKitAddStreamProxy re Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}addStreamProxy"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}addStreamProxy"; try { req.Secret = this._secret; @@ -684,6 +686,37 @@ public ResZLMediaKitAddStreamProxy AddStreamProxy(ReqZLMediaKitAddStreamProxy re var httpRet = NetHelper.HttpPostRequest(url, null, reqData, "utf-8", _httpClientTimeout); if (!string.IsNullOrEmpty(httpRet)) { + //当发现有流已存在时断掉这个流 + if (httpRet.ToLower().Contains("-1") && httpRet.ToLower().Contains("this") && + httpRet.ToLower().Contains("stream") && + httpRet.ToLower().Contains("already") && httpRet.ToLower().Contains("exists")) + { + var req2 = new ReqZLMediaKitCloseStreams() + { + App = req.App, + Force = true, + Stream = req.Stream, + Vhost = req.Vhost, + }; + try + { + CloseStreams(req2, out _); + } + catch + { + } + + rs = new ResponseStruct() + { + Code = ErrorNumber.MediaServer_WebApiDataExcept, + Message = ErrorMessage.ErrorDic![ErrorNumber.MediaServer_WebApiDataExcept], + ExceptMessage = httpRet, + ExceptStackTrace = JsonHelper.ToJson(httpRet + "\r\n" + + "此处处理了AddStreamProxy返回This stream already exists的问题,先断开这个流,等后续拉流时应该能正常拉到"), + }; + return null; + } + if (UtilsHelper.HttpClientResponseIsNetWorkError(httpRet)) { rs = new ResponseStruct() @@ -747,7 +780,7 @@ public ResZLMediaKitAddFFmpegProxy AddFFmpegSource(ReqZLMediaKitAddFFmpegProxy r Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}addFFmpegSource"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}addFFmpegSource"; try { req.Secret = this._secret; @@ -817,7 +850,7 @@ public ResZLMeidaKitDelStreamProxy DelStreamProxy(ReqZLMediaKitDelStreamProxy re Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}delStreamProxy"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}delStreamProxy"; try { req.Secret = this._secret; @@ -888,7 +921,7 @@ public ResZLMeidaKitDelFfMpegSource DelFFmpegSource(ReqZLMediaKitDelFFmpegSource Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}delFFmpegSource"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}delFFmpegSource"; try { req.Secret = this._secret; @@ -958,7 +991,7 @@ public ResZLMediaKitGetRtpInfo GetRtpInfo(ReqZLMediaKitGetRtpInfo req, out Respo Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}getRtpInfo"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}getRtpInfo"; try { req.Secret = this._secret; @@ -1029,7 +1062,7 @@ public ResZLMediaKitStartRecord StartRecord(ReqZLMediaKitStartRecord req, out Re Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}startRecord"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}startRecord"; try { req.Secret = this._secret; @@ -1103,7 +1136,7 @@ public ResZLMediaKitStopRecord StopRecord(ReqZLMediaKitStopRecord req, out Respo Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}stopRecord"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}stopRecord"; try { req.Secret = this._secret; @@ -1174,7 +1207,7 @@ public ResZLMediaKitIsRecording IsRecording(ReqZLMediaKitIsRecording req, out Re Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}isRecording"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}isRecording"; try { req.Secret = this._secret; @@ -1244,10 +1277,8 @@ public string GetSnap(ReqZLMediaKitGetSnap req, out ResponseStruct rs) Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; req.Url = req.Url.Replace(_ipAddress, "127.0.0.1"); - string url = _useSSL - ? "https://" - : "http://" + - $"{_ipAddress}:{_webApiPort}{_baseUri}getSnap?secret={this._secret}&url={req.Url}&timeout_sec={req.Timeout_Sec}&expire_sec={req.Expire_Sec}"; + string url = (_useSSL ? "https://" : "http://") + + $"{_ipAddress}:{_webApiPort}{_baseUri}getSnap?secret={this._secret}&url={req.Url}&timeout_sec={req.Timeout_Sec}&expire_sec={req.Expire_Sec}"; try { @@ -1295,7 +1326,7 @@ public ResZLMediaKitOpenRtpPort OpenRtpPort(ReqZLMediaKitOpenRtpPort req, out Re Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}openRtpServer"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}openRtpServer"; try { req.Secret = this._secret; @@ -1366,7 +1397,7 @@ public ResZLMediaKitCloseRtpPort CloseRtpPort(ReqZLMediaKitCloseRtpPort req, out Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}closeRtpServer"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}closeRtpServer"; try { req.Secret = this._secret; @@ -1437,7 +1468,7 @@ public ResZLMediaKitListRtpServer ListRtpServer(ReqZLMediaKitRequestBase req, ou Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}listRtpServer"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}listRtpServer"; try { req.Secret = this._secret; @@ -1507,7 +1538,7 @@ public ResZLMediakitStartSendRtp StartSendRtp(ReqZLMediaKitStartSendRtp req, out Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}startSendRtp"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}startSendRtp"; try { req.Secret = this._secret; @@ -1577,7 +1608,7 @@ public ResZLMediaKitResponseBase StopSendRtp(ReqZLMediaKitStopSendRtp req, out R Message = ErrorMessage.ErrorDic![ErrorNumber.None], }; - string url = _useSSL ? "https://" : "http://" + $"{_ipAddress}:{_webApiPort}{_baseUri}stopSendRtp"; + string url = (_useSSL ? "https://" : "http://") + $"{_ipAddress}:{_webApiPort}{_baseUri}stopSendRtp"; try { req.Secret = this._secret; diff --git a/README.md b/README.md index eac23858..1d79ec50 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +# 提醒:重庆菲莫科技有限公司,你们在没有告知我,没有得到我同意的情况下,将AKStream及其相关组件作为你们申请发明专利的内容进行发明专利申请;同时还未按照MIT开源协议将技术来源标记出来,这是违反开源协议的行为,请立即终止或整改你们的侵权行为,目前看到的专利申请号为:CN202110965081.9,特此提醒! # AKStream介绍 ## 技术交流QQ群:870526956 ------- diff --git a/SipSorcery/net/DtlsSrtp/DtlsSrtpClient.cs b/SipSorcery/net/DtlsSrtp/DtlsSrtpClient.cs index 407351c5..18a5bb5e 100644 --- a/SipSorcery/net/DtlsSrtp/DtlsSrtpClient.cs +++ b/SipSorcery/net/DtlsSrtp/DtlsSrtpClient.cs @@ -348,11 +348,11 @@ protected virtual void PrepareSrtpSharedSecret() byte[] sharedSecret = GetKeyingMaterial(2 * (keyLen + saltLen)); /* - * + * * See: http://tools.ietf.org/html/rfc5764#section-4.2 - * + * * sharedSecret is an equivalent of : - * + * * struct { * client_write_SRTP_master_key[SRTPSecurityParams.master_key_len]; * server_write_SRTP_master_key[SRTPSecurityParams.master_key_len]; @@ -361,14 +361,14 @@ protected virtual void PrepareSrtpSharedSecret() * } ; * * Here, client = local configuration, server = remote. - * NOTE [ivelin]: 'local' makes sense if this code is used from a DTLS SRTP client. - * Here we run as a server, so 'local' referring to the client is actually confusing. - * + * NOTE [ivelin]: 'local' makes sense if this code is used from a DTLS SRTP client. + * Here we run as a server, so 'local' referring to the client is actually confusing. + * * l(k) = KEY length * s(k) = salt lenght - * + * * So we have the following repartition : - * l(k) 2*l(k)+s(k) + * l(k) 2*l(k)+s(k) * 2*l(k) 2*(l(k)+s(k)) * +------------------------+------------------------+---------------+-------------------+ * + local key | remote key | local salt | remote salt | diff --git a/SipSorcery/net/DtlsSrtp/DtlsSrtpServer.cs b/SipSorcery/net/DtlsSrtp/DtlsSrtpServer.cs index 0f8050c3..8cfce5be 100644 --- a/SipSorcery/net/DtlsSrtp/DtlsSrtpServer.cs +++ b/SipSorcery/net/DtlsSrtp/DtlsSrtpServer.cs @@ -420,11 +420,11 @@ protected virtual void PrepareSrtpSharedSecret() byte[] sharedSecret = GetKeyingMaterial(2 * (keyLen + saltLen)); /* - * + * * See: http://tools.ietf.org/html/rfc5764#section-4.2 - * + * * sharedSecret is an equivalent of : - * + * * struct { * client_write_SRTP_master_key[SRTPSecurityParams.master_key_len]; * server_write_SRTP_master_key[SRTPSecurityParams.master_key_len]; @@ -433,14 +433,14 @@ protected virtual void PrepareSrtpSharedSecret() * } ; * * Here, client = local configuration, server = remote. - * NOTE [ivelin]: 'local' makes sense if this code is used from a DTLS SRTP client. - * Here we run as a server, so 'local' referring to the client is actually confusing. - * + * NOTE [ivelin]: 'local' makes sense if this code is used from a DTLS SRTP client. + * Here we run as a server, so 'local' referring to the client is actually confusing. + * * l(k) = KEY length * s(k) = salt length - * + * * So we have the following repartition : - * l(k) 2*l(k)+s(k) + * l(k) 2*l(k)+s(k) * 2*l(k) 2*(l(k)+s(k)) * +------------------------+------------------------+---------------+-------------------+ * + local key | remote key | local salt | remote salt | diff --git a/SipSorcery/net/DtlsSrtp/Transform/IPackerTransformer.cs b/SipSorcery/net/DtlsSrtp/Transform/IPackerTransformer.cs index 4d0759b5..cd592826 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/IPackerTransformer.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/IPackerTransformer.cs @@ -25,7 +25,7 @@ public interface IPacketTransformer { /** * Transforms a non-secure packet. - * + * * @param pkt * the packet to be transformed * @return The transformed packet. Returns null if the packet cannot be transformed. @@ -34,7 +34,7 @@ public interface IPacketTransformer /** * Transforms a specific non-secure packet. - * + * * @param pkt * The packet to be secured * @param offset @@ -49,7 +49,7 @@ public interface IPacketTransformer /** * Reverse-transforms a specific packet (i.e. transforms a transformed * packet back). - * + * * @param pkt * the transformed packet to be restored * @return Whether the packet was successfully restored @@ -59,7 +59,7 @@ public interface IPacketTransformer /** * Reverse-transforms a specific packet (i.e. transforms a transformed * packet back). - * + * * @param pkt * the packet to be restored * @param offset @@ -72,7 +72,7 @@ public interface IPacketTransformer /** * Close the transformer and underlying transform engine. - * + * * The close functions closes all stored crypto contexts. This deletes key * data and forces a cleanup of the crypto contexts. */ diff --git a/SipSorcery/net/DtlsSrtp/Transform/RawPacket.cs b/SipSorcery/net/DtlsSrtp/Transform/RawPacket.cs index e6797bef..069e1eae 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/RawPacket.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/RawPacket.cs @@ -37,7 +37,7 @@ * @author Damian Minkov * @author Boris Grozev * @author Lyubomir Marinov -* +* */ using System; @@ -77,7 +77,7 @@ public RawPacket() * byte array buffer. * * @param buffer the byte array to be the buffer of the new - * instance + * instance * @param offset the offset in buffer at which the actual data to * be represented by the new instance starts * @param length the number of bytes in buffer which @@ -387,7 +387,7 @@ public byte[] ReadRegion(int off, int len) /** * Read a byte region from specified offset in the RTP packet and with * specified length into a given buffer - * + * * @param off * start offset in the RTP packet of the region to be read * @param len diff --git a/SipSorcery/net/DtlsSrtp/Transform/SrtcpCryptoContext.cs b/SipSorcery/net/DtlsSrtp/Transform/SrtcpCryptoContext.cs index 24a727fd..761d40fb 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/SrtcpCryptoContext.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/SrtcpCryptoContext.cs @@ -53,7 +53,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ + */ using System; using System.IO; @@ -130,7 +130,7 @@ public class SrtcpCryptoContext /** * Construct an empty SRTPCryptoContext using ssrc. * The other parameters are set to default null value. - * + * * @param ssrc SSRC of this SRTPCryptoContext */ public SrtcpCryptoContext(long ssrcIn) @@ -148,7 +148,7 @@ public SrtcpCryptoContext(long ssrcIn) /** * Construct a normal SRTPCryptoContext based on the given parameters. - * + * * @param ssrc * the RTP SSRC that this SRTP cryptographic context protects. * @param masterKey @@ -234,14 +234,14 @@ public SrtcpCryptoContext(long ssrcIn, byte[] masterK, byte[] masterS, SrtpPolic /** * Close the crypto context. - * - * The close functions deletes key data and performs a cleanup of the + * + * The close functions deletes key data and performs a cleanup of the * crypto context. - * + * * Clean up key data, maybe this is the second time. However, sometimes * we cannot know if the CryptoContext was used and the application called * deriveSrtpKeys(...) that would have cleaned the key data. - * + * */ public void Close() { @@ -251,7 +251,7 @@ public void Close() /** * Get the authentication tag length of this SRTP cryptographic context - * + * * @return the authentication tag length of this SRTP cryptographic context */ public int GetAuthTagLength() @@ -261,7 +261,7 @@ public int GetAuthTagLength() /** * Get the MKI length of this SRTP cryptographic context - * + * * @return the MKI length of this SRTP cryptographic context */ public int GetMKILength() @@ -285,20 +285,20 @@ public long GetSSRC() } /** - * Transform a RTP packet into a SRTP packet. + * Transform a RTP packet into a SRTP packet. * This method is called when a normal RTP packet ready to be sent. - * + * * Operations done by the transformation may include: encryption, using * either Counter Mode encryption, or F8 Mode encryption, adding * authentication tag, currently HMC SHA1 method. - * + * * Both encryption and authentication functionality can be turned off * as long as the SRTPPolicy used in this SRTPCryptoContext is requires no * encryption and no authentication. Then the packet will be sent out * untouched. However this is not encouraged. If no SRTP feature is enabled, * then we shall not use SRTP TransformConnector. We should use the original - * method (RTPManager managed transportation) instead. - * + * method (RTPManager managed transportation) instead. + * * @param pkt the RTP packet that is going to be sent out */ public void TransformPacket(RawPacket pkt) @@ -341,20 +341,20 @@ public void TransformPacket(RawPacket pkt) /** * Transform a SRTCP packet into a RTCP packet. * This method is called when a SRTCP packet was received. - * + * * Operations done by the this operation include: * Authentication check, Packet replay check and decryption. - * + * * Both encryption and authentication functionality can be turned off * as long as the SRTPPolicy used in this SRTPCryptoContext requires no * encryption and no authentication. Then the packet will be sent out * untouched. However this is not encouraged. If no SRTCP feature is enabled, * then we shall not use SRTP TransformConnector. We should use the original - * method (RTPManager managed transportation) instead. - * - * @param pkt the received RTCP packet + * method (RTPManager managed transportation) instead. + * + * @param pkt the received RTCP packet * @return true if the packet can be accepted - * false if authentication or replay check failed + * false if authentication or replay check failed */ public bool ReverseTransformPacket(RawPacket pkt) { @@ -421,7 +421,7 @@ public bool ReverseTransformPacket(RawPacket pkt) } /** - * Perform Counter Mode AES encryption / decryption + * Perform Counter Mode AES encryption / decryption * @param pkt the RTP packet to be encrypted / decrypted */ public void ProcessPacketAESCM(RawPacket pkt, int index) @@ -429,14 +429,14 @@ public void ProcessPacketAESCM(RawPacket pkt, int index) long ssrc = pkt.GetRTCPSSRC(); /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711): - * - * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX - * SSRC XX XX XX XX - * index XX XX XX XX - * ------------------------------------------------------XOR - * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00 - * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - */ + * + * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX + * SSRC XX XX XX XX + * index XX XX XX XX + * ------------------------------------------------------XOR + * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00 + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + */ ivStore[0] = saltKey[0]; ivStore[1] = saltKey[1]; ivStore[2] = saltKey[2]; @@ -505,7 +505,7 @@ public void ProcessPacketAESF8(RawPacket pkt, int index) /** * Authenticate a packet. - * + * * Calculated authentication tag is stored in tagStore area. * * @param pkt the RTP packet to be authenticated @@ -528,13 +528,13 @@ private void AuthenticatePacket(RawPacket pkt, int index) /** * Checks if a packet is a replayed on based on its sequence number. - * + * * This method supports a 64 packet history relative to the given * sequence number. * - * Sequence Number is guaranteed to be real (not faked) through + * Sequence Number is guaranteed to be real (not faked) through * authentication. - * + * * @param index index number of the SRTCP packet * @return true if this sequence number indicates the packet is not a * replayed one, false if not @@ -576,8 +576,8 @@ bool CheckReplay(int index) /** * Compute the initialization vector, used later by encryption algorithms, * based on the label. - * - * @param label label specified for each type of iv + * + * @param label label specified for each type of iv */ private void ComputeIv(byte label) { @@ -592,7 +592,7 @@ private void ComputeIv(byte label) /** * Derives the srtcp session keys from the master key. - * + * */ public void DeriveSrtcpKeys() { @@ -646,9 +646,9 @@ public void DeriveSrtcpKeys() /** * Update the SRTP packet index. - * - * This method is called after all checks were successful. - * + * + * This method is called after all checks were successful. + * * @param index index number of the accepted packet */ private void Update(int index) @@ -673,16 +673,16 @@ private void Update(int index) /** * Derive a new SRTPCryptoContext for use with a new SSRC - * + * * This method returns a new SRTPCryptoContext initialized with the data of * this SRTPCryptoContext. Replacing the SSRC, Roll-over-Counter, and the * key derivation rate the application cab use this SRTPCryptoContext to * encrypt / decrypt a new stream (Synchronization source) inside one RTP * session. - * + * * Before the application can use this SRTPCryptoContext it must call the * deriveSrtpKeys method. - * + * * @param ssrc * The SSRC for this context * @return a new SRTPCryptoContext with all relevant data set. diff --git a/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherCTR.cs b/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherCTR.cs index f9b20939..64f26dbc 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherCTR.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherCTR.cs @@ -36,27 +36,27 @@ /** * SRTPCipherF8 implements SRTP F8 Mode AES Encryption (AES-f8). * F8 Mode AES Encryption algorithm is defined in RFC3711, section 4.1.2. - * + * * Other than Null Cipher, RFC3711 defined two encryption algorithms: * Counter Mode AES Encryption and F8 Mode AES encryption. Both encryption * algorithms are capable to encrypt / decrypt arbitrary length data, and the - * size of packet data is not required to be a multiple of the AES block + * size of packet data is not required to be a multiple of the AES block * size (128bit). So, no padding is needed. - * + * * Please note: these two encryption algorithms are specially defined by SRTP. - * They are not common AES encryption modes, so you will not be able to find a - * replacement implementation in common cryptographic libraries. - * + * They are not common AES encryption modes, so you will not be able to find a + * replacement implementation in common cryptographic libraries. + * * As defined by RFC3711: F8 mode encryption is optional. * * mandatory to impl optional default * ------------------------------------------------------------------------- * encryption AES-CM, NULL AES-f8 AES-CM * message integrity HMAC-SHA1 - HMAC-SHA1 - * key derivation (PRF) AES-CM - AES-CM + * key derivation (PRF) AES-CM - AES-CM * * We use AESCipher to handle basic AES encryption / decryption. - * + * * @author Bing SU (nova.su@gmail.com) * @author Werner Dittmann */ @@ -70,16 +70,16 @@ namespace SIPSorcery.Net /** * SRTPCipherCTR implements SRTP Counter Mode AES Encryption (AES-CM). * Counter Mode AES Encryption algorithm is defined in RFC3711, section 4.1.1. - * + * * Other than Null Cipher, RFC3711 defined two two encryption algorithms: * Counter Mode AES Encryption and F8 Mode AES encryption. Both encryption * algorithms are capable to encrypt / decrypt arbitrary length data, and the - * size of packet data is not required to be a multiple of the AES block + * size of packet data is not required to be a multiple of the AES block * size (128bit). So, no padding is needed. - * + * * Please note: these two encryption algorithms are specially defined by SRTP. - * They are not common AES encryption modes, so you will not be able to find a - * replacement implementation in common cryptographic libraries. + * They are not common AES encryption modes, so you will not be able to find a + * replacement implementation in common cryptographic libraries. * * As defined by RFC3711: Counter Mode Encryption is mandatory.. * @@ -87,10 +87,10 @@ namespace SIPSorcery.Net * ------------------------------------------------------------------------- * encryption AES-CM, NULL AES-f8 AES-CM * message integrity HMAC-SHA1 - HMAC-SHA1 - * key derivation (PRF) AES-CM - AES-CM + * key derivation (PRF) AES-CM - AES-CM * * We use AESCipher to handle basic AES encryption / decryption. - * + * * @author Werner Dittmann (Werner.Dittmann@t-online.de) * @author Bing SU (nova.su@gmail.com) */ @@ -134,7 +134,7 @@ public void Process(IBlockCipher cipher, MemoryStream data, int off, int len, by /** * Computes the cipher stream for AES CM mode. See section 4.1.1 in RFC3711 * for detailed description. - * + * * @param out * byte array holding the output cipher stream * @param length diff --git a/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherF8.cs b/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherF8.cs index d855f51b..dce1b201 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherF8.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/SrtpCipherF8.cs @@ -36,27 +36,27 @@ /** * SRTPCipherF8 implements SRTP F8 Mode AES Encryption (AES-f8). * F8 Mode AES Encryption algorithm is defined in RFC3711, section 4.1.2. - * + * * Other than Null Cipher, RFC3711 defined two two encryption algorithms: * Counter Mode AES Encryption and F8 Mode AES encryption. Both encryption * algorithms are capable to encrypt / decrypt arbitrary length data, and the - * size of packet data is not required to be a multiple of the AES block + * size of packet data is not required to be a multiple of the AES block * size (128bit). So, no padding is needed. - * + * * Please note: these two encryption algorithms are specially defined by SRTP. - * They are not common AES encryption modes, so you will not be able to find a - * replacement implementation in common cryptographic libraries. - * + * They are not common AES encryption modes, so you will not be able to find a + * replacement implementation in common cryptographic libraries. + * * As defined by RFC3711: F8 mode encryption is optional. * * mandatory to impl optional default * ------------------------------------------------------------------------- * encryption AES-CM, NULL AES-f8 AES-CM * message integrity HMAC-SHA1 - HMAC-SHA1 - * key derivation (PRF) AES-CM - AES-CM + * key derivation (PRF) AES-CM - AES-CM * * We use AESCipher to handle basic AES encryption / decryption. - * + * * @author Bing SU (nova.su@gmail.com) * @author Werner Dittmann */ @@ -162,7 +162,7 @@ public static void Process(IBlockCipher cipher, MemoryStream data, int off, int /** * Encrypt / Decrypt a block using F8 Mode AES algorithm, read len bytes * data from in at inOff and write the output into out at outOff - * + * * @param f8ctx * F8 encryption context * @param in @@ -189,7 +189,7 @@ public static void ProcessBlock(IBlockCipher cipher, F8Context f8ctx, } /* - * Now XOR (S(n-1) xor IV') with the current counter, then increment + * Now XOR (S(n-1) xor IV') with the current counter, then increment * the counter */ f8ctx.S[12] ^= (byte)(f8ctx.J >> 24); diff --git a/SipSorcery/net/DtlsSrtp/Transform/SrtpCryptoContext.cs b/SipSorcery/net/DtlsSrtp/Transform/SrtpCryptoContext.cs index 0f6904e6..2cc6d2ec 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/SrtpCryptoContext.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/SrtpCryptoContext.cs @@ -53,30 +53,30 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ + */ /** * SRTPCryptoContext class is the core class of SRTP implementation. There can * be multiple SRTP sources in one SRTP session. And each SRTP stream has a * corresponding SRTPCryptoContext object, identified by SSRC. In this way, * different sources can be protected independently. - * + * * SRTPCryptoContext class acts as a manager class and maintains all the * information used in SRTP transformation. It is responsible for deriving * encryption keys / salting keys / authentication keys from master keys. And it * will invoke certain class to encrypt / decrypt (transform / reverse * transform) RTP packets. It will hold a replay check db and do replay check * against incoming packets. - * + * * Refer to section 3.2 in RFC3711 for detailed description of cryptographic * context. - * + * * Cryptographic related parameters, i.e. encryption mode / authentication mode, * master encryption key and master salt key are determined outside the scope of * SRTP implementation. They can be assigned manually, or can be assigned * automatically using some key management protocol, such as MIKEY (RFC3830), * SDES (RFC4568) or Phil Zimmermann's ZRTP protocol (RFC6189). - * + * * @author Bing SU (nova.su@gmail.com) */ @@ -212,7 +212,7 @@ public class SrtpCryptoContext /** * Construct an empty SRTPCryptoContext using ssrc. The other parameters are * set to default null value. - * + * * @param ssrcIn * SSRC of this SRTPCryptoContext */ @@ -236,7 +236,7 @@ public SrtpCryptoContext(long ssrcIn) /** * Construct a normal SRTPCryptoContext based on the given parameters. - * + * * @param ssrcIn * the RTP SSRC that this SRTP cryptographic context protects. * @param rocIn @@ -336,14 +336,14 @@ public SrtpCryptoContext(long ssrcIn, int rocIn, long kdr, byte[] masterK, /** * Close the crypto context. - * + * * The close functions deletes key data and performs a cleanup of the crypto * context. - * + * * Clean up key data, maybe this is the second time however, sometimes we * cannot know if the CryptoCOntext was used and the application called * deriveSrtpKeys(...) . - * + * */ public void Close() { @@ -353,7 +353,7 @@ public void Close() /** * Get the authentication tag length of this SRTP cryptographic context - * + * * @return the authentication tag length of this SRTP cryptographic context */ public int GetAuthTagLength() @@ -363,7 +363,7 @@ public int GetAuthTagLength() /** * Get the MKI length of this SRTP cryptographic context - * + * * @return the MKI length of this SRTP cryptographic context */ public int GetMKILength() @@ -373,7 +373,7 @@ public int GetMKILength() /** * Get the SSRC of this SRTP cryptographic context - * + * * @return the SSRC of this SRTP cryptographic context */ public long GetSSRC() @@ -383,7 +383,7 @@ public long GetSSRC() /** * Get the Roll-Over-Counter of this SRTP cryptographic context - * + * * @return the Roll-Over-Counter of this SRTP cryptographic context */ public int GetROC() @@ -393,7 +393,7 @@ public int GetROC() /** * Set the Roll-Over-Counter of this SRTP cryptographic context - * + * * @param rocIn * the Roll-Over-Counter of this SRTP cryptographic context */ @@ -405,18 +405,18 @@ public void SetROC(int rocIn) /** * Transform a RTP packet into a SRTP packet. This method is called when a * normal RTP packet ready to be sent. - * + * * Operations done by the transformation may include: encryption, using * either Counter Mode encryption, or F8 Mode encryption, adding * authentication tag, currently HMC SHA1 method. - * + * * Both encryption and authentication functionality can be turned off as * long as the SRTPPolicy used in this SRTPCryptoContext is requires no * encryption and no authentication. Then the packet will be sent out * untouched. However this is not encouraged. If no SRTP feature is enabled, * then we shall not use SRTP TransformConnector. We should use the original * method (RTPManager managed transportation) instead. - * + * * @param pkt * the RTP packet that is going to be sent out */ @@ -451,17 +451,17 @@ public void TransformPacket(RawPacket pkt) /** * Transform a SRTP packet into a RTP packet. This method is called when a * SRTP packet is received. - * + * * Operations done by the this operation include: Authentication check, * Packet replay check and Decryption. - * + * * Both encryption and authentication functionality can be turned off as * long as the SRTPPolicy used in this SRTPCryptoContext requires no * encryption and no authentication. Then the packet will be sent out * untouched. However this is not encouraged. If no SRTP feature is enabled, * then we shall not use SRTP TransformConnector. We should use the original * method (RTPManager managed transportation) instead. - * + * * @param pkt * the RTP packet that is just received * @return true if the packet can be accepted false if the packet failed @@ -533,7 +533,7 @@ public bool ReverseTransformPacket(RawPacket pkt) /** * Perform Counter Mode AES encryption / decryption - * + * * @param pkt * the RTP packet to be encrypted / decrypted */ @@ -571,7 +571,7 @@ public void ProcessPacketAESCM(RawPacket pkt) /** * Perform F8 Mode AES encryption / decryption - * + * * @param pkt * the RTP packet to be encrypted / decrypted */ @@ -599,7 +599,7 @@ public void ProcessPacketAESF8(RawPacket pkt) /** * Authenticate a packet. Calculated authentication tag is returned. - * + * * @param pkt * the RTP packet to be authenticated * @param rocIn @@ -622,13 +622,13 @@ private void AuthenticatePacketHMCSHA1(RawPacket pkt, int rocIn) /** * Checks if a packet is a replayed on based on its sequence number. - * + * * This method supports a 64 packet history relative the the given sequence * number. - * + * * Sequence Number is guaranteed to be real (not faked) through * authentication. - * + * * @param seqNo * sequence number of the packet * @param guessedIndex @@ -677,7 +677,7 @@ bool CheckReplay(int seqNo, long guessedIndex) * Compute the initialization vector, used later by encryption algorithms, * based on the lable, the packet index, key derivation rate and master salt * key. - * + * * @param label * label specified for each type of iv * @param index @@ -711,7 +711,7 @@ private void ComputeIv(long label, long index) /** * Derives the srtp session keys from the master key - * + * * @param index * the 48 bit SRTP packet index */ @@ -768,7 +768,7 @@ public void DeriveSrtpKeys(long index) /** * Compute (guess) the new SRTP index based on the sequence number of a * received RTP packet. - * + * * @param seqNo * sequence number of the received RTP packet * @return the new SRTP packet index @@ -805,10 +805,10 @@ private long GuessIndex(int seqNo) /** * Update the SRTP packet index. - * + * * This method is called after all checks were successful. See section 3.3.1 * in RFC3711 for detailed description. - * + * * @param seqNo * sequence number of the accepted packet * @param guessedIndex @@ -847,16 +847,16 @@ private void Update(int seqNo, long guessedIndex) /** * Derive a new SRTPCryptoContext for use with a new SSRC - * + * * This method returns a new SRTPCryptoContext initialized with the data of * this SRTPCryptoContext. Replacing the SSRC, Roll-over-Counter, and the * key derivation rate the application cab use this SRTPCryptoContext to * encrypt / decrypt a new stream (Synchronization source) inside one RTP * session. - * + * * Before the application can use this SRTPCryptoContext it must call the * deriveSrtpKeys method. - * + * * @param ssrc * The SSRC for this context * @param roc diff --git a/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformEngine.cs b/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformEngine.cs index 3b34c8f5..448d1022 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformEngine.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformEngine.cs @@ -25,9 +25,9 @@ namespace SIPSorcery.Net public class SrtpTransformEngine : ITransformEngine { /** - * The default SRTPCryptoContext, which will be used to derivate other - * contexts. - */ + * The default SRTPCryptoContext, which will be used to derivate other + * contexts. + */ private SrtpCryptoContext defaultContext; /** @@ -39,7 +39,7 @@ public class SrtpTransformEngine : ITransformEngine /** * Construct a SRTPTransformEngine based on given master encryption key, * master salt key and SRTP/SRTCP policy. - * + * * @param masterKey * the master encryption key * @param masterSalt @@ -57,7 +57,7 @@ public SrtpTransformEngine(byte[] masterKey, byte[] masterSalt, SrtpPolicy srtpP /** * Close the transformer engine. - * + * * The close functions closes all stored default crypto contexts. This * deletes key data and forces a cleanup of the crypto contexts. */ @@ -78,7 +78,7 @@ public void Close() /** * Gets the PacketTransformer for RTCP packets. - * + * * @return the PacketTransformer for RTCP packets */ public IPacketTransformer GetRTCPTransformer() @@ -88,7 +88,7 @@ public IPacketTransformer GetRTCPTransformer() /* * (non-Javadoc) - * + * * @see net.java.sip.communicator.impl.media.transform. * TransformEngine#getRTPTransformer() */ @@ -99,7 +99,7 @@ public IPacketTransformer GetRTPTransformer() /** * Get the default SRTPCryptoContext - * + * * @return the default SRTPCryptoContext */ public SrtpCryptoContext GetDefaultContext() @@ -109,7 +109,7 @@ public SrtpCryptoContext GetDefaultContext() /** * Get the default SRTPCryptoContext - * + * * @return the default SRTPCryptoContext */ public SrtcpCryptoContext GetDefaultContextControl() diff --git a/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformer.cs b/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformer.cs index 83b9d377..202e9b9e 100644 --- a/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformer.cs +++ b/SipSorcery/net/DtlsSrtp/Transform/SrtpTransformer.cs @@ -20,23 +20,23 @@ //----------------------------------------------------------------------------- /** -* +* * Code derived and adapted from the Jitsi client side SRTP framework. -* +* * Distributed under LGPL license. * See terms of license at gnu.org. */ /** * SRTPTransformer implements PacketTransformer and provides implementations for * RTP packet to SRTP packet transformation and SRTP packet to RTP packet * transformation logic. -* +* * It will first find the corresponding SRTPCryptoContext for each packet based * on their SSRC and then invoke the context object to perform the * transformation and reverse transformation operation. -* +* * @author Bing SU (nova.su@gmail.com) * @author Rafael Soares (raf.csoares@kyubinteractive.com) -* +* */ using System.Collections.Concurrent; @@ -54,8 +54,8 @@ public class SrtpTransformer : IPacketTransformer private SrtpTransformEngine reverseEngine; /** - * All the known SSRC's corresponding SRTPCryptoContexts - */ + * All the known SSRC's corresponding SRTPCryptoContexts + */ private ConcurrentDictionary contexts; public SrtpTransformer(SrtpTransformEngine engine) : this(engine, engine) @@ -116,7 +116,7 @@ public byte[] Transform(byte[] pkt, int offset, int length) /** * Reverse-transforms a specific packet (i.e. transforms a transformed * packet back). - * + * * @param pkt * the transformed packet to be restored * @return the restored packet @@ -167,7 +167,7 @@ public byte[] ReverseTransform(byte[] pkt, int offset, int length) /** * Close the transformer and underlying transform engine. - * + * * The close functions closes all stored crypto contexts. This deletes key * data and forces a cleanup of the crypto contexts. */ diff --git a/SipSorcery/net/RTCP/RTCPFeedback.cs b/SipSorcery/net/RTCP/RTCPFeedback.cs index afd4638d..776a9818 100644 --- a/SipSorcery/net/RTCP/RTCPFeedback.cs +++ b/SipSorcery/net/RTCP/RTCPFeedback.cs @@ -696,9 +696,9 @@ correct reference picture can be used.As this reference picture is picture will use more bits. Both MPEG - 4 and H.263 define a binary format for the "payload" of an - + RPSI message that includes information such as the temporal ID of the - + damaged picture and the size of the damaged region.This bit string is typically small (a couple of dozen bits), of variable length, and self - contained, i.e., contains all information that is necessary to diff --git a/SipSorcery/net/RTSP/Mjpeg.cs b/SipSorcery/net/RTSP/Mjpeg.cs index 3092b2b4..feef8e6a 100644 --- a/SipSorcery/net/RTSP/Mjpeg.cs +++ b/SipSorcery/net/RTSP/Mjpeg.cs @@ -9,37 +9,37 @@ // License: /* This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/ - + Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com) -Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, +Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, * including without limitation the rights to : - * use, - * copy, - * modify, - * merge, - * publish, - * distribute, - * sublicense, - * and/or sell copies of the Software, + * use, + * copy, + * modify, + * merge, + * publish, + * distribute, + * sublicense, + * and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * + * + * * JuliusFriedman@gmail.com should be contacted for further details. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, - * ARISING FROM, +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, + * ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * + * * v// */ //----------------------------------------------------------------------------- diff --git a/SipSorcery/net/SDP/SDPSecurityDescription.cs b/SipSorcery/net/SDP/SDPSecurityDescription.cs index b131f4f6..b62549aa 100644 --- a/SipSorcery/net/SDP/SDPSecurityDescription.cs +++ b/SipSorcery/net/SDP/SDPSecurityDescription.cs @@ -663,30 +663,30 @@ public ulong Kdr set { /*if(value < 1 || value > Math.Pow(2, 24)) - throw new ArgumentOutOfRangeException("Kdr", "Kdr must be power of 2 and less than 2^24"); - ulong ul = value; - for(int i = 0; i < 64; i++) - { - if((ul & 0x1) == 0x1) - { - if(i == 0)//2^0 wollen wir nicht - throw new ArgumentOutOfRangeException("Kdr", "Kdr must be power of 2 and less than 2^24"); - else - { - ul = ul >> 1; - break; - } - } - else - { - ul = ul >> 1; - } - } - if(ul == 0) - this.m_kdr = value; - else - throw new ArgumentOutOfRangeException("Kdr", "Kdr must be power of 2 and less than 2^24"); - */ + throw new ArgumentOutOfRangeException("Kdr", "Kdr must be power of 2 and less than 2^24"); + ulong ul = value; + for(int i = 0; i < 64; i++) + { + if((ul & 0x1) == 0x1) + { + if(i == 0)//2^0 wollen wir nicht + throw new ArgumentOutOfRangeException("Kdr", "Kdr must be power of 2 and less than 2^24"); + else + { + ul = ul >> 1; + break; + } + } + else + { + ul = ul >> 1; + } + } + if(ul == 0) + this.m_kdr = value; + else + throw new ArgumentOutOfRangeException("Kdr", "Kdr must be power of 2 and less than 2^24"); + */ if (value < 0 || value > 24) { throw new ArgumentOutOfRangeException("Kdr", "Kdr must be between 0 and 24"); diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/BSDHardwareInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/BSDHardwareInfo.cs index cb22528a..1ee47e90 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/BSDHardwareInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/BSDHardwareInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System.Collections.Generic; using SystemInfoLibrary.Hardware.CPU; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/HardwareInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/HardwareInfo.cs index cca06822..61a09009 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/HardwareInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/HardwareInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System.Collections.Generic; using SystemInfoLibrary.Hardware.CPU; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/LinuxHardwareInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/LinuxHardwareInfo.cs index d95885bb..a5a63be2 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/LinuxHardwareInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/LinuxHardwareInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System.Collections.Generic; using System.Linq; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/MacOSXHardwareInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/MacOSXHardwareInfo.cs index a7b53740..e5e4f067 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/MacOSXHardwareInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Hardware/MacOSXHardwareInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System; using System.Collections.Generic; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/BSDOperatingSystemInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/BSDOperatingSystemInfo.cs index 652a59b0..a7448766 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/BSDOperatingSystemInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/BSDOperatingSystemInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using SystemInfoLibrary.Hardware; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/LinuxOperatingSystemInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/LinuxOperatingSystemInfo.cs index 83c2bf4e..7afb1962 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/LinuxOperatingSystemInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/LinuxOperatingSystemInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System; using System.Text.RegularExpressions; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/MacOSXOperatingSystemInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/MacOSXOperatingSystemInfo.cs index 75e7c5db..6db57d06 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/MacOSXOperatingSystemInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/MacOSXOperatingSystemInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using SystemInfoLibrary.Hardware; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/OperatingSystemInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/OperatingSystemInfo.cs index c5ac4346..337e93ad 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/OperatingSystemInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/OperatingSystemInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System; using System.Runtime.InteropServices; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/UnixOperatingSystemInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/UnixOperatingSystemInfo.cs index c0128b61..0bf162fb 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/UnixOperatingSystemInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/UnixOperatingSystemInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System; using System.Text.RegularExpressions; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/WindowsOperatingSystemInfo.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/WindowsOperatingSystemInfo.cs index b8814356..640c938c 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/WindowsOperatingSystemInfo.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/OperatingSystem/WindowsOperatingSystemInfo.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System; using System.Linq; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Utils.cs b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Utils.cs index 5d04a36e..dec9545d 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Utils.cs +++ b/SystemInfoLibrary/src/SystemInfoLibrary.NetFX/Utils.cs @@ -1,20 +1,20 @@ /* * Little Software Stats - .NET Library * Copyright (C) 2008-2012 Little Apps (http://www.little-apps.org) - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ using System; using System.Diagnostics; diff --git a/SystemInfoLibrary/src/SystemInfoLibrary.Standard/SystemInfoLibrary.Standard.csproj b/SystemInfoLibrary/src/SystemInfoLibrary.Standard/SystemInfoLibrary.Standard.csproj index 47de8827..f214d27a 100644 --- a/SystemInfoLibrary/src/SystemInfoLibrary.Standard/SystemInfoLibrary.Standard.csproj +++ b/SystemInfoLibrary/src/SystemInfoLibrary.Standard/SystemInfoLibrary.Standard.csproj @@ -62,7 +62,7 @@ - + diff --git a/Test_LibSystemInfo/Program.cs b/Test_LibSystemInfo/Program.cs index 2529237a..857600ee 100644 --- a/Test_LibSystemInfo/Program.cs +++ b/Test_LibSystemInfo/Program.cs @@ -1,5 +1,8 @@ using System; +using System.Security.Cryptography; +using System.Text; using System.Threading; +using LibCommon; using LibCommon.Structs; using LibSystemInfo; using Newtonsoft.Json; @@ -9,11 +12,39 @@ namespace Test_LibSystemInfo { class Program { + public static string MD5Encrypt32(string source) + + { + string rule = ""; + + MD5 md5 = MD5.Create(); + + byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(source)); + + // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得 + + for (int i = 0; i < s.Length; i++) + + { + rule = rule + s[i].ToString("x2"); // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 + } + + + return rule; + } + + public static PerformanceInfo KeeperPerformanceInfo = new PerformanceInfo(); private static SystemInfo _keeperSystemInfo = new SystemInfo(); static void Main(string[] args) { + Console.WriteLine(MD5Encrypt32("defaultuser:default:defaultpasswd")); + return; + + Console.WriteLine(UtilsHelper.DirAreMounttedAndWriteableForLinux("/home/disk/record/record/rtsp/E56A7514")); + + while (true) { KeeperPerformanceInfo = _keeperSystemInfo.GetSystemInfoObject(); diff --git a/Test_LibSystemInfo/Test_LibSystemInfo.csproj b/Test_LibSystemInfo/Test_LibSystemInfo.csproj index 0c9b5d24..818cd9a9 100644 --- a/Test_LibSystemInfo/Test_LibSystemInfo.csproj +++ b/Test_LibSystemInfo/Test_LibSystemInfo.csproj @@ -12,7 +12,7 @@ - + diff --git a/deploy.sh b/deploy.sh index e65cba88..5aedbe57 100644 --- a/deploy.sh +++ b/deploy.sh @@ -88,7 +88,8 @@ if [ "$ACTION" == deploy-keeper ]; then -v ./AKStreamKeeper/Config/logconfig.xml:/root/AKStreamKeeper/Config/logconfig.xml \ --name=$APP_KEEPER_NAME \ --restart=always \ - -d $APP_KEEPER_NAME + -d $APP_KEEPER_NAME \ + dotnet AKStreamKeeper.dll fi if [ "$ACTION" == run-keeper ]; then @@ -109,7 +110,8 @@ if [ "$ACTION" == run-keeper ]; then -v ./AKStreamKeeper/Config/logconfig.xml:/root/AKStreamKeeper/Config/logconfig.xml \ --name=$APP_KEEPER_NAME \ --restart=always \ - -d $APP_KEEPER_NAME + -d $APP_KEEPER_NAME \ + dotnet AKStreamKeeper.dll fi