diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index 162e2a05..a23c4c43 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -42,8 +42,10 @@ class Audio(pykka.ThreadingActor): self._mixer = None self._mixer_track = None self._software_mixing = False + self._appsrc = None self._notify_source_signal_id = None + self._about_to_finish_id = None self._message_signal_id = None def on_start(self): @@ -67,9 +69,14 @@ class Audio(pykka.ThreadingActor): fakesink = gst.element_factory_make('fakesink') self._playbin.set_property('video-sink', fakesink) + self._about_to_finish_id = self._playbin.connect( + 'about-to-finish', self._on_about_to_finish) self._notify_source_signal_id = self._playbin.connect( 'notify::source', self._on_new_source) + def _on_about_to_finish(self, element): + self._appsrc = None + def _on_new_source(self, element, pad): uri = element.get_property('uri') if not uri or not uri.startswith('appsrc://'): @@ -82,8 +89,13 @@ class Audio(pykka.ThreadingActor): b'rate=(int)44100') source = element.get_property('source') source.set_property('caps', default_caps) + source.set_property('format', b'time') # Gstreamer does not like unicode + + self._appsrc = source def _teardown_playbin(self): + if self._about_to_finish_id: + self._playbin.disconnect(self._about_to_finish_id) if self._notify_source_signal_id: self._playbin.disconnect(self._notify_source_signal_id) self._playbin.set_state(gst.STATE_NULL) @@ -225,23 +237,21 @@ class Audio(pykka.ThreadingActor): """ self._playbin.set_property('uri', uri) - def emit_data(self, capabilities, data): + def emit_data(self, buffer_): """ Call this to deliver raw audio data to be played. Note that the uri must be set to ``appsrc://`` for this to work. - :param capabilities: a GStreamer capabilities string - :type capabilities: string - :param data: raw audio data to be played - """ - caps = gst.caps_from_string(capabilities) - buffer_ = gst.Buffer(buffer(data)) - buffer_.set_caps(caps) + Returns true if data was delivered. - source = self._playbin.get_property('source') - source.set_property('caps', caps) - source.emit('push-buffer', buffer_) + :param buffer_: buffer to pass to appsrc + :type buffer_: :class:`gst.Buffer` + :rtype: boolean + """ + if not self._appsrc: + return False + return self._appsrc.emit('push-buffer', buffer_) == gst.FLOW_OK def emit_end_of_stream(self): """ diff --git a/mopidy/backends/spotify/session_manager.py b/mopidy/backends/spotify/session_manager.py index cd3d97db..998e4d5e 100644 --- a/mopidy/backends/spotify/session_manager.py +++ b/mopidy/backends/spotify/session_manager.py @@ -1,5 +1,9 @@ from __future__ import unicode_literals +import pygst +pygst.require('0.10') +import gst + import logging import os import threading @@ -108,8 +112,13 @@ class SpotifySessionManager(process.BaseThread, PyspotifySessionManager): 'sample_rate': sample_rate, 'channels': channels, } - self.audio.emit_data(capabilites, bytes(frames)) - return num_frames + buffer_ = gst.Buffer(bytes(frames)) + buffer_.set_caps(gst.caps_from_string(capabilites)) + + if self.audio.emit_data(buffer_).get(): + return num_frames + else: + return 0 def play_token_lost(self, session): """Callback used by pyspotify"""