[MOVED FROM GST-P-FARSIGHT] Added dtmfsrc, a DTMF Tone Generator, and made it part...
[platform/upstream/gst-plugins-good.git] / gst / dtmf / gstrtpdtmfsrc.c
1 /* GStreamer RTP DTMF source
2  *
3  * gstrtpdtmfsrc.c:
4  *
5  * Copyright (C) <2007> Nokia Corporation.
6  *   Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
7  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
8  *               2000,2005 Wim Taymans <wim@fluendo.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 /**
27  * SECTION:element-rtpdtmfsrc
28  * @short_description: Generates RTP DTMF packets
29  *
30  * <refsect2>
31  *
32  * <para>
33  * The RTPDTMFSrc element generates RTP DTMF (RFC 2833) event packets on request
34  * from application. The application communicates the beginning and end of a
35  * DTMF event using custom upstream gstreamer events. To report a DTMF event, an
36  * application must send an event of type GST_EVENT_CUSTOM_UPSTREAM, having a
37  * structure of name "dtmf-event" with fields set according to the following
38  * table:
39  * </para>
40  *
41  * <para>
42  * <informaltable>
43  * <tgroup cols='4'>
44  * <colspec colname='Name' />
45  * <colspec colname='Type' />
46  * <colspec colname='Possible values' />
47  * <colspec colname='Purpose' />
48  * 
49  * <thead>
50  * <row>
51  * <entry>Name</entry>
52  * <entry>GType</entry>
53  * <entry>Possible values</entry>
54  * <entry>Purpose</entry>
55  * </row>
56  * </thead>
57  * 
58  * <tbody>
59  * <row>
60  * <entry>type</entry>
61  * <entry>G_TYPE_INT</entry>
62  * <entry>0-1</entry>
63  * <entry>The application uses this field to specify which of the two methods
64  * specified in RFC 2833 to use. The value should be 0 for tones and 1 for
65  * named events. This element is only capable of generating named events.
66  * </entry>
67  * </row>
68  * <row>
69  * <entry>number</entry>
70  * <entry>G_TYPE_INT</entry>
71  * <entry>0-16</entry>
72  * <entry>The event number.</entry>
73  * </row>
74  * <row>
75  * <entry>volume</entry>
76  * <entry>G_TYPE_INT</entry>
77  * <entry>0-36</entry>
78  * <entry>This field describes the power level of the tone, expressed in dBm0
79  * after dropping the sign. Power levels range from 0 to -63 dBm0. The range of
80  * valid DTMF is from 0 to -36 dBm0. Can be omitted if start is set to FALSE.
81  * </entry>
82  * </row>
83  * <row>
84  * <entry>start</entry>
85  * <entry>G_TYPE_BOOLEAN</entry>
86  * <entry>True or False</entry>
87  * <entry>Whether the event is starting or ending.</entry>
88  * </row>
89  * <row>
90  * <entry>method</entry>
91  * <entry>G_TYPE_INT</entry>
92  * <entry>1</entry>
93  * <entry>The method used for sending event, this element will react if this field
94  * is absent or 1.
95  * </entry>
96  * </row>
97  * </tbody>
98  * </tgroup>
99  * </informaltable>
100  * </para>
101  * 
102  * <para>For example, the following code informs the pipeline (and in turn, the
103  * RTPDTMFSrc element inside the pipeline) about the start of an RTP DTMF named
104  * event '1' of volume -25 dBm0:
105  * </para>
106  * 
107  * <para>
108  * <programlisting>
109  * structure = gst_structure_new ("dtmf-event",
110  *                    "type", G_TYPE_INT, 1,
111  *                    "number", G_TYPE_INT, 1,
112  *                    "volume", G_TYPE_INT, 25,
113  *                    "start", G_TYPE_BOOLEAN, TRUE, NULL);
114  * 
115  * event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
116  * gst_element_send_event (pipeline, event);
117  * </programlisting>
118  * </para>
119  *
120  * </refsect2>
121  */
122
123 #ifdef HAVE_CONFIG_H
124 #  include "config.h"
125 #endif
126
127 #include <stdlib.h>
128 #include <string.h>
129
130 #include "gstrtpdtmfsrc.h"
131
132 #define GST_RTP_DTMF_TYPE_EVENT  1
133 #define DEFAULT_PACKET_INTERVAL  50 /* ms */
134 #define MIN_PACKET_INTERVAL      10 /* ms */
135 #define MAX_PACKET_INTERVAL      50 /* ms */
136 #define DEFAULT_SSRC             -1
137 #define DEFAULT_PT               96
138 #define DEFAULT_TIMESTAMP_OFFSET -1
139 #define DEFAULT_SEQNUM_OFFSET    -1
140 #define DEFAULT_CLOCK_RATE       8000
141 #define MIN_EVENT                0
142 #define MAX_EVENT                16
143 #define MIN_EVENT_STRING         "0"
144 #define MAX_EVENT_STRING         "16"
145 #define MIN_VOLUME               0
146 #define MAX_VOLUME               36
147 #define MIN_EVENT_DURATION       50
148
149 #define DEFAULT_PACKET_REDUNDANCY 1
150 #define MIN_PACKET_REDUNDANCY 1
151 #define MAX_PACKET_REDUNDANCY 5
152
153 /* elementfactory information */
154 static const GstElementDetails gst_rtp_dtmf_src_details =
155 GST_ELEMENT_DETAILS ("RTP DTMF packet generator",
156     "Source/Network",
157     "Generates RTP DTMF packets",
158     "Zeeshan Ali <zeeshan.ali@nokia.com>");
159
160 GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_src_debug);
161 #define GST_CAT_DEFAULT gst_rtp_dtmf_src_debug
162
163 /* signals and args */
164 enum
165 {
166   /* FILL ME */
167   LAST_SIGNAL
168 };
169
170 enum
171 {
172   PROP_0,
173   PROP_SSRC,
174   PROP_TIMESTAMP_OFFSET,
175   PROP_SEQNUM_OFFSET,
176   PROP_PT,
177   PROP_CLOCK_RATE,
178   PROP_TIMESTAMP,
179   PROP_SEQNUM,
180   PROP_INTERVAL,
181   PROP_REDUNDANCY
182 };
183
184 static GstStaticPadTemplate gst_rtp_dtmf_src_template =
185 GST_STATIC_PAD_TEMPLATE ("src",
186     GST_PAD_SRC,
187     GST_PAD_ALWAYS,
188     GST_STATIC_CAPS ("application/x-rtp, "
189         "media = (string) \"audio\", "
190         "payload = (int) [ 96, 127 ], "
191         "clock-rate = (int) [ 0, MAX ], " 
192         "ssrc = (int) [ 0, MAX ], " 
193         "events = (int) [ " MIN_EVENT_STRING ", " MAX_EVENT_STRING " ], "
194         "encoding-name = (string) \"telephone-event\"")
195     );
196
197 static GstElementClass *parent_class = NULL;
198
199 static void gst_rtp_dtmf_src_base_init (gpointer g_class);
200 static void gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass);
201 static void gst_rtp_dtmf_src_init (GstRTPDTMFSrc * dtmfsrc, gpointer g_class);
202 static void gst_rtp_dtmf_src_finalize (GObject * object);
203
204 GType
205 gst_rtp_dtmf_src_get_type (void)
206 {
207   static GType base_src_type = 0;
208
209   if (G_UNLIKELY (base_src_type == 0)) {
210     static const GTypeInfo base_src_info = {
211       sizeof (GstRTPDTMFSrcClass),
212       (GBaseInitFunc) gst_rtp_dtmf_src_base_init,
213       NULL,
214       (GClassInitFunc) gst_rtp_dtmf_src_class_init,
215       NULL,
216       NULL,
217       sizeof (GstRTPDTMFSrc),
218       0,
219       (GInstanceInitFunc) gst_rtp_dtmf_src_init,
220     };
221
222     base_src_type = g_type_register_static (GST_TYPE_ELEMENT,
223         "GstRTPDTMFSrc", &base_src_info, 0);
224   }
225   return base_src_type;
226 }
227
228 static void gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
229     const GValue * value, GParamSpec * pspec);
230 static void gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id,
231     GValue * value, GParamSpec * pspec);
232 static gboolean gst_rtp_dtmf_src_handle_event (GstPad * pad, GstEvent * event);
233 static GstStateChangeReturn gst_rtp_dtmf_src_change_state (GstElement * element,
234     GstStateChange transition);
235 static void gst_rtp_dtmf_src_push_next_rtp_packet (GstRTPDTMFSrc *dtmfsrc);
236 static void gst_rtp_dtmf_src_start (GstRTPDTMFSrc *dtmfsrc, gint event_number,
237     gint event_volume);
238 static void gst_rtp_dtmf_src_stop (GstRTPDTMFSrc *dtmfsrc);
239 static void gst_rtp_dtmf_src_set_caps (GstRTPDTMFSrc *dtmfsrc);
240
241 static void
242 gst_rtp_dtmf_src_base_init (gpointer g_class)
243 {
244   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
245   
246   GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_src_debug,
247           "rtpdtmfsrc", 0, "rtpdtmfsrc element");
248   
249   gst_element_class_add_pad_template (element_class,
250       gst_static_pad_template_get (&gst_rtp_dtmf_src_template));
251   
252   gst_element_class_set_details (element_class, &gst_rtp_dtmf_src_details);
253 }
254
255 static void
256 gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass)
257 {
258   GObjectClass *gobject_class;
259   GstElementClass *gstelement_class;
260
261   gobject_class = G_OBJECT_CLASS (klass);
262   gstelement_class = GST_ELEMENT_CLASS (klass);
263
264   parent_class = g_type_class_peek_parent (klass);
265
266   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_finalize);
267   gobject_class->set_property = 
268       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_set_property);
269   gobject_class->get_property =
270       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_get_property);
271
272   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
273       g_param_spec_uint ("timestamp", "Timestamp",
274           "The RTP timestamp of the last processed packet",
275           0, G_MAXUINT, 0, G_PARAM_READABLE));
276   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
277       g_param_spec_uint ("seqnum", "Sequence number",
278           "The RTP sequence number of the last processed packet",
279           0, G_MAXUINT, 0, G_PARAM_READABLE));
280   g_object_class_install_property (G_OBJECT_CLASS (klass),
281       PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
282           "Timestamp Offset",
283           "Offset to add to all outgoing timestamps (-1 = random)", -1,
284           G_MAXINT, DEFAULT_TIMESTAMP_OFFSET, G_PARAM_READWRITE));
285   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
286       g_param_spec_int ("seqnum-offset", "Sequence number Offset",
287           "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
288           DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE));
289   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLOCK_RATE,
290       g_param_spec_uint ("clock-rate", "clockrate",
291           "The clock-rate at which to generate the dtmf packets",
292           0, G_MAXUINT, DEFAULT_CLOCK_RATE, G_PARAM_READWRITE));
293   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
294       g_param_spec_uint ("ssrc", "SSRC",
295           "The SSRC of the packets (-1 == random)",
296           0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
297   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
298       g_param_spec_uint ("pt", "payload type",
299           "The payload type of the packets",
300           0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
301   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INTERVAL,
302       g_param_spec_int ("interval", "Interval between rtp packets",
303           "Interval in ms between two rtp packets", MIN_PACKET_INTERVAL,
304           MAX_PACKET_INTERVAL, DEFAULT_PACKET_INTERVAL, G_PARAM_READWRITE));
305   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_REDUNDANCY,
306       g_param_spec_int ("packet-redundancy", "Packet Redundancy",
307           "Number of packets to send to indicate start and stop dtmf events",
308           MIN_PACKET_REDUNDANCY, MAX_PACKET_REDUNDANCY,
309           DEFAULT_PACKET_REDUNDANCY, G_PARAM_READWRITE));
310
311   gstelement_class->change_state =
312       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_change_state);
313 }
314
315 static void
316 gst_rtp_dtmf_src_init (GstRTPDTMFSrc * dtmfsrc, gpointer g_class)
317 {
318   dtmfsrc->srcpad =
319       gst_pad_new_from_static_template (&gst_rtp_dtmf_src_template, "src");
320   GST_DEBUG_OBJECT (dtmfsrc, "adding src pad");
321   gst_element_add_pad (GST_ELEMENT (dtmfsrc), dtmfsrc->srcpad);
322
323   gst_pad_set_event_function (dtmfsrc->srcpad, gst_rtp_dtmf_src_handle_event);
324   
325   dtmfsrc->ssrc = DEFAULT_SSRC;
326   dtmfsrc->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
327   dtmfsrc->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
328   dtmfsrc->pt = DEFAULT_PT;
329   dtmfsrc->clock_rate = DEFAULT_CLOCK_RATE;
330   dtmfsrc->payload = NULL;
331   dtmfsrc->interval = DEFAULT_PACKET_INTERVAL;
332   dtmfsrc->packet_redundancy = DEFAULT_PACKET_REDUNDANCY;
333   
334   GST_DEBUG_OBJECT (dtmfsrc, "init done");
335 }
336
337 static void
338 gst_rtp_dtmf_src_finalize (GObject * object)
339 {
340   GstRTPDTMFSrc *dtmfsrc;
341
342   dtmfsrc = GST_RTP_DTMF_SRC (object);
343
344   G_OBJECT_CLASS (parent_class)->finalize (object);
345 }
346
347 static gboolean
348 gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc *dtmfsrc,
349         const GstStructure * event_structure)
350 {
351   gint event_type;
352   gboolean start;
353   gint method;
354
355   if (!gst_structure_get_int (event_structure, "type", &event_type) ||
356           !gst_structure_get_boolean (event_structure, "start", &start) ||
357           event_type != GST_RTP_DTMF_TYPE_EVENT)
358     goto failure;
359
360   if (gst_structure_get_int (event_structure, "method", &method)) {
361     if (method != 1) {
362       goto failure;
363     }
364   }
365
366   if (start) {
367     gint event_number;
368     gint event_volume;
369
370     if (!gst_structure_get_int (event_structure, "number", &event_number) ||
371             !gst_structure_get_int (event_structure, "volume", &event_volume))
372       goto failure;
373
374     GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
375             event_number, event_volume);
376     gst_rtp_dtmf_src_start (dtmfsrc, event_number, event_volume);
377   }
378
379   else {
380     GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
381     gst_rtp_dtmf_src_stop (dtmfsrc);
382   }
383
384   return TRUE;
385 failure:
386   return FALSE;
387 }
388
389 static gboolean
390 gst_rtp_dtmf_src_handle_custom_upstream (GstRTPDTMFSrc *dtmfsrc,
391     GstEvent * event)
392 {
393   gboolean result = FALSE;
394   const GstStructure *structure;
395
396   if (GST_STATE (dtmfsrc) != GST_STATE_PLAYING) {
397     GST_DEBUG_OBJECT (dtmfsrc, "Received event while not in PLAYING state");
398     goto ret;
399   }
400
401   GST_DEBUG_OBJECT (dtmfsrc, "Received event is of our interest");
402   structure = gst_event_get_structure (event);
403   if (structure && gst_structure_has_name (structure, "dtmf-event"))
404     result = gst_rtp_dtmf_src_handle_dtmf_event (dtmfsrc, structure);
405
406 ret:
407   return result;
408 }
409
410 static gboolean
411 gst_rtp_dtmf_src_handle_event (GstPad * pad, GstEvent * event)
412 {
413   GstRTPDTMFSrc *dtmfsrc;
414   gboolean result = FALSE;
415
416   dtmfsrc = GST_RTP_DTMF_SRC (GST_PAD_PARENT (pad));
417
418   GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad");
419   switch (GST_EVENT_TYPE (event)) {
420     case GST_EVENT_CUSTOM_UPSTREAM:
421     {
422       result = gst_rtp_dtmf_src_handle_custom_upstream (dtmfsrc, event);
423       break;
424     }
425     /* Ideally this element should not be flushed but let's handle the event
426      * just in case it is */
427     case GST_EVENT_FLUSH_START:
428       gst_rtp_dtmf_src_stop (dtmfsrc);
429       result = TRUE;
430       break;
431     case GST_EVENT_FLUSH_STOP:
432       gst_segment_init (&dtmfsrc->segment, GST_FORMAT_UNDEFINED);
433       break;
434     case GST_EVENT_NEWSEGMENT:
435       {
436         gboolean update;
437         gdouble rate;
438         GstFormat fmt;
439         gint64 start, stop, position;
440
441         gst_event_parse_new_segment (event, &update, &rate, &fmt, &start,
442             &stop, &position);
443         gst_segment_set_newsegment (&dtmfsrc->segment, update, rate, fmt,
444             start, stop, position);
445       }
446       /* fallthrough */
447     default:
448       result = gst_pad_event_default (pad, event);
449       break;
450   }
451
452   gst_event_unref (event);
453   return result;
454 }
455
456 static void
457 gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
458     const GValue * value, GParamSpec * pspec)
459 {
460   GstRTPDTMFSrc *dtmfsrc;
461
462   dtmfsrc = GST_RTP_DTMF_SRC (object);
463
464   switch (prop_id) {
465     case PROP_TIMESTAMP_OFFSET:
466       dtmfsrc->ts_offset = g_value_get_int (value);
467       break;
468     case PROP_SEQNUM_OFFSET:
469       dtmfsrc->seqnum_offset = g_value_get_int (value);
470       break;
471     case PROP_CLOCK_RATE:
472       dtmfsrc->clock_rate = g_value_get_uint (value);
473       gst_rtp_dtmf_src_set_caps (dtmfsrc);
474       break;
475     case PROP_SSRC:
476       dtmfsrc->ssrc = g_value_get_uint (value);
477       break;
478     case PROP_PT:
479       dtmfsrc->pt = g_value_get_uint (value);
480       gst_rtp_dtmf_src_set_caps (dtmfsrc);
481       break;
482     case PROP_INTERVAL:
483       dtmfsrc->interval = g_value_get_int (value);
484       break;
485     case PROP_REDUNDANCY:
486       dtmfsrc->packet_redundancy = g_value_get_int (value);
487       break;
488     default:
489       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
490       break;
491   }
492 }
493
494 static void
495 gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
496     GParamSpec * pspec)
497 {
498   GstRTPDTMFSrc *dtmfsrc;
499
500   dtmfsrc = GST_RTP_DTMF_SRC (object);
501
502   switch (prop_id) {
503     case PROP_TIMESTAMP_OFFSET:
504       g_value_set_int (value, dtmfsrc->ts_offset);
505       break;
506     case PROP_SEQNUM_OFFSET:
507       g_value_set_int (value, dtmfsrc->seqnum_offset);
508       break;
509     case PROP_CLOCK_RATE:
510       g_value_set_uint (value, dtmfsrc->clock_rate);
511       break;
512     case PROP_SSRC:
513       g_value_set_uint (value, dtmfsrc->ssrc);
514       break;
515     case PROP_PT:
516       g_value_set_uint (value, dtmfsrc->pt);
517       break;
518     case PROP_TIMESTAMP:
519       g_value_set_uint (value, dtmfsrc->rtp_timestamp);
520       break;
521     case PROP_SEQNUM:
522       g_value_set_uint (value, dtmfsrc->seqnum);
523       break;
524     case PROP_INTERVAL:
525       g_value_set_uint (value, dtmfsrc->interval);
526       break;
527     case PROP_REDUNDANCY:
528       g_value_set_uint (value, dtmfsrc->packet_redundancy);
529       break;
530     default:
531       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
532       break;
533   }
534 }
535
536 static void
537 gst_rtp_dtmf_src_set_stream_lock (GstRTPDTMFSrc *dtmfsrc, gboolean lock)
538 {
539    GstEvent *event;
540    GstStructure *structure;
541
542    structure = gst_structure_new ("stream-lock",
543                       "lock", G_TYPE_BOOLEAN, lock, NULL);
544
545    event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure);
546    gst_pad_push_event (dtmfsrc->srcpad, event);
547 }
548
549 static void
550 gst_rtp_dtmf_prepare_timestamps (GstRTPDTMFSrc *dtmfsrc)
551 {
552   GstClock *clock;
553
554   clock = GST_ELEMENT_CLOCK (dtmfsrc);
555   if (clock != NULL)
556     dtmfsrc->timestamp = gst_clock_get_time (GST_ELEMENT_CLOCK (dtmfsrc));
557
558   else {
559     GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s",
560         GST_ELEMENT_NAME (dtmfsrc));
561     dtmfsrc->timestamp = GST_CLOCK_TIME_NONE;
562   }
563
564   dtmfsrc->rtp_timestamp = dtmfsrc->ts_base +
565       gst_util_uint64_scale_int (
566           gst_segment_to_running_time (&dtmfsrc->segment, GST_FORMAT_TIME,
567               dtmfsrc->timestamp),
568           dtmfsrc->clock_rate, GST_SECOND);
569 }
570
571 static void
572 gst_rtp_dtmf_src_start (GstRTPDTMFSrc *dtmfsrc,
573         gint event_number, gint event_volume)
574 {
575   g_return_if_fail (dtmfsrc->payload == NULL);
576
577   dtmfsrc->payload = g_new0 (GstRTPDTMFPayload, 1);
578   dtmfsrc->payload->event = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
579   dtmfsrc->payload->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
580   dtmfsrc->first_packet = TRUE;
581   dtmfsrc->last_packet = FALSE;
582
583   gst_rtp_dtmf_prepare_timestamps (dtmfsrc);
584   gst_rtp_dtmf_src_set_caps (dtmfsrc);
585
586   /* Don't forget to get exclusive access to the stream */
587   gst_rtp_dtmf_src_set_stream_lock (dtmfsrc, TRUE);
588   
589   if (!gst_pad_start_task (dtmfsrc->srcpad,
590       (GstTaskFunction) gst_rtp_dtmf_src_push_next_rtp_packet, dtmfsrc)) {
591     GST_ERROR_OBJECT (dtmfsrc, "Failed to start task on src pad");
592   }
593 }
594
595 static void
596 gst_rtp_dtmf_src_stop (GstRTPDTMFSrc *dtmfsrc)
597 {
598   g_return_if_fail (dtmfsrc->payload != NULL);
599
600   /* Push the last packet with e-bit set */
601   /* Next packet sent will be the last */
602   dtmfsrc->last_packet = TRUE;
603
604 }
605
606 static void
607 gst_rtp_dtmf_src_wait_for_buffer_ts (GstRTPDTMFSrc *dtmfsrc, GstBuffer * buf)
608 {
609   GstClock *clock;
610   
611   clock = GST_ELEMENT_CLOCK (dtmfsrc);
612   if (clock != NULL) {
613     GstClockID clock_id;
614     GstClockReturn clock_ret;
615
616     clock_id = gst_clock_new_single_shot_id (clock, GST_BUFFER_TIMESTAMP (buf));
617     clock_ret = gst_clock_id_wait (clock_id, NULL);
618     if (clock_ret != GST_CLOCK_OK && clock_ret != GST_CLOCK_EARLY) {
619       GST_ERROR_OBJECT (dtmfsrc, "Failed to wait on clock %s",
620               GST_ELEMENT_NAME (clock));
621     }
622     gst_clock_id_unref (clock_id);
623   }
624
625   else {
626     GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s",
627         GST_ELEMENT_NAME (dtmfsrc));
628   }
629 }
630
631 static void
632 gst_rtp_dtmf_prepare_rtp_headers (GstRTPDTMFSrc *dtmfsrc, GstBuffer *buf)
633 {
634   gst_rtp_buffer_set_ssrc (buf, dtmfsrc->current_ssrc);
635   gst_rtp_buffer_set_payload_type (buf, dtmfsrc->pt);
636   if (dtmfsrc->first_packet) {
637     gst_rtp_buffer_set_marker (buf, TRUE);
638     dtmfsrc->first_packet = FALSE;
639   } else if (dtmfsrc->last_packet) {
640     dtmfsrc->payload->e = 1;
641     dtmfsrc->last_packet = FALSE;
642   }
643
644   dtmfsrc->seqnum++;
645   gst_rtp_buffer_set_seq (buf, dtmfsrc->seqnum);
646   
647   /* timestamp of RTP header */
648   gst_rtp_buffer_set_timestamp (buf, dtmfsrc->rtp_timestamp);
649 }
650
651 static void
652 gst_rtp_dtmf_prepare_buffer_data (GstRTPDTMFSrc *dtmfsrc, GstBuffer *buf)
653 {
654   GstRTPDTMFPayload *payload;
655   
656   gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, buf);
657
658   /* duration of DTMF payload */
659   dtmfsrc->payload->duration +=
660       dtmfsrc->interval * dtmfsrc->clock_rate / 1000;
661
662   /* timestamp and duration of GstBuffer */ 
663   GST_BUFFER_DURATION (buf) = dtmfsrc->interval * GST_MSECOND;
664   GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
665   dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
666   
667   payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (buf);
668   
669   /* copy payload and convert to network-byte order */
670   g_memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload));
671   /* Force the packet duration to a certain minumum
672    * if its the end of the event
673    */
674   if (payload->e &&
675       payload->duration < MIN_EVENT_DURATION * dtmfsrc->clock_rate / 1000)
676     payload->duration = MIN_EVENT_DURATION * dtmfsrc->clock_rate / 1000;
677
678   payload->duration = g_htons (payload->duration);
679 }
680
681 static GstBuffer *
682 gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc *dtmfsrc)
683 {
684   GstBuffer *buf = NULL;
685   
686   /* create buffer to hold the payload */
687   buf = gst_rtp_buffer_new_allocate (sizeof (GstRTPDTMFPayload), 0, 0);
688
689   gst_rtp_dtmf_prepare_buffer_data (dtmfsrc, buf);
690
691   /* FIXME: Should we sync to clock ourselves or leave it to sink */
692   gst_rtp_dtmf_src_wait_for_buffer_ts (dtmfsrc, buf);
693
694   /* Set caps on the buffer before pushing it */
695   gst_buffer_set_caps (buf, GST_PAD_CAPS (dtmfsrc->srcpad));
696
697   return buf;
698 }
699
700 static void
701 gst_rtp_dtmf_src_push_next_rtp_packet (GstRTPDTMFSrc *dtmfsrc)
702 {
703   GstBuffer *buf = NULL;
704   GstFlowReturn ret;
705   gint redundancy_count = 1;
706
707   if (dtmfsrc->first_packet == TRUE || dtmfsrc->last_packet == TRUE) {
708     redundancy_count = dtmfsrc->packet_redundancy;
709
710     if(dtmfsrc->first_packet == TRUE) {
711       GST_DEBUG_OBJECT (dtmfsrc,
712           "redundancy count set to %d due to dtmf start",
713           redundancy_count);
714     } else if(dtmfsrc->last_packet == TRUE) {
715       GST_DEBUG_OBJECT (dtmfsrc,
716           "redundancy count set to %d due to dtmf stop",
717           redundancy_count);
718     }
719
720   }
721
722   /* create buffer to hold the payload */
723   buf = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);
724
725   while ( redundancy_count-- ) {
726     gst_buffer_ref(buf);
727
728     GST_DEBUG_OBJECT (dtmfsrc,
729         "pushing buffer on src pad of size %d with redundancy count %d",
730         GST_BUFFER_SIZE (buf), redundancy_count);
731     ret = gst_pad_push (dtmfsrc->srcpad, buf);
732     if (ret != GST_FLOW_OK)
733       GST_ERROR_OBJECT (dtmfsrc,
734           "Failed to push buffer on src pad", GST_BUFFER_SIZE (buf));
735
736     /* Make sure only the first packet sent has the marker set */
737     gst_rtp_buffer_set_marker (buf, FALSE);
738   }
739
740   gst_buffer_unref(buf);
741   GST_DEBUG_OBJECT (dtmfsrc,
742           "pushed DTMF event '%d' on src pad", dtmfsrc->payload->event);
743
744   if (dtmfsrc->payload->e) {
745     /* Don't forget to release the stream lock */
746     gst_rtp_dtmf_src_set_stream_lock (dtmfsrc, FALSE);
747
748     g_free (dtmfsrc->payload);
749     dtmfsrc->payload = NULL;
750
751     if (!gst_pad_pause_task (dtmfsrc->srcpad)) {
752       GST_ERROR_OBJECT (dtmfsrc, "Failed to pause task on src pad");
753       return;
754     }
755
756   }
757
758 }
759
760 static void
761 gst_rtp_dtmf_src_set_caps (GstRTPDTMFSrc *dtmfsrc)
762 {
763   GstCaps *caps;
764
765   caps = gst_caps_new_simple ("application/x-rtp",
766       "media", G_TYPE_STRING, "audio",
767       "payload", G_TYPE_INT, dtmfsrc->pt,
768       "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate,
769       "encoding-name", G_TYPE_STRING, "telephone-event",
770       "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc,
771       "clock-base", G_TYPE_UINT, dtmfsrc->ts_base,
772       "seqnum-base", G_TYPE_UINT, dtmfsrc->seqnum_base, NULL);
773
774   if (!gst_pad_set_caps (dtmfsrc->srcpad, caps))
775     GST_ERROR_OBJECT (dtmfsrc,
776             "Failed to set caps %" GST_PTR_FORMAT " on src pad", caps);
777   else
778     GST_DEBUG_OBJECT (dtmfsrc,
779             "caps %" GST_PTR_FORMAT " set on src pad", caps);
780
781   gst_caps_unref (caps);
782 }
783
784 static void
785 gst_rtp_dtmf_src_ready_to_paused (GstRTPDTMFSrc *dtmfsrc)
786 {
787   gst_segment_init (&dtmfsrc->segment, GST_FORMAT_UNDEFINED);
788   
789   if (dtmfsrc->ssrc == -1)
790     dtmfsrc->current_ssrc = g_random_int ();
791   else
792     dtmfsrc->current_ssrc = dtmfsrc->ssrc;
793
794   if (dtmfsrc->seqnum_offset == -1)
795     dtmfsrc->seqnum_base = g_random_int_range (0, G_MAXUINT16);
796   else
797     dtmfsrc->seqnum_base = dtmfsrc->seqnum_offset;
798   dtmfsrc->seqnum = dtmfsrc->seqnum_base;
799   
800   if (dtmfsrc->ts_offset == -1)
801     dtmfsrc->ts_base = g_random_int ();
802   else
803     dtmfsrc->ts_base = dtmfsrc->ts_offset;
804 }
805
806 static GstStateChangeReturn
807 gst_rtp_dtmf_src_change_state (GstElement * element, GstStateChange transition)
808 {
809   GstRTPDTMFSrc *dtmfsrc;
810   GstStateChangeReturn result;
811   gboolean no_preroll = FALSE;
812
813   dtmfsrc = GST_RTP_DTMF_SRC (element);
814
815   switch (transition) {
816     case GST_STATE_CHANGE_READY_TO_PAUSED:
817       gst_rtp_dtmf_src_ready_to_paused (dtmfsrc);
818       /* Indicate that we don't do PRE_ROLL */
819       no_preroll = TRUE;
820       break;
821     default:
822       break;
823   }
824
825   if ((result =
826           GST_ELEMENT_CLASS (parent_class)->change_state (element,
827               transition)) == GST_STATE_CHANGE_FAILURE)
828     goto failure;
829
830   switch (transition) {
831     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
832       /* Indicate that we don't do PRE_ROLL */
833       no_preroll = TRUE;
834       break;
835     default:
836       break;
837   }
838
839   if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
840     result = GST_STATE_CHANGE_NO_PREROLL;
841
842   return result;
843
844   /* ERRORS */
845 failure:
846   {
847     GST_ERROR_OBJECT (dtmfsrc, "parent failed state change");
848     return result;
849   }
850 }
851
852 gboolean
853 gst_rtp_dtmf_src_plugin_init (GstPlugin * plugin)
854 {
855   return gst_element_register (plugin, "rtpdtmfsrc",
856       GST_RANK_NONE, GST_TYPE_RTP_DTMF_SRC);
857 }