From 0a6545f6d0515735da1443e19a04f45a0de40c29 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 22 Feb 2010 19:47:25 +0100 Subject: [PATCH] Add volume control support to BaseBackend through alsaaudio.Mixer --- docs/installation.rst | 1 + mopidy/backends/__init__.py | 22 +++++++++++++++++----- mopidy/backends/dummy.py | 11 ++++++++++- mopidy/mpd/handler.py | 5 +++-- tests/mpd/handlertest.py | 23 +++++++++++++++++------ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index bdf523ea..004454e8 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -14,6 +14,7 @@ Dependencies ============ * Python >= 2.5 +* pyalsaaudio >= 0.2 (Debian/Ubuntu: python-alsaaudio) * Dependencies for at least one Mopidy backend: * :ref:`despotify` diff --git a/mopidy/backends/__init__.py b/mopidy/backends/__init__.py index 962e91ba..f0d700c9 100644 --- a/mopidy/backends/__init__.py +++ b/mopidy/backends/__init__.py @@ -3,6 +3,8 @@ import logging import random import time +import alsaaudio + from mopidy.models import Playlist logger = logging.getLogger('backends.base') @@ -242,13 +244,10 @@ class BasePlaybackController(object): #: The current track is played once. repeat = False - #: The audio volume as an int in the range [0, 100]. :class:`None` if - #: unknown. - volume = None - - def __init__(self, backend): + def __init__(self, backend, mixer=alsaaudio.Mixer): self.backend = backend self._state = self.STOPPED + self._mixer = mixer() @property def next_track(self): @@ -325,6 +324,19 @@ class BasePlaybackController(object): def _play_time_resume(self): self._play_time_started = int(time.time()) + @property + def volume(self): + """ + The audio volume as an int in the range [0, 100]. + + :class:`None` if unknown. + """ + return self._mixer.getvolume()[0] + + @volume.setter + def volume(self, volume): + self._mixer.setvolume(volume) + def new_playlist_loaded_callback(self): """Tell the playback controller that a new playlist has been loaded.""" self.current_track = None diff --git a/mopidy/backends/dummy.py b/mopidy/backends/dummy.py index 93c8f218..76e59fc5 100644 --- a/mopidy/backends/dummy.py +++ b/mopidy/backends/dummy.py @@ -7,7 +7,7 @@ class DummyBackend(BaseBackend): def __init__(self): self.current_playlist = DummyCurrentPlaylistController(backend=self) self.library = DummyLibraryController(backend=self) - self.playback = DummyPlaybackController(backend=self) + self.playback = DummyPlaybackController(backend=self, mixer=DummyMixer) self.stored_playlists = DummyStoredPlaylistsController(backend=self) self.uri_handlers = [u'dummy:'] @@ -37,3 +37,12 @@ class DummyPlaybackController(BasePlaybackController): class DummyStoredPlaylistsController(BaseStoredPlaylistsController): def search(self, query): return [Playlist(name=query)] + +class DummyMixer(object): + volume = 0 + + def getvolume(self): + return [self.volume, self.volume] + + def setvolume(self, volume): + self.volume = volume diff --git a/mopidy/mpd/handler.py b/mopidy/mpd/handler.py index a37960db..b9b032a2 100644 --- a/mopidy/mpd/handler.py +++ b/mopidy/mpd/handler.py @@ -419,14 +419,15 @@ class MpdHandler(object): def _seekid(self, songid, seconds): raise MpdNotImplemented # TODO - @register(r'^setvol "(?P-*\d+)"$') + @register(r'^setvol (?P[-+]*\d+)$') + @register(r'^setvol "(?P[-+]*\d+)"$') def _setvol(self, volume): volume = int(volume) if volume < 0: volume = 0 if volume > 100: volume = 100 - raise MpdNotImplemented # TODO + self.backend.playback.volume = volume @register(r'^shuffle$') @register(r'^shuffle "(?P\d+):(?P\d+)*"$') diff --git a/tests/mpd/handlertest.py b/tests/mpd/handlertest.py index 8996d6af..1cef5718 100644 --- a/tests/mpd/handlertest.py +++ b/tests/mpd/handlertest.py @@ -290,7 +290,8 @@ class StatusHandlerTest(unittest.TestCase): class PlaybackOptionsHandlerTest(unittest.TestCase): def setUp(self): - self.h = handler.MpdHandler(backend=DummyBackend()) + self.b = DummyBackend() + self.h = handler.MpdHandler(backend=self.b) def test_consume_off(self): result = self.h.handle_request(u'consume "0"') @@ -322,23 +323,33 @@ class PlaybackOptionsHandlerTest(unittest.TestCase): def test_setvol_below_min(self): result = self.h.handle_request(u'setvol "-10"') - self.assert_(u'ACK Not implemented' in result) + self.assert_(u'OK' in result) + self.assertEqual(0, self.b.playback.volume) def test_setvol_min(self): result = self.h.handle_request(u'setvol "0"') - self.assert_(u'ACK Not implemented' in result) + self.assert_(u'OK' in result) + self.assertEqual(0, self.b.playback.volume) def test_setvol_middle(self): result = self.h.handle_request(u'setvol "50"') - self.assert_(u'ACK Not implemented' in result) + self.assert_(u'OK' in result) + self.assertEqual(50, self.b.playback.volume) def test_setvol_max(self): result = self.h.handle_request(u'setvol "100"') - self.assert_(u'ACK Not implemented' in result) + self.assert_(u'OK' in result) + self.assertEqual(100, self.b.playback.volume) def test_setvol_above_max(self): result = self.h.handle_request(u'setvol "110"') - self.assert_(u'ACK Not implemented' in result) + self.assert_(u'OK' in result) + self.assertEqual(100, self.b.playback.volume) + + def test_setvol_plus_is_ignored(self): + result = self.h.handle_request(u'setvol "+10"') + self.assert_(u'OK' in result) + self.assertEqual(10, self.b.playback.volume) def test_single_off(self): result = self.h.handle_request(u'single "0"')