swyx-win10-media-controll/swyxcontrol.py
Simon Zeyer 65f3a5c1da refactoring as gui application
:# Please enter the commit message for your changes. Lines starting
2021-12-29 15:14:33 +01:00

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