You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
692 lines
28 KiB
692 lines
28 KiB
using Application.Domain.Entities;
|
|
using Infrastructure.Data;
|
|
using Infrastructure.Extensions;
|
|
using IoT.Shared.Application.Models;
|
|
using IoT.Shared.Services;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace IoTNode.DeviceServices.Onvif
|
|
{
|
|
public class OnvifService : BaseDeviceService, IDisposable
|
|
{
|
|
private bool isDisposed;
|
|
|
|
private readonly ConcurrentDictionary<string, Process> _list = new ConcurrentDictionary<string, Process>();
|
|
|
|
private readonly ILogger<OnvifService> _logger;
|
|
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
|
|
private readonly IOnvifDeviceManagement _onvifDeviceManagement;
|
|
|
|
public OnvifService(IServiceProvider applicationServices, ILogger<OnvifService> logger, IWebHostEnvironment env, IHttpClientFactory httpClientFactory, IOnvifDeviceManagement onvifDeviceManagement)
|
|
: base(applicationServices, env)
|
|
{
|
|
this._logger = logger;
|
|
this._httpClientFactory = httpClientFactory;
|
|
this._onvifDeviceManagement = onvifDeviceManagement;
|
|
}
|
|
|
|
public override void Execute()
|
|
{
|
|
try
|
|
{
|
|
Search();
|
|
Notify();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
|
|
public override Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
Stop();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void Stop()
|
|
{
|
|
this._logger.LogDebug("OnvifService>Onvif Service Dispose");
|
|
try
|
|
{
|
|
foreach (var item in this._list.Keys.ToList())
|
|
{
|
|
try
|
|
{
|
|
this.StopPushToServer(item);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
this._logger.LogError(ex.ToString());
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
this._logger.LogError(ex.ToString());
|
|
}
|
|
finally
|
|
{
|
|
this._logger.LogDebug($"{this.GetType().Name} Service Stopd");
|
|
}
|
|
}
|
|
|
|
public void Search()
|
|
{
|
|
try
|
|
{
|
|
var list = this._onvifDeviceManagement.Discovery();
|
|
this.UpdateOnlineStatus(list.Select(o=>o.Id).ToList());
|
|
foreach (var ipCamera in list)
|
|
{
|
|
if (string.IsNullOrEmpty(ipCamera.Id) || string.IsNullOrEmpty(ipCamera.DeviceUrl))
|
|
{
|
|
continue;
|
|
}
|
|
var writeList = GetSetting("camera.writelist");
|
|
if (!string.IsNullOrEmpty(writeList))
|
|
{
|
|
var snList = writeList.Split(',');
|
|
if (!snList.Contains(ipCamera.Id))
|
|
{
|
|
this._logger.LogDebug($"skip {ipCamera.Id} because it isn't contains by writelist");
|
|
continue;
|
|
}
|
|
}
|
|
this._logger.LogDebug(ipCamera.DeviceUrl);
|
|
try
|
|
{
|
|
using var scope = _applicationServices.CreateScope();
|
|
var iotNodeClient = scope.ServiceProvider.GetService<IoTNodeClient>();
|
|
var productNumber = "onvifcamera";
|
|
|
|
var productRepo = scope.ServiceProvider.GetService<IRepository<IoTProduct>>();
|
|
var product = this.UpdateProduct("摄像头", productNumber, "/Onvif/", "camera");
|
|
|
|
var deviceNodeRepo = scope.ServiceProvider.GetService<IRepository<IoTGateway>>();
|
|
var node = deviceNodeRepo.ReadOnlyTable().FirstOrDefault();
|
|
|
|
var deviceRepo = scope.ServiceProvider.GetService<IRepository<IoTDevice>>();
|
|
var device = deviceRepo.Table().FirstOrDefault(o => o.Number == ipCamera.Id);
|
|
var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
if (device == null)
|
|
{
|
|
device = new IoTDevice
|
|
{
|
|
Name = "摄像头",
|
|
DisplayName = "摄像头",
|
|
Number = ipCamera.Id,
|
|
Ip = ipCamera.Ip,
|
|
Icon = "camera",
|
|
IsOnline = true,
|
|
IoTProductId = product.Id,
|
|
IoTGatewayId = node.Id
|
|
};
|
|
deviceRepo.Add(device);
|
|
}
|
|
else
|
|
{
|
|
device.Ip = ipCamera.Ip;
|
|
}
|
|
deviceRepo.SaveChanges();
|
|
this.UpdateIoTData(device.Id, DataKeys.DeviceUrl, ipCamera.DeviceUrl);
|
|
this.UpdateIoTData(device.Id, DataKeys.MediaUrl, ipCamera.MediaUrl);
|
|
this.UpdateIoTData(device.Id, DataKeys.PtzAddress, ipCamera.PTZAddress);
|
|
this.UpdateIoTData(device.Id, DataKeys.Ptz3DZoomSupport, ipCamera.Ptz3DZoomSupport ? "1" : "0");
|
|
|
|
var fileName = $"ffmpeg-{Helper.Instance.GetRunTime()}{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "")}";
|
|
var file = Path.Combine(this._env.WebRootPath, fileName);
|
|
this.AddIoTData(device.Id, DataKeys.Push, "是");
|
|
this.AddIoTData(device.Id, DataKeys.Record, "否");
|
|
this.UpdateIoTData(device.Id, DataKeys.FFmpegFile, file);
|
|
this.UpdateIoTData(device.Id, DataKeys.FFmpegArgs, GetSetting("ffmpeg.args"));
|
|
|
|
var profiles = this._onvifDeviceManagement.GetProfiles(ipCamera.DeviceUrl, ipCamera.MediaUrl);
|
|
var needAuth = false;
|
|
var hasAuth = false;
|
|
if (string.IsNullOrEmpty(profiles))
|
|
{
|
|
needAuth = true;
|
|
device.UserName ??= GetSetting("camera.usr");
|
|
device.Password ??= GetSetting("camera.pwd");
|
|
deviceRepo.SaveChanges();
|
|
profiles = this._onvifDeviceManagement.GetProfiles(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password);
|
|
if (string.IsNullOrEmpty(profiles))
|
|
{
|
|
hasAuth = false;
|
|
}
|
|
else
|
|
{
|
|
hasAuth = true;
|
|
ipCamera.GetProfilesXml = profiles;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipCamera.GetProfilesXml = profiles;
|
|
}
|
|
ipCamera.ParseProfiles();
|
|
try
|
|
{
|
|
if (ipCamera.Profiles.Count > 0)
|
|
{
|
|
var tokens = ipCamera.Profiles.ToJson();
|
|
this.UpdateIoTData(device.Id, DataKeys.Profiles, tokens);
|
|
var token = this.GetIoTDataValue(device.Id, DataKeys.ProfileToken);
|
|
if (string.IsNullOrEmpty(token)|| !ipCamera.Profiles.Any(o => o.Token == token))
|
|
{
|
|
token = (ipCamera.Profiles.FirstOrDefault(o=>o.Width==1280)??ipCamera.Profiles.First()).Token;
|
|
}
|
|
if (needAuth)
|
|
{
|
|
ipCamera.StreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, token);
|
|
ipCamera.SnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, token);
|
|
}
|
|
else
|
|
{
|
|
ipCamera.StreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, token);
|
|
ipCamera.SnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, token);
|
|
}
|
|
ipCamera.ParseStreamUri();
|
|
ipCamera.ParseSnapshotUri();
|
|
|
|
this.UpdateIoTData(device.Id, DataKeys.ProfileToken, token);
|
|
this.UpdateIoTData(device.Id, DataKeys.StreamUri, ipCamera.StreamUri);
|
|
this.UpdateIoTData(device.Id, DataKeys.SnapshotUri, ipCamera.SnapshotUri);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack(ex.Message);
|
|
}
|
|
this.UpdateIoTData(device.Id, DataKeys.NeedAuth, needAuth ? "是" : "否");
|
|
this.UpdateIoTData(device.Id, DataKeys.HasAuth, hasAuth ? "是" : "否");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
|
|
private void UpdateOnlineStatus(List<string> list)
|
|
{
|
|
using var scope = _applicationServices.CreateScope();
|
|
var repo = scope.ServiceProvider.GetService<IRepository<IoTDevice>>();
|
|
var devicesList = repo.Table().Where(o => o.Name == "摄像头").ToList();
|
|
foreach (var item in devicesList)
|
|
{
|
|
item.IsOnline = list.Any(o=>o==item.Number);
|
|
}
|
|
repo.SaveChanges();
|
|
}
|
|
|
|
public void Notify()
|
|
{
|
|
using var scope = _applicationServices.CreateScope();
|
|
var repo = scope.ServiceProvider.GetService<IRepository<IoTDevice>>();
|
|
var devicesList = repo.ReadOnlyTable().Where(o => o.Name == "摄像头").ToList();
|
|
foreach (var number in this._list.Keys)
|
|
{
|
|
var device = devicesList.FirstOrDefault(o => o.Number == number);
|
|
var remove = false;
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.Push) == "否")
|
|
{
|
|
remove = true;
|
|
}
|
|
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.NeedAuth) == "是" && this.GetIoTDataValue(device.Id, DataKeys.HasAuth) == "否")
|
|
{
|
|
remove = true;
|
|
}
|
|
if (remove)
|
|
{
|
|
this.StopPushToServer(number);
|
|
}
|
|
}
|
|
foreach (var device in devicesList)
|
|
{
|
|
try
|
|
{
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.Push) == "是")
|
|
{
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.NeedAuth) == "否" || this.GetIoTDataValue(device.Id, DataKeys.HasAuth) == "是")
|
|
{
|
|
this.StartPushToServer(device);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StartPushToServer()
|
|
{
|
|
using var scope = _applicationServices.CreateScope();
|
|
var repo = scope.ServiceProvider.GetService<IRepository<IoTDevice>>();
|
|
var devices = repo.ReadOnlyTable().Where(o => o.Name == "摄像头").ToList();
|
|
foreach (var device in devices)
|
|
{
|
|
try
|
|
{
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.Push) == "是")
|
|
{
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.NeedAuth) == "否" && this.GetIoTDataValue(device.Id, DataKeys.HasAuth) == "是")
|
|
{
|
|
this.StartPushToServer(device);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StartPushToServer(IoTDevice device)
|
|
{
|
|
try
|
|
{
|
|
if (!this._list.Any(o => o.Key == device.Number))
|
|
{
|
|
this.Add(device);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
|
|
public void Add(string key)
|
|
{
|
|
var device = this.GetIoTDevice(key);
|
|
if (device != null && this.GetIoTDataValue(device.Id,DataKeys.Push) == "是")
|
|
{
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.NeedAuth) == "否" || this.GetIoTDataValue(device.Id, DataKeys.HasAuth) == "是")
|
|
{
|
|
this.Add(device);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Add(IoTDevice device)
|
|
{
|
|
if (this._list.Any(o => o.Key == device.Number))
|
|
{
|
|
return;
|
|
}
|
|
var needAuth = this.GetIoTDataValue(device.Id, DataKeys.NeedAuth) == "是";
|
|
var hasAuth = this.GetIoTDataValue(device.Id, DataKeys.HasAuth) == "是";
|
|
var streamUri = this.GetIoTDataValue(device.Id, DataKeys.StreamUri);
|
|
var rtspUrl = $"rtsp://{(needAuth ? $"{device.UserName}:{device.Password}@" : "")}{streamUri.Substring(7)}";
|
|
var fileName = $"ffmpeg-{Helper.Instance.GetRunTime()}{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "")}";
|
|
var file = this.GetIoTDataValue(device.Id, DataKeys.FFmpegFile);
|
|
var rtmp = $"rtmp://{GetSetting("stream.rtmp")}/live/{device.Number}"; //camera.Data.FirstOrDefault(o => o.Key == "rtmp").Value;
|
|
this._logger.LogDebug(file);
|
|
var arguments = this.GetIoTDataValue(device.Id, DataKeys.FFmpegArgs);
|
|
Process process = null;
|
|
if (!string.IsNullOrEmpty(streamUri))
|
|
{
|
|
if (!string.IsNullOrEmpty(rtmp))
|
|
{
|
|
process = this.SetProcess(file, string.Format(arguments, Environment.ProcessorCount, rtspUrl, rtmp));
|
|
}
|
|
}
|
|
if (this._list.TryAdd(device.Number, process))
|
|
{
|
|
this._logger.LogDebug($"add {device.Number} to list");
|
|
}
|
|
else
|
|
{
|
|
if (process != null)
|
|
{
|
|
this.CloseProcess(process);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StopPushToServer()
|
|
{
|
|
foreach (var item in this._list.Keys)
|
|
{
|
|
try
|
|
{
|
|
this.StopPushToServer(item);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StopPushToServer(string key)
|
|
{
|
|
if (this._list.TryRemove(key, out Process process))
|
|
{
|
|
this._logger.LogDebug($"OnvifService>remove {key} from list");
|
|
this.CloseProcess(process);
|
|
}
|
|
}
|
|
|
|
private Process SetProcess(string file, string arguments)
|
|
{
|
|
this._logger.LogDebug(file);
|
|
this._logger.LogDebug(arguments);
|
|
var process = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
WorkingDirectory = this._env.WebRootPath,
|
|
FileName = file,
|
|
Arguments = arguments,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
RedirectStandardError = true
|
|
},
|
|
EnableRaisingEvents = true
|
|
};
|
|
process.Exited += (s, e) =>
|
|
{
|
|
var _process = s as Process;
|
|
this._logger.LogDebug($"ffmpeg processes list:{_list.Count},exit:{_process?.ExitCode},args:{arguments}");
|
|
if (_process != null)
|
|
{
|
|
Thread.Sleep(3000);
|
|
_process.CancelErrorRead();
|
|
_process.Start();
|
|
_process.BeginErrorReadLine();
|
|
}
|
|
};
|
|
process.ErrorDataReceived += (s, e) =>
|
|
{
|
|
if (!string.IsNullOrEmpty(e.Data))
|
|
{
|
|
if (GetSetting("debug") == "true")
|
|
{
|
|
this._logger.LogDebug(e.Data);
|
|
}
|
|
if (e.Data.IndexOf("forcing output") > -1)
|
|
{
|
|
process.Kill();
|
|
}
|
|
}
|
|
};
|
|
this._logger.LogDebug(arguments);
|
|
try
|
|
{
|
|
process.Start();
|
|
process.BeginErrorReadLine();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack($"start ffmpeg error:{ex.Message}");
|
|
}
|
|
return process;
|
|
}
|
|
|
|
private void CloseProcess(Process process)
|
|
{
|
|
this._logger.LogInformation($"close process:{process?.StartInfo?.FileName} with {process?.StartInfo?.Arguments}");
|
|
try
|
|
{
|
|
if (process != null)
|
|
{
|
|
process.EnableRaisingEvents = false;
|
|
process?.Kill();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack($"error when close ffmpeg process {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
process?.Dispose();
|
|
}
|
|
}
|
|
|
|
private string GetOnoce(string deviceUrl)
|
|
{
|
|
var message = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
|
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
|
<GetDeviceInformation xmlns=""http://www.onvif.org/ver10/device/wsdl""></GetDeviceInformation>
|
|
</s:Body>
|
|
</s:Envelope>";
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{MessageTemplate.GetDeviceInformationAction}\"");
|
|
var task = hc.PostAsync(deviceUrl, new StringContent(message));
|
|
var result = task.Result.Headers.WwwAuthenticate;
|
|
return Regex.Match(result.ToString(), "nonce=\"([^\"]+)\"").Groups[1].Value;
|
|
}
|
|
|
|
private string RequestXml(string url, string action, string body, string userName, string password, string onoce)
|
|
{
|
|
var nonce_b = Convert.FromBase64String(onoce);
|
|
var now = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ss.fffZ");
|
|
var creationtime_b = Encoding.ASCII.GetBytes(now);
|
|
var password_b = Encoding.ASCII.GetBytes(password);
|
|
var concatenation_b = new byte[nonce_b.Length + creationtime_b.Length + password_b.Length];
|
|
Buffer.BlockCopy(nonce_b, 0, concatenation_b, 0, nonce_b.Length);
|
|
Buffer.BlockCopy(creationtime_b, 0, concatenation_b, nonce_b.Length, creationtime_b.Length);
|
|
Buffer.BlockCopy(password_b, 0, concatenation_b, nonce_b.Length + creationtime_b.Length, password_b.Length);
|
|
var sha = new SHA1CryptoServiceProvider();
|
|
var pdresult = sha.ComputeHash(concatenation_b);
|
|
var passworddigest = Convert.ToBase64String(pdresult);
|
|
var message = string.Format(MessageTemplate.AuthTemplate, userName, passworddigest, Convert.ToBase64String(nonce_b), now, body);
|
|
var result = SoapRequest(url, action, message);
|
|
return result;
|
|
}
|
|
|
|
private string SoapRequest(string url, string action, string message)
|
|
{
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{action}\"");
|
|
var task = hc.PostAsync(url, new StringContent(message));
|
|
var result = task.Result.Content.ReadAsStringAsync().Result;
|
|
return result;
|
|
}
|
|
|
|
public void ChangeToken(string id,string token)
|
|
{
|
|
var device = this.GetIoTDevice(id);
|
|
if (device != null)
|
|
{
|
|
using var scope = _applicationServices.CreateScope();
|
|
var repo = scope.ServiceProvider.GetRequiredService<IRepository<IoTData>>();
|
|
var profiles = this.GetIoTDataValue(device.Id,DataKeys.Profiles);
|
|
if (!string.IsNullOrEmpty(profiles))
|
|
{
|
|
var tokens = profiles.FromJson<List<Profile>>();
|
|
if(tokens.Any(o=>o.Token==token))
|
|
{
|
|
var currentToken = this.GetIoTDataValue(device.Id, DataKeys.ProfileToken);
|
|
if (!string.IsNullOrEmpty(currentToken) && currentToken != token)
|
|
{
|
|
this.UpdateIoTData(device.Id, DataKeys.ProfileToken, token);
|
|
var deviceUrl = this.GetIoTDataValue(device.Id, DataKeys.DeviceUrl);
|
|
var mediaUrl = this.GetIoTDataValue(device.Id, DataKeys.MediaUrl);
|
|
if (!string.IsNullOrEmpty(deviceUrl) && !string.IsNullOrEmpty(mediaUrl))
|
|
{
|
|
var streamUriXml = this._onvifDeviceManagement.GetStreamUri(deviceUrl, mediaUrl, device.UserName, device.Password, token);
|
|
var snapshotUri = this._onvifDeviceManagement.GetSnapshotUri(deviceUrl, mediaUrl, device.UserName, device.Password, token);
|
|
var ipCamera = new IPCamera { StreamUriXml = streamUriXml, SnapshotUriXml = snapshotUri };
|
|
ipCamera.ParseStreamUri();
|
|
ipCamera.ParseSnapshotUri();
|
|
this.UpdateIoTData(device.Id, DataKeys.StreamUri, ipCamera.StreamUri);
|
|
this.UpdateIoTData(device.Id, DataKeys.SnapshotUri, ipCamera.SnapshotUri);
|
|
this.SetPush(device.Number, false);
|
|
this.SetPush(device.Number, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ZoomIn(string id, float speed)
|
|
{
|
|
this.Move(id, speed, 0, 0);
|
|
}
|
|
|
|
public void ZoomOut(string id, float speed)
|
|
{
|
|
this.Move(id, -speed, 0, 0);
|
|
}
|
|
|
|
public void Up(string id, float speed)
|
|
{
|
|
this.Move(id, 0, 0, speed);
|
|
}
|
|
|
|
public void Right(string id, float speed)
|
|
{
|
|
this.Move(id, 0, speed, 0);
|
|
}
|
|
|
|
public void Down(string id, float speed)
|
|
{
|
|
this.Move(id, 0, 0, -speed);
|
|
}
|
|
|
|
public void Left(string id, float speed)
|
|
{
|
|
this.Move(id, 0, -speed, 0);
|
|
}
|
|
|
|
public void Stop(string id)
|
|
{
|
|
var device = this.GetIoTDevice(id);
|
|
if (device != null)
|
|
{
|
|
var ptzAddress = this.GetIoTDataValue(device.Id, DataKeys.PtzAddress);
|
|
if (!string.IsNullOrEmpty(ptzAddress))
|
|
{
|
|
var deviceUrl = this.GetIoTDataValue(device.Id, DataKeys.DeviceUrl);
|
|
var onoce = (this._onvifDeviceManagement as OnvifDeviceManagement).GetOnoce(deviceUrl);
|
|
var token = this.GetIoTDataValue(device.Id, DataKeys.ProfileToken);
|
|
RequestXml(ptzAddress, MessageTemplate.StopAction, string.Format(MessageTemplate.StopMessage, token, true, true), device.UserName, device.Password, onoce);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Move(string id, float zx, float px, float py)
|
|
{
|
|
var device = this.GetIoTDevice(id);
|
|
if (device != null)
|
|
{
|
|
var ptzAddress = this.GetIoTDataValue(device.Id, DataKeys.PtzAddress);
|
|
if (!string.IsNullOrEmpty(ptzAddress))
|
|
{
|
|
var deviceUrl = this.GetIoTDataValue(device.Id, DataKeys.DeviceUrl);
|
|
var onoce = (this._onvifDeviceManagement as OnvifDeviceManagement).GetOnoce(deviceUrl);
|
|
var token = this.GetIoTDataValue(device.Id, DataKeys.ProfileToken);
|
|
RequestXml(ptzAddress, MessageTemplate.ContinuousMoveAction, String.Format(MessageTemplate.ContinuousMoveMessage, token, zx, px, py), device.UserName, device.Password, onoce);
|
|
}
|
|
}
|
|
}
|
|
|
|
public byte[] ScreenShot(string id)
|
|
{
|
|
var device = this.GetIoTDevice(id);
|
|
var url = this.GetIoTDataValue(device.Id, DataKeys.SnapshotUri);
|
|
if (!string.IsNullOrEmpty(url))
|
|
{
|
|
var hc = this._httpClientFactory.CreateClient();
|
|
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.NeedAuth) == "否")
|
|
{
|
|
return hc.GetByteArrayAsync(url).Result;
|
|
}
|
|
else
|
|
{
|
|
if (this.GetIoTDataValue(device.Id, DataKeys.HasAuth) == "是")
|
|
{
|
|
return hc.GetByteDigest(new Uri(url), device.UserName, device.Password);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Array.Empty<byte>();
|
|
}
|
|
|
|
public void SetPush(string number, bool state)
|
|
{
|
|
var device = this.GetIoTDevice(number);
|
|
if (device != null)
|
|
{
|
|
this.UpdateIoTData(device.Id, DataKeys.Push, state ? "是" : "否");
|
|
if (state)
|
|
{
|
|
this.StartPushToServer(device);
|
|
}
|
|
else
|
|
{
|
|
this.StopPushToServer(device.Number);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetRecord(string number, bool state)
|
|
{
|
|
using var scope = _applicationServices.CreateScope();
|
|
var repo = scope.ServiceProvider.GetService<IRepository<IoTDevice>>();
|
|
var device = repo.ReadOnlyTable().FirstOrDefault(o => o.Number == number);
|
|
if (device != null)
|
|
{
|
|
var data = this.UpdateIoTData(device.Id, DataKeys.Record, state ? "是" : "否");
|
|
var iotNodeClient = scope.ServiceProvider.GetService<IoTNodeClient>();
|
|
iotNodeClient.ClientToServer(Methods.UpdateDvr, data,null);
|
|
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (isDisposed) return;
|
|
|
|
if (disposing)
|
|
{
|
|
this.Stop();
|
|
}
|
|
isDisposed = true;
|
|
}
|
|
}
|
|
}
|