From 703141c15b214edaff14a73a476db5def3472042 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 01:32:52 +0200 Subject: [PATCH 1/3] Make sure bad data to OUTPUT does not deadlock. - Moves GStreamer initialization out of on-start as it is not obvious to me how to stop rest of setup on other ways. - Note that gst.GError != gobject.GError as far as except is concerned. --- mopidy/core.py | 4 +++- mopidy/gstreamer.py | 13 +++++++++++-- tests/gstreamer_test.py | 6 +++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/mopidy/core.py b/mopidy/core.py index 596e0fe5..ddbf9b8b 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -20,7 +20,7 @@ sys.argv[1:] = gstreamer_args from mopidy import (get_version, settings, OptionalDependencyError, SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE) -from mopidy.gstreamer import GStreamer +from mopidy.gstreamer import GStreamer, GStreamerError from mopidy.utils import get_class from mopidy.utils.log import setup_logging from mopidy.utils.path import get_or_create_folder, get_or_create_file @@ -45,6 +45,8 @@ def main(): loop.run() except SettingsError as e: logger.error(e.message) + except GStreamerError as e: + logger.error(e) except KeyboardInterrupt: logger.info(u'Interrupted. Exiting...') except Exception as e: diff --git a/mopidy/gstreamer.py b/mopidy/gstreamer.py index 0dd02937..8d349fcc 100644 --- a/mopidy/gstreamer.py +++ b/mopidy/gstreamer.py @@ -1,5 +1,6 @@ import pygst pygst.require('0.10') +import gobject import gst import logging @@ -13,6 +14,10 @@ from mopidy.backends.base import Backend logger = logging.getLogger('mopidy.gstreamer') +class GStreamerError(Exception): + pass + + class GStreamer(ThreadingActor): """ Audio output through `GStreamer `_. @@ -39,7 +44,6 @@ class GStreamer(ThreadingActor): self._volume = None self._output = None - def on_start(self): self._setup_pipeline() self._setup_output() self._setup_message_processor() @@ -61,7 +65,12 @@ class GStreamer(ThreadingActor): self._pipeline.get_by_name('convert').get_pad('sink')) def _setup_output(self): - self._output = gst.parse_bin_from_description(settings.OUTPUT, True) + try: + self._output = gst.parse_bin_from_description(settings.OUTPUT, True) + except gobject.GError as e: + raise GStreamerError('%r while creating %r' % (e.message, + settings.OUTPUT)) + self._pipeline.add(self._output) gst.element_link_many(self._volume, self._output) logger.debug('Output set to %s', settings.OUTPUT) diff --git a/tests/gstreamer_test.py b/tests/gstreamer_test.py index 012c9002..b370981a 100644 --- a/tests/gstreamer_test.py +++ b/tests/gstreamer_test.py @@ -14,7 +14,6 @@ class GStreamerTest(unittest.TestCase): settings.BACKENDS = ('mopidy.backends.local.LocalBackend',) self.song_uri = path_to_uri(path_to_data_dir('song1.wav')) self.gstreamer = GStreamer() - self.gstreamer.on_start() def prepare_uri(self, uri): self.gstreamer.prepare_change() @@ -71,3 +70,8 @@ class GStreamerTest(unittest.TestCase): @unittest.SkipTest def test_set_position(self): pass # TODO + + @unittest.SkipTest + def test_invalid_output_raises_error(self): + pass # TODO + From 0a86afbe31a42913947f55eef4f7eaca87a3830a Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 11:19:46 +0200 Subject: [PATCH 2/3] Add audioresample and queue to pipeline, fixes #159 - Audioresample should perform as a noop in cases where no conversion is needed. In cases where the sink requires a fixed sample rate this will prevent output from breaking. - The queue is needed to ensure that our outputs play nicely and is simply a continuation of the queue that was in our old Output abstraction. --- mopidy/gstreamer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mopidy/gstreamer.py b/mopidy/gstreamer.py index 8d349fcc..ab4fd59b 100644 --- a/mopidy/gstreamer.py +++ b/mopidy/gstreamer.py @@ -52,6 +52,8 @@ class GStreamer(ThreadingActor): description = ' ! '.join([ 'uridecodebin name=uri', 'audioconvert name=convert', + 'audioresample name=resample', + 'queue name=queue', 'volume name=volume']) logger.debug(u'Setting up base GStreamer pipeline: %s', description) From 387da5842582b950c329277bafb169d8682caaa3 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 11:22:05 +0200 Subject: [PATCH 3/3] Deprecate and remove shoutcast settings. I've also verfied that the examples provided will actually work. --- mopidy/settings.py | 54 ---------------------------------------- mopidy/utils/settings.py | 16 ++++++------ 2 files changed, 9 insertions(+), 61 deletions(-) diff --git a/mopidy/settings.py b/mopidy/settings.py index 0bb04823..e7c5593a 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -184,60 +184,6 @@ MPD_SERVER_MAX_CONNECTIONS = 20 #: OUTPUT = u'autoaudiosink' OUTPUT = u'autoaudiosink' -#: Hostname of the SHOUTcast server which Mopidy should stream audio to. -#: -#: Used by :mod:`mopidy.outputs.shoutcast`. -#: -#: Default:: -#: -#: SHOUTCAST_OUTPUT_HOSTNAME = u'127.0.0.1' -SHOUTCAST_OUTPUT_HOSTNAME = u'127.0.0.1' - -#: Port of the SHOUTcast server. -#: -#: Used by :mod:`mopidy.outputs.shoutcast`. -#: -#: Default:: -#: -#: SHOUTCAST_OUTPUT_PORT = 8000 -SHOUTCAST_OUTPUT_PORT = 8000 - -#: User to authenticate as against SHOUTcast server. -#: -#: Used by :mod:`mopidy.outputs.shoutcast`. -#: -#: Default:: -#: -#: SHOUTCAST_OUTPUT_USERNAME = u'source' -SHOUTCAST_OUTPUT_USERNAME = u'source' - -#: Password to authenticate with against SHOUTcast server. -#: -#: Used by :mod:`mopidy.outputs.shoutcast`. -#: -#: Default:: -#: -#: SHOUTCAST_OUTPUT_PASSWORD = u'hackme' -SHOUTCAST_OUTPUT_PASSWORD = u'hackme' - -#: Mountpoint to use for the stream on the SHOUTcast server. -#: -#: Used by :mod:`mopidy.outputs.shoutcast`. -#: -#: Default:: -#: -#: SHOUTCAST_OUTPUT_MOUNT = u'/stream' -SHOUTCAST_OUTPUT_MOUNT = u'/stream' - -#: Encoder to use to process audio data before streaming to SHOUTcast server. -#: -#: Used by :mod:`mopidy.outputs.shoutcast`. -#: -#: Default:: -#: -#: SHOUTCAST_OUTPUT_ENCODER = u'lame mode=stereo bitrate=320' -SHOUTCAST_OUTPUT_ENCODER = u'lame mode=stereo bitrate=320' - #: Path to the Spotify cache. #: #: Used by :mod:`mopidy.backends.spotify`. diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 8060c667..a07075fb 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -136,29 +136,31 @@ def validate_settings(defaults, settings): else: errors[setting] = u'Deprecated setting. Use %s.' % ( changed[setting],) - continue - if setting == 'BACKENDS': + elif setting == 'BACKENDS': if 'mopidy.backends.despotify.DespotifyBackend' in value: errors[setting] = ( u'Deprecated setting value. ' u'"mopidy.backends.despotify.DespotifyBackend" is no ' u'longer available.') - continue - if setting == 'OUTPUTS': + elif setting == 'OUTPUTS': errors[setting] = ( u'Deprecated setting, please change to OUTPUT. OUTPUT expectes ' u'a GStreamer bin describing your desired output.') - continue - if setting == 'SPOTIFY_BITRATE': + elif setting == 'SPOTIFY_BITRATE': if value not in (96, 160, 320): errors[setting] = ( u'Unavailable Spotify bitrate. Available bitrates are 96, ' u'160, and 320.') - if setting not in defaults: + elif setting.startswith('SHOUTCAST_OUTPUT_'): + errors[setting] = ( + u'Deprecated setting, please set the value via the GStreamer ' + u'bin in OUTPUT.') + + elif setting not in defaults: errors[setting] = u'Unknown setting. Is it misspelled?' continue