diff --git a/docs/changelog.rst b/docs/changelog.rst index 32453c13..938e19d6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -176,6 +176,10 @@ Audio time of the GStreamer queue. If you experience buffering before track changes, it may help to increase this. Workaround for :issue:`1409`. +- ``tags_changed`` events are only emitted for fields that have changed. + Previous behavior was to emit this for all fields received from GStreamer. + (PR: :issue:`1439`) + Gapless ------- diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index f825a768..64300ff9 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -326,9 +326,24 @@ class _Handler(object): def on_tag(self, taglist): tags = tags_lib.convert_taglist(taglist) gst_logger.debug('Got TAG bus message: tags=%r', dict(tags)) - self._audio._tags.update(tags) - logger.debug('Audio event: tags_changed(tags=%r)', tags.keys()) - AudioListener.send('tags_changed', tags=tags.keys()) + + # Postpone emitting tags until stream start. + if self._audio._pending_tags is not None: + self._audio._pending_tags.update(tags) + return + + # TODO: Add proper tests for only emitting changed tags. + unique = object() + changed = [] + for key, value in tags.items(): + # Update any tags that changed, and store changed keys. + if self._audio._tags.get(key, unique) != value: + self._audio._tags[key] = value + changed.append(key) + + if changed: + logger.debug('Audio event: tags_changed(tags=%r)', changed) + AudioListener.send('tags_changed', tags=changed) def on_missing_plugin(self, msg): desc = GstPbutils.missing_plugin_message_get_description(msg) @@ -349,6 +364,14 @@ class _Handler(object): logger.debug('Audio event: stream_changed(uri=%r)', uri) AudioListener.send('stream_changed', uri=uri) + # 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 + + if tags: + logger.debug('Audio event: tags_changed(tags=%r)', tags.keys()) + AudioListener.send('tags_changed', tags=tags.keys()) + def on_segment(self, segment): gst_logger.debug( 'Got SEGMENT pad event: ' @@ -386,6 +409,7 @@ class Audio(pykka.ThreadingActor): self._buffering = False self._tags = {} self._pending_uri = None + self._pending_tags = None self._playbin = None self._outputs = None @@ -536,8 +560,8 @@ class Audio(pykka.ThreadingActor): else: current_volume = None - self._tags = {} # TODO: add test for this somehow self._pending_uri = uri + self._pending_tags = {} self._playbin.set_property('uri', uri) if self.mixer is not None and current_volume is not None: diff --git a/mopidy/audio/tags.py b/mopidy/audio/tags.py index 62784bc0..38a0bac9 100644 --- a/mopidy/audio/tags.py +++ b/mopidy/audio/tags.py @@ -58,6 +58,7 @@ gstreamer-GstTagList.html log.TRACE_LOG_LEVEL, 'Ignoring unknown tag data: %r = %r', tag, value) + # TODO: dict(result) to not leak the defaultdict, or just use setdefault? return result