Allow 'none' as audio.mixer value
To disable mixing altogether, you can now set the configuration value audio/mixer to 'none'.
This commit is contained in:
parent
29b00cabf9
commit
cb19b2c48c
@ -57,6 +57,9 @@ v0.20.0 (UNRELEASED)
|
|||||||
|
|
||||||
- Add debug logging of unknown sections. (Fixes: :issue:`694`, PR: :issue:`1002`)
|
- Add debug logging of unknown sections. (Fixes: :issue:`694`, PR: :issue:`1002`)
|
||||||
|
|
||||||
|
- Add support for configuring :confval:`audio/mixer` to ``none``. (Fixes:
|
||||||
|
:issue:`936`)
|
||||||
|
|
||||||
**Logging**
|
**Logging**
|
||||||
|
|
||||||
- Add custom log level ``TRACE`` (numerical level 5), which can be used by
|
- Add custom log level ``TRACE`` (numerical level 5), which can be used by
|
||||||
@ -114,6 +117,10 @@ v0.20.0 (UNRELEASED)
|
|||||||
- Switch the ``list`` command over to using
|
- Switch the ``list`` command over to using
|
||||||
:meth:`mopidy.core.LibraryController.get_distinct`. (Fixes: :issue:`913`)
|
:meth:`mopidy.core.LibraryController.get_distinct`. (Fixes: :issue:`913`)
|
||||||
|
|
||||||
|
- Add support for ``toggleoutput`` command. The ``mixrampdb`` and
|
||||||
|
``mixrampdelay`` commands are now supported but throw a NotImplemented
|
||||||
|
exception.
|
||||||
|
|
||||||
**HTTP frontend**
|
**HTTP frontend**
|
||||||
|
|
||||||
- Prevent race condition in webservice broadcast from breaking the server.
|
- Prevent race condition in webservice broadcast from breaking the server.
|
||||||
|
|||||||
@ -70,6 +70,8 @@ Audio configuration
|
|||||||
will affect the audio volume if you're streaming the audio from Mopidy
|
will affect the audio volume if you're streaming the audio from Mopidy
|
||||||
through Shoutcast.
|
through Shoutcast.
|
||||||
|
|
||||||
|
If you want to disable audio mixing set the value to ``none``.
|
||||||
|
|
||||||
If you want to use a hardware mixer, you need to install a Mopidy extension
|
If you want to use a hardware mixer, you need to install a Mopidy extension
|
||||||
which integrates with your sound subsystem. E.g. for ALSA, install
|
which integrates with your sound subsystem. E.g. for ALSA, install
|
||||||
`Mopidy-ALSAMixer <https://github.com/mopidy/mopidy-alsamixer>`_.
|
`Mopidy-ALSAMixer <https://github.com/mopidy/mopidy-alsamixer>`_.
|
||||||
|
|||||||
@ -276,7 +276,9 @@ class RootCommand(Command):
|
|||||||
|
|
||||||
exit_status_code = 0
|
exit_status_code = 0
|
||||||
try:
|
try:
|
||||||
mixer = self.start_mixer(config, mixer_class)
|
mixer = None
|
||||||
|
if mixer_class is not None:
|
||||||
|
mixer = self.start_mixer(config, mixer_class)
|
||||||
audio = self.start_audio(config, mixer)
|
audio = self.start_audio(config, mixer)
|
||||||
backends = self.start_backends(config, backend_classes, audio)
|
backends = self.start_backends(config, backend_classes, audio)
|
||||||
core = self.start_core(mixer, backends, audio)
|
core = self.start_core(mixer, backends, audio)
|
||||||
@ -297,7 +299,8 @@ class RootCommand(Command):
|
|||||||
self.stop_core()
|
self.stop_core()
|
||||||
self.stop_backends(backend_classes)
|
self.stop_backends(backend_classes)
|
||||||
self.stop_audio()
|
self.stop_audio()
|
||||||
self.stop_mixer(mixer_class)
|
if mixer_class is not None:
|
||||||
|
self.stop_mixer(mixer_class)
|
||||||
process.stop_remaining_actors()
|
process.stop_remaining_actors()
|
||||||
return exit_status_code
|
return exit_status_code
|
||||||
|
|
||||||
@ -306,13 +309,18 @@ class RootCommand(Command):
|
|||||||
'Available Mopidy mixers: %s',
|
'Available Mopidy mixers: %s',
|
||||||
', '.join(m.__name__ for m in mixer_classes) or 'none')
|
', '.join(m.__name__ for m in mixer_classes) or 'none')
|
||||||
|
|
||||||
|
if config['audio']['mixer'] == 'none':
|
||||||
|
logger.debug('Mixer disabled')
|
||||||
|
return None
|
||||||
|
|
||||||
selected_mixers = [
|
selected_mixers = [
|
||||||
m for m in mixer_classes if m.name == config['audio']['mixer']]
|
m for m in mixer_classes if m.name == config['audio']['mixer']]
|
||||||
if len(selected_mixers) != 1:
|
if len(selected_mixers) != 1:
|
||||||
logger.error(
|
logger.error(
|
||||||
'Did not find unique mixer "%s". Alternatives are: %s',
|
'Did not find unique mixer "%s". Alternatives are: %s',
|
||||||
config['audio']['mixer'],
|
config['audio']['mixer'],
|
||||||
', '.join([m.name for m in mixer_classes]))
|
', '.join([m.name for m in mixer_classes]) + ', none' or
|
||||||
|
'none')
|
||||||
process.exit_process()
|
process.exit_process()
|
||||||
return selected_mixers[0]
|
return selected_mixers[0]
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,6 @@ class MixerController(object):
|
|||||||
|
|
||||||
def __init__(self, mixer):
|
def __init__(self, mixer):
|
||||||
self._mixer = mixer
|
self._mixer = mixer
|
||||||
self._volume = None
|
|
||||||
self._mute = False
|
|
||||||
|
|
||||||
def get_volume(self):
|
def get_volume(self):
|
||||||
"""Get the volume.
|
"""Get the volume.
|
||||||
@ -27,12 +25,15 @@ class MixerController(object):
|
|||||||
def set_volume(self, volume):
|
def set_volume(self, volume):
|
||||||
"""Set the volume.
|
"""Set the volume.
|
||||||
|
|
||||||
The volume is defined as an integer in range [0..100].
|
The volume is defined as an integer in range [0..100] or :class:`None`
|
||||||
|
if the mixer is disabled.
|
||||||
|
|
||||||
The volume scale is linear.
|
The volume scale is linear.
|
||||||
"""
|
"""
|
||||||
if self._mixer is not None:
|
if self._mixer is None:
|
||||||
self._mixer.set_volume(volume)
|
return False
|
||||||
|
else:
|
||||||
|
return self._mixer.set_volume(volume).get()
|
||||||
|
|
||||||
def get_mute(self):
|
def get_mute(self):
|
||||||
"""Get mute state.
|
"""Get mute state.
|
||||||
@ -40,13 +41,19 @@ class MixerController(object):
|
|||||||
:class:`True` if muted, :class:`False` unmuted, :class:`None` if
|
:class:`True` if muted, :class:`False` unmuted, :class:`None` if
|
||||||
unknown.
|
unknown.
|
||||||
"""
|
"""
|
||||||
if self._mixer is not None:
|
if self._mixer is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
return self._mixer.get_mute().get()
|
return self._mixer.get_mute().get()
|
||||||
|
|
||||||
def set_mute(self, mute):
|
def set_mute(self, mute):
|
||||||
"""Set mute state.
|
"""Set mute state.
|
||||||
|
|
||||||
:class:`True` to mute, :class:`False` to unmute.
|
:class:`True` to mute, :class:`False` to unmute.
|
||||||
|
|
||||||
|
Returns :class:`True` if call is successful, otherwise :class:`False`.
|
||||||
"""
|
"""
|
||||||
if self._mixer is not None:
|
if self._mixer is None:
|
||||||
self._mixer.set_mute(bool(mute))
|
return False
|
||||||
|
else:
|
||||||
|
return self._mixer.set_mute(bool(mute)).get()
|
||||||
|
|||||||
@ -13,7 +13,9 @@ def disableoutput(context, outputid):
|
|||||||
Turns an output off.
|
Turns an output off.
|
||||||
"""
|
"""
|
||||||
if outputid == 0:
|
if outputid == 0:
|
||||||
context.core.mixer.set_mute(False)
|
success = context.core.mixer.set_mute(False).get()
|
||||||
|
if success is False:
|
||||||
|
raise exceptions.MpdSystemError('problems disabling output')
|
||||||
else:
|
else:
|
||||||
raise exceptions.MpdNoExistError('No such audio output')
|
raise exceptions.MpdNoExistError('No such audio output')
|
||||||
|
|
||||||
@ -28,13 +30,14 @@ def enableoutput(context, outputid):
|
|||||||
Turns an output on.
|
Turns an output on.
|
||||||
"""
|
"""
|
||||||
if outputid == 0:
|
if outputid == 0:
|
||||||
context.core.mixer.set_mute(True)
|
success = context.core.mixer.set_mute(True).get()
|
||||||
|
if success is False:
|
||||||
|
raise exceptions.MpdSystemError('problems enabling output')
|
||||||
else:
|
else:
|
||||||
raise exceptions.MpdNoExistError('No such audio output')
|
raise exceptions.MpdNoExistError('No such audio output')
|
||||||
|
|
||||||
|
|
||||||
# TODO: implement and test
|
@protocol.commands.add('toggleoutput', outputid=protocol.UINT)
|
||||||
# @protocol.commands.add('toggleoutput', outputid=protocol.UINT)
|
|
||||||
def toggleoutput(context, outputid):
|
def toggleoutput(context, outputid):
|
||||||
"""
|
"""
|
||||||
*musicpd.org, audio output section:*
|
*musicpd.org, audio output section:*
|
||||||
@ -43,7 +46,13 @@ def toggleoutput(context, outputid):
|
|||||||
|
|
||||||
Turns an output on or off, depending on the current state.
|
Turns an output on or off, depending on the current state.
|
||||||
"""
|
"""
|
||||||
pass
|
if outputid == 0:
|
||||||
|
mute_status = context.core.mixer.get_mute().get()
|
||||||
|
success = context.core.mixer.set_mute(not mute_status)
|
||||||
|
if success is False:
|
||||||
|
raise exceptions.MpdSystemError('problems toggling output')
|
||||||
|
else:
|
||||||
|
raise exceptions.MpdNoExistError('No such audio output')
|
||||||
|
|
||||||
|
|
||||||
@protocol.commands.add('outputs')
|
@protocol.commands.add('outputs')
|
||||||
|
|||||||
@ -32,8 +32,7 @@ def crossfade(context, seconds):
|
|||||||
raise exceptions.MpdNotImplemented # TODO
|
raise exceptions.MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
|
||||||
# TODO: add at least reflection tests before adding NotImplemented version
|
@protocol.commands.add('mixrampdb')
|
||||||
# @protocol.commands.add('mixrampdb')
|
|
||||||
def mixrampdb(context, decibels):
|
def mixrampdb(context, decibels):
|
||||||
"""
|
"""
|
||||||
*musicpd.org, playback section:*
|
*musicpd.org, playback section:*
|
||||||
@ -46,11 +45,10 @@ def mixrampdb(context, decibels):
|
|||||||
volume so use negative values, I prefer -17dB. In the absence of mixramp
|
volume so use negative values, I prefer -17dB. In the absence of mixramp
|
||||||
tags crossfading will be used. See http://sourceforge.net/projects/mixramp
|
tags crossfading will be used. See http://sourceforge.net/projects/mixramp
|
||||||
"""
|
"""
|
||||||
pass
|
raise exceptions.MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
|
||||||
# TODO: add at least reflection tests before adding NotImplemented version
|
@protocol.commands.add('mixrampdelay', seconds=protocol.UINT)
|
||||||
# @protocol.commands.add('mixrampdelay', seconds=protocol.UINT)
|
|
||||||
def mixrampdelay(context, seconds):
|
def mixrampdelay(context, seconds):
|
||||||
"""
|
"""
|
||||||
*musicpd.org, playback section:*
|
*musicpd.org, playback section:*
|
||||||
@ -61,7 +59,7 @@ def mixrampdelay(context, seconds):
|
|||||||
value of "nan" disables MixRamp overlapping and falls back to
|
value of "nan" disables MixRamp overlapping and falls back to
|
||||||
crossfading.
|
crossfading.
|
||||||
"""
|
"""
|
||||||
pass
|
raise exceptions.MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
|
||||||
@protocol.commands.add('next')
|
@protocol.commands.add('next')
|
||||||
@ -397,7 +395,10 @@ def setvol(context, volume):
|
|||||||
- issues ``setvol 50`` without quotes around the argument.
|
- issues ``setvol 50`` without quotes around the argument.
|
||||||
"""
|
"""
|
||||||
# NOTE: we use INT as clients can pass in +N etc.
|
# NOTE: we use INT as clients can pass in +N etc.
|
||||||
context.core.mixer.set_volume(min(max(0, volume), 100))
|
value = min(max(0, volume), 100)
|
||||||
|
success = context.core.mixer.set_volume(value).get()
|
||||||
|
if success is False:
|
||||||
|
raise exceptions.MpdSystemError('problems setting volume')
|
||||||
|
|
||||||
|
|
||||||
@protocol.commands.add('single', state=protocol.BOOL)
|
@protocol.commands.add('single', state=protocol.BOOL)
|
||||||
|
|||||||
@ -57,3 +57,6 @@ class CoreListenerTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_listener_has_default_impl_for_seeked(self):
|
def test_listener_has_default_impl_for_seeked(self):
|
||||||
self.listener.seeked(0)
|
self.listener.seeked(0)
|
||||||
|
|
||||||
|
def test_listener_has_default_impl_for_current_metadata_changed(self):
|
||||||
|
self.listener.current_metadata_changed()
|
||||||
|
|||||||
@ -4,7 +4,10 @@ import unittest
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
import pykka
|
||||||
|
|
||||||
from mopidy import core, mixer
|
from mopidy import core, mixer
|
||||||
|
from tests import dummy_mixer
|
||||||
|
|
||||||
|
|
||||||
class CoreMixerTest(unittest.TestCase):
|
class CoreMixerTest(unittest.TestCase):
|
||||||
@ -33,3 +36,55 @@ class CoreMixerTest(unittest.TestCase):
|
|||||||
self.core.mixer.set_mute(True)
|
self.core.mixer.set_mute(True)
|
||||||
|
|
||||||
self.mixer.set_mute.assert_called_once_with(True)
|
self.mixer.set_mute.assert_called_once_with(True)
|
||||||
|
|
||||||
|
|
||||||
|
class CoreNoneMixerTest(unittest.TestCase):
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
self.core = core.Core(mixer=None, backends=[])
|
||||||
|
|
||||||
|
def test_get_volume_return_none(self):
|
||||||
|
self.assertEqual(self.core.mixer.get_volume(), None)
|
||||||
|
|
||||||
|
def test_set_volume_return_false(self):
|
||||||
|
self.assertEqual(self.core.mixer.set_volume(30), False)
|
||||||
|
|
||||||
|
def test_get_set_mute_return_proper_state(self):
|
||||||
|
self.assertEqual(self.core.mixer.set_mute(False), False)
|
||||||
|
self.assertEqual(self.core.mixer.get_mute(), False)
|
||||||
|
self.assertEqual(self.core.mixer.set_mute(True), False)
|
||||||
|
self.assertEqual(self.core.mixer.get_mute(), False)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(mixer.MixerListener, 'send')
|
||||||
|
class CoreMixerListenerTest(unittest.TestCase):
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
self.mixer = dummy_mixer.create_proxy()
|
||||||
|
self.core = core.Core(mixer=self.mixer, backends=[])
|
||||||
|
|
||||||
|
def tearDown(self): # noqa: N802
|
||||||
|
pykka.ActorRegistry.stop_all()
|
||||||
|
|
||||||
|
def test_forwards_mixer_volume_changed_event_to_frontends(self, send):
|
||||||
|
self.assertEqual(self.core.mixer.set_volume(volume=60), True)
|
||||||
|
self.assertEqual(send.call_args[0][0], 'volume_changed')
|
||||||
|
self.assertEqual(send.call_args[1]['volume'], 60)
|
||||||
|
|
||||||
|
def test_forwards_mixer_mute_changed_event_to_frontends(self, send):
|
||||||
|
self.core.mixer.set_mute(mute=True)
|
||||||
|
|
||||||
|
self.assertEqual(send.call_args[0][0], 'mute_changed')
|
||||||
|
self.assertEqual(send.call_args[1]['mute'], True)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(mixer.MixerListener, 'send')
|
||||||
|
class CoreNoneMixerListenerTest(unittest.TestCase):
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
self.core = core.Core(mixer=None, backends=[])
|
||||||
|
|
||||||
|
def test_forwards_mixer_volume_changed_event_to_frontends(self, send):
|
||||||
|
self.assertEqual(self.core.mixer.set_volume(volume=60), False)
|
||||||
|
self.assertEqual(send.call_count, 0)
|
||||||
|
|
||||||
|
def test_forwards_mixer_mute_changed_event_to_frontends(self, send):
|
||||||
|
self.core.mixer.set_mute(mute=True)
|
||||||
|
self.assertEqual(send.call_count, 0)
|
||||||
|
|||||||
@ -21,9 +21,13 @@ class DummyMixer(pykka.ThreadingActor, mixer.Mixer):
|
|||||||
|
|
||||||
def set_volume(self, volume):
|
def set_volume(self, volume):
|
||||||
self._volume = volume
|
self._volume = volume
|
||||||
|
self.trigger_volume_changed(volume=volume)
|
||||||
|
return True
|
||||||
|
|
||||||
def get_mute(self):
|
def get_mute(self):
|
||||||
return self._mute
|
return self._mute
|
||||||
|
|
||||||
def set_mute(self, mute):
|
def set_mute(self, mute):
|
||||||
self._mute = mute
|
self._mute = mute
|
||||||
|
self.trigger_mute_changed(mute=mute)
|
||||||
|
return True
|
||||||
|
|||||||
@ -25,6 +25,8 @@ class MockConnection(mock.Mock):
|
|||||||
|
|
||||||
|
|
||||||
class BaseTestCase(unittest.TestCase):
|
class BaseTestCase(unittest.TestCase):
|
||||||
|
enable_mixer = True
|
||||||
|
|
||||||
def get_config(self):
|
def get_config(self):
|
||||||
return {
|
return {
|
||||||
'mpd': {
|
'mpd': {
|
||||||
@ -33,7 +35,10 @@ class BaseTestCase(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def setUp(self): # noqa: N802
|
def setUp(self): # noqa: N802
|
||||||
self.mixer = dummy_mixer.create_proxy()
|
if self.enable_mixer:
|
||||||
|
self.mixer = dummy_mixer.create_proxy()
|
||||||
|
else:
|
||||||
|
self.mixer = None
|
||||||
self.backend = dummy_backend.create_proxy()
|
self.backend = dummy_backend.create_proxy()
|
||||||
self.core = core.Core.start(
|
self.core = core.Core.start(
|
||||||
mixer=self.mixer, backends=[self.backend]).proxy()
|
mixer=self.mixer, backends=[self.backend]).proxy()
|
||||||
|
|||||||
@ -4,6 +4,7 @@ from tests.mpd import protocol
|
|||||||
|
|
||||||
|
|
||||||
class AudioOutputHandlerTest(protocol.BaseTestCase):
|
class AudioOutputHandlerTest(protocol.BaseTestCase):
|
||||||
|
|
||||||
def test_enableoutput(self):
|
def test_enableoutput(self):
|
||||||
self.core.mixer.set_mute(False)
|
self.core.mixer.set_mute(False)
|
||||||
|
|
||||||
@ -50,3 +51,95 @@ class AudioOutputHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('outputname: Mute')
|
self.assertInResponse('outputname: Mute')
|
||||||
self.assertInResponse('outputenabled: 1')
|
self.assertInResponse('outputenabled: 1')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_outputs_toggleoutput(self):
|
||||||
|
self.core.mixer.set_mute(False)
|
||||||
|
|
||||||
|
self.send_request('toggleoutput "0"')
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 1')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
self.send_request('toggleoutput "0"')
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 0')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
self.send_request('toggleoutput "0"')
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 1')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_outputs_toggleoutput_unknown_outputid(self):
|
||||||
|
self.send_request('toggleoutput "7"')
|
||||||
|
|
||||||
|
self.assertInResponse(
|
||||||
|
'ACK [50@0] {toggleoutput} No such audio output')
|
||||||
|
|
||||||
|
|
||||||
|
class AudioOutputHandlerNoneMixerTest(protocol.BaseTestCase):
|
||||||
|
enable_mixer = False
|
||||||
|
|
||||||
|
def test_enableoutput(self):
|
||||||
|
self.core.mixer.set_mute(False)
|
||||||
|
|
||||||
|
self.send_request('enableoutput "0"')
|
||||||
|
self.assertInResponse(
|
||||||
|
'ACK [52@0] {enableoutput} problems enabling output')
|
||||||
|
self.assertEqual(self.core.mixer.get_mute().get(), False)
|
||||||
|
|
||||||
|
def test_disableoutput(self):
|
||||||
|
self.core.mixer.set_mute(True)
|
||||||
|
|
||||||
|
self.send_request('disableoutput "0"')
|
||||||
|
self.assertInResponse(
|
||||||
|
'ACK [52@0] {disableoutput} problems disabling output')
|
||||||
|
self.assertEqual(self.core.mixer.get_mute().get(), False)
|
||||||
|
|
||||||
|
def test_outputs_when_unmuted(self):
|
||||||
|
self.core.mixer.set_mute(False)
|
||||||
|
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 0')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_outputs_when_muted(self):
|
||||||
|
self.core.mixer.set_mute(True)
|
||||||
|
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 0')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_outputs_toggleoutput(self):
|
||||||
|
self.core.mixer.set_mute(False)
|
||||||
|
|
||||||
|
self.send_request('toggleoutput "0"')
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 0')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
self.send_request('toggleoutput "0"')
|
||||||
|
self.send_request('outputs')
|
||||||
|
|
||||||
|
self.assertInResponse('outputid: 0')
|
||||||
|
self.assertInResponse('outputname: Mute')
|
||||||
|
self.assertInResponse('outputenabled: 0')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|||||||
@ -50,6 +50,12 @@ class IdleHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertNoEvents()
|
self.assertNoEvents()
|
||||||
self.assertNoResponse()
|
self.assertNoResponse()
|
||||||
|
|
||||||
|
def test_idle_output(self):
|
||||||
|
self.send_request('idle output')
|
||||||
|
self.assertEqualSubscriptions(['output'])
|
||||||
|
self.assertNoEvents()
|
||||||
|
self.assertNoResponse()
|
||||||
|
|
||||||
def test_idle_player_playlist(self):
|
def test_idle_player_playlist(self):
|
||||||
self.send_request('idle player playlist')
|
self.send_request('idle player playlist')
|
||||||
self.assertEqualSubscriptions(['player', 'playlist'])
|
self.assertEqualSubscriptions(['player', 'playlist'])
|
||||||
@ -102,6 +108,22 @@ class IdleHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertOnceInResponse('changed: player')
|
self.assertOnceInResponse('changed: player')
|
||||||
self.assertOnceInResponse('OK')
|
self.assertOnceInResponse('OK')
|
||||||
|
|
||||||
|
def test_idle_then_output(self):
|
||||||
|
self.send_request('idle')
|
||||||
|
self.idle_event('output')
|
||||||
|
self.assertNoSubscriptions()
|
||||||
|
self.assertNoEvents()
|
||||||
|
self.assertOnceInResponse('changed: output')
|
||||||
|
self.assertOnceInResponse('OK')
|
||||||
|
|
||||||
|
def test_idle_output_then_event_output(self):
|
||||||
|
self.send_request('idle output')
|
||||||
|
self.idle_event('output')
|
||||||
|
self.assertNoSubscriptions()
|
||||||
|
self.assertNoEvents()
|
||||||
|
self.assertOnceInResponse('changed: output')
|
||||||
|
self.assertOnceInResponse('OK')
|
||||||
|
|
||||||
def test_idle_player_then_noidle(self):
|
def test_idle_player_then_noidle(self):
|
||||||
self.send_request('idle player')
|
self.send_request('idle player')
|
||||||
self.send_request('noidle')
|
self.send_request('noidle')
|
||||||
@ -206,3 +228,11 @@ class IdleHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertNotInResponse('changed: player')
|
self.assertNotInResponse('changed: player')
|
||||||
self.assertOnceInResponse('changed: playlist')
|
self.assertOnceInResponse('changed: playlist')
|
||||||
self.assertOnceInResponse('OK')
|
self.assertOnceInResponse('OK')
|
||||||
|
|
||||||
|
def test_output_then_idle_toggleoutput(self):
|
||||||
|
self.idle_event('output')
|
||||||
|
self.send_request('idle output')
|
||||||
|
self.assertNoEvents()
|
||||||
|
self.assertNoSubscriptions()
|
||||||
|
self.assertOnceInResponse('changed: output')
|
||||||
|
self.assertOnceInResponse('OK')
|
||||||
|
|||||||
@ -150,6 +150,14 @@ class PlaybackOptionsHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
self.assertInResponse('off')
|
self.assertInResponse('off')
|
||||||
|
|
||||||
|
def test_mixrampdb(self):
|
||||||
|
self.send_request('mixrampdb "10"')
|
||||||
|
self.assertInResponse('ACK [0@0] {mixrampdb} Not implemented')
|
||||||
|
|
||||||
|
def test_mixrampdelay(self):
|
||||||
|
self.send_request('mixrampdelay "10"')
|
||||||
|
self.assertInResponse('ACK [0@0] {mixrampdelay} Not implemented')
|
||||||
|
|
||||||
@unittest.SkipTest
|
@unittest.SkipTest
|
||||||
def test_replay_gain_status_off(self):
|
def test_replay_gain_status_off(self):
|
||||||
pass
|
pass
|
||||||
@ -463,3 +471,11 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.send_request('stop')
|
self.send_request('stop')
|
||||||
self.assertEqual(STOPPED, self.core.playback.state.get())
|
self.assertEqual(STOPPED, self.core.playback.state.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
|
||||||
|
class PlaybackOptionsHandlerNoneMixerTest(protocol.BaseTestCase):
|
||||||
|
enable_mixer = False
|
||||||
|
|
||||||
|
def test_setvol_max_error(self):
|
||||||
|
self.send_request('setvol "100"')
|
||||||
|
self.assertInResponse('ACK [52@0] {setvol} problems setting volume')
|
||||||
|
|||||||
@ -3,8 +3,8 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from mopidy.mpd.exceptions import (
|
from mopidy.mpd.exceptions import (
|
||||||
MpdAckError, MpdNoCommand, MpdNotImplemented, MpdPermissionError,
|
MpdAckError, MpdNoCommand, MpdNoExistError, MpdNotImplemented,
|
||||||
MpdSystemError, MpdUnknownCommand)
|
MpdPermissionError, MpdSystemError, MpdUnknownCommand)
|
||||||
|
|
||||||
|
|
||||||
class MpdExceptionsTest(unittest.TestCase):
|
class MpdExceptionsTest(unittest.TestCase):
|
||||||
@ -61,3 +61,11 @@ class MpdExceptionsTest(unittest.TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
e.get_mpd_ack(),
|
e.get_mpd_ack(),
|
||||||
'ACK [4@0] {foo} you don\'t have permission for "foo"')
|
'ACK [4@0] {foo} you don\'t have permission for "foo"')
|
||||||
|
|
||||||
|
def test_mpd_noexist_error(self):
|
||||||
|
try:
|
||||||
|
raise MpdNoExistError(command='foo')
|
||||||
|
except MpdNoExistError as e:
|
||||||
|
self.assertEqual(
|
||||||
|
e.get_mpd_ack(),
|
||||||
|
'ACK [50@0] {foo} ')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user