2024-02-22 16:43:59 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using SafeMobileLib;
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
|
|
|
|
namespace AppServer
|
|
|
|
|
{
|
|
|
|
|
class VoiceRecording
|
|
|
|
|
{
|
|
|
|
|
private string ip;
|
|
|
|
|
private int port;
|
|
|
|
|
private UdpMulticast udp4VoiceRecv;
|
|
|
|
|
private bool isRecording;
|
|
|
|
|
|
|
|
|
|
public bool IsRecording
|
|
|
|
|
{
|
|
|
|
|
get { return isRecording; }
|
|
|
|
|
set { isRecording = value; }
|
|
|
|
|
}
|
|
|
|
|
private MemoryStream recStream;
|
|
|
|
|
private string fileDir;
|
|
|
|
|
System.Timers.Timer backUPTimer;
|
|
|
|
|
private DBrecordingsManager DBrec;
|
|
|
|
|
|
|
|
|
|
private int gwID;
|
|
|
|
|
private int radioGWid;
|
|
|
|
|
private int typeSD;
|
|
|
|
|
private Int32 callType;
|
|
|
|
|
|
|
|
|
|
private UdpMulticast udp_multi;
|
|
|
|
|
private int sampleRate = 8000;
|
|
|
|
|
private int bitdepth = 16;
|
|
|
|
|
|
|
|
|
|
public int? dispatcher_id;
|
|
|
|
|
public int? subs_imei;
|
|
|
|
|
private int? group_cpsid;
|
|
|
|
|
|
|
|
|
|
private DateTime dtStart;
|
|
|
|
|
|
|
|
|
|
public VoiceRecording(string ip, int voicePort, int gwID, int radiogwID, int? dispatcherId, int? subs_imei, int? group_cpsid, int typeSD, Int32 callType, UdpMulticast udp_multi, int sampleRate, int bitdepth)
|
|
|
|
|
{
|
|
|
|
|
this.ip = ip;
|
|
|
|
|
this.port = voicePort;
|
|
|
|
|
this.gwID = gwID;
|
|
|
|
|
this.radioGWid = radiogwID;
|
|
|
|
|
|
|
|
|
|
this.dispatcher_id = dispatcherId;
|
|
|
|
|
this.subs_imei = subs_imei;
|
|
|
|
|
this.group_cpsid = group_cpsid;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.typeSD = typeSD;
|
|
|
|
|
this.callType = callType;
|
|
|
|
|
|
|
|
|
|
this.udp_multi = udp_multi;
|
|
|
|
|
this.sampleRate = sampleRate;
|
|
|
|
|
this.bitdepth = bitdepth;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fileDir = @"recordings";
|
|
|
|
|
DirectoryInfo dir = new DirectoryInfo(fileDir);
|
|
|
|
|
if (!Directory.Exists(fileDir))
|
|
|
|
|
{
|
|
|
|
|
dir.Create();
|
|
|
|
|
}
|
|
|
|
|
DBrec = new DBrecordingsManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
|
|
|
|
|
|
|
|
SM.Debug("Starting voice recording for " + ip);
|
|
|
|
|
udp4VoiceRecv = new UdpMulticast(ip, port);
|
|
|
|
|
udp4VoiceRecv.OnNewDataRecv += new UdpMulticast.newData4Send(udp4VoiceRecv_OnNewDataRecv);
|
|
|
|
|
|
|
|
|
|
backUPTimer = new System.Timers.Timer();
|
|
|
|
|
backUPTimer.Interval = 60000;
|
|
|
|
|
backUPTimer.Elapsed += new System.Timers.ElapsedEventHandler(backUPTimer_Elapsed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void backUPTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
SM.Debug("backup timer expired(60sec) ... force stoping voice recording");
|
|
|
|
|
Stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void udp4VoiceRecv_OnNewDataRecv(byte[] data, int dataLen)
|
|
|
|
|
{
|
|
|
|
|
if (isRecording)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("datalen="+dataLen);
|
|
|
|
|
if (dataLen > 0)
|
|
|
|
|
{
|
|
|
|
|
recStream.Write(data, 0, dataLen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Start()
|
|
|
|
|
{
|
|
|
|
|
udp4VoiceRecv.StartListen_ThreadPool();
|
|
|
|
|
|
|
|
|
|
recStream = new MemoryStream();
|
|
|
|
|
isRecording = true;
|
|
|
|
|
backUPTimer.Enabled = true;
|
|
|
|
|
dtStart = DateTime.Now;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string test;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Stop()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
backUPTimer.Enabled = false;
|
|
|
|
|
udp4VoiceRecv.StopListen();
|
|
|
|
|
SM.Debug("Recording stoped... dumping memory stream in to file; len=" + recStream.ToArray().Length);
|
|
|
|
|
|
|
|
|
|
if (recStream.ToArray().Length == 0)
|
|
|
|
|
{
|
|
|
|
|
SM.Debug("Nothing to write. Returning");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MainForm.recordings == 0)
|
|
|
|
|
{
|
|
|
|
|
SM.Debug("No recordings license. Returning");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Int32 call_type = GetCallType(); // 0-private 1-group 2-all call 3-users voice call from dispacher
|
|
|
|
|
// 4-private 5 -group 6 -all call
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string ending = ".wav";
|
|
|
|
|
string endRepeater = ".amb";
|
|
|
|
|
|
|
|
|
|
//format the name of the recording
|
|
|
|
|
string filename = FormatFileName();
|
|
|
|
|
filename = filename.Replace(' ', '_');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if we got some data save it 2 file
|
|
|
|
|
if (recStream.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
string fileName = fileDir + "/" + filename + ending;
|
|
|
|
|
string fileNameDB = fileName;
|
|
|
|
|
|
|
|
|
|
if ((MulticastListener.GatewayList[gwID] != null) && ((Boolean)MulticastListener.GatewayList[gwID]))
|
|
|
|
|
fileName = fileDir + "/" + filename + endRepeater;
|
|
|
|
|
|
|
|
|
|
using (FileStream fs1 = new FileStream(fileName, System.IO.FileMode.Create))
|
|
|
|
|
{
|
|
|
|
|
if (!((MulticastListener.GatewayList[gwID] != null) && ((Boolean)MulticastListener.GatewayList[gwID])))
|
|
|
|
|
{
|
|
|
|
|
WriteHeader(fs1, recStream.ToArray().Length, 1, sampleRate, bitdepth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
System.IO.BinaryWriter bw = new BinaryWriter(fs1);
|
|
|
|
|
bw.Write(recStream.ToArray());
|
|
|
|
|
bw.Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// trigger event when a recording was received from the repeater
|
|
|
|
|
if ((MulticastListener.GatewayList[gwID] != null) && ((Boolean)MulticastListener.GatewayList[gwID]))
|
|
|
|
|
OnRecordingFileWritteen(fileName);
|
|
|
|
|
|
|
|
|
|
// add to db
|
|
|
|
|
Recording rec = new Recording(dtStart.GetSecondsLocalFromDT() * 1000000 + DateTime.Now.Millisecond * 1000, dtStart.GetSecondsLocalFromDT(), DateTime.Now.GetSecondsLocalFromDT(), dtStart, DateTime.Now, fileNameDB, subs_imei, gwID, radioGWid, typeSD, call_type, group_cpsid, dispatcher_id);
|
|
|
|
|
|
|
|
|
|
DBrec.addRecording(rec);
|
|
|
|
|
|
|
|
|
|
|
2024-07-01 14:39:01 +00:00
|
|
|
|
test = $"#155#{rec.id}#{rec.hddLocation}#{rec.gwID}#{rec.radioGWID}#{rec.group_cpsId}#{rec.subs_imei}#{rec.startTime}#{rec.endTime}#{rec.typeSD}#{rec.calltype}#{rec.dispatcher_id}#";
|
|
|
|
|
|
|
|
|
|
byte[] dataToSend = Utils.Convert_text_For_multicast("#0.0" + test);
|
|
|
|
|
MainForm.udp.Send(dataToSend, dataToSend.Length);
|
2024-02-22 16:43:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
SM.Debug(ex.ToString());
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
backUPTimer.Close();
|
|
|
|
|
recStream.Flush();
|
|
|
|
|
isRecording = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int GetCallType()
|
|
|
|
|
{
|
|
|
|
|
int call_type = 0;
|
|
|
|
|
|
|
|
|
|
if (typeSD == 0)
|
|
|
|
|
{
|
|
|
|
|
if (callType == 162)
|
|
|
|
|
call_type = 7;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch (callType)
|
|
|
|
|
{
|
|
|
|
|
case 101 /*AllCall*/:
|
|
|
|
|
call_type = 6;
|
|
|
|
|
break;
|
|
|
|
|
case 102 /* Private call */:
|
|
|
|
|
call_type = 4;
|
|
|
|
|
break;
|
|
|
|
|
case 103 /* Group call */:
|
|
|
|
|
call_type = 5;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeSD == 1)
|
|
|
|
|
{
|
|
|
|
|
switch (callType)
|
|
|
|
|
{
|
|
|
|
|
case 201:
|
|
|
|
|
call_type = 3;
|
|
|
|
|
break;
|
|
|
|
|
case 101:
|
|
|
|
|
call_type = 2;
|
|
|
|
|
break;
|
|
|
|
|
case 102:
|
|
|
|
|
call_type = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 103:
|
|
|
|
|
call_type = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return call_type;
|
|
|
|
|
}
|
|
|
|
|
private string FormatDispatcherRadioFileName()
|
|
|
|
|
{
|
|
|
|
|
string filename = string.Empty;
|
|
|
|
|
string tmp = "";
|
|
|
|
|
|
|
|
|
|
if (typeSD == 1)
|
|
|
|
|
{
|
|
|
|
|
switch (callType)
|
|
|
|
|
{
|
|
|
|
|
case 201:
|
|
|
|
|
tmp = "";
|
|
|
|
|
if (MulticastListener.UserList[radioGWid] != null)
|
|
|
|
|
tmp = "_" + MulticastListener.UserList[radioGWid] + "_";
|
|
|
|
|
else
|
|
|
|
|
tmp = "_UserID(" + radioGWid.ToString() + ")_";
|
|
|
|
|
|
|
|
|
|
if (MulticastListener.UserList[dispatcher_id] != null)
|
|
|
|
|
filename = MulticastListener.UserList[dispatcher_id] + "_CALL_USER_TO" + tmp + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "UserID(" + dispatcher_id.ToString() + ")_CALL_USER_TO" + tmp + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 101: // dispatcher - radio (all call)
|
|
|
|
|
if (MulticastListener.UserList[dispatcher_id] != null)
|
|
|
|
|
filename = MulticastListener.UserList[dispatcher_id] + "_ALLCALL_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "UserID(" + dispatcher_id.ToString() + ")_ALLCALL_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 102: // dispatcher - radio (private call)
|
|
|
|
|
tmp = "";
|
|
|
|
|
|
|
|
|
|
if (MulticastListener.VehicleList[subs_imei.ToString()] != null)
|
|
|
|
|
tmp = "_" + MulticastListener.VehicleList[subs_imei.ToString()] + "(" + subs_imei.ToString() + ")_";
|
|
|
|
|
else
|
|
|
|
|
tmp = "_RadioID(" + subs_imei.ToString() + ")_";
|
|
|
|
|
|
|
|
|
|
if (MulticastListener.UserList[dispatcher_id] != null)
|
|
|
|
|
filename = MulticastListener.UserList[dispatcher_id] + "_PRIVATE_CALL_TO" + tmp + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "UserID(" + dispatcher_id.ToString() + ")_PRIVATE_CALL_TO" + tmp + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 103: // dispatcher - radio (group call)
|
|
|
|
|
if (MulticastListener.UserList[(int)dispatcher_id] != null)
|
|
|
|
|
filename = MulticastListener.UserList[(int)dispatcher_id] + "_GROUP_CALL_" + dispatcher_id.ToString() + "_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "UserID(" + dispatcher_id.ToString() + ")_GROUP_CALL_" + group_cpsid.ToString() + "_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filename.Trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string FormatRadioDispatcherFileName()
|
|
|
|
|
{
|
|
|
|
|
string filename = string.Empty;
|
|
|
|
|
|
|
|
|
|
if (typeSD == 0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (callType == 162) // Remote monitor
|
|
|
|
|
{
|
|
|
|
|
if (MulticastListener.VehicleList[subs_imei.ToString()] != null)
|
|
|
|
|
filename = "Remote monitor " + MulticastListener.VehicleList[subs_imei.ToString()] + "(" + subs_imei.ToString() + ")" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "Remote monitor RadioID(" + subs_imei.ToString() + ") " + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (callType == 103)
|
|
|
|
|
{
|
|
|
|
|
if (MulticastListener.VehicleList[subs_imei.ToString()] != null)
|
|
|
|
|
filename = MulticastListener.VehicleList[subs_imei.ToString()] + "(" + subs_imei.ToString() + ")" + "_DO_GROUP_CALL_ID_" + group_cpsid.ToString() + "_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "RadioID(" + subs_imei.ToString() + ")_DO_GROUP_CALL_ID_" + group_cpsid.ToString() + "_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
}
|
|
|
|
|
else if (callType == 102) // radio - dispatcher ( private call)
|
|
|
|
|
{
|
|
|
|
|
if (MulticastListener.VehicleList[subs_imei.ToString()] != null)
|
|
|
|
|
filename = MulticastListener.VehicleList[subs_imei.ToString()] + "(" + subs_imei.ToString() + ")" + "_DO_A_PRIVATE_CALL_";
|
|
|
|
|
else
|
|
|
|
|
filename = "RadioID(" + subs_imei.ToString() + ")_DO_A_PRIVATE_CALL_";
|
|
|
|
|
|
|
|
|
|
if (MulticastListener.VehicleList[dispatcher_id.ToString()] != null)
|
|
|
|
|
filename += MulticastListener.VehicleList[dispatcher_id.ToString()] + "(" + dispatcher_id.ToString() + ")" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename += "RadioID(" + dispatcher_id.ToString() + ")" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
}
|
|
|
|
|
else if (callType == 101) // radio - dispatcher ( all call)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (MulticastListener.VehicleList[subs_imei.ToString()] != null)
|
|
|
|
|
filename = MulticastListener.VehicleList[subs_imei.ToString()] + "(" + subs_imei.ToString() + ")" + "_DO_ALL_CALL_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
else
|
|
|
|
|
filename = "RadioID(" + subs_imei.ToString() + ")_DO_ALL_CALL_" + DateTime.Now.ToString("dd_MMM_yy_HH_mm_ss");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filename.Trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string FormatFileName()
|
|
|
|
|
{
|
|
|
|
|
if (typeSD == 0)
|
|
|
|
|
return FormatRadioDispatcherFileName();
|
|
|
|
|
|
|
|
|
|
return FormatDispatcherRadioFileName();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void WriteHeader(
|
|
|
|
|
System.IO.Stream targetStream,
|
|
|
|
|
int byteStreamSize,
|
|
|
|
|
int channelCount,
|
|
|
|
|
int sampleRate,
|
|
|
|
|
int bitdepth)
|
|
|
|
|
{
|
|
|
|
|
bool isFloatingPoint = false;
|
|
|
|
|
targetStream.Position = 0;
|
|
|
|
|
|
|
|
|
|
// RIFF header.
|
|
|
|
|
// Chunk ID.
|
|
|
|
|
targetStream.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Chunk size.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes(((bitdepth / 8) * byteStreamSize) + 36), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Format.
|
|
|
|
|
targetStream.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Sub-chunk 1.
|
|
|
|
|
// Sub-chunk 1 ID.
|
|
|
|
|
targetStream.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Sub-chunk 1 size.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes(16), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Audio format (floating point (3) or PCM (1)). Any other format indicates compression.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes((ushort)(isFloatingPoint ? 3 : 1)), 0, 2);
|
|
|
|
|
|
|
|
|
|
// Channels.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes(channelCount), 0, 2);
|
|
|
|
|
|
|
|
|
|
// Sample rate.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Bytes rate.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes(sampleRate * channelCount * (bitdepth / 8)), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Block align.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes((ushort)channelCount * (bitdepth / 8)), 0, 2);
|
|
|
|
|
|
|
|
|
|
// Bits per sample.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes(bitdepth), 0, 2);
|
|
|
|
|
|
|
|
|
|
// Sub-chunk 2.
|
|
|
|
|
// Sub-chunk 2 ID.
|
|
|
|
|
targetStream.Write(Encoding.ASCII.GetBytes("data"), 0, 4);
|
|
|
|
|
|
|
|
|
|
// Sub-chunk 2 size.
|
|
|
|
|
targetStream.Write(BitConverter.GetBytes((bitdepth / 8) * byteStreamSize), 0, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public delegate void RecordingFileWritteenDEl(string filePath);
|
|
|
|
|
public event RecordingFileWritteenDEl OnRecordingFileWritteen;
|
|
|
|
|
}
|
|
|
|
|
}
|