From f960309b9a62c716712bf14d6ec00464f7debc45 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Mon, 3 Feb 2014 00:23:25 +0100 Subject: [PATCH] Use select() in status thread. The ``StatusThread`` now uses ``select.select()`` calls with a timeout to check whether the MPD ``idle`` command has new information already or not. This prevents a blocked client if something goes wrong. Refs #45. --- orochi/backends/mpd.py | 25 +++++++++++++++++++++++-- orochi/client.py | 1 - 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/orochi/backends/mpd.py b/orochi/backends/mpd.py index 85d759a..56b1810 100644 --- a/orochi/backends/mpd.py +++ b/orochi/backends/mpd.py @@ -6,6 +6,7 @@ from __future__ import print_function, division, absolute_import, unicode_literals import os +import select import threading import functools import logging @@ -69,18 +70,38 @@ def __init__(self, host, port, timeout): def run(self): """Start the thread.""" logger.debug('[status thread] Starting.') + + # Connect self.client.connect(self.host, self.port) + + # Store old state oldstate = self.client.status().get('state') + + # Send an asynchronous IDLE command + self.client.send_idle('player') + + # Set the timeout for the select() command in seconds. This allows the + # ``self._stop`` flag to be checked regularly. Not doing so would + # result in an indefinitely blocked client if something goes wrong. + select_timeout = 1.0 + while not self._stop: - systems = self.client.idle() # Blocking call - if not 'player' in systems: + # Do a select() call to see if socket is ready + changes = select.select([self.client], [], [], select_timeout) + # If nothing has changed, loop again. + if self.client not in changes[0]: continue + # Otherwise, reset the IDLE command and query / process status. + logger.debug('[status thread] Player status has changed.') + self.client.noidle() status = self.client.status() newstate = status.get('state') if oldstate == 'play' and newstate == 'stop' and status.get('songid') is None: logger.debug('[status thread] Song has ended.') os.kill(os.getpid(), signals.SONG_ENDED) oldstate = newstate + # Back to IDLE state. + self.client.send_idle('player') logger.debug('[status thread] Exiting.') def stop(self): diff --git a/orochi/client.py b/orochi/client.py index 192cc70..1e34d86 100644 --- a/orochi/client.py +++ b/orochi/client.py @@ -515,7 +515,6 @@ def _song_end_handler(self, signum, frame): """Signal handler for SIGUSR1. Advance to the next track, if available.""" print('') - print('Song has ended!') if self.status['at_last_track']: print('Playlist has ended!') self.do_next_mix()