Add AudioListener for events from the audio actor

This is analogous to how the core actor sends events to the frontends. This
removes the audio actor's direct dependency on the core actor, which
conceptually is on a higher layer.
This commit is contained in:
Stein Magnus Jodal 2012-09-27 23:17:57 +02:00
parent 8c78d469e2
commit 4b13f46e2e
4 changed files with 51 additions and 16 deletions

View File

@ -10,10 +10,17 @@ the URI of the resource they want to play, for these cases the default playback
provider should be used.
For more advanced cases such as when the raw audio data is delivered outside of
GStreamer or the backend needs to add metadata to the currently playing resource,
developers should sub-class the base playback provider and implement the extra
behaviour that is needed through the following API:
GStreamer or the backend needs to add metadata to the currently playing
resource, developers should sub-class the base playback provider and implement
the extra behaviour that is needed through the following API:
.. autoclass:: mopidy.audio.Audio
:members:
Audio listener
==============
.. autoclass:: mopidy.audio.AudioListener
:members:

View File

@ -6,13 +6,13 @@ import gobject
import logging
from pykka.actor import ThreadingActor
from pykka.registry import ActorRegistry
from mopidy import core, settings, utils
from mopidy import settings, utils
from mopidy.utils import process
# Trigger install of gst mixer plugins
from mopidy.audio import mixers
from . import mixers
from .listener import AudioListener
logger = logging.getLogger('mopidy.audio')
@ -149,7 +149,7 @@ class Audio(ThreadingActor):
def _on_message(self, bus, message):
if message.type == gst.MESSAGE_EOS:
self._notify_core_of_eos()
self._trigger_reached_end_of_stream_event()
elif message.type == gst.MESSAGE_ERROR:
error, debug = message.parse_error()
logger.error(u'%s %s', error, debug)
@ -158,14 +158,9 @@ class Audio(ThreadingActor):
error, debug = message.parse_warning()
logger.warning(u'%s %s', error, debug)
def _notify_core_of_eos(self):
core_refs = ActorRegistry.get_by_class(core.Core)
assert len(core_refs) <= 1, 'Expected at most one running core instance'
if core_refs:
logger.debug(u'Notifying core of end-of-stream')
core_refs[0].proxy().playback.on_end_of_track()
else:
logger.debug(u'No core instance to notify of end-of-stream found')
def _trigger_reached_end_of_stream_event(self):
logger.debug(u'Triggering reached end of stream event')
AudioListener.send('reached_end_of_stream')
def set_uri(self, uri):
"""

28
mopidy/audio/listener.py Normal file
View File

@ -0,0 +1,28 @@
from pykka.registry import ActorRegistry
class AudioListener(object):
"""
Marker interface for recipients of events sent by the audio actor.
Any Pykka actor that mixes in this class will receive calls to the methods
defined here when the corresponding events happen in the core actor. This
interface is used both for looking up what actors to notify of the events,
and for providing default implementations for those listeners that are not
interested in all events.
"""
@staticmethod
def send(event, **kwargs):
"""Helper to allow calling of audio listener events"""
listeners = ActorRegistry.get_by_class(AudioListener)
for listener in listeners:
getattr(listener.proxy(), event)(**kwargs)
def reached_end_of_stream(self):
"""
Called whenever the end of the audio stream is reached.
*MAY* be implemented by actor.
"""
pass

View File

@ -1,12 +1,14 @@
from pykka.actor import ThreadingActor
from mopidy import audio
from .current_playlist import CurrentPlaylistController
from .library import LibraryController
from .playback import PlaybackController
from .stored_playlists import StoredPlaylistsController
class Core(ThreadingActor):
class Core(ThreadingActor, audio.AudioListener):
#: The current playlist controller. An instance of
#: :class:`mopidy.core.CurrentPlaylistController`.
current_playlist = None
@ -40,3 +42,6 @@ class Core(ThreadingActor):
def uri_schemes(self):
"""List of URI schemes we can handle"""
return self._backend.uri_schemes.get()
def reached_end_of_stream(self):
self.playback.on_end_of_track()