source: server/lib/gutenbach/server/player.py @ 3c0760f

Last change on this file since 3c0760f was 3c0760f, checked in by Steven Allen <steven@…>, 12 years ago

Block instead of looping and sleeping.

  • Property mode set to 100644
File size: 4.6 KB
Line 
1import logging
2import threading
3import subprocess
4import time
5from . import sync
6
7# initialize logger
8logger = logging.getLogger(__name__)
9
10class Player(threading.Thread):
11
12    def __init__(self, fh, *args, **kwargs):
13        self.lock = threading.RLock()
14
15        with self.lock:
16            super(Player, self).__init__(*args, **kwargs)
17            self.fh = fh
18            self.player = None
19            self._callback = None
20            self._paused = False
21            self._paused_condition = threading.Condition(self.lock)
22            self._done = False
23            self._done_condition = threading.Condition(self.lock)
24            self._dryrun = False
25            self._dryrun_time = 0.5
26
27    @property
28    @sync
29    def is_playing(self):
30        if self._dryrun:
31            return self.ident is not None and \
32                   self.isAlive() and \
33                   not self.done
34        else:
35            return self.ident is not None and \
36                   self.isAlive() and \
37                   not self.done and \
38                   self.player is not None and \
39                   self.player.poll() is None
40
41
42    # DONE
43    @property
44    @sync
45    def done(self):
46        return self._done
47    @done.setter
48    @sync
49    def done(self, val):
50        if (self._done != val):
51            self._done = val
52            self._done_condition.notifyAll()
53    @sync
54    def wait_done(self):
55        """Wait for the player to finish playing.
56
57        Requires that the main thread be started.
58        """
59        while not self._done:
60            self._done_condition.wait()
61
62    # PAUSED
63    @property
64    @sync
65    def paused(self):
66        return self._paused
67    @paused.setter
68    @sync
69    def paused(self, val):
70        if (self._paused != val):
71            self._paused = val
72            self._paused_condition.notifyAll()
73
74    @sync
75    def wait_unpaused(self):
76        """Wait for the player to finish playing.
77
78        Requires that the main thread be started.
79        """
80        while self._paused:
81            self._paused_condition.wait()
82
83
84    @property
85    def callback(self):
86        return self._callback
87    @callback.setter
88    @sync
89    def callback(self, val):
90        self._callback = val
91
92    def start(self):
93        super(Player, self).start()
94
95    def run(self):
96        try:
97            if self.fh is None:
98                raise ValueError, "file handler is None"
99
100            logger.info("playing file '%s'" % self.fh.name)
101
102            with self.lock:
103                self.paused = False
104                self.done = False
105
106            command = ["mplayer", "-really-quiet", "-slave", self.fh.name]
107            logger.info("running '%s'", " ".join(command))
108
109            if self._dryrun:
110                step = 0.01
111                while self._dryrun_time > 0:
112                    time.sleep(step)
113                    self._dryrun_time -= step
114                    self.wait_unpaused()
115            else:
116                with self.lock:
117                    self.player = subprocess.Popen(
118                        command,
119                        stdin=subprocess.PIPE,
120                        stderr=subprocess.PIPE,
121                        stdout=subprocess.PIPE)
122
123                # wait for mplayer to finish
124                self.player.wait()
125
126                logger.info("mplayer finished with code %d" % self.player.returncode)
127
128                # get output from mplayer and log it
129                with self.lock:
130                    stderr = self.player.stderr.read()
131                    stdout = self.player.stdout.read()
132
133                if stderr.strip() != "":
134                    logger.error(stderr)
135                if stdout.strip() != "":
136                    logger.debug(stdout)
137        finally:
138            with self.lock:
139                if self.callback:
140                    self.callback()
141                self.done = True
142
143    def mplayer_pause(self):
144        # Note: Inner lock due to sleep.
145        with self.lock:
146            if self.is_playing:
147                if not self._dryrun:
148                    self.player.stdin.write("pause\n")
149                self.paused = not(self.paused)
150                logger.info("paused: %s", self.paused)
151            else:
152                logger.warning("trying to pause non-playing job")
153
154    def mplayer_stop(self):
155        # Note: Inner lock due to join.
156        with self.lock:
157            if self.is_playing:
158                if not self._dryrun:
159                    self.player.stdin.write("quit\n")
160                else:
161                    self._dryrun_time = 0.0
162                self.paused = False
163                logger.info("stopped")
164            else:
165                logger.warning("trying to stop non-playing job")
166        self.join()
167
Note: See TracBrowser for help on using the repository browser.