Further player hardening

This commit is contained in:
Matthew Stratford 2020-10-30 00:32:34 +00:00
parent eafb4dd461
commit 2bf4ff4715
No known key found for this signature in database
GPG key ID: 5F50E4308A3416E8

156
player.py
View file

@ -14,8 +14,11 @@ os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
class Player(): class Player():
state = None state = None
running = False running = False
out_q = None
last_msg = None
__default_state = { __default_state = {
"initialised": False,
"filename": "", "filename": "",
"channel": -1, "channel": -1,
"playing": False, "playing": False,
@ -49,14 +52,30 @@ class Player():
if self.isPlaying: if self.isPlaying:
return True return True
# Because Pygame/SDL is annoying
# We're not playing now, so we can quickly test run
# If that works, we're loaded.
try: try:
current_pos = mixer.music.get_pos() position = self.state.state["pos"]
mixer.music.set_pos(current_pos) mixer.music.set_volume(0)
mixer.music.play(0)
except: except:
# TODO: Trigger specially off the SDLError (couldn't find it) try:
mixer.music.set_volume(1)
except:
pass
return False return False
if position > 0:
mixer.music.pause()
else:
mixer.music.stop()
mixer.music.set_volume(1)
return True
return False @property
def status(self):
res = json.dumps(self.state.state)
return res
def play(self): def play(self):
if not self.isPlaying: if not self.isPlaying:
@ -144,33 +163,47 @@ class Player():
def output(self, name=None): def output(self, name=None):
self.quit() self.quit()
self.state.update("output", name)
self.state.update("filename", "")
try: try:
if name: if name:
mixer.init(44100, -16, 1, 1024, devicename=name) mixer.init(44100, -16, 1, 1024, devicename=name)
else: else:
mixer.init(44100, -16, 1, 1024) mixer.init(44100, -16, 1, 1024)
except: except:
return "FAIL:Failed to init mixer, check sound devices." return False
return True
def _updateState(self, pos=None):
self.state.update("initialised", self.isInit)
if self.isInit:
self.state.update("playing", self.isPlaying)
self.state.update("loaded", self.isLoaded)
if (pos):
self.state.update("pos", max(0, pos))
else:
self.state.update("pos", max(0, mixer.music.get_pos()/1000))
self.state.update("remaining", self.state.state["length"] - self.state.state["pos"])
def _retMsg(self, msg, okay_str=False):
response = self.last_msg + ":"
if msg == True:
response += "OKAY"
elif isinstance(msg, str):
if okay_str:
response += "OKAY:" + msg
else:
response += "FAIL:" + msg
else: else:
self.state.update("output", name) response += "FAIL"
if self.out_q:
return "OK" self.out_q.put(response)
def updateState(self, pos=None):
self.state.update("playing", self.isPlaying)
self.state.update("loaded", self.isLoaded)
if (pos):
self.state.update("pos", max(0, pos))
else:
self.state.update("pos", max(0, mixer.music.get_pos()/1000))
self.state.update("remaining", self.state.state["length"] - self.state.state["pos"])
def getDetails(self):
res = "RESP:DETAILS: " + json.dumps(self.state.state)
return res
def __init__(self, channel, in_q, out_q): def __init__(self, channel, in_q, out_q):
self.running = True self.running = True
self.out_q = out_q
setproctitle.setproctitle("BAPSicle - Player " + str(channel)) setproctitle.setproctitle("BAPSicle - Player " + str(channel))
self.state = StateManager("channel" + str(channel), self.__default_state) self.state = StateManager("channel" + str(channel), self.__default_state)
@ -201,47 +234,67 @@ class Player():
print("No file was previously loaded.") print("No file was previously loaded.")
while self.running: while self.running:
time.sleep(0.01) time.sleep(0.1)
self._updateState()
try: try:
try: try:
incoming_msg = in_q.get_nowait() self.last_msg = in_q.get_nowait()
except Empty: except Empty:
# The incomming message queue was empty, # The incomming message queue was empty,
# skip message processing # skip message processing
pass pass
else: else:
# We got a message. # We got a message.
if self.isInit:
self.updateState() # Output re-inits the mixer, so we can do this any time.
if (self.last_msg.startswith("OUTPUT")):
split = self.last_msg.split(":")
self._retMsg(self.output(split[1]))
if (incoming_msg == 'LOADED?'): elif self.isInit:
out_q.put(self.isLoaded)
if (self.last_msg == 'LOADED?'):
self._retMsg(self.isLoaded)
continue continue
if (incoming_msg == 'PLAY'): elif (self.last_msg == 'PLAY'):
self.play() self._retMsg(self.play())
if (incoming_msg == 'PAUSE'):
self.pause()
if (incoming_msg == 'UNPAUSE'):
self.unpause()
if (incoming_msg == 'STOP'):
self.stop()
if (incoming_msg == 'QUIT'):
self.quit()
self.running = False
if (incoming_msg.startswith("SEEK")):
split = incoming_msg.split(":")
self.seek(float(split[1]))
if (incoming_msg.startswith("LOAD")):
split = incoming_msg.split(":")
self.load(split[1])
if (incoming_msg == 'DETAILS'):
out_q.put(self.getDetails())
if (incoming_msg.startswith("OUTPUT")): elif (self.last_msg == 'PAUSE'):
split = incoming_msg.split(":") self._retMsg(self.pause())
out_q.put(self.output(split[1]))
elif (self.last_msg == 'UNPAUSE'):
self._retMsg(self.unpause())
elif (self.last_msg == 'STOP'):
self._retMsg(self.stop())
elif (self.last_msg == 'QUIT'):
self.running = False
continue
elif (self.last_msg.startswith("SEEK")):
split = self.last_msg.split(":")
self._retMsg(self.seek(float(split[1])))
elif (self.last_msg.startswith("LOAD")):
split = self.last_msg.split(":")
self._retMsg(self.load(split[1]))
elif (self.last_msg == 'UNLOAD'):
self._retMsg(self.unload())
elif (self.last_msg == 'STATUS'):
self._retMsg(self.status, True)
else:
self._retMsg("Unknown Command")
else:
if (self.last_msg == 'STATUS'):
self._retMsg(self.status)
else:
self._retMsg(False)
# Catch the player being killed externally. # Catch the player being killed externally.
except KeyboardInterrupt: except KeyboardInterrupt:
@ -253,14 +306,15 @@ class Player():
print("Quiting player ", channel) print("Quiting player ", channel)
self.quit() self.quit()
self._retMsg("EXIT")
def showOutput(in_q, out_q): def showOutput(in_q, out_q):
print("Starting showOutput().") print("Starting showOutput().")
while True: while True:
time.sleep(0.01) time.sleep(0.01)
incoming_msg = out_q.get() self.last_msg = out_q.get()
print(incoming_msg) print(self.last_msg)
if __name__ == "__main__": if __name__ == "__main__":