This commit is contained in:
Simon Zeyer 2021-12-05 13:41:26 +01:00
commit dc47a1d50f
4 changed files with 218 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
build
dist
__pycache__

72
__main__.py Normal file
View File

@ -0,0 +1,72 @@
import asyncio
from winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager
import win32com.client
import pythoncom
import time
from resources import LineState, CLMgrMessage
phone_mgr = ""
lines = []
class PhoneLineEventHandler():
def OnDispOnLineMgrNotification(self, msg, param, returns=""):
if msg == 0:
print(CLMgrMessage.s[msg], LineState.s[param])
for line in lines:
if line.DispState != LineState.Inactive:
asyncio.run(try_pause())
return True
asyncio.run(try_play())
return True
# async def get_media_info():
# sessions = await MediaManager.request_async()
# # This source_app_user_model_id check and if statement is optional
# # Use it if you want to only get a certain player/program's media
# # (e.g. only chrome.exe's media not any other program's).
# # To get the ID, use a breakpoint() to run sessions.get_current_session()
# # while the media you want to get is playing.
# # Then set TARGET_ID to the string this call returns.
# current_session = sessions.get_current_session()
# if current_session: # there needs to be a media session running
# #if current_session.source_app_user_model_id == TARGET_ID:
# info = await current_session.try_get_media_properties_async()
# # song_attr[0] != '_' ignores system attributes
# info_dict = {song_attr: info.__getattribute__(song_attr) for song_attr in dir(info) if song_attr[0] != '_'}
# # converts winrt vector to list
# info_dict['genres'] = list(info_dict['genres'])
# return info_dict
# # It could be possible to select a program from a list of current
# # available ones. I just haven't implemented this here for my use case.
# # See references for more information.
# raise Exception('TARGET_PROGRAM is not the current media session')
async def try_play():
print("try_play")
sessions = await MediaManager.request_async()
current_session = sessions.get_current_session()
if current_session:
await current_session.try_play_async()
async def try_pause():
print("try_pause")
sessions = await MediaManager.request_async()
current_session = sessions.get_current_session()
if current_session:
await current_session.try_pause_async()
if __name__ == '__main__':
phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr")
phone_mgr_event = win32com.client.WithEvents("CLMgr.ClientLineMgr", PhoneLineEventHandler)
for i in range(3):
lines.append(phone_mgr.DispGetLine(i))
while True:
#pythoncom.PumpWaitingMessages()
time.sleep(0.1) # Don't use up all our CPU checking constantly

44
__main__.spec Normal file
View File

@ -0,0 +1,44 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['__main__.py'],
pathex=['X:\\Documents\\Projekte\\Simon\\python media controll'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='__main__',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='__main__')

99
resources.py Normal file
View File

@ -0,0 +1,99 @@
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",
"",
"CLMgrCallDetailsMessage",
"CLMgrServerDownMessage",
"CLMgrServerUpMessage",
"CLMgrWaveDeviceChanged",
"CLMgrGroupCallNotificationMessage",
"",
"CLMgrNumberOfLinesChangedMessage",
"CLMgrClientShutDownRequest",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"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