221 lines
7.8 KiB
Python
221 lines
7.8 KiB
Python
import asyncio
|
|
from threading import Thread
|
|
import logging
|
|
import time
|
|
import logging
|
|
import pythoncom
|
|
|
|
class 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
|
|
|
|
s = [
|
|
"CLMgrLineStateChangedMessage",
|
|
"CLMgrLineSelectionChangedMessage",
|
|
"CLMgrLineDetailsChangedMessage",
|
|
"3",
|
|
"CLMgrCallDetailsMessage",
|
|
"CLMgrServerDownMessage",
|
|
"CLMgrServerUpMessage",
|
|
"CLMgrWaveDeviceChanged",
|
|
"CLMgrGroupCallNotificationMessage",
|
|
"9",
|
|
"CLMgrNumberOfLinesChangedMessage",
|
|
"CLMgrClientShutDownRequest",
|
|
"12",
|
|
"13",
|
|
"14",
|
|
"15",
|
|
"16",
|
|
"17",
|
|
"18",
|
|
"19",
|
|
"20",
|
|
"21",
|
|
"22",
|
|
"23",
|
|
"24",
|
|
"25",
|
|
"26",
|
|
"27",
|
|
"CLMgrLineStateChangedMessageEx"
|
|
]
|
|
|
|
class 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
|
|
|
|
s = [
|
|
"Inactive",
|
|
"HookOffInternal",
|
|
"HookOffExternal",
|
|
"Ringing",
|
|
"Dialing",
|
|
"Alerting",
|
|
"Knocking",
|
|
"Busy",
|
|
"Active",
|
|
"OnHold",
|
|
"ConferenceActive",
|
|
"ConferenceOnHold",
|
|
"Terminated",
|
|
"Transferring",
|
|
"Disabled"
|
|
]
|
|
|
|
class 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
|
|
|
|
class SwyxControlException(Exception):
|
|
|
|
def __init__(self, msg, *args: object) -> None:
|
|
self.msg = msg
|
|
super().__init__(*args)
|
|
|
|
class SwyxControl(Thread):
|
|
|
|
__running = True
|
|
phone_mgr = None
|
|
__line_state_changed_hander = []
|
|
__phone_mgr_connected_hander = []
|
|
all_lines_inactive = False
|
|
|
|
class __PhoneLineEventHandler():
|
|
outer: 'SwyxControl' = None
|
|
|
|
def OnDispOnLineMgrNotification(self, msg, param, returns=""):
|
|
if not self.outer:
|
|
logging.debug("self.outer not set")
|
|
return True
|
|
logging.debug("msg: {}\tparam: {}\treturns: {}".format(msg, param,returns))
|
|
if msg == CLMgrMessage.CLMgrLineStateChangedMessage:
|
|
self.outer._handle_line_state_changed(msg, param)
|
|
return True
|
|
|
|
def setOuter(self, outer: 'SwyxControl'):
|
|
logging.debug("set outer class")
|
|
self.outer = outer
|
|
|
|
def _handle_line_state_changed(self, msg, param):
|
|
line = self.phone_mgr.DispGetLine(param)
|
|
logging.debug("Line: {} {} / {}".format(
|
|
param,
|
|
LineState.s[line.DispState],
|
|
LineState.s[msg]
|
|
)
|
|
)
|
|
self.all_lines_inactive = self.__all_lines_inactive()
|
|
for handler in self.__line_state_changed_hander:
|
|
handler(line)
|
|
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
pass
|
|
|
|
def __all_lines_inactive(self) -> bool:
|
|
'''returns true if all lines are inactive'''
|
|
for linenum in range(self.phone_mgr.DispNumberOfLines):
|
|
line = self.phone_mgr.DispGetLine(linenum)
|
|
if line.DispState != LineState.Inactive:
|
|
return False
|
|
return True
|
|
|
|
def add_line_state_changed_handler(self, handler):
|
|
'''handler called when CLMgrMessage.CLMgrLineStateChangedMessage
|
|
is fired
|
|
|
|
def handler(line):
|
|
if line.DispState == LineState.Ringing:
|
|
print("Ringing")
|
|
if line.DispState == LineState.HookOffInternal:
|
|
print("HookOffInternal")
|
|
sc.add_line_state_changed_handler(handler)
|
|
'''
|
|
self.__line_state_changed_hander.append(handler)
|
|
|
|
def add_phone_mgr_connected_handler(self, handler):
|
|
'''
|
|
handler called when CLMgr.ClientLineMgr dispatched
|
|
|
|
def handler():
|
|
print("connected")
|
|
sc.add_phone_mgr_connected_handler(handler)
|
|
'''
|
|
self.__phone_mgr_connected_hander.append(handler)
|
|
|
|
def stop(self):
|
|
'''stops the running thread'''
|
|
self.__running = False
|
|
|
|
def run(self):
|
|
# Initialize
|
|
import win32com.client
|
|
#pythoncom.CoInitialize(pythoncom.COINIT_MULTITHREADED)
|
|
#try:
|
|
self.phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr")
|
|
self.all_lines_inactive = self.__all_lines_inactive()
|
|
for handler in self.__phone_mgr_connected_hander:
|
|
handler()
|
|
# except Exception:
|
|
# raise SwyxControlException("Swyx Client not installed")
|
|
self.e = win32com.client.WithEvents("CLMgr.ClientLineMgr", self.__PhoneLineEventHandler)
|
|
self.e.setOuter(self)
|
|
while self.__running:
|
|
pythoncom.PumpWaitingMessages()
|
|
time.sleep(0.1)
|
|
|
|
if __name__ == "__main__":
|
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
def line_change_handler(line):
|
|
if line.DispState == LineState.Ringing:
|
|
print("Ringing")
|
|
if line.DispState == LineState.HookOffInternal:
|
|
print("HookOffInternal")
|
|
|
|
def phone_mgr_connected_handler():
|
|
print(sc.all_lines_inactive)
|
|
|
|
sc = SwyxControl()
|
|
sc.add_line_state_changed_handler(line_change_handler)
|
|
sc.add_phone_mgr_connected_handler(phone_mgr_connected_handler)
|
|
sc.start()
|
|
pass |