Merge branch 'gstreamer', remote branch 'adamcik/gstreamer' into gstreamer
This commit is contained in:
commit
f448771027
@ -22,7 +22,10 @@ def main():
|
||||
get_or_create_folder('~/.mopidy/')
|
||||
core_queue = multiprocessing.Queue()
|
||||
get_class(settings.SERVER)(core_queue).start()
|
||||
core = CoreProcess(core_queue)
|
||||
output_class = get_class(settings.OUTPUT)
|
||||
backend_class = get_class(settings.BACKENDS[0])
|
||||
frontend_class = get_class(settings.FRONTEND)
|
||||
core = CoreProcess(core_queue, output_class, backend_class, frontend_class)
|
||||
core.start()
|
||||
asyncore.loop()
|
||||
|
||||
|
||||
@ -39,6 +39,8 @@ class GStreamerProcess(BaseProcess):
|
||||
http://jameswestby.net/weblog/tech/14-caution-python-multiprocessing-and-glib-dont-mix.html.
|
||||
"""
|
||||
|
||||
pipeline_description = 'appsrc name=data ! volume name=volume ! autoaudiosink name=sink'
|
||||
|
||||
def __init__(self, core_queue, output_queue):
|
||||
super(GStreamerProcess, self).__init__()
|
||||
self.core_queue = core_queue
|
||||
@ -65,8 +67,10 @@ class GStreamerProcess(BaseProcess):
|
||||
messages_thread.daemon = True
|
||||
messages_thread.start()
|
||||
|
||||
# A pipeline consisting of many elements
|
||||
self.gst_pipeline = gst.Pipeline("pipeline")
|
||||
self.gst_pipeline = gst.parse_launch(self.pipeline_description)
|
||||
self.gst_data_src = self.gst_pipeline.get_by_name('data')
|
||||
self.gst_volume = self.gst_pipeline.get_by_name('volume')
|
||||
self.gst_sink = self.gst_pipeline.get_by_name('sink')
|
||||
|
||||
# Setup bus and message processor
|
||||
self.gst_bus = self.gst_pipeline.get_bus()
|
||||
@ -74,42 +78,6 @@ class GStreamerProcess(BaseProcess):
|
||||
self.gst_bus_id = self.gst_bus.connect('message',
|
||||
self.process_gst_message)
|
||||
|
||||
# Bin for playing audio URIs
|
||||
#self.gst_uri_src = gst.element_factory_make('uridecodebin', 'uri_src')
|
||||
#self.gst_pipeline.add(self.gst_uri_src)
|
||||
|
||||
# Bin for playing audio data
|
||||
self.gst_data_src = gst.element_factory_make('appsrc', 'data_src')
|
||||
self.gst_pipeline.add(self.gst_data_src)
|
||||
|
||||
# Volume filter
|
||||
self.gst_volume = gst.element_factory_make('volume', 'volume')
|
||||
self.gst_pipeline.add(self.gst_volume)
|
||||
|
||||
# Audio output sink
|
||||
self.gst_sink = gst.element_factory_make('autoaudiosink', 'sink')
|
||||
self.gst_pipeline.add(self.gst_sink)
|
||||
|
||||
# Add callback that will link uri_src output with volume filter input
|
||||
# when the output pad is ready.
|
||||
# See http://stackoverflow.com/questions/2993777 for details.
|
||||
def on_new_decoded_pad(dbin, pad, is_last):
|
||||
uri_src = pad.get_parent()
|
||||
pipeline = uri_src.get_parent()
|
||||
volume = pipeline.get_by_name('volume')
|
||||
uri_src.link(volume)
|
||||
logger.debug("Linked uri_src's new decoded pad to volume filter")
|
||||
# FIXME uridecodebin got no new-decoded-pad signal, but it's
|
||||
# subcomponent decodebin2 got that signal. Fixing this is postponed
|
||||
# till after data_src is up and running perfectly
|
||||
#self.gst_uri_src.connect('new-decoded-pad', on_new_decoded_pad)
|
||||
|
||||
# Link data source output with volume filter input
|
||||
self.gst_data_src.link(self.gst_volume)
|
||||
|
||||
# Link volume filter output to audio sink input
|
||||
self.gst_volume.link(self.gst_sink)
|
||||
|
||||
def process_mopidy_message(self, message):
|
||||
"""Process messages from the rest of Mopidy."""
|
||||
if message['command'] == 'play_uri':
|
||||
|
||||
@ -28,16 +28,23 @@ class BaseProcess(multiprocessing.Process):
|
||||
except SettingsError as e:
|
||||
logger.error(e.message)
|
||||
sys.exit(1)
|
||||
except ImportError as e:
|
||||
logger.error(e)
|
||||
sys.exit(1)
|
||||
|
||||
def run_inside_try(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class CoreProcess(BaseProcess):
|
||||
def __init__(self, core_queue):
|
||||
def __init__(self, core_queue, output_class, backend_class,
|
||||
frontend_class):
|
||||
super(CoreProcess, self).__init__()
|
||||
self.core_queue = core_queue
|
||||
self.output_queue = None
|
||||
self.output_class = output_class
|
||||
self.backend_class = backend_class
|
||||
self.frontend_class = frontend_class
|
||||
self.output = None
|
||||
self.backend = None
|
||||
self.frontend = None
|
||||
@ -50,11 +57,9 @@ class CoreProcess(BaseProcess):
|
||||
|
||||
def setup(self):
|
||||
self.output_queue = multiprocessing.Queue()
|
||||
self.output = get_class(settings.OUTPUT)(self.core_queue,
|
||||
self.output_queue)
|
||||
self.backend = get_class(settings.BACKENDS[0])(self.core_queue,
|
||||
self.output_queue)
|
||||
self.frontend = get_class(settings.FRONTEND)(self.backend)
|
||||
self.output = self.output_class(self.core_queue, self.output_queue)
|
||||
self.backend = self.backend_class(self.core_queue, self.output_queue)
|
||||
self.frontend = self.frontend_class(self.backend)
|
||||
|
||||
def process_message(self, message):
|
||||
if message.get('to') == 'output':
|
||||
|
||||
@ -24,8 +24,11 @@ def get_class(name):
|
||||
module_name = name[:name.rindex('.')]
|
||||
class_name = name[name.rindex('.') + 1:]
|
||||
logger.debug('Loading: %s', name)
|
||||
module = import_module(module_name)
|
||||
class_object = getattr(module, class_name)
|
||||
try:
|
||||
module = import_module(module_name)
|
||||
class_object = getattr(module, class_name)
|
||||
except (ImportError, AttributeError):
|
||||
raise ImportError("Couldn't load: %s" % name)
|
||||
return class_object
|
||||
|
||||
def get_or_create_folder(folder):
|
||||
|
||||
@ -11,6 +11,25 @@ from mopidy.models import Track, Artist, Album
|
||||
|
||||
from tests import SkipTest, data_folder
|
||||
|
||||
class GetClassTest(unittest.TestCase):
|
||||
def test_loading_module_that_does_not_exist(self):
|
||||
test = lambda: get_class('foo.bar.Baz')
|
||||
self.assertRaises(ImportError, test)
|
||||
|
||||
def test_loading_class_that_does_not_exist(self):
|
||||
test = lambda: get_class('unittest.FooBarBaz')
|
||||
self.assertRaises(ImportError, test)
|
||||
|
||||
def test_import_error_message_contains_complete_class_path(self):
|
||||
try:
|
||||
get_class('foo.bar.Baz')
|
||||
except ImportError as e:
|
||||
self.assert_('foo.bar.Baz' in str(e))
|
||||
|
||||
def test_loading_existing_class(self):
|
||||
cls = get_class('unittest.TestCase')
|
||||
self.assertEqual(cls.__name__, 'TestCase')
|
||||
|
||||
class GetOrCreateFolderTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.parent = tempfile.mkdtemp()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user