546 lines
25 KiB
C#
546 lines
25 KiB
C#
|
using SafeMobileLib;
|
|||
|
using SipComponent;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Net;
|
|||
|
using System.Net.Sockets;
|
|||
|
using System.Text;
|
|||
|
using System.Threading;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
namespace MotoTrbo_GW.LINX
|
|||
|
{
|
|||
|
public class TrboSipGateway
|
|||
|
{
|
|||
|
private string _sipServerIP;
|
|||
|
private int _sipServerPort, _webServicePort, _minSipPort, _maxSipPort;
|
|||
|
private Dictionary<int, RadioSipInfo> _sipIDToRadioSipInfoDict = new Dictionary<int, RadioSipInfo>();
|
|||
|
private bool _connectedToAsterisk = false;
|
|||
|
private object _lockerConnectedToAstersik = new object();
|
|||
|
private volatile bool _unregistering = false;
|
|||
|
private IEnumerable<ContactLinx> _contactsToRegister;
|
|||
|
private Dictionary<LINX.RadioIdKey, int> _motoRadioIDToSipID_dict = new Dictionary<RadioIdKey, int>();
|
|||
|
private Dictionary<int, int> _radioGroupSipIDToListeningLINX = new Dictionary<int, int>();
|
|||
|
private Dictionary<int, int> _linxRadioIdToLinxSipID_dict = new Dictionary<int, int>();
|
|||
|
private Dictionary<int, int> _linxSipIDToLinxRadioID_dict = new Dictionary<int, int>();
|
|||
|
private Dictionary<int, int> _radioIDtoLinxSipIDforPrivateCall_dict = new Dictionary<int, int>();
|
|||
|
private string _msgForErrorOnRegister = "Not all the radios are connected to Linx server.Check sip ports range in config file";
|
|||
|
private HashSet<int> _setOfUnavalablePorts = new HashSet<int>();
|
|||
|
DBcontactsManager _dbContactsManager = null;
|
|||
|
DBgroupsManager _dbgroupsManager = null;
|
|||
|
|
|||
|
public TrboSipGateway(string appServerIP, string dbSchema, string user, string password, string dbPort, int minSipPort, int maxSipPort, out bool errorOnRegister)
|
|||
|
{
|
|||
|
// Get sip server ip and port from database
|
|||
|
// Get asterisk server's ip and sip port
|
|||
|
DBsettingsManager dbSettingsManager = new DBsettingsManager(
|
|||
|
appServerIP, dbSchema, user, password, dbPort);
|
|||
|
_sipServerIP = dbSettingsManager.getSettingValue(0, "lanLinxServer");
|
|||
|
string sSipServerPort = dbSettingsManager.getSettingValue(0, "lanSipPort");
|
|||
|
string sWebServicePort = dbSettingsManager.getSettingValue(0, "lanSigPort");
|
|||
|
_minSipPort = minSipPort;
|
|||
|
_maxSipPort = maxSipPort;
|
|||
|
errorOnRegister = false;
|
|||
|
if (!string.IsNullOrEmpty(_sipServerIP) && !string.IsNullOrEmpty(sWebServicePort) && !string.IsNullOrEmpty(sSipServerPort))
|
|||
|
{
|
|||
|
if (int.TryParse(sSipServerPort, out _sipServerPort) && int.TryParse(sWebServicePort, out _webServicePort))
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine($"LINX version\nRegistering with sip server {_sipServerIP}:{_sipServerPort}, signalling on {_sipServerIP}:{_webServicePort}",
|
|||
|
ConsoleColor.Green);
|
|||
|
// Get list of motorla units and groups to register
|
|||
|
_dbContactsManager = new DBcontactsManager(appServerIP, dbSchema, user, password, dbPort);
|
|||
|
_dbgroupsManager = new DBgroupsManager(appServerIP, dbSchema, user, password, dbPort);
|
|||
|
_contactsToRegister = GetListOfContactsToRegister(_dbContactsManager);
|
|||
|
// Register
|
|||
|
RegisterToSipServer(_contactsToRegister, out errorOnRegister);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#region Public Members
|
|||
|
|
|||
|
public bool ConnectedToAstersisk
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
lock (_lockerConnectedToAstersik)
|
|||
|
{
|
|||
|
return _connectedToAsterisk;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public SipClientClass2 GetSipClass(int radioSipID)
|
|||
|
{
|
|||
|
return _sipIDToRadioSipInfoDict[radioSipID].SipClass;
|
|||
|
}
|
|||
|
|
|||
|
public void SendInvite(int radioSipID, string linxSipID)
|
|||
|
{
|
|||
|
if (LinxSipIDisGroup(int.Parse(linxSipID)))
|
|||
|
this.GetSipClass(radioSipID).InviteGroup(linxSipID.ToString());
|
|||
|
else
|
|||
|
this.GetSipClass(radioSipID).Invite(linxSipID.ToString());
|
|||
|
}
|
|||
|
|
|||
|
public bool LinxSipIDisGroup(int linxSipID)
|
|||
|
{
|
|||
|
return !_linxSipIDToLinxRadioID_dict.ContainsKey(linxSipID);
|
|||
|
}
|
|||
|
|
|||
|
internal int? GetLinxInRadioGroup(int groupRadioID)
|
|||
|
{
|
|||
|
int groupSipID = GetSipIDFromRadioID(groupRadioID, true);
|
|||
|
if (_radioGroupSipIDToListeningLINX.ContainsKey(groupSipID))
|
|||
|
{
|
|||
|
return _radioGroupSipIDToListeningLINX[groupSipID];
|
|||
|
}
|
|||
|
else
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
internal int? GetLinxForPrivateCall(int radioID)
|
|||
|
{
|
|||
|
if (_radioIDtoLinxSipIDforPrivateCall_dict.ContainsKey(radioID))
|
|||
|
return _radioIDtoLinxSipIDforPrivateCall_dict[radioID];
|
|||
|
else
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <para>Returns the sip id of a radio unit or group,</para>
|
|||
|
/// <para>or the received radioID if the radio is not on the list of registered radios</para>
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio id of a radio or a radio group</param>
|
|||
|
/// <param name="isGroup">True if is id is for radio group, otherwise false</param>
|
|||
|
/// <returns>The sip id of a radio unit or group, or the received radio id if the sip id is not found</returns>
|
|||
|
internal int GetSipIDFromRadioID(int radioID, bool isGroup)
|
|||
|
{
|
|||
|
LINX.RadioIdKey radioKey = new RadioIdKey(radioID, isGroup);
|
|||
|
if (_motoRadioIDToSipID_dict.ContainsKey(radioKey))
|
|||
|
return _motoRadioIDToSipID_dict[radioKey];
|
|||
|
else
|
|||
|
return radioID;
|
|||
|
}
|
|||
|
|
|||
|
public void ListOfSipIDHasChanged()
|
|||
|
{
|
|||
|
//Unregister from sip server
|
|||
|
UnregisterFromSipServer();
|
|||
|
// Read new data from database
|
|||
|
_contactsToRegister = GetListOfContactsToRegister(_dbContactsManager);
|
|||
|
// Register again to Sip server for the new ID's
|
|||
|
bool errorOnregister = false;
|
|||
|
RegisterToSipServer(_contactsToRegister, out errorOnregister);
|
|||
|
}
|
|||
|
|
|||
|
public async Task<bool> SendSmsToLinx(string seqID, int linxRadioID, int remoteRadioID, string text)
|
|||
|
{
|
|||
|
// Get linx sip id from linx radio id
|
|||
|
int linxSipID = -1;
|
|||
|
bool smsReceivedByLinx = false;
|
|||
|
if (_linxRadioIdToLinxSipID_dict.ContainsKey(linxRadioID))
|
|||
|
{
|
|||
|
linxSipID = _linxRadioIdToLinxSipID_dict[linxRadioID];
|
|||
|
int radioSipID = GetSipIDFromRadioID(remoteRadioID, false);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
smsReceivedByLinx = await _sipIDToRadioSipInfoDict[radioSipID].SipClass.SendSmsAsync(linxSipID.ToString(), text);
|
|||
|
}
|
|||
|
}
|
|||
|
return smsReceivedByLinx;
|
|||
|
}
|
|||
|
|
|||
|
public void PrivateCallRequestFromRadioReceived(int remoteRadioID, int linxRadioID)
|
|||
|
{
|
|||
|
// Radio with "remoteRadioID" wants to make private call to linx with "linxRadioID"
|
|||
|
// Check if the radio has right (in Admin) to make private call to this linx
|
|||
|
if (RadioCanMakePrivateCallToLinx(remoteRadioID, linxRadioID))
|
|||
|
{
|
|||
|
if (_linxRadioIdToLinxSipID_dict.ContainsKey(linxRadioID))
|
|||
|
{
|
|||
|
// Create (update) the correspondence between the radio and linx for private call
|
|||
|
_radioIDtoLinxSipIDforPrivateCall_dict[remoteRadioID] = _linxRadioIdToLinxSipID_dict[linxRadioID];
|
|||
|
// Notify the radio by sending an sms
|
|||
|
SmsFromLinxToRadio?.Invoke(_sipIDToRadioSipInfoDict[GetSipIDFromRadioID(remoteRadioID, false)].ContactInfo,
|
|||
|
"Private PTT to dispatcher is redirected to me", linxRadioID);
|
|||
|
}
|
|||
|
else if (linxRadioID == 0)
|
|||
|
{
|
|||
|
if (_radioIDtoLinxSipIDforPrivateCall_dict.ContainsKey(remoteRadioID))
|
|||
|
{
|
|||
|
int linxSipID = _radioIDtoLinxSipIDforPrivateCall_dict[remoteRadioID];
|
|||
|
// this means that the radio want's to talk with the dispatcher (to reset the link with Linx)
|
|||
|
_radioIDtoLinxSipIDforPrivateCall_dict.Remove(remoteRadioID);
|
|||
|
// Notify the radio by sending an sms
|
|||
|
SmsFromLinxToRadio?.Invoke(_sipIDToRadioSipInfoDict[GetSipIDFromRadioID(remoteRadioID, false)].ContactInfo,
|
|||
|
"Private PTT is now redirected to dispatcher", _linxSipIDToLinxRadioID_dict[linxSipID]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public void Stop()
|
|||
|
{
|
|||
|
UnregisterFromSipServer();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Private Sip methods
|
|||
|
|
|||
|
private void RegisterToSipServer(IEnumerable<ContactLinx> contactsToRegister, out bool exceptionOnRegister)
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("Starting registration......", ConsoleColor.Green);
|
|||
|
int linxListeningToGroup = -1;
|
|||
|
string localIPAddres = BestLocalEndPoint(new IPEndPoint(IPAddress.Parse(_sipServerIP), _sipServerPort)).Address.ToString();
|
|||
|
exceptionOnRegister = false;
|
|||
|
foreach (ContactLinx c in contactsToRegister)
|
|||
|
{
|
|||
|
Random r = new Random();
|
|||
|
// Get available port for sip messages
|
|||
|
int sipPort = ReturnAvailableSIPport(_minSipPort, _maxSipPort);
|
|||
|
|
|||
|
// Create sip Class
|
|||
|
SipClientClass2 sipClass = null;
|
|||
|
try
|
|||
|
{
|
|||
|
sipClass = CreateSipClass(_sipServerIP, _sipServerPort, _webServicePort, sipPort, c.SipId, c.Sippwd, r.Next(30, 57), 32, 10000,
|
|||
|
localIPAddres);
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
SafeMobileLib.Utils.WriteLine("Could not register to Asterisk for motorola " + c.Name + $"(radio id {c.Id} )" +
|
|||
|
$" with sipID {c.SipId} on local sip port {sipPort}\n" + ex.ToString(), ConsoleColor.Red);
|
|||
|
_setOfUnavalablePorts.Add(sipPort);
|
|||
|
exceptionOnRegister = true;
|
|||
|
continue;
|
|||
|
}
|
|||
|
_sipIDToRadioSipInfoDict.Add(c.SipId, new RadioSipInfo(sipClass, c));
|
|||
|
_motoRadioIDToSipID_dict.Add(new RadioIdKey(c.Id, c.Type == ContactType.GROUP), c.SipId);
|
|||
|
// LINX listening to radio Groups
|
|||
|
|
|||
|
if (c.Type == ContactType.GROUP)
|
|||
|
{
|
|||
|
// Check if a LINX is listening to this radio group
|
|||
|
if ((linxListeningToGroup = _dbgroupsManager.getLinxSIPIdForGroupSIPid(c.SipId)) != -1)
|
|||
|
_radioGroupSipIDToListeningLINX.Add(c.SipId, linxListeningToGroup);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void UnregisterFromSipServer()
|
|||
|
{
|
|||
|
foreach (ContactLinx c in _contactsToRegister)
|
|||
|
{
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(c.SipId))
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = _sipIDToRadioSipInfoDict[c.SipId].SipClass;
|
|||
|
RemoveEventHandlers(sipClass);
|
|||
|
sipClass.Stop(false);
|
|||
|
Thread.Sleep(10);
|
|||
|
}
|
|||
|
}
|
|||
|
_sipIDToRadioSipInfoDict.Clear();
|
|||
|
_motoRadioIDToSipID_dict.Clear();
|
|||
|
_radioGroupSipIDToListeningLINX.Clear();
|
|||
|
}
|
|||
|
|
|||
|
private SipClientClass2 CreateSipClass(string sipServerIP, int sipServerPort, int socketI0Port, int localSipPort, int userName, string password,
|
|||
|
int registrationInterval, int bufferMiliseconds, int requestTimeout, string localIP)
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = new SipClientClass2(sipServerIP, sipServerPort, localSipPort, userName.ToString(), password,
|
|||
|
registrationInterval, bufferMiliseconds, requestTimeout, socketI0Port, false, localIP);
|
|||
|
sipClass.MaxNbOfDialogs = 1; // Just one sip dialog permited
|
|||
|
sipClass.SmsConfirmationFromAsterisk = true;
|
|||
|
sipClass.MinRtpPortNumber = 26284;
|
|||
|
sipClass.MaxRtpPortNumber = 26300;
|
|||
|
|
|||
|
// Add event handlers
|
|||
|
AddEventHandlers(sipClass);
|
|||
|
|
|||
|
return sipClass;
|
|||
|
}
|
|||
|
|
|||
|
private void AddEventHandlers(SipClientClass2 sipClass)
|
|||
|
{
|
|||
|
sipClass.RegistrationStateChanged += SipClass_RegistrationStateChanged;
|
|||
|
sipClass.InviteReceived += SipClass_InviteReceived;
|
|||
|
sipClass.DialogCreated += SipClass_DialogCreated;
|
|||
|
sipClass.VoiceReceived += SipClass_VoiceReceived;
|
|||
|
sipClass.DialogClosed += SipClass_DialogClosed;
|
|||
|
//sipClass.HangtimeEnded += SipClass_HangtimeEnded;
|
|||
|
sipClass.ErrorOnCreatingDialog += SipClass_ErrorOnCreatingDialog;
|
|||
|
sipClass.SipSmsReceived += SipClass_SipSmsReceived;
|
|||
|
}
|
|||
|
|
|||
|
private void RemoveEventHandlers(SipClientClass2 sipClass)
|
|||
|
{
|
|||
|
sipClass.RegistrationStateChanged -= SipClass_RegistrationStateChanged;
|
|||
|
sipClass.InviteReceived -= SipClass_InviteReceived;
|
|||
|
sipClass.DialogCreated -= SipClass_DialogCreated;
|
|||
|
sipClass.VoiceReceived -= SipClass_VoiceReceived;
|
|||
|
sipClass.DialogClosed -= SipClass_DialogClosed;
|
|||
|
//sipClass.HangtimeEnded -= SipClass_HangtimeEnded;
|
|||
|
sipClass.ErrorOnCreatingDialog -= SipClass_ErrorOnCreatingDialog;
|
|||
|
sipClass.SipSmsReceived -= SipClass_SipSmsReceived;
|
|||
|
}
|
|||
|
|
|||
|
private bool RadioCanMakePrivateCallToLinx(int remoteRadioID, int linxRadioID)
|
|||
|
{
|
|||
|
// Check that the radio sending the request is registered to Asterisk by the gateway
|
|||
|
int radioSipID = GetSipIDFromRadioID(remoteRadioID, false);
|
|||
|
if (radioSipID == remoteRadioID) // the radio sip id was not found, the function returned te radio id
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Check that the linx radio id exists
|
|||
|
bool linxExists = _linxRadioIdToLinxSipID_dict.ContainsKey(linxRadioID);
|
|||
|
if (linxExists)
|
|||
|
{
|
|||
|
// Check if the radio has right in Admin to make private PTT to the linx
|
|||
|
// ..... code that checks that .......
|
|||
|
return true;
|
|||
|
}
|
|||
|
else if (linxRadioID == 0)
|
|||
|
{
|
|||
|
return true; // this will reset the link with Linx
|
|||
|
}
|
|||
|
else
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
#region SipClientClass Event Handlers
|
|||
|
|
|||
|
private void SipClass_RegistrationStateChanged(object sender, RegistrationStateChangedEventArgs e)
|
|||
|
{
|
|||
|
bool connectedToAsterisk = (e.Reason == RegistrationStatus.Registered);
|
|||
|
SafeMobileLib.Utils.WriteLine($"Sip id's {e.RegisteredId} registration status is \"{e.Reason}\"",
|
|||
|
connectedToAsterisk ? ConsoleColor.Green : ConsoleColor.Red);
|
|||
|
lock (_lockerConnectedToAstersik)
|
|||
|
{
|
|||
|
if (this._connectedToAsterisk != connectedToAsterisk)
|
|||
|
{
|
|||
|
_connectedToAsterisk = connectedToAsterisk;
|
|||
|
// fire event
|
|||
|
ConnectionStatusChanded?.Invoke(_connectedToAsterisk);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//// Restart gw if error on IndependentSoft library (when Asterisk is down)
|
|||
|
if (e.Reason == RegistrationStatus.SocketError && !_unregistering)
|
|||
|
{
|
|||
|
_unregistering = true;
|
|||
|
string message = "Unregistering from Sip Server....";
|
|||
|
SafeMobileLib.Utils.WriteLine(message, ConsoleColor.Green);
|
|||
|
|
|||
|
// Start a task with a delay of 5s that will unregister and register again to Sip server for the new IDs
|
|||
|
Task.Delay(5000).ContinueWith(t =>
|
|||
|
{
|
|||
|
UnregisterFromSipServer();
|
|||
|
Thread.Sleep(3000);
|
|||
|
_unregistering = false;
|
|||
|
string message1 = "Unregistered from Sip Server. Will start registration";
|
|||
|
SafeMobileLib.Utils.WriteLine(message1, ConsoleColor.Green);
|
|||
|
Thread.Sleep(3000);
|
|||
|
bool exceptionOnRegister = false;
|
|||
|
RegisterToSipServer(_contactsToRegister, out exceptionOnRegister);
|
|||
|
if (exceptionOnRegister)
|
|||
|
ShowUIMessage?.Invoke(_msgForErrorOnRegister);
|
|||
|
});
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SipClass_InviteReceived(object sender, InviteReceivedArgs e)
|
|||
|
{
|
|||
|
//throw new NotImplementedException();
|
|||
|
SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
SafeMobileLib.Utils.WriteLine($"Sip id {e.SipIDsendingInvite} sends invite to radio with sip id {radioSipID}", ConsoleColor.Green);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
LinxSendsInvite?.Invoke(_sipIDToRadioSipInfoDict[radioSipID], e.SipIDsendingInvite);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SipClass_ErrorOnCreatingDialog(object sender, ErrorEventArgs e)
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
SafeMobileLib.Utils.WriteLine($"Error on creating dialog when sip id {e.FromID} sent invite to {e.ToID}; Reason: {e.Reason}",
|
|||
|
ConsoleColor.Red);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
bool inviteWasSentbyRadio = e.FromID == sipClass.UserName;
|
|||
|
ErrorOnCreatingDialog?.Invoke(_sipIDToRadioSipInfoDict[radioSipID], inviteWasSentbyRadio ? e.ToID : e.FromID, inviteWasSentbyRadio);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//private void SipClass_HangtimeEnded(object sender, HangtimeEndedEventArgs e)
|
|||
|
//{
|
|||
|
// SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
// int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
// SafeMobileLib.Utils.WriteLine($"Linx with sipID {e.SipIDinDialogWith} has ended hangtime with radio with sipID {radioSipID}",
|
|||
|
// ConsoleColor.Magenta);
|
|||
|
// if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
// {
|
|||
|
// LinxHangtimeEnded?.Invoke(_sipIDToRadioSipInfoDict[radioSipID], e.SipIDinDialogWith);
|
|||
|
// }
|
|||
|
//}
|
|||
|
|
|||
|
private void SipClass_SipSmsReceived(object sender, SmsReceivedEventsArgs e)
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
SafeMobileLib.Utils.WriteLine($"Sms from linx with sipID {e.SipIDinDialogWith} to radio with sipID {radioSipID}",
|
|||
|
ConsoleColor.Green);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
int linxSipID = int.Parse(e.SipIDinDialogWith);
|
|||
|
if (_linxSipIDToLinxRadioID_dict.ContainsKey(linxSipID))
|
|||
|
{
|
|||
|
SmsFromLinxToRadio?.Invoke(_sipIDToRadioSipInfoDict[radioSipID].ContactInfo, e.Message, _linxSipIDToLinxRadioID_dict[linxSipID]);
|
|||
|
}
|
|||
|
}
|
|||
|
//SmsReceived?.Invoke()
|
|||
|
}
|
|||
|
|
|||
|
private void SipClass_DialogClosed(object sender, LinxDialogClosedEventArgs e)
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
SafeMobileLib.Utils.WriteLine($"Dialog closed between linx with sipID {e.SipIDinDialogWith} and radio with sipID {radioSipID}",
|
|||
|
ConsoleColor.Green);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
DialogClosed?.Invoke(_sipIDToRadioSipInfoDict[radioSipID], e.SipIDinDialogWith, e.SipIDwhoClosed == sipClass.UserName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SipClass_VoiceReceived(object sender, LinxAudioEventArgs e)
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
VoiceReceived?.Invoke(_sipIDToRadioSipInfoDict[radioSipID], e.Buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
private void SipClass_DialogCreated(object sender, LinxDialogCreatedEventArgs e)
|
|||
|
{
|
|||
|
SipClientClass2 sipClass = (SipClientClass2)sender;
|
|||
|
int radioSipID = int.Parse(sipClass.UserName);
|
|||
|
// get the linx sip id
|
|||
|
string linxSipID = (e.FromID == sipClass.UserName ? e.ToID : e.FromID);
|
|||
|
if (_sipIDToRadioSipInfoDict.ContainsKey(radioSipID))
|
|||
|
{
|
|||
|
DialogCreated?.Invoke(_sipIDToRadioSipInfoDict[radioSipID], linxSipID, e.FromID == sipClass.UserName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
#region Private methods
|
|||
|
|
|||
|
private int ReturnAvailableSIPport(int minSipPort, int maxSipPort)
|
|||
|
{
|
|||
|
int sipPort = minSipPort;
|
|||
|
while (_setOfUnavalablePorts.Contains(sipPort) || IsPortAllreadyInUse(sipPort) && sipPort < maxSipPort)
|
|||
|
{
|
|||
|
sipPort++;
|
|||
|
}
|
|||
|
if (sipPort < maxSipPort)
|
|||
|
return sipPort;
|
|||
|
else
|
|||
|
throw new ApplicationException(
|
|||
|
string.Format("Nu gasesc port liber in range-ul {0} - {1}", minSipPort, maxSipPort));
|
|||
|
}
|
|||
|
|
|||
|
private bool IsPortAllreadyInUse(int portNumber)
|
|||
|
{
|
|||
|
|
|||
|
return (from p in System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners()
|
|||
|
where p.Port == portNumber
|
|||
|
select p).Count() == 1;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Determines the most appropriate local end point to contact the provided remote end point.
|
|||
|
/// Testing shows this method takes on average 1.6ms to return.
|
|||
|
/// </summary>
|
|||
|
/// <param name="remoteIPEndPoint">The remote end point</param>
|
|||
|
/// <returns>The selected local end point</returns>
|
|||
|
private static IPEndPoint BestLocalEndPoint(IPEndPoint remoteIPEndPoint)
|
|||
|
{
|
|||
|
Socket testSocket = new Socket(remoteIPEndPoint.AddressFamily, SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
|
|||
|
testSocket.Connect(remoteIPEndPoint);
|
|||
|
return (IPEndPoint)testSocket.LocalEndPoint;
|
|||
|
}
|
|||
|
|
|||
|
IEnumerable<ContactLinx> GetListOfContactsToRegister(DBcontactsManager contactsManager)
|
|||
|
{
|
|||
|
List<ContactLinx> dbContacts = contactsManager.getContactsForSIPgw(Main.GWID);
|
|||
|
// update the dictionary with Linx radio id to linx sip id
|
|||
|
_linxRadioIdToLinxSipID_dict.Clear();
|
|||
|
_linxSipIDToLinxRadioID_dict.Clear();
|
|||
|
foreach (ContactLinx contact in dbContacts)
|
|||
|
{
|
|||
|
if (contact.GWtype == GatewayType.Broadband && contact.Type == ContactType.UNIT)
|
|||
|
{
|
|||
|
// This is a linx unit (not group)
|
|||
|
_linxRadioIdToLinxSipID_dict.Add(contact.Id, contact.SipId);
|
|||
|
_linxSipIDToLinxRadioID_dict.Add(contact.SipId, contact.Id);
|
|||
|
}
|
|||
|
}
|
|||
|
// Select only units or groups
|
|||
|
var contactsToRegister = from contact in dbContacts
|
|||
|
where (contact.GWtype == GatewayType.Tier2Radio && (contact.Type == ContactType.GROUP || contact.Type == ContactType.UNIT))
|
|||
|
select contact;
|
|||
|
return contactsToRegister;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Events
|
|||
|
|
|||
|
public delegate void LinxToRadioDel(RadioSipInfo sipInfo, string linxID);
|
|||
|
public event LinxToRadioDel LinxSendsInvite;
|
|||
|
|
|||
|
public delegate void LinxToRadioDel2(RadioSipInfo sipInfo, string linxID, bool fromRadioToLinx);
|
|||
|
public event LinxToRadioDel2 DialogCreated;
|
|||
|
|
|||
|
public event LinxToRadioDel2 DialogClosed;
|
|||
|
|
|||
|
public event LinxToRadioDel2 ErrorOnCreatingDialog;
|
|||
|
|
|||
|
//public event LinxToRadioDel LinxHangtimeEnded;
|
|||
|
|
|||
|
public delegate void VoiceReceivedDel(RadioSipInfo sipInfo, byte[] buffer);
|
|||
|
public event VoiceReceivedDel VoiceReceived;
|
|||
|
|
|||
|
public delegate void ConnectionStatusChangedDel(bool connected);
|
|||
|
public event ConnectionStatusChangedDel ConnectionStatusChanded;
|
|||
|
|
|||
|
public delegate void SmsFromLinxToRadioDelegate(ContactLinx radioContactInfo, string message, int linxRadioID);
|
|||
|
public event SmsFromLinxToRadioDelegate SmsFromLinxToRadio;
|
|||
|
|
|||
|
public delegate void ShowUIMessageDel(string message);
|
|||
|
public event ShowUIMessageDel ShowUIMessage;
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|