Bump to 1.0.6
[watersofshiloah] / src / player.py
1 import logging
2
3 import gobject
4
5 import util.misc as misc_utils
6 try:
7         import stream_gst
8         stream = stream_gst
9 except ImportError:
10         try:
11                 import stream_osso
12                 stream = stream_osso
13         except ImportError:
14                 import stream_null
15                 stream = stream_null
16 import stream_index
17 import call_monitor
18
19
20 _moduleLogger = logging.getLogger(__name__)
21
22
23 class Player(gobject.GObject):
24
25         __gsignals__ = {
26                 'state_change' : (
27                         gobject.SIGNAL_RUN_LAST,
28                         gobject.TYPE_NONE,
29                         (gobject.TYPE_PYOBJECT, ),
30                 ),
31                 'title_change' : (
32                         gobject.SIGNAL_RUN_LAST,
33                         gobject.TYPE_NONE,
34                         (gobject.TYPE_PYOBJECT, ),
35                 ),
36                 'error' : (
37                         gobject.SIGNAL_RUN_LAST,
38                         gobject.TYPE_NONE,
39                         (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT),
40                 ),
41         }
42
43         STATE_PLAY = stream.Stream.STATE_PLAY
44         STATE_PAUSE = stream.Stream.STATE_PAUSE
45         STATE_STOP = stream.Stream.STATE_STOP
46
47         def __init__(self, index):
48                 gobject.GObject.__init__(self)
49                 self._index = index
50                 self._node = None
51                 self._nextSearch = None
52
53                 self._calls = call_monitor.CallMonitor()
54                 self._calls.connect("call_start", self._on_call_start)
55
56                 self._stream = stream.Stream()
57                 self._stream.connect("state-change", self._on_stream_state)
58                 self._stream.connect("eof", self._on_stream_eof)
59                 self._stream.connect("error", self._on_stream_error)
60
61         def set_piece_by_node(self, node):
62                 self._set_piece_by_node(node)
63
64         @property
65         def node(self):
66                 return self._node
67
68         @property
69         def title(self):
70                 if self._node is None:
71                         return ""
72                 return self._node.title
73
74         @property
75         def subtitle(self):
76                 if self._node is None:
77                         return ""
78                 return self._node.subtitle
79
80         @property
81         def can_navigate(self):
82                 if self._node is None:
83                         return False
84                 return self.node.can_navigate
85
86         @property
87         def state(self):
88                 return self._stream.state
89
90         def play(self):
91                 _moduleLogger.info("play")
92                 self._stream.play()
93
94                 self._calls.start()
95
96         def pause(self):
97                 _moduleLogger.info("pause")
98                 self._stream.pause()
99
100         def stop(self):
101                 _moduleLogger.info("stop")
102                 self._stream.stop()
103                 self.set_piece_by_node(None)
104
105                 self._calls.stop()
106
107         def back(self, forcePlay = False):
108                 _moduleLogger.info("back")
109                 assert self._nextSearch is None
110                 self._nextSearch = stream_index.AsyncWalker(stream_index.get_previous)
111                 self._nextSearch.start(
112                         self.node,
113                         lambda node: self._on_next_node(node, forcePlay),
114                         self._on_node_search_error
115                 )
116
117         def next(self, forcePlay = False):
118                 _moduleLogger.info("next")
119                 assert self._nextSearch is None
120                 self._nextSearch = stream_index.AsyncWalker(stream_index.get_next)
121                 self._nextSearch.start(
122                         self.node,
123                         lambda node: self._on_next_node(node, forcePlay),
124                         self._on_node_search_error
125                 )
126
127         def seek(self, percent):
128                 target = percent * self._stream.duration
129                 self._stream.seek_time(target)
130
131         @property
132         def percent_elapsed(self):
133                 percent = float(self._stream.elapsed) / float(self._stream.duration)
134                 return percent
135
136         def _set_piece_by_node(self, node):
137                 assert node is None or node.is_leaf(), node
138                 if self._node is node:
139                         _moduleLogger.info("Already set to %r" % node)
140                         return
141                 self._node = node
142                 if self._node is not None:
143                         self._stream.set_file(self._node.uri)
144                 _moduleLogger.info("New node %r" % self._node)
145                 self.emit("title_change", self._node)
146
147         @misc_utils.log_exception(_moduleLogger)
148         def _on_next_node(self, node, forcePlay):
149                 self._nextSearch = None
150
151                 restart = self.state == self.STATE_PLAY
152                 self._set_piece_by_node(node)
153                 if restart or forcePlay:
154                         self.play()
155
156         @misc_utils.log_exception(_moduleLogger)
157         def _on_node_search_error(self, e):
158                 self._nextSearch = None
159                 self.emit("error", e, "")
160
161         @misc_utils.log_exception(_moduleLogger)
162         def _on_stream_state(self, s, state):
163                 _moduleLogger.info("State change %r" % state)
164                 self.emit("state_change", state)
165
166         @misc_utils.log_exception(_moduleLogger)
167         def _on_stream_eof(self, s, uri):
168                 _moduleLogger.info("EOF %s" % uri)
169                 self.next(forcePlay = True)
170
171         @misc_utils.log_exception(_moduleLogger)
172         def _on_stream_error(self, s, error, debug):
173                 _moduleLogger.info("Error %s %s" % (error, debug))
174                 self.emit("error", error, debug)
175
176         @misc_utils.log_exception(_moduleLogger)
177         def _on_call_start(self, monitor):
178                 _moduleLogger.info("Call in progress, pausing")
179                 self.pause()
180
181
182 gobject.type_register(Player)