Stop playing old sound when playing new sound
[projects/chimara/chimara.git] / libchimara / schannel.c
1 #include <config.h>
2 #include <glib.h>
3 #include <glib/gi18n.h>
4 #include <libchimara/glk.h>
5 #ifdef GSTREAMER_SOUND
6 #include <gst/gst.h>
7 #endif
8 #include "magic.h"
9 #include "schannel.h"
10 #include "chimara-glk-private.h"
11 #include "gi_dispa.h"
12 #include "gi_blorb.h"
13 #include "resource.h"
14
15 extern GPrivate *glk_data_key;
16
17 #ifdef GSTREAMER_SOUND
18 /* Stop any currently playing sound on this channel, and remove any
19  format-specific GStreamer elements from the channel. */
20 static void
21 clean_up_after_playing_sound(schanid_t chan)
22 {
23         if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
24                 WARNING_S(_("Could not set GstElement state to"), "NULL");
25         if(chan->demux)
26         {
27                 gst_bin_remove(GST_BIN(chan->pipeline), chan->demux);
28                 chan->demux = NULL;
29         }
30         if(chan->decode)
31         {
32                 gst_bin_remove(GST_BIN(chan->pipeline), chan->decode);
33                 chan->decode = NULL;
34         }
35 }
36
37 /* This signal is thrown whenever the GStreamer pipeline generates a message.
38  Most messages are harmless. */
39 static void
40 on_pipeline_message(GstBus *bus, GstMessage *message, schanid_t s)
41 {
42         /* g_printerr("Got %s message\n", GST_MESSAGE_TYPE_NAME(message)); */
43
44         GError *err;
45         gchar *debug_message;
46         
47         switch(GST_MESSAGE_TYPE(message)) {
48         case GST_MESSAGE_ERROR: 
49         {
50                 gst_message_parse_error(message, &err, &debug_message);
51                 IO_WARNING(_("GStreamer error"), err->message, debug_message);
52                 g_error_free(err);
53                 g_free(debug_message);
54                 clean_up_after_playing_sound(s);
55         }
56                 break;
57         case GST_MESSAGE_WARNING:
58         {
59                 gst_message_parse_warning(message, &err, &debug_message);
60                 IO_WARNING(_("GStreamer warning"), err->message, debug_message);
61                 g_error_free(err);
62                 g_free(debug_message);
63         }
64                 break;
65         case GST_MESSAGE_INFO:
66         {
67                 gst_message_parse_info(message, &err, &debug_message);
68                 g_message("GStreamer info \"%s\": %s", err->message, debug_message);
69                 g_error_free(err);
70                 g_free(debug_message);
71         }
72                 break;
73         case GST_MESSAGE_EOS:
74                 /* end-of-stream */
75                 clean_up_after_playing_sound(s);
76                 break;
77         default:
78                 /* unhandled message */
79                 break;
80         }
81 }
82
83 /* This signal is thrown when the OGG demuxer element has decided what kind of
84  outputs it will output. We connect the decoder element dynamically. */
85 static void
86 on_ogg_demuxer_pad_added(GstElement *demux, GstPad *pad, schanid_t s)
87 {
88         GstPad *sinkpad;
89         
90         /* We can now link this pad with the vorbis-decoder sink pad */
91         sinkpad = gst_element_get_static_pad(s->decode, "sink");
92         if(gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK)
93                 WARNING(_("Could not link OGG demuxer with Vorbis decoder"));
94         gst_object_unref(sinkpad);
95 }
96
97 /* This signal is thrown when the typefinder element has found the type of its
98  input. Now that we know what kind of input stream we have, we can connect the
99  proper demuxer/decoder elements. */
100 static void
101 on_type_found(GstElement *typefind, guint probability, GstCaps *caps, schanid_t s)
102 {
103         gchar *type = gst_caps_to_string(caps);
104         if(strcmp(type, "application/ogg") == 0) 
105         {
106                 s->demux = gst_element_factory_make("oggdemux", NULL);
107                 s->decode = gst_element_factory_make("vorbisdec", NULL);
108                 if(!s->demux || !s->decode)
109                 {
110                         WARNING(_("Could not create one or more GStreamer elements"));
111                         goto finally;
112                 }
113                 gst_bin_add_many(GST_BIN(s->pipeline), s->demux, s->decode, NULL);
114                 if(!gst_element_link(s->typefind, s->demux) || !gst_element_link(s->decode, s->convert))
115                 {
116                         WARNING(_("Could not link GStreamer elements"));
117                         goto finally;
118                 }
119                 /* We link the demuxer and decoder together dynamically, since the
120                  demuxer doesn't know what source pads it will have until it starts
121                  demuxing the stream */
122                 g_signal_connect(s->demux, "pad-added", G_CALLBACK(on_ogg_demuxer_pad_added), s);
123         }
124         else if(strcmp(type, "audio/x-aiff") == 0)
125         {
126                 s->decode = gst_element_factory_make("aiffparse", NULL);
127                 if(!s->decode)
128                 {
129                         WARNING(_("Could not create 'aiffparse' GStreamer element"));
130                         goto finally;
131                 }
132                 gst_bin_add(GST_BIN(s->pipeline), s->decode);
133                 if(!gst_element_link_many(s->typefind, s->decode, s->convert, NULL))
134                 {
135                         WARNING(_("Could not link GStreamer elements"));
136                         goto finally;
137                 }
138         }
139         else
140         {
141                 WARNING_S(_("Unexpected audio type in blorb"), type);
142         }
143
144 finally:
145         g_free(type);
146 }
147 #endif /* GSTREAMER_SOUND */
148
149 /**
150  * glk_schannel_create:
151  * @rock: The rock value to give the new sound channel.
152  *
153  * This creates a sound channel, about as you'd expect.
154  *
155  * Remember that it is possible that the library will be unable to create a new
156  * channel, in which case glk_schannel_create() will return %NULL.
157  *
158  * Returns: A new sound channel, or %NULL.
159  */
160 schanid_t 
161 glk_schannel_create(glui32 rock)
162 {
163 #ifdef GSTREAMER_SOUND
164         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
165
166         schanid_t s = g_new0(struct glk_schannel_struct, 1);
167         s->magic = MAGIC_SCHANNEL;
168         s->rock = rock;
169         if(glk_data->register_obj)
170                 s->disprock = (*glk_data->register_obj)(s, gidisp_Class_Schannel);
171
172         /* Add it to the global sound channel list */
173         glk_data->schannel_list = g_list_prepend(glk_data->schannel_list, s);
174         s->schannel_list = glk_data->schannel_list;
175
176         /* Create a GStreamer pipeline for the sound channel */
177         gchar *pipeline_name = g_strdup_printf("pipeline-%p", s);
178         s->pipeline = gst_pipeline_new(pipeline_name);
179         g_free(pipeline_name);
180
181         /* Watch for messages from the pipeline */
182         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(s->pipeline));
183         gst_bus_add_signal_watch(bus);
184         g_signal_connect(bus, "message", G_CALLBACK(on_pipeline_message), s);
185         gst_object_unref(bus);
186
187         /* Create GStreamer elements to put in the pipeline */
188         s->source = gst_element_factory_make("giostreamsrc", NULL);
189         s->typefind = gst_element_factory_make("typefind", NULL);
190         s->convert = gst_element_factory_make("audioconvert", NULL);
191         s->filter = gst_element_factory_make("volume", NULL);
192         s->sink = gst_element_factory_make("autoaudiosink", NULL);
193         if(!s->source || !s->typefind || !s->convert || !s->filter || !s->sink) {
194                 WARNING(_("Could not create one or more GStreamer elements"));
195                 goto fail;
196         }
197
198         /* Put the elements in the pipeline and link as many together as we can
199          without knowing the type of the audio stream */
200         gst_bin_add_many(GST_BIN(s->pipeline), s->source, s->typefind, s->convert, s->filter, s->sink, NULL);
201         /* Link elements: Source -> typefinder -> ??? -> Converter -> Volume filter -> Sink */
202         if(!gst_element_link(s->source, s->typefind) || !gst_element_link_many(s->convert, s->filter, s->sink, NULL)) {
203                 WARNING(_("Could not link GStreamer elements"));
204                 goto fail;
205         }
206         g_signal_connect(s->typefind, "have-type", G_CALLBACK(on_type_found), s);
207         
208         return s;
209
210 fail:
211         glk_schannel_destroy(s);
212         return NULL;
213 #else
214         return NULL;
215 #endif /* GSTREAMER_SOUND */
216 }
217
218 /**
219  * glk_schannel_destroy:
220  * @chan: The sound channel to destroy.
221  *
222  * Destroys the channel. If the channel is playing a sound, the sound stops 
223  * immediately (with no notification event).
224  */
225 void 
226 glk_schannel_destroy(schanid_t chan)
227 {
228         VALID_SCHANNEL(chan, return);
229
230 #ifdef GSTREAMER_SOUND
231         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
232
233         if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
234                 WARNING_S(_("Could not set GstElement state to"), "NULL");
235         
236         glk_data->schannel_list = g_list_delete_link(glk_data->schannel_list, chan->schannel_list);
237
238         if(glk_data->unregister_obj)
239         {
240                 (*glk_data->unregister_obj)(chan, gidisp_Class_Schannel, chan->disprock);
241                 chan->disprock.ptr = NULL;
242         }
243
244         /* This also frees all the objects inside the pipeline */
245         if(chan->pipeline)
246                 gst_object_unref(chan->pipeline);
247         
248         chan->magic = MAGIC_FREE;
249         g_free(chan);
250 #endif
251 }
252
253 /**
254  * glk_schannel_iterate:
255  * @chan: A sound channel, or %NULL.
256  * @rockptr: Return location for the next sound channel's rock, or %NULL.
257  *
258  * This function can be used to iterate through the list of all open channels.
259  * See <link linkend="chimara-Iterating-Through-Opaque-Objects">Iterating 
260  * Through Opaque Objects</link>.
261  *
262  * As that section describes, the order in which channels are returned is 
263  * arbitrary.
264  *
265  * Returns: the next sound channel, or %NULL if there are no more.
266  */
267 schanid_t 
268 glk_schannel_iterate(schanid_t chan, glui32 *rockptr)
269 {
270         VALID_SCHANNEL_OR_NULL(chan, return NULL);
271
272 #ifdef GSTREAMER_SOUND
273         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
274         GList *retnode;
275         
276         if(chan == NULL)
277                 retnode = glk_data->schannel_list;
278         else
279                 retnode = chan->schannel_list->next;
280         schanid_t retval = retnode? (schanid_t)retnode->data : NULL;
281                 
282         /* Store the sound channel's rock in rockptr */
283         if(retval && rockptr)
284                 *rockptr = glk_schannel_get_rock(retval);
285                 
286         return retval;
287 #else
288         return NULL;
289 #endif /* GSTREAMER_SOUND */
290 }
291
292 /**
293  * glk_schannel_get_rock:
294  * @chan: A sound channel.
295  * 
296  * Retrieves the channel's rock value. See <link 
297  * linkend="chimara-Rocks">Rocks</link>.
298  *
299  * Returns: A rock value.
300  */
301 glui32 
302 glk_schannel_get_rock(schanid_t chan)
303 {
304         VALID_SCHANNEL(chan, return 0);
305         return chan->rock;
306 }
307
308 /**
309  * glk_schannel_play:
310  * @chan: Channel to play the sound in.
311  * @snd: Resource number of the sound to play.
312  *
313  * Begins playing the given sound on the channel. If the channel was already
314  * playing a sound (even the same one), the old sound is stopped (with no
315  * notification event.
316  *
317  * This returns 1 if the sound actually started playing, and 0 if there was any
318  * problem.
319  * <note><para>
320  *   The most obvious problem is if there is no sound resource with the given
321  *   identifier. But other problems can occur. For example, the MOD-playing 
322  *   facility in a library might be unable to handle two MODs at the same time,
323  *   in which case playing a MOD resource would fail if one was already playing.
324  * </para></note>
325  *
326  * Returns: 1 on success, 0 on failure.
327  */
328 glui32 
329 glk_schannel_play(schanid_t chan, glui32 snd)
330 {
331         return glk_schannel_play_ext(chan, snd, 1, 0);
332 }
333
334 /**
335  * glk_schannel_play_ext:
336  * @chan: Channel to play the sound in.
337  * @snd: Resource number of the sound to play.
338  * @repeats: Number of times to repeat the sound.
339  * @notify: If nonzero, requests a notification when the sound is finished.
340  *
341  * This works the same as glk_schannel_play(), but lets you specify additional 
342  * options. <code>glk_schannel_play(chan, snd)</code> is exactly equivalent to 
343  * <code>glk_schannel_play_ext(chan, snd, 1, 0)</code>.
344  * 
345  * The @repeats value is the number of times the sound should be repeated. A 
346  * repeat value of -1 (or rather 0xFFFFFFFF) means that the sound should repeat 
347  * forever. A repeat value of 0 means that the sound will not be played at all; 
348  * nothing happens. (Although a previous sound on the channel will be stopped, 
349  * and the function will return 1.)
350  * 
351  * The @notify value should be nonzero in order to request a sound notification
352  * event. If you do this, when the sound is completed, you will get an event 
353  * with type %evtype_SoundNotify. The @window will be %NULL, @val1 will be the 
354  * sound's resource id, and @val2 will be the nonzero value you passed as 
355  * @notify.
356  * 
357  * If you request sound notification, and the repeat value is greater than one, 
358  * you will get the event only after the last repetition. If the repeat value is
359  * 0 or -1, you will never get a notification event at all. Similarly, if the 
360  * sound is stopped or interrupted, or if the channel is destroyed while the 
361  * sound is playing, there will be no notification event.
362  *
363  * Not all libraries support sound notification. You should test the
364  * %gestalt_SoundNotify selector before you rely on it; see <link
365  * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound 
366  * Capabilities</link>.
367  * 
368  * Returns: 1 on success, 0 on failure.
369  */
370 glui32 
371 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify)
372 {
373         VALID_SCHANNEL(chan, return 0);
374 #ifdef GSTREAMER_SOUND  
375         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
376
377         /* Stop the previous sound */
378         clean_up_after_playing_sound(chan);
379         
380         if(!glk_data->resource_map) {
381                 if(!glk_data->resource_load_callback) {
382                         WARNING(_("No resource map has been loaded yet."));
383                         return 0;
384                 }
385                 WARNING(_("Loading sound resources from alternative location not yet supported."));
386                 return 0;
387         }
388         
389         giblorb_result_t resource;
390         giblorb_err_t result = giblorb_load_resource(glk_data->resource_map, giblorb_method_Memory, &resource, giblorb_ID_Snd, snd);
391         if(result != giblorb_err_None) {
392                 WARNING_S( _("Error loading resource"), giblorb_get_error_message(result) );
393                 return 0;
394         }
395         GInputStream *stream = g_memory_input_stream_new_from_data(resource.data.ptr, resource.length, NULL);
396         g_object_set(chan->source, "stream", stream, NULL);
397         
398         if(!gst_element_set_state(chan->pipeline, GST_STATE_PLAYING)) {
399                 WARNING_S(_("Could not set GstElement state to"), "PLAYING");
400                 return 0;
401         }
402         return 1;
403 #else
404         return 0;
405 #endif
406 }
407
408 /**
409  * glk_schannel_stop:
410  * @chan: Channel to silence.
411  *
412  * Stops any sound playing in the channel. No notification event is generated,
413  * even if you requested one. If no sound is playing, this has no effect.
414  */
415 void 
416 glk_schannel_stop(schanid_t chan)
417 {
418         VALID_SCHANNEL(chan, return);
419 #ifdef GSTREAMER_SOUND
420         clean_up_after_playing_sound(chan);
421 #endif
422 }
423
424 /**
425  * glk_schannel_set_volume:
426  * @chan: Channel to set the volume of.
427  * @vol: Integer representing the volume; 0x10000 is 100&percnt;.
428  *
429  * Sets the volume in the channel. When you create a channel, it has full 
430  * volume, represented by the value 0x10000. Half volume would be 0x8000, 
431  * three-quarters volume would be 0xC000, and so on. A volume of zero represents
432  * silence, although the sound is still considered to be playing.
433  *
434  * You can call this function between sounds, or while a sound is playing. The 
435  * effect is immediate.
436  * 
437  * You can overdrive the volume of a channel by setting a volume greater than 
438  * 0x10000. However, this is not recommended; the library may be unable to 
439  * increase the volume past full, or the sound may become distorted. You should 
440  * always create sound resources with the maximum volume you will need, and then
441  * call glk_schannel_set_volume() to reduce the volume when appropriate.
442  *
443  * Not all libraries support this function. You should test the
444  * %gestalt_SoundVolume selector before you rely on it; see <link
445  * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound
446  * Capabilities</link>.
447  *
448  * <note><title>Chimara</title>
449  *   <para>Chimara supports volumes from 0 to 1000&percnt;, that is, values of
450  *   @vol up to 0xA0000.</para>
451  * </note>
452  */
453 void 
454 glk_schannel_set_volume(schanid_t chan, glui32 vol)
455 {
456         VALID_SCHANNEL(chan, return);
457 #ifdef GSTREAMER_SOUND
458         gdouble volume_gst = (gdouble)vol / 0x10000;
459         g_printerr("Volume set to: %f\n", volume_gst);
460         g_object_set(chan->filter, "volume", CLAMP(volume_gst, 0.0, 10.0), NULL);
461 #endif
462 }
463
464 /**
465  * glk_sound_load_hint:
466  * @snd: Resource number of a sound.
467  * @flag: Nonzero to tell the library to load the sound, zero to tell the
468  * library to unload it.
469  *
470  * This gives the library a hint about whether the given sound should be loaded
471  * or not. If the @flag is nonzero, the library may preload the sound or do
472  * other initialization, so that glk_schannel_play() will be faster. If the
473  * @flag is zero, the library may release memory or other resources associated
474  * with the sound. Calling this function is always optional, and it has no
475  * effect on what the library actually plays.
476  *
477  * <warning><para>This function is not implemented yet.</para></warning>
478  */
479 void 
480 glk_sound_load_hint(glui32 snd, glui32 flag)
481 {
482 }