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