Merge lp:~samuel-buffet/entertainer/volume_management into lp:entertainer

Proposed by Samuel Buffet
Status: Merged
Approved by: Paul Hummer
Approved revision: 404
Merged at revision: not available
Proposed branch: lp:~samuel-buffet/entertainer/volume_management
Merge into: lp:entertainer
Diff against target: None lines
To merge this branch: bzr merge lp:~samuel-buffet/entertainer/volume_management
Reviewer Review Type Date Requested Status
Paul Hummer Approve
Review via email: mp+7992@code.launchpad.net

Commit message

It's now possible to change the player's volume level.

To post a comment you must log in.
Revision history for this message
Samuel Buffet (samuel-buffet) wrote :

Devs,

With this branch it is now possible to change the volume level when playing a media. This is something important that was missing (I think).

To reach that goal, a "volume" property has been added to the media player.
A VolumeIndicator has also been created. It's themable and is displayed when we change the volume with a fade in effect while the screen is faded out at the same time.

The keys I've chosen to change the volume are l = volume down and m = volume up. If you prefer other keys just let me know.

The VolumeIndicator widget is not reactive right now (I'l do that in an other branch)

Samuel-

402. By Samuel Buffet

Merged with trunk 389.

403. By Samuel Buffet

Fixes after Paul's comments.

404. By Samuel Buffet

Merged with trunk 393.

Revision history for this message
Samuel Buffet (samuel-buffet) wrote :
Download full text (14.6 KiB)

Devs,

I've pushed some modifications after Paul's comments.

new diff :

=== added file 'cfg/themes/Black/images/volume.png'
Binary files cfg/themes/Black/images/volume.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume.png 2009-06-27 09:25:00 +0000 differ
=== added file 'cfg/themes/Black/images/volume_filled.png'
Binary files cfg/themes/Black/images/volume_filled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume_filled.png 2009-06-01 20:55:32 +0000 differ
=== added file 'cfg/themes/Black/images/volume_unfilled.png'
Binary files cfg/themes/Black/images/volume_unfilled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume_unfilled.png 2009-06-01 20:55:34 +0000 differ
=== added file 'cfg/themes/Default/images/volume.png'
Binary files cfg/themes/Default/images/volume.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume.png 2009-06-01 20:55:33 +0000 differ
=== added file 'cfg/themes/Default/images/volume_filled.png'
Binary files cfg/themes/Default/images/volume_filled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume_filled.png 2009-06-01 20:55:34 +0000 differ
=== added file 'cfg/themes/Default/images/volume_unfilled.png'
Binary files cfg/themes/Default/images/volume_unfilled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume_unfilled.png 2009-06-01 20:55:34 +0000 differ
=== modified file 'entertainerlib/frontend/gui/user_event.py'
--- entertainerlib/frontend/gui/user_event.py 2009-05-06 03:40:22 +0000
+++ entertainerlib/frontend/gui/user_event.py 2009-06-01 20:55:33 +0000
@@ -18,6 +18,8 @@
     PLAYER_PREVIOUS = 3
     PLAYER_SKIP_FORWARD = 4
     PLAYER_SKIP_BACKWARD = 5
+ PLAYER_VOLUME_UP = 6
+ PLAYER_VOLUME_DOWN = 7

     # Navigation events
     NAVIGATE_UP = 20

=== modified file 'entertainerlib/frontend/gui/user_interface.py'
--- entertainerlib/frontend/gui/user_interface.py 2009-06-28 20:12:13 +0000
+++ entertainerlib/frontend/gui/user_interface.py 2009-06-29 19:35:06 +0000
@@ -20,6 +20,7 @@
 from entertainerlib.frontend.gui.user_event import UserEvent
 from entertainerlib.frontend.gui.widgets.menu_overlay import MenuOverlay
 from entertainerlib.frontend.media_player import MediaPlayer
+from entertainerlib.frontend.gui.widgets.volume_indicator import VolumeIndicator
 from entertainerlib.utils.configuration import Configuration
 from entertainerlib.utils.logger import Logger

@@ -92,6 +93,7 @@

         self.player = MediaPlayer(self.stage,
             self.config.get_stage_width(), self.config.get_stage_height())
+ self.player.connect('volume-changed', self._on_volume_changed)

         # Initialize menu overlay texture
         self.is_overlay = False
@@ -101,6 +103,15 @@
             self.config.get_stage_width(), self.config.get_stage_height())
         self.stage.add(self.menu_overlay)

+ self.volume_indicator = VolumeIndicator()
+ self.stage.add(self.volume_indicator)
+ self.volume_indicator.connect('hiding',
+ self._on_volume_indicator_hiding)
+ self.fade_screen_timeline = clutter.Timeline(13, 26)
+ alpha = clutter.Alpha(self.fade_screen_timeline,
+ clutter.smoothstep_inc...

Revision history for this message
Paul Hummer (rockstar) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'cfg/themes/Black/images/volume.png'
2Binary files cfg/themes/Black/images/volume.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume.png 2009-06-01 19:59:57 +0000 differ
3=== added file 'cfg/themes/Black/images/volume_filled.png'
4Binary files cfg/themes/Black/images/volume_filled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume_filled.png 2009-06-01 19:25:27 +0000 differ
5=== added file 'cfg/themes/Black/images/volume_unfilled.png'
6Binary files cfg/themes/Black/images/volume_unfilled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume_unfilled.png 2009-06-01 19:25:27 +0000 differ
7=== added file 'cfg/themes/Default/images/volume.png'
8Binary files cfg/themes/Default/images/volume.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume.png 2009-06-01 19:59:57 +0000 differ
9=== added file 'cfg/themes/Default/images/volume_filled.png'
10Binary files cfg/themes/Default/images/volume_filled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume_filled.png 2009-06-01 19:25:27 +0000 differ
11=== added file 'cfg/themes/Default/images/volume_unfilled.png'
12Binary files cfg/themes/Default/images/volume_unfilled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume_unfilled.png 2009-06-01 19:25:27 +0000 differ
13=== modified file 'entertainerlib/frontend/gui/user_event.py'
14--- entertainerlib/frontend/gui/user_event.py 2009-05-06 03:40:22 +0000
15+++ entertainerlib/frontend/gui/user_event.py 2009-05-29 10:33:32 +0000
16@@ -18,6 +18,8 @@
17 PLAYER_PREVIOUS = 3
18 PLAYER_SKIP_FORWARD = 4
19 PLAYER_SKIP_BACKWARD = 5
20+ PLAYER_VOLUME_UP = 6
21+ PLAYER_VOLUME_DOWN = 7
22
23 # Navigation events
24 NAVIGATE_UP = 20
25
26=== modified file 'entertainerlib/frontend/gui/user_interface.py'
27--- entertainerlib/frontend/gui/user_interface.py 2009-06-03 01:54:03 +0000
28+++ entertainerlib/frontend/gui/user_interface.py 2009-06-27 10:51:35 +0000
29@@ -20,6 +20,7 @@
30 from entertainerlib.frontend.gui.user_event import UserEvent
31 from entertainerlib.frontend.gui.widgets.menu_overlay import MenuOverlay
32 from entertainerlib.frontend.media_player import MediaPlayer
33+from entertainerlib.frontend.gui.widgets.volume_indicator import VolumeIndicator
34 from entertainerlib.utils.configuration import Configuration
35 from entertainerlib.utils.logger import Logger
36
37@@ -92,6 +93,7 @@
38
39 self.player = MediaPlayer(self.stage,
40 self.config.get_stage_width(), self.config.get_stage_height())
41+ self.player.connect("volume-changed", self._on_volume_changed)
42
43 # Initialize menu overlay texture
44 self.overlay_status = False
45@@ -102,6 +104,15 @@
46 self.config.get_stage_width(), self.config.get_stage_height())
47 self.stage.add(self.menu_overlay)
48
49+ self.volume_indicator = VolumeIndicator()
50+ self.stage.add(self.volume_indicator)
51+ self.volume_indicator.connect("hidening",
52+ self._on_volume_indicator_hidening)
53+ self.fade_screen_timeline = clutter.Timeline(13, 26)
54+ alpha = clutter.Alpha(self.fade_screen_timeline,
55+ clutter.smoothstep_inc_func)
56+ self.fade_screen_behaviour = clutter.BehaviourOpacity(255, 0, alpha)
57+
58 # Transition object. Handles effects between screen changes.
59 transition_factory = TransitionFactory(self._remove_from_stage)
60 self.transition = transition_factory.generate_transition()
61@@ -140,6 +151,8 @@
62 clutter.keysyms.c : UserEvent.PLAYER_SKIP_FORWARD,
63 clutter.keysyms.z : UserEvent.PLAYER_PREVIOUS,
64 clutter.keysyms.v : UserEvent.PLAYER_NEXT,
65+ clutter.keysyms.m : UserEvent.PLAYER_VOLUME_UP,
66+ clutter.keysyms.l : UserEvent.PLAYER_VOLUME_DOWN,
67 clutter.keysyms.q : UserEvent.QUIT_FRONTEND,
68 clutter.keysyms.Escape : UserEvent.QUIT_FRONTEND
69 })
70@@ -168,6 +181,8 @@
71 UserEvent.PLAYER_SKIP_FORWARD : self._handle_player_skip_forward,
72 UserEvent.PLAYER_PREVIOUS : self._handle_player_previous,
73 UserEvent.PLAYER_NEXT : self._handle_player_next,
74+ UserEvent.PLAYER_VOLUME_UP : self._handle_player_volume_up,
75+ UserEvent.PLAYER_VOLUME_DOWN : self._handle_player_volume_down,
76 UserEvent.QUIT_FRONTEND : self._handle_quit_frontend
77 }
78
79@@ -394,6 +409,14 @@
80 self.player.stop()
81 self.current.handle_user_event(event)
82
83+ def _handle_player_volume_up(self, event):
84+ '''Handle UserEvent.PLAYER_VOLUME_UP.'''
85+ self.player.volume_up()
86+
87+ def _handle_player_volume_down(self, event):
88+ '''Handle UserEvent.PLAYER_VOLUME_DOWN.'''
89+ self.player.volume_down()
90+
91 def _handle_toggle_fullscreen(self, event):
92 '''Handle UserEvent.TOGGLE_FULLSCREEN.'''
93 self._toggle_fullscreen()
94@@ -402,3 +425,18 @@
95 '''Handle UserEvent.QUIT_FRONTEND.'''
96 self.confirm_exit()
97
98+ def _on_volume_changed(self, event):
99+ """Show volume indicator and fade out the screen (if needed)."""
100+ if not self.volume_indicator.visible:
101+ if not self.fade_screen_behaviour.is_applied(self.current):
102+ self.fade_screen_behaviour.apply(self.current)
103+ self.fade_screen_behaviour.set_bounds(255, 50)
104+ self.fade_screen_timeline.start()
105+
106+ self.volume_indicator.show_volume(self.player.volume)
107+
108+ def _on_volume_indicator_hidening(self, event):
109+ """Restore previous screen opacity."""
110+ self.fade_screen_behaviour.set_bounds(50, 255)
111+ self.fade_screen_timeline.start()
112+
113
114=== added file 'entertainerlib/frontend/gui/widgets/volume_indicator.py'
115--- entertainerlib/frontend/gui/widgets/volume_indicator.py 1970-01-01 00:00:00 +0000
116+++ entertainerlib/frontend/gui/widgets/volume_indicator.py 2009-06-28 09:12:14 +0000
117@@ -0,0 +1,80 @@
118+# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2
119+"""A volume indicator widgets."""
120+
121+import clutter
122+import gobject
123+
124+from entertainerlib.frontend.gui.widgets.base import Base
125+
126+class VolumeIndicator(Base, clutter.Group):
127+ """Volume Indicator displaying player's volume level."""
128+ __gsignals__ = {
129+ 'hidening' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
130+ }
131+
132+ def __init__(self):
133+ Base.__init__(self)
134+ clutter.Group.__init__(self)
135+
136+ theme = self.config.theme
137+ filled = clutter.Texture(theme.getImage("volume_filled"))
138+ unfilled = clutter.Texture(theme.getImage("volume_unfilled"))
139+ volume = clutter.Texture(theme.getImage("volume"))
140+ self.add(volume)
141+
142+ self._pokes = []
143+
144+ poke_width = filled.get_width()
145+
146+ for i in range(20):
147+ poke_filled = clutter.CloneTexture(filled)
148+ poke_unfilled = clutter.CloneTexture(unfilled)
149+ poke_filled.set_position(volume.get_width() + i * poke_width, 0)
150+ poke_unfilled.set_position(volume.get_width() + i * poke_width, 0)
151+ self.add(poke_filled)
152+ self.add(poke_unfilled)
153+ self._pokes.append([poke_filled, poke_unfilled])
154+
155+ self._hide_timeout_key = None
156+ self.visible = False
157+ self.set_opacity(0)
158+
159+ self.timeline = clutter.Timeline(13, 26)
160+ self.alpha = clutter.Alpha(self.timeline, clutter.smoothstep_inc_func)
161+ self.behaviour = clutter.BehaviourOpacity(255, 0, self.alpha)
162+ self.behaviour.apply(self)
163+
164+ self.set_position(self.get_abs_x(0.35), self.get_abs_y(0.1))
165+
166+ def show_volume(self, volume):
167+ """Displays volume level using filled and unfilled pokes."""
168+ self.raise_top()
169+
170+ if self._hide_timeout_key is not None:
171+ gobject.source_remove(self._hide_timeout_key)
172+ self._hide_timeout_key = gobject.timeout_add(2000,
173+ self.animate_out)
174+
175+ for index, pokes in enumerate(self._pokes):
176+ if index >= volume:
177+ pokes[0].set_opacity(0)
178+ pokes[1].set_opacity(255)
179+ else:
180+ pokes[0].set_opacity(255)
181+ pokes[1].set_opacity(0)
182+
183+ if self.visible == True:
184+ return
185+
186+ self.visible = True
187+ self.behaviour.set_bounds(0, 255)
188+ self.timeline.start()
189+
190+ def animate_out(self):
191+ """Fades out."""
192+ self.behaviour.set_bounds(255, 0)
193+ self.timeline.start()
194+ self.visible = False
195+ self.emit("hidening")
196+ return False
197+
198
199=== modified file 'entertainerlib/frontend/media_player.py'
200--- entertainerlib/frontend/media_player.py 2009-05-26 17:32:56 +0000
201+++ entertainerlib/frontend/media_player.py 2009-06-27 11:00:55 +0000
202@@ -32,6 +32,7 @@
203 'skip-forward' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
204 'skip-backward' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
205 'position_changed' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
206+ 'volume_changed' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
207 }
208
209 # Ratio constants
210@@ -64,6 +65,8 @@
211
212 self.video_texture = cluttergst.VideoTexture()
213 self.playbin = self.video_texture.get_playbin()
214+ self.playbin.set_property("volume", 0.5)
215+ self._volume = 10
216 self.bus = self.playbin.get_bus()
217 self.bus.add_signal_watch()
218 self.bus.connect('message', self._on_gst_message)
219@@ -91,6 +94,30 @@
220 self.logger.error("Error: %(err)s, %(debug)s" % \
221 {'err': err, 'debug': debug})
222
223+ def _get_volume(self):
224+ """volume property getter."""
225+ return self._volume
226+
227+ def _set_volume(self, volume):
228+ """volume property setter."""
229+ self._volume = volume
230+ if self._volume > 20:
231+ self._volume = 20
232+ if self._volume < 0:
233+ self._volume = 0
234+ self.playbin.set_property("volume", self._volume / 20.0)
235+ self.emit("volume-changed")
236+
237+ volume = property(_get_volume, _set_volume)
238+
239+ def volume_up(self):
240+ """Increase player's volume level."""
241+ self.volume = self._volume + 1
242+
243+ def volume_down(self):
244+ """Decrease player's volume level."""
245+ self.volume = self._volume - 1
246+
247 def set_playlist(self, playlist):
248 '''Set new playlist to MediaPlayer.'''
249 if len(playlist) == 0:
250
251=== modified file 'entertainerlib/tests/mock.py'
252--- entertainerlib/tests/mock.py 2009-06-15 03:19:46 +0000
253+++ entertainerlib/tests/mock.py 2009-06-28 12:19:08 +0000
254@@ -1,6 +1,7 @@
255 # Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2
256 '''Test mock objects'''
257 # pylint: disable-msg=W0231
258+import clutter
259 import gobject
260
261 from entertainerlib.frontend.backend_connection import BackendConnection
262@@ -328,3 +329,10 @@
263 self.y = 0
264 self.time = 0
265
266+
267+class MockStage(clutter.Stage):
268+ '''Mock a clutter Stage.'''
269+
270+ def __init__(self):
271+ clutter.Stage.__init__(self)
272+
273
274=== added file 'entertainerlib/tests/test_mediaplayer.py'
275--- entertainerlib/tests/test_mediaplayer.py 1970-01-01 00:00:00 +0000
276+++ entertainerlib/tests/test_mediaplayer.py 2009-06-28 12:19:08 +0000
277@@ -0,0 +1,85 @@
278+# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2
279+"""Tests MediaPlayer"""
280+
281+import os
282+
283+from entertainerlib.frontend.media_player import MediaPlayer
284+from entertainerlib.frontend.medialibrary.videos import VideoItem
285+from entertainerlib.tests import EntertainerTest
286+from entertainerlib.tests.mock import MockStage
287+
288+THIS_DIR = os.path.dirname(__file__)
289+
290+class MediaPlayerTest(EntertainerTest):
291+ """Test for entertainerlib.frontend.gui.widgets.volume_indicator"""
292+
293+ def setUp(self):
294+ '''Set up the test.'''
295+ EntertainerTest.setUp(self)
296+
297+ self.stage = MockStage()
298+ self.player = MediaPlayer(self.stage, 100, 100)
299+ self.video_item = VideoItem()
300+ self.video_item.set_filename(
301+ THIS_DIR + '/data/VideoThumbnailer/test.avi')
302+ self.player.set_media(self.video_item)
303+
304+ def test_create(self):
305+ '''Test correct MediaPlayer initialization.'''
306+ self.assertTrue(isinstance(self.player, MediaPlayer))
307+
308+ def test_volume(self):
309+ '''Test the use of the volume property.'''
310+ self.player.volume = 10
311+ self.assertEqual(self.player.volume, 10)
312+ self.player.volume = 99
313+ self.assertEqual(self.player.volume, 20)
314+ self.player.volume = -10
315+ self.assertEqual(self.player.volume, 0)
316+
317+ def test_volumedown(self):
318+ '''Test the use of the volume_down method.'''
319+ self.player.volume = 10
320+ self.player.volume_down()
321+ self.assertEqual(self.player.volume, 9)
322+
323+ def test_volumeup(self):
324+ '''Test the use of the volume_up method.'''
325+ self.player.volume = 10
326+ self.player.volume_up()
327+ self.assertEqual(self.player.volume, 11)
328+
329+ def test_setmedia(self):
330+ '''Test the use of the set_media method.'''
331+ # The method is called during setUp.
332+ self.assertTrue(self.player.media is not None)
333+
334+ def test_getmedia(self):
335+ '''Test the use of the get_media method.'''
336+ self.assertEqual(self.player.get_media(), self.video_item)
337+
338+ def test_hasmedia(self):
339+ '''Test the use of the has_media method.'''
340+ self.assertTrue(self.player.has_media())
341+
342+ def test_getmediatype(self):
343+ '''Test the use of the get_media_type method.'''
344+ self.assertEqual(self.player.get_media_type(),
345+ self.video_item.get_type())
346+
347+ def test_playstop(self):
348+ '''Test the use of the play and stop methods.'''
349+ self.player.play()
350+ self.assertTrue(self.player.playing)
351+ self.player.stop()
352+ self.assertFalse(self.player.playing)
353+
354+ def test_getmediatitle(self):
355+ '''Test the use of the get_media_title method.'''
356+ self.assertEqual(self.player.get_media_title(),
357+ THIS_DIR + '/data/VideoThumbnailer/test.avi')
358+
359+ def test_getmediadurationstring(self):
360+ '''Test the use of the get_media_title method.'''
361+ self.assertEqual(self.player.get_media_duration_string(), "00:00")
362+
363
364=== added file 'entertainerlib/tests/test_volumeindicator.py'
365--- entertainerlib/tests/test_volumeindicator.py 1970-01-01 00:00:00 +0000
366+++ entertainerlib/tests/test_volumeindicator.py 2009-06-28 12:19:08 +0000
367@@ -0,0 +1,24 @@
368+# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2
369+"""Tests VolumeIndicator"""
370+
371+from entertainerlib.frontend.gui.widgets.volume_indicator import VolumeIndicator
372+from entertainerlib.tests import EntertainerTest
373+
374+class VolumeIndicatorTest(EntertainerTest):
375+ """Test for entertainerlib.frontend.gui.widgets.volume_indicator"""
376+
377+ def setUp(self):
378+ '''Set up the test.'''
379+ EntertainerTest.setUp(self)
380+
381+ self.indicator = VolumeIndicator()
382+
383+ def test_create(self):
384+ '''Test correct VolumeIndicator initialization.'''
385+ self.assertTrue(isinstance(self.indicator, VolumeIndicator))
386+
387+ def test_show_volume(self):
388+ '''Test the use of the show_volume method.'''
389+ self.indicator.show_volume(5)
390+ self.assertTrue(self.indicator.visible)
391+

Subscribers

People subscribed via source and target branches