using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using IpPbx.CLMgrLib; using C4IT.Logging; using static C4IT.Logging.cLogManager; using System.Runtime.Remoting.Channels; namespace F4SD_PhoneMonitor { public delegate void ActiveCallMessage(string phone, string name, bool isOutgoing); public class cCLMgrEvents { public ActiveCallMessage ActiveCallHandler; private ClientLineMgrClass pCLMgr = null; private ClientSdkEventSink MyEventSink = null; private PubCLMgrLineDetails lastChangedLineDetails; public bool Initialize() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { lastChangedLineDetails.m_sPeerName = null; lastChangedLineDetails.m_sPeerNumber = null; pCLMgr = new ClientLineMgrClass(); if (pCLMgr == null) { LogEntry("Error conntection SwyxIt client interface. Terminating...", LogLevels.Fatal); return false; } pCLMgr.GetVersion(out var Info); if (Info.dwMajorVersion < 11) { LogEntry("Incompatible SwyxIt client version. Terminating...", LogLevels.Fatal); return false; } MyEventSink = new ClientSdkEventSink(); MyEventSink.Connect(pCLMgr, new LineManagerMessageHandler(OnLineManagerMessage)); return true; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return false; } private void OnLineManagerMessage(ClientSdkEventArgs e) { var _msg = e.Msg.ToString(); if (int.TryParse(_msg, out _)) return; var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { LogEntry($"Client event signaled {e.Msg.ToString()}", LogLevels.Debug); switch (e.Msg) { case CLMgrMessage.CLMgrLineStateChangedMessage: IClientLinePub changedLinePub = (IClientLinePub)pCLMgr.DispGetLine(e.Param); PubCLMgrLineDetails changedLineDetails; changedLinePub.PubGetDetails(out changedLineDetails); lastChangedLineDetails = changedLineDetails; break; case CLMgrMessage.CLMgrLineStateChangedMessageEx: //Get Line int line = e.Param & 0xff; int high = e.Param >> 8; LineState NewLineState; //Get the LineState NewLineState = (LineState)high; LogEntry($"New line state: {NewLineState}", LogLevels.Debug); if (NewLineState == LineState.Active) { if (lastChangedLineDetails.m_sPeerNumber != null) { var IsOutgoing = lastChangedLineDetails.m_bIsOutgoing == 1; var _strDir = IsOutgoing ? "to" : "from"; LogEntry($"Active call {_strDir}: phone={lastChangedLineDetails.m_sPeerNumber}, name={lastChangedLineDetails.m_sPeerName}", LogLevels.Debug); if (ActiveCallHandler != null) ActiveCallHandler.Invoke(lastChangedLineDetails.m_sPeerNumber, lastChangedLineDetails.m_sPeerName, IsOutgoing); } } break; } } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } public void Disconnect() { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { if (MyEventSink != null) MyEventSink.Disconnect(); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } } public class ClientSdkEventArgs : EventArgs { public CLMgrMessage Msg; public int Param; public ClientSdkEventArgs(CLMgrMessage msg, int param) { Msg = msg; Param = param; } } public delegate void LineManagerMessageHandler(ClientSdkEventArgs e); public class ClientSdkEventSink { private ClientLineMgrClass ConnectedLineManager; private IClientLineMgrEventsPub_PubOnLineMgrNotificationEventHandler EventHandler; private LineManagerMessageHandler LineManagerMessageDelegateOfForm; public ClientSdkEventSink() { EventHandler = new IClientLineMgrEventsPub_PubOnLineMgrNotificationEventHandler(clmgr_EventSink); } public void Connect(ClientLineMgrClass lineManager, LineManagerMessageHandler lineManagerMessageDelegateOfForm) { ConnectedLineManager = lineManager; LineManagerMessageDelegateOfForm = lineManagerMessageDelegateOfForm; //add eventhandler for the PubOnlineMgrNotification Events ConnectedLineManager.PubOnLineMgrNotification += EventHandler; } public void Disconnect() { //remove eventhandler for the PubOnlineMgrNotification Events ConnectedLineManager.PubOnLineMgrNotification -= EventHandler; ConnectedLineManager = null; LineManagerMessageDelegateOfForm = null; } private void clmgr_EventSink(int msg, int param) { //this method receives the COM events from the client line manger if ((LineManagerMessageDelegateOfForm != null)) { LineManagerMessageDelegateOfForm?.Invoke(new ClientSdkEventArgs((CLMgrMessage)msg, param)); } } } public enum CLMgrMessage { CLMgrLineStateChangedMessage = 0, //state of at least one line has changed CLMgrLineSelectionChangedMessage = 1, //line in focus has changed CLMgrLineDetailsChangedMessage = 2, //details of at least one line have changed CLMgrCallDetailsMessage = 4, //details of last call are available, post mortem for logging purpose CLMgrServerDownMessage = 5, //server goes down, keep line manager, wait for ServerUp message CLMgrServerUpMessage = 6, //server is up again, keep interfaces to line manger CLMgrWaveDeviceChanged = 7, //speaker / micro has been switched on / off CLMgrGroupCallNotificationMessage = 8, //notification about group call CLMgrNumberOfLinesChangedMessage = 10, //the number of lines has changed CLMgrClientShutDownRequest = 11, //Client Line Manager requests client to shutdown and release all interfaces CLMgrLineStateChangedMessageEx = 28, //state of certain line has changed, lParam: LOWORD: line index of line that changed its state (starting with 0) HIWORD: new state of this line CLMgrSIPRegistrationStateChanged = 30, //registration state of SIP account has changed //lParam: LOBYTE: Account index // HIBYTE: new state CLMgrWaveFilePlayed = 31, //wave file playback finished //lParam: line index; //if -1, the message is related to a LineMgr function PlaySoundFile or PlayToRtp //if >=0 the message is related to a line function PlaySoundFile of line with this index PubCLMgrFirstDataReceived = 32 //first RTP data received on line, might be silence //lParam: line index; } public enum LineState { Inactive = 0, //line is inactive HookOffInternal = 1, //off hook, internal dialtone HookOffExternal = 2, //off hook, external dialtone Ringing = 3, //incoming call, ringing Dialing = 4, //outgoing call, we are dialing, no sound Alerting = 5, //outgoing call, alerting = ringing on destination Knocking = 6, //outgoing call, knocking = second call ringing on destination Busy = 7, //outgoing call, destination is busy Active = 8, //incoming / outgoing call, logical and physical connection is established OnHold = 9, //incoming / outgoing call, logical connection is established, destination gets music on hold ConferenceActive = 10, //incoming / outgoing conference, logical and physical connection is established ConferenceOnHold = 11, //incoming / outgoing conference, logical connection is established, not physcically connected Terminated = 12, //incoming / outgoing connection / call has been disconnected Transferring = 13, //special LSOnHold, call is awaiting to be transferred, peer gets special music on hold Disabled = 14 //special LSInactive: wrap up time } public enum DisconnectReason { Normal = 0, Busy = 1, Rejected = 2, Cancelled = 3, Transferred = 4, JoinedConference = 5, NoAnswer = 6, TooLate = 7, DirectCallImpossible = 8, WrongNumber = 9, Unreachable = 10, CallDiverted = 11, CallRoutingFailed = 12, PermissionDenied = 13, NetworkCongestion = 14, NoChannelAvailable = 15, NumberChanged = 16, IncompatibleDestination = 17 } }