Redone vibrator in a stackable way
[gregoa/zavai.git] / src / audio.vala
index e6dba6208b60b13d5aae2f52c6ea684d19d9efc5..7639bcb3080584e835054f3b25f4cea33a2b9f28 100644 (file)
@@ -23,11 +23,110 @@ using GLib;
 namespace zavai {
 namespace audio {
 
-public class Audio: zavai.Service
+public class VibratorState
+{
+    public string name;
+    public int brightness;
+    public string trigger;
+    public int delay_on;
+    public int delay_off;
+
+    public VibratorState(string name)
+    {
+        this.name = name;
+        set_constant(0);
+    }
+
+    public void set_constant(int power)
+    {
+        brightness = power;
+        trigger = "none";
+        delay_on = 0;
+        delay_off = 0;
+    }
+
+    public void set_blink(int power, int delay_on=200, int delay_off=300)
+    {
+        brightness = power;
+        trigger = "timer";
+        this.delay_on = delay_on;
+        this.delay_off = delay_off;
+    }
+
+    public void to_omhacks(ref Omhacks.Led led)
+    {
+        led.brightness = brightness;
+        Memory.copy(led.trigger, trigger, trigger.size());
+        led.delay_on = 200;
+        led.delay_off = 300;
+    }
+}
+
+public class Vibrator : zavai.Resource, Object
 {
     protected Omhacks.Led vibrator;
-    protected bool has_vibrator;
 
+    protected List<VibratorState> states;
+
+    public Vibrator() throws FileError
+    {
+        if (vibrator.init("neo1973:vibrator") != 0)
+            throw new FileError.NOENT("vibrator not found");
+
+        states = new List<VibratorState>();
+    }
+
+    public void turn_off()
+    {
+        vibrator.brightness = 0;
+        Memory.copy(vibrator.trigger, "none", 5);
+        vibrator.set();
+    }
+
+    public void push_state(VibratorState state)
+    {
+        states.prepend(state);
+        state.to_omhacks(ref vibrator);
+        vibrator.set();
+    }
+
+    public void pop_state(string name)
+    {
+        // Handle empty list
+        if (states == null) return;
+
+        // Track if the list head changed
+        weak List<VibratorState> old_top = states;
+
+        // Remove state "name" from the stack
+        for (weak List<VibratorState> i = states; i != null; i = i.next)
+            if (i.data.name == name)
+            {
+                states.delete_link(i);
+                break;
+            }
+
+        // If the list head changed, put into action the new top state
+        if (states != old_top)
+            if (states == null)
+                turn_off();
+            else {
+                // Activate the new top
+                states.data.to_omhacks(ref vibrator);
+                vibrator.set();
+            }
+    }
+
+    public void shutdown()
+    {
+        while (states != null)
+            states.delete_link(states);
+        turn_off();
+    }
+}
+
+public class Audio: zavai.Service
+{
     /*
        protected dynamic DBus.Object audiodev;
        protected dynamic DBus.Object vibdev;
@@ -37,8 +136,6 @@ public class Audio: zavai.Service
     {
         Object(name: "audio");
 
-        has_vibrator = (vibrator.init("neo1973:vibrator") == 0);
-
 /*
         audiodev = zavai.registry.sbus.get_object(
                 "org.freesmartphone.odeviced",
@@ -49,61 +146,30 @@ public class Audio: zavai.Service
                 "/org/freesmartphone/Device/LED/neo1973_vibrator",
                 "org.freesmartphone.Device.LED");
 */
-        if (has_vibrator)
-        {
-            zavai.log.warning("audio: can notify alarm triggers");
-            clock.alarm_trigger_queue.triggered += on_alarm_trigger;
-            clock.alarm_trigger_queue.acked += on_alarm_done;
-            clock.alarm_trigger_queue.canceled += on_alarm_done;
-        } else {
-            zavai.log.warning("audio: no way to notify alarm triggers");
-        }
+        clock.alarm_trigger_queue.triggered += on_alarm_trigger;
+        clock.alarm_trigger_queue.acked += on_alarm_done;
+        clock.alarm_trigger_queue.canceled += on_alarm_done;
     }
 
     public void on_alarm_trigger(clock.AlarmTriggerInfo info)
     {
-        zavai.log.debug("Start vibrator");
-        vibrator.brightness = 256;
-        // FIXME: is there a better way? I hope there is a better way. Please
-        // tell me there is a better way.
-        var trig = "timer";
-        for (int i = 0; ; ++i)
+        zavai.log.debug("Make noise for alarm");
+        if (vibrator != null)
         {
-            vibrator.trigger[i] = (char)trig[i];
-            if (trig[i] == 0) break;
+            var state = new VibratorState("alarm");
+            state.set_blink(255);
+            vibrator.push_state(state);
         }
-        vibrator.delay_on = 200;
-        vibrator.delay_off = 300;
-        vibrator.set();
+        soundplayer.play(config.ringtone_alarm, true);
     }
 
     public void on_alarm_done(clock.AlarmTriggerInfo info)
     {
-        zavai.log.debug("Stop vibrator");
-        var trig = "none";
-        for (int i = 0; ; ++i)
-        {
-            vibrator.trigger[i] = (char)trig[i];
-            if (trig[i] == 0) break;
-        }
-        vibrator.brightness = 0;
-        vibrator.set();
-    }
-
-/*
-    public void notify_alarm(zavai.clock.Alarm a)
-    {
-        // Wiggle screen to turn on backlight
-        zavai.ui.power.backlight.wiggle();
-        try {
-            // Method does not exist in this frameworkd
-            vibdev.BlinkSeconds(5, 500, 200);
-        } catch (Error e) {
-            zavai.log.error("Cannot blink vibrator: " + e.message);
-        }
-        // TODO: play music?
+        zavai.log.debug("Stop noise for alarm");
+        if (vibrator != null)
+            vibrator.pop_state("alarm");
+        soundplayer.stop();
     }
-*/
 }
 
 public class Player: zavai.Resource, Object
@@ -112,6 +178,9 @@ public class Player: zavai.Resource, Object
     protected bool playing;
     protected Player slave;
     protected Player master;
+    protected bool loop;
+    protected string uri;
+    public signal void state_changed(Gst.State new_state);
 
     public Player()
     {
@@ -119,6 +188,7 @@ public class Player: zavai.Resource, Object
         master = null;
         player = Gst.ElementFactory.make("playbin", null);
         playing = false;
+        loop = false;
         var bus = player.get_bus();
         bus.add_signal_watch();
         bus.message += on_message;
@@ -130,30 +200,54 @@ public class Player: zavai.Resource, Object
         slave.master = this;
     }
 
-    public void play(string uri)
+    public void play(string uri, bool loop = false)
     {
+stderr.printf("Playing %s\n", uri);
+        this.uri = uri;
+
         if (slave != null && slave.playing)
             slave.pause();
 
         player.set_property("uri", uri);
         player.set_state(master != null && master.playing ? Gst.State.PAUSED : Gst.State.PLAYING);
         playing = true;
+        this.loop = loop;
+    }
+
+    public Gst.State get_state()
+    {
+        Gst.State state;
+        Gst.State pending;
+
+        player.get_state(out state, out pending, (Gst.ClockType)Gst.CLOCK_TIME_NONE);
+
+        return state;
     }
 
     public void pause()
     {
         player.set_state(Gst.State.PAUSED);
+        state_changed(Gst.State.PAUSED);
     }
 
     public void resume()
     {
         player.set_state(Gst.State.PLAYING);
+        state_changed(Gst.State.PLAYING);
+    }
+
+    public void restart()
+    {
+        player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
+        player.set_state(Gst.State.PLAYING);
+        state_changed(Gst.State.PLAYING);
     }
 
     public void stop()
     {
         playing = false;
         player.set_state(Gst.State.NULL);
+        state_changed(Gst.State.NULL);
 
         // Resume slave after we are done
         if (slave != null && slave.playing)
@@ -163,7 +257,12 @@ public class Player: zavai.Resource, Object
     protected void on_message(Gst.Message message)
     {
         if (message.type == Gst.MessageType.EOS)
-            stop();
+        {
+            if (loop)
+                restart();
+            else
+                stop();
+        }
     }
 
     public void shutdown()
@@ -172,12 +271,20 @@ public class Player: zavai.Resource, Object
     }
 }
 
+public Vibrator vibrator = null;
 public Audio audio = null;
 public Player musicplayer = null;
 public Player soundplayer = null;
 
 public void init()
 {
+    try {
+        vibrator = new Vibrator();
+        zavai.registry.register(vibrator);
+    } catch (Error e) {
+        zavai.log.info("No vibrator found");
+        vibrator = null;
+    }
     audio = new Audio();
     musicplayer = new Player();
     soundplayer = new Player();