chain up in set_clock
[platform/upstream/gstreamer.git] / gst / playondemand / gstplayondemand.c
1 /* GStreamer
2  * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <string.h>
25 #include <gst/gst.h>
26 #include <gst/audio/audio.h>
27
28 #include "gstplayondemand.h"
29
30 /* in these files, a 'tick' is a discrete unit of time, usually around the 1ms
31  * range. a tick is not divisible into smaller units of time. 1ms is probably
32  * way beyond what a real computer can actually keep track of, but hey ... */
33
34 /* some default values */
35 #define GST_POD_MAX_PLAYS    100        /* maximum simultaneous plays */
36 #define GST_POD_BUFFER_TIME  5.0        /* buffer length in seconds */
37 #define GST_POD_TICK_RATE    1e-6       /* ticks per second */
38
39 /* buffer pool fallback values ... use if no buffer pool is available */
40 #define GST_POD_BUFPOOL_SIZE 4096
41 #define GST_POD_BUFPOOL_NUM  6
42
43 static GstStaticPadTemplate play_on_demand_sink_template =
44     GST_STATIC_PAD_TEMPLATE ("sink",
45     GST_PAD_SINK,
46     GST_PAD_ALWAYS,
47     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
48         GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
49     );
50
51 static GstStaticPadTemplate play_on_demand_src_template =
52     GST_STATIC_PAD_TEMPLATE ("src",
53     GST_PAD_SRC,
54     GST_PAD_ALWAYS,
55     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
56         GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
57     );
58
59
60 /* GObject functionality */
61 static void play_on_demand_class_init (GstPlayOnDemandClass * klass);
62 static void play_on_demand_base_init (GstPlayOnDemandClass * klass);
63 static void play_on_demand_init (GstPlayOnDemand * filter);
64 static void play_on_demand_set_property (GObject * object, guint prop_id,
65     const GValue * value, GParamSpec * pspec);
66 static void play_on_demand_get_property (GObject * object, guint prop_id,
67     GValue * value, GParamSpec * pspec);
68 static void play_on_demand_finalize (GObject * object);
69
70 /* GStreamer functionality */
71 static GstPadLinkReturn play_on_demand_pad_link (GstPad * pad,
72     const GstCaps * caps);
73 static void play_on_demand_loop (GstElement * elem);
74 static gboolean play_on_demand_set_clock (GstElement * elem, GstClock * clock);
75
76 /* signal handlers */
77 static void play_on_demand_play_handler (GstElement * elem);
78 static void play_on_demand_clear_handler (GstElement * elem);
79 static void play_on_demand_reset_handler (GstElement * elem);
80
81 /* utility functions */
82 static void play_on_demand_add_play_pointer (GstPlayOnDemand * filter,
83     guint pos);
84 static void play_on_demand_resize_buffer (GstPlayOnDemand * filter);
85
86 GType
87 gst_play_on_demand_get_type (void)
88 {
89   static GType play_on_demand_type = 0;
90
91   if (!play_on_demand_type) {
92     static const GTypeInfo play_on_demand_info = {
93       sizeof (GstPlayOnDemandClass),
94       (GBaseInitFunc) play_on_demand_base_init,
95       NULL,
96       (GClassInitFunc) play_on_demand_class_init,
97       NULL,
98       NULL,
99       sizeof (GstPlayOnDemand),
100       0,
101       (GInstanceInitFunc) play_on_demand_init,
102     };
103
104     play_on_demand_type = g_type_register_static (GST_TYPE_ELEMENT,
105         "GstPlayOnDemand", &play_on_demand_info, 0);
106   }
107   return play_on_demand_type;
108 }
109
110
111 /* signals and properties */
112 enum
113 {
114   /* add signals here */
115   PLAYED_SIGNAL,
116   STOPPED_SIGNAL,
117   PLAY_SIGNAL,
118   CLEAR_SIGNAL,
119   RESET_SIGNAL,
120   LAST_SIGNAL
121 };
122
123 enum
124 {
125   PROP_0,
126   PROP_MUTE,
127   PROP_BUFFER_TIME,
128   PROP_MAX_PLAYS,
129   PROP_TICK_RATE,
130   PROP_TOTAL_TICKS,
131   PROP_TICKS
132 };
133
134 static guint gst_pod_filter_signals[LAST_SIGNAL] = { 0 };
135
136 static GstElementClass *parent_class = NULL;
137
138 static void
139 play_on_demand_base_init (GstPlayOnDemandClass * klass)
140 {
141   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
142
143   gst_element_class_add_pad_template (element_class,
144       gst_static_pad_template_get (&play_on_demand_src_template));
145   gst_element_class_add_pad_template (element_class,
146       gst_static_pad_template_get (&play_on_demand_sink_template));
147   gst_element_class_set_details_simple (element_class, "Play On Demand",
148       "Filter/Editor/Audio",
149       "Schedule a stream to play at specific times, or when a signal is received",
150       "Leif Morgan Johnson <leif@ambient.2y.net>");
151 }
152
153 static void
154 play_on_demand_class_init (GstPlayOnDemandClass * klass)
155 {
156   GObjectClass *gobject_class;
157   GstElementClass *gstelement_class;
158
159   gobject_class = (GObjectClass *) klass;
160   gstelement_class = (GstElementClass *) klass;
161
162   gst_pod_filter_signals[PLAYED_SIGNAL] =
163       g_signal_new ("played", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
164       G_STRUCT_OFFSET (GstPlayOnDemandClass, played),
165       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
166
167   gst_pod_filter_signals[STOPPED_SIGNAL] =
168       g_signal_new ("stopped", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
169       G_STRUCT_OFFSET (GstPlayOnDemandClass, stopped),
170       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
171
172   gst_pod_filter_signals[PLAY_SIGNAL] =
173       g_signal_new ("play", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
174       G_STRUCT_OFFSET (GstPlayOnDemandClass, play),
175       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
176
177   gst_pod_filter_signals[CLEAR_SIGNAL] =
178       g_signal_new ("clear", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
179       G_STRUCT_OFFSET (GstPlayOnDemandClass, clear),
180       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
181
182   gst_pod_filter_signals[RESET_SIGNAL] =
183       g_signal_new ("reset", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
184       G_STRUCT_OFFSET (GstPlayOnDemandClass, reset),
185       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
186
187   klass->play = play_on_demand_play_handler;
188   klass->clear = play_on_demand_clear_handler;
189   klass->reset = play_on_demand_reset_handler;
190
191   parent_class = g_type_class_peek_parent (klass);
192
193   gobject_class->set_property = play_on_demand_set_property;
194   gobject_class->get_property = play_on_demand_get_property;
195   gobject_class->finalize = play_on_demand_finalize;
196
197   gstelement_class->set_clock = play_on_demand_set_clock;
198
199   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MUTE,
200       g_param_spec_boolean ("mute", "Silence output", "Do not output any sound",
201           FALSE,
202           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
203
204   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_TIME,
205       g_param_spec_float ("buffer-time", "Buffer length in seconds",
206           "Number of seconds of audio the buffer holds", 0.0, G_MAXFLOAT,
207           GST_POD_BUFFER_TIME,
208           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
209
210   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PLAYS,
211       g_param_spec_uint ("max-plays", "Maximum simultaneous playbacks",
212           "Maximum allowed number of simultaneous plays from the buffer", 1,
213           G_MAXUINT, GST_POD_MAX_PLAYS,
214           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
215
216   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TICK_RATE,
217       g_param_spec_float ("tick-rate", "Tick rate (ticks/second)",
218           "The rate of musical ticks, the smallest time unit in a song", 0,
219           G_MAXFLOAT, GST_POD_TICK_RATE,
220           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
221
222   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOTAL_TICKS,
223       g_param_spec_uint ("total-ticks", "Total number of ticks",
224           "Total number of ticks in the tick array", 1, G_MAXUINT, 1,
225           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
226
227   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TICKS,
228       g_param_spec_pointer ("ticks", "Ticks to play sample on",
229           "An array of ticks (musical times) at which to play the sample",
230           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
231 }
232
233 static void
234 play_on_demand_init (GstPlayOnDemand * filter)
235 {
236   filter->srcpad =
237       gst_pad_new_from_static_template (&play_on_demand_src_template, "src");
238   filter->sinkpad =
239       gst_pad_new_from_static_template (&play_on_demand_sink_template, "sink");
240
241   gst_pad_set_link_function (filter->sinkpad, play_on_demand_pad_link);
242
243   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
244   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
245
246   gst_element_set_loop_function (GST_ELEMENT (filter), play_on_demand_loop);
247
248   filter->clock = NULL;
249
250   filter->rate = 0;
251
252   filter->ticks = g_new (guint32, filter->total_ticks / 32 + 1);
253   filter->plays = g_new (guint, filter->max_plays);
254
255   play_on_demand_resize_buffer (filter);
256   play_on_demand_reset_handler (GST_ELEMENT (filter));
257 }
258
259 static void
260 play_on_demand_set_property (GObject * object, guint prop_id,
261     const GValue * value, GParamSpec * pspec)
262 {
263   GstPlayOnDemand *filter;
264   register guint i;
265   guint new_size, min_size, *new_plays;
266   guint *new_ticks;
267
268   g_return_if_fail (GST_IS_PLAYONDEMAND (object));
269   filter = GST_PLAYONDEMAND (object);
270
271   switch (prop_id) {
272     case PROP_MUTE:
273       filter->mute = g_value_get_boolean (value);
274       break;
275     case PROP_BUFFER_TIME:
276       filter->buffer_time = g_value_get_float (value);
277       play_on_demand_resize_buffer (filter);
278
279       /* clear out now-invalid play pointers */
280       for (i = 0; i < filter->max_plays; i++)
281         filter->plays[i] = G_MAXUINT;
282
283       break;
284     case PROP_MAX_PLAYS:
285       new_size = g_value_get_uint (value);
286       min_size = (new_size < filter->max_plays) ? new_size : filter->max_plays;
287
288       new_plays = g_new (guint, new_size);
289       for (i = 0; i < min_size; i++)
290         new_plays[i] = filter->plays[i];
291       for (i = min_size; i < new_size; i++)
292         new_plays[i] = G_MAXUINT;
293
294       g_free (filter->plays);
295       filter->plays = new_plays;
296       filter->max_plays = new_size;
297
298       break;
299     case PROP_TICK_RATE:
300       filter->tick_rate = g_value_get_float (value);
301       break;
302     case PROP_TOTAL_TICKS:
303       new_size = g_value_get_uint (value);
304       min_size =
305           (new_size < filter->total_ticks) ? new_size : filter->total_ticks;
306
307       new_ticks = g_new (guint32, new_size / 32 + 1);
308       for (i = 0; i <= min_size / 32; i++)
309         new_ticks[i] = filter->ticks[i];
310       for (i = min_size / 32 + 1; i <= new_size / 32; i++)
311         new_ticks[i] = 0;
312
313       g_free (filter->ticks);
314       filter->ticks = new_ticks;
315       filter->total_ticks = new_size;
316
317       break;
318     case PROP_TICKS:
319       new_ticks = (guint *) g_value_get_pointer (value);
320       if (new_ticks) {
321         g_free (filter->ticks);
322         filter->ticks = new_ticks;
323       }
324       break;
325     default:
326       break;
327   }
328 }
329
330 static void
331 play_on_demand_get_property (GObject * object, guint prop_id,
332     GValue * value, GParamSpec * pspec)
333 {
334   GstPlayOnDemand *filter;
335
336   g_return_if_fail (GST_IS_PLAYONDEMAND (object));
337   filter = GST_PLAYONDEMAND (object);
338
339   switch (prop_id) {
340     case PROP_MUTE:
341       g_value_set_boolean (value, filter->mute);
342       break;
343     case PROP_BUFFER_TIME:
344       g_value_set_float (value, filter->buffer_time);
345       break;
346     case PROP_MAX_PLAYS:
347       g_value_set_uint (value, filter->max_plays);
348       break;
349     case PROP_TICK_RATE:
350       g_value_set_float (value, filter->tick_rate);
351       break;
352     case PROP_TOTAL_TICKS:
353       g_value_set_uint (value, filter->total_ticks);
354       break;
355     case PROP_TICKS:
356       g_value_set_pointer (value, (gpointer) filter->ticks);
357       break;
358     default:
359       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
360       break;
361   }
362 }
363
364 static void
365 play_on_demand_finalize (GObject * object)
366 {
367   GstPlayOnDemand *filter = GST_PLAYONDEMAND (object);
368
369   g_free (filter->ticks);
370   g_free (filter->plays);
371   g_free (filter->buffer);
372
373   G_OBJECT_CLASS (parent_class)->finalize (object);
374 }
375
376 static GstPadLinkReturn
377 play_on_demand_pad_link (GstPad * pad, const GstCaps * caps)
378 {
379   const gchar *mimetype;
380   GstPlayOnDemand *filter;
381   GstStructure *structure;
382
383   g_return_val_if_fail (caps != NULL, GST_PAD_LINK_DELAYED);
384   g_return_val_if_fail (pad != NULL, GST_PAD_LINK_DELAYED);
385
386   filter = GST_PLAYONDEMAND (GST_PAD_PARENT (pad));
387
388   structure = gst_caps_get_structure (caps, 0);
389
390   mimetype = gst_structure_get_name (structure);
391   gst_structure_get_int (structure, "rate", &filter->rate);
392   gst_structure_get_int (structure, "channels", &filter->channels);
393
394   if (strcmp (mimetype, "audio/x-raw-int") == 0) {
395     filter->format = GST_PLAYONDEMAND_FORMAT_INT;
396     gst_structure_get_int (structure, "width", &filter->width);
397   } else if (strcmp (mimetype, "audio/x-raw-float") == 0) {
398     filter->format = GST_PLAYONDEMAND_FORMAT_FLOAT;
399   }
400
401   play_on_demand_resize_buffer (filter);
402
403   return gst_pad_try_set_caps (filter->srcpad, caps);
404 }
405
406 inline static void
407 play_on_demand_add_play_pointer (GstPlayOnDemand * filter, guint pos)
408 {
409   register guint i;
410
411   if (filter->rate && ((filter->buffer_time * filter->rate) > pos)) {
412     for (i = 0; i < filter->max_plays; i++) {
413       if (filter->plays[i] == G_MAXUINT) {
414         filter->plays[i] = pos;
415         /* emit a signal to indicate a sample being played */
416         g_signal_emit (filter, gst_pod_filter_signals[PLAYED_SIGNAL], 0);
417         break;
418       }
419     }
420   }
421 }
422
423 static void
424 play_on_demand_loop (GstElement * elem)
425 {
426   GstPlayOnDemand *filter = GST_PLAYONDEMAND (elem);
427   guint num_in, num_out, num_filter;
428   GstData *in = NULL;
429   GstBuffer *out = NULL;
430   static guint last_tick = 0;
431
432   g_return_if_fail (filter != NULL);
433   g_return_if_fail (GST_IS_PLAYONDEMAND (filter));
434
435   in = (in == NULL && !filter->eos) ? gst_pad_pull (filter->sinkpad) : NULL;
436
437   if (filter->format == GST_PLAYONDEMAND_FORMAT_INT) {
438     if (filter->width == 16) {
439       gint16 min = 0xffff;
440       gint16 max = 0x7fff;
441       gint16 zero = 0;
442
443 #define _TYPE_ gint16
444 #include "filter.func"
445 #undef _TYPE_
446     } else if (filter->width == 8) {
447       gint8 min = 0xff;
448       gint8 max = 0x7f;
449       gint8 zero = 0;
450
451 #define _TYPE_ gint8
452 #include "filter.func"
453 #undef _TYPE_
454     }
455   } else if (filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT) {
456     gfloat min = -1.0;
457     gfloat max = 1.0;
458     gfloat zero = 0.0;
459
460 #define _TYPE_ gfloat
461 #include "filter.func"
462 #undef _TYPE_
463   }
464 }
465
466 static gboolean
467 play_on_demand_set_clock (GstElement * elem, GstClock * clock)
468 {
469   GstPlayOnDemand *filter;
470
471   g_return_if_fail (elem != NULL);
472   g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
473   filter = GST_PLAYONDEMAND (elem);
474
475   filter->clock = clock;
476
477   return GST_ELEMENT_CLASS (parent_class)->set_clock (elem, clock);
478 }
479
480 static void
481 play_on_demand_play_handler (GstElement * elem)
482 {
483   GstPlayOnDemand *filter;
484
485   g_return_if_fail (elem != NULL);
486   g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
487   filter = GST_PLAYONDEMAND (elem);
488
489   play_on_demand_add_play_pointer (filter, 0);
490 }
491
492 static void
493 play_on_demand_clear_handler (GstElement * elem)
494 {
495   GstPlayOnDemand *filter;
496   register guint i;
497
498   g_return_if_fail (elem != NULL);
499   g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
500   filter = GST_PLAYONDEMAND (elem);
501
502   filter->write = 0;
503   filter->eos = FALSE;
504
505   for (i = 0; i < filter->max_plays; i++)
506     filter->plays[i] = G_MAXUINT;
507   for (i = 0; i < filter->buffer_bytes; i++)
508     filter->buffer[i] = (gchar) 0;
509 }
510
511 static void
512 play_on_demand_reset_handler (GstElement * elem)
513 {
514   GstPlayOnDemand *filter;
515   register guint i;
516
517   play_on_demand_clear_handler (elem);
518
519   g_return_if_fail (elem != NULL);
520   g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
521   filter = GST_PLAYONDEMAND (elem);
522
523   for (i = 0; i <= filter->total_ticks / 32; i++)
524     filter->ticks[i] = 0;
525 }
526
527 static void
528 play_on_demand_resize_buffer (GstPlayOnDemand * filter)
529 {
530   register guint i;
531   guint new_size, min_size;
532   gchar *new_buffer;
533
534   /* use a default sample rate of 44100, 1 channel, 1 byte per sample if caps
535      haven't been set yet */
536   new_size = (guint) filter->buffer_time;
537   new_size *= (filter->rate) ? filter->rate : 44100;
538   new_size *= (filter->channels) ? filter->channels : 1;
539
540   if (filter->format && filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT)
541     new_size *= sizeof (gfloat);
542   else
543     new_size *= (filter->width) ? filter->width / 8 : 1;
544
545   min_size =
546       (new_size < filter->buffer_bytes) ? new_size : filter->buffer_bytes;
547
548   new_buffer = g_new (gchar, new_size);
549   for (i = 0; i < min_size; i++)
550     new_buffer[i] = filter->buffer[i];
551   for (i = min_size; i < new_size; i++)
552     new_buffer[i] = (gchar) 0;
553
554   g_free (filter->buffer);
555   filter->buffer = new_buffer;
556   filter->buffer_bytes = new_size;
557 }
558
559 static gboolean
560 plugin_init (GstPlugin * plugin)
561 {
562   return gst_element_register (plugin, "playondemand",
563       GST_RANK_NONE, GST_TYPE_PLAYONDEMAND);
564 }
565
566 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
567     GST_VERSION_MINOR,
568     "playondemand",
569     "Plays a stream at specific times, or when it receives a signal",
570     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)