Integrating and testing of playback
[watersofshiloah] / src / stream.py
1 import logging
2
3 import gobject
4 import gst
5
6 import util.misc as misc_utils
7
8
9 _moduleLogger = logging.getLogger(__name__)
10
11
12 class GSTStream(gobject.GObject):
13
14         STATE_PLAY = "play"
15         STATE_PAUSE = "pause"
16         STATE_STOP = "stop"
17
18         __gsignals__ = {
19                 'state-change' : (
20                         gobject.SIGNAL_RUN_LAST,
21                         gobject.TYPE_NONE,
22                         (gobject.TYPE_STRING, ),
23                 ),
24                 'eof' : (
25                         gobject.SIGNAL_RUN_LAST,
26                         gobject.TYPE_NONE,
27                         (gobject.TYPE_STRING, ),
28                 ),
29                 'error' : (
30                         gobject.SIGNAL_RUN_LAST,
31                         gobject.TYPE_NONE,
32                         (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT),
33                 ),
34         }
35
36
37         def __init__(self):
38                 gobject.GObject.__init__(self)
39                 #Fields
40                 self._state = self.STATE_STOP
41                 self._uri = ""
42                 self._elapsed = 0
43                 self._duration = 0
44
45                 #Set up GStreamer
46                 self._player = gst.element_factory_make("playbin2", "player")
47                 bus = self._player.get_bus()
48                 bus.add_signal_watch()
49                 bus.connect("message", self._on_message)
50
51                 #Constants
52                 self._timeFormat = gst.Format(gst.FORMAT_TIME)
53                 self._seekFlag = gst.SEEK_FLAG_FLUSH
54
55         @property
56         def playing(self):
57                 return self.state == self.STATE_PLAY
58
59         @property
60         def has_file(self):
61                 return 0 < len(self._uri)
62
63         @property
64         def state(self):
65                 state = self._player.get_state()[1]
66                 return self._translate_state(state)
67
68         def set_file(self, uri):
69                 if self._uri != file:
70                         self._invalidate_cache()
71                 if self.playing:
72                         self.stop()
73
74                 self._uri = uri
75                 self._player.set_property("uri", uri)
76
77         def play(self):
78                 if self.state == self.STATE_PLAY:
79                         _moduleLogger.info("Already play")
80                         return
81                 _moduleLogger.info("Play")
82                 self._player.set_state(gst.STATE_PLAYING)
83                 self.emit("state-change", self.STATE_PLAY)
84
85         def pause(self):
86                 if self.state == self.STATE_PAUSE:
87                         _moduleLogger.info("Already pause")
88                         return
89                 _moduleLogger.info("Pause")
90                 self._player.set_state(gst.STATE_PAUSED)
91                 self.emit("state-change", self.STATE_PAUSE)
92
93         def stop(self):
94                 if self.state == self.STATE_STOP:
95                         _moduleLogger.info("Already stop")
96                         return
97                 self._player.set_state(gst.STATE_NULL)
98                 _moduleLogger.info("Stopped")
99                 self.emit("state-change", self.STATE_STOP)
100
101         def elapsed(self):
102                 try:
103                         self._elapsed = self._player.query_position(self._timeFormat, None)[0]
104                 except:
105                         pass
106                 return self._elapsed
107
108         def duration(self):
109                 try:
110                         self._duration = self._player.query_duration(self._timeFormat, None)[0]
111                 except:
112                         _moduleLogger.exception("Query failed")
113                 return self._duration
114
115         def seek_time(self, ns):
116                 _moduleLogger.debug("Seeking to: %s", ns)
117                 self._elapsed = ns
118                 self._player.seek_simple(self._timeFormat, self._seekFlag, ns)
119
120         def _invalidate_cache(self):
121                 self._elapsed = 0
122                 self._duration = 0
123
124         def _translate_state(self, gstState):
125                 return {
126                         gst.STATE_NULL: self.STATE_STOP,
127                         gst.STATE_PAUSED: self.STATE_PAUSE,
128                         gst.STATE_PLAYING: self.STATE_PLAY,
129                 }.get(gstState, self.STATE_STOP)
130
131         @misc_utils.log_exception(_moduleLogger)
132         def _on_message(self, bus, message):
133                 t = message.type
134                 if t == gst.MESSAGE_EOS:
135                         self._player.set_state(gst.STATE_NULL)
136                         self.emit("eof", self._uri)
137                 elif t == gst.MESSAGE_ERROR:
138                         self._player.set_state(gst.STATE_NULL)
139                         err, debug = message.parse_error()
140                         _moduleLogger.error("Error: %s, (%s)" % (err, debug))
141                         self.emit("error", err, debug)
142
143
144 gobject.type_register(GSTStream)