1 /* GStreamer RTP DTMF source
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>
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.
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.
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.
27 * SECTION:element-rtpdtmfsrc
28 * @see_also: dtmfsrc, rtpdtmfdepay, rtpdtmfmux
30 * The RTPDTMFSrc element generates RTP DTMF (RFC 2833) event packets on request
31 * from application. The application communicates the beginning and end of a
32 * DTMF event using custom upstream gstreamer events. To report a DTMF event, an
33 * application must send an event of type GST_EVENT_CUSTOM_UPSTREAM, having a
34 * structure of name "dtmf-event" with fields set according to the following
39 * <colspec colname='Name' />
40 * <colspec colname='Type' />
41 * <colspec colname='Possible values' />
42 * <colspec colname='Purpose' />
46 * <entry>GType</entry>
47 * <entry>Possible values</entry>
48 * <entry>Purpose</entry>
54 * <entry>G_TYPE_INT</entry>
56 * <entry>The application uses this field to specify which of the two methods
57 * specified in RFC 2833 to use. The value should be 0 for tones and 1 for
58 * named events. Tones are specified by their frequencies and events are specied
59 * by their number. This element can only take events as input. Do not confuse
60 * with "method" which specified the output.
64 * <entry>number</entry>
65 * <entry>G_TYPE_INT</entry>
67 * <entry>The event number.</entry>
70 * <entry>volume</entry>
71 * <entry>G_TYPE_INT</entry>
73 * <entry>This field describes the power level of the tone, expressed in dBm0
74 * after dropping the sign. Power levels range from 0 to -63 dBm0. The range of
75 * valid DTMF is from 0 to -36 dBm0. Can be omitted if start is set to FALSE.
79 * <entry>start</entry>
80 * <entry>G_TYPE_BOOLEAN</entry>
81 * <entry>True or False</entry>
82 * <entry>Whether the event is starting or ending.</entry>
85 * <entry>method</entry>
86 * <entry>G_TYPE_INT</entry>
88 * <entry>The method used for sending event, this element will react if this
89 * field is absent or 1.
96 * For example, the following code informs the pipeline (and in turn, the
97 * RTPDTMFSrc element inside the pipeline) about the start of an RTP DTMF named
98 * event '1' of volume -25 dBm0:
101 * structure = gst_structure_new ("dtmf-event",
102 * "type", G_TYPE_INT, 1,
103 * "number", G_TYPE_INT, 1,
104 * "volume", G_TYPE_INT, 25,
105 * "start", G_TYPE_BOOLEAN, TRUE, NULL);
107 * event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
108 * gst_element_send_event (pipeline, event);
122 #include "gstrtpdtmfsrc.h"
124 #define GST_RTP_DTMF_TYPE_EVENT 1
125 #define DEFAULT_PTIME 40 /* ms */
126 #define DEFAULT_SSRC -1
127 #define DEFAULT_PT 96
128 #define DEFAULT_TIMESTAMP_OFFSET -1
129 #define DEFAULT_SEQNUM_OFFSET -1
130 #define DEFAULT_CLOCK_RATE 8000
132 #define DEFAULT_PACKET_REDUNDANCY 1
133 #define MIN_PACKET_REDUNDANCY 1
134 #define MAX_PACKET_REDUNDANCY 5
136 GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_src_debug);
137 #define GST_CAT_DEFAULT gst_rtp_dtmf_src_debug
139 /* signals and args */
150 PROP_TIMESTAMP_OFFSET,
159 static GstStaticPadTemplate gst_rtp_dtmf_src_template =
160 GST_STATIC_PAD_TEMPLATE ("src",
163 GST_STATIC_CAPS ("application/x-rtp, "
164 "media = (string) \"audio\", "
165 "payload = (int) [ 96, 127 ], "
166 "clock-rate = (int) [ 0, MAX ], "
167 "ssrc = (int) [ 0, MAX ], "
168 "encoding-name = (string) \"TELEPHONE-EVENT\"")
169 /* "events = (string) \"0-15\" */
173 GST_BOILERPLATE (GstRTPDTMFSrc, gst_rtp_dtmf_src, GstBaseSrc,
176 static void gst_rtp_dtmf_src_finalize (GObject * object);
178 static void gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
179 const GValue * value, GParamSpec * pspec);
180 static void gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id,
181 GValue * value, GParamSpec * pspec);
182 static gboolean gst_rtp_dtmf_src_handle_event (GstBaseSrc * basesrc,
184 static GstStateChangeReturn gst_rtp_dtmf_src_change_state (GstElement * element,
185 GstStateChange transition);
186 static void gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc,
187 gint event_number, gint event_volume);
188 static void gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc * dtmfsrc);
190 static gboolean gst_rtp_dtmf_src_unlock (GstBaseSrc * src);
191 static gboolean gst_rtp_dtmf_src_unlock_stop (GstBaseSrc * src);
192 static GstFlowReturn gst_rtp_dtmf_src_create (GstBaseSrc * basesrc,
193 guint64 offset, guint length, GstBuffer ** buffer);
194 static gboolean gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc);
198 gst_rtp_dtmf_src_base_init (gpointer g_class)
200 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
202 GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_src_debug,
203 "rtpdtmfsrc", 0, "rtpdtmfsrc element");
205 gst_element_class_add_pad_template (element_class,
206 gst_static_pad_template_get (&gst_rtp_dtmf_src_template));
208 gst_element_class_set_details_simple (element_class,
209 "RTP DTMF packet generator", "Source/Network",
210 "Generates RTP DTMF packets", "Zeeshan Ali <zeeshan.ali@nokia.com>");
214 gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass)
216 GObjectClass *gobject_class;
217 GstBaseSrcClass *gstbasesrc_class;
218 GstElementClass *gstelement_class;
220 gobject_class = G_OBJECT_CLASS (klass);
221 gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
222 gstelement_class = GST_ELEMENT_CLASS (klass);
224 parent_class = g_type_class_peek_parent (klass);
226 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_finalize);
227 gobject_class->set_property =
228 GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_set_property);
229 gobject_class->get_property =
230 GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_get_property);
232 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
233 g_param_spec_uint ("timestamp", "Timestamp",
234 "The RTP timestamp of the last processed packet",
235 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
236 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
237 g_param_spec_uint ("seqnum", "Sequence number",
238 "The RTP sequence number of the last processed packet",
239 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
240 g_object_class_install_property (G_OBJECT_CLASS (klass),
241 PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
243 "Offset to add to all outgoing timestamps (-1 = random)", -1,
244 G_MAXINT, DEFAULT_TIMESTAMP_OFFSET,
245 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
246 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
247 g_param_spec_int ("seqnum-offset", "Sequence number Offset",
248 "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
249 DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
250 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLOCK_RATE,
251 g_param_spec_uint ("clock-rate", "clockrate",
252 "The clock-rate at which to generate the dtmf packets",
253 0, G_MAXUINT, DEFAULT_CLOCK_RATE,
254 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
255 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
256 g_param_spec_uint ("ssrc", "SSRC",
257 "The SSRC of the packets (-1 == random)",
258 0, G_MAXUINT, DEFAULT_SSRC,
259 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
260 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
261 g_param_spec_uint ("pt", "payload type",
262 "The payload type of the packets",
263 0, 0x80, DEFAULT_PT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
264 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_REDUNDANCY,
265 g_param_spec_uint ("packet-redundancy", "Packet Redundancy",
266 "Number of packets to send to indicate start and stop dtmf events",
267 MIN_PACKET_REDUNDANCY, MAX_PACKET_REDUNDANCY,
268 DEFAULT_PACKET_REDUNDANCY,
269 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
271 gstelement_class->change_state =
272 GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_change_state);
274 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock);
275 gstbasesrc_class->unlock_stop =
276 GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock_stop);
278 gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_handle_event);
279 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_create);
280 gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_negotiate);
284 gst_rtp_dtmf_src_event_free (GstRTPDTMFSrcEvent * event)
288 g_slice_free (GstRTPDTMFPayload, event->payload);
289 g_slice_free (GstRTPDTMFSrcEvent, event);
294 gst_rtp_dtmf_src_init (GstRTPDTMFSrc * object, GstRTPDTMFSrcClass * g_class)
296 gst_base_src_set_format (GST_BASE_SRC (object), GST_FORMAT_TIME);
297 gst_base_src_set_live (GST_BASE_SRC (object), TRUE);
299 object->ssrc = DEFAULT_SSRC;
300 object->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
301 object->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
302 object->pt = DEFAULT_PT;
303 object->clock_rate = DEFAULT_CLOCK_RATE;
304 object->ptime = DEFAULT_PTIME;
305 object->packet_redundancy = DEFAULT_PACKET_REDUNDANCY;
307 object->event_queue =
308 g_async_queue_new_full ((GDestroyNotify) gst_rtp_dtmf_src_event_free);
309 object->payload = NULL;
311 GST_DEBUG_OBJECT (object, "init done");
315 gst_rtp_dtmf_src_finalize (GObject * object)
317 GstRTPDTMFSrc *dtmfsrc;
319 dtmfsrc = GST_RTP_DTMF_SRC (object);
321 if (dtmfsrc->event_queue) {
322 g_async_queue_unref (dtmfsrc->event_queue);
323 dtmfsrc->event_queue = NULL;
327 G_OBJECT_CLASS (parent_class)->finalize (object);
331 gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc * dtmfsrc,
332 const GstStructure * event_structure)
338 if (!gst_structure_get_int (event_structure, "type", &event_type) ||
339 !gst_structure_get_boolean (event_structure, "start", &start) ||
340 event_type != GST_RTP_DTMF_TYPE_EVENT)
343 if (gst_structure_get_int (event_structure, "method", &method)) {
353 if (!gst_structure_get_int (event_structure, "number", &event_number) ||
354 !gst_structure_get_int (event_structure, "volume", &event_volume))
357 GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
358 event_number, event_volume);
359 gst_rtp_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
363 GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
364 gst_rtp_dtmf_src_add_stop_event (dtmfsrc);
373 gst_rtp_dtmf_src_handle_custom_upstream (GstRTPDTMFSrc * dtmfsrc,
376 gboolean result = FALSE;
378 const GstStructure *structure;
381 GstStateChangeReturn ret;
383 ret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
384 if (ret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
385 GST_DEBUG_OBJECT (dtmfsrc, "Received event while not in PLAYING state");
389 GST_DEBUG_OBJECT (dtmfsrc, "Received event is of our interest");
390 structure = gst_event_get_structure (event);
391 struct_str = gst_structure_to_string (structure);
392 GST_DEBUG_OBJECT (dtmfsrc, "Event has structure %s", struct_str);
394 if (structure && gst_structure_has_name (structure, "dtmf-event"))
395 result = gst_rtp_dtmf_src_handle_dtmf_event (dtmfsrc, structure);
402 gst_rtp_dtmf_src_handle_event (GstBaseSrc * basesrc, GstEvent * event)
404 GstRTPDTMFSrc *dtmfsrc;
405 gboolean result = FALSE;
407 dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
409 GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad");
410 if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
411 result = gst_rtp_dtmf_src_handle_custom_upstream (dtmfsrc, event);
418 gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
419 const GValue * value, GParamSpec * pspec)
421 GstRTPDTMFSrc *dtmfsrc;
423 dtmfsrc = GST_RTP_DTMF_SRC (object);
426 case PROP_TIMESTAMP_OFFSET:
427 dtmfsrc->ts_offset = g_value_get_int (value);
429 case PROP_SEQNUM_OFFSET:
430 dtmfsrc->seqnum_offset = g_value_get_int (value);
432 case PROP_CLOCK_RATE:
433 dtmfsrc->clock_rate = g_value_get_uint (value);
434 dtmfsrc->dirty = TRUE;
437 dtmfsrc->ssrc = g_value_get_uint (value);
440 dtmfsrc->pt = g_value_get_uint (value);
441 dtmfsrc->dirty = TRUE;
443 case PROP_REDUNDANCY:
444 dtmfsrc->packet_redundancy = g_value_get_uint (value);
447 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
453 gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
456 GstRTPDTMFSrc *dtmfsrc;
458 dtmfsrc = GST_RTP_DTMF_SRC (object);
461 case PROP_TIMESTAMP_OFFSET:
462 g_value_set_int (value, dtmfsrc->ts_offset);
464 case PROP_SEQNUM_OFFSET:
465 g_value_set_int (value, dtmfsrc->seqnum_offset);
467 case PROP_CLOCK_RATE:
468 g_value_set_uint (value, dtmfsrc->clock_rate);
471 g_value_set_uint (value, dtmfsrc->ssrc);
474 g_value_set_uint (value, dtmfsrc->pt);
477 g_value_set_uint (value, dtmfsrc->rtp_timestamp);
480 g_value_set_uint (value, dtmfsrc->seqnum);
482 case PROP_REDUNDANCY:
483 g_value_set_uint (value, dtmfsrc->packet_redundancy);
486 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
492 gst_rtp_dtmf_prepare_timestamps (GstRTPDTMFSrc * dtmfsrc)
496 clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
500 dtmfsrc->timestamp = gst_clock_get_time (clock)
501 + (MIN_INTER_DIGIT_INTERVAL * GST_MSECOND)
502 - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
503 dtmfsrc->start_timestamp = dtmfsrc->timestamp;
504 gst_object_unref (clock);
506 dtmfsrc->rtp_timestamp = dtmfsrc->ts_base +
507 gst_util_uint64_scale_int (gst_segment_to_running_time (&GST_BASE_SRC
508 (dtmfsrc)->segment, GST_FORMAT_TIME, dtmfsrc->timestamp),
509 dtmfsrc->clock_rate, GST_SECOND);
516 gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc, gint event_number,
520 GstRTPDTMFSrcEvent *event = g_slice_new0 (GstRTPDTMFSrcEvent);
521 event->event_type = RTP_DTMF_EVENT_TYPE_START;
523 event->payload = g_slice_new0 (GstRTPDTMFPayload);
524 event->payload->event = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
525 event->payload->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
526 event->payload->duration = dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
528 g_async_queue_push (dtmfsrc->event_queue, event);
532 gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc * dtmfsrc)
535 GstRTPDTMFSrcEvent *event = g_slice_new0 (GstRTPDTMFSrcEvent);
536 event->event_type = RTP_DTMF_EVENT_TYPE_STOP;
538 g_async_queue_push (dtmfsrc->event_queue, event);
543 gst_rtp_dtmf_prepare_rtp_headers (GstRTPDTMFSrc * dtmfsrc, GstBuffer * buf)
545 gst_rtp_buffer_set_ssrc (buf, dtmfsrc->current_ssrc);
546 gst_rtp_buffer_set_payload_type (buf, dtmfsrc->pt);
547 /* Only the very first packet gets a marker */
548 if (dtmfsrc->first_packet) {
549 gst_rtp_buffer_set_marker (buf, TRUE);
550 } else if (dtmfsrc->last_packet) {
551 dtmfsrc->payload->e = 1;
555 gst_rtp_buffer_set_seq (buf, dtmfsrc->seqnum);
557 /* timestamp of RTP header */
558 gst_rtp_buffer_set_timestamp (buf, dtmfsrc->rtp_timestamp);
562 gst_rtp_dtmf_prepare_buffer_data (GstRTPDTMFSrc * dtmfsrc, GstBuffer * buf)
564 GstRTPDTMFPayload *payload;
566 gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, buf);
568 /* timestamp and duration of GstBuffer */
569 /* Redundant buffer have no duration ... */
570 if (dtmfsrc->redundancy_count > 1)
571 GST_BUFFER_DURATION (buf) = 0;
573 GST_BUFFER_DURATION (buf) = dtmfsrc->ptime * GST_MSECOND;
574 GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp;
576 dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
578 payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (buf);
580 /* copy payload and convert to network-byte order */
581 g_memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload));
583 payload->duration = g_htons (payload->duration);
586 /* duration of DTMF payloadfor the NEXT packet */
587 /* not updated for redundant packets */
588 if (dtmfsrc->redundancy_count == 0)
589 dtmfsrc->payload->duration += dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
594 gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc * dtmfsrc)
596 GstBuffer *buf = NULL;
598 /* create buffer to hold the payload */
599 buf = gst_rtp_buffer_new_allocate (sizeof (GstRTPDTMFPayload), 0, 0);
601 gst_rtp_dtmf_prepare_buffer_data (dtmfsrc, buf);
603 /* Set caps on the buffer before pushing it */
604 gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (dtmfsrc)));
610 gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
611 guint length, GstBuffer ** buffer)
613 GstRTPDTMFSrcEvent *event;
614 GstRTPDTMFSrc *dtmfsrc;
617 GstClockReturn clockret;
619 dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
623 if (dtmfsrc->payload == NULL) {
624 GST_DEBUG_OBJECT (dtmfsrc, "popping");
625 event = g_async_queue_pop (dtmfsrc->event_queue);
627 GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);
629 switch (event->event_type) {
630 case RTP_DTMF_EVENT_TYPE_STOP:
631 GST_WARNING_OBJECT (dtmfsrc,
632 "Received a DTMF stop event when already stopped");
635 case RTP_DTMF_EVENT_TYPE_START:
636 dtmfsrc->first_packet = TRUE;
637 dtmfsrc->last_packet = FALSE;
638 /* Set the redundancy on the first packet */
639 dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
640 if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc))
643 dtmfsrc->payload = event->payload;
644 event->payload = NULL;
647 case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
649 * We're pushing it back because it has to stay in there until
650 * the task is really paused (and the queue will then be flushed
652 GST_OBJECT_LOCK (dtmfsrc);
653 if (dtmfsrc->paused) {
654 g_async_queue_push (dtmfsrc->event_queue, event);
657 GST_OBJECT_UNLOCK (dtmfsrc);
661 gst_rtp_dtmf_src_event_free (event);
662 } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
663 (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >=
664 MIN_PULSE_DURATION) {
665 GST_DEBUG_OBJECT (dtmfsrc, "try popping");
666 event = g_async_queue_try_pop (dtmfsrc->event_queue);
670 GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);
672 switch (event->event_type) {
673 case RTP_DTMF_EVENT_TYPE_START:
674 GST_WARNING_OBJECT (dtmfsrc,
675 "Received two consecutive DTMF start events");
678 case RTP_DTMF_EVENT_TYPE_STOP:
679 dtmfsrc->first_packet = FALSE;
680 dtmfsrc->last_packet = TRUE;
681 /* Set the redundancy on the last packet */
682 dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
685 case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
687 * We're pushing it back because it has to stay in there until
688 * the task is really paused (and the queue will then be flushed)
690 GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
691 GST_OBJECT_LOCK (dtmfsrc);
692 if (dtmfsrc->paused) {
693 g_async_queue_push (dtmfsrc->event_queue, event);
696 GST_OBJECT_UNLOCK (dtmfsrc);
699 gst_rtp_dtmf_src_event_free (event);
702 } while (dtmfsrc->payload == NULL);
705 GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");
707 clock = gst_element_get_clock (GST_ELEMENT (basesrc));
710 clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
711 gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
712 gst_object_unref (clock);
714 GST_OBJECT_LOCK (dtmfsrc);
715 if (!dtmfsrc->paused) {
716 dtmfsrc->clockid = clockid;
717 GST_OBJECT_UNLOCK (dtmfsrc);
719 clockret = gst_clock_id_wait (clockid, NULL);
721 GST_OBJECT_LOCK (dtmfsrc);
723 clockret = GST_CLOCK_UNSCHEDULED;
725 clockret = GST_CLOCK_UNSCHEDULED;
727 gst_clock_id_unref (clockid);
728 dtmfsrc->clockid = NULL;
729 GST_OBJECT_UNLOCK (dtmfsrc);
731 if (clockret == GST_CLOCK_UNSCHEDULED) {
738 if (!gst_rtp_dtmf_src_negotiate (basesrc))
739 return GST_FLOW_NOT_NEGOTIATED;
741 /* create buffer to hold the payload */
742 *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc);
744 if (dtmfsrc->redundancy_count)
745 dtmfsrc->redundancy_count--;
747 /* Only the very first one has a marker */
748 dtmfsrc->first_packet = FALSE;
750 /* This is the end of the event */
751 if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) {
753 g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload);
754 dtmfsrc->payload = NULL;
756 dtmfsrc->last_packet = FALSE;
763 GST_OBJECT_UNLOCK (dtmfsrc);
767 if (dtmfsrc->payload) {
768 dtmfsrc->first_packet = FALSE;
769 dtmfsrc->last_packet = TRUE;
770 /* Set the redundanc on the last packet */
771 dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
774 return GST_FLOW_WRONG_STATE;
778 GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"),
779 ("No available clock"));
780 gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc));
781 return GST_FLOW_ERROR;
786 gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc)
788 GstCaps *srccaps, *peercaps;
789 GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
792 /* fill in the defaults, there properties cannot be negotiated. */
793 srccaps = gst_caps_new_simple ("application/x-rtp",
794 "media", G_TYPE_STRING, "audio",
795 "encoding-name", G_TYPE_STRING, "TELEPHONE-EVENT", NULL);
797 /* the peer caps can override some of the defaults */
798 peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
799 if (peercaps == NULL) {
800 /* no peer caps, just add the other properties */
801 gst_caps_set_simple (srccaps,
802 "payload", G_TYPE_INT, dtmfsrc->pt,
803 "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc,
804 "clock-base", G_TYPE_UINT, dtmfsrc->ts_base,
805 "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate,
806 "seqnum-base", G_TYPE_UINT, dtmfsrc->seqnum_base, NULL);
808 GST_DEBUG_OBJECT (dtmfsrc, "no peer caps: %" GST_PTR_FORMAT, srccaps);
816 /* peer provides caps we can use to fixate, intersect. This always returns a
818 temp = gst_caps_intersect (srccaps, peercaps);
819 gst_caps_unref (srccaps);
820 gst_caps_unref (peercaps);
823 GST_DEBUG_OBJECT (dtmfsrc, "Could not get intersection with peer caps");
827 if (gst_caps_is_empty (temp)) {
828 GST_DEBUG_OBJECT (dtmfsrc, "Intersection with peer caps is empty");
829 gst_caps_unref (temp);
833 /* now fixate, start by taking the first caps */
834 gst_caps_truncate (temp);
837 /* get first structure */
838 s = gst_caps_get_structure (srccaps, 0);
840 if (gst_structure_get_int (s, "payload", &pt)) {
843 GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
845 if (gst_structure_has_field (s, "payload")) {
846 /* can only fixate if there is a field */
847 gst_structure_fixate_field_nearest_int (s, "payload", dtmfsrc->pt);
848 gst_structure_get_int (s, "payload", &pt);
849 GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
851 /* no pt field, use the internal pt */
853 gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
854 GST_LOG_OBJECT (dtmfsrc, "using internal pt %d", pt);
858 if (gst_structure_get_int (s, "clock-rate", &clock_rate)) {
859 dtmfsrc->clock_rate = clock_rate;
860 GST_LOG_OBJECT (dtmfsrc, "using clock-rate from caps %d",
861 dtmfsrc->clock_rate);
863 GST_LOG_OBJECT (dtmfsrc, "using existing clock-rate %d",
864 dtmfsrc->clock_rate);
866 gst_structure_set (s, "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate, NULL);
869 if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
870 value = gst_structure_get_value (s, "ssrc");
871 dtmfsrc->current_ssrc = g_value_get_uint (value);
872 GST_LOG_OBJECT (dtmfsrc, "using peer ssrc %08x", dtmfsrc->current_ssrc);
874 /* FIXME, fixate_nearest_uint would be even better */
875 gst_structure_set (s, "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc, NULL);
876 GST_LOG_OBJECT (dtmfsrc, "using internal ssrc %08x",
877 dtmfsrc->current_ssrc);
880 if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) {
881 value = gst_structure_get_value (s, "clock-base");
882 dtmfsrc->ts_base = g_value_get_uint (value);
883 GST_LOG_OBJECT (dtmfsrc, "using peer clock-base %u", dtmfsrc->ts_base);
885 /* FIXME, fixate_nearest_uint would be even better */
886 gst_structure_set (s, "clock-base", G_TYPE_UINT, dtmfsrc->ts_base, NULL);
887 GST_LOG_OBJECT (dtmfsrc, "using internal clock-base %u",
890 if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) {
891 value = gst_structure_get_value (s, "seqnum-base");
892 dtmfsrc->seqnum_base = g_value_get_uint (value);
893 GST_LOG_OBJECT (dtmfsrc, "using peer seqnum-base %u",
894 dtmfsrc->seqnum_base);
896 /* FIXME, fixate_nearest_uint would be even better */
897 gst_structure_set (s, "seqnum-base", G_TYPE_UINT, dtmfsrc->seqnum_base,
899 GST_LOG_OBJECT (dtmfsrc, "using internal seqnum-base %u",
900 dtmfsrc->seqnum_base);
903 if (gst_structure_has_field_typed (s, "ptime", G_TYPE_UINT)) {
904 value = gst_structure_get_value (s, "ptime");
905 dtmfsrc->ptime = g_value_get_uint (value);
906 GST_LOG_OBJECT (dtmfsrc, "using peer ptime %u", dtmfsrc->ptime);
907 } else if (gst_structure_has_field_typed (s, "maxptime", G_TYPE_UINT)) {
908 value = gst_structure_get_value (s, "maxptime");
909 dtmfsrc->ptime = g_value_get_uint (value);
910 GST_LOG_OBJECT (dtmfsrc, "using peer maxptime as ptime %u",
913 /* FIXME, fixate_nearest_uint would be even better */
914 gst_structure_set (s, "ptime", G_TYPE_UINT, dtmfsrc->ptime, NULL);
915 GST_LOG_OBJECT (dtmfsrc, "using internal ptime %u", dtmfsrc->ptime);
919 GST_DEBUG_OBJECT (dtmfsrc, "with peer caps: %" GST_PTR_FORMAT, srccaps);
922 ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), srccaps);
923 gst_caps_unref (srccaps);
925 dtmfsrc->dirty = FALSE;
933 gst_rtp_dtmf_src_ready_to_paused (GstRTPDTMFSrc * dtmfsrc)
935 if (dtmfsrc->ssrc == -1)
936 dtmfsrc->current_ssrc = g_random_int ();
938 dtmfsrc->current_ssrc = dtmfsrc->ssrc;
940 if (dtmfsrc->seqnum_offset == -1)
941 dtmfsrc->seqnum_base = g_random_int_range (0, G_MAXUINT16);
943 dtmfsrc->seqnum_base = dtmfsrc->seqnum_offset;
944 dtmfsrc->seqnum = dtmfsrc->seqnum_base;
946 if (dtmfsrc->ts_offset == -1)
947 dtmfsrc->ts_base = g_random_int ();
949 dtmfsrc->ts_base = dtmfsrc->ts_offset;
953 static GstStateChangeReturn
954 gst_rtp_dtmf_src_change_state (GstElement * element, GstStateChange transition)
956 GstRTPDTMFSrc *dtmfsrc;
957 GstStateChangeReturn result;
958 gboolean no_preroll = FALSE;
959 GstRTPDTMFSrcEvent *event = NULL;
961 dtmfsrc = GST_RTP_DTMF_SRC (element);
963 switch (transition) {
964 case GST_STATE_CHANGE_READY_TO_PAUSED:
965 gst_rtp_dtmf_src_ready_to_paused (dtmfsrc);
967 /* Flushing the event queue */
968 while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL)
969 gst_rtp_dtmf_src_event_free (event);
978 GST_ELEMENT_CLASS (parent_class)->change_state (element,
979 transition)) == GST_STATE_CHANGE_FAILURE)
982 switch (transition) {
983 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
986 case GST_STATE_CHANGE_PAUSED_TO_READY:
988 /* Flushing the event queue */
989 while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL)
990 gst_rtp_dtmf_src_event_free (event);
992 /* Indicate that we don't do PRE_ROLL */
999 if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
1000 result = GST_STATE_CHANGE_NO_PREROLL;
1007 GST_ERROR_OBJECT (dtmfsrc, "parent failed state change");
1014 gst_rtp_dtmf_src_unlock (GstBaseSrc * src)
1016 GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
1017 GstRTPDTMFSrcEvent *event = NULL;
1019 GST_DEBUG_OBJECT (dtmfsrc, "Called unlock");
1021 GST_OBJECT_LOCK (dtmfsrc);
1022 dtmfsrc->paused = TRUE;
1023 if (dtmfsrc->clockid) {
1024 gst_clock_id_unschedule (dtmfsrc->clockid);
1026 GST_OBJECT_UNLOCK (dtmfsrc);
1028 GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request");
1029 event = g_slice_new0 (GstRTPDTMFSrcEvent);
1030 event->event_type = RTP_DTMF_EVENT_TYPE_PAUSE_TASK;
1031 g_async_queue_push (dtmfsrc->event_queue, event);
1038 gst_rtp_dtmf_src_unlock_stop (GstBaseSrc * src)
1040 GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
1042 GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped");
1044 GST_OBJECT_LOCK (dtmfsrc);
1045 dtmfsrc->paused = FALSE;
1046 GST_OBJECT_UNLOCK (dtmfsrc);
1052 gst_rtp_dtmf_src_plugin_init (GstPlugin * plugin)
1054 return gst_element_register (plugin, "rtpdtmfsrc",
1055 GST_RANK_NONE, GST_TYPE_RTP_DTMF_SRC);