Adding additional sources
[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         @property
102         def elapsed(self):
103                 try:
104                         self._elapsed = self._player.query_position(self._timeFormat, None)[0]
105                 except:
106                         pass
107                 return self._elapsed
108
109         @property
110         def duration(self):
111                 try:
112                         self._duration = self._player.query_duration(self._timeFormat, None)[0]
113                 except:
114                         _moduleLogger.exception("Query failed")
115                 return self._duration
116
117         def seek_time(self, ns):
118                 _moduleLogger.debug("Seeking to: %s", ns)
119                 self._elapsed = ns
120                 self._player.seek_simple(self._timeFormat, self._seekFlag, ns)
121
122         def _invalidate_cache(self):
123                 self._elapsed = 0
124                 self._duration = 0
125
126         def _translate_state(self, gstState):
127                 return {
128                         gst.STATE_NULL: self.STATE_STOP,
129                         gst.STATE_PAUSED: self.STATE_PAUSE,
130                         gst.STATE_PLAYING: self.STATE_PLAY,
131                 }.get(gstState, self.STATE_STOP)
132
133         @misc_utils.log_exception(_moduleLogger)
134         def _on_message(self, bus, message):
135                 t = message.type
136                 if t == gst.MESSAGE_EOS:
137                         self._player.set_state(gst.STATE_NULL)
138                         self.emit("eof", self._uri)
139                 elif t == gst.MESSAGE_ERROR:
140                         self._player.set_state(gst.STATE_NULL)
141                         err, debug = message.parse_error()
142                         _moduleLogger.error("Error: %s, (%s)" % (err, debug))
143                         self.emit("error", err, debug)
144
145
146 gobject.type_register(GSTStream)