diff --git a/docs/changes.rst b/docs/changes.rst index 2347ddb0..5d2ab57d 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -8,6 +8,10 @@ This change log is used to track all major changes to Mopidy. v0.6.0 (in development) ======================= +**Important changes** + +- Pykka 0.12.3 or greater is required. + **Changes** - Replace :attr:`mopidy.backends.base.Backend.uri_handlers` with diff --git a/docs/installation/index.rst b/docs/installation/index.rst index 5101cc84..198ac9e8 100644 --- a/docs/installation/index.rst +++ b/docs/installation/index.rst @@ -25,7 +25,7 @@ Otherwise, make sure you got the required dependencies installed. - Python >= 2.6, < 3 -- `Pykka `_ >= 0.12 +- `Pykka `_ >= 0.12.3 - GStreamer >= 0.10, with Python bindings. See :doc:`gstreamer`. diff --git a/mopidy/backends/base/playback.py b/mopidy/backends/base/playback.py index 07e286fa..088a5ad4 100644 --- a/mopidy/backends/base/playback.py +++ b/mopidy/backends/base/playback.py @@ -461,32 +461,30 @@ class PlaybackController(object): self.current_cp_track = None def _trigger_started_playing_event(self): - """ - Notifies implementors of :class:`mopidy.listeners.BackendListener` that - a track has started playing. - - For internal use only. Should be called by the backend directly after a - track has started playing. - """ + logger.debug(u'Triggering started playing event') if self.current_track is None: return - for listener_ref in ActorRegistry.get_by_class(BackendListener): - listener_ref.proxy().started_playing(track=self.current_track) + ActorRegistry.broadcast({ + 'command': 'pykka_call', + 'attr_path': ('started_playing',), + 'args': [], + 'kwargs': {'track': self.current_track}, + }, target_class=BackendListener) def _trigger_stopped_playing_event(self): - """ - Notifies implementors of :class:`mopidy.listeners.BackendListener` that - a track has stopped playing. - - For internal use only. Should be called by the backend before a track - is stopped playing, e.g. at the next, previous, and stop actions and at - end-of-track. - """ + # TODO Test that this is called on next/prev/end-of-track + logger.debug(u'Triggering stopped playing event') if self.current_track is None: return - for listener_ref in ActorRegistry.get_by_class(BackendListener): - listener_ref.proxy().stopped_playing( - track=self.current_track, stop_position=self.time_position) + ActorRegistry.broadcast({ + 'command': 'pykka_call', + 'attr_path': ('stopped_playing',), + 'args': [], + 'kwargs': { + 'track': self.current_track, + 'time_position': self.time_position, + }, + }, target_class=BackendListener) class BasePlaybackProvider(object): diff --git a/mopidy/listeners.py b/mopidy/listeners.py index f6d1c67e..dfc5c60b 100644 --- a/mopidy/listeners.py +++ b/mopidy/listeners.py @@ -20,7 +20,7 @@ class BackendListener(object): """ pass - def stopped_playing(self, track, stop_position): + def stopped_playing(self, track, time_position): """ Called whenever playback is stopped. @@ -28,7 +28,7 @@ class BackendListener(object): :param track: the track that was played before playback stopped :type track: :class:`mopidy.models.Track` - :param stop_position: the time position when stopped in milliseconds - :type stop_position: int + :param time_position: the time position in milliseconds + :type time_position: int """ pass diff --git a/requirements/core.txt b/requirements/core.txt index aaae84f8..8f9da622 100644 --- a/requirements/core.txt +++ b/requirements/core.txt @@ -1 +1 @@ -Pykka >= 0.12 +Pykka >= 0.12.3 diff --git a/tests/backends/events_test.py b/tests/backends/events_test.py new file mode 100644 index 00000000..44529e90 --- /dev/null +++ b/tests/backends/events_test.py @@ -0,0 +1,45 @@ +import threading +import unittest + +from pykka.actor import ThreadingActor +from pykka.registry import ActorRegistry + +from mopidy.backends.dummy import DummyBackend +from mopidy.listeners import BackendListener +from mopidy.models import Track + +class BackendEventsTest(unittest.TestCase): + def setUp(self): + self.events = { + 'started_playing': threading.Event(), + 'stopped_playing': threading.Event(), + } + self.backend = DummyBackend.start().proxy() + self.listener = DummyBackendListener.start(self.events).proxy() + + def tearDown(self): + ActorRegistry.stop_all() + + def test_play_sends_started_playing_event(self): + self.backend.current_playlist.add([Track(uri='a')]) + self.backend.playback.play() + self.events['started_playing'].wait(timeout=1) + self.assertTrue(self.events['started_playing'].is_set()) + + def test_stop_sends_stopped_playing_event(self): + self.backend.current_playlist.add([Track(uri='a')]) + self.backend.playback.play() + self.backend.playback.stop() + self.events['stopped_playing'].wait(timeout=1) + self.assertTrue(self.events['stopped_playing'].is_set()) + + +class DummyBackendListener(ThreadingActor, BackendListener): + def __init__(self, events): + self.events = events + + def started_playing(self, track): + self.events['started_playing'].set() + + def stopped_playing(self, track, time_position): + self.events['stopped_playing'].set()