diff --git a/docs/api/outputs.rst b/docs/api/outputs.rst index 5ef1606d..0650563e 100644 --- a/docs/api/outputs.rst +++ b/docs/api/outputs.rst @@ -17,4 +17,5 @@ Outputs are responsible for playing audio. Output implementations ====================== +* :mod:`mopidy.outputs.dummy` * :mod:`mopidy.outputs.gstreamer` diff --git a/docs/modules/outputs/dummy.rst b/docs/modules/outputs/dummy.rst new file mode 100644 index 00000000..56436c94 --- /dev/null +++ b/docs/modules/outputs/dummy.rst @@ -0,0 +1,10 @@ +******************************************************* +:mod:`mopidy.outputs.dummy` -- Dummy output for testing +******************************************************* + +.. inheritance-diagram:: mopidy.outputs.dummy + +.. automodule:: mopidy.outputs.dummy + :synopsis: Dummy output for testing + :members: + :undoc-members: diff --git a/mopidy/backends/base/playback.py b/mopidy/backends/base/playback.py index 88ae141d..88aa0877 100644 --- a/mopidy/backends/base/playback.py +++ b/mopidy/backends/base/playback.py @@ -5,6 +5,7 @@ import time from pykka.registry import ActorRegistry from mopidy.frontends.base import BaseFrontend +from mopidy.outputs.base import BaseOutput logger = logging.getLogger('mopidy.backends.base') @@ -288,6 +289,9 @@ class PlaybackController(object): @property def time_position(self): """Time position in milliseconds.""" + output_position = self._time_position_from_output() + if output_position is not None: + return output_position if self.state == self.PLAYING: time_since_started = (self._current_wall_time - self.play_time_started) @@ -297,6 +301,13 @@ class PlaybackController(object): elif self.state == self.STOPPED: return 0 + def _time_position_from_output(self): + output_refs = ActorRegistry.get_by_class(BaseOutput) + if not output_refs: + return None + output = output_refs[0].proxy() + return output.get_position() + def _play_time_start(self): self.play_time_accumulated = 0 self.play_time_started = self._current_wall_time diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index 2fa96dab..fc7f170c 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -41,7 +41,7 @@ class LocalBackend(ThreadingActor, Backend): provider=library_provider) playback_provider = LocalPlaybackProvider(backend=self) - self.playback = LocalPlaybackController(backend=self, + self.playback = PlaybackController(backend=self, provider=playback_provider) stored_playlists_provider = LocalStoredPlaylistsProvider(backend=self) @@ -58,18 +58,6 @@ class LocalBackend(ThreadingActor, Backend): self.output = output_refs[0].proxy() -class LocalPlaybackController(PlaybackController): - def __init__(self, *args, **kwargs): - super(LocalPlaybackController, self).__init__(*args, **kwargs) - - # XXX Why do we call stop()? Is it to set GStreamer state to 'READY'? - self.stop() - - @property - def time_position(self): - return self.backend.output.get_position().get() - - class LocalPlaybackProvider(BasePlaybackProvider): def pause(self): return self.backend.output.set_state('PAUSED').get() diff --git a/mopidy/outputs/base.py b/mopidy/outputs/base.py index fbc86688..11c2f86e 100644 --- a/mopidy/outputs/base.py +++ b/mopidy/outputs/base.py @@ -40,7 +40,7 @@ class BaseOutput(object): *MUST be implemented by subclass.* - :rtype: int + :rtype: int or :class:`None` if unknown """ raise NotImplementedError diff --git a/mopidy/outputs/dummy.py b/mopidy/outputs/dummy.py index f09965f7..02f1bfca 100644 --- a/mopidy/outputs/dummy.py +++ b/mopidy/outputs/dummy.py @@ -25,7 +25,7 @@ class DummyOutput(ThreadingActor, BaseOutput): end_of_data_stream_called = False #: For testing. Contains the current position. - position = 0 + position = None #: For testing. Contains the current state. state = 'NULL' diff --git a/mopidy/outputs/gstreamer.py b/mopidy/outputs/gstreamer.py index 0596addb..d7ff6e6d 100644 --- a/mopidy/outputs/gstreamer.py +++ b/mopidy/outputs/gstreamer.py @@ -165,3 +165,18 @@ class GStreamerOutput(ThreadingActor, BaseOutput): gst_volume = self.gst_pipeline.get_by_name('volume') gst_volume.set_property('volume', volume / 100.0) return True + + def set_position(self, position): + self.gst_pipeline.get_state() # block until state changes are done + handeled = self.gst_pipeline.seek_simple(gst.Format(gst.FORMAT_TIME), + gst.SEEK_FLAG_FLUSH, position * gst.MSECOND) + self.gst_pipeline.get_state() # block until seek is done + return handeled + + def get_position(self): + try: + position = self.gst_pipeline.query_position(gst.FORMAT_TIME)[0] + return position // gst.MSECOND + except gst.QueryError, e: + logger.debug(u'GStreamer time position: %s', e) + return None diff --git a/tests/frontends/mpd/music_db_test.py b/tests/frontends/mpd/music_db_test.py index fa5634be..28469136 100644 --- a/tests/frontends/mpd/music_db_test.py +++ b/tests/frontends/mpd/music_db_test.py @@ -386,5 +386,3 @@ class MusicDatabaseSearchTest(unittest.TestCase): def test_search_else_should_fail(self): result = self.h.handle_request(u'search "sometype" "something"') self.assertEqual(result[0], u'ACK [2@0] {search} incorrect arguments') - -