[gnome-music/wip/mschraal/gapless-v3: 21/25] Introduce gapless playback



commit c25218599ae21025a146c9de8b82c9821c778f48
Author: Marinus Schraal <mschraal gnome org>
Date:   Wed Aug 22 01:39:11 2018 +0200

    Introduce gapless playback
    
    gstplayer: Reset tick on stream start

 gnomemusic/gstplayer.py             | 44 +++++++++++++++++++++++++++++--------
 gnomemusic/player.py                | 21 +++++++++++++-----
 gnomemusic/widgets/playertoolbar.py |  6 +++--
 gnomemusic/widgets/smoothscale.py   |  9 +++++++-
 4 files changed, 62 insertions(+), 18 deletions(-)
---
diff --git a/gnomemusic/gstplayer.py b/gnomemusic/gstplayer.py
index b4648163..0366bc97 100644
--- a/gnomemusic/gstplayer.py
+++ b/gnomemusic/gstplayer.py
@@ -30,7 +30,7 @@ import gi
 gi.require_version('Gst', '1.0')
 gi.require_version('GstAudio', '1.0')
 gi.require_version('GstPbutils', '1.0')
-from gi.repository import Gtk, Gio, GObject, Gst, GstAudio, GstPbutils
+from gi.repository import Gtk, Gio, GLib, GObject, Gst, GstAudio, GstPbutils
 
 from gnomemusic import log
 from gnomemusic.playlists import Playlists
@@ -53,8 +53,9 @@ class GstPlayer(GObject.GObject):
     Handles GStreamer interaction for Player and SmoothScale.
     """
     __gsignals__ = {
-        'eos': (GObject.SignalFlags.RUN_FIRST, None, ()),
-        'clock-tick': (GObject.SignalFlags.RUN_FIRST, None, (int, ))
+        'clock-tick': (GObject.SignalFlags.RUN_FIRST, None, (int, )),
+        'eos': (GObject.SignalFlags.RUN_FIRST, None, (bool, )),
+        'stream-start': (GObject.SignalFlags.RUN_FIRST, None, ())
     }
 
     def __repr__(self):
@@ -67,6 +68,7 @@ class GstPlayer(GObject.GObject):
         Gst.init(None)
 
         self._duration = -1.
+        self._tick = 0
 
         self._missing_plugin_messages = []
         self._settings = Gio.Settings.new('org.gnome.Music')
@@ -88,6 +90,9 @@ class GstPlayer(GObject.GObject):
         self._bus.connect(
             'message::duration-changed', self._on_duration_changed)
         self._bus.connect('message::new-clock', self._on_new_clock)
+        self._bus.connect('message::stream-start', self._on_stream_start)
+
+        self._player.connect('about-to-finish', self._on_about_to_finish)
 
         self._previous_state = Playback.STOPPED
         self.props.state = Playback.STOPPED
@@ -117,6 +122,11 @@ class GstPlayer(GObject.GObject):
             logger.debug("Replay Gain is not available")
             return
 
+    @log
+    def _on_about_to_finish(self, klass, data=None):
+        print("about to finish")
+        self.emit('eos', True)
+
     @log
     def _on_replaygain_setting_changed(self, settings, value):
         if value:
@@ -132,13 +142,14 @@ class GstPlayer(GObject.GObject):
 
         # TODO: Workaround the first duration change not being emitted
         # and hence smoothscale not being initialized properly.
-        if self.props.duration == -1.:
-            self._on_duration_changed(None, None)
+        # if self.props.duration == -1.:
+        #     self._on_duration_changed(None, None)
 
     @log
     def _on_clock_tick(self, clock, time, id, data):
-        tick = time / Gst.SECOND
-        self.emit('clock-tick', tick)
+        self.emit('clock-tick', self._tick)
+        print("TICK", self._tick)
+        self._tick += 1
 
     @log
     def _on_bus_state_changed(self, bus, message):
@@ -186,12 +197,26 @@ class GstPlayer(GObject.GObject):
                 message.src.get_name(), error.message))
         logger.warning("Debugging info:\n{}".format(debug))
 
-        self.emit('eos')
+        self.emit('eos', False)
         return True
 
     @log
     def _on_bus_eos(self, bus, message):
-        self.emit('eos')
+        print("bus eos")
+        self.emit('eos', False)
+
+    @log
+    def _on_stream_start(self, bus, message):
+        print("stream start")
+
+        def delayed_query(bus, message):
+            self._on_duration_changed(None, None)
+            self._tick = 0
+            self.emit('stream-start')
+
+            return False
+
+        GLib.timeout_add(1, delayed_query, bus, message)
 
     @log
     def _get_playback_status(self):
@@ -311,6 +336,7 @@ class GstPlayer(GObject.GObject):
 
         :param float seconds: Position in seconds to seek
         """
+        print("seek", seconds)
         # FIXME: seek should be signalled to MPRIS
         self._player.seek_simple(
             Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 7e72bcc9..8686b3fc 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -583,6 +583,8 @@ class Player(GObject.GObject):
         self._gst_player = GstPlayer()
         self._gst_player.connect('clock-tick', self._on_clock_tick)
         self._gst_player.connect('eos', self._on_eos)
+        self._gst_player.connect('stream-start', self._on_stream_start)
+
         self._gst_player.bind_property(
             'duration', self, 'duration', GObject.BindingFlags.SYNC_CREATE)
         self._gst_player.bind_property(
@@ -635,15 +637,22 @@ class Player(GObject.GObject):
         self.emit('song-changed', self._playlist.get_current_index())
 
     @log
-    def _on_eos(self, klass):
-        def on_glib_idle():
-            self._playlist.next()
-            self.play()
+    def _on_eos(self, klass, gapless=False):
+        print("eos, gapless:", gapless)
 
         if self.props.has_next:
-            GLib.idle_add(on_glib_idle)
+            self._playlist.next()
+            if gapless:
+                new_url = self._playlist.props.current_song.get_url()
+                self._gst_player.props.url = new_url
+            else:
+                GLib.idle_add(self.play)
         else:
-            self.stop()
+            GLib.idle_add(self.stop)
+
+    @log
+    def _on_stream_start(self, klass):
+        self.emit('song-changed', self._playlist.get_current_index())
 
     @log
     def play(self, song_offset=None):
diff --git a/gnomemusic/widgets/playertoolbar.py b/gnomemusic/widgets/playertoolbar.py
index 7c0b69ca..3bafbf23 100644
--- a/gnomemusic/widgets/playertoolbar.py
+++ b/gnomemusic/widgets/playertoolbar.py
@@ -156,8 +156,10 @@ class PlayerToolbar(Gtk.ActionBar):
         :param int position: current song position
         """
         current_song = player.props.current_song
-        self._duration_label.set_label(
-            utils.seconds_to_string(current_song.get_duration()))
+        duration = player.props.duration
+        if duration != -1:
+            self._duration_label.set_label(
+                utils.seconds_to_string(int(duration)))
 
         self._play_button.set_sensitive(True)
         self._sync_prev_next()
diff --git a/gnomemusic/widgets/smoothscale.py b/gnomemusic/widgets/smoothscale.py
index d7ad2a8d..6d136dc1 100644
--- a/gnomemusic/widgets/smoothscale.py
+++ b/gnomemusic/widgets/smoothscale.py
@@ -48,6 +48,7 @@ class SmoothScale(Gtk.Scale):
         super().__init__()
 
         self._player = None
+        self._previous_duration = -1
         self._old_smooth_scale_value = 0.0
 
         self._seek_timeout = None
@@ -110,10 +111,16 @@ class SmoothScale(Gtk.Scale):
     @log
     def _on_duration_changed(self, klass, arguments):
         duration = self._player.props.duration
+        print("duration changed", duration)
 
-        if duration != -1.:
+        if (duration != -1
+                and duration != self._previous_duration):
+            print("RESET SCALE")
+            self._previous_duration = duration
             self.set_range(0.0, duration * 60)
             self.set_increments(300, 600)
+            self.set_value(0)
+            self._on_smooth_scale_event(None, None)
 
     @log
     def _on_smooth_scale_seek_finish(self, value):


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]