It is possible to set an alarm, which will be shown in the alarm window. When
the alarm expires, the phone wakes up if it is suspended, and zavai vibrates,
turns on baclight, shows a big ACK button and flashes the AUX led for 30
- seconds.
+ seconds. It also plays some music.
You can use the big button on screen or the AUX button to acknowledge the
alarm and stop all the attention-seeking activities.
- When I'll implement some audio playing infrastructure, I'll implement playing
- an audio file as well.
+ If you want to change the alarm ringtone, you can set:
+ ringtone_alarm = "file:///some/where/file.ext"
+ in ~/.zavai/config
Alarms (acknowledged or not) are logged in "~/.zavai/log-alarm/". Still
missing, howerver, is a way to show that an alarm rang and noone noticed.
+ start frameworkd as a subprocess, configured to only do phone
+ go through the dbus motions of turning on this and that, and entering PIN
hardcoded in zavai config
- - GSM status on main screen (with messages while coming online, and
+ + GSM status on main screen (with messages while coming online, and
operator, power and so on)
- log and refuse incoming calls and messages
- alarm
- - play sound at alarm trigger
+ + play sound at alarm trigger
- leave expired alarm on screen until acknowledged
(alarm status icon that also brings to alarm menu)
- remember alarm names (on request, maybe with an add feature) and how
often they are triggered, and show them most frequent first
- show active alarms and allow to delete them
+ - fisheye list music player
+ (-> learn/test gstreamer libs)
+ - player page with seek/skip controls
+ - playlist editor
+ - chosen song start playing if nothing is being played
+ - chosen song moves to playlist editor: play, add to playlist, add dir to playlist
+ (show a standard list multiselectable with all the songs in the dir and
+ only the selected song selected; allow to select others, select all, add
+ selected to playlist)
+ - playlist as reorderable standard list, allow to delete tracks, reorder tracks
+ - save playlist to file to reload later
+ - pause with headset button
- audio notes
- record audio notes, logging start and stop so it gets an associated GPX
- shortcut icon in main screen
(-> learn/test libalsamixer something)
/usr/share/vala/vapi/alsa.vapi
- space buttons from sliders, to avoid shutting down instead of lowering the volume
- - fisheye list music player
- (-> learn/test gstreamer libs)
- - player page with seek/skip controls
- - playlist editor
- - chosen song start playing if nothing is being played
- - chosen song moves to playlist editor: play, add to playlist, add dir to playlist
- (show a standard list multiselectable with all the songs in the dir and
- only the selected song selected; allow to select others, select all, add
- selected to playlist)
- - playlist as reorderable standard list, allow to delete tracks, reorder tracks
- - save playlist to file to reload later
- - pause with headset button
- battery without devkit: do the parsing via lua
- contacts: show as a fancy focus+context list (see prefuse)
- vcard on e-vcard.{h,c}
set(zavai_version 0.1)
-set(packages gtk+-2.0 dbus-glib-1>=0.80 libwnck-1.0>=2.26.0 lua5.1 libomhacks x11 gdk-x11-2.0 libgps)
+set(packages gtk+-2.0 dbus-glib-1>=0.80 libwnck-1.0>=2.26.0 lua5.1 libomhacks x11 gdk-x11-2.0 libgps gstreamer-0.10)
add_packages(ZAVAI ${packages})
set(VALA_PACKAGES ${packages} posix linux-input dbus-extra gtkfisheyelist)
/*
* app - zavai main window
*
- * 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
pack_start(status_icons, false, false, 0);
pack_start(clock, false, false, 0);
pack_start(gsm_status, false, false, 0);
+ // pack_start(music.player, false, false, 0);
pack_end(menu, false, false, 0);
zavai.gsm.gsm.status_changed += (msg) => { gsm_status.set_text(msg); };
--- /dev/null
+/*
+ * app_music - zavai music player UI functions
+ *
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+using GLib;
+
+namespace zavai {
+namespace ui {
+namespace music {
+
+public class PlayPauseButton : Gtk.Button
+{
+ protected Gtk.Image img_play;
+ protected Gtk.Image img_pause;
+ protected bool is_play;
+
+ construct
+ {
+ img_play = new Gtk.Image.from_stock(Gtk.STOCK_MEDIA_PLAY, Gtk.IconSize.BUTTON);
+ img_pause = new Gtk.Image.from_stock(Gtk.STOCK_MEDIA_PAUSE, Gtk.IconSize.BUTTON);
+
+ clicked += on_clicked;
+
+ is_play = audio.musicplayer.get_state() == Gst.State.PAUSED;
+
+ audio.musicplayer.state_changed += (state) => {
+ if (is_play != (state == Gst.State.PAUSED))
+ {
+ is_play = !is_play;
+ update_image();
+ }
+ };
+
+ update_image();
+ }
+
+ protected void update_image()
+ {
+ if (is_play)
+ {
+ set_image(img_play);
+ } else {
+ set_image(img_pause);
+ }
+ }
+
+ void on_clicked(Gtk.Button b)
+ {
+ if (is_play)
+ audio.musicplayer.pause();
+ else
+ audio.musicplayer.resume();
+ }
+}
+
+public class Player : Gtk.VBox
+{
+ protected Gtk.Label l_status;
+ protected PlayPauseButton b_playpause;
+ protected Gtk.Button b_stop;
+ protected Gtk.Button b_prev;
+ protected Gtk.Button b_next;
+
+ construct
+ {
+ l_status = new Gtk.Label("");
+ //l_date.modify_font(Pango.FontDescription.from_string("Sans 40"));
+ b_playpause = new PlayPauseButton();
+ b_stop = new Gtk.Button.from_stock(Gtk.STOCK_MEDIA_STOP);
+ b_stop.clicked += (b) => { audio.musicplayer.stop(); };
+ b_prev = new Gtk.Button.from_stock(Gtk.STOCK_MEDIA_PREVIOUS);
+ b_next = new Gtk.Button.from_stock(Gtk.STOCK_MEDIA_NEXT);
+ pack_start(l_status, false, false, 0);
+ var buttons = new Gtk.HButtonBox();
+ buttons.add(b_prev);
+ buttons.add(b_playpause);
+ buttons.add(b_stop);
+ buttons.add(b_next);
+ pack_start(buttons, false, false, 0);
+
+ //zavai.clock.clock.minute_changed += on_minute_changed;
+ //zavai.clock.clock.schedule_changed += on_schedule_changed;
+ //on_schedule_changed(zavai.clock.clock.next_alarm());
+ }
+
+#if 0
+ private void on_date_clicked(Gtk.Button b)
+ {
+ zavai.app.push_applet(zavai.ui.calendar.calendar);
+ }
+
+ private void on_schedule_changed(zavai.clock.Alarm? next)
+ {
+ if (next == null)
+ {
+ last_deadline = 0;
+ last_deadline_label = "";
+ } else {
+ last_deadline = next.ev.deadline;
+ last_deadline_label = next.label;
+ }
+ on_minute_changed((long)last_time, last_time_type);
+ }
+
+ private void on_minute_changed(long ts, zavai.clock.SourceType type)
+ {
+ last_time = (time_t)ts;
+ last_time_type = type;
+
+ string typetag = "unknown";
+ switch (type)
+ {
+ case zavai.clock.SourceType.GPS:
+ typetag = "gps";
+ break;
+ case zavai.clock.SourceType.SYSTEM:
+ typetag = "sys";
+ break;
+ }
+
+ var t = Time.local((time_t)ts);
+ l_date.set_text(t.format("%a %d %b"));
+ l_time.set_text("%2d:%02d (%s)".printf(t.hour, t.minute, typetag));
+
+ if (last_deadline == 0)
+ l_deadline.set_text("");
+ else
+ {
+ int remaining = (int)(last_deadline - last_time);
+ int hours = remaining / 3600;
+ int minutes = (remaining % 3600) / 60;
+ if (hours == 0 && minutes == 0)
+ l_deadline.set_text(last_deadline_label + "\nanytime now");
+ else
+ l_deadline.set_text("%s\nin %02dh %02dm".printf(last_deadline_label, hours, minutes));
+ }
+ }
+#endif
+}
+
+public Player player = null;
+
+public void init()
+{
+ player = new Player();
+ // Menus
+ //zavai.menu_gsm.add_service_toggle(zavai.gsm.gsm, "Start GSM", "Stop GSM");
+ //zavai.menu_gsm.add_service_toggle(zavai.gsm.gprs, "Start GPRS", "Stop GPRS");
+}
+
+}
+}
+}
{
protected Omhacks.Led vibrator;
protected bool has_vibrator;
+
/*
protected dynamic DBus.Object audiodev;
protected dynamic DBus.Object vibdev;
"/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 (has_vibrator)
{
- vibrator.trigger[i] = (char)trig[i];
- if (trig[i] == 0) break;
+ 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)
+ {
+ vibrator.trigger[i] = (char)trig[i];
+ if (trig[i] == 0) break;
+ }
+ vibrator.delay_on = 200;
+ vibrator.delay_off = 300;
+ vibrator.set();
}
- 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)
+ zavai.log.debug("Stop noise for alarm");
+ if (has_vibrator)
{
- vibrator.trigger[i] = (char)trig[i];
- if (trig[i] == 0) break;
+ var trig = "none";
+ for (int i = 0; ; ++i)
+ {
+ vibrator.trigger[i] = (char)trig[i];
+ if (trig[i] == 0) break;
+ }
+ vibrator.brightness = 0;
+ vibrator.set();
}
- vibrator.brightness = 0;
- vibrator.set();
+ soundplayer.stop();
}
/*
*/
}
+public class Player: zavai.Resource, Object
+{
+ protected Gst.Element player;
+ 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()
+ {
+ slave = null;
+ 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;
+ }
+
+ public void set_slave(Player player)
+ {
+ slave = player;
+ slave.master = this;
+ }
+
+ 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)
+ slave.resume();
+ }
+
+ protected void on_message(Gst.Message message)
+ {
+ if (message.type == Gst.MessageType.EOS)
+ {
+ if (loop)
+ restart();
+ else
+ stop();
+ }
+ }
+
+ public void shutdown()
+ {
+ stop();
+ }
+}
+
public Audio audio = null;
+public Player musicplayer = null;
+public Player soundplayer = null;
public void init()
{
audio = new Audio();
+ musicplayer = new Player();
+ soundplayer = new Player();
+ soundplayer.set_slave(musicplayer);
+ zavai.registry.register(musicplayer);
+ zavai.registry.register(soundplayer);
}
}
/*
* config - zavai configuration
*
- * 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
set { _aux_button_keycode = set_int("aux_button_keycode", value); }
}
+ private string _ringtone_alarm;
+ public string ringtone_alarm
+ {
+ get { return _ringtone_alarm; }
+ set { _ringtone_alarm = set_string("ringtone_alarm", value); }
+ }
+
public int backlight_max
{
get;
_sim_pin = get_string("sim_pin");
_power_button_keycode = get_int("power_button_keycode");
_aux_button_keycode = get_int("aux_button_keycode");
+ _ringtone_alarm = get_string("ringtone_alarm");
}
public Config()
backlight_max = 15;
power_button_keycode = 124;
aux_button_keycode = 177;
+ ringtone_alarm = "file:///usr/share/sounds/yue-fso/lec1.ogg";
// Read config
if (lua.do_file(homedir + "/config"))
static int main (string[] args) {
Gtk.init (ref args);
+ Gst.init (ref args);
// parser = Parser(usage="usage: %prog [options]",
// version="%prog "+ VERSION,
*/
// User interface
+ zavai.ui.music.init();
zavai.ui.main.init();
zavai.ui.gps.init();
zavai.ui.gsm.init();
zavai.clock.alarm_trigger_queue.enqueue_trigger(alarm);
}
+ if (args.length > 2 && args[1] == "play")
+ {
+ zavai.audio.musicplayer.play("file://" + args[2]);
+
+ // Timeout.add(3 * 1000, () => {
+ // zavai.audio.soundplayer.play("file:///backup/ciapino/src/openmoocow/data/moo.wav", true);
+ // Timeout.add(4 * 1000, () => {
+ // zavai.audio.soundplayer.stop();
+ // return false;
+ // });
+ // return false;
+ // });
+ }
+
Gtk.main();
// zavai.info("Shutting down")