core: Add mixer controller (fixes: #962)

Deprecate volume and mute methods on playback controller.
This commit is contained in:
Stein Magnus Jodal 2015-02-11 00:48:59 +01:00
parent cc3e9d5597
commit 42115c56f7
9 changed files with 153 additions and 72 deletions

View File

@ -64,6 +64,14 @@ Manages the music library, e.g. searching for tracks to be added to a playlist.
:members:
Mixer controller
================
Manages volume and muting.
.. autoclass:: mopidy.core.MixerController
:members:
Core listener
=============

View File

@ -17,6 +17,10 @@ v0.20.0 (UNRELEASED)
- Added :class:`mopidy.core.HistoryController` which keeps track of what
tracks have been played. (Fixes: :issue:`423`, PR: :issue:`803`)
- Added :class:`mopidy.core.MixerController` which keeps track of volume and
mute. The old methods on :class:`mopidy.core.PlaybackController` for volume
and mute management has been deprecated. (Fixes: :issue:`962`)
- Removed ``clear_current_track`` keyword argument to
:meth:`mopidy.core.Playback.stop`. It was a leaky internal abstraction,
which was never intended to be used externally.

View File

@ -5,6 +5,7 @@ from .actor import Core
from .history import HistoryController
from .library import LibraryController
from .listener import CoreListener
from .mixer import MixerController
from .playback import PlaybackController, PlaybackState
from .playlists import PlaylistsController
from .tracklist import TracklistController

View File

@ -11,6 +11,7 @@ from mopidy.audio.utils import convert_tags_to_track
from mopidy.core.history import HistoryController
from mopidy.core.library import LibraryController
from mopidy.core.listener import CoreListener
from mopidy.core.mixer import MixerController
from mopidy.core.playback import PlaybackController
from mopidy.core.playlists import PlaylistsController
from mopidy.core.tracklist import TracklistController
@ -31,6 +32,10 @@ class Core(
"""The playback history controller. An instance of
:class:`mopidy.core.HistoryController`."""
mixer = None
"""The mixer controller. An instance of
:class:`mopidy.core.MixerController`."""
playback = None
"""The playback controller. An instance of
:class:`mopidy.core.PlaybackController`."""
@ -49,15 +54,10 @@ class Core(
self.backends = Backends(backends)
self.library = LibraryController(backends=self.backends, core=self)
self.history = HistoryController()
self.playback = PlaybackController(
mixer=mixer, backends=self.backends, core=self)
self.playlists = PlaylistsController(
backends=self.backends, core=self)
self.mixer = MixerController(mixer=mixer)
self.playback = PlaybackController(backends=self.backends, core=self)
self.playlists = PlaylistsController(backends=self.backends, core=self)
self.tracklist = TracklistController(core=self)
self.audio = audio

64
mopidy/core/mixer.py Normal file
View File

@ -0,0 +1,64 @@
from __future__ import absolute_import, unicode_literals
import logging
logger = logging.getLogger(__name__)
class MixerController(object):
pykka_traversable = True
def __init__(self, mixer):
self._mixer = mixer
self._volume = None
self._mute = False
def get_volume(self):
"""Get the volume.
Integer in range [0..100] or :class:`None` if unknown.
The volume scale is linear.
"""
if self._mixer:
return self._mixer.get_volume().get()
else:
# For testing
return self._volume
def set_volume(self, volume):
"""Set the volume.
The volume is defined as an integer in range [0..100].
The volume scale is linear.
"""
if self._mixer:
self._mixer.set_volume(volume)
else:
# For testing
self._volume = volume
def get_mute(self):
"""Get mute state.
:class:`True` if muted, :class:`False` otherwise.
"""
if self._mixer:
return self._mixer.get_mute().get()
else:
# For testing
return self._mute
def set_mute(self, mute):
"""Set mute state.
:class:`True` to mute, :class:`False` to unmute.
"""
mute = bool(mute)
if self._mixer:
self._mixer.set_mute(mute)
else:
# For testing
self._mute = mute

View File

@ -2,6 +2,7 @@ from __future__ import absolute_import, unicode_literals
import logging
import urlparse
import warnings
from mopidy.audio import PlaybackState
from mopidy.core import listener
@ -11,20 +12,16 @@ from mopidy.utils.deprecation import deprecated_property
logger = logging.getLogger(__name__)
# TODO: split mixing out from playback?
class PlaybackController(object):
pykka_traversable = True
def __init__(self, mixer, backends, core):
self.mixer = mixer
def __init__(self, backends, core):
self.backends = backends
self.core = core
self._current_tl_track = None
self._current_metadata_track = None
self._state = PlaybackState.STOPPED
self._volume = None
self._mute = False
def _get_backend(self):
# TODO: take in track instead
@ -139,64 +136,59 @@ class PlaybackController(object):
"""
def get_volume(self):
"""Get the volume.
Integer in range [0..100] or :class:`None` if unknown.
The volume scale is linear.
"""
if self.mixer:
return self.mixer.get_volume().get()
else:
# For testing
return self._volume
... deprecated:: 0.20
Use :meth:`core.mixer.get_volume()
<mopidy.core.MixerController.get_volume>` instead.
"""
warnings.warn(
'playback.get_volume() is deprecated', DeprecationWarning)
return self.core.mixer.get_volume()
def set_volume(self, volume):
"""Set the volume.
The volume is defined as an integer in range [0..100].
The volume scale is linear.
"""
if self.mixer:
self.mixer.set_volume(volume)
else:
# For testing
self._volume = volume
... deprecated:: 0.20
Use :meth:`core.mixer.set_volume()
<mopidy.core.MixerController.set_volume>` instead.
"""
warnings.warn(
'playback.set_volume() is deprecated', DeprecationWarning)
return self.core.mixer.set_volume(volume)
volume = deprecated_property(get_volume, set_volume)
"""
.. deprecated:: 0.20
Use :meth:`get_volume` and :meth:`set_volume` instead.
Use :meth:`core.mixer.get_volume()
<mopidy.core.MixerController.get_volume>` and
:meth:`core.mixer.set_volume()
<mopidy.core.MixerController.set_volume>` instead.
"""
def get_mute(self):
"""Get mute state.
:class:`True` if muted, :class:`False` otherwise.
"""
if self.mixer:
return self.mixer.get_mute().get()
else:
# For testing
return self._mute
def set_mute(self, value):
"""Set mute state.
:class:`True` to mute, :class:`False` to unmute.
... deprecated:: 0.20
Use :meth:`core.mixer.get_mute()
<mopidy.core.MixerController.get_mute>` instead.
"""
value = bool(value)
if self.mixer:
self.mixer.set_mute(value)
else:
# For testing
self._mute = value
warnings.warn('playback.get_mute() is deprecated', DeprecationWarning)
return self.core.mixer.get_mute()
def set_mute(self, mute):
"""
... deprecated:: 0.20
Use :meth:`core.mixer.set_mute()
<mopidy.core.MixerController.set_mute>` instead.
"""
warnings.warn('playback.set_mute() is deprecated', DeprecationWarning)
return self.core.mixer.set_mute(mute)
mute = deprecated_property(get_mute, set_mute)
"""
.. deprecated:: 0.20
Use :meth:`get_mute` and :meth:`set_mute` instead.
Use :meth:`core.mixer.get_mute()
<mopidy.core.MixerController.get_mute>` and
:meth:`core.mixer.set_mute()
<mopidy.core.MixerController.set_mute>` instead.
"""
# Methods

View File

@ -43,6 +43,7 @@ def make_jsonrpc_wrapper(core_actor):
'core.get_version': core.Core.get_version,
'core.history': core.HistoryController,
'core.library': core.LibraryController,
'core.mixer': core.MixerController,
'core.playback': core.PlaybackController,
'core.playlists': core.PlaylistsController,
'core.tracklist': core.TracklistController,
@ -54,6 +55,7 @@ def make_jsonrpc_wrapper(core_actor):
'core.get_version': core_actor.get_version,
'core.history': core_actor.history,
'core.library': core_actor.library,
'core.mixer': core_actor.mixer,
'core.playback': core_actor.playback,
'core.playlists': core_actor.playlists,
'core.tracklist': core_actor.tracklist,

28
tests/core/test_mixer.py Normal file
View File

@ -0,0 +1,28 @@
from __future__ import absolute_import, unicode_literals
import unittest
from mopidy import core
class CoreMixerTest(unittest.TestCase):
def setUp(self): # noqa: N802
self.core = core.Core(mixer=None, backends=[])
def test_volume(self):
self.assertEqual(self.core.mixer.get_volume(), None)
self.core.mixer.set_volume(30)
self.assertEqual(self.core.mixer.get_volume(), 30)
self.core.mixer.set_volume(70)
self.assertEqual(self.core.mixer.get_volume(), 70)
def test_mute(self):
self.assertEqual(self.core.mixer.get_mute(), False)
self.core.mixer.set_mute(True)
self.assertEqual(self.core.mixer.get_mute(), True)

View File

@ -426,21 +426,3 @@ class CorePlaybackTest(unittest.TestCase):
self.assertFalse(self.playback2.get_time_position.called)
# TODO Test on_tracklist_change
def test_volume(self):
self.assertEqual(self.core.playback.volume, None)
self.core.playback.volume = 30
self.assertEqual(self.core.playback.volume, 30)
self.core.playback.volume = 70
self.assertEqual(self.core.playback.volume, 70)
def test_mute(self):
self.assertEqual(self.core.playback.mute, False)
self.core.playback.mute = True
self.assertEqual(self.core.playback.mute, True)