Added music playing infrastructure with preempting sound player
[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 Audio: zavai.Service
27 {
28     protected Omhacks.Led vibrator;
29     protected bool has_vibrator;
30
31     /*
32        protected dynamic DBus.Object audiodev;
33        protected dynamic DBus.Object vibdev;
34    */
35
36     public Audio()
37     {
38         Object(name: "audio");
39
40         has_vibrator = (vibrator.init("neo1973:vibrator") == 0);
41
42 /*
43         audiodev = zavai.registry.sbus.get_object(
44                 "org.freesmartphone.odeviced",
45                 "/org/freesmartphone/Device/Audio",
46                 "org.freesmartphone.Device.Audio");
47         vibdev = zavai.registry.sbus.get_object(
48                 "org.freesmartphone.odeviced",
49                 "/org/freesmartphone/Device/LED/neo1973_vibrator",
50                 "org.freesmartphone.Device.LED");
51 */
52         if (has_vibrator)
53         {
54             zavai.log.warning("audio: can notify alarm triggers");
55             clock.alarm_trigger_queue.triggered += on_alarm_trigger;
56             clock.alarm_trigger_queue.acked += on_alarm_done;
57             clock.alarm_trigger_queue.canceled += on_alarm_done;
58         } else {
59             zavai.log.warning("audio: no way to notify alarm triggers");
60         }
61     }
62
63     public void on_alarm_trigger(clock.AlarmTriggerInfo info)
64     {
65         zavai.log.debug("Start vibrator");
66         vibrator.brightness = 256;
67         // FIXME: is there a better way? I hope there is a better way. Please
68         // tell me there is a better way.
69         var trig = "timer";
70         for (int i = 0; ; ++i)
71         {
72             vibrator.trigger[i] = (char)trig[i];
73             if (trig[i] == 0) break;
74         }
75         vibrator.delay_on = 200;
76         vibrator.delay_off = 300;
77         vibrator.set();
78     }
79
80     public void on_alarm_done(clock.AlarmTriggerInfo info)
81     {
82         zavai.log.debug("Stop vibrator");
83         var trig = "none";
84         for (int i = 0; ; ++i)
85         {
86             vibrator.trigger[i] = (char)trig[i];
87             if (trig[i] == 0) break;
88         }
89         vibrator.brightness = 0;
90         vibrator.set();
91     }
92
93 /*
94     public void notify_alarm(zavai.clock.Alarm a)
95     {
96         // Wiggle screen to turn on backlight
97         zavai.ui.power.backlight.wiggle();
98         try {
99             // Method does not exist in this frameworkd
100             vibdev.BlinkSeconds(5, 500, 200);
101         } catch (Error e) {
102             zavai.log.error("Cannot blink vibrator: " + e.message);
103         }
104         // TODO: play music?
105     }
106 */
107 }
108
109 public class Player: zavai.Service
110 {
111     protected Gst.Element music_player;
112     protected bool music_playing;
113     protected Gst.Element sound_player;
114     protected bool sound_playing;
115
116     public Player()
117     {
118         Object(name: "audio.player");
119
120         music_player = Gst.ElementFactory.make("playbin", null);
121         music_playing = false;
122         var music_bus = music_player.get_bus();
123         music_bus.add_signal_watch();
124         music_bus.message += on_music_message;
125
126         sound_player = Gst.ElementFactory.make("playbin", null);
127         sound_playing = false;
128         var sound_bus = sound_player.get_bus();
129         sound_bus.add_signal_watch();
130         sound_bus.message += on_sound_message;
131     }
132
133     public void play_music(string uri)
134     {
135 stderr.printf("Music starts %s\n", uri);
136         music_player.set_property("uri", uri);
137         music_player.set_state(sound_playing ? Gst.State.PAUSED : Gst.State.PLAYING);
138         music_playing = true;
139     }
140
141     public void play_sound(string uri)
142     {
143 stderr.printf("Sound starts %s\n", uri);
144         // Pause music
145         if (music_playing) music_player.set_state(Gst.State.PAUSED);
146         // Play sound
147         sound_player.set_property("uri", uri);
148         sound_player.set_state(Gst.State.PLAYING);
149         music_playing = true;
150     }
151
152     protected void on_music_message(Gst.Message message)
153     {
154         if (message.type == Gst.MessageType.EOS)
155         {
156 stderr.printf("Music ends\n");
157             music_playing = false;
158             music_player.set_state(Gst.State.NULL);
159         }
160     }
161
162     protected void on_sound_message(Gst.Message message)
163     {
164         if (message.type == Gst.MessageType.EOS)
165         {
166 stderr.printf("Sound ends\n");
167             sound_playing = false;
168             sound_player.set_state(Gst.State.NULL);
169
170             // Resume music after playing alarm
171             if (music_playing) music_player.set_state(Gst.State.PLAYING);
172         }
173     }
174
175 }
176
177 public Audio audio = null;
178 public Player player = null;
179
180 public void init()
181 {
182     audio = new Audio();
183     player = new Player();
184 }
185
186 }
187 }