Stacked sound player works
[gregoa/zavai.git] / src / audio.vala
index 7639bcb3080584e835054f3b25f4cea33a2b9f28..51790d0aed63f4d05da2422febda74f0092175c8 100644 (file)
@@ -23,217 +23,226 @@ using GLib;
 namespace zavai {
 namespace audio {
 
-public class VibratorState
+public class Audio: zavai.Service
 {
-    public string name;
-    public int brightness;
-    public string trigger;
-    public int delay_on;
-    public int delay_off;
+    /*
+       protected dynamic DBus.Object audiodev;
+       protected dynamic DBus.Object vibdev;
+   */
 
-    public VibratorState(string name)
+    public Audio()
     {
-        this.name = name;
-        set_constant(0);
+        Object(name: "audio");
+
+/*
+        audiodev = zavai.registry.sbus.get_object(
+                "org.freesmartphone.odeviced",
+                "/org/freesmartphone/Device/Audio",
+                "org.freesmartphone.Device.Audio");
+        vibdev = zavai.registry.sbus.get_object(
+                "org.freesmartphone.odeviced",
+                "/org/freesmartphone/Device/LED/neo1973_vibrator",
+                "org.freesmartphone.Device.LED");
+*/
     }
+}
+
+public class PlayerState : Object
+{
+    protected SoundPlayer soundplayer;
+    protected Gst.Element player;
+    public string owner;
+    public string uri;
+    public bool loop;
 
-    public void set_constant(int power)
+    public PlayerState(string owner, string uri, bool loop=false)
     {
-        brightness = power;
-        trigger = "none";
-        delay_on = 0;
-        delay_off = 0;
+        soundplayer = null;
+
+        this.owner = owner;
+        this.uri = uri;
+        this.loop = loop;
+
+        player = Gst.ElementFactory.make("playbin", null);
+        var bus = player.get_bus();
+        bus.add_signal_watch();
+        bus.message += on_message;
+
+        player.set_property("uri", uri);
+        player.set_state(Gst.State.PAUSED);
     }
 
-    public void set_blink(int power, int delay_on=200, int delay_off=300)
+    public void register(SoundPlayer sp)
     {
-        brightness = power;
-        trigger = "timer";
-        this.delay_on = delay_on;
-        this.delay_off = delay_off;
+        soundplayer = sp;
     }
 
-    public void to_omhacks(ref Omhacks.Led led)
+    public void stop()
     {
-        led.brightness = brightness;
-        Memory.copy(led.trigger, trigger, trigger.size());
-        led.delay_on = 200;
-        led.delay_off = 300;
+        player.set_state(Gst.State.NULL);
+    }
+
+    public void pause()
+    {
+        player.set_state(Gst.State.PAUSED);
+    }
+
+    public void resume()
+    {
+        player.set_state(Gst.State.PLAYING);
+    }
+
+    protected void on_message(Gst.Message message)
+    {
+        if (message.type == Gst.MessageType.EOS)
+        {
+            if (loop)
+            {
+                player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
+                player.set_state(Gst.State.PLAYING);
+            }
+            else if (soundplayer != null)
+                soundplayer.pop_state(owner);
+        }
     }
 }
 
-public class Vibrator : zavai.Resource, Object
+public class SoundPlayer : zavai.Resource, Object
 {
-    protected Omhacks.Led vibrator;
+    protected List<PlayerState> states;
+    protected MusicPlayer slave;
+    protected bool slave_was_playing;
 
-    protected List<VibratorState> states;
+    public SoundPlayer()
+    {
+        states = new List<PlayerState>();
+    }
 
-    public Vibrator() throws FileError
+    public void set_slave(MusicPlayer player)
     {
-        if (vibrator.init("neo1973:vibrator") != 0)
-            throw new FileError.NOENT("vibrator not found");
+        slave = player;
+        slave.master = this;
+    }
 
-        states = new List<VibratorState>();
+    public bool playing()
+    {
+        return states != null;
     }
 
-    public void turn_off()
+    protected void stop_playing()
     {
-        vibrator.brightness = 0;
-        Memory.copy(vibrator.trigger, "none", 5);
-        vibrator.set();
+        if (slave_was_playing)
+            slave.resume();
     }
 
-    public void push_state(VibratorState state)
+    public void push_state(PlayerState state)
     {
+        // Save current playing position
+        if (states == null)
+        {
+            // We start playing: see about preempting slave
+            slave_was_playing = (slave != null && slave.playing);
+            if (slave_was_playing)
+                slave.pause();
+        } else
+            // We were playing: pause previous sound
+            states.data.pause();
+        state.register(this);
         states.prepend(state);
-        state.to_omhacks(ref vibrator);
-        vibrator.set();
+        states.data.resume();
     }
 
-    public void pop_state(string name)
+    public void pop_state(string owner)
     {
         // Handle empty list
         if (states == null) return;
 
         // Track if the list head changed
-        weak List<VibratorState> old_top = states;
+        weak List<PlayerState> 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)
+        for (weak List<PlayerState> i = states; i != null; i = i.next)
+            if (i.data.owner == owner)
             {
+                i.data.stop();
                 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();
-            }
+                stop_playing();
+            else
+                states.data.resume();
+        }
     }
 
     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;
-   */
-
-    public Audio()
-    {
-        Object(name: "audio");
-
-/*
-        audiodev = zavai.registry.sbus.get_object(
-                "org.freesmartphone.odeviced",
-                "/org/freesmartphone/Device/Audio",
-                "org.freesmartphone.Device.Audio");
-        vibdev = zavai.registry.sbus.get_object(
-                "org.freesmartphone.odeviced",
-                "/org/freesmartphone/Device/LED/neo1973_vibrator",
-                "org.freesmartphone.Device.LED");
-*/
-        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("Make noise for alarm");
-        if (vibrator != null)
         {
-            var state = new VibratorState("alarm");
-            state.set_blink(255);
-            vibrator.push_state(state);
+            states.data.stop();
+            states.delete_link(states);
         }
-        soundplayer.play(config.ringtone_alarm, true);
-    }
-
-    public void on_alarm_done(clock.AlarmTriggerInfo info)
-    {
-        zavai.log.debug("Stop noise for alarm");
-        if (vibrator != null)
-            vibrator.pop_state("alarm");
-        soundplayer.stop();
+        stop_playing();
     }
 }
 
-public class Player: zavai.Resource, Object
+public class MusicPlayer: zavai.Resource, Object
 {
     protected Gst.Element player;
-    protected bool playing;
-    protected Player slave;
-    protected Player master;
-    protected bool loop;
-    protected string uri;
+    public SoundPlayer master;
     public signal void state_changed(Gst.State new_state);
+    public string uri;
+    public bool playing;
 
-    public Player()
+    public MusicPlayer()
     {
-        slave = null;
         master = null;
-        player = Gst.ElementFactory.make("playbin", null);
+        uri = null;
         playing = false;
-        loop = false;
+        player = Gst.ElementFactory.make("playbin", null);
         var bus = player.get_bus();
         bus.add_signal_watch();
         bus.message += on_message;
     }
 
-    public void set_slave(Player player)
+    public void play(string uri)
     {
-        slave = player;
-        slave.master = this;
+        this.uri = uri;
+        playing = true;
+        player.set_property("uri", uri);
+        player.set_state(master != null && master.playing() ? Gst.State.PAUSED : Gst.State.PLAYING);
     }
 
-    public void play(string uri, bool loop = false)
+    protected void stop_playing()
     {
-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;
+        player.set_state(Gst.State.NULL);
+        state_changed(Gst.State.NULL);
     }
 
     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;
+        return player.current_state;
     }
 
     public void pause()
     {
+        playing = false;
         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);
+        playing = true;
+        if (master == null || !master.playing())
+        {
+            player.set_state(Gst.State.PLAYING);
+            state_changed(Gst.State.PLAYING);
+        }
     }
 
     public void restart()
@@ -243,51 +252,30 @@ stderr.printf("Playing %s\n", uri);
         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)
-            slave.resume();
-    }
-
     protected void on_message(Gst.Message message)
     {
         if (message.type == Gst.MessageType.EOS)
         {
-            if (loop)
-                restart();
-            else
-                stop();
+            playing = false;
+            stop_playing();
         }
     }
 
     public void shutdown()
     {
-        stop();
+        stop_playing();
     }
 }
 
-public Vibrator vibrator = null;
 public Audio audio = null;
-public Player musicplayer = null;
-public Player soundplayer = null;
+public SoundPlayer soundplayer = null;
+public MusicPlayer musicplayer = 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();
+    musicplayer = new MusicPlayer();
+    soundplayer = new SoundPlayer();
     soundplayer.set_slave(musicplayer);
     zavai.registry.register(musicplayer);
     zavai.registry.register(soundplayer);