[pkg-fso-commits] [SCM] FSO frameworkd Debian packaging branch, master, updated. milestone4-368-g700ab82

Michael 'Mickey' Lauer mickey at vanille-media.de
Mon Feb 2 18:51:21 UTC 2009


The following commit has been merged in the master branch:
commit 847140750778ce5aa386c3274f47ecb0fc0227d1
Author: Michael 'Mickey' Lauer <mickey at vanille-media.de>
Date:   Fri Nov 21 17:48:51 2008 +0100

    odeviced: fix a couple of problems in the Audio problem and support new features
    such as a loop parameter and an optional length override (time in seconds).
    NOTE: Some codecs (i.e. machine emulators such as siddec) can not find out
    when a song ends, hence it will play forever until you stop it (or give
    it a length override, which is now possible).
    WARNING: API breakage in org.freesmartphone.Device.Audio.PlaySound()
    oeventsd: catch up with API breakage in odeviced/audio
    rules: override length for SID ring and message tunes
    This fixes FSO ticket #247 and the message notification tone only working
    for the first time in ms4(.1)
    NOTE: More stress-tests for the audio API necessary

diff --git a/etc/freesmartphone/opreferences/conf/phone/default.yaml b/etc/freesmartphone/opreferences/conf/phone/default.yaml
index 2d9619b..b552a8a 100644
--- a/etc/freesmartphone/opreferences/conf/phone/default.yaml
+++ b/etc/freesmartphone/opreferences/conf/phone/default.yaml
@@ -1,8 +1,10 @@
-
-
 ring-tone: "Arkanoid_PSID.sid"
 ring-volume: 10
+# SID tunes have no concept of length
+ring-length: 60
 
 message-tone: "Arkanoid_PSID.sid;tune=3"
 message-volume: 10
+# SID tunes have no concept of length
+message-length: 3
 
diff --git a/etc/freesmartphone/opreferences/schema/phone.yaml b/etc/freesmartphone/opreferences/schema/phone.yaml
index 7994e45..dcb742d 100644
--- a/etc/freesmartphone/opreferences/schema/phone.yaml
+++ b/etc/freesmartphone/opreferences/schema/phone.yaml
@@ -7,6 +7,16 @@ ring-volume:
     profilable: yes
     default: 10
 
+ring-loop:
+    type: int
+    profilable: yes
+    default: 0
+
+ring-length:
+    type: int
+    profilable: yes
+    default: 0
+
 message-tone:
     type: str
     profilable: yes
@@ -16,3 +26,13 @@ message-volume:
     profilable: yes
     default: 10
 
+message-loop:
+    type: int
+    profilable: yes
+    default: 0
+
+message-length:
+    type: int
+    profilable: yes
+    default: 0
+
diff --git a/framework/subsystems/odeviced/audio.py b/framework/subsystems/odeviced/audio.py
index 9763d2b..c33c283 100644
--- a/framework/subsystems/odeviced/audio.py
+++ b/framework/subsystems/odeviced/audio.py
@@ -11,7 +11,7 @@ Module: audio
 """
 
 MODULE_NAME = "odeviced.audio"
-__version__ = "0.4.3"
+__version__ = "0.5.0"
 
 from framework.config import config
 from framework.patterns import asyncworker
@@ -151,12 +151,19 @@ class GStreamerPlayer( Player ):
             return True
 
     def _onMessage( self, bus, message, name ):
-        pipeline, status, repeat, ok_cb, error_cb = self.pipelines[name]
+        pipeline, status, loop, length, ok_cb, error_cb = self.pipelines[name]
+        logger.debug( "GST message received while file status = %s" % status )
         t = message.type
         if t == gst.MESSAGE_EOS:
-            logger.debug( "G: EOS" )
-            pipeline.set_state(gst.STATE_NULL)
-            del self.pipelines[name]
+            # shall we restart?
+            if loop:
+                logger.debug( "G: EOS -- restarting stream" )
+                pipeline.seek_simple( gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, 0 )
+            else:
+                logger.debug( "G: EOS" )
+                self._updateSoundStatus( name, "stopped" )
+                pipeline.set_state( gst.STATE_NULL )
+                del self.pipelines[name]
 
         elif t == gst.MESSAGE_ERROR:
             pipeline.set_state(gst.STATE_NULL)
@@ -168,27 +175,47 @@ class GStreamerPlayer( Player ):
         elif t == gst.MESSAGE_STATE_CHANGED:
             previous, current, pending = message.parse_state_changed()
             logger.debug( "G: STATE NOW: (%s) -> %s -> (%s)" % ( previous, current, pending ) )
-            if previous == gst.STATE_PAUSED and current == gst.STATE_PLAYING:
+
+            if ( previous, current, pending ) == ( gst.STATE_READY, gst.STATE_PAUSED, gst.STATE_PLAYING ):
                 self._updateSoundStatus( name, "playing" )
                 ok_cb()
-            elif previous == gst.STATE_PAUSED and current == gst.STATE_PLAYING:
-                self._updateSoundStatus( name, "paused" )
-                # ok_cb()
-            elif previous == gst.STATE_PAUSED and current == gst.STATE_READY:
+                if length:
+                    logger.debug( "adding timeout for %s of %d seconds" % ( name, length ) )
+                    gobject.timeout_add_seconds( length, self._playTimeoutReached, name )
+            elif ( previous, current, pending ) == ( gst.STATE_PLAYING, gst.STATE_PAUSED, gst.STATE_READY ):
                 self._updateSoundStatus( name, "stopped" )
                 pipeline.set_state( gst.STATE_NULL )
                 del self.pipelines[name]
                 # ok_cb()
+            else: # uninteresting state change
+                pass
         else:
             logger.debug( "G: UNHANDLED: %s" % t )
 
+    def _playTimeoutReached( self, name ):
+        try:
+            pipeline, status, loop, length, ok_cb, error_cb = self.pipelines[name]
+        except KeyError: # might have vanished in the meantime?
+            logger.warning( "audio pipeline for %s has vanished before timer could fire" % name )
+            return False
+        previous, current, next = pipeline.get_state()
+        logger.debug( "custom player timeout for %s reached, state is %s" % ( name, current ) )
+        if loop:
+            pipeline.set_state( gst.STATE_NULL )
+            del self.pipelines[name]
+            self.task_play( lambda: None, lambda foo: None, name, loop, length )
+            #pipeline.seek_simple( gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, 0 )
+        else:
+            self.task_stop( lambda: None, lambda foo: None, name )
+        return False # don't call us again, mainloop
+
     def _updateSoundStatus( self, name, newstatus ):
-        pipeline, status, repeat, ok_cb, error_cb = self.pipelines[name]
+        pipeline, status, loop, length, ok_cb, error_cb = self.pipelines[name]
         if newstatus != status:
-            self.pipelines[name] = pipeline, newstatus, repeat, ok_cb, error_cb
+            self.pipelines[name] = pipeline, newstatus, loop, length, ok_cb, error_cb
             self._object.SoundStatus( name, newstatus, {} )
 
-    def task_play( self, ok_cb, error_cb, name, repeat ):
+    def task_play( self, ok_cb, error_cb, name, loop, length ):
         if name in self.pipelines:
             error_cb( AlreadyPlaying( name ) )
         else:
@@ -218,7 +245,7 @@ class GStreamerPlayer( Player ):
                     bus = pipeline.get_bus()
                     bus.add_signal_watch()
                     bus.connect( "message", self._onMessage, name )
-                    self.pipelines[name] = ( pipeline, "unknown", repeat, ok_cb, error_cb )
+                    self.pipelines[name] = ( pipeline, "unknown", loop, length, ok_cb, error_cb )
                     pipeline.set_state( gst.STATE_PLAYING )
 
     def task_stop( self, ok_cb, error_cb, name ):
@@ -355,10 +382,10 @@ class Audio( dbus.service.Object ):
     #
     # dbus sound methods
     #
-    @dbus.service.method( DBUS_INTERFACE, "s", "",
+    @dbus.service.method( DBUS_INTERFACE, "sii", "",
                           async_callbacks=( "dbus_ok", "dbus_error" ) )
-    def PlaySound( self, name, dbus_ok, dbus_error ):
-        self.player.enqueueTask( dbus_ok, dbus_error, "play", name, False )
+    def PlaySound( self, name, loop, length, dbus_ok, dbus_error ):
+        self.player.enqueueTask( dbus_ok, dbus_error, "play", name, loop, length )
 
     @dbus.service.method( DBUS_INTERFACE, "s", "",
                           async_callbacks=( "dbus_ok", "dbus_error" ) )
diff --git a/framework/subsystems/oeventsd/fso_actions.py b/framework/subsystems/oeventsd/fso_actions.py
index 13324b9..04d7c7d 100644
--- a/framework/subsystems/oeventsd/fso_actions.py
+++ b/framework/subsystems/oeventsd/fso_actions.py
@@ -28,10 +28,10 @@ logger = logging.getLogger('oeventsd')
 
 class SetProfile( Action ):
     function_name = 'SetProfile'
-    
+
     def __init__( self, profile ):
         self.profile = profile
-    
+
     @tasklet.tasklet
     def __trigger( self ):
         # We store the current profile
@@ -44,18 +44,18 @@ class SetProfile( Action ):
         self.backup_profile = yield tasklet.WaitDBus( prefs.GetProfile )
         # Then we can set the profile
         yield tasklet.WaitDBus( prefs.SetProfile, self.profile )
-    
+
     def trigger( self, **kargs ):
         self.__trigger().start()
-        
+
     def untrigger( self, **kargs ):
         # TODO: how do we handle the case where we untrigger the action
-        #       before we finish the trigger tasklet ? 
+        #       before we finish the trigger tasklet ?
         SetProfile( self.backup_profile ).trigger()
-        
+
     def __repr__( self ):
         return "SetProfile(%s)" % self.profile
-         
+
 
 #============================================================================#
 class AudioAction(Action):
@@ -63,9 +63,11 @@ class AudioAction(Action):
     """
     A dbus action on the freesmartphone audio device
     """
-    def __init__(self, path):
+    def __init__(self, path, loop=0, length=0):
         super(AudioAction, self).__init__()
         self.path = path
+        self.loop = loop
+        self.length = length
 
     def trigger(self, **kargs):
         DBusAction(
@@ -73,7 +75,7 @@ class AudioAction(Action):
             'org.freesmartphone.odeviced',
             '/org/freesmartphone/Device/Audio',
             'org.freesmartphone.Device.Audio',
-            'PlaySound', self.path).trigger()
+            'PlaySound', self.path, self.loop, self.length).trigger()
 
     def untrigger(self, **kargs):
         DBusAction(
@@ -148,14 +150,14 @@ class VibratorAction(Action):
     def __init__(self, target = 'neo1973_vibrator'):
         self.target = target
     def trigger(self, **kargs):
-        DBusAction(dbus.SystemBus(), 
+        DBusAction(dbus.SystemBus(),
                     'org.freesmartphone.odeviced',
                     '/org/freesmartphone/Device/LED/%s' % self.target,
                     'org.freesmartphone.Device.LED',
                     'SetBlinking', 300, 700).trigger()
 
     def untrigger(self, **kargs):
-        DBusAction(dbus.SystemBus(), 
+        DBusAction(dbus.SystemBus(),
                     'org.freesmartphone.odeviced',
                     '/org/freesmartphone/Device/LED/%s' % self.target,
                     'org.freesmartphone.Device.LED',
@@ -165,7 +167,7 @@ class VibratorAction(Action):
 class RingToneAction(Action):
 #=========================================================================#
     function_name = 'RingTone'
-    
+
     # We need to make DBus calls and wait for the result,
     # So we use a tasklet to avoid blocking the mainloop.
     @tasklet.tasklet
@@ -180,22 +182,25 @@ class RingToneAction(Action):
             '/org/freesmartphone/Preferences'
         )
         prefs = dbus.Interface(prefs, 'org.freesmartphone.Preferences')
-        
+
         phone_prefs = yield tasklet.WaitDBus( prefs.GetService, "phone" )
         phone_prefs = dbus.SystemBus().get_object(
             'org.freesmartphone.opreferencesd',
             phone_prefs
         )
         phone_prefs = dbus.Interface(phone_prefs, 'org.freesmartphone.Preferences.Service')
-        
+
+        # FIXME does that still work if (some of) the entries are missing?
         ring_tone = yield tasklet.WaitDBus( phone_prefs.GetValue, "ring-tone" )
         ring_volume = yield tasklet.WaitDBus( phone_prefs.GetValue, "ring-volume" )
+        ring_loop = yield tasklet.WaitDBus( phone_prefs.GetValue, "ring-loop" )
+        ring_length = yield tasklet.WaitDBus( phone_prefs.GetValue, "ring-length" )
         self.sound_path = os.path.join( installprefix, "share/sounds/", ring_tone )
 
-        logger.info( "Start ringing : tone=%s, volume=%s", ring_tone, ring_volume )
+        logger.info( "Start ringing : tone=%s, volume=%s, loop=%d, length=%d", ring_tone, ring_volume, ring_loop, ring_length )
         # XXX: We don't set the ringing volume.
         #      Here we only disable the ringing action if the volume is 0
-        self.audio_action = AudioAction(self.sound_path) if ring_volume != 0 else None
+        self.audio_action = AudioAction(self.sound_path, ring_loop, ring_length) if ring_volume != 0 else None
         self.vibrator_action = VibratorAction()
 
         if self.audio_action:
@@ -207,7 +212,6 @@ class RingToneAction(Action):
         self.vibrator_action = None
         # Start the tasklet
         self.__trigger().start()
-        
 
     def untrigger(self, **kargs):
         logger.info( "RingToneAction stop" )
@@ -236,22 +240,23 @@ class MessageToneAction(Action):
         phone_prefs = prefs.GetService( "phone" )
         tone = phone_prefs.GetValue( "message-tone" )
         volume = phone_prefs.GetValue( "message-volume" )
+        loop = phone_prefs.GetValue( "message-loop" )
+        length = phone_prefs.GetValue( "message-length" )
         sound_path = os.path.join( installprefix, "share/sounds/", tone )
 
         # XXX: We don't set the ringing volume.
         #      Here we only disable the audio action if the volume is 0
-        self.audio_action = AudioAction(sound_path) if volume != 0 else None
+        self.audio_action = AudioAction(sound_path, loop, length) if volume != 0 else None
         #self.vibrator_action = VibratorAction()
 
-
         if self.cmd == "play":
-            logger.info( "Start ringing : tone=%s, volume=%s", tone, volume )
+            logger.info( "Start message tone : tone=%s, volume=%s, loop=%d, length=%d", tone, volume, loop, length )
             if self.audio_action:
                 self.audio_action.trigger()
             #self.vibrator_action.trigger()
 
         elif self.cmd == "stop":
-            logger.info( "Stop ringing : tone=%s, volume=%s", tone, volume )
+            logger.info( "Stop message tone : tone=%s, volume=%s, loop=%d, length=%d", tone, volume, loop, length )
             if self.audio_action: self.audio_action.untrigger()
             if self.vibrator_action : self.vibrator_action.untrigger()
         else:
@@ -328,7 +333,7 @@ class ExternalDBusAction(DBusAction):
         assert obj is None or isinstance(obj, str), "obj is not str or None"
         assert isinstance(interface, str), "interface is not str"
         assert isinstance(signal, str), "signal is not str"
-        
+
         super(ExternalDBusAction, self).__init__(bus, service, obj, interface, method, *args)
 
     def __repr__( self ):

-- 
FSO frameworkd Debian packaging



More information about the pkg-fso-commits mailing list