[gnome-music/wip/merge: 324/343] player: Add methods and signals needed by mpris



commit 16322878f3d2921e9ddf084a4cf4c123883fadaa
Author: Arnel A. Borja <arnelborja src gnome org>
Date:   Mon Jul 22 20:23:30 2013 +0800

    player: Add methods and signals needed by mpris
    
    - Make has_next and has_previous public
    - Add play_pause method
    - Remove mpris functions
    - Return playback status as class constants
    - Remove variant wrappers on metadata values
    - Add playback-status-changed signal
    - Add repeat-mode-changed signal
    - Add get/set repeat mode methods
    - Add volume-changed signal
    - Add prev-next-invalidated signal
    - Add seeked signal
    - Add get/set position methods

 gnomemusic/player.py |  254 ++++++++++++++------------------------------------
 1 files changed, 69 insertions(+), 185 deletions(-)
---
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 3187f5f..d7760e3 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -7,45 +7,6 @@ from gnomemusic.albumArtCache import AlbumArtCache
 
 ART_SIZE = 34
 
-MediaPlayer2PlayerIface = """
-<interface name="org.mpris.MediaPlayer2.Player">
-  <method name="Next"/>
-  <method name="Previous"/>
-  <method name="Pause"/>
-  <method name="PlayPause"/>
-  <method name="Stop"/>
-  <method name="Play"/>
-  <method name="Seek">
-    <arg direction="in" name="Offset" type="x"/>
-  </method>
-  <method name="SetPosition">
-    <arg direction="in" name="TrackId" type="o"/>
-    <arg direction="in" name="Position" type="x"/>
-  </method>
-  <method name="OpenUri">
-    <arg direction="in" name="Uri" type="s"/>
-  </method>
-  <signal name="Seeked">
-    <arg name="Position" type="x"/>
-  </signal>
-  <property name="PlaybackStatus" type="s" access="read"/>
-  <property name="LoopStatus" type="s" access="readwrite"/>
-  <property name="Rate" type="d" access="readwrite"/>
-  <property name="Shuffle" type="b" access="readwrite"/>
-  <property name="Metadata" type="a{sv}" access="read"/>
-  <property name="Volume" type="d" access="readwrite"/>
-  <property name="Position" type="x" access="read"/>
-  <property name="MinimumRate" type="d" access="read"/>
-  <property name="MaximumRate" type="d" access="read"/>
-  <property name="CanGoNext" type="b" access="read"/>
-  <property name="CanGoPrevious" type="b" access="read"/>
-  <property name="CanPlay" type="b" access="read"/>
-  <property name="CanPause" type="b" access="read"/>
-  <property name="CanSeek" type="b" access="read"/>
-  <property name="CanControl" type="b" access="read"/>
-</interface>
-"""
-
 
 class RepeatType:
     NONE = 0
@@ -54,6 +15,12 @@ class RepeatType:
     SHUFFLE = 3
 
 
+class PlaybackStatus:
+    PLAYING = 0
+    PAUSED = 1
+    STOPPED = 2
+
+
 class Player(GObject.GObject):
     nextTrack = None
     timeout = None
@@ -63,6 +30,11 @@ class Player(GObject.GObject):
         'playing-changed': (GObject.SIGNAL_RUN_FIRST, None, ()),
         'playlist-item-changed': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.ListStore, Gtk.TreeIter)),
         'current-changed': (GObject.SIGNAL_RUN_FIRST, None, ()),
+        'playback-status-changed': (GObject.SIGNAL_RUN_FIRST, None, ()),
+        'repeat-mode-changed': (GObject.SIGNAL_RUN_FIRST, None, ()),
+        'volume-changed': (GObject.SIGNAL_RUN_FIRST, None, ()),
+        'prev-next-invalidated': (GObject.SIGNAL_RUN_FIRST, None, ()),
+        'seeked': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
     }
 
     def __init__(self):
@@ -86,9 +58,6 @@ class Player(GObject.GObject):
         self._settings.connect('changed::repeat', self._on_settings_changed)
         self.repeat = self._settings.get_enum('repeat')
 
-        #self._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MediaPlayer2PlayerIface, self)
-        #self._dbusImpl.export(Gio.DBus.session, '/org/mpris/MediaPlayer2')
-
         self.bus.connect("message::state-changed", self._on_bus_state_changed)
         self.bus.connect("message::error", self._onBusError)
         self.bus.connect("message::eos", self._on_bus_eos)
@@ -142,6 +111,7 @@ class Player(GObject.GObject):
             self.playBtn.set_image(self._playImage)
             self.progressScale.set_value(0)
             self.progressScale.set_sensitive(False)
+            self.emit('playback-status-changed')
 
     def _on_glib_idle(self):
         self.currentTrack = self.nextTrack
@@ -196,14 +166,14 @@ class Player(GObject.GObject):
 
         return previousTrack
 
-    def _has_next(self):
+    def has_next(self):
         if self.repeat in [RepeatType.ALL, RepeatType.SONG, RepeatType.SHUFFLE]:
             return True
         else:
             tmp = self.currentTrack.copy()
             return self.playlist.iter_next(tmp) is not None
 
-    def _has_previous(self):
+    def has_previous(self):
         if self.repeat in [RepeatType.ALL, RepeatType.SONG, RepeatType.SHUFFLE]:
             return True
         else:
@@ -226,14 +196,13 @@ class Player(GObject.GObject):
             self.playBtn.set_image(image)
 
     def _sync_prev_next(self):
-        hasNext = self._has_next()
-        hasPrevious = self._has_previous()
+        hasNext = self.has_next()
+        hasPrevious = self.has_previous()
 
         self.nextBtn.set_sensitive(hasNext)
         self.prevBtn.set_sensitive(hasPrevious)
 
-        #self._dbusImpl.emit_property_changed('CanGoNext', GLib.Variant.new('b', hasNext))
-        #self._dbusImpl.emit_property_changed('CanGoPrevious', GLib.Variant.new('b', hasPrevious))
+        self.emit('prev-next-invalidated')
 
     def set_playing(self, value):
         self.eventBox.show()
@@ -279,10 +248,6 @@ class Player(GObject.GObject):
         else:
             self.player.nextUrl = None
 
-        #self._dbusImpl.emit_property_changed('Metadata', GLib.Variant.new('a{sv}', self.Metadata))
-        #self._dbusImpl.emit_property_changed('CanPlay', GLib.Variant.new('b', True))
-        #self._dbusImpl.emit_property_changed('CanPause', GLib.Variant.new('b', True))
-
         self.emit("playlist-item-changed", self.playlist, self.currentTrack)
         self.emit('current-changed')
 
@@ -304,7 +269,7 @@ class Player(GObject.GObject):
         if not self.timeout:
             self.timeout = GLib.timeout_add(1000, self._update_position_callback)
 
-        #self._dbusImpl.emit_property_changed('PlaybackStatus', GLib.Variant.new('s', 'Playing'))
+        self.emit('playback-status-changed')
 
     def pause(self):
         if self.timeout:
@@ -312,7 +277,7 @@ class Player(GObject.GObject):
             self.timeout = None
 
         self.player.set_state(Gst.State.PAUSED)
-        #self._dbusImpl.emit_property_changed('PlaybackStatus', GLib.Variant.new('s', 'Paused'))
+        self.emit('playback-status-changed')
         self.emit('playing-changed')
 
     def stop(self):
@@ -321,7 +286,6 @@ class Player(GObject.GObject):
             self.timeout = None
 
         self.player.set_state(Gst.State.NULL)
-        #self._dbusImpl.emit_property_changed('PlaybackStatus', GLib.Variant.new('s', 'Stopped'))
         self.emit('playing-changed')
 
     def play_next(self):
@@ -350,6 +314,12 @@ class Player(GObject.GObject):
         if self.currentTrack:
             self.play()
 
+    def play_pause(self):
+        if self.player.get_state(1)[1] == Gst.State.PLAYING:
+            self.set_playing(False)
+        else:
+            self.set_playing(True)
+
     def set_playlist(self, type, id, model, iter, field):
         self.stop()
 
@@ -461,168 +431,109 @@ class Player(GObject.GObject):
             icon = 'media-playlist-repeat-song-symbolic'
 
         self.repeatBtnImage.set_from_icon_name(icon, 0)
-        #self._dbusImpl.emit_property_changed('LoopStatus', GLib.Variant.new('s', self.LoopStatus))
-        #self._dbusImpl.emit_property_changed('Shuffle', GLib.Variant.new('b', self.Shuffle))
+        self.emit('repeat-mode-changed')
 
     def on_progress_scale_change_value(self, scroll):
         seconds = scroll.get_value() / 60
         if seconds != self.duration:
             self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, seconds * 
1000000000)
-            #self._dbusImpl.emit_signal('Seeked', GLib.Variant.new('(x)', [seconds * 1000000]))
+            self.emit('seeked', seconds * 1000000)
         else:
             duration = self.player.query_duration(Gst.Format.TIME)
             if duration:
                 #Rewind a second back before the track end
                 self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 
duration[1] - 1000000000)
-                #self._dbusImpl.emit_signal('Seeked', GLib.Variant.new('(x)', [(duration[1] - 1000000000) / 
1000]))
+                self.emit('seeked', (duration[1] - 1000000000) / 1000)
         return True
 
     #MPRIS
 
-    def Next(self):
-        self.play_next()
-
-    def Previous(self):
-        self.play_previous()
-
-    def Pause(self):
-        self.set_playing(False)
-
-    def PlayPause(self):
-        if self.player.get_state(1)[1] == Gst.State.PLAYING:
-            self.set_playing(False)
-        else:
-            self.set_playing(True)
-
-    def Play(self):
-        self.set_playing(True)
-
     def Stop(self):
         self.progressScale.set_value(0)
         self.progressScale.set_sensitive(False)
         self.playBtn.set_image(self._playImage)
         self.stop()
-
-    def SeekAsync(self, params, invocation):
-        offset = params
-
-        duration = self.player.query_duration(Gst.Format.TIME)
-        if duration is None:
-            return
-
-        if offset < 0:
-            offset = 0
-
-        if duration[1] >= offset * 1000:
-            self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, offset * 
1000)
-            #self._dbusImpl.emit_signal('Seeked', GLib.Variant.new('(x)', [offset]))
-        else:
-            self.play_next()
-
-    def SetPositionAsync(self, params, invocation):
-        trackId, position = params
-
-        if self.currentTrack is None:
-            return
-
-        media = self.playlist.get_value(self.currentTrack, self.playlistField)
-        if trackId != '/org/mpris/MediaPlayer2/Track/' + media.get_id():
-            return
-
-        duration = self.player.query_duration(Gst.Format.TIME)
-        if duration and position >= 0 and duration[1] >= position * 1000:
-            self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, position 
* 1000)
-            #self._dbusImpl.emit_signal('Seeked', GLib.Variant.new('(x)', [position]))
-
-    def OpenUriAsync(self, params, invocation):
-        uri = params
-        return uri
+        self.emit('playback-status-changed')
 
     def get_playback_status(self):
         ok, state, pending = self.player.get_state(0)
         if ok == Gst.StateChangeReturn.ASYNC:
             state = pending
         elif (ok != Gst.StateChangeReturn.SUCCESS):
-            return 'Stopped'
+            return PlaybackStatus.STOPPED
 
         if state == Gst.State.PLAYING:
-            return 'Playing'
+            return PlaybackStatus.PLAYING
         elif state == Gst.State.PAUSED:
-            return 'Paused'
+            return PlaybackStatus.PAUSED
         else:
-            return 'Stopped'
+            return PlaybackStatus.STOPPED
 
-    def get_loop_status(self):
-        if self.repeat == RepeatType.NONE:
-            return 'None'
-        elif self.repeat == RepeatType.SONG:
-            return 'Track'
-        else:
-            return 'Playlist'
-
-    def set_loop_status(self, mode):
-        if mode == 'None':
-            self.repeat = RepeatType.NONE
-        elif mode == 'Track':
-            self.repeat = RepeatType.SONG
-        elif mode == 'Playlist':
-            self.repeat = RepeatType.ALL
+    def get_repeat_mode(self):
+        return self.repeat
+
+    def set_repeat_mode(self, mode):
+        self.repeat = mode
         self._sync_repeat_image()
 
-    def get_rate(self):
-        return 1.0
+    def get_position(self):
+        return self.player.query_position(Gst.Format.TIME)[1] / 1000
 
-    def set_rate(self, rate):
-        pass
+    def set_position(self, offset, start_if_ne=False, next_on_overflow=False):
+        if offset < 0:
+            if start_if_ne:
+                offset = 0
+            else:
+                return
 
-    def get_shuffle(self):
-        return self.repeat == RepeatType.SHUFFLE
+        duration = self.player.query_duration(Gst.Format.TIME)
+        if duration is None:
+            return
 
-    def set_shuffle(self, enable):
-        if (enable and self.repeat != RepeatType.SHUFFLE):
-            self.repeat = RepeatType.SHUFFLE
-        elif enable is not None and self.repeat == RepeatType.SHUFFLE:
-            self.repeat = RepeatType.NONE
-        self._sync_repeat_image()
+        if duration[1] >= offset * 1000:
+            self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, offset * 
1000)
+            self.emit('seeked', offset)
+        elif next_on_overflow:
+            self.play_next()
 
     def get_metadata(self):
         if self.currentTrack is None:
-            return
+            return {}
 
         media = self.playlist.get_value(self.currentTrack, self.playlistField)
         metadata = {
-            'mpris:trackid': GLib.Variant.new('s', '/org/mpris/MediaPlayer2/Track/' + media.get_id()),
-            'xesam:url': GLib.Variant.new('s', media.get_url()),
-            'mpris:length': GLib.Variant.new('x', media.get_duration() * 1000000),
-            'xesam:trackNumber': GLib.Variant.new('i', media.get_track_number()),
-            'xesam:useCount': GLib.Variant.new('i', media.get_play_count()),
-            'xesam:userRating': GLib.Variant.new('d', media.get_rating()),
+            'mpris:trackid': '/org/mpris/MediaPlayer2/Track/%s' % media.get_id(),
+            'xesam:url': media.get_url(),
+            'mpris:length': media.get_duration() * 1000000,
+            'xesam:trackNumber': media.get_track_number(),
+            'xesam:useCount': media.get_play_count(),
+            'xesam:userRating': media.get_rating(),
         }
 
         title = AlbumArtCache.get_media_title(media)
         if title:
-            metadata['xesam:title'] = GLib.Variant.new('s', title)
+            metadata['xesam:title'] = title
 
         album = media.get_album()
         if album:
-            metadata['xesam:album'] = GLib.Variant.new('s', album)
+            metadata['xesam:album'] = album
 
         artist = media.get_artist()
         if artist:
-            metadata['xesam:artist'] = GLib.Variant.new('as', [artist])
-            metadata['xesam:albumArtist'] = GLib.Variant.new('as', [artist])
+            metadata['xesam:artist'] = [artist]
+            metadata['xesam:albumArtist'] = [artist]
 
         genre = media.get_genre()
         if genre:
-            metadata['xesam:genre'] = GLib.Variant.new('as', [genre])
+            metadata['xesam:genre'] = [genre]
 
         last_played = media.get_last_played()
         if last_played:
-            metadata['xesam:lastUsed'] = GLib.Variant.new('s', last_played)
+            metadata['xesam:lastUsed'] = last_played
 
         thumbnail = media.get_thumbnail()
         if thumbnail:
-            metadata['mpris:artUrl'] = GLib.Variant.new('s', thumbnail)
+            metadata['mpris:artUrl'] = thumbnail
 
         return metadata
 
@@ -631,34 +542,7 @@ class Player(GObject.GObject):
 
     def set_volume(self, rate):
         self.player.set_volume(GstAudio.StreamVolumeFormat.LINEAR, rate)
-        #self._dbusImpl.emit_property_changed('Volume', GLib.Variant.new('d', rate))
-
-    def get_position(self):
-        return self.player.query_position(Gst.Format.TIME, None)[1] / 1000
-
-    def get_minimum_rate(self):
-        return 1.0
-
-    def get_maximum_rate(self):
-        return 1.0
-
-    def get_can_go_next(self):
-        return self._has_next()
-
-    def get_can_go_previous(self):
-        return self._has_previous()
-
-    def get_can_play(self):
-        return self.currentTrack is not None
-
-    def get_can_pause(self):
-        return self.currentTrack is not None
-
-    def get_can_seek(self):
-        return True
-
-    def get_can_control(self):
-        return True
+        self.emit('volume-changed')
 
 
 class SelectionToolbar():


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