diff --git a/mopidy/core.py b/mopidy/core.py index 128b4723..4012359f 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 84b540a6..60e601f3 100644 --- a/mopidy/gstreamer.py +++ b/mopidy/gstreamer.py @@ -14,6 +14,10 @@ from mopidy.backends.base import Backend logger = logging.getLogger('mopidy.gstreamer') +class GStreamerError(Exception): + pass + + # TODO: we might want to add some ranking to the mixers we know about? # TODO: move to mixers module and do from mopidy.mixers import * to install # elements. @@ -123,7 +127,6 @@ class GStreamer(ThreadingActor): self._output = None self._mixer = None - def on_start(self): self._setup_pipeline() self._setup_output() self._setup_mixer() @@ -134,7 +137,9 @@ class GStreamer(ThreadingActor): # connect to an output bin with a mixer on the side. set_uri on bin? description = ' ! '.join([ 'uridecodebin name=uri', - 'audioconvert name=convert']) + 'audioconvert name=convert', + 'audioresample name=resample', + 'queue name=queue']) logger.debug(u'Setting up base GStreamer pipeline: %s', description) @@ -143,12 +148,17 @@ class GStreamer(ThreadingActor): self._uridecodebin.connect('notify::source', self._on_new_source) self._uridecodebin.connect('pad-added', self._on_new_pad, - self._pipeline.get_by_name('convert').get_pad('sink')) + self._pipeline.get_by_name('queue').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._pipeline.get_by_name('convert'), + gst.element_link_many(self._pipeline.get_by_name('queue'), self._output) logger.debug('Output set to %s', settings.OUTPUT) diff --git a/mopidy/settings.py b/mopidy/settings.py index 1d5ec330..4e8370e6 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -173,60 +173,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 52320099..372dd8a0 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -140,29 +140,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 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 +