Move optional wall clock-based position tracking down to the playback provider

This commit is contained in:
Stein Magnus Jodal 2012-09-25 12:10:25 +02:00
parent ef17e36a1a
commit 2237e4f5a1
3 changed files with 58 additions and 44 deletions

View File

@ -1,3 +1,8 @@
import time
from mopidy.core.playback import PlaybackState
class BasePlaybackProvider(object):
"""
:param backend: the backend
@ -9,6 +14,9 @@ class BasePlaybackProvider(object):
def __init__(self, backend):
self.backend = backend
self._play_time_accumulated = 0
self._play_time_started = 0
def pause(self):
"""
Pause playback.
@ -95,3 +103,40 @@ class BasePlaybackProvider(object):
:type volume: int [0..100]
"""
self.backend.audio.set_volume(volume)
def wall_clock_based_time_position(self):
"""
Helper method that tracks track time position using the wall clock.
To use this helper you must call the helper from your implementation of
:meth:`get_time_position` and return its return value.
:rtype: int
"""
state = self.backend.playback.state
if state == PlaybackState.PLAYING:
time_since_started = (self._wall_time() -
self._play_time_started)
return self._play_time_accumulated + time_since_started
elif state == PlaybackState.PAUSED:
return self._play_time_accumulated
elif state == PlaybackState.STOPPED:
return 0
def update_play_time_on_play(self):
self._play_time_accumulated = 0
self._play_time_started = self._wall_time()
def update_play_time_on_pause(self):
time_since_started = self._wall_time() - self._play_time_started
self._play_time_accumulated += time_since_started
def update_play_time_on_resume(self):
self._play_time_started = self._wall_time()
def update_play_time_on_seek(self, time_position):
self._play_time_started = self._wall_time()
self._play_time_accumulated = time_position
def _wall_time(self):
return int(time.time() * 1000)

View File

@ -5,8 +5,10 @@ from spotify import Link, SpotifyError
from mopidy.backends.base import BasePlaybackProvider
from mopidy.core import PlaybackState
logger = logging.getLogger('mopidy.backends.spotify.playback')
class SpotifyPlaybackProvider(BasePlaybackProvider):
def play(self, track):
if self.backend.playback.state == PlaybackState.PLAYING:
@ -38,3 +40,10 @@ class SpotifyPlaybackProvider(BasePlaybackProvider):
def stop(self):
self.backend.spotify.session.play(0)
return super(SpotifyPlaybackProvider, self).stop()
def get_time_position(self):
# XXX: The default implementation of get_time_position hangs/times out
# when used with the Spotify backend and GStreamer appsrc. If this can
# be resolved, we no longer need to use a wall clock based time
# position for Spotify playback.
return self.wall_clock_based_time_position()

View File

@ -1,6 +1,5 @@
import logging
import random
import time
from mopidy.listeners import BackendListener
@ -20,7 +19,6 @@ def option_wrapper(name, default):
return property(get_option, set_option)
class PlaybackState(object):
"""
Enum of playback states.
@ -87,8 +85,6 @@ class PlaybackController(object):
self._state = PlaybackState.STOPPED
self._shuffled = []
self._first_shuffle = True
self.play_time_accumulated = 0
self.play_time_started = 0
def _get_cpid(self, cp_track):
if cp_track is None:
@ -292,48 +288,11 @@ class PlaybackController(object):
self._trigger_playback_state_changed(old_state, new_state)
# FIXME play_time stuff assumes backend does not have a better way of
# handeling this stuff :/
if (old_state in (PlaybackState.PLAYING, PlaybackState.STOPPED)
and new_state == PlaybackState.PLAYING):
self._play_time_start()
elif (old_state == PlaybackState.PLAYING
and new_state == PlaybackState.PAUSED):
self._play_time_pause()
elif (old_state == PlaybackState.PAUSED
and new_state == PlaybackState.PLAYING):
self._play_time_resume()
@property
def time_position(self):
"""Time position in milliseconds."""
return self.provider.get_time_position()
def _wall_clock_based_time_position():
if self.state == PlaybackState.PLAYING:
time_since_started = (self._current_wall_time -
self.play_time_started)
return self.play_time_accumulated + time_since_started
elif self.state == PlaybackState.PAUSED:
return self.play_time_accumulated
elif self.state == PlaybackState.STOPPED:
return 0
def _play_time_start(self):
self.play_time_accumulated = 0
self.play_time_started = self._current_wall_time
def _play_time_pause(self):
time_since_started = self._current_wall_time - self.play_time_started
self.play_time_accumulated += time_since_started
def _play_time_resume(self):
self.play_time_started = self._current_wall_time
@property
def _current_wall_time(self):
return int(time.time() * 1000)
@property
def volume(self):
return self.provider.get_volume()
@ -411,6 +370,7 @@ class PlaybackController(object):
"""Pause playback."""
if self.provider.pause():
self.state = PlaybackState.PAUSED
self.provider.update_play_time_on_pause()
self._trigger_track_playback_paused()
def play(self, cp_track=None, on_error_step=1):
@ -453,6 +413,7 @@ class PlaybackController(object):
if self.random and self.current_cp_track in self._shuffled:
self._shuffled.remove(self.current_cp_track)
self.provider.update_play_time_on_play()
self._trigger_track_playback_started()
def previous(self):
@ -469,6 +430,7 @@ class PlaybackController(object):
"""If paused, resume playing the current track."""
if self.state == PlaybackState.PAUSED and self.provider.resume():
self.state = PlaybackState.PLAYING
self.provider.update_play_time_on_resume()
self._trigger_track_playback_resumed()
def seek(self, time_position):
@ -493,11 +455,9 @@ class PlaybackController(object):
self.next()
return True
self.play_time_started = self._current_wall_time
self.play_time_accumulated = time_position
success = self.provider.seek(time_position)
if success:
self.provider.update_play_time_on_seek(time_position)
self._trigger_seeked(time_position)
return success