butcher butcher butcher
[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     /*
29        protected dynamic DBus.Object audiodev;
30        protected dynamic DBus.Object vibdev;
31    */
32
33     public Audio()
34     {
35         Object(name: "audio");
36
37 /*
38         audiodev = zavai.registry.sbus.get_object(
39                 "org.freesmartphone.odeviced",
40                 "/org/freesmartphone/Device/Audio",
41                 "org.freesmartphone.Device.Audio");
42         vibdev = zavai.registry.sbus.get_object(
43                 "org.freesmartphone.odeviced",
44                 "/org/freesmartphone/Device/LED/neo1973_vibrator",
45                 "org.freesmartphone.Device.LED");
46 */
47     }
48 }
49
50 public class PlayerState : Object
51 {
52     protected SoundPlayer soundplayer;
53     protected Gst.Element player;
54     public string owner;
55     public string uri;
56     public bool loop;
57
58     public PlayerState(string owner, string uri, bool loop=false)
59     {
60         soundplayer = null;
61
62         this.owner = owner;
63         this.uri = uri;
64         this.loop = loop;
65
66         player = Gst.ElementFactory.make("playbin", null);
67         var bus = player.get_bus();
68         bus.add_signal_watch();
69         bus.message += on_message;
70
71         player.set_property("uri", uri);
72         player.set_state(Gst.State.PAUSED);
73     }
74
75     public void register(SoundPlayer sp)
76     {
77         soundplayer = sp;
78     }
79
80     public void stop()
81     {
82         player.set_state(Gst.State.NULL);
83     }
84
85     public void pause()
86     {
87         player.set_state(Gst.State.PAUSED);
88     }
89
90     public void resume()
91     {
92         player.set_state(Gst.State.PLAYING);
93     }
94
95     protected void on_message(Gst.Message message)
96     {
97         if (message.type == Gst.MessageType.EOS)
98         {
99             if (loop)
100             {
101                 player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
102                 player.set_state(Gst.State.PLAYING);
103             }
104             else if (soundplayer != null)
105                 soundplayer.pop_state(owner);
106         }
107     }
108 }
109
110 public class SoundPlayer : zavai.Resource, Object
111 {
112     protected List<PlayerState> states;
113     protected MusicPlayer slave;
114     protected bool slave_was_playing;
115
116     public SoundPlayer()
117     {
118         states = new List<PlayerState>();
119     }
120
121     public void set_slave(MusicPlayer player)
122     {
123         slave = player;
124         slave.master = this;
125     }
126
127     public bool playing()
128     {
129         return states != null;
130     }
131
132     protected void stop_playing()
133     {
134         if (slave_was_playing)
135             slave.resume();
136     }
137
138     public void push_state(PlayerState state)
139     {
140         // Save current playing position
141         if (states == null)
142         {
143             // We start playing: see about preempting slave
144             slave_was_playing = (slave != null && slave.playing);
145             if (slave_was_playing)
146                 slave.pause();
147         } else
148             // We were playing: pause previous sound
149             states.data.pause();
150         state.register(this);
151         states.prepend(state);
152         states.data.resume();
153     }
154
155     public void pop_state(string owner)
156     {
157         // Handle empty list
158         if (states == null) return;
159
160         // Track if the list head changed
161         weak List<PlayerState> old_top = states;
162
163         // Remove state "name" from the stack
164         for (weak List<PlayerState> i = states; i != null; i = i.next)
165             if (i.data.owner == owner)
166             {
167                 i.data.stop();
168                 states.delete_link(i);
169                 break;
170             }
171
172         // If the list head changed, put into action the new top state
173         if (states != old_top)
174         {
175             if (states == null)
176                 stop_playing();
177             else
178                 states.data.resume();
179         }
180     }
181
182     public void shutdown()
183     {
184         while (states != null)
185         {
186             states.data.stop();
187             states.delete_link(states);
188         }
189         stop_playing();
190     }
191 }
192
193 public class MusicPlayer: zavai.Resource, Object
194 {
195     protected Gst.Element player;
196     public SoundPlayer master;
197     public signal void state_changed(Gst.State new_state);
198     public string uri;
199     public bool playing;
200
201     public MusicPlayer()
202     {
203         master = null;
204         uri = null;
205         playing = false;
206         player = Gst.ElementFactory.make("playbin", null);
207         var bus = player.get_bus();
208         bus.add_signal_watch();
209         bus.message += on_message;
210     }
211
212     public void play(string uri)
213     {
214         this.uri = uri;
215         playing = true;
216         player.set_property("uri", uri);
217         player.set_state(master != null && master.playing() ? Gst.State.PAUSED : Gst.State.PLAYING);
218     }
219
220     protected void stop_playing()
221     {
222         player.set_state(Gst.State.NULL);
223         state_changed(Gst.State.NULL);
224     }
225
226     public Gst.State get_state()
227     {
228         return player.current_state;
229     }
230
231     public void pause()
232     {
233         playing = false;
234         player.set_state(Gst.State.PAUSED);
235         state_changed(Gst.State.PAUSED);
236     }
237
238     public void resume()
239     {
240         playing = true;
241         if (master == null || !master.playing())
242         {
243             player.set_state(Gst.State.PLAYING);
244             state_changed(Gst.State.PLAYING);
245         }
246     }
247
248     public void restart()
249     {
250         player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
251         player.set_state(Gst.State.PLAYING);
252         state_changed(Gst.State.PLAYING);
253     }
254
255     protected void on_message(Gst.Message message)
256     {
257         if (message.type == Gst.MessageType.EOS)
258         {
259             playing = false;
260             stop_playing();
261         }
262     }
263
264     public void shutdown()
265     {
266         stop_playing();
267     }
268 }
269
270 public Audio audio = null;
271 public SoundPlayer soundplayer = null;
272 public MusicPlayer musicplayer = null;
273
274 public void init()
275 {
276     audio = new Audio();
277     musicplayer = new MusicPlayer();
278     soundplayer = new SoundPlayer();
279     soundplayer.set_slave(musicplayer);
280     zavai.registry.register(musicplayer);
281     zavai.registry.register(soundplayer);
282 }
283
284 }
285 }