PySide Workaround: connected to wrong signal type
[gc-dialer] / dialcentral / stream_gst.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 Stream(gobject.GObject):
13
14         # @bug Advertising state changes a bit early, should watch for GStreamer state change
15
16         STATE_PLAY = "play"
17         STATE_PAUSE = "pause"
18         STATE_STOP = "stop"
19
20         __gsignals__ = {
21                 'state-change' : (
22                         gobject.SIGNAL_RUN_LAST,
23                         gobject.TYPE_NONE,
24                         (gobject.TYPE_STRING, ),
25                 ),
26                 'eof' : (
27                         gobject.SIGNAL_RUN_LAST,
28                         gobject.TYPE_NONE,
29                         (gobject.TYPE_STRING, ),
30                 ),
31                 'error' : (
32                         gobject.SIGNAL_RUN_LAST,
33                         gobject.TYPE_NONE,
34                         (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT),
35                 ),
36         }
37
38         def __init__(self):
39                 gobject.GObject.__init__(self)
40                 #Fields
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 != uri:
70                         self._invalidate_cache()
71                 if self.state != self.STATE_STOP:
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                 self._elapsed = ns
119                 self._player.seek_simple(self._timeFormat, self._seekFlag, ns)
120
121         def _invalidate_cache(self):
122                 self._elapsed = 0
123                 self._duration = 0
124
125         def _translate_state(self, gstState):
126                 return {
127                         gst.STATE_NULL: self.STATE_STOP,
128                         gst.STATE_PAUSED: self.STATE_PAUSE,
129                         gst.STATE_PLAYING: self.STATE_PLAY,
130                 }.get(gstState, self.STATE_STOP)
131
132         @misc_utils.log_exception(_moduleLogger)
133         def _on_message(self, bus, message):
134                 t = message.type
135                 if t == gst.MESSAGE_EOS:
136                         self._player.set_state(gst.STATE_NULL)
137                         self.emit("eof", self._uri)
138                 elif t == gst.MESSAGE_ERROR:
139                         self._player.set_state(gst.STATE_NULL)
140                         err, debug = message.parse_error()
141                         _moduleLogger.error("Error: %s, (%s)" % (err, debug))
142                         self.emit("error", err, debug)
143
144
145 gobject.type_register(Stream)