SafeDispatch/MotoTrbo_GW/Main.cs
2024-02-22 18:43:59 +02:00

2161 lines
88 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using Telerik.WinControls.UI;
using Nini.Config;
using System.Threading;
using MotoTRBO_GW;
using System.Net;
using System.Diagnostics;
using Telerik.WinControls;
using SafeMobileLib;
using System.Net.Sockets;
using System.Collections;
using MotoTRBO_XNL_Cmd;
using System.IO;
using SharedUI;
using NAudio.Wave;
using System.Runtime.InteropServices;
//using NetFwTypeLib;
namespace MotoTrbo_GW
{
public partial class Main : RadForm
{
// save the version of the application server in order to use it for the updater
public static String APP_SERVER_VERSION = "";
public static TimeSpan timeDifference = new TimeSpan(0);
public static int GWID = -1;
public static bool TESTMODE = false;
private static IConfigSource source = null;
public static string CFG_FILE = "GWconfig.ini";
public static string ApplicationServer, DBServer, DBSchema, DBUser, DBPass, DBPort;
// Audio related fields
private static AudioManager _audioManager = null;
BufferedWaveProvider _buffWaveProviderAsio = null;
public static AudioDriverType AudioDriver;
public static int bitdepth = 16;
public static int bitdepthInBytes = 2;
public static int sampleRate = 8000;
public static int recordedBufferMiliseconds = 32;
public static string asioDriverName = "";
private List<radioForm> _listOfRadioForms = new List<radioForm>();
private byte[] _bufferForAudio = null;
private bool _connectedToAsioBoard = false;
private System.Timers.Timer _timerCheckAsioBoard = null;
//
public static Boolean capacityPlus;
public static int pingInterval = 5000;
public static bool autoupdate = true;
public static bool isDevelope = false;
public static String masterRadioIP;
public static String messageBusIP;
public static String messageBusPort;
private controlVoiceMain voiceMainCTRL;
private LocationThread LocationConnection = null;
private ARSThread ARSConnection = null;
private EmergencyThread EmergencyConnection = null;
private SMSReceiveThread SMSReceiveConnection = null;
private SMSSendThread SMSSendConnection = null;
private TallysmanReceiveThread TallysmanReceiveConnection = null;
private TelemetryReceiveThread TelemetryReceiveConnection = null;
private static TallysmanSendThread TallysmanSendConnection = null;
private TelemetrySendThread TelemetrySendConnection = null;
private RemoteStunThread RemoteStunConnection = null;
public static Int32 SMSServicePort = 4007;
public static Int32 ARSServicePort = 4005;
public static Int32 LocationServicePort = 4001;
public static Int32 EmergencyServicePort = 8002;
public static Int32 TelemetryServicePort = 4008;
public static Int32 TallysmanServicePort = 4010;
//Non-IP Capable Peripheral Raw Data port
private static Int32 TallysmanSendPort = 4069;
//default time value for checking missign Id from database
public static int TallysmanRequestInterval = 1;
private static bool SEND_LOCATION_STOP = false;
private Thread LocationThreadObj = null;
private Thread SMSReceiveThreadObj = null;
private Thread SMSSendThreadObj = null;
private Thread TelemetryReceiveThreadObj = null;
private Thread TelemetrySendThreadObj = null;
private Thread TallysmanReceiveThreadObj = null;
private Thread TallysmanSendThreadObj = null;
private TcpClient client;
private Int32 registrationPort = 5680;
private Boolean registeredIP;
private BackgroundWorker bgWorkerRegistration;
private WaitingForm wf;
public static bool wait4ack = true;
public static int sms_sending_interval = 1200;
public static int number_of_retries = 5;
public static int retry_interval_sec = 180;
private RouteManager routeManager;
private Hashtable NetworkIDS_hash;
public string YourIPaddress = "";
private Hashtable SMSReceiveThreadObjArr;
private Hashtable RemoteStunThreadOBJArr;
private Hashtable RemoteStunConnectionArr;
private Hashtable EmergencyThreadObjArr;
private Hashtable EmergencyConnectionArr;
private Hashtable ARSThreadObjArr;
public static Dictionary<string, RadioConnection> RadioComArr;
public MessageBusHandler mbHandler;
public static List<GatewayID_IP> gatewayRadios;
//public static List<Group> GroupList;
public static Dictionary<Int32, SMSConfirm> smsConfirmForUnits = new Dictionary<int, SMSConfirm>();
private System.Windows.Forms.Timer StatusCheckTimer;
public static string LocalIP { get; private set; } = null;
//this variable is used to prevent multiple start/end call processing from dispatchers while a gateway is in a patch
public static Dictionary<string, bool> gatewayState = new Dictionary<string, bool>();
#region LINX
#if LINXB
LINX.TrboSipGateway _sipGateway = null;
private bool _connectedToAsterisk;
public bool ConnectedToAsterisk
{
get { return _connectedToAsterisk; }
private set
{
if (value != _connectedToAsterisk)
{
_connectedToAsterisk = value;
UpdateUIConnectionStatus(_connectedToAsterisk);
}
}
}
private int _minSipPort;
private int _maxSipPort;
#endif
#endregion
#region constructor + config file
public Main()
{
//SafeMobileLib.Utils.WriteLine("Blalalalalalalalalala");
SM debug = new SM();
LoadConfig();
InitializeComponent();
StatusCheckTimer = new System.Windows.Forms.Timer();
StatusCheckTimer.Interval = 60 * 1000;
StatusCheckTimer.Enabled = true;
StatusCheckTimer.Tick += new System.EventHandler(StatusCheckTimerTick);
RadMessageBox.SetThemeName("TelerikMetroBlue");
// customize the new FeedbackRadMessageBox
FeedbackRadMessageBox.InteractionWaitSeconds = 7;
FeedbackRadMessageBox.SetTheme("TelerikMetroBlue");
// register for restart event
FeedbackRadMessageBox.OnRestartRequest += delegate()
{
RestartApp();
};
if (TESTMODE)
this.Text = "!!!!Warning TEST MODE activated!!!!!";
// add firewall exception
try
{
FireWallException fw = new FireWallException();
string name = System.AppDomain.CurrentDomain.FriendlyName;
string path = Application.ExecutablePath;
fw.checkFirewall(name, path);
//bool result = fw.AuthorizeProgram(name, path, NET_FW_SCOPE_.NET_FW_SCOPE_ALL, NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY);
//if (result) SafeMobileLib.Utils.WriteLine("Firewall exception added for:" + name + " path:" + path);
//else SafeMobileLib.Utils.WriteLine("Firewall exception ERROR for:" + name + " path:" + path);
}
catch (Exception ex)
{
//SafeMobileLib.Utils.WriteLine("Firewall exception ERROR:",false);
SafeMobileLib.Utils.WriteLine(ex.ToString());
RadMessageBox.Show("MotoTRBO GW could not add an exception to Windows Firewall.\r\nPlese manually add this exception or close Windows Firewall. ",
"Windows Firewall exception.Please restart the application.");
}
//get version
Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
lbVersion.Text = "Version: " + v.ToString();
tabVoice.Enabled = false;
if (capacityPlus)
{
cbCapacityPlus.Checked = true;
lbMasterIP.Text = "Master Radio IP:" + masterRadioIP;
}
else
{
cbCapacityPlus.Checked = false;
lbMasterIP.Text = "";
}
// Get the time from Internet and then save the difference in time between the local computer time
// and the internet one from time.nist.gov
Thread internetTimeThread = new Thread(new ThreadStart(delegate ()
{
timeDifference = (DT.GetNetworkTime()).Subtract(DateTime.UtcNow);
}));
internetTimeThread.Start();
wf = new WaitingForm();
wf.Show();
bgWorkerRegistration = new BackgroundWorker();
bgWorkerRegistration.DoWork += new DoWorkEventHandler(bgWorkerRegistration_DoWork);
bgWorkerRegistration.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkerRegistration_RunWorkerCompleted);
bgWorkerRegistration.RunWorkerAsync();
}
private void AudioManager_AsioAudioAvailable(object sender, AsioAudioAvailableEventArgs e)
{
try
{
if (e.OutputBuffers.Length != 0)
{
_bufferForAudio = NAudio.Utils.BufferHelpers.Ensure(_bufferForAudio, e.SamplesPerBuffer * bitdepthInBytes);
foreach (radioForm rf in _listOfRadioForms)
{
RadioComHandler rcHandler = rf.rcHandler;
if (rcHandler != null && rcHandler.buffWaveProvider != null)
{
rcHandler.buffWaveProvider.Read(_bufferForAudio, 0, _bufferForAudio.Length);
Marshal.Copy(_bufferForAudio, 0, e.OutputBuffers[rcHandler.OutDevIDProperty], _bufferForAudio.Length);
}
}
}
if (e.InputBuffers.Length != 0)
{
_bufferForAudio = NAudio.Utils.BufferHelpers.Ensure(_bufferForAudio, e.SamplesPerBuffer * bitdepthInBytes);
foreach (radioForm rf in _listOfRadioForms)
{
RadioComHandler rcHandler = rf.rcHandler;
if (rcHandler != null)
{
Marshal.Copy(e.InputBuffers[rcHandler.InDevIDProperty], _bufferForAudio, 0, e.SamplesPerBuffer * bitdepthInBytes);
rcHandler.VoiceReceivedFromRadio(_bufferForAudio, _bufferForAudio.Length);
}
}
}
if (!_connectedToAsioBoard)
{
_connectedToAsioBoard = true;
SafeMobileLib.Utils.WriteLine("---- ASIO: inside audio available event handler----");
//SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Asio audio available", EventLogEntryType.Information, 21777);
}
e.WrittenToOutputBuffers = true;
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Error AudioManager_AsioAudioAvailable: " + ex.ToString(), ConsoleColor.Red);
SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Error AudioManager_AsioAudioAvailable: " + ex.ToString(), EventLogEntryType.Error, 21778);
}
}
private void AudioManager_PlaybackStopped(object sender, StoppedEventArgs e)
{
string msg = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nASIO playback stopped event\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
SafeMobileLib.Utils.WriteLine(msg, ConsoleColor.Red);
SafeMobileLib.Utils.WriteEventLog("SafeMobile", msg, EventLogEntryType.Warning, 21779);
}
private void _timerCheckAsioBoard_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (_connectedToAsioBoard)
{
_connectedToAsioBoard = false;
}
else
{
// Instantiate again the asio class
string msg = "ASIO board disconnected. Reconecting....";
SafeMobileLib.Utils.WriteLine(msg, ConsoleColor.Yellow);
SafeMobileLib.Utils.WriteEventLog("SafeMobile", msg, EventLogEntryType.Warning, 21780);
ClearAsioResources();
if (_audioManager == null)
{
try
{
InitAsioClassOnUIThread();
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine(ex.ToString(), ConsoleColor.Red);
}
}
}
}
/// <summary>
/// Display a console message displaying the number of positions received in the last minute and the total number of positions
/// since the gateway was started
/// </summary>
private void StatusCheckTimerTick(object sender, EventArgs e)
{
SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Received " + LocationThread.NumberOfPositionsSinceLastRead
+ " positions in last minute " + " [" + LocationThread.NumberOfPositions + " total]", EventLogEntryType.Information, 21522);
}
/// <summary>
/// Restart the application and close other notify icons
/// </summary>
private void RestartApp()
{
SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Gateway is Restarting", EventLogEntryType.Warning, 21522);
CloseNotifyIcon();
Program.isRunning = false;
Thread p = new Thread(new ThreadStart(delegate ()
{
//oldProcess.WaitForExit(8000);
System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location, Program.isConsoleEnabled ? " -c" : "");
Process oldProcess = Process.GetCurrentProcess();
oldProcess.Kill();
System.Environment.Exit(0);
}));
p.Start();
}
private void CloseNotifyIcon()
{
if (notifyIcon1 != null)
{
notifyIcon1.Visible = false;
notifyIcon1.Icon = null;
notifyIcon1.Dispose();
}
}
private void ContinueConstructor()
{
if (!registeredIP)
{
tabVoice.Enabled = false;
DialogResult result = FeedbackRadMessageBox.ShowExclamation("Please register your copy of MotoTrbo Gateway using the Administrative Module.\n Your IP address is:" + YourIPaddress, "Info");
if (result == DialogResult.OK)
Application.Exit();
}
else if (registeredIP && !App.isValidVersion(APP_SERVER_VERSION,
System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()))
{
DialogResult dr = RadMessageBox.Show("Please update your version of software to the latest one required by Application Server. Do you wish to update now?",
"Update required...", MessageBoxButtons.YesNo, RadMessageIcon.Exclamation);
if (dr == DialogResult.Yes)
{
CheckForUpdate(true);
Application.Exit();
}
else
Application.Exit();
}
else
{
// Get Audio settings
DBsettingsManager dbSettings = new DBsettingsManager(DBServer, DBSchema, DBUser, DBPass, DBPort);
string tmpSamplaRate = dbSettings.getSettingValue(0, "sampleRate");
if (!string.IsNullOrEmpty(tmpSamplaRate))
sampleRate = int.Parse(tmpSamplaRate);
else
{
SafeMobileLib.Utils.WriteLine("Invalid sample rate", ConsoleColor.Red);
}
string tmpBitDepth = dbSettings.getSettingValue(0, "bitDepth");
if (!string.IsNullOrEmpty(tmpSamplaRate))
{
bitdepth = int.Parse(tmpBitDepth);
bitdepthInBytes = bitdepth / 8;
}
else
{
SafeMobileLib.Utils.WriteLine("Invalid bit depth", ConsoleColor.Red);
}
string tmpBufferMilliseconds = dbSettings.getSettingValue(0, "bufferMilliseconds");
if (!string.IsNullOrEmpty(tmpBufferMilliseconds))
recordedBufferMiliseconds = int.Parse(tmpBufferMilliseconds);
else
{
SafeMobileLib.Utils.WriteLine("Invalid bufferMilliseconds", ConsoleColor.Red);
}
//int asio driver object
if (Main.AudioDriver == AudioDriverType.Asio)
{
try
{
if (_audioManager == null)
{
InitAsio();
InitAsioClassOnUIThread();
// Set up timer that checks if Asio board is connected
_timerCheckAsioBoard = new System.Timers.Timer(2000);
_timerCheckAsioBoard.Elapsed += _timerCheckAsioBoard_Elapsed;
_timerCheckAsioBoard.Start();
}
}
catch (Exception ex)
{
//string msg = "Unable to instantiate asio driver. Please ensure your soundcard is connected or choose another driver from combobox.\n\r\n\r" + ex.Message;
string msg = "Unable to instantiate asio driver. Do you want this time to use the default windows drivers instead?";//+".\n\r\n\r" + ex.Message;
FeedbackRadMessageBox.InteractionWaitSeconds = 320;
DialogResult result = FeedbackRadMessageBox.Show("Asio drivers issue", msg, MessageBoxButtons.YesNo, RadMessageIcon.Exclamation);
if (result == DialogResult.Yes)
{
lblAsioDriverName.Visibility = cbAsio.Visibility = ElementVisibility.Hidden;
Main.AudioDriver = AudioDriverType.Windows;
}
else
{
MainPanel.Text = "Unable to instantiate asio driver.";
return;
}
}
}
//old code
/*if (GWID == -1)
{
int id = getGWidFromDB(YourIPaddress);
if (id == -1)
{
RadMessageBox.Show("Gateway IP not present in DB\n\r Please go to Administrative module and register this GW with IP:!!!" + YourIPaddress, "IP missing", MessageBoxButtons.OK, RadMessageIcon.Error);
System.Environment.Exit(0);
}
else
{
GWID = id;
source = new IniConfigSource(Main.CFG_FILE);
source.Configs["Gateway"].Set("id", id);
source.Save();
SafeMobileLib.Utils.WriteLine("ID:" + id +" saved to config file.");
}
}*/
//new code
List <Gateway> listGW = new List<Gateway>();
try
{
listGW = getGWidFromDB(YourIPaddress);
if (listGW.Count == 0)
{
if (DBServer.Contains("127.0.0.1") || (DBServer.ToUpper().Contains("LOCALHOST")))
listGW = getGWidFromDB("127.0.0.1");
}
else
{
if (GWID != -1)
{
Boolean find = false;
foreach (Gateway obj in listGW)
if (obj.Id == GWID) { find = true; break; }
if ((!find) && (DBServer.Contains("127.0.0.1") || (DBServer.ToUpper().Contains("LOCALHOST"))))
listGW = getGWidFromDB("127.0.0.1");
}
}
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Ex on find automat the gateway ID:" + ex.ToString());
}
try
{
if (listGW.Count == 0)
{
FeedbackRadMessageBox.ShowError("Gateway IP not present in DB\n\r Please go to Administrative module and register this GW with IP:!!!" + YourIPaddress, "IP missing");
System.Environment.Exit(0);
return;
}
else
{
GWID = ((Gateway)listGW[0]).Id;
source = new IniConfigSource(Main.CFG_FILE);
source.Configs["Gateway"].Set("id", GWID);
// source.Configs["NAI"].Set("peerID", ((Gateway)listGW[0]).Peer_id);
source.Save();
SafeMobileLib.Utils.WriteLine("Gateway ID is " + GWID, ConsoleColor.Cyan);
//SafeMobileLib.Utils.WriteLine("ID:" + GWID + " saved to config file.");
btGWID.Text = GWID.ToString();
}
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("DB error!!!");
SafeMobileLib.Utils.WriteLine(ex.ToString());
FeedbackRadMessageBox.ShowError("DB error.\n\rPlease turn down the firewall or add an exception for the Datebase in the firewall and try again!!!\n\r DB ip:" + YourIPaddress,
"DB error");
System.Environment.Exit(0);
//System.Windows.Forms.Application.Exit();
return;
}
//end of new code
/*try
{
DBgroupsManager db4groups = new DBgroupsManager(DBServer, DBSchema, DBUser, DBPass, DBPort);
GroupList = db4groups.GetAllGroups();
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Error on load groups: "+ex.ToString());
}*/
tabVoice.Enabled = true;
radRibbonBar1.RibbonBarElement.QuickAccessToolBar.Visibility = Telerik.WinControls.ElementVisibility.Hidden;
radRibbonBar1.Expanded = false;
//test id app is already running
testIfAlreadyRunning();
//start message bus handler
mbHandler = new MessageBusHandler(messageBusIP, messageBusPort);
#region LINX
#if LINXB
mbHandler.RefreshDatabaseCommandReceived += MbHandler_RefreshDatabaseCommandReceived;
#endif
#endregion
routeManager = new RouteManager();
routeManager.OnRadioStatusUpdate += new RouteManager.RadioStatusUpdateDEl(routeManager_OnRadioStatusUpdate);
routeManager.Start();
SMSReceiveThreadObjArr =new Hashtable();
RemoteStunThreadOBJArr = new Hashtable();
RemoteStunConnectionArr = new Hashtable();
EmergencyThreadObjArr = new Hashtable();
EmergencyConnectionArr = new Hashtable();
ARSThreadObjArr = new Hashtable();
RadioComArr = new Dictionary<string, RadioConnection>();
StartLocationService();
StartARSService();
StartSMSService();
//StartEmergencyService();moved to routeManager_OnRadioStatusUpdate
StartTelemetryService();
StartTallysmanService();
StartRemoteStunService(); //for non Cap plus moved to routeManager_OnRadioStatusUpdate
LoadRadioTab(true);
#region LINX
#if LINXB
// Start sip registration
bool errorOnRegister = false;
_sipGateway = new LINX.TrboSipGateway(DBServer, DBSchema, DBUser, DBPass, DBPort, _minSipPort, _maxSipPort, out errorOnRegister);
_sipGateway.ConnectionStatusChanded += _sipGateway_ConnectionStatusChanded;
_sipGateway.LinxSendsInvite += _sipGateway_LinxSendsInvite;
_sipGateway.DialogCreated += _sipGateway_DialogCreated;
_sipGateway.DialogClosed += _sipGateway_DialogClosed;
_sipGateway.ErrorOnCreatingDialog += _sipGateway_ErrorOnCreatingDialog;
_sipGateway.VoiceReceived += _sipGateway_VoiceReceived;
//_sipGateway.LinxHangtimeEnded += _sipGateway_LinxHangtimeEnded;
_sipGateway.SmsFromLinxToRadio += _sipGateway_SmsReceived;
_sipGateway.ShowUIMessage += _sipGateway_ShowUIMessage;
ConnectedToAsterisk = _sipGateway.ConnectedToAstersisk;
if (errorOnRegister)
_sipGateway_ShowUIMessage("Not all the radios are connected to Linx server.Check sip ports range in config file");
#endif
#endregion
}
SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Gateway turned on with ID " + GWID, EventLogEntryType.SuccessAudit, 21521);
}
private void InitAsioClassOnUIThread()
{
if (this.InvokeRequired)
{
this.Invoke((Action)(() => { InitAsioClass(); }));
}
else
InitAsioClass();
}
private void InitAsioClass()
{
_audioManager = new AudioManager(asioDriverName);
int channels = _audioManager.AsioDriverInputChannelCount;
_buffWaveProviderAsio = new BufferedWaveProvider(new NAudio.Wave.WaveFormat(sampleRate, bitdepth, channels));
_audioManager.AsioAudioAvailable += AudioManager_AsioAudioAvailable;
_audioManager.PlaybackStopped += AudioManager_PlaybackStopped;
_audioManager.Init(_buffWaveProviderAsio, channels, sampleRate);
_audioManager.Play();
}
#region TRBO Sip Gateway event handlers
#if LINXB
private void _sipGateway_ConnectionStatusChanded(bool connected)
{
this.ConnectedToAsterisk = connected;
}
private void _sipGateway_LinxSendsInvite(LINX.RadioSipInfo radioSipInfo, string callingLinxID)
{
// 1. Check if the corresponding base radio is available for call
int radioGwID = int.Parse(radioSipInfo.ContactInfo.GWandRadioGW.Split('.')[1]);
radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID);
if (rf != null)
{
if (rf.rcHandler != null)
{
/* I MOVED THIS PART IN A FUNCTION IN RADIOCOMHANDLER.CS
if (rf.rcHandler.IsPTTbussy)
{
// 2. If base radio is not available reject the invite.
radioSipInfo.SipClass.Decline(callingLinxID);
SafeMobileLib.Utils.WriteLine($@"Declined the inivite from sip id {callingLinxID} to radio {radioSipInfo.ContactInfo.Name}
because base station {radioGwID} is ptt busy", ConsoleColor.Green);
}
else
{
bool groupCall = radioSipInfo.ContactInfo.Type == ContactType.GROUP;
rf.rcHandler.LinxCallInfo = new LINX.LinxCall(callingLinxID, radioSipInfo.ContactInfo.SipId);
if (groupCall)
{
RadioComArr[rf.RadioIP].SendCallType(0, radioSipInfo.ContactInfo.Id); // group radio ptt
rf.rcHandler.RadioStatusProp = RADIO_STATUS.GroupCall_INIT;
}
else
{
RadioComArr[rf.RadioIP].SendCallType(1, radioSipInfo.ContactInfo.Id); // private radio ptt
rf.rcHandler.RadioStatusProp = RADIO_STATUS.PrivateCall_INIT;
}
// start the tCheckStatus timer
rf.rcHandler.StartCheckStatusTimer();
bool success = RadioComArr[rf.RadioIP].SendPTTon();
if (success)
{
// Linx Private Call - 1002
// Linx Group Call - 1003
rf.rcHandler.CallType = groupCall ? 1003 : 1002;
}
else
{
// Error on SendPTTon()
// Reject the invite
radioSipInfo.SipClass.Decline(callingLinxID);
SafeMobileLib.Utils.WriteLine($@"Declined the inivite from sip id {callingLinxID} to radio {radioSipInfo.ContactInfo.Name}
because base station {radioGwID} failed to send PTT", ConsoleColor.Red);
}
}*/
bool acceptInvite = rf.rcHandler.InviteFromLinx(callingLinxID, radioSipInfo.ContactInfo.SipId, radioSipInfo.ContactInfo.Id, radioSipInfo.ContactInfo.Type == ContactType.GROUP);
if (!acceptInvite)
radioSipInfo.SipClass.Decline(callingLinxID);
}
}
}
private void _sipGateway_DialogCreated(LINX.RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx)
{
if (fromRadioToLinx)
{
// PTT initiated from radio
// Notify RadioComHandler class that the dialog has been established
int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]);
radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID);
if (rf != null)
{
if (rf.rcHandler != null)
{
rf.rcHandler.LinxReceivesPTTFromRadio(new LINX.LinxCall(linxID, sipInfo.ContactInfo.SipId));
}
}
}
SafeMobileLib.Utils.WriteLine($"Dialog created between linx with sipID {linxID} and radio {sipInfo.ContactInfo.Name}",
ConsoleColor.Green);
}
private void _sipGateway_DialogClosed(LINX.RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx)
{
int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]);
radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID);
SafeMobileLib.Utils.WriteLine($"PTT ended between linx with sipID {linxID} and radio {sipInfo.ContactInfo.Name}",
ConsoleColor.Green);
if (rf != null)
{
if (rf.rcHandler != null)
{
if (rf.rcHandler.IsPTTbussy)
{
if (!fromRadioToLinx)
{
// Linx sent PTT
rf.rcHandler.CallType = sipInfo.ContactInfo.Type == ContactType.GROUP ? 1003 : 1002;
RadioComArr[rf.RadioIP].SendPTToff();
}
}
}
}
}
private void _sipGateway_ErrorOnCreatingDialog(LINX.RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx)
{
int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]);
radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID);
SafeMobileLib.Utils.WriteLine($"Error on creating dialog between {linxID} and radio {sipInfo.ContactInfo.Name}",
ConsoleColor.Red);
if (rf != null)
{
if (rf.rcHandler != null)
{
if (rf.rcHandler.IsPTTbussy)
{
if (!fromRadioToLinx)
{
// Linx sent PTT
rf.rcHandler.CallType = sipInfo.ContactInfo.Type == ContactType.GROUP ? 1003 : 1002;
RadioComArr[rf.RadioIP].SendPTToff();
}
}
}
}
}
private void _sipGateway_VoiceReceived(LINX.RadioSipInfo sipInfo, byte[] buffer)
{
int radioGwID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]);
radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID);
if (rf != null)
{
if (rf.rcHandler != null)
{
rf.rcHandler.buffWaveProvider.AddSamples(buffer, 0, buffer.Length);
}
}
}
private void _sipGateway_SmsReceived(ContactLinx remoteRadioIDInfo, string message, int linxRadioID)
{
// Sms received from linx
// Just send it on mbus
int radioGwID = int.Parse(remoteRadioIDInfo.GWandRadioGW.Split('.')[1]);
radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGwID);
if (rf != null)
{
if (rf.rcHandler != null)
{
// Generate string command to send on message bus
// #seqID#Opcode#gatewayId.gatewayRadioId.remoteRadioId#message#scheduleTime#dispatcherID#
string seqID = Utils.GenerateSeqID(linxRadioID);
string cmd= $"#{(int)MessageBusCmds.SendSMSRequest}#{Main.GWID}.{rf.rcHandler.RadioID}.{remoteRadioIDInfo.Id}#Linx{linxRadioID}.{message}#{DateTime.Now.ToUniversalTime().DateTo70Format()}#{linxRadioID}#";
MessageBusHandler.SendOnMsgBuss(seqID, cmd);
}
}
}
private void _sipGateway_ShowUIMessage(string message)
{
if (this.InvokeRequired)
{
this.Invoke((Action)(() => ShowMessageBox(message)));
}
else
ShowMessageBox(message);
}
private void ShowMessageBox(string message)
{
MessageBox.Show(message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
//private void _sipGateway_LinxHangtimeEnded(LINX.RadioSipInfo sipInfo, string linxID)
//{
// // Clear linx call info in radioComHandler class
// int radioGWID = int.Parse(sipInfo.ContactInfo.GWandRadioGW.Split('.')[1]);
// radioForm rf = voiceMainCTRL.radiosFormList.Find(radioF => radioF.RadioID == radioGWID);
// if (rf != null)
// {
// if (rf.rcHandler != null)
// {
// rf.rcHandler.LinxCallInfo = LINX.LinxCall.DefaultValue; // default value.
// }
// }
//}
#endif
#endregion
#region Private functions for sip
#if LINXB
private void RcHandler_LinxCallEstablished(object sender, EventArgs e)
{
// Radio call established, accept the invite from LINX
RadioComHandler rcHandler = (RadioComHandler)sender;
LINX.LinxCall linxCallInfo;
if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue)
{
_sipGateway.GetSipClass(linxCallInfo.RadioSipID).AcceptInvite(linxCallInfo.LinxSipID);
}
}
private void RcHandler_LinxCallFailed(object sender, EventArgs e)
{
// Radio call failed, decline the invite from LINX
RadioComHandler rcHandler = (RadioComHandler)sender;
LINX.LinxCall linxCallInfo;
if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue)
{
_sipGateway.GetSipClass(linxCallInfo.RadioSipID).Decline(linxCallInfo.LinxSipID);
SafeMobileLib.Utils.WriteLine("Will reset linx call info from main because base radio could not call portable", ConsoleColor.DarkRed);
rcHandler.ResetLinxCallInfoValue();
}
}
private void RcHandler_CallLinx(object sender, LINX.CallLinxEventArgs e)
{
RadioComHandler rcHandler = (RadioComHandler)sender;
// Call linx and send voice
LINX.LinxCall linxCallInfo;
if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue)
{
_sipGateway.SendInvite(linxCallInfo.RadioSipID, linxCallInfo.LinxSipID);
}
else
{
int? linxSipID = null;
// The call is not in response to a LINX call
// Check if is group or private call
// If group call, check if there is a LINX associated with this group call
// If private call, check if there is a LINX that receives private call from this unit
if (e.IsGroup)
{
// group call
// Check if there is a LINX associated with this group call
linxSipID = _sipGateway.GetLinxInRadioGroup(e.GroupID);
if (linxSipID.HasValue)
{
int radioSipID = -1;
if (_sipGateway.LinxSipIDisGroup(linxSipID.Value))
radioSipID = _sipGateway.GetSipIDFromRadioID(e.RadioID, false);
else
radioSipID = _sipGateway.GetSipIDFromRadioID(e.GroupID, true);
_sipGateway.SendInvite(radioSipID, linxSipID.Value.ToString());
rcHandler.GroupCallInitiatedByRadio = true;
}
}
else
{
// private call
// If private call, check if there is a LINX that receives private call from this unit
linxSipID = _sipGateway.GetLinxForPrivateCall(e.RadioID);
if (linxSipID.HasValue)
{
int radioSipID = _sipGateway.GetSipIDFromRadioID(e.RadioID, false);
_sipGateway.SendInvite(radioSipID, linxSipID.Value.ToString());
}
}
}
}
private void RcHandler_RadioEndsPTTtoLinx(object sender, EventArgs e)
{
// Radio has ended ptt
RadioComHandler rcHandler = (RadioComHandler)sender;
LINX.LinxCall linxCallInfo;
if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue)
{
// get the sip class
SipComponent.SipClientClass2 sipClass = _sipGateway.GetSipClass(linxCallInfo.RadioSipID);
// end sip call if call is in progress or cancel invite
if (sipClass.InDialogWith(linxCallInfo.LinxSipID))
sipClass.Close(linxCallInfo.LinxSipID);
else
sipClass.CancelInvite(linxCallInfo.LinxSipID);
}
}
private void RcHandler_RadioVoiceToLinx(object sender, LINX.RadioVoiceToLinxEventArgs e)
{
RadioComHandler rcHandler = (RadioComHandler)sender;
LINX.LinxCall linxCallInfo;
if ((linxCallInfo = rcHandler.LinxCallInfo) != LINX.LinxCall.DefaultValue)
{
_sipGateway.GetSipClass(linxCallInfo.RadioSipID).SendAudio(
linxCallInfo.LinxSipID, e.VoiceBuffer, e.BufferLength, SipComponent.AudioFormat.PCM);
}
}
private int? RcHandler_LinxIDForPrivateCallRequested(int radioID)
{
return _sipGateway.GetLinxForPrivateCall(radioID);
}
private int RcHandler_RadioSipIDRequested(int radioID, bool isGroup)
{
return _sipGateway.GetSipIDFromRadioID(radioID, isGroup);
}
private void UpdateUIConnectionStatus(bool connectedToAsterisk)
{
System.Drawing.Color color;
string textToDisplay;
if (connectedToAsterisk)
{
color = System.Drawing.Color.Green;
textToDisplay = "Connected to Asterisk";
}
else
{
color = System.Drawing.Color.Red;
textToDisplay = "Not connected to Asterisk";
}
if (this.InvokeRequired)
{
this.Invoke((Action)(() => { ChangeConnectionLabel(color, textToDisplay); }));
}
else
ChangeConnectionLabel(color, textToDisplay);
}
private void SMSReceiveConnection_PrivateCallRequestForLinxReceived(int remoteRadioID, int linxRadioID)
{
_sipGateway.PrivateCallRequestFromRadioReceived(remoteRadioID, linxRadioID);
}
private async void SMSReceiveConnection_SmsForLixReceived(string seqID, int remoteRadioID, int linxRadioID, string text)
{
bool smsReceivedByLinx = await _sipGateway.SendSmsToLinx(seqID, linxRadioID, remoteRadioID, text);
// Send confirmation on mBus
// #seqID#Opcode#state#
// #seqID#242#1# or #seqID#242#0#
int state = smsReceivedByLinx ? 1 : 0;
MessageBusHandler.SendOnMsgBuss(seqID, $"#{(int)MessageBusCmds.FieldRadioReceivedSmsAck}#{state}#");
}
private void MbHandler_RefreshDatabaseCommandReceived(object sender, EventArgs e)
{
_sipGateway?.ListOfSipIDHasChanged();
}
private void ChangeConnectionLabel(System.Drawing.Color color, string text)
{
lblConnectedToAsterisk.ForeColor = color;
lblConnectedToAsterisk.Text = text;
}
#endif
#endregion
#region asio events for main
private void InitAsio()
{
lblAsioDriverName.Visibility = cbAsio.Visibility = ElementVisibility.Visible;
LoadAsioDrivers();
}
private void LoadAsioDrivers()
{
string[] driverList = AudioManager.GetAsioDriverNames();
foreach (String obj in driverList)
{
SafeMobileLib.Utils.WriteLine(obj, ConsoleColor.DarkMagenta);
RadMenuItem tmp = new RadMenuItem(obj);
tmp.Name = obj;
cbAsio.Items.Add(tmp);
tmp.Click += new System.EventHandler(DriverChangeEvent);
}
if (cbAsio.Items.Count > 0)
{
for (int i = 0; i < cbAsio.Items.Count; i++)
{
if (((RadMenuItem)cbAsio.Items[i]).Text == asioDriverName)
{
((RadMenuItem)cbAsio.Items[i]).IsChecked = true;
cbAsio.Text = ((RadMenuItem)cbAsio.Items[i]).Text;
}
}
}
if(cbAsio.Items.Count == 1 && ((RadMenuItem)cbAsio.Items[0]).Text != asioDriverName)
{
((RadMenuItem)cbAsio.Items[0]).IsChecked = true;
cbAsio.Text = asioDriverName = ((RadMenuItem)cbAsio.Items[0]).Text;
source = new IniConfigSource(CFG_FILE);
source.Configs["Voice"].Set("driverName", cbAsio.Text);
source.Save();
}
}
private void DriverChangeEvent(object sender, EventArgs e)
{
if (((RadMenuItem)sender).Name != asioDriverName)
{
source = new IniConfigSource(CFG_FILE);
source.Configs["Voice"].Set("driverName", ((RadMenuItem)sender).Name);
source.Save();
FeedbackRadMessageBox.ShowInfo("Info: You need to restart gateway to work with selected driver", "");
}
}
#endregion
void routeManager_OnRadioStatusUpdate(bool status, string ip)
{
SafeMobileLib.Utils.WriteLine(". . . . . . . . . . . routeManager_OnRadioStatusUpdate . . . . . . . . . .");
SafeMobileLib.Utils.WriteLine($". . . . . . . . . . . ip:{ip} status:{status}. . . . . . . . . .");
SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Radio gateway " + ip + " is now " + (status ? "online" : "offline"),
EventLogEntryType.Information, 21521);
//if (capacityPlus)
//{
//return;
//}
if (status)
{
//start radio connection
RadioConnection rc = null;
rc = new RadioConnection(ip, EmergencyServicePort, "XNL_CMDS");
if (RadioComArr.ContainsKey(ip))
{
RadioComArr[ip].Stop();
RadioComArr.Remove(ip);
}
RadioComArr.Add(ip, rc);
rc.Start();
//start ARS
if (!capacityPlus)
{
int Network_ID = Convert.ToInt32(RouteManager.NetworkIDs_Hash[ip]);
RoutingUtils.UpdateRoutes_NonCapPlus(ip, RadioStuff.GetInterface(ip), Network_ID);
GatewayID_IP ID_IP = new GatewayID_IP();
ID_IP.remoteIP = ip;
ID_IP.localIP = RadioStuff.GetInterface(ip);
ID_IP.ID = Network_ID.ToString();
if (!ARSThreadObjArr.ContainsKey(ip))
{
ARSThread ARSConnection = new ARSThread(ID_IP, ARSServicePort, false, messageBusIP, messageBusPort);
/*ARSConnection.OnArsReceived += delegate (Int64 radioID, bool isON)
{
// nothing for now here
};*/
Thread ARSThreadObj = new Thread(new ThreadStart(ARSConnection.handleConnection));
ARSThreadObj.IsBackground = true;
ARSThreadObj.Start();
ARSThreadObjArr.Add(ip, ARSThreadObj);
}
}
else
{
//add route for cap plus
RoutingUtils.UpdateRoutes(masterRadioIP, true);
}
if (!capacityPlus)
{
//start SMS for current ip
if (!SMSReceiveThreadObjArr.ContainsKey(ip))
{
SMSReceiveThread SMSReceiveConnection = new SMSReceiveThread(ip, SMSServicePort, messageBusIP, messageBusPort);
Thread SMSReceiveThreadObj = new Thread(new ThreadStart(SMSReceiveConnection.handleConnection));
SMSReceiveThreadObj.IsBackground = true;
SMSReceiveThreadObj.Start();
#if LINXB
SMSReceiveConnection.SmsForLixReceived += SMSReceiveConnection_SmsForLixReceived;
SMSReceiveConnection.PrivateCallRequestForLinxReceived += SMSReceiveConnection_PrivateCallRequestForLinxReceived;
#endif
SMSReceiveThreadObjArr.Add(ip, SMSReceiveThreadObj);
}
}
int total_sleep = 0;
while (!rc.AuthDone && Program.isRunning)
{
SafeMobileLib.Utils.WriteLine("Sleeping auth not completed!!!!");
Thread.Sleep(100);
total_sleep++;
if (total_sleep > 50)//after 5sec retry a new auth
{
total_sleep = 0;
SafeMobileLib.Utils.WriteLine("Stopping current AUTH atempt and retry in 5 seconds");
rc.Stop();
int c = 0;
while(c < 50 && Program.isRunning)
{
c++;
Thread.Sleep(100);
}
rc = new RadioConnection(ip, EmergencyServicePort, "XNL_CMDS");
RadioComArr[ip] = rc;
rc.Start();
}
}
//start remote stun
if (!RemoteStunThreadOBJArr.ContainsKey(ip))
{
int radioID = Convert.ToInt32(RouteManager.RadioGW_IDs[ip]);
RemoteStunThread RemoteStunConnection = new RemoteStunThread(rc, ip, radioID, EmergencyServicePort, messageBusIP, messageBusPort);
Thread RemoteStunThreadOBJ = new Thread(new ThreadStart(RemoteStunConnection.handleConnection));
RemoteStunThreadOBJ.IsBackground = true;
RemoteStunThreadOBJ.Start();
RemoteStunThreadOBJArr.Add(ip, RemoteStunThreadOBJ);
RemoteStunConnectionArr.Add(ip, RemoteStunConnection);
}
//start emergency
if (!EmergencyThreadObjArr.ContainsKey(ip))
{
EmergencyThread EmergencyConnection = new EmergencyThread(rc, ip, EmergencyServicePort, messageBusIP, messageBusPort);
Thread EmergencyThreadObj = new Thread(new ThreadStart(EmergencyConnection.handleConnection));
EmergencyThreadObj.IsBackground = true;
EmergencyThreadObj.Start();
EmergencyThreadObjArr.Add(ip, EmergencyThreadObj);
EmergencyConnectionArr.Add(ip, EmergencyConnection);
}
}
else
{
SafeMobileLib.Utils.WriteLine("routeManager_OnRadioStatusUpdate status:" + status + " ip:" + ip);
//remove connections from EMERGEBCY REMOTESTUN radioConnection HASHTABLES
PingOffFallowUP(ip);
}
}
private void PingOffFallowUP(string ip)
{
if (EmergencyThreadObjArr.ContainsKey(ip))
{
((EmergencyThread)EmergencyConnectionArr[ip]).Disconnect();
EmergencyThreadObjArr[ip] = null;
EmergencyThreadObjArr.Remove(ip);
EmergencyConnectionArr.Remove(ip);
}
if (RemoteStunThreadOBJArr.ContainsKey(ip))
{
((RemoteStunThread)RemoteStunConnectionArr[ip]).Disconnect();
RemoteStunThreadOBJArr[ip] = null;
RemoteStunThreadOBJArr.Remove(ip);
RemoteStunConnectionArr.Remove(ip);
}
if (RadioComArr.ContainsKey(ip))
{
RadioComArr[ip].Stop();
RadioComArr.Remove(ip);
}
}
#region bg worker registration events
void bgWorkerRegistration_DoWork(object sender, DoWorkEventArgs e)
{
registeredIP = getRegistration();
}
void bgWorkerRegistration_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (wf != null)
if (wf.IsInitialized)
if (wf.IsLoaded)
{
SafeMobileLib.Utils.WriteLine("Shuting down waiting form");
wf.Close();
}
if (appServerMissing)
{
FeedbackRadMessageBox.ShowError("Could not reach Application Server. Please check the connection and try again!!!", "Connection Error");
Application.Exit();
}
ContinueConstructor();
}
#endregion
private bool appServerMissing = false;
private Boolean getRegistration()
{
Boolean toReturn = false;
try
{
client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(Main.ApplicationServer), registrationPort);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
YourIPaddress = (client.Client.LocalEndPoint.ToString().Split(':'))[0];
Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
UTF8Encoding encoding = new UTF8Encoding();
byte[] buffer = encoding.GetBytes("200");
//encryption doesn't work, to be added when working
//byte[] encodedBuffer = Encryption.Encrypt(buffer);
clientStream.Write(buffer, 0, buffer.Length);
SafeMobileLib.Utils.WriteLine("Sent registration request to server, waiting...");
byte[] message = new byte[128];
//set read timeout to 10s
clientStream.ReadTimeout = 10000;
int result = clientStream.Read(message, 0, message.Length);
//close waiting thread
//byte[] decodedMessage = Encryption.Decrypt(message);
String decodedString = encoding.GetString(message).Trim('\0');
String[] options = decodedString.Split(';');
SafeMobileLib.Utils.WriteLine($"Received registration from server {decodedString}")
;
if (options[0].Equals("201"))
{
if (options[1].StartsWith("invalid"))
{
toReturn = false;
}
else
{
APP_SERVER_VERSION = options[1].Replace("valid-", "");
messageBusIP = options[2];
messageBusPort = options[3];
DBServer = options[4];
DBSchema = options[5];
DBUser = options[6];
DBPass = options[7];
DBPort = options[8];
toReturn = true;
}
}
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Exception in gateway:getRegistration():" + ex.ToString(), ConsoleColor.Red);
appServerMissing = true;
}
return toReturn;
}
/*private int getGWidFromDB(string currentIP)
{
DBgatewaysManager dbmanager = new DBgatewaysManager(Main.DBServer, Main.DBSchema, Main.DBUser, Main.DBPass, Main.DBPort);
List<Gateway> list = dbmanager.getAllGateways();
foreach (Gateway g in list)
{
if (g.Ip == currentIP)
{
SafeMobileLib.Utils.WriteLine("Gateway IP found in registration tabel. ID:"+g.Id);
return g.Id;
}
}
SafeMobileLib.Utils.WriteLine("Gateway IP not found in registration tabel!!!");
return -1;
}*/
private List<Gateway> getGWidFromDB(string currentIP)
{
DBgatewaysManager dbmanager = new DBgatewaysManager(Main.DBServer, Main.DBSchema, Main.DBUser, Main.DBPass, Main.DBPort);
List<Gateway> list = dbmanager.getAllGateways();
List<Gateway> listtoreturn = new List<Gateway>();
foreach (Gateway g in list)
{
if (g.Ip == currentIP)
{
SafeMobileLib.Utils.WriteLine("Gateway IP found in registration tabel. ID:" + g.Id);
listtoreturn.Add(g);
}
}
return listtoreturn;
}
void StartLocationService()
{
// create thread to listen UDP
LocationConnection = new LocationThread(LocationServicePort, messageBusIP, messageBusPort);
LocationThreadObj = new Thread(new ThreadStart(LocationConnection.handleConnection));
LocationThreadObj.IsBackground = true;
LocationThreadObj.Start();
}
void StartSMSService()
{
//create thread for sending SMSs to the radios
SMSSendConnection = new SMSSendThread(SMSServicePort, messageBusIP, messageBusPort);
SMSSendThreadObj = new Thread(new ThreadStart(SMSSendConnection.handleConnection));
SMSSendThreadObj.IsBackground = true;
SMSSendThreadObj.Start();
Thread.Sleep(1000);
if (capacityPlus)
{
SafeMobileLib.Utils.WriteLine("StartSMSService for cap plus");
SMSReceiveConnection = new SMSReceiveThread(masterRadioIP, SMSServicePort, messageBusIP, messageBusPort, SMSSendConnection.udpClientSMS);
SMSReceiveThreadObj = new Thread(new ThreadStart(SMSReceiveConnection.handleConnection));
SMSReceiveThreadObj.IsBackground = true;
SMSReceiveThreadObj.Start();
#if LINXB
SMSReceiveConnection.SmsForLixReceived += SMSReceiveConnection_SmsForLixReceived;
SMSReceiveConnection.PrivateCallRequestForLinxReceived += SMSReceiveConnection_PrivateCallRequestForLinxReceived;
#endif
}
}
void StartTelemetryService()
{
//create thread for receiving telemetry notifications from the radios
TelemetryReceiveConnection = new TelemetryReceiveThread(TelemetryServicePort, messageBusIP, messageBusPort);
TelemetryReceiveThreadObj = new Thread(new ThreadStart(TelemetryReceiveConnection.handleConnection));
TelemetryReceiveThreadObj.IsBackground = true;
TelemetryReceiveThreadObj.Start();
//create thread for sending telemetry commands to the radios
TelemetrySendConnection = new TelemetrySendThread(TelemetryServicePort, messageBusIP, messageBusPort);
TelemetrySendThreadObj = new Thread(new ThreadStart(TelemetrySendConnection.handleConnection));
TelemetrySendThreadObj.IsBackground = true;
TelemetrySendThreadObj.Start();
}
void StartTallysmanService()
{
//create thread for receiving tallysman notifications from the radios
TallysmanReceiveConnection = new TallysmanReceiveThread(TallysmanServicePort, messageBusIP, messageBusPort);
TallysmanReceiveThreadObj = new Thread(new ThreadStart(TallysmanReceiveConnection.handleConnection));
TallysmanReceiveThreadObj.IsBackground = true;
TallysmanReceiveThreadObj.Start();
//create thread for sending commands to the radios
TallysmanSendConnection = new TallysmanSendThread(TallysmanSendPort, messageBusIP, messageBusPort, TallysmanRequestInterval);
TallysmanSendThreadObj = new Thread(new ThreadStart(TallysmanSendConnection.handleConnection));
TallysmanSendThreadObj.IsBackground = true;
TallysmanSendThreadObj.Start();
}
public static void resetTallysmanCheckTimer(int newvalue)
{
TallysmanSendConnection.resetCheckTimer(newvalue);
}
void StartARSService()
{
if (capacityPlus)
{
SafeMobileLib.Utils.WriteLine("StartARSService for cap plus");
RoutingUtils.UpdateRoutes( masterRadioIP, true);
GatewayID_IP radioID_IP = new GatewayID_IP();
ARSConnection = new ARSThread(radioID_IP, ARSServicePort, true, messageBusIP, messageBusPort);
Thread ARSThreadObj = new Thread(new ThreadStart(ARSConnection.handleConnection));
ARSThreadObj.IsBackground = true;
ARSThreadObj.Start();
}
}
RadioConnection rc_cap_plus = null;
void StartRemoteStunService()
{
if (capacityPlus)
{
SafeMobileLib.Utils.WriteLine("StartRemoteStunService for cap plus");
//start radio connection
rc_cap_plus = new RadioConnection(masterRadioIP, EmergencyServicePort, "XNL_CMDS");
if (RadioComArr.ContainsKey(masterRadioIP))
{
RadioComArr[masterRadioIP].Stop();
RadioComArr.Remove(masterRadioIP);
}
RadioComArr.Add(masterRadioIP, rc_cap_plus);
rc_cap_plus.Start();
//start remote stun
if (!RemoteStunThreadOBJArr.ContainsKey(masterRadioIP))
{
int radioID = Convert.ToInt32(RouteManager.RadioGW_IDs[masterRadioIP]);
RemoteStunThread RemoteStunConnection = new RemoteStunThread(rc_cap_plus, masterRadioIP, radioID, EmergencyServicePort, messageBusIP, messageBusPort);
Thread RemoteStunThreadOBJ = new Thread(new ThreadStart(RemoteStunConnection.handleConnection));
RemoteStunThreadOBJ.IsBackground = true;
RemoteStunThreadOBJ.Start();
RemoteStunThreadOBJArr.Add(masterRadioIP, RemoteStunThreadOBJ);
RemoteStunConnectionArr.Add(masterRadioIP, RemoteStunConnection);
}
}
}
private void LoadConfig()
{
try
{
if (!File.Exists(CFG_FILE))
{
SafeMobileLib.Utils.WriteLine("Config file doesn't exist. Creating it...", ConsoleColor.Yellow);
try
{
using (FileStream fs = File.Create(CFG_FILE)) { }
}
catch (Exception)
{
SafeMobileLib.Utils.WriteLine("Application ended!!!! " + CFG_FILE + " could not be created");
SafeMobileLib.Utils.WriteLine("Press any key to exit...");
Console.ReadKey();
System.Environment.Exit(0);
}
}
source = new IniConfigSource(CFG_FILE);
if (source.Configs["Gateway"] == null)
source.Configs.Add("Gateway");
GWID = GetInt32Value("Gateway", "id", -1);
registrationPort = GetInt32Value("Gateway", "regPort", 5680);
pingInterval = GetInt32Value("Gateway", "pingInterval", 10000);
TESTMODE = GetBooleanValue("Gateway", "testmode", false);
LocalIP = GetStringValue("Gateway", "localIP", "");
SMSServicePort = GetInt32Value("Gateway", "smsPort", 4007);
LocationServicePort = GetInt32Value("Gateway", "locationPort", 4001);
ARSServicePort = GetInt32Value("Gateway", "arsPort", 4005);
/*
GWID = Convert.ToInt32(source.Configs["Gateway"].Get("id"));
registrationPort = Convert.ToInt32(source.Configs["Gateway"].Get("regPort"));
pingInterval = Convert.ToInt32(source.Configs["Gateway"].Get("pingInterval"));
TESTMODE = Convert.ToBoolean(source.Configs["Gateway"].Get("testmode"));
*/
if (source.Configs["Database"] == null)
source.Configs.Add("Database");
ApplicationServer = GetStringValue("Server", "IP", "127.0.0.1");
if (ApplicationServer.Equals("localhost"))
ApplicationServer = "127.0.0.1";
//DBSchema = GetStringValue("Database", "Schema", "safedispatchdb");
//DBUser = GetStringValue("Database", "User", "postgres");
//DBPass = GetStringValue("Database", "Passwd", "wizdemo26");
//DBPort = GetStringValue("Database", "Port", "5432");
/*
DBServer = source.Configs["Database"].Get("IP");
if (DBServer.Equals("localhost"))
DBServer = "127.0.0.1";
DBSchema = source.Configs["Database"].Get("Schema");
DBUser = source.Configs["Database"].Get("User");
DBPort = source.Configs["Database"].Get("Port");
DBPass = source.Configs["Database"].Get("Passwd");
*/
if (source.Configs["ARS Service"] == null)
source.Configs.Add("ARS Service");
capacityPlus = GetBooleanValue("ARS Service", "CapacityPlusEnabled", false);
masterRadioIP = GetStringValue("ARS Service", "MasterRadioIP", "192.168.10.1");
GetBooleanValue("ARS Service", "Scan for SU presence at statup", false);
GetInt32Value("ARS Service", "Invalidate SU after", 200);
GetInt32Value("ARS Service", "Refresh status", 1);
GetBooleanValue("ARS Service", "Start service at startup", true);
asioDriverName = GetStringValue("Voice", "driverName", "N/A");
/*
capacityPlus = Convert.ToBoolean(source.Configs["ARS Service"].Get("CapacityPlusEnabled"));
masterRadioIP = source.Configs["ARS Service"].Get("MasterRadioIP");
*/
if (source.Configs["MessageBus"] == null)
source.Configs.Add("MessageBus");
//messageBusIP = GetStringValue("MessageBus", "ip", "224.30.0.1");
//messageBusPort = GetStringValue("MessageBus", "port", "17233");
/*
messageBusIP = source.Configs["MessageBus"].Get("ip");
messageBusPort = source.Configs["MessageBus"].Get("port");
*/
if (source.Configs["Tallysman"] == null)
source.Configs.Add("Tallysman");
TallysmanServicePort = (ushort)GetInt32Value("Tallysman", "port", 4010);
/*
try
{
TallysmanServicePort = Convert.ToUInt16(source.Configs["Tallysman"].Get("port"));
}
catch
{
TallysmanServicePort = 4010;
}*/
TallysmanRequestInterval = GetInt32Value("Tallysman", "checkInterval", -1);
if (source.Configs["SMS"] == null)
source.Configs.Add("SMS");
wait4ack = GetBooleanValue("SMS", "wait4ack", true);
sms_sending_interval = GetInt32Value("SMS", "sending_interval", 1200);
number_of_retries = GetInt32Value("SMS", "number_of_retries", 3);
retry_interval_sec = GetInt32Value("SMS", "retry_interval_sec", 180);
/*
wait4ack = Convert.ToBoolean(source.Configs["SMS"].Get("wait4ack"));
sms_sending_interval = Convert.ToInt32(source.Configs["SMS"].Get("sending_interval"));
number_of_retries = Convert.ToInt32(source.Configs["SMS"].Get("number_of_retries"));
if (source.Configs["SMS"].Contains("retry_interval_sec"))
retry_interval_sec = Convert.ToInt32(source.Configs["SMS"].Get("retry_interval_sec"));
*/
if (source.Configs["Update"] == null)
source.Configs.Add("Update");
autoupdate = GetBooleanValue("Update", "autoupdate", true);
if (source.Configs["Update"].Contains("develop"))
isDevelope = source.Configs["Update"].GetBoolean("develop");
GetStringValue("Update", "Version", "1.0.0.2");
GetBooleanValue("Update", "Enable", true);
/*
try
{
if (!source.Configs["Update"].Contains("autoupdate"))
source.Configs["Update"].Set("autoupdate", true);
autoupdate = source.Configs["Update"].GetBoolean("autoupdate");
if (source.Configs["Update"].Contains("develop"))
isDevelope = source.Configs["Update"].GetBoolean("develop");
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("AUTOUPDATE " + ex.ToString(), ConsoleColor.Red);
}
*/
if (source.Configs["Voice"] == null)
source.Configs.Add("Voice");
GetBooleanValue("Voice", "onOFF", false);
GetStringValue("Voice", "SelectedOutDevice", "");
GetStringValue("Voice", "SelectedInDevice", "");
GetStringValue("Voice", "RadioIP", "192.168.10.40");
GetStringValue("Voice", "MulticastIP", "224.30.0.1");
GetInt32Value("Voice", "Port", 17234);
string audioDriver = GetStringValue("Voice", "driver", "windows");
if (audioDriver.ToLower() == "asio")
AudioDriver = AudioDriverType.Asio;
else
AudioDriver = AudioDriverType.Windows;
//GetInt32Value("Voice", "radioNr", 0);
/*
[Voice]
SelectedOutDevice = Speakers(USB VoIP Device)
SelectedInDevice = Microphone(USB VoIP Device)
RadioIP = 192.168.10.40
MulticastIP = 224.30.0.1
onOFF = false
port = 17234*/
source.Save();
SafeMobileLib.Utils.WriteLine("Gateway ID:" + GWID, ConsoleColor.Green);
SafeMobileLib.Utils.WriteLine("Ping Interval:" + pingInterval, ConsoleColor.Green);
#region LINX
#if LINXB
_minSipPort = GetInt32Value("LINX", "minSipPort", 3024);
_maxSipPort = GetInt32Value("LINX", "maxSipPort", 3999);
if (_maxSipPort <= _minSipPort)
{
// Error in config file. Get back to defaults
_minSipPort = 3024;
_maxSipPort = 3999;
}
SafeMobileLib.Utils.WriteLine($"Sip Ports Range: {_minSipPort} - {_maxSipPort}", ConsoleColor.Green);
#endif
#endregion
if (TESTMODE)
{
SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
SafeMobileLib.Utils.WriteLine("---------------------------------------");
SafeMobileLib.Utils.WriteLine("!!!!Warning TEST MODE activated!!!!!");
SafeMobileLib.Utils.WriteLine("If this is a live GW please go to config and mask GATEWAY->testmode = false;");
SafeMobileLib.Utils.WriteLine("---------------------------------------");
SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
SafeMobileLib.Utils.WriteLine("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW");
}
}
catch (Exception e)
{
SafeMobileLib.Utils.WriteLine("LoadConfig Exception" + e.ToString(), ConsoleColor.Red);
}
}
/// <summary>
/// Get an int value from the configuration file. The desired value is identifiec by
/// the key and the header under which is placed is pointed by the header. Also a default
/// value can be set in case the value doesn't exist and needs to be created before
/// beeing returned
/// </summary>
/// <param name="header">Header unde which the desired config parameter is placed</param>
/// <param name="key">The Key that designates the desired config parameter</param>
/// <param name="defaultValue">A default value that will be used and returned in case the
/// config file doesn't have a value for the parameter</param>
/// <returns>Parameter value from the config file, or the default value in case it doesn't
/// exist</returns>
private Int32 GetInt32Value(String header, String key, Int32 defaultValue)
{
if (!source.Configs[header].Contains(key))
source.Configs[header].Set(key, defaultValue);
return source.Configs[header].GetInt(key);
}
/// <summary>
/// Get a string value from the configuration file. The desired value is identifiec by
/// the key and the header under which is placed is pointed by the header. Also a default
/// value can be set in case the value doesn't exist and needs to be created before
/// beeing returned
/// </summary>
/// <param name="header">Header unde which the desired config parameter is placed</param>
/// <param name="key">The Key that designates the desired config parameter</param>
/// <param name="defaultValue">A default value that will be used and returned in case the
/// config file doesn't have a value for the parameter</param>
/// <returns>Parameter value from the config file, or the default value in case it doesn't
/// exist</returns>
private String GetStringValue(String header, String key, String defaultValue)
{
if (!source.Configs[header].Contains(key))
source.Configs[header].Set(key, defaultValue);
return source.Configs[header].GetString(key);
}
/// <summary>
/// Get a boolean value from the configuration file. The desired value is identifiec by
/// the key and the header under which is placed is pointed by the header. Also a default
/// value can be set in case the value doesn't exist and needs to be created before
/// beeing returned
/// </summary>
/// <param name="header">Header unde which the desired config parameter is placed</param>
/// <param name="key">The Key that designates the desired config parameter</param>
/// <param name="defaultValue">A default value that will be used and returned in case the
/// config file doesn't have a value for the parameter</param>
/// <returns>Parameter value from the config file, or the default value in case it doesn't
/// exist</returns>
private Boolean GetBooleanValue(String header, String key, Boolean defaultValue)
{
if (!source.Configs[header].Contains(key))
source.Configs[header].Set(key, defaultValue);
return source.Configs[header].GetBoolean(key);
}
private void testIfAlreadyRunning()
{
Process[] processlist = Process.GetProcesses();
Process curentP = Process.GetCurrentProcess();
int count = 0;
foreach (Process theprocess in processlist)
{
if (theprocess.ProcessName == curentP.ProcessName)
{
count++;
}
}
if (count > 1)
{
SafeMobileLib.Utils.WriteLine("App already running!!!");
FeedbackRadMessageBox.ShowError("Aplication already running!!", "error");
foreach (Process theprocess in processlist)
{
if (theprocess.ProcessName == curentP.ProcessName)
{
SafeMobileLib.Utils.WriteLine($"Process: {theprocess.ProcessName} ID: {theprocess.Id}");
SafeMobileLib.Utils.WriteLine($"Curent Process: {curentP.ProcessName} ID: {curentP.Id}");
if (theprocess.Id != curentP.Id)
{
SafeMobileLib.Utils.WriteLine($"Killing Process: {theprocess.ProcessName} ID: {theprocess.Id}");
theprocess.Kill();
}
}
}
Thread.Sleep(1000);
}
}
#endregion
#region tabs load functions
private void radRibbonBar1_CommandTabSelected(object sender, Telerik.WinControls.UI.CommandTabEventArgs args)
{
if (args.CommandTab == tabVoice)
{
SafeMobileLib.Utils.WriteLine("Why load Voice Tab here???", ConsoleColor.Magenta);
//LoadVoiceTab(true);
}
}
private void LoadRadioTab(bool mainTab)
{
if (mainTab)
{
voiceMainCTRL = new controlVoiceMain();
voiceMainCTRL.Dock = System.Windows.Forms.DockStyle.Fill;
MainPanel.Controls.Clear();
MainPanel.Controls.Add(voiceMainCTRL);
_listOfRadioForms = voiceMainCTRL.radiosFormList;
#if LINXB
foreach (radioForm radioF in voiceMainCTRL.radiosFormList)
{
radioF.StartedRadioComHandler += RadioF_StartedRadioComHandler;
radioF.StoppingRadioComHandler += RadioF_StoppingRadioComHandler;
}
#endif
}
}
#endregion
private void btnVoiceAdd_Click(object sender, EventArgs e)
{
//voiceMainCTRL.AddNewRadio();
}
private void btnVoiceRemove_Click(object sender, EventArgs e)
{
//voiceMainCTRL.RemoveRadio();
}
private void Main_FormClosing(object sender, FormClosingEventArgs e)
{
wf?.Close();
Program.isRunning = false;
SafeMobileLib.Utils.WriteEventLog("SafeMobile", "Gateway Closing", EventLogEntryType.Information, 21523);
if (voiceMainCTRL != null)
{
voiceMainCTRL.SaveConfigForRadios();
try
{
// Clear voice resources
ClearAsioResources();
foreach (radioForm r in voiceMainCTRL.radiosFormList)
{
if (r.rcHandler != null)
{
//if (r.rcHandler.nVOice != null)
// r.rcHandler.nVOice.Dispose();
//if (r.rcHandler.waveOutClass != null)
//{
// r.rcHandler.waveOutClass.Dispose();
// r.rcHandler.waveOutClass = null;
//}
//if (r.rcHandler.waveInClass != null)
//{
// r.rcHandler.waveInClass.DataAvailable -= r.rcHandler.waveInClass_DataAvailable;
// r.rcHandler.waveInClass.Dispose();
// r.rcHandler.waveInClass = null;
//}
r.rcHandler.ClearVoiceResources();
}
}
#region LINX
#if LINXB
if (_sipGateway != null)
{
_sipGateway.Stop();
}
#endif
#endregion
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Main_FormClosing: " + ex.ToString(), ConsoleColor.Red);
}
}
}
private void ClearAsioResources()
{
if (_audioManager != null)
{
_audioManager.AsioAudioAvailable -= AudioManager_AsioAudioAvailable;
_audioManager.PlaybackStopped -= AudioManager_PlaybackStopped;
_audioManager.Dispose();
_audioManager = null;
}
}
/// <summary>
/// Close necessary things before closing the app
/// </summary>
private void CloseApp()
{
// close necessary things in the app
Main_FormClosing(null, null);
Process oldProcess = Process.GetCurrentProcess();
oldProcess.Kill();
Application.Exit();
}
/// <summary>
/// Update a specific config file parameter from a desired category.
/// </summary>
/// <param name="category">Category in which the parameter is located</param>
/// <param name="option">Parameter which needs to be updated</param>
/// <param name="value">New value for the desired parameter</param>
public static void UpdateConfigParameter(string category, string option, string value)
{
try
{
source = new IniConfigSource(CFG_FILE);
//DataBase
source.Configs[category].Set(option, value);
// Save the INI file
source.Save();
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine(ex.ToString());
}
}
private void Main_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
this.Visible = false;
notifyIcon1.Visible = true;
}
}
private void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
this.Visible = true;
this.WindowState = FormWindowState.Normal;
notifyIcon1.Visible = false;
}
private void radCheckBoxElement1_Click(object sender, EventArgs e)
{
try
{
if (!cbCapacityPlus.Checked)
{
CapacityPlusIP tmp = new CapacityPlusIP(masterRadioIP);
tmp.ShowDialog();
System.Threading.Timer tCheckSTATUS = new System.Threading.Timer(UncheckCapPlus, null, 500, System.Threading.Timeout.Infinite);
}
else
{
lbMasterIP.Text = "";
RestoreDefaulCapacityConfig();
}
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Error on click capacityPuls:"+ex.ToString(), ConsoleColor.Red);
}
}
private void Main_Load(object sender, EventArgs e)
{
ContextMenu contextMenu = new ContextMenu();
contextMenu.MenuItems.Add("Check for updates...", (s, e2) => {
UpdateForm uf = new UpdateForm(App.GW_TRBO, true) { IsDevelop = Main.isDevelope };
uf.Show();
});
contextMenu.MenuItems.Add("Exit", (s, e2) => CloseApp());
notifyIcon1.ContextMenu = contextMenu;
// check for a new version if available
if(Main.isDevelope)
CheckForUpdate(false);
}
#region UPDATE
/// <summary>
/// Check for new version release on SafeMobile Portal
/// The check is done by comparing Current Assembly Version with the one
/// written in a xml file on the portal.
/// </summary>
private void CheckForUpdate(bool isModal)
{
App appType = App.GW_TRBO;
if (isModal)
{
UpdateForm uf = new UpdateForm(appType, true) { IsDevelop = Main.isDevelope };
uf.ShowDialog();
}
else
{
AutoUpdate au = new AutoUpdate(appType) { IsDevelop = Main.isDevelope };
au.OnNewVersionAvailable += delegate (string version)
{
if (APP_SERVER_VERSION.Split('.')[2].Equals(version.Split('.')[2]))
{
notifyIcon1.Text = "New version available";
notifyIcon1.ShowBalloonTip(2500, $"{App.GetAppName(appType)} version {version} available",
$"Press to download and install the latest version of {App.GetAppName(appType)}.", ToolTipIcon.Info);
notifyIcon1.BalloonTipClicked += delegate (object sender, EventArgs e)
{
if (notifyIcon1.Text.Equals("New version available"))
{
UpdateForm uf = new UpdateForm(appType, true) { IsDevelop = Main.isDevelope };
uf.Show();
}
};
}
else
SafeMobileLib.Utils.WriteLine("New version available but AppServer is an old version stil");
};
// call method to check for new updated
au.CheckUpdate();
}
}
#endregion
private void UncheckCapPlus(Object state)
{
try
{
cbCapacityPlus.Checked = false;
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Unable to uncheck capacityPuls:"+ex.ToString(), ConsoleColor.Red);
}
}
public void RestoreDefaulCapacityConfig()
{
source = new IniConfigSource(Main.CFG_FILE);
source.Configs["ARS Service"].Set("MasterRadioIP", "192.168.10.40");
source.Configs["ARS Service"].Set("CapacityPlusEnabled", "False");
source.Save();
}
internal static List<radioForm.sDevice> GetAsioInputDevices()
{
return _audioManager?.GetAsioInputDevices();
}
internal static List<radioForm.sDevice> GetAsioOutputDevices()
{
return _audioManager?.GetAsioOutputDevices();
}
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
try
{
//System.Environment.Exit(0);
Application.Exit();
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("Error on closing: "+ex.ToString(), ConsoleColor.Red);
}
}
private void settingsRibbon_Click(object sender, EventArgs e)
{
SettingsForm sf = new SettingsForm();
sf.ShowDialog();
}
private void RadioF_StoppingRadioComHandler(object sender, RadioComHandler rcHandler)
{
#if LINXB
// Remove event halders
rcHandler.LinxCallEstablished -= RcHandler_LinxCallEstablished;
rcHandler.CallLinx -= RcHandler_CallLinx;
rcHandler.RadioEndsPTTtoLinx -= RcHandler_RadioEndsPTTtoLinx;
rcHandler.RadioVoiceToLinx -= RcHandler_RadioVoiceToLinx;
rcHandler.RadioSipIDRequested -= RcHandler_RadioSipIDRequested;
rcHandler.LinxIDForPrivateCallRequested -= RcHandler_LinxIDForPrivateCallRequested;
rcHandler.LinxCallFailed -= RcHandler_LinxCallFailed;
#endif
}
private void RadioF_StartedRadioComHandler(object sender, RadioComHandler rcHandler)
{
#if LINXB
// Add event handlers
rcHandler.LinxCallEstablished += RcHandler_LinxCallEstablished;
rcHandler.CallLinx += RcHandler_CallLinx;
rcHandler.RadioEndsPTTtoLinx += RcHandler_RadioEndsPTTtoLinx;
rcHandler.RadioVoiceToLinx += RcHandler_RadioVoiceToLinx;
rcHandler.RadioSipIDRequested += RcHandler_RadioSipIDRequested;
rcHandler.LinxIDForPrivateCallRequested += RcHandler_LinxIDForPrivateCallRequested;
rcHandler.LinxCallFailed += RcHandler_LinxCallFailed;
#endif
}
}
public class ShapeNew : ShapedForm
{
public Boolean typeRadio = true;
public Int32 ID = 0;
public Boolean Selected = false;
public Boolean VoiceON = true;
}
public enum AudioDriverType
{
Windows,
Asio,
Unknown
}
}