audio: Expand audio state changed with target state

This commit is contained in:
Thomas Adamcik 2014-06-21 17:28:25 +02:00
parent 168aa432aa
commit 7975815cde
4 changed files with 33 additions and 16 deletions

View File

@ -23,6 +23,10 @@ mixers.register_mixers()
playlists.register_typefinders()
playlists.register_elements()
_GST_STATE_MAPPING = {
gst.STATE_PLAYING: PlaybackState.PLAYING,
gst.STATE_PAUSED: PlaybackState.PAUSED,
gst.STATE_NULL: PlaybackState.STOPPED}
MB = 1 << 20
@ -321,20 +325,18 @@ class Audio(pykka.ThreadingActor):
if new_state == gst.STATE_READY:
return # Ignore READY state as it's GStreamer specific
if new_state == gst.STATE_PLAYING:
new_state = PlaybackState.PLAYING
elif new_state == gst.STATE_PAUSED:
new_state = PlaybackState.PAUSED
elif new_state == gst.STATE_NULL:
new_state = PlaybackState.STOPPED
new_state = _GST_STATE_MAPPING[new_state]
old_state, self.state = self.state, new_state
target_state = _GST_STATE_MAPPING[self._target_state]
if target_state == new_state:
target_state = None
logger.debug(
'Triggering event: state_changed(old_state=%s, new_state=%s)',
old_state, new_state)
AudioListener.send(
'state_changed', old_state=old_state, new_state=new_state)
'Triggering event: state_changed(old_state=%s, new_state=%s, '
'target_state=%s)', old_state, new_state, target_state)
AudioListener.send('state_changed', old_state=old_state,
new_state=new_state, target_state=target_state)
def _on_buffering(self, percent):
if percent < 10 and not self._buffering:

View File

@ -27,17 +27,31 @@ class AudioListener(listener.Listener):
"""
pass
def state_changed(self, old_state, new_state):
def state_changed(self, old_state, new_state, target_state):
"""
Called after the playback state have changed.
Will be called for both immediate and async state changes in GStreamer.
Target state is used to when we should be in the target state, but
temporarily need to switch to an other state. A typical example of this
is buffering. When this happens an event with
`old=PLAYING, new=PAUSED, target=PLAYING` will be emitted. Once we have
caught up a `old=PAUSED, new=PLAYING, target=None` event will be
be generated.
Regular state changes will not have target state set as they are final
states which should be stable.
*MAY* be implemented by actor.
:param old_state: the state before the change
:type old_state: string from :class:`mopidy.core.PlaybackState` field
:param new_state: the state after the change
:type new_state: A :class:`mopidy.core.PlaybackState` field
:type new_state: string from :class:`mopidy.core.PlaybackState` field
:param target_state: the intended state
:type target_state: string from :class:`mopidy.core.PlaybackState`
field or :class:`None` if this is a final state.
"""
pass

View File

@ -65,7 +65,7 @@ class Core(pykka.ThreadingActor, audio.AudioListener, backend.BackendListener):
def reached_end_of_stream(self):
self.playback.on_end_of_track()
def state_changed(self, old_state, new_state):
def state_changed(self, old_state, new_state, target_state):
# XXX: This is a temporary fix for issue #232 while we wait for a more
# permanent solution with the implementation of issue #234. When the
# Spotify play token is lost, the Spotify backend pauses audio

View File

@ -15,13 +15,14 @@ class AudioListenerTest(unittest.TestCase):
self.listener.state_changed = mock.Mock()
self.listener.on_event(
'state_changed', old_state='stopped', new_state='playing')
'state_changed', old_state='stopped', new_state='playing',
target_state=None)
self.listener.state_changed.assert_called_with(
old_state='stopped', new_state='playing')
old_state='stopped', new_state='playing', target_state=None)
def test_listener_has_default_impl_for_reached_end_of_stream(self):
self.listener.reached_end_of_stream()
def test_listener_has_default_impl_for_state_changed(self):
self.listener.state_changed(None, None)
self.listener.state_changed(None, None, None)