/*
* audio - audio resource for zavai
*
- * Copyright (C) 2009 Enrico Zini <enrico@enricozini.org>
+ * Copyright (C) 2009--2010 Enrico Zini <enrico@enricozini.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
public class Audio: zavai.Service
{
- protected dynamic DBus.Object audiodev;
- protected dynamic DBus.Object vibdev;
-
- public Audio()
- {
- name = "audio";
- audiodev = zavai.registry.sbus.get_object(
- "org.freesmartphone.odeviced",
- "/org/freesmartphone/Device/Audio",
- "org.freesmartphone.Device.Audio");
+ /*
+ 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");
- }
-
- public void notify_alarm(zavai.clock.Alarm a)
- {
- // Wiggle screen to turn on backlight
- zavai.ui.power.backlight.wiggle();
- try {
- vibdev.BlinkSeconds(2, 500, 200);
- } catch (Error e) {
- zavai.log.error("Cannot blink vibrator: " + e.message);
+ "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 PlayerState(string owner, string uri, bool loop=false)
+ {
+ 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 register(SoundPlayer sp)
+ {
+ soundplayer = sp;
+ }
+
+ public void stop()
+ {
+ 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 SoundPlayer : zavai.Resource, Object
+{
+ protected List<PlayerState> states;
+ protected MusicPlayer slave;
+ protected bool slave_was_playing;
+
+ public SoundPlayer()
+ {
+ states = new List<PlayerState>();
+ }
+
+ public void set_slave(MusicPlayer player)
+ {
+ slave = player;
+ slave.master = this;
+ }
+
+ public bool playing()
+ {
+ return states != null;
+ }
+
+ protected void stop_playing()
+ {
+ if (slave_was_playing)
+ slave.resume();
+ }
+
+ 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);
+ states.data.resume();
+ }
+
+ public void pop_state(string owner)
+ {
+ // Handle empty list
+ if (states == null) return;
+
+ // Track if the list head changed
+ weak List<PlayerState> old_top = states;
+
+ // Remove state "name" from the stack
+ 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)
+ stop_playing();
+ else
+ states.data.resume();
+ }
+ }
+
+ public void shutdown()
+ {
+ while (states != null)
+ {
+ states.data.stop();
+ states.delete_link(states);
}
+ stop_playing();
+ }
+}
+
+public class MusicPlayer: zavai.Resource, Object
+{
+ protected Gst.Element player;
+ public SoundPlayer master;
+ public signal void state_changed(Gst.State new_state);
+ public string uri;
+ public bool playing;
+
+ public MusicPlayer()
+ {
+ master = null;
+ uri = null;
+ playing = false;
+ player = Gst.ElementFactory.make("playbin", null);
+ var bus = player.get_bus();
+ bus.add_signal_watch();
+ bus.message += on_message;
+ }
+
+ public void play(string uri)
+ {
+ this.uri = uri;
+ playing = true;
+ player.set_property("uri", uri);
+ player.set_state(master != null && master.playing() ? Gst.State.PAUSED : Gst.State.PLAYING);
+ }
+
+ protected void stop_playing()
+ {
+ player.set_state(Gst.State.NULL);
+ state_changed(Gst.State.NULL);
+ }
+
+ public Gst.State get_state()
+ {
+ return player.current_state;
+ }
+
+ public void pause()
+ {
+ playing = false;
+ player.set_state(Gst.State.PAUSED);
+ state_changed(Gst.State.PAUSED);
+ }
+
+ public void resume()
+ {
+ playing = true;
+ if (master == null || !master.playing())
+ {
+ 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);
+ }
+
+ protected void on_message(Gst.Message message)
+ {
+ if (message.type == Gst.MessageType.EOS)
+ {
+ playing = false;
+ stop_playing();
+ }
+ }
+
+ public void shutdown()
+ {
+ stop_playing();
}
}
public Audio audio = null;
+public SoundPlayer soundplayer = null;
+public MusicPlayer musicplayer = null;
public void init()
{
audio = new Audio();
-
- zavai.registry.register_service(audio);
+ musicplayer = new MusicPlayer();
+ soundplayer = new SoundPlayer();
+ soundplayer.set_slave(musicplayer);
+ zavai.registry.register(musicplayer);
+ zavai.registry.register(soundplayer);
}
}