source: server/lib/gutenbach/server/player.py @ cf0d7e8

no-cups
Last change on this file since cf0d7e8 was cf0d7e8, checked in by Steven Allen <steven@…>, 12 years ago

Use sync decorator instead of manually locking.

  • Property mode set to 100644
File size: 3.8 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._done = False
22            self._dryrun = False
23            self._dryrun_time = 0.5
24            self._lag = 0.01
25
26    @property
27    @sync
28    def is_playing(self):
29        if self._dryrun:
30            return self.isAlive() and not self.is_done
31        else:
32            return self.isAlive() and \
33                      not self.is_done and \
34                      self.player is not None and \
35                      self.player.poll() is None
36
37    @property
38    @sync
39    def is_paused(self):
40        return self.is_playing and self._paused
41
42    @property
43    def is_done(self):
44        return self._done
45
46    @property
47    def callback(self):
48        return self._callback
49    @callback.setter
50    @sync
51    def callback(self, val):
52        self._callback = val
53
54    def start(self):
55        super(Player, self).start()
56        time.sleep(self._lag)
57
58    def run(self):
59        if self.fh is None:
60            raise ValueError, "file handler is None"
61       
62        logger.info("playing file '%s'" % self.fh.name)
63
64        with self.lock:
65            self._paused = False
66            self._done = False
67
68        command = ["mplayer", "-really-quiet", "-slave", self.fh.name]
69        logger.info("running '%s'", " ".join(command))
70
71        if self._dryrun:
72            step = 0.01
73            while self._dryrun_time > 0:
74                time.sleep(step)
75                self._dryrun_time -= step
76                while self.is_paused:
77                    time.sleep(0.01)
78
79        else:
80            with self.lock:
81                self.player = subprocess.Popen(
82                    command,
83                    stdin=subprocess.PIPE,
84                    stderr=subprocess.PIPE,
85                    stdout=subprocess.PIPE)
86
87            # wait for mplayer to finish
88            while True:
89                with self.lock:
90                    playing = self.is_playing
91                if not playing:
92                    break
93                time.sleep(0.1)
94
95            logger.info("mplayer finished with code %d" % self.player.returncode)
96       
97            # get output from mplayer and log it
98            with self.lock:
99                stderr = self.player.stderr.read()
100                stdout = self.player.stdout.read()
101           
102            if stderr.strip() != "":
103                logger.error(stderr)
104            if stdout.strip() != "":
105                logger.debug(stdout)
106
107        with self.lock:
108            if self.callback:
109                self.callback()
110            self._done = True
111
112    def mplayer_pause(self):
113        # Note: Inner lock due to sleep.
114        with self.lock:
115            if self.is_playing:
116                if not self._dryrun:
117                    self.player.stdin.write("pause\n")
118                self._paused = not(self._paused)
119                logger.info("paused: %s", self.is_paused)
120            else:
121                logger.warning("trying to pause non-playing job")
122        time.sleep(self._lag)
123               
124    def mplayer_stop(self):
125        # Note: Inner Lock due to join.
126        with self.lock:
127            if self.is_playing:
128                if not self._dryrun:
129                    self.player.stdin.write("quit\n")
130                else:
131                    self._dryrun_time = 0.0
132                logger.info("stopped")
133            else:
134                logger.warning("trying to stop non-playing job")
135        self.join()
Note: See TracBrowser for help on using the repository browser.