3 #include <glib/gi18n.h>
4 #include <libchimara/glk.h>
10 #include "chimara-glk-private.h"
15 extern GPrivate *glk_data_key;
17 #ifdef GSTREAMER_SOUND
18 /* Stop any currently playing sound on this channel, and remove any
19 format-specific GStreamer elements from the channel. */
21 clean_up_after_playing_sound(schanid_t chan)
23 if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
24 WARNING_S(_("Could not set GstElement state to"), "NULL");
27 gst_bin_remove(GST_BIN(chan->pipeline), chan->demux);
32 gst_bin_remove(GST_BIN(chan->pipeline), chan->decode);
37 /* This signal is thrown whenever the GStreamer pipeline generates a message.
38 Most messages are harmless. */
40 on_pipeline_message(GstBus *bus, GstMessage *message, schanid_t s)
42 /* g_printerr("Got %s message\n", GST_MESSAGE_TYPE_NAME(message)); */
47 switch(GST_MESSAGE_TYPE(message)) {
48 case GST_MESSAGE_ERROR:
50 gst_message_parse_error(message, &err, &debug_message);
51 IO_WARNING(_("GStreamer error"), err->message, debug_message);
53 g_free(debug_message);
54 clean_up_after_playing_sound(s);
57 case GST_MESSAGE_WARNING:
59 gst_message_parse_warning(message, &err, &debug_message);
60 IO_WARNING(_("GStreamer warning"), err->message, debug_message);
62 g_free(debug_message);
65 case GST_MESSAGE_INFO:
67 gst_message_parse_info(message, &err, &debug_message);
68 g_message("GStreamer info \"%s\": %s", err->message, debug_message);
70 g_free(debug_message);
75 clean_up_after_playing_sound(s);
78 /* unhandled message */
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. */
86 on_ogg_demuxer_pad_added(GstElement *demux, GstPad *pad, schanid_t s)
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);
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. */
101 on_type_found(GstElement *typefind, guint probability, GstCaps *caps, schanid_t s)
103 gchar *type = gst_caps_to_string(caps);
104 if(strcmp(type, "application/ogg") == 0)
106 s->demux = gst_element_factory_make("oggdemux", NULL);
107 s->decode = gst_element_factory_make("vorbisdec", NULL);
108 if(!s->demux || !s->decode)
110 WARNING(_("Could not create one or more GStreamer elements"));
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))
116 WARNING(_("Could not link GStreamer elements"));
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);
124 else if(strcmp(type, "audio/x-aiff") == 0)
126 s->decode = gst_element_factory_make("aiffparse", NULL);
129 WARNING(_("Could not create 'aiffparse' GStreamer element"));
132 gst_bin_add(GST_BIN(s->pipeline), s->decode);
133 if(!gst_element_link_many(s->typefind, s->decode, s->convert, NULL))
135 WARNING(_("Could not link GStreamer elements"));
141 WARNING_S(_("Unexpected audio type in blorb"), type);
147 #endif /* GSTREAMER_SOUND */
150 * glk_schannel_create:
151 * @rock: The rock value to give the new sound channel.
153 * This creates a sound channel, about as you'd expect.
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.
158 * Returns: A new sound channel, or %NULL.
161 glk_schannel_create(glui32 rock)
163 #ifdef GSTREAMER_SOUND
164 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
166 schanid_t s = g_new0(struct glk_schannel_struct, 1);
167 s->magic = MAGIC_SCHANNEL;
169 if(glk_data->register_obj)
170 s->disprock = (*glk_data->register_obj)(s, gidisp_Class_Schannel);
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;
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);
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);
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"));
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"));
206 g_signal_connect(s->typefind, "have-type", G_CALLBACK(on_type_found), s);
211 glk_schannel_destroy(s);
215 #endif /* GSTREAMER_SOUND */
219 * glk_schannel_destroy:
220 * @chan: The sound channel to destroy.
222 * Destroys the channel. If the channel is playing a sound, the sound stops
223 * immediately (with no notification event).
226 glk_schannel_destroy(schanid_t chan)
228 VALID_SCHANNEL(chan, return);
230 #ifdef GSTREAMER_SOUND
231 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
233 if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
234 WARNING_S(_("Could not set GstElement state to"), "NULL");
236 glk_data->schannel_list = g_list_delete_link(glk_data->schannel_list, chan->schannel_list);
238 if(glk_data->unregister_obj)
240 (*glk_data->unregister_obj)(chan, gidisp_Class_Schannel, chan->disprock);
241 chan->disprock.ptr = NULL;
244 /* This also frees all the objects inside the pipeline */
246 gst_object_unref(chan->pipeline);
248 chan->magic = MAGIC_FREE;
254 * glk_schannel_iterate:
255 * @chan: A sound channel, or %NULL.
256 * @rockptr: Return location for the next sound channel's rock, or %NULL.
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>.
262 * As that section describes, the order in which channels are returned is
265 * Returns: the next sound channel, or %NULL if there are no more.
268 glk_schannel_iterate(schanid_t chan, glui32 *rockptr)
270 VALID_SCHANNEL_OR_NULL(chan, return NULL);
272 #ifdef GSTREAMER_SOUND
273 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
277 retnode = glk_data->schannel_list;
279 retnode = chan->schannel_list->next;
280 schanid_t retval = retnode? (schanid_t)retnode->data : NULL;
282 /* Store the sound channel's rock in rockptr */
283 if(retval && rockptr)
284 *rockptr = glk_schannel_get_rock(retval);
289 #endif /* GSTREAMER_SOUND */
293 * glk_schannel_get_rock:
294 * @chan: A sound channel.
296 * Retrieves the channel's rock value. See <link
297 * linkend="chimara-Rocks">Rocks</link>.
299 * Returns: A rock value.
302 glk_schannel_get_rock(schanid_t chan)
304 VALID_SCHANNEL(chan, return 0);
310 * @chan: Channel to play the sound in.
311 * @snd: Resource number of the sound to play.
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.
317 * This returns 1 if the sound actually started playing, and 0 if there was any
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.
326 * Returns: 1 on success, 0 on failure.
329 glk_schannel_play(schanid_t chan, glui32 snd)
331 return glk_schannel_play_ext(chan, snd, 1, 0);
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.
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>.
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.)
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
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.
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>.
368 * Returns: 1 on success, 0 on failure.
371 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify)
373 VALID_SCHANNEL(chan, return 0);
374 #ifdef GSTREAMER_SOUND
375 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
377 /* Stop the previous sound */
378 clean_up_after_playing_sound(chan);
380 if(!glk_data->resource_map) {
381 if(!glk_data->resource_load_callback) {
382 WARNING(_("No resource map has been loaded yet."));
385 WARNING(_("Loading sound resources from alternative location not yet supported."));
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) );
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);
398 if(!gst_element_set_state(chan->pipeline, GST_STATE_PLAYING)) {
399 WARNING_S(_("Could not set GstElement state to"), "PLAYING");
410 * @chan: Channel to silence.
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.
416 glk_schannel_stop(schanid_t chan)
418 VALID_SCHANNEL(chan, return);
419 #ifdef GSTREAMER_SOUND
420 clean_up_after_playing_sound(chan);
425 * glk_schannel_set_volume:
426 * @chan: Channel to set the volume of.
427 * @vol: Integer representing the volume; 0x10000 is 100%.
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.
434 * You can call this function between sounds, or while a sound is playing. The
435 * effect is immediate.
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.
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>.
448 * <note><title>Chimara</title>
449 * <para>Chimara supports volumes from 0 to 1000%, that is, values of
450 * @vol up to 0xA0000.</para>
454 glk_schannel_set_volume(schanid_t chan, glui32 vol)
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);
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.
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.
477 * <warning><para>This function is not implemented yet.</para></warning>
480 glk_sound_load_hint(glui32 snd, glui32 flag)