-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathsoundplay.py
More file actions
173 lines (132 loc) · 5.71 KB
/
soundplay.py
File metadata and controls
173 lines (132 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import os
import sys
import subprocess
import atexit
import time
import argparse
import logging
import platform
log = logging.getLogger('KRO')
log.setLevel(logging.DEBUG)
class soundplay(object):
def __init__(self):
#class vars
self.proc = None
def connect(self, instrument, server=None, port=9798, aplay='aplay', player=None):
'''
Connect to sound server
'''
log.info(f'Starting soundplayer: server={server}, instrument={instrument}')
try:
#massage inputs
instrument = instrument.lower()
port = str(port)
if server is None:
server = self.getVncServer(instrument)
serverport = f'{server}:{port}'
# TODO: It should be OK for aplay to be None here.
if aplay is None:
aplay = 'aplay'
soundplayPath = full_path(player)
#check existing soundplay process
procs = self.check_existing_process(server, port, instrument)
if procs and len(procs) > 0:
log.info(f"SOUNDPLAY PROCESS ALREADY EXISTS FOR: {serverport} {instrument}")
log.debug(procs)
return False
#create command and open process and hold on to handle so we can terminate later
cmd = [soundplayPath, '-s', serverport, '-T', instrument]
if aplay is not None:
cmd.append('-px')
cmd.append(aplay)
log.debug('Soundplay cmd: ' + str(cmd))
self.proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except Exception as error:
log.error("Could not start soundplayer")
log.error(error)
return False
return True
def check_existing_process(self, server, port, instrument):
'''
Use system ps command to look for processes connected to same server/port/instr combo
'''
#todo: fix this to use proper cmd array and shell=False
cmd = f'ps -elf | grep soundplay | grep "{server}:{port}" | grep {instrument} | grep -v grep'
log.debug('Checking for existing soundplay process: ' + cmd)
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
data = proc.communicate()[0]
data = data.decode("utf-8").strip()
lines = data.split('\n') if data else []
return lines
def getVncServer(self, instrument):
'''
#todo: move this common function to shared module. It can look for ssh key. If not found, then it can prompt for password.
'''
raise Exception("Not implemented yet. Must provide server name explicitly.")
def terminate(self):
if self.proc:
log.info('Terminating soundplay process...')
self.proc.terminate()
##-------------------------------------------------------------------------
## Get the full path to the soundplay executable
##-------------------------------------------------------------------------
def full_path(player=None):
remobs_base = os.path.dirname(os.path.abspath(__file__))
soundplayers = os.path.join(remobs_base, 'soundplayer')
if player is None:
system = platform.system()
system = system.lower()
arch = platform.machine()
arch = arch.lower()
specific = '.'.join(('soundplay', system, arch))
sound_path = os.path.join(soundplayers, specific)
if os.path.exists(sound_path):
pass
else:
sound_path = os.path.join(soundplayers, 'soundplay')
else:
if os.path.exists(player):
sound_path = player
else:
sound_path = os.path.join(soundplayers, player)
if os.path.exists(sound_path):
pass
else:
raise ValueError('invalid soundplay binary name: ' + player)
return sound_path
##-------------------------------------------------------------------------
## main
##-------------------------------------------------------------------------
if __name__ == "__main__":
'''
Run in command line mode
'''
#create logger
create_logger()
log = logging.getLogger('KRO')
# arg parser
parser = argparse.ArgumentParser(description="Start Keck event sounds player.")
parser.add_argument("instrument", type=str, help="Instrument to get event sounds for.")
parser.add_argument("--server", type=str, dest="server", default=None, help="IP name or address of sound server to connect to. Will query for value if not given.")
parser.add_argument("--port", type=int, dest="port", default=9798, help="Server port where soundplayer should connect. Default is standard.")
parser.add_argument("--player", type=str, dest="player", default='soundplay', help="Keck soundplay executable filename to use in soundplayer folder.")
parser.add_argument("--aplay", type=str, dest="aplay", default='aplay', help="Full path to local system command-line sound player.")
args = parser.parse_args()
#define exit handler in case program is killed by user
def exit_handler(soundplay=None):
if soundplay: soundplay.terminate()
#start soundplay
sp = soundplay()
ok = sp.connect(args.instrument, server=args.server, port=args.port, aplay=args.aplay, player=args.player)
if not ok:
sys.exit(1)
#wait for interrupt to exit cleanly
try:
atexit.register(exit_handler, sp)
print ('Hit control-C to terminate program and close soundplay connection.')
while True:
time.sleep(1)
except KeyboardInterrupt:
pass
finally:
if sp: sp.terminate()