9c796fff4a4655906d8d2200d936605a5f94e62f
[platform/upstream/gstreamer.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
94  * field 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 <glib.h>
131
132 #include "gstrtpdtmfsrc.h"
133
134 #define GST_RTP_DTMF_TYPE_EVENT  1
135 #define DEFAULT_PACKET_INTERVAL  50 /* ms */
136 #define MIN_PACKET_INTERVAL      10 /* ms */
137 #define MAX_PACKET_INTERVAL      50 /* ms */
138 #define DEFAULT_SSRC             -1
139 #define DEFAULT_PT               96
140 #define DEFAULT_TIMESTAMP_OFFSET -1
141 #define DEFAULT_SEQNUM_OFFSET    -1
142 #define DEFAULT_CLOCK_RATE       8000
143 #define MIN_EVENT                0
144 #define MAX_EVENT                16
145 #define MIN_EVENT_STRING         "0"
146 #define MAX_EVENT_STRING         "16"
147 #define MIN_VOLUME               0
148 #define MAX_VOLUME               36
149
150 #define MIN_INTER_DIGIT_INTERVAL 50 /* ms */
151 #define MIN_PULSE_DURATION       70 /* ms */
152
153 #define DEFAULT_PACKET_REDUNDANCY 1
154 #define MIN_PACKET_REDUNDANCY 1
155 #define MAX_PACKET_REDUNDANCY 5
156
157 /* elementfactory information */
158 static const GstElementDetails gst_rtp_dtmf_src_details =
159 GST_ELEMENT_DETAILS ("RTP DTMF packet generator",
160     "Source/Network",
161     "Generates RTP DTMF packets",
162     "Zeeshan Ali <zeeshan.ali@nokia.com>");
163
164 GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_src_debug);
165 #define GST_CAT_DEFAULT gst_rtp_dtmf_src_debug
166
167 /* signals and args */
168 enum
169 {
170   /* FILL ME */
171   LAST_SIGNAL
172 };
173
174 enum
175 {
176   PROP_0,
177   PROP_SSRC,
178   PROP_TIMESTAMP_OFFSET,
179   PROP_SEQNUM_OFFSET,
180   PROP_PT,
181   PROP_CLOCK_RATE,
182   PROP_TIMESTAMP,
183   PROP_SEQNUM,
184   PROP_INTERVAL,
185   PROP_REDUNDANCY
186 };
187
188 static GstStaticPadTemplate gst_rtp_dtmf_src_template =
189 GST_STATIC_PAD_TEMPLATE ("src",
190     GST_PAD_SRC,
191     GST_PAD_ALWAYS,
192     GST_STATIC_CAPS ("application/x-rtp, "
193         "media = (string) \"audio\", "
194         "payload = (int) [ 96, 127 ], "
195         "clock-rate = (int) [ 0, MAX ], "
196         "ssrc = (int) [ 0, MAX ], "
197         "events = (int) [ " MIN_EVENT_STRING ", " MAX_EVENT_STRING " ], "
198         "encoding-name = (string) \"telephone-event\"")
199     );
200
201
202 GST_BOILERPLATE (GstRTPDTMFSrc, gst_rtp_dtmf_src, GstBaseSrc,
203     GST_TYPE_BASE_SRC);
204
205
206 static void gst_rtp_dtmf_src_base_init (gpointer g_class);
207 static void gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass);
208 static void gst_rtp_dtmf_src_finalize (GObject * object);
209
210
211 static void gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
212     const GValue * value, GParamSpec * pspec);
213 static void gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id,
214     GValue * value, GParamSpec * pspec);
215 static gboolean gst_rtp_dtmf_src_handle_event (GstBaseSrc *basesrc,
216     GstEvent * event);
217 static GstStateChangeReturn gst_rtp_dtmf_src_change_state (GstElement * element,
218     GstStateChange transition);
219 static void gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc *dtmfsrc,
220     gint event_number, gint event_volume);
221 static void gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc *dtmfsrc);
222
223 static gboolean gst_rtp_dtmf_src_unlock (GstBaseSrc *src);
224 static gboolean gst_rtp_dtmf_src_unlock_stop (GstBaseSrc *src);
225 static GstFlowReturn gst_rtp_dtmf_src_create (GstBaseSrc * basesrc,
226     guint64 offset, guint length, GstBuffer ** buffer);
227 static gboolean gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc);
228
229
230 static void
231 gst_rtp_dtmf_src_base_init (gpointer g_class)
232 {
233   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
234
235   GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_src_debug,
236           "rtpdtmfsrc", 0, "rtpdtmfsrc element");
237
238   gst_element_class_add_pad_template (element_class,
239       gst_static_pad_template_get (&gst_rtp_dtmf_src_template));
240
241   gst_element_class_set_details (element_class, &gst_rtp_dtmf_src_details);
242 }
243
244 static void
245 gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass)
246 {
247   GObjectClass *gobject_class;
248   GstBaseSrcClass *gstbasesrc_class;
249   GstElementClass *gstelement_class;
250
251   gobject_class = G_OBJECT_CLASS (klass);
252   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
253   gstelement_class = GST_ELEMENT_CLASS (klass);
254
255   parent_class = g_type_class_peek_parent (klass);
256
257   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_finalize);
258   gobject_class->set_property =
259       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_set_property);
260   gobject_class->get_property =
261       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_get_property);
262
263   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
264       g_param_spec_uint ("timestamp", "Timestamp",
265           "The RTP timestamp of the last processed packet",
266           0, G_MAXUINT, 0, G_PARAM_READABLE));
267   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
268       g_param_spec_uint ("seqnum", "Sequence number",
269           "The RTP sequence number of the last processed packet",
270           0, G_MAXUINT, 0, G_PARAM_READABLE));
271   g_object_class_install_property (G_OBJECT_CLASS (klass),
272       PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
273           "Timestamp Offset",
274           "Offset to add to all outgoing timestamps (-1 = random)", -1,
275           G_MAXINT, DEFAULT_TIMESTAMP_OFFSET, G_PARAM_READWRITE));
276   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
277       g_param_spec_int ("seqnum-offset", "Sequence number Offset",
278           "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
279           DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE));
280   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLOCK_RATE,
281       g_param_spec_uint ("clock-rate", "clockrate",
282           "The clock-rate at which to generate the dtmf packets",
283           0, G_MAXUINT, DEFAULT_CLOCK_RATE, G_PARAM_READWRITE));
284   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
285       g_param_spec_uint ("ssrc", "SSRC",
286           "The SSRC of the packets (-1 == random)",
287           0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
288   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
289       g_param_spec_uint ("pt", "payload type",
290           "The payload type of the packets",
291           0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
292   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INTERVAL,
293       g_param_spec_uint ("interval", "Interval between rtp packets",
294           "Interval in ms between two rtp packets", MIN_PACKET_INTERVAL,
295           MAX_PACKET_INTERVAL, DEFAULT_PACKET_INTERVAL, G_PARAM_READWRITE));
296   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_REDUNDANCY,
297       g_param_spec_uint ("packet-redundancy", "Packet Redundancy",
298           "Number of packets to send to indicate start and stop dtmf events",
299           MIN_PACKET_REDUNDANCY, MAX_PACKET_REDUNDANCY,
300           DEFAULT_PACKET_REDUNDANCY, G_PARAM_READWRITE));
301
302   gstelement_class->change_state =
303       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_change_state);
304
305   gstbasesrc_class->unlock =
306       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock);
307   gstbasesrc_class->unlock_stop =
308       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock_stop);
309
310   gstbasesrc_class->event =
311       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_handle_event);
312   gstbasesrc_class->create =
313       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_create);
314   gstbasesrc_class->negotiate =
315       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_negotiate);
316 }
317
318 static void
319 gst_rtp_dtmf_src_init (GstRTPDTMFSrc * object, GstRTPDTMFSrcClass * g_class)
320 {
321   gst_base_src_set_format (GST_BASE_SRC (object), GST_FORMAT_TIME);
322   gst_base_src_set_live (GST_BASE_SRC (object), TRUE);
323
324   object->ssrc = DEFAULT_SSRC;
325   object->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
326   object->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
327   object->pt = DEFAULT_PT;
328   object->clock_rate = DEFAULT_CLOCK_RATE;
329   object->interval = DEFAULT_PACKET_INTERVAL;
330   object->packet_redundancy = DEFAULT_PACKET_REDUNDANCY;
331
332   object->event_queue = g_async_queue_new ();
333   object->payload = NULL;
334
335   GST_DEBUG_OBJECT (object, "init done");
336 }
337
338 static void
339 gst_rtp_dtmf_src_finalize (GObject * object)
340 {
341   GstRTPDTMFSrc *dtmfsrc;
342
343   dtmfsrc = GST_RTP_DTMF_SRC (object);
344
345   if (dtmfsrc->event_queue) {
346     g_async_queue_unref (dtmfsrc->event_queue);
347     dtmfsrc->event_queue = NULL;
348   }
349
350
351   G_OBJECT_CLASS (parent_class)->finalize (object);
352 }
353
354 static gboolean
355 gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc *dtmfsrc,
356         const GstStructure * event_structure)
357 {
358   gint event_type;
359   gboolean start;
360   gint method;
361
362   if (!gst_structure_get_int (event_structure, "type", &event_type) ||
363           !gst_structure_get_boolean (event_structure, "start", &start) ||
364           event_type != GST_RTP_DTMF_TYPE_EVENT)
365     goto failure;
366
367   if (gst_structure_get_int (event_structure, "method", &method)) {
368     if (method != 1) {
369       goto failure;
370     }
371   }
372
373   if (start) {
374     gint event_number;
375     gint event_volume;
376
377     if (!gst_structure_get_int (event_structure, "number", &event_number) ||
378             !gst_structure_get_int (event_structure, "volume", &event_volume))
379       goto failure;
380
381     GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
382             event_number, event_volume);
383     gst_rtp_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
384   }
385
386   else {
387     GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
388     gst_rtp_dtmf_src_add_stop_event (dtmfsrc);
389   }
390
391   return TRUE;
392 failure:
393   return FALSE;
394 }
395
396 static gboolean
397 gst_rtp_dtmf_src_handle_custom_upstream (GstRTPDTMFSrc *dtmfsrc,
398     GstEvent * event)
399 {
400   gboolean result = FALSE;
401   gchar *struct_str;
402   const GstStructure *structure;
403
404   GstState state;
405   GstStateChangeReturn ret;
406
407   ret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
408   if (ret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
409     GST_DEBUG_OBJECT (dtmfsrc, "Received event while not in PLAYING state");
410     goto ret;
411   }
412
413   GST_DEBUG_OBJECT (dtmfsrc, "Received event is of our interest");
414   structure = gst_event_get_structure (event);
415   struct_str = gst_structure_to_string (structure);
416   GST_DEBUG_OBJECT (dtmfsrc, "Event has structure %s", struct_str);
417   g_free (struct_str);
418   if (structure && gst_structure_has_name (structure, "dtmf-event"))
419     result = gst_rtp_dtmf_src_handle_dtmf_event (dtmfsrc, structure);
420
421 ret:
422   return result;
423 }
424
425 static gboolean
426 gst_rtp_dtmf_src_handle_event (GstBaseSrc *basesrc, GstEvent * event)
427 {
428   GstRTPDTMFSrc *dtmfsrc;
429   gboolean result = FALSE;
430
431   dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
432
433   GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad");
434   if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
435     result = gst_rtp_dtmf_src_handle_custom_upstream (dtmfsrc, event);
436   }
437
438   return result;
439 }
440
441 static void
442 gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
443     const GValue * value, GParamSpec * pspec)
444 {
445   GstRTPDTMFSrc *dtmfsrc;
446
447   dtmfsrc = GST_RTP_DTMF_SRC (object);
448
449   switch (prop_id) {
450     case PROP_TIMESTAMP_OFFSET:
451       dtmfsrc->ts_offset = g_value_get_int (value);
452       break;
453     case PROP_SEQNUM_OFFSET:
454       dtmfsrc->seqnum_offset = g_value_get_int (value);
455       break;
456     case PROP_CLOCK_RATE:
457       dtmfsrc->clock_rate = g_value_get_uint (value);
458       dtmfsrc->dirty = TRUE;
459       break;
460     case PROP_SSRC:
461       dtmfsrc->ssrc = g_value_get_uint (value);
462       break;
463     case PROP_PT:
464       dtmfsrc->pt = g_value_get_uint (value);
465       dtmfsrc->dirty = TRUE;
466       break;
467     case PROP_INTERVAL:
468       dtmfsrc->interval = g_value_get_uint (value);
469       break;
470     case PROP_REDUNDANCY:
471       dtmfsrc->packet_redundancy = g_value_get_uint (value);
472       break;
473     default:
474       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
475       break;
476   }
477 }
478
479 static void
480 gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
481     GParamSpec * pspec)
482 {
483   GstRTPDTMFSrc *dtmfsrc;
484
485   dtmfsrc = GST_RTP_DTMF_SRC (object);
486
487   switch (prop_id) {
488     case PROP_TIMESTAMP_OFFSET:
489       g_value_set_int (value, dtmfsrc->ts_offset);
490       break;
491     case PROP_SEQNUM_OFFSET:
492       g_value_set_int (value, dtmfsrc->seqnum_offset);
493       break;
494     case PROP_CLOCK_RATE:
495       g_value_set_uint (value, dtmfsrc->clock_rate);
496       break;
497     case PROP_SSRC:
498       g_value_set_uint (value, dtmfsrc->ssrc);
499       break;
500     case PROP_PT:
501       g_value_set_uint (value, dtmfsrc->pt);
502       break;
503     case PROP_TIMESTAMP:
504       g_value_set_uint (value, dtmfsrc->rtp_timestamp);
505       break;
506     case PROP_SEQNUM:
507       g_value_set_uint (value, dtmfsrc->seqnum);
508       break;
509     case PROP_INTERVAL:
510       g_value_set_uint (value, dtmfsrc->interval);
511       break;
512     case PROP_REDUNDANCY:
513       g_value_set_uint (value, dtmfsrc->packet_redundancy);
514       break;
515     default:
516       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
517       break;
518   }
519 }
520
521 static void
522 gst_rtp_dtmf_src_set_stream_lock (GstRTPDTMFSrc *dtmfsrc, gboolean lock)
523 {
524    GstEvent *event;
525    GstStructure *structure;
526
527    structure = gst_structure_new ("stream-lock",
528                       "lock", G_TYPE_BOOLEAN, lock, NULL);
529
530    event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure);
531    if (!gst_pad_push_event (GST_BASE_SRC_PAD (dtmfsrc), event)) {
532      GST_WARNING_OBJECT (dtmfsrc, "stream-lock event not handled");
533    }
534
535 }
536
537 static void
538 gst_rtp_dtmf_prepare_timestamps (GstRTPDTMFSrc *dtmfsrc)
539 {
540   GstClock *clock;
541   GstClockTime base_time;
542
543   base_time = gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
544
545   clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
546   if (clock != NULL) {
547     dtmfsrc->timestamp = gst_clock_get_time (clock)
548         + (MIN_INTER_DIGIT_INTERVAL * GST_MSECOND) - base_time;
549     dtmfsrc->start_timestamp = dtmfsrc->timestamp;
550     gst_object_unref (clock);
551   } else {
552     gchar *dtmf_name = gst_element_get_name (dtmfsrc);
553     GST_ERROR_OBJECT (dtmfsrc, "No clock set for element %s", dtmf_name);
554     dtmfsrc->timestamp = GST_CLOCK_TIME_NONE;
555     g_free (dtmf_name);
556   }
557
558   dtmfsrc->rtp_timestamp = dtmfsrc->ts_base +
559       gst_util_uint64_scale_int (
560           gst_segment_to_running_time (&GST_BASE_SRC (dtmfsrc)->segment,
561               GST_FORMAT_TIME, dtmfsrc->timestamp),
562           dtmfsrc->clock_rate, GST_SECOND);
563 }
564
565
566 static void
567 gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc *dtmfsrc, gint event_number,
568     gint event_volume)
569 {
570
571   GstRTPDTMFSrcEvent * event = g_malloc (sizeof(GstRTPDTMFSrcEvent));
572   event->event_type = RTP_DTMF_EVENT_TYPE_START;
573
574   event->payload = g_new0 (GstRTPDTMFPayload, 1);
575   event->payload->event = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
576   event->payload->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
577   event->payload->duration = dtmfsrc->interval * dtmfsrc->clock_rate / 1000;
578
579   g_async_queue_push (dtmfsrc->event_queue, event);
580 }
581
582 static void
583 gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc *dtmfsrc)
584 {
585
586   GstRTPDTMFSrcEvent * event = g_malloc (sizeof(GstRTPDTMFSrcEvent));
587   event->event_type = RTP_DTMF_EVENT_TYPE_STOP;
588
589   g_async_queue_push (dtmfsrc->event_queue, event);
590 }
591
592
593 static void
594 gst_rtp_dtmf_prepare_rtp_headers (GstRTPDTMFSrc *dtmfsrc, GstBuffer *buf)
595 {
596   gst_rtp_buffer_set_ssrc (buf, dtmfsrc->current_ssrc);
597   gst_rtp_buffer_set_payload_type (buf, dtmfsrc->pt);
598   /* Only the very first packet gets a marker */
599   if (dtmfsrc->first_packet) {
600     gst_rtp_buffer_set_marker (buf, TRUE);
601   } else if (dtmfsrc->last_packet) {
602     dtmfsrc->payload->e = 1;
603   }
604
605   dtmfsrc->seqnum++;
606   gst_rtp_buffer_set_seq (buf, dtmfsrc->seqnum);
607
608   /* timestamp of RTP header */
609   gst_rtp_buffer_set_timestamp (buf, dtmfsrc->rtp_timestamp);
610 }
611
612 static void
613 gst_rtp_dtmf_prepare_buffer_data (GstRTPDTMFSrc *dtmfsrc, GstBuffer *buf)
614 {
615   GstRTPDTMFPayload *payload;
616
617   gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, buf);
618
619   /* timestamp and duration of GstBuffer */
620   /* Redundant buffer have no duration ... */
621   if (dtmfsrc->redundancy_count > 1)
622     GST_BUFFER_DURATION (buf) = 0;
623   else
624     GST_BUFFER_DURATION (buf) = dtmfsrc->interval * GST_MSECOND;
625   GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
626
627   dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
628
629   payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (buf);
630
631   /* copy payload and convert to network-byte order */
632   g_memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload));
633   /* Force the packet duration to a certain minumum
634    * if its the end of the event
635    */
636   if (payload->e &&
637       payload->duration < MIN_PULSE_DURATION * dtmfsrc->clock_rate / 1000 )
638     payload->duration = MIN_PULSE_DURATION * dtmfsrc->clock_rate / 1000;
639
640   payload->duration = g_htons (payload->duration);
641
642
643   /* duration of DTMF payloadfor the NEXT packet */
644   /* not updated for redundant packets */
645   if (dtmfsrc->redundancy_count == 0)
646     dtmfsrc->payload->duration +=
647         dtmfsrc->interval * dtmfsrc->clock_rate / 1000;
648
649 }
650
651 static GstBuffer *
652 gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc *dtmfsrc)
653 {
654   GstBuffer *buf = NULL;
655
656   /* create buffer to hold the payload */
657   buf = gst_rtp_buffer_new_allocate (sizeof (GstRTPDTMFPayload), 0, 0);
658
659   gst_rtp_dtmf_prepare_buffer_data (dtmfsrc, buf);
660
661   /* Set caps on the buffer before pushing it */
662   gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (dtmfsrc)));
663
664   return buf;
665 }
666
667 static GstFlowReturn
668 gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
669     guint length, GstBuffer ** buffer)
670 {
671   GstRTPDTMFSrcEvent *event;
672   GstRTPDTMFSrc * dtmfsrc;
673   GstClock *clock;
674   GstClockID *clockid;
675   GstClockReturn clockret;
676
677   dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
678
679   do {
680
681     if (dtmfsrc->payload == NULL) {
682       GST_DEBUG_OBJECT (dtmfsrc, "popping");
683       event = g_async_queue_pop (dtmfsrc->event_queue);
684
685       GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);
686
687       switch (event->event_type) {
688         case RTP_DTMF_EVENT_TYPE_STOP:
689           GST_WARNING_OBJECT (dtmfsrc,
690               "Received a DTMF stop event when already stopped");
691           break;
692
693         case RTP_DTMF_EVENT_TYPE_START:
694           dtmfsrc->first_packet = TRUE;
695           dtmfsrc->last_packet = FALSE;
696           /* Set the redundanc on the first packet */
697           dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
698           gst_rtp_dtmf_prepare_timestamps (dtmfsrc);
699
700           /* Don't forget to get exclusive access to the stream */
701           gst_rtp_dtmf_src_set_stream_lock (dtmfsrc, TRUE);
702
703           dtmfsrc->payload = event->payload;
704           break;
705
706         case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
707           /*
708            * We're pushing it back because it has to stay in there until
709            * the task is really paused (and the queue will then be flushed
710            */
711           GST_OBJECT_LOCK (dtmfsrc);
712           if (dtmfsrc->paused) {
713             g_async_queue_push (dtmfsrc->event_queue, event);
714             goto paused_locked;
715           }
716           GST_OBJECT_UNLOCK (dtmfsrc);
717           break;
718       }
719
720       g_free (event);
721     } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
722         (dtmfsrc->timestamp - dtmfsrc->start_timestamp)/GST_MSECOND >=
723         MIN_PULSE_DURATION) {
724       GST_DEBUG_OBJECT (dtmfsrc, "try popping");
725       event = g_async_queue_try_pop (dtmfsrc->event_queue);
726
727
728       if (event != NULL) {
729         GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);
730
731         switch (event->event_type) {
732           case RTP_DTMF_EVENT_TYPE_START:
733             GST_WARNING_OBJECT (dtmfsrc,
734                 "Received two consecutive DTMF start events");
735             break;
736
737           case RTP_DTMF_EVENT_TYPE_STOP:
738             dtmfsrc->first_packet = FALSE;
739             dtmfsrc->last_packet = TRUE;
740             /* Set the redundanc on the last packet */
741             dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
742             break;
743
744           case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
745             /*
746              * We're pushing it back because it has to stay in there until
747              * the task is really paused (and the queue will then be flushed)
748              */
749             GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
750             GST_OBJECT_LOCK (dtmfsrc);
751             if (dtmfsrc->paused) {
752               g_async_queue_push (dtmfsrc->event_queue, event);
753               goto paused_locked;
754             }
755             GST_OBJECT_UNLOCK (dtmfsrc);
756             break;
757         }
758         g_free (event);
759       }
760     }
761   } while (dtmfsrc->payload == NULL);
762
763
764   GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");
765
766   clock = gst_element_get_clock (GST_ELEMENT (basesrc));
767
768   clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
769       gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
770   gst_object_unref (clock);
771
772   GST_OBJECT_LOCK (dtmfsrc);
773   if (!dtmfsrc->paused) {
774     dtmfsrc->clockid = clockid;
775     GST_OBJECT_UNLOCK (dtmfsrc);
776
777     clockret = gst_clock_id_wait (clockid, NULL);
778
779     GST_OBJECT_LOCK (dtmfsrc);
780     if (dtmfsrc->paused)
781       clockret = GST_CLOCK_UNSCHEDULED;
782   } else  {
783     clockret = GST_CLOCK_UNSCHEDULED;
784   }
785   gst_clock_id_unref (clockid);
786   dtmfsrc->clockid = NULL;
787   GST_OBJECT_UNLOCK (dtmfsrc);
788
789   if (clockret == GST_CLOCK_UNSCHEDULED) {
790     goto paused;
791   }
792
793  send_last:
794
795   if (dtmfsrc->dirty)
796     if (!gst_rtp_dtmf_src_negotiate (basesrc))
797       return GST_FLOW_NOT_NEGOTIATED;
798
799   /* create buffer to hold the payload */
800   *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);
801
802   if (dtmfsrc->redundancy_count)
803     dtmfsrc->redundancy_count--;
804
805   /* Only the very first one has a marker */
806   dtmfsrc->first_packet = FALSE;
807
808   /* This is the end of the event */
809   if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) {
810
811     /* Don't forget to release the stream lock */
812     gst_rtp_dtmf_src_set_stream_lock (dtmfsrc, FALSE);
813
814     g_free (dtmfsrc->payload);
815     dtmfsrc->payload = NULL;
816
817     dtmfsrc->last_packet = FALSE;
818   }
819
820   return GST_FLOW_OK;
821
822  paused_locked:
823
824   GST_OBJECT_UNLOCK (dtmfsrc);
825
826  paused:
827
828   if (dtmfsrc->payload) {
829     dtmfsrc->first_packet = FALSE;
830     dtmfsrc->last_packet = TRUE;
831     /* Set the redundanc on the last packet */
832     dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
833     goto send_last;
834   } else {
835     return GST_FLOW_WRONG_STATE;
836   }
837 }
838
839
840 static gboolean
841 gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc)
842 {
843   GstCaps *srccaps, *peercaps;
844   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
845   gboolean ret;
846
847   /* fill in the defaults, there properties cannot be negotiated. */
848   srccaps = gst_caps_new_simple ("application/x-rtp",
849       "media", G_TYPE_STRING, "audio",
850       "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate,
851       "encoding-name", G_TYPE_STRING, "telephone-event", NULL);
852
853   /* the peer caps can override some of the defaults */
854   peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
855   if (peercaps == NULL) {
856     /* no peer caps, just add the other properties */
857     gst_caps_set_simple (srccaps,
858         "payload", G_TYPE_INT, dtmfsrc->pt,
859         "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc,
860         "clock-base", G_TYPE_UINT, dtmfsrc->ts_base,
861         "seqnum-base", G_TYPE_UINT, dtmfsrc->seqnum_base, NULL);
862
863     GST_DEBUG_OBJECT (dtmfsrc, "no peer caps: %" GST_PTR_FORMAT, srccaps);
864   } else {
865     GstCaps *temp;
866     GstStructure *s;
867     const GValue *value;
868     gint pt;
869
870     /* peer provides caps we can use to fixate, intersect. This always returns a
871      * writable caps. */
872     temp = gst_caps_intersect (srccaps, peercaps);
873     gst_caps_unref (srccaps);
874     gst_caps_unref (peercaps);
875
876     if (!temp) {
877       GST_DEBUG_OBJECT (dtmfsrc, "Could not get intersection with peer caps");
878       return FALSE;
879     }
880
881     if (gst_caps_is_empty (temp)) {
882       GST_DEBUG_OBJECT (dtmfsrc, "Intersection with peer caps is empty");
883       gst_caps_unref (temp);
884       return FALSE;
885     }
886
887     /* now fixate, start by taking the first caps */
888     gst_caps_truncate (temp);
889     srccaps = temp;
890
891     /* get first structure */
892     s = gst_caps_get_structure (srccaps, 0);
893
894     if (gst_structure_get_int (s, "dtmfsrc", &pt)) {
895       /* use peer pt */
896       dtmfsrc->pt = pt;
897       GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
898     } else {
899       if (gst_structure_has_field (s, "payload")) {
900         /* can only fixate if there is a field */
901         gst_structure_fixate_field_nearest_int (s, "payload",
902             dtmfsrc->pt);
903         gst_structure_get_int (s, "payload", &pt);
904         GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
905       } else {
906         /* no pt field, use the internal pt */
907         pt = dtmfsrc->pt;
908         gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
909         GST_LOG_OBJECT (dtmfsrc, "using internal pt", pt);
910       }
911     }
912
913     if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
914       value = gst_structure_get_value (s, "ssrc");
915       dtmfsrc->current_ssrc = g_value_get_uint (value);
916       GST_LOG_OBJECT (dtmfsrc, "using peer ssrc %08x", dtmfsrc->current_ssrc);
917     } else {
918       /* FIXME, fixate_nearest_uint would be even better */
919       gst_structure_set (s, "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc, NULL);
920       GST_LOG_OBJECT (dtmfsrc, "using internal ssrc %08x",
921           dtmfsrc->current_ssrc);
922     }
923
924     if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) {
925       value = gst_structure_get_value (s, "clock-base");
926       dtmfsrc->ts_base = g_value_get_uint (value);
927       GST_LOG_OBJECT (dtmfsrc, "using peer clock-base %u", dtmfsrc->ts_base);
928     } else {
929       /* FIXME, fixate_nearest_uint would be even better */
930       gst_structure_set (s, "clock-base", G_TYPE_UINT, dtmfsrc->ts_base, NULL);
931       GST_LOG_OBJECT (dtmfsrc, "using internal clock-base %u",
932           dtmfsrc->ts_base);
933     }
934     if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) {
935       value = gst_structure_get_value (s, "seqnum-base");
936       dtmfsrc->seqnum_base = g_value_get_uint (value);
937       GST_LOG_OBJECT (dtmfsrc, "using peer seqnum-base %u",
938           dtmfsrc->seqnum_base);
939     } else {
940       /* FIXME, fixate_nearest_uint would be even better */
941       gst_structure_set (s, "seqnum-base", G_TYPE_UINT, dtmfsrc->seqnum_base,
942           NULL);
943       GST_LOG_OBJECT (dtmfsrc, "using internal seqnum-base %u",
944           dtmfsrc->seqnum_base);
945     }
946     GST_DEBUG_OBJECT (dtmfsrc, "with peer caps: %" GST_PTR_FORMAT, srccaps);
947   }
948
949   ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), srccaps);
950   gst_caps_unref (srccaps);
951
952   dtmfsrc->dirty = FALSE;
953
954   return ret;
955
956 }
957
958
959 static void
960 gst_rtp_dtmf_src_ready_to_paused (GstRTPDTMFSrc *dtmfsrc)
961 {
962   if (dtmfsrc->ssrc == -1)
963     dtmfsrc->current_ssrc = g_random_int ();
964   else
965     dtmfsrc->current_ssrc = dtmfsrc->ssrc;
966
967   if (dtmfsrc->seqnum_offset == -1)
968     dtmfsrc->seqnum_base = g_random_int_range (0, G_MAXUINT16);
969   else
970     dtmfsrc->seqnum_base = dtmfsrc->seqnum_offset;
971   dtmfsrc->seqnum = dtmfsrc->seqnum_base;
972
973   if (dtmfsrc->ts_offset == -1)
974     dtmfsrc->ts_base = g_random_int ();
975   else
976     dtmfsrc->ts_base = dtmfsrc->ts_offset;
977
978 }
979
980 static GstStateChangeReturn
981 gst_rtp_dtmf_src_change_state (GstElement * element, GstStateChange transition)
982 {
983   GstRTPDTMFSrc *dtmfsrc;
984   GstStateChangeReturn result;
985   gboolean no_preroll = FALSE;
986   GstRTPDTMFSrcEvent *event= NULL;
987
988   dtmfsrc = GST_RTP_DTMF_SRC (element);
989
990   switch (transition) {
991     case GST_STATE_CHANGE_READY_TO_PAUSED:
992       gst_rtp_dtmf_src_ready_to_paused (dtmfsrc);
993
994       /* Flushing the event queue */
995       while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL)
996         g_free (event);
997
998       no_preroll = TRUE;
999       break;
1000     default:
1001       break;
1002   }
1003
1004   if ((result =
1005           GST_ELEMENT_CLASS (parent_class)->change_state (element,
1006               transition)) == GST_STATE_CHANGE_FAILURE)
1007     goto failure;
1008
1009   switch (transition) {
1010     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1011       no_preroll = TRUE;
1012       break;
1013     case GST_STATE_CHANGE_PAUSED_TO_READY:
1014
1015      /* Flushing the event queue */
1016       while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL)
1017         g_free (event);
1018
1019       /* Indicate that we don't do PRE_ROLL */
1020       break;
1021
1022     default:
1023       break;
1024   }
1025
1026   if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
1027     result = GST_STATE_CHANGE_NO_PREROLL;
1028
1029   return result;
1030
1031   /* ERRORS */
1032 failure:
1033   {
1034     GST_ERROR_OBJECT (dtmfsrc, "parent failed state change");
1035     return result;
1036   }
1037 }
1038
1039
1040 static gboolean
1041 gst_rtp_dtmf_src_unlock (GstBaseSrc *src) {
1042   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
1043   GstRTPDTMFSrcEvent *event = NULL;
1044
1045   GST_DEBUG_OBJECT (dtmfsrc, "Called unlock");
1046
1047   GST_OBJECT_LOCK (dtmfsrc);
1048   dtmfsrc->paused = TRUE;
1049   if (dtmfsrc->clockid) {
1050     gst_clock_id_unschedule (dtmfsrc->clockid);
1051   }
1052   GST_OBJECT_UNLOCK (dtmfsrc);
1053
1054   GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request");
1055   event = g_malloc (sizeof(GstRTPDTMFSrcEvent));
1056   event->event_type = RTP_DTMF_EVENT_TYPE_PAUSE_TASK;
1057   g_async_queue_push (dtmfsrc->event_queue, event);
1058
1059   return TRUE;
1060 }
1061
1062
1063 static gboolean
1064 gst_rtp_dtmf_src_unlock_stop (GstBaseSrc *src) {
1065   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
1066
1067   GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped");
1068
1069   GST_OBJECT_LOCK (dtmfsrc);
1070   dtmfsrc->paused = FALSE;
1071   GST_OBJECT_UNLOCK (dtmfsrc);
1072
1073   return TRUE;
1074 }
1075
1076 gboolean
1077 gst_rtp_dtmf_src_plugin_init (GstPlugin * plugin)
1078 {
1079   return gst_element_register (plugin, "rtpdtmfsrc",
1080       GST_RANK_NONE, GST_TYPE_RTP_DTMF_SRC);
1081 }