1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 __maintainer__ = 'Benjamin Kampmann <benjamin@fluendo.com>'
19
20 from elisa.core.component import Component
21
22 from elisa.core import common
23
24 from elisa.core.player import PlayerPlaying, PlayerStopping, \
25 PlayerPausing, PlayerLoading, \
26 STATES
27
28 from twisted.internet import reactor
29
30 import gst
31
33 """
34 A PlayerEngine provides various media playback related functionalities. It
35 declares the uri schemes it supports and will be automatically instantiated by
36 the L{elisa.core.player_engine_registry.PlayerEngineRegistry} if needed.
37
38 Messages listed at L{elisa.core.player} have to be sent by the engine at
39 appropriate times.
40
41 @cvar uri_schemes: the uri-schemes this engine supports associated
42 with their ranking value between 0 (highest rank)
43 and 255 (lowest rank)
44 @type uri_schemes: dict
45
46 @ivar _pipeline: the internally used pipeline
47 @type _pipeline: L{gst.Pipeline}
48
49 @ivar video_sink: the videosink of this player engine
50 @type video_sink: L{gst.BaseSink}
51
52 @ivar audio_sink: the audiosink of this player engine
53 @type audio_sink: L{gst.BaseSink}
54
55 @ivar visualisation: the visualisation element for the player engine
56 @type visualisation: L{gst.Element}
57
58 @ivar volume: a value between 0 and 10
59 @type volume: float
60
61 @ivar position: the position we are currently playing in
62 nanoseconds
63 @type position: float
64
65 @ivar duration: (read-only) the total length of the loaded uri in
66 nanoseconds
67 @type duration: float
68
69 @ivar speed: The speed of the current playback:
70 - Normal playback is 1.0
71 - a positive value means forward
72 - a negative one backward
73 - a value bigger (+/-) 1.0 means faster
74 - a value smaller (+/-) 1.0 means slower
75 - the value 0.0 (equivalent to pause) is not
76 allowed
77 @type speed: float
78
79 @ivar state: (read-only) The current state.
80 @type state: L{elisa.core.player.STATES}
81
82 @ivar uri: (write-only) change the engine to be able to play
83 the set uri.
84 @type uri: L{elisa.core.media_uri.Mediauri}
85
86
87 @ivar message_sender: who is the sender of messages (per default it is
88 self)
89 @type message_sender: instance
90 """
91
92 uri_schemes = {}
93
95 Component.__init__(self)
96 self._pipeline = None
97 self._state = STATES.STOPPED
98 self._speed = 1.0
99 self.message_sender = self
100 self._current_uri = None
101
102
103
104
105 - def play(self, trigger_message=True):
106 """
107 Play the media. If trigger_message is set to True, this triggers first
108 the message L{elisa.core.player.PlayerLoading} message and if the
109 playback is really starting, it triggers
110 L{elisa.core.player.PlayerPlaying}. Otherwise it does not trigger any
111 messages.
112
113 @param trigger_message: should the player trigger messages here
114 @type trigger_message: bool
115 """
116 if not self._pipeline:
117 return
118
119 if self.state == STATES.STOPPED:
120 self._state = STATES.LOADING
121
122 if trigger_message:
123 self.info("Loading %r", str(self._current_uri))
124 self._send_msg(PlayerLoading())
125
126 self._pipeline_set_state(gst.STATE_PLAYING)
127
128 elif self.state == STATES.PAUSED:
129 self._state = STATES.PLAYING
130
131 if trigger_message:
132 self._send_msg(PlayerPlaying())
133
134 self._pipeline_set_state(gst.STATE_PLAYING)
135
136
137
138 - def pause(self, trigger_message=True):
139 """
140 Pause the playback. If trigger_message is set to True, this triggers
141 the L{elisa.core.player.PlayerPausing} message.
142
143 @param trigger_message: should the player trigger a message here
144 @type trigger_message: bool
145 """
146 if self._pipeline:
147 if self.state == STATES.PLAYING:
148 self.info("Pausing Player")
149 self._state = STATES.PAUSED
150 if trigger_message:
151 self._send_msg(PlayerPausing())
152 self._pipeline_set_state(gst.STATE_PAUSED)
153
154
155 - def stop(self, trigger_message=True):
156 """
157 Stop the playback.
158 If trigger_message is set, this method triggers the
159 L{elisa.core.player.PlayerStopping} message.
160
161 @param trigger_message: should the player trigger a message here
162 @type trigger_message: bool
163 """
164 if self._pipeline:
165 self.info("Stopping Player")
166 if self.state != STATES.STOPPED:
167 self._state = STATES.STOPPED
168 self._pipeline_set_state(gst.STATE_READY)
169 if trigger_message:
170 self._send_msg(PlayerStopping())
171
172
173
176
179
180
181
184
185
186
188 if self.state not in (STATES.PLAYING, STATES.PAUSED):
189 return -1
190
191 try:
192 position, format = self._pipeline.query_position(gst.FORMAT_TIME)
193 return position
194 except:
195 return -1
196
201
204
206 if self.state not in (STATES.PLAYING, STATES.PAUSED):
207 return -1
208 try:
209 duration, format = self._pipeline.query_duration(gst.FORMAT_TIME)
210 return duration
211 except:
212 return -1
213
216
220
221
222
225
228
229
230
233
236
237
238
241
244
245
246
248 """
249 Makes it easier to send a message for the developers...
250 @param message: the message you want to send. Normally one of
251 L{elisa.core.player.PlayerLoading},
252 L{elisa.core.player.PlayerPlaying},
253 L{elisa.core.player.PlayerPausing} or
254 L{elisa.core.player.PlayerStopping}
255 @type message: L{elisa.core.bus.bus_message.Message}
256 """
257 self.debug("Sending message %r" % message)
258
259 common.application.bus.send_message(message,
260 sender = self.message_sender)
261
294
296 """
297 Set the state of the pipeline asynchronisly
298 """
299
300
301
302 if not self._pipeline:
303 return
304 reactor.callInThread(self._pipeline.set_state, state)
305