2 * mixer.c - stereo audio mixer - thomas@apestaart.org
3 * example based on helloworld
4 * demonstrates the adder plugin and the volume envelope plugin
5 * work in progress but do try it out
7 * Latest change : 28/08/2001
8 * trying to adapt to incsched
9 * delayed start for channels > 1
10 * now works by quickhacking the
12 * GST_ELEMENT_COTHREAD_STOPPING
22 /*#define WITH_BUG2 */
24 /*#define AUTOPLUG * define if you want autoplugging of input channels * */
25 /* function prototypes */
27 input_channel_t* create_input_channel (int id, char* location);
28 void destroy_input_channel (input_channel_t *pipe);
29 void env_register_cp (GstElement *volenv, double cp_time, double cp_level);
35 /* eos will be called when the src element has an end of stream */
36 void eos(GstElement *element)
38 g_print("have eos, quitting ?\n");
40 /* playing = FALSE; */
43 G_GNUC_UNUSED static GstCaps*
44 gst_play_type_find (GstBin *bin, GstElement *element)
50 GST_DEBUG ("GstPipeline: typefind for element \"%s\"",
51 GST_ELEMENT_NAME(element));
53 pipeline = gst_pipeline_new ("autoplug_pipeline");
55 typefind = gst_element_factory_make ("typefind", "typefind");
56 g_return_val_if_fail (typefind != NULL, FALSE);
58 gst_pad_link (gst_element_get_pad (element, "src"),
59 gst_element_get_pad (typefind, "sink"));
60 gst_bin_add (bin, typefind);
61 gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
63 gst_element_set_state (pipeline, GST_STATE_PLAYING);
65 /* push a buffer... the have_type signal handler will set the found flag */
66 gst_bin_iterate (GST_BIN (pipeline));
68 gst_element_set_state (pipeline, GST_STATE_NULL);
70 caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
72 gst_pad_unlink (gst_element_get_pad (element, "src"),
73 gst_element_get_pad (typefind, "sink"));
74 gst_bin_remove (bin, typefind);
75 gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
76 gst_object_unref (GST_OBJECT (typefind));
77 gst_object_unref (GST_OBJECT (pipeline));
82 int main(int argc,char *argv[])
89 GList *input_channels; /* structure holding all the input channels */
91 input_channel_t *channel_in;
95 GstElement *audiosink;
97 GstPad *pad; /* to request pads for the adder */
99 gst_init(&argc,&argv);
102 g_print("usage: %s <filename1> <filename2> <...>\n", argv[0]);
105 num_channels = argc - 1;
107 /* set up output channel and main bin */
110 adder = gst_element_factory_make ("adder", "adderel");
112 /* create an audio sink */
113 audiosink = gst_element_factory_make ("esdsink", "play_audio");
115 /* create main bin */
116 main_bin = gst_pipeline_new("bin");
118 /* link adder and output to bin */
119 GST_INFO ( "main: adding adder to bin");
120 gst_bin_add (GST_BIN(main_bin), adder);
121 GST_INFO ( "main: adding audiosink to bin");
122 gst_bin_add (GST_BIN(main_bin), audiosink);
124 /* link adder and audiosink */
126 gst_pad_link(gst_element_get_pad(adder,"src"),
127 gst_element_get_pad(audiosink,"sink"));
130 input_channels = NULL;
132 for (i = 1; i < argc; ++i)
134 printf ("Opening channel %d from file %s...\n", i, argv[i]);
135 channel_in = create_input_channel (i, argv[i]);
136 input_channels = g_list_append (input_channels, channel_in);
138 if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
139 gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
141 /* request pads and link to adder */
142 GST_INFO ( "requesting pad\n");
143 pad = gst_element_get_request_pad (adder, "sink%d");
144 printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
145 sprintf (buffer, "channel%d", i);
146 gst_pad_link (gst_element_get_pad (channel_in->pipe, buffer), pad);
148 /* register a volume envelope */
149 printf ("\tregistering volume envelope...\n");
152 * this is the volenv :
153 * each song gets a slot of 5 seconds, with a 5 second fadeout
154 * at the end of that, all audio streams play simultaneously
155 * at a level ensuring no distortion
156 * example for three songs :
157 * song1 : starts at full level, plays 5 seconds, faded out at 10 seconds,
158 * sleep until 25, fade to end level at 30
159 * song2 : starts silent, fades in at 5 seconds, full blast at 10 seconds,
160 * full level until 15, faded out at 20, sleep until 25, fade to end at 30
161 * song3 : starts muted, fades in from 15, full at 20, until 25, fade to end level
166 /* first song gets special treatment for end style */
167 env_register_cp (channel_in->volenv, 0.0, 1.0);
171 env_register_cp (channel_in->volenv, 0.0 , 0.0000001); /* start muted */
172 env_register_cp (channel_in->volenv, i * 10.0 - 15.0, 0.0000001); /* start fade in */
173 env_register_cp (channel_in->volenv, i * 10.0 - 10.0, 1.0);
175 env_register_cp (channel_in->volenv, i * 10.0 - 5.0, 1.0); /* end of full level */
177 if (i != num_channels)
179 env_register_cp (channel_in->volenv, i * 10.0 , 0.0000001); /* fade to black */
180 env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
182 env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
184 #ifndef GST_DISABLE_LOADSAVE
185 gst_xml_write_file (GST_ELEMENT (main_bin), fopen ("mixer.xml", "w"));
189 gst_element_set_state(main_bin, GST_STATE_PLAYING);
191 /* write out the schedule */
192 gst_scheduler_show(GST_ELEMENT_SCHED(main_bin));
196 /*printf ("main: start iterating from 0"); */
197 while (playing && j < 100)
199 /* printf ("main: iterating %d\n", j); */
200 gst_bin_iterate(GST_BIN(main_bin));
201 /*fprintf(stderr,"after iterate()\n"); */
205 printf ("main: all the channels are open\n");
208 gst_bin_iterate(GST_BIN(main_bin));
209 /*fprintf(stderr,"after iterate()\n"); */
212 gst_element_set_state(main_bin, GST_STATE_NULL);
214 while (input_channels)
216 destroy_input_channel (input_channels->data);
217 input_channels = g_list_next (input_channels);
219 g_list_free (input_channels);
221 gst_object_unref(GST_OBJECT(audiosink));
223 gst_object_unref(GST_OBJECT(main_bin));
229 create_input_channel (int id, char* location)
231 /* create an input channel, reading from location
232 * return a pointer to the channel
233 * return NULL if failed
236 input_channel_t *channel;
238 char buffer[20]; /* hold the names */
240 /* GstAutoplug *autoplug;
242 GstElement *new_element;
245 GST_DEBUG ( "c_i_p : creating channel with id %d for file %s",
248 /* allocate channel */
250 channel = (input_channel_t *) malloc (sizeof (input_channel_t));
253 printf ("create_input_channel : could not allocate memory for channel !\n");
259 GST_DEBUG ( "c_i_p : creating pipeline");
261 sprintf (buffer, "pipeline%d", id);
262 channel->pipe = gst_bin_new (buffer);
263 g_assert(channel->pipe != NULL);
265 /* create elements */
267 GST_DEBUG ( "c_i_p : creating filesrc");
269 sprintf (buffer, "filesrc%d", id);
270 channel->filesrc = gst_element_factory_make ("filesrc", buffer);
271 g_assert(channel->filesrc != NULL);
273 GST_DEBUG ( "c_i_p : setting location");
274 g_object_set(G_OBJECT(channel->filesrc),"location", location, NULL);
276 /* add filesrc to the bin before autoplug */
277 gst_bin_add(GST_BIN(channel->pipe), channel->filesrc);
279 /* link signal to eos of filesrc */
280 g_signal_connect (G_OBJECT(channel->filesrc),"eos",
281 G_CALLBACK(eos),NULL);
285 printf ("DEBUG : c_i_p : creating volume envelope\n");
288 sprintf (buffer, "volenv%d", id);
289 channel->volenv = gst_element_factory_make ("volenv", buffer);
290 g_assert(channel->volenv != NULL);
292 /* autoplug the pipe */
295 printf ("DEBUG : c_i_p : getting srccaps\n");
299 srccaps = gst_play_type_find (GST_BIN (channel->pipe), channel->filesrc);
303 GstElement *pipeline;
305 pipeline = gst_pipeline_new ("autoplug_pipeline");
307 gst_bin_add (GST_BIN (pipeline), channel->pipe);
308 gst_element_set_state (pipeline, GST_STATE_PLAYING);
309 gst_element_set_state (pipeline, GST_STATE_NULL);
310 gst_bin_remove (GST_BIN (pipeline), channel->pipe);
317 g_print ("could not autoplug, unknown media type...\n");
322 printf ("DEBUG : c_i_p : creating autoplug\n");
325 autoplug = gst_autoplug_factory_make ("static");
326 g_assert (autoplug != NULL);
329 printf ("DEBUG : c_i_p : autoplugging\n");
332 new_element = gst_autoplug_to_caps (autoplug, srccaps,
333 gst_caps_new ("audio/raw", NULL), NULL);
336 g_print ("could not autoplug, no suitable codecs found...\n");
342 new_element = gst_bin_new ("autoplug_bin");
344 /* static plug, use mad plugin and assume mp3 input */
345 printf ("using static plugging for input channel\n");
346 decoder = gst_element_factory_make ("mad", "mpg123");
349 fprintf (stderr, "Could not get a decoder element !\n");
352 gst_bin_add (GST_BIN (new_element), decoder);
354 gst_element_add_ghost_pad (new_element,
355 gst_element_get_pad (decoder, "sink"), "sink");
356 gst_element_add_ghost_pad (new_element,
357 gst_element_get_pad (decoder, "src"), "src_00");
360 #ifndef GST_DISABLE_LOADSAVE
361 gst_xml_write_file (GST_ELEMENT (new_element), fopen ("mixer.gst", "w"));
364 gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
365 gst_bin_add (GST_BIN (channel->pipe), new_element);
367 gst_element_link_pads (channel->filesrc, "src", new_element, "sink");
368 gst_element_link_pads (new_element, "src_00", channel->volenv, "sink");
370 /* add a ghost pad */
371 sprintf (buffer, "channel%d", id);
372 gst_element_add_ghost_pad (channel->pipe,
373 gst_element_get_pad (channel->volenv, "src"), buffer);
377 printf ("DEBUG : c_i_p : end function\n");
384 destroy_input_channel (input_channel_t *channel)
387 * destroy an input channel
391 printf ("DEBUG : d_i_p : start\n");
394 /* destroy elements */
396 gst_object_unref (GST_OBJECT (channel->pipe));
401 void env_register_cp (GstElement *volenv, double cp_time, double cp_level)
405 sprintf (buffer, "%f:%f", cp_time, cp_level);
406 g_object_set(G_OBJECT(volenv), "controlpoint", buffer, NULL);