diff --git a/docs/changelog.rst b/docs/changelog.rst index 067adc46..c61071db 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,7 +10,11 @@ v2.1.0 (UNRELEASED) Feature release. -- Nothing yet. +- MPD: Fix MPD protocol for ``replay_gain_status`` command. The actual command + remains unimplemented. (PR: :issue:`1520`) + +- MPD: Add ``nextsong`` and ``nextsongid`` to the response of MPD ``status`` command. + (Fixes: :issue:`1133`, :issue:`1516`, PR: :issue:`1523`) v2.0.1 (UNRELEASED) @@ -31,23 +35,32 @@ Bug fix release. (Fixes: :issue:`935`, :issue:`1453`, :issue:`1474` and :issue:`1480`, PR: :issue:`1487`) +- Audio: Better handling of seek when position does not match the expected + pending position. (Fixes: :issue:`1462`, PR: :issue:`1496`) + +- Audio: Handle bad date tags from audio, thanks to Mario Lang and Tom Parker + who fixed this in parallel. (Fixes: :issue:`1506`, PR: :issue:`1525`, + :issue:`1517`) + +- Audio: Make sure scanner handles streams without a duration. + (Fixes: :issue:`1526`) + +- Audio: Ensure audio tags are never `None`. (Fixes: :issue:`1449`) + - Core: Avoid endless loop if all tracks in the tracklist are unplayable and consume mode is off. (Fixes: :issue:`1221`, :issue:`1454`, PR: :issue:`1455`) -- File: Ensure path comparision is done between bytestrings only. Fixes crash - where a :confval:`file/media_dirs` path contained non-ASCII characters. - (Fixes: :issue:`1345`, PR: :issue:`1493`) - -- MPD: Fix MPD protocol for ``replay_gain_status`` command. The actual command - remains unimplemented. (PR: :issue:`1520`) - -- MPD: Add ``nextsong`` and ``nextsongid`` to the response of MPD ``status`` command. - (Fixes: :issue:`1133`, :issue:`1516`, PR: :issue:`1523`) - - Core: Correctly record the last position of a track when switching to another one. Particularly relevant for `mopidy-scrobbler` users, as before it was essentially unusable. (Fixes: :issue:`1456`, PR: :issue:`1534`) +- File: Ensure path comparison is done between bytestrings only. Fixes crash + where a :confval:`file/media_dirs` path contained non-ASCII characters. + (Fixes: :issue:`1345`, PR: :issue:`1493`) + +- Stream: Fix milliseconds vs seconds mistake in timeout handling. + (Fixes: :issue:`1521`, PR: :issue:`1522`) + v2.0.0 (2016-02-15) =================== diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index 267b228d..61a8e008 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -22,7 +22,6 @@ logger = logging.getLogger(__name__) gst_logger = logging.getLogger('mopidy.audio.gst') _GST_PLAY_FLAGS_AUDIO = 0x02 -_GST_PLAY_FLAGS_SOFT_VOLUME = 0x10 _GST_STATE_MAPPING = { Gst.State.PLAYING: PlaybackState.PLAYING, @@ -369,7 +368,7 @@ class _Handler(object): # Emit any postponed tags that we got after about-to-finish. tags, self._audio._pending_tags = self._audio._pending_tags, None - self._audio._tags = tags + self._audio._tags = tags or {} if tags: logger.debug('Audio event: tags_changed(tags=%r)', tags.keys()) @@ -451,8 +450,7 @@ class Audio(pykka.ThreadingActor): def _setup_playbin(self): playbin = Gst.ElementFactory.make('playbin') - playbin.set_property( - 'flags', _GST_PLAY_FLAGS_AUDIO | _GST_PLAY_FLAGS_SOFT_VOLUME) + playbin.set_property('flags', _GST_PLAY_FLAGS_AUDIO) # TODO: turn into config values... playbin.set_property('buffer-size', 5 << 20) # 5MB @@ -489,15 +487,16 @@ class Audio(pykka.ThreadingActor): def _setup_audio_sink(self): audio_sink = Gst.ElementFactory.make('bin', 'audio-sink') + queue = Gst.ElementFactory.make('queue') + volume = Gst.ElementFactory.make('volume') # Queue element to buy us time between the about-to-finish event and # the actual switch, i.e. about to switch can block for longer thanks # to this queue. + # TODO: See if settings should be set to minimize latency. Previous # setting breaks appsrc, and settings before that broke on a few # systems. So leave the default to play it safe. - queue = Gst.ElementFactory.make('queue') - if self._config['audio']['buffer_time'] > 0: queue.set_property( 'max-size-time', @@ -505,15 +504,13 @@ class Audio(pykka.ThreadingActor): audio_sink.add(queue) audio_sink.add(self._outputs) + audio_sink.add(volume) + + queue.link(volume) + volume.link(self._outputs) if self.mixer: - volume = Gst.ElementFactory.make('volume') - audio_sink.add(volume) - queue.link(volume) - volume.link(self._outputs) self.mixer.setup(volume, self.actor_ref.proxy().mixer) - else: - queue.link(self._outputs) ghost_pad = Gst.GhostPad.new('sink', queue.get_static_pad('sink')) audio_sink.add_pad(ghost_pad) diff --git a/mopidy/audio/scan.py b/mopidy/audio/scan.py index 27888638..f99c4489 100644 --- a/mopidy/audio/scan.py +++ b/mopidy/audio/scan.py @@ -135,6 +135,17 @@ def _start_pipeline(pipeline): pipeline.set_state(Gst.State.PLAYING) +def _query_duration(pipeline): + success, duration = pipeline.query_duration(Gst.Format.TIME) + if not success: + duration = None # Make sure error case preserves None. + elif duration < 0: + duration = None # Stream without duration. + else: + duration = duration // Gst.MSECOND + return success, duration + + def _query_seekable(pipeline): query = Gst.Query.new_seeking(Gst.Format.TIME) pipeline.query(query) @@ -187,13 +198,8 @@ def _process(pipeline, timeout_ms): elif message.type == Gst.MessageType.EOS: return tags, mime, have_audio, duration elif message.type == Gst.MessageType.ASYNC_DONE: - success, duration = pipeline.query_duration(Gst.Format.TIME) - if success: - duration = duration // Gst.MSECOND - else: - duration = None - - if tags and duration is not None: + success, duration = _query_duration(pipeline) + if tags and success: return tags, mime, have_audio, duration # Workaround for upstream bug which causes tags/duration to arrive