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 */
37 eos (GstElement * element)
39 g_print ("have eos, quitting ?\n");
41 /* playing = FALSE; */
44 G_GNUC_UNUSED static GstCaps *
45 gst_play_type_find (GstBin * bin, GstElement * element)
51 GST_DEBUG ("GstPipeline: typefind for element \"%s\"",
52 GST_ELEMENT_NAME (element));
54 pipeline = gst_pipeline_new ("autoplug_pipeline");
56 typefind = gst_element_factory_make ("typefind", "typefind");
57 g_return_val_if_fail (typefind != NULL, FALSE);
59 gst_pad_link (gst_element_get_pad (element, "src"),
60 gst_element_get_pad (typefind, "sink"));
61 gst_bin_add (bin, typefind);
62 gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
64 gst_element_set_state (pipeline, GST_STATE_PLAYING);
66 /* push a buffer... the have_type signal handler will set the found flag */
67 gst_bin_iterate (GST_BIN (pipeline));
69 gst_element_set_state (pipeline, GST_STATE_NULL);
71 caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
73 gst_pad_unlink (gst_element_get_pad (element, "src"),
74 gst_element_get_pad (typefind, "sink"));
75 gst_bin_remove (bin, typefind);
76 gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
77 gst_object_unref (typefind);
78 gst_object_unref (pipeline);
84 main (int argc, char *argv[])
91 GList *input_channels; /* structure holding all the input channels */
93 input_channel_t *channel_in;
97 GstElement *audiosink;
99 GstPad *pad; /* to request pads for the adder */
101 gst_init (&argc, &argv);
104 g_print ("usage: %s <filename1> <filename2> <...>\n", argv[0]);
107 num_channels = argc - 1;
109 /* set up output channel and main bin */
112 adder = gst_element_factory_make ("adder", "adderel");
114 /* create an audio sink */
115 audiosink = gst_element_factory_make ("esdsink", "play_audio");
117 /* create main bin */
118 main_bin = gst_pipeline_new ("bin");
120 /* link adder and output to bin */
121 GST_INFO ("main: adding adder to bin");
122 gst_bin_add (GST_BIN (main_bin), adder);
123 GST_INFO ("main: adding audiosink to bin");
124 gst_bin_add (GST_BIN (main_bin), audiosink);
126 /* link adder and audiosink */
128 gst_pad_link (gst_element_get_pad (adder, "src"),
129 gst_element_get_pad (audiosink, "sink"));
132 input_channels = NULL;
134 for (i = 1; i < argc; ++i) {
135 printf ("Opening channel %d from file %s...\n", i, argv[i]);
136 channel_in = create_input_channel (i, argv[i]);
137 input_channels = g_list_append (input_channels, channel_in);
140 gst_element_set_state (main_bin, GST_STATE_PAUSED);
141 gst_bin_add (GST_BIN (main_bin), channel_in->pipe);
143 /* request pads and link to adder */
144 GST_INFO ("requesting pad\n");
145 pad = gst_element_get_request_pad (adder, "sink%d");
146 printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
147 sprintf (buffer, "channel%d", i);
148 gst_pad_link (gst_element_get_pad (channel_in->pipe, buffer), pad);
150 /* register a volume envelope */
151 printf ("\tregistering volume envelope...\n");
154 * this is the volenv :
155 * each song gets a slot of 5 seconds, with a 5 second fadeout
156 * at the end of that, all audio streams play simultaneously
157 * at a level ensuring no distortion
158 * example for three songs :
159 * song1 : starts at full level, plays 5 seconds, faded out at 10 seconds,
160 * sleep until 25, fade to end level at 30
161 * song2 : starts silent, fades in at 5 seconds, full blast at 10 seconds,
162 * full level until 15, faded out at 20, sleep until 25, fade to end at 30
163 * song3 : starts muted, fades in from 15, full at 20, until 25, fade to end level
167 /* first song gets special treatment for end style */
168 env_register_cp (channel_in->volenv, 0.0, 1.0);
170 env_register_cp (channel_in->volenv, 0.0, 0.0000001); /* start muted */
171 env_register_cp (channel_in->volenv, i * 10.0 - 15.0, 0.0000001); /* start fade in */
172 env_register_cp (channel_in->volenv, i * 10.0 - 10.0, 1.0);
174 env_register_cp (channel_in->volenv, i * 10.0 - 5.0, 1.0); /* end of full level */
176 if (i != num_channels) {
177 env_register_cp (channel_in->volenv, i * 10.0, 0.0000001); /* fade to black */
178 env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
180 env_register_cp (channel_in->volenv, num_channels * 10.0, 1.0 / num_channels); /* to end level */
182 #ifndef GST_DISABLE_LOADSAVE
183 gst_xml_write_file (GST_ELEMENT (main_bin), fopen ("mixer.xml", "w"));
187 gst_element_set_state (main_bin, GST_STATE_PLAYING);
189 /* write out the schedule */
190 gst_scheduler_show (GST_ELEMENT_SCHEDULER (main_bin));
194 /*printf ("main: start iterating from 0"); */
195 while (playing && j < 100) {
196 /* printf ("main: iterating %d\n", j); */
197 gst_bin_iterate (GST_BIN (main_bin));
198 /*fprintf(stderr,"after iterate()\n"); */
202 printf ("main: all the channels are open\n");
204 gst_bin_iterate (GST_BIN (main_bin));
205 /*fprintf(stderr,"after iterate()\n"); */
208 gst_element_set_state (main_bin, GST_STATE_NULL);
210 while (input_channels) {
211 destroy_input_channel (input_channels->data);
212 input_channels = g_list_next (input_channels);
214 g_list_free (input_channels);
216 gst_object_unref (audiosink);
218 gst_object_unref (main_bin);
224 create_input_channel (int id, char *location)
226 /* create an input channel, reading from location
227 * return a pointer to the channel
228 * return NULL if failed
231 input_channel_t *channel;
233 char buffer[20]; /* hold the names */
235 /* GstAutoplug *autoplug;
237 GstElement *new_element;
240 GST_DEBUG ("c_i_p : creating channel with id %d for file %s", id, location);
242 /* allocate channel */
244 channel = (input_channel_t *) malloc (sizeof (input_channel_t));
245 if (channel == NULL) {
246 printf ("create_input_channel : could not allocate memory for channel !\n");
252 GST_DEBUG ("c_i_p : creating pipeline");
254 sprintf (buffer, "pipeline%d", id);
255 channel->pipe = gst_bin_new (buffer);
256 g_assert (channel->pipe != NULL);
258 /* create elements */
260 GST_DEBUG ("c_i_p : creating filesrc");
262 sprintf (buffer, "filesrc%d", id);
263 channel->filesrc = gst_element_factory_make ("filesrc", buffer);
264 g_assert (channel->filesrc != NULL);
266 GST_DEBUG ("c_i_p : setting location");
267 g_object_set (G_OBJECT (channel->filesrc), "location", location, NULL);
269 /* add filesrc to the bin before autoplug */
270 gst_bin_add (GST_BIN (channel->pipe), channel->filesrc);
272 /* link signal to eos of filesrc */
273 g_signal_connect (G_OBJECT (channel->filesrc), "eos", G_CALLBACK (eos), NULL);
277 printf ("DEBUG : c_i_p : creating volume envelope\n");
280 sprintf (buffer, "volenv%d", id);
281 channel->volenv = gst_element_factory_make ("volenv", buffer);
282 g_assert (channel->volenv != NULL);
284 /* autoplug the pipe */
287 printf ("DEBUG : c_i_p : getting srccaps\n");
291 srccaps = gst_play_type_find (GST_BIN (channel->pipe), channel->filesrc);
295 GstElement *pipeline;
297 pipeline = gst_pipeline_new ("autoplug_pipeline");
299 gst_bin_add (GST_BIN (pipeline), channel->pipe);
300 gst_element_set_state (pipeline, GST_STATE_PLAYING);
301 gst_element_set_state (pipeline, GST_STATE_NULL);
302 gst_bin_remove (GST_BIN (pipeline), channel->pipe);
309 g_print ("could not autoplug, unknown media type...\n");
313 printf ("DEBUG : c_i_p : creating autoplug\n");
316 autoplug = gst_autoplug_factory_make ("static");
317 g_assert (autoplug != NULL);
320 printf ("DEBUG : c_i_p : autoplugging\n");
323 new_element = gst_autoplug_to_caps (autoplug, srccaps,
324 gst_caps_new ("audio/raw", NULL), NULL);
327 g_print ("could not autoplug, no suitable codecs found...\n");
332 new_element = gst_bin_new ("autoplug_bin");
334 /* static plug, use mad plugin and assume mp3 input */
335 printf ("using static plugging for input channel\n");
336 decoder = gst_element_factory_make ("mad", "mpg123");
338 fprintf (stderr, "Could not get a decoder element !\n");
341 gst_bin_add (GST_BIN (new_element), decoder);
343 gst_element_add_ghost_pad (new_element,
344 gst_element_get_pad (decoder, "sink"), "sink");
345 gst_element_add_ghost_pad (new_element,
346 gst_element_get_pad (decoder, "src"), "src_00");
349 #ifndef GST_DISABLE_LOADSAVE
350 gst_xml_write_file (GST_ELEMENT (new_element), fopen ("mixer.gst", "w"));
353 gst_bin_add (GST_BIN (channel->pipe), channel->volenv);
354 gst_bin_add (GST_BIN (channel->pipe), new_element);
356 gst_element_link_pads (channel->filesrc, "src", new_element, "sink");
357 gst_element_link_pads (new_element, "src_00", channel->volenv, "sink");
359 /* add a ghost pad */
360 sprintf (buffer, "channel%d", id);
361 gst_element_add_ghost_pad (channel->pipe,
362 gst_element_get_pad (channel->volenv, "src"), buffer);
366 printf ("DEBUG : c_i_p : end function\n");
373 destroy_input_channel (input_channel_t * channel)
376 * destroy an input channel
380 printf ("DEBUG : d_i_p : start\n");
383 /* destroy elements */
385 gst_object_unref (channel->pipe);
391 env_register_cp (GstElement * volenv, double cp_time, double cp_level)
395 sprintf (buffer, "%f:%f", cp_time, cp_level);
396 g_object_set (G_OBJECT (volenv), "controlpoint", buffer, NULL);