diff --git a/mopidy/outputs/gstreamer.py b/mopidy/outputs/gstreamer.py index 7f1d35eb..cdf3829e 100644 --- a/mopidy/outputs/gstreamer.py +++ b/mopidy/outputs/gstreamer.py @@ -68,6 +68,29 @@ class GStreamerOutput(ThreadingActor, BaseOutput): output.sync_state_with_parent() gst.element_link_many(self.gst_tee, output) + def _build_shoutcast_description(self): + if settings.SHOUTCAST_OVERRIDE: + return settings.SHOUTCAST_OVERRIDE + + if not settings.SHOUTCAST_SERVER: + return None + + description = ['%s ! shout2send' % settings.SHOUTCAST_ENCODER] + options = { + u'ip': settings.SHOUTCAST_SERVER, + u'mount': settings.SHOUTCAST_MOUNT, + u'port': settings.SHOUTCAST_PORT, + u'username': settings.SHOUTCAST_USER, + u'password': settings.SHOUTCAST_PASSWORD, + } + + for key, value in sorted(options.items()): + if value: + description.append('%s="%s"' % (key, value)) + + return u' '.join(description) + + def _process_new_pad(self, source, pad, target_pad): pad.link(target_pad) diff --git a/mopidy/settings.py b/mopidy/settings.py index 6e33ffaa..cd8f445e 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -174,6 +174,51 @@ MPD_SERVER_PASSWORD = None #: Default: 6600 MPD_SERVER_PORT = 6600 +#: Servar that runs Shoutcast server to send stream to. +#: +#: Default: :class:`None`, disables shoutcast if set to :class:`None` +SHOUTCAST_SERVER = None + +#: User to authenticate as against Shoutcast server. +#: +#: Default: 'source' +SHOUTCAST_USER = u'source' + +#: Password to authenticate with against Shoutcast server. +#: +#: Default: 'hackme' +SHOUTCAST_PASSWORD = u'hackme' + +#: Port to use for streaming to Shoutcast server. +#: +#: Default: 8000 +SHOUTCAST_PORT = 8000 + +#: Mountpoint to use for the stream on the Shoutcast server. +#: +#: Default: /stream +SHOUTCAST_MOUNT = u'/stream' + +#: Encoder to use to process audio data before streaming. +#: +#: Default: vorbisenc ! oggmux +SHOUTCAST_ENCODER = u'vorbisenc ! oggmux' + +#: Overrides to allow advanced setup of shoutcast. Using this settings implies +#: that all other SHOUTCAST_* settings will be ignored. +#: +#: Examples: +#: +#: ``vorbisenc ! oggmux ! shout2send mount=/stream port=8000`` +#: Encode with vorbis and use ogg mux. +#: ``lame bitrate=320 ! shout2send mount=/stream port=8000`` +#: Encode with lame to bitrate=320. +#: +#: For all options see gst-inspect-0.10 lame, vorbisenc and shout2send. +#: +#: Default: :class:`None` +SHOUTCAST_OVERRIDE = None + #: Path to the Spotify cache. #: #: Used by :mod:`mopidy.backends.spotify`. diff --git a/tests/outputs/gstreamer_test.py b/tests/outputs/gstreamer_test.py index 31a16756..b39e5583 100644 --- a/tests/outputs/gstreamer_test.py +++ b/tests/outputs/gstreamer_test.py @@ -60,3 +60,59 @@ class GStreamerOutputTest(unittest.TestCase): @SkipTest def test_set_position(self): pass # TODO + + def test_build_shoutcast_description_without_server(self): + self.assertEqual(None, self.output._build_shoutcast_description()) + + def test_build_shoutcast_description_with_server(self): + settings.SHOUTCAST_SERVER = '127.0.0.1' + + expected = u'%s ! ' % settings.SHOUTCAST_ENCODER + \ + u'shout2send ip="127.0.0.1" mount="/stream" ' \ + u'password="hackme" port="8000" username="source"' + result = self.output._build_shoutcast_description() + self.assertEqual(expected, result) + + def test_build_shoutcast_description_with_mount(self): + settings.SHOUTCAST_SERVER = '127.0.0.1' + settings.SHOUTCAST_MOUNT = '/stream.mp3' + + expected = u'%s ! ' % settings.SHOUTCAST_ENCODER + \ + u'shout2send ip="127.0.0.1" mount="/stream.mp3" ' \ + u'password="hackme" port="8000" username="source"' + result = self.output._build_shoutcast_description() + self.assertEqual(expected, result) + + def test_build_shoutcast_description_with_user_and_passwod(self): + settings.SHOUTCAST_SERVER = '127.0.0.1' + settings.SHOUTCAST_USER = 'john' + settings.SHOUTCAST_PASSWORD = 'doe' + + expected = u'%s ! ' % settings.SHOUTCAST_ENCODER + \ + u'shout2send ip="127.0.0.1" mount="/stream" ' \ + u'password="doe" port="8000" username="john"' + result = self.output._build_shoutcast_description() + self.assertEqual(expected, result) + + def test_build_shoutcast_description_unset_user_and_pass(self): + settings.SHOUTCAST_SERVER = '127.0.0.1' + settings.SHOUTCAST_USER = None + settings.SHOUTCAST_PASSWORD = None + + expected = u'%s ! shout2send ' % settings.SHOUTCAST_ENCODER + \ + u'ip="127.0.0.1" mount="/stream" port="8000"' + result = self.output._build_shoutcast_description() + self.assertEqual(expected, result) + + def test_build_shoutcast_description_with_override(self): + settings.SHOUTCAST_OVERRIDE = 'foobar' + + result = self.output._build_shoutcast_description() + self.assertEqual('foobar', result) + + def test_build_shoutcast_description_with_override_and_server(self): + settings.SHOUTCAST_OVERRIDE = 'foobar' + settings.SHOUTCAST_SERVER = '127.0.0.1' + + result = self.output._build_shoutcast_description() + self.assertEqual('foobar', result)