Refactor BaseOutput to prepare for better error handling

This commit is contained in:
Thomas Adamcik 2011-05-16 21:08:01 +02:00
parent 3f35e9b391
commit 09a1d646f2
3 changed files with 32 additions and 26 deletions

View File

@ -40,7 +40,7 @@ class GStreamer(ThreadingActor):
self._tee = None
self._uridecodebin = None
self._volume = None
self._outputs = {}
self._outputs = []
def on_start(self):
self._setup_gstreamer()
@ -71,7 +71,7 @@ class GStreamer(ThreadingActor):
self._pipeline.get_by_name('convert').get_pad('sink'))
for output in settings.OUTPUTS:
self.connect_output(get_class(output))
get_class(output)(self).connect()
# Setup bus and message processor
bus = self._pipeline.get_bus()
@ -263,37 +263,34 @@ class GStreamer(ThreadingActor):
logger.debug('Setting tags to: %s', tags)
self._taginject.set_property('tags', tags)
def connect_output(self, cls):
def connect_output(self, output):
"""
Connect output to pipeline.
:param output: output to connect to our pipeline.
:type output: :class:`BaseOutput`
:type output: :class:`gst.Bin`
"""
output = cls().get_bin()
self._pipeline.add(output)
output.sync_state_with_parent() # Required to add to running pipe
gst.element_link_many(self._tee, output)
self._outputs[output.get_name()] = output
self._outputs.append(output)
logger.info('Added %s', output.get_name())
def list_outputs(self):
return self._outputs.keys()
def remove_output(self, name):
def remove_output(self, output):
logger.debug('Trying to remove %s', output.get_name())
if name not in self._outputs:
return # FIXME raise mopidy exception of some sort?
src = self._taginject.get_pad('src')
src.set_blocked_async(True, self._blocked_callback, name)
src.set_blocked_async(True, self._blocked_callback, output)
def _blocked_callback(self, pad, blocked, name):
output = self._outputs.pop(name)
def _blocked_callback(self, pad, blocked, output):
gst.element_unlink_many(self._tee, output)
output.set_state(gst.STATE_NULL)
self._pipeline.remove(output)
self._outputs.remove(output)
pad.set_blocked(False)
logger.warning(u'Removed %s', name)
logger.warning(u'Removed %s', output.get_name())

View File

@ -9,18 +9,29 @@ logger = logging.getLogger('mopidy.outputs')
class BaseOutput(object):
"""Base class for providing support for multiple pluggable outputs."""
def get_bin(self):
def __init__(self, gstreamer):
self.gstreamer = gstreamer
self.bin = self.build_bin()
self.bin.set_name(self.get_name())
self.modify_bin()
def build_bin(self):
"""
Build output bin that will attached to pipeline.
"""
description = 'queue ! %s' % self.describe_bin()
logger.debug('Creating new output: %s', description)
output = gst.parse_bin_from_description(description, True)
output.set_name(self.get_name())
self.modify_bin(output)
return gst.parse_bin_from_description(description, True)
return output
def connect(self):
"""Convenience wrapper to attach output to GStreamer pipeline"""
self.gstreamer.connect_output(self.bin)
def remove(self):
"""Convenience wrapper to remove output from GStreamer pipeline"""
self.gstreamer.remove_output(self.bin)
def get_name(self):
"""
@ -30,16 +41,13 @@ class BaseOutput(object):
"""
return self.__class__.__name__
def modify_bin(self, output):
def modify_bin(self):
"""
Modifies bin before it is installed if needed.
Modifies ``self.bin`` before it is installed if needed.
Overriding this method allows for outputs to modify the constructed bin
before it is installed. This can for instance be a good place to call
`set_properties` on elements that need to be configured.
:param output: gst.Bin to modify in some way.
:type output: :class:`gst.Bin`
"""
pass

View File

@ -15,8 +15,9 @@ class ShoutcastOutput(BaseOutput):
return 'audioconvert ! %s ! shout2send name=shoutcast' \
% settings.SHOUTCAST_OUTPUT_ENCODER
def modify_bin(self, output):
self.set_properties(output.get_by_name('shoutcast'), {
def modify_bin(self):
shoutcast = self.bin.get_by_name('shoutcast')
self.set_properties(shoutcast, {
u'ip': settings.SHOUTCAST_OUTPUT_SERVER,
u'mount': settings.SHOUTCAST_OUTPUT_MOUNT,
u'port': settings.SHOUTCAST_OUTPUT_PORT,