[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