Redone vibrator in a stackable way
[gregoa/zavai.git] / src / audio.vala
1 /*
2  * audio - audio resource for zavai
3  *
4  * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace zavai {
24 namespace audio {
25
26 public class VibratorState
27 {
28     public string name;
29     public int brightness;
30     public string trigger;
31     public int delay_on;
32     public int delay_off;
33
34     public VibratorState(string name)
35     {
36         this.name = name;
37         set_constant(0);
38     }
39
40     public void set_constant(int power)
41     {
42         brightness = power;
43         trigger = "none";
44         delay_on = 0;
45         delay_off = 0;
46     }
47
48     public void set_blink(int power, int delay_on=200, int delay_off=300)
49     {
50         brightness = power;
51         trigger = "timer";
52         this.delay_on = delay_on;
53         this.delay_off = delay_off;
54     }
55
56     public void to_omhacks(ref Omhacks.Led led)
57     {
58         led.brightness = brightness;
59         Memory.copy(led.trigger, trigger, trigger.size());
60         led.delay_on = 200;
61         led.delay_off = 300;
62     }
63 }
64
65 public class Vibrator : zavai.Resource, Object
66 {
67     protected Omhacks.Led vibrator;
68
69     protected List<VibratorState> states;
70
71     public Vibrator() throws FileError
72     {
73         if (vibrator.init("neo1973:vibrator") != 0)
74             throw new FileError.NOENT("vibrator not found");
75
76         states = new List<VibratorState>();
77     }
78
79     public void turn_off()
80     {
81         vibrator.brightness = 0;
82         Memory.copy(vibrator.trigger, "none", 5);
83         vibrator.set();
84     }
85
86     public void push_state(VibratorState state)
87     {
88         states.prepend(state);
89         state.to_omhacks(ref vibrator);
90         vibrator.set();
91     }
92
93     public void pop_state(string name)
94     {
95         // Handle empty list
96         if (states == null) return;
97
98         // Track if the list head changed
99         weak List<VibratorState> old_top = states;
100
101         // Remove state "name" from the stack
102         for (weak List<VibratorState> i = states; i != null; i = i.next)
103             if (i.data.name == name)
104             {
105                 states.delete_link(i);
106                 break;
107             }
108
109         // If the list head changed, put into action the new top state
110         if (states != old_top)
111             if (states == null)
112                 turn_off();
113             else {
114                 // Activate the new top
115                 states.data.to_omhacks(ref vibrator);
116                 vibrator.set();
117             }
118     }
119
120     public void shutdown()
121     {
122         while (states != null)
123             states.delete_link(states);
124         turn_off();
125     }
126 }
127
128 public class Audio: zavai.Service
129 {
130     /*
131        protected dynamic DBus.Object audiodev;
132        protected dynamic DBus.Object vibdev;
133    */
134
135     public Audio()
136     {
137         Object(name: "audio");
138
139 /*
140         audiodev = zavai.registry.sbus.get_object(
141                 "org.freesmartphone.odeviced",
142                 "/org/freesmartphone/Device/Audio",
143                 "org.freesmartphone.Device.Audio");
144         vibdev = zavai.registry.sbus.get_object(
145                 "org.freesmartphone.odeviced",
146                 "/org/freesmartphone/Device/LED/neo1973_vibrator",
147                 "org.freesmartphone.Device.LED");
148 */
149         clock.alarm_trigger_queue.triggered += on_alarm_trigger;
150         clock.alarm_trigger_queue.acked += on_alarm_done;
151         clock.alarm_trigger_queue.canceled += on_alarm_done;
152     }
153
154     public void on_alarm_trigger(clock.AlarmTriggerInfo info)
155     {
156         zavai.log.debug("Make noise for alarm");
157         if (vibrator != null)
158         {
159             var state = new VibratorState("alarm");
160             state.set_blink(255);
161             vibrator.push_state(state);
162         }
163         soundplayer.play(config.ringtone_alarm, true);
164     }
165
166     public void on_alarm_done(clock.AlarmTriggerInfo info)
167     {
168         zavai.log.debug("Stop noise for alarm");
169         if (vibrator != null)
170             vibrator.pop_state("alarm");
171         soundplayer.stop();
172     }
173 }
174
175 public class Player: zavai.Resource, Object
176 {
177     protected Gst.Element player;
178     protected bool playing;
179     protected Player slave;
180     protected Player master;
181     protected bool loop;
182     protected string uri;
183     public signal void state_changed(Gst.State new_state);
184
185     public Player()
186     {
187         slave = null;
188         master = null;
189         player = Gst.ElementFactory.make("playbin", null);
190         playing = false;
191         loop = false;
192         var bus = player.get_bus();
193         bus.add_signal_watch();
194         bus.message += on_message;
195     }
196
197     public void set_slave(Player player)
198     {
199         slave = player;
200         slave.master = this;
201     }
202
203     public void play(string uri, bool loop = false)
204     {
205 stderr.printf("Playing %s\n", uri);
206         this.uri = uri;
207
208         if (slave != null && slave.playing)
209             slave.pause();
210
211         player.set_property("uri", uri);
212         player.set_state(master != null && master.playing ? Gst.State.PAUSED : Gst.State.PLAYING);
213         playing = true;
214         this.loop = loop;
215     }
216
217     public Gst.State get_state()
218     {
219         Gst.State state;
220         Gst.State pending;
221
222         player.get_state(out state, out pending, (Gst.ClockType)Gst.CLOCK_TIME_NONE);
223
224         return state;
225     }
226
227     public void pause()
228     {
229         player.set_state(Gst.State.PAUSED);
230         state_changed(Gst.State.PAUSED);
231     }
232
233     public void resume()
234     {
235         player.set_state(Gst.State.PLAYING);
236         state_changed(Gst.State.PLAYING);
237     }
238
239     public void restart()
240     {
241         player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
242         player.set_state(Gst.State.PLAYING);
243         state_changed(Gst.State.PLAYING);
244     }
245
246     public void stop()
247     {
248         playing = false;
249         player.set_state(Gst.State.NULL);
250         state_changed(Gst.State.NULL);
251
252         // Resume slave after we are done
253         if (slave != null && slave.playing)
254             slave.resume();
255     }
256
257     protected void on_message(Gst.Message message)
258     {
259         if (message.type == Gst.MessageType.EOS)
260         {
261             if (loop)
262                 restart();
263             else
264                 stop();
265         }
266     }
267
268     public void shutdown()
269     {
270         stop();
271     }
272 }
273
274 public Vibrator vibrator = null;
275 public Audio audio = null;
276 public Player musicplayer = null;
277 public Player soundplayer = null;
278
279 public void init()
280 {
281     try {
282         vibrator = new Vibrator();
283         zavai.registry.register(vibrator);
284     } catch (Error e) {
285         zavai.log.info("No vibrator found");
286         vibrator = null;
287     }
288     audio = new Audio();
289     musicplayer = new Player();
290     soundplayer = new Player();
291     soundplayer.set_slave(musicplayer);
292     zavai.registry.register(musicplayer);
293     zavai.registry.register(soundplayer);
294 }
295
296 }
297 }