• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 
26 /**
27  * SECTION:element-rtpdtmfsrc
28  * @title: rtpdtmfsrc
29  * @see_also: dtmfsrc, rtpdtmfdepay, rtpdtmfmux
30  *
31  * The RTPDTMFSrc element generates RTP DTMF (RFC 2833) event packets on request
32  * from application. The application communicates the beginning and end of a
33  * DTMF event using custom upstream gstreamer events. To report a DTMF event, an
34  * application must send an event of type GST_EVENT_CUSTOM_UPSTREAM, having a
35  * structure of name "dtmf-event" with fields set according to the following
36  * table:
37  *
38  * * `type` (G_TYPE_INT, 0-1): The application uses this field to specify which of the two methods
39  *   specified in RFC 2833 to use. The value should be 0 for tones and 1 for
40  *   named events. Tones are specified by their frequencies and events are specified
41  *   by their number. This element can only take events as input. Do not confuse
42  *   with "method" which specified the output.
43  *
44  * * `number` (G_TYPE_INT, 0-15): The event number.
45  *
46  * * `volume` (G_TYPE_INT, 0-36): This field describes the power level of the tone, expressed in dBm0
47  *   after dropping the sign. Power levels range from 0 to -63 dBm0. The range of
48  *   valid DTMF is from 0 to -36 dBm0. Can be omitted if start is set to FALSE.
49  *
50  * * `start` (G_TYPE_BOOLEAN, True or False): Whether the event is starting or ending.
51  *
52  * * `method` (G_TYPE_INT, 1): The method used for sending event, this element will react if this
53  *   field is absent or 1.
54  *
55  * For example, the following code informs the pipeline (and in turn, the
56  * RTPDTMFSrc element inside the pipeline) about the start of an RTP DTMF named
57  * event '1' of volume -25 dBm0:
58  *
59  * |[
60  * structure = gst_structure_new ("dtmf-event",
61  *                    "type", G_TYPE_INT, 1,
62  *                    "number", G_TYPE_INT, 1,
63  *                    "volume", G_TYPE_INT, 25,
64  *                    "start", G_TYPE_BOOLEAN, TRUE, NULL);
65  *
66  * event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
67  * gst_element_send_event (pipeline, event);
68  * ]|
69  *
70  * When a DTMF tone actually starts or stop, a "dtmf-event-processed"
71  * element #GstMessage with the same fields as the "dtmf-event"
72  * #GstEvent that was used to request the event. Also, if any event
73  * has not been processed when the element goes from the PAUSED to the
74  * READY state, then a "dtmf-event-dropped" message is posted on the
75  * #GstBus in the order that they were received.
76   */
77 
78 #ifdef HAVE_CONFIG_H
79 #include "config.h"
80 #endif
81 
82 #include <stdlib.h>
83 #include <string.h>
84 
85 #include <glib.h>
86 
87 #include "gstrtpdtmfsrc.h"
88 #include <gst/base/gstbitwriter.h>
89 
90 #define GST_RTP_DTMF_TYPE_EVENT  1
91 #define DEFAULT_PTIME            40     /* ms */
92 #define DEFAULT_SSRC             -1
93 #define DEFAULT_PT               96
94 #define DEFAULT_TIMESTAMP_OFFSET -1
95 #define DEFAULT_SEQNUM_OFFSET    -1
96 #define DEFAULT_CLOCK_RATE       8000
97 
98 #define DEFAULT_PACKET_REDUNDANCY 1
99 #define MIN_PACKET_REDUNDANCY 1
100 #define MAX_PACKET_REDUNDANCY 5
101 
102 GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_src_debug);
103 #define GST_CAT_DEFAULT gst_rtp_dtmf_src_debug
104 
105 /* signals and args */
106 enum
107 {
108   /* FILL ME */
109   LAST_SIGNAL
110 };
111 
112 enum
113 {
114   PROP_0,
115   PROP_SSRC,
116   PROP_TIMESTAMP_OFFSET,
117   PROP_SEQNUM_OFFSET,
118   PROP_PT,
119   PROP_CLOCK_RATE,
120   PROP_TIMESTAMP,
121   PROP_SEQNUM,
122   PROP_REDUNDANCY
123 };
124 
125 static GstStaticPadTemplate gst_rtp_dtmf_src_template =
126 GST_STATIC_PAD_TEMPLATE ("src",
127     GST_PAD_SRC,
128     GST_PAD_ALWAYS,
129     GST_STATIC_CAPS ("application/x-rtp, "
130         "media = (string) \"audio\", "
131         "payload = (int) [ 96, 127 ], "
132         "clock-rate = (int) [ 0, MAX ], "
133         "encoding-name = (string) \"TELEPHONE-EVENT\"")
134     /*  "events = (string) \"0-15\" */
135     );
136 
137 
138 G_DEFINE_TYPE (GstRTPDTMFSrc, gst_rtp_dtmf_src, GST_TYPE_BASE_SRC);
139 GST_ELEMENT_REGISTER_DEFINE (rtpdtmfsrc, "rtpdtmfsrc", GST_RANK_NONE,
140     GST_TYPE_RTP_DTMF_SRC);
141 
142 static void gst_rtp_dtmf_src_finalize (GObject * object);
143 
144 static void gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
145     const GValue * value, GParamSpec * pspec);
146 static void gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id,
147     GValue * value, GParamSpec * pspec);
148 static gboolean gst_rtp_dtmf_src_handle_event (GstBaseSrc * basesrc,
149     GstEvent * event);
150 static GstStateChangeReturn gst_rtp_dtmf_src_change_state (GstElement * element,
151     GstStateChange transition);
152 static void gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc,
153     gint event_number, gint event_volume);
154 static void gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc * dtmfsrc);
155 
156 static gboolean gst_rtp_dtmf_src_unlock (GstBaseSrc * src);
157 static gboolean gst_rtp_dtmf_src_unlock_stop (GstBaseSrc * src);
158 static GstFlowReturn gst_rtp_dtmf_src_create (GstBaseSrc * basesrc,
159     guint64 offset, guint length, GstBuffer ** buffer);
160 static gboolean gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc);
161 static gboolean gst_rtp_dtmf_src_query (GstBaseSrc * basesrc, GstQuery * query);
162 
163 
164 static void
gst_rtp_dtmf_src_class_init(GstRTPDTMFSrcClass * klass)165 gst_rtp_dtmf_src_class_init (GstRTPDTMFSrcClass * klass)
166 {
167   GObjectClass *gobject_class;
168   GstBaseSrcClass *gstbasesrc_class;
169   GstElementClass *gstelement_class;
170 
171   gobject_class = G_OBJECT_CLASS (klass);
172   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
173   gstelement_class = GST_ELEMENT_CLASS (klass);
174 
175   GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_src_debug,
176       "rtpdtmfsrc", 0, "rtpdtmfsrc element");
177 
178   gst_element_class_add_static_pad_template (gstelement_class,
179       &gst_rtp_dtmf_src_template);
180 
181   gst_element_class_set_static_metadata (gstelement_class,
182       "RTP DTMF packet generator", "Source/Network",
183       "Generates RTP DTMF packets", "Zeeshan Ali <zeeshan.ali@nokia.com>");
184 
185   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_finalize);
186   gobject_class->set_property =
187       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_set_property);
188   gobject_class->get_property =
189       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_get_property);
190 
191   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
192       g_param_spec_uint ("timestamp", "Timestamp",
193           "The RTP timestamp of the last processed packet",
194           0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
195   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
196       g_param_spec_uint ("seqnum", "Sequence number",
197           "The RTP sequence number of the last processed packet",
198           0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
199   g_object_class_install_property (G_OBJECT_CLASS (klass),
200       PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
201           "Timestamp Offset",
202           "Offset to add to all outgoing timestamps (-1 = random)", -1,
203           G_MAXINT, DEFAULT_TIMESTAMP_OFFSET,
204           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
206       g_param_spec_int ("seqnum-offset", "Sequence number Offset",
207           "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
208           DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLOCK_RATE,
210       g_param_spec_uint ("clock-rate", "clockrate",
211           "The clock-rate at which to generate the dtmf packets",
212           0, G_MAXUINT, DEFAULT_CLOCK_RATE,
213           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
214   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
215       g_param_spec_uint ("ssrc", "SSRC",
216           "The SSRC of the packets (-1 == random)",
217           0, G_MAXUINT, DEFAULT_SSRC,
218           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
219   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
220       g_param_spec_uint ("pt", "payload type",
221           "The payload type of the packets",
222           0, 0x80, DEFAULT_PT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_REDUNDANCY,
224       g_param_spec_uint ("packet-redundancy", "Packet Redundancy",
225           "Number of packets to send to indicate start and stop dtmf events",
226           MIN_PACKET_REDUNDANCY, MAX_PACKET_REDUNDANCY,
227           DEFAULT_PACKET_REDUNDANCY,
228           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
229 
230   gstelement_class->change_state =
231       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_change_state);
232 
233   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock);
234   gstbasesrc_class->unlock_stop =
235       GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_unlock_stop);
236 
237   gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_handle_event);
238   gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_create);
239   gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_negotiate);
240   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_rtp_dtmf_src_query);
241 }
242 
243 static void
gst_rtp_dtmf_src_event_free(GstRTPDTMFSrcEvent * event)244 gst_rtp_dtmf_src_event_free (GstRTPDTMFSrcEvent * event)
245 {
246   if (event) {
247     if (event->payload)
248       g_slice_free (GstRTPDTMFPayload, event->payload);
249     g_slice_free (GstRTPDTMFSrcEvent, event);
250   }
251 }
252 
253 static void
gst_rtp_dtmf_src_init(GstRTPDTMFSrc * object)254 gst_rtp_dtmf_src_init (GstRTPDTMFSrc * object)
255 {
256   gst_base_src_set_format (GST_BASE_SRC (object), GST_FORMAT_TIME);
257   gst_base_src_set_live (GST_BASE_SRC (object), TRUE);
258 
259   object->ssrc = DEFAULT_SSRC;
260   object->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
261   object->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
262   object->pt = DEFAULT_PT;
263   object->clock_rate = DEFAULT_CLOCK_RATE;
264   object->ptime = DEFAULT_PTIME;
265   object->packet_redundancy = DEFAULT_PACKET_REDUNDANCY;
266 
267   object->event_queue =
268       g_async_queue_new_full ((GDestroyNotify) gst_rtp_dtmf_src_event_free);
269   object->payload = NULL;
270 
271   GST_DEBUG_OBJECT (object, "init done");
272 }
273 
274 static void
gst_rtp_dtmf_src_finalize(GObject * object)275 gst_rtp_dtmf_src_finalize (GObject * object)
276 {
277   GstRTPDTMFSrc *dtmfsrc;
278 
279   dtmfsrc = GST_RTP_DTMF_SRC (object);
280 
281   if (dtmfsrc->event_queue) {
282     g_async_queue_unref (dtmfsrc->event_queue);
283     dtmfsrc->event_queue = NULL;
284   }
285 
286 
287   G_OBJECT_CLASS (gst_rtp_dtmf_src_parent_class)->finalize (object);
288 }
289 
290 static gboolean
gst_rtp_dtmf_src_handle_dtmf_event(GstRTPDTMFSrc * dtmfsrc,const GstStructure * event_structure)291 gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc * dtmfsrc,
292     const GstStructure * event_structure)
293 {
294   gint event_type;
295   gboolean start;
296   gint method;
297   GstClockTime last_stop;
298   gint event_number;
299   gint event_volume;
300   gboolean correct_order;
301 
302   if (!gst_structure_get_int (event_structure, "type", &event_type) ||
303       !gst_structure_get_boolean (event_structure, "start", &start) ||
304       event_type != GST_RTP_DTMF_TYPE_EVENT)
305     goto failure;
306 
307   if (gst_structure_get_int (event_structure, "method", &method)) {
308     if (method != 1) {
309       goto failure;
310     }
311   }
312 
313   if (start)
314     if (!gst_structure_get_int (event_structure, "number", &event_number) ||
315         !gst_structure_get_int (event_structure, "volume", &event_volume))
316       goto failure;
317 
318   GST_OBJECT_LOCK (dtmfsrc);
319   if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
320     dtmfsrc->last_stop = last_stop;
321   else
322     dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
323   correct_order = (start != dtmfsrc->last_event_was_start);
324   dtmfsrc->last_event_was_start = start;
325   GST_OBJECT_UNLOCK (dtmfsrc);
326 
327   if (!correct_order)
328     goto failure;
329 
330   if (start) {
331     if (!gst_structure_get_int (event_structure, "number", &event_number) ||
332         !gst_structure_get_int (event_structure, "volume", &event_volume))
333       goto failure;
334 
335     GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
336         event_number, event_volume);
337     gst_rtp_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
338   }
339 
340   else {
341     GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
342     gst_rtp_dtmf_src_add_stop_event (dtmfsrc);
343   }
344 
345   return TRUE;
346 failure:
347   return FALSE;
348 }
349 
350 static gboolean
gst_rtp_dtmf_src_handle_custom_upstream(GstRTPDTMFSrc * dtmfsrc,GstEvent * event)351 gst_rtp_dtmf_src_handle_custom_upstream (GstRTPDTMFSrc * dtmfsrc,
352     GstEvent * event)
353 {
354   gboolean result = FALSE;
355   gchar *struct_str;
356   const GstStructure *structure;
357 
358   GstState state;
359   GstStateChangeReturn ret;
360 
361   ret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
362   if (ret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
363     GST_DEBUG_OBJECT (dtmfsrc, "Received event while not in PLAYING state");
364     goto ret;
365   }
366 
367   GST_DEBUG_OBJECT (dtmfsrc, "Received event is of our interest");
368   structure = gst_event_get_structure (event);
369   struct_str = gst_structure_to_string (structure);
370   GST_DEBUG_OBJECT (dtmfsrc, "Event has structure %s", struct_str);
371   g_free (struct_str);
372   if (structure && gst_structure_has_name (structure, "dtmf-event"))
373     result = gst_rtp_dtmf_src_handle_dtmf_event (dtmfsrc, structure);
374 
375 ret:
376   return result;
377 }
378 
379 static gboolean
gst_rtp_dtmf_src_handle_event(GstBaseSrc * basesrc,GstEvent * event)380 gst_rtp_dtmf_src_handle_event (GstBaseSrc * basesrc, GstEvent * event)
381 {
382   GstRTPDTMFSrc *dtmfsrc;
383   gboolean result = FALSE;
384 
385   dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
386 
387   GST_DEBUG_OBJECT (dtmfsrc, "Received an event on the src pad");
388   if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
389     result = gst_rtp_dtmf_src_handle_custom_upstream (dtmfsrc, event);
390   }
391 
392   return result;
393 }
394 
395 static void
gst_rtp_dtmf_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)396 gst_rtp_dtmf_src_set_property (GObject * object, guint prop_id,
397     const GValue * value, GParamSpec * pspec)
398 {
399   GstRTPDTMFSrc *dtmfsrc;
400 
401   dtmfsrc = GST_RTP_DTMF_SRC (object);
402 
403   switch (prop_id) {
404     case PROP_TIMESTAMP_OFFSET:
405       dtmfsrc->ts_offset = g_value_get_int (value);
406       break;
407     case PROP_SEQNUM_OFFSET:
408       dtmfsrc->seqnum_offset = g_value_get_int (value);
409       break;
410     case PROP_CLOCK_RATE:
411       dtmfsrc->clock_rate = g_value_get_uint (value);
412       dtmfsrc->dirty = TRUE;
413       break;
414     case PROP_SSRC:
415       dtmfsrc->ssrc = g_value_get_uint (value);
416       break;
417     case PROP_PT:
418       dtmfsrc->pt = g_value_get_uint (value);
419       dtmfsrc->dirty = TRUE;
420       break;
421     case PROP_REDUNDANCY:
422       dtmfsrc->packet_redundancy = g_value_get_uint (value);
423       break;
424     default:
425       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
426       break;
427   }
428 }
429 
430 static void
gst_rtp_dtmf_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)431 gst_rtp_dtmf_src_get_property (GObject * object, guint prop_id, GValue * value,
432     GParamSpec * pspec)
433 {
434   GstRTPDTMFSrc *dtmfsrc;
435 
436   dtmfsrc = GST_RTP_DTMF_SRC (object);
437 
438   switch (prop_id) {
439     case PROP_TIMESTAMP_OFFSET:
440       g_value_set_int (value, dtmfsrc->ts_offset);
441       break;
442     case PROP_SEQNUM_OFFSET:
443       g_value_set_int (value, dtmfsrc->seqnum_offset);
444       break;
445     case PROP_CLOCK_RATE:
446       g_value_set_uint (value, dtmfsrc->clock_rate);
447       break;
448     case PROP_SSRC:
449       g_value_set_uint (value, dtmfsrc->ssrc);
450       break;
451     case PROP_PT:
452       g_value_set_uint (value, dtmfsrc->pt);
453       break;
454     case PROP_TIMESTAMP:
455       g_value_set_uint (value, dtmfsrc->rtp_timestamp);
456       break;
457     case PROP_SEQNUM:
458       g_value_set_uint (value, dtmfsrc->seqnum);
459       break;
460     case PROP_REDUNDANCY:
461       g_value_set_uint (value, dtmfsrc->packet_redundancy);
462       break;
463     default:
464       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
465       break;
466   }
467 }
468 
469 static gboolean
gst_rtp_dtmf_prepare_timestamps(GstRTPDTMFSrc * dtmfsrc)470 gst_rtp_dtmf_prepare_timestamps (GstRTPDTMFSrc * dtmfsrc)
471 {
472   GstClockTime last_stop;
473 
474   GST_OBJECT_LOCK (dtmfsrc);
475   last_stop = dtmfsrc->last_stop;
476   GST_OBJECT_UNLOCK (dtmfsrc);
477 
478   if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
479     dtmfsrc->start_timestamp = last_stop;
480   } else {
481     GstClock *clock = gst_element_get_clock (GST_ELEMENT (dtmfsrc));
482 
483     if (clock == NULL)
484       return FALSE;
485 
486     dtmfsrc->start_timestamp = gst_clock_get_time (clock)
487         - gst_element_get_base_time (GST_ELEMENT (dtmfsrc));
488     gst_object_unref (clock);
489   }
490 
491   /* If the last stop was in the past, then lets add the buffers together */
492   if (dtmfsrc->start_timestamp < dtmfsrc->timestamp)
493     dtmfsrc->start_timestamp = dtmfsrc->timestamp;
494 
495   dtmfsrc->timestamp = dtmfsrc->start_timestamp;
496 
497   dtmfsrc->rtp_timestamp = dtmfsrc->ts_base +
498       gst_util_uint64_scale_int (gst_segment_to_running_time (&GST_BASE_SRC
499           (dtmfsrc)->segment, GST_FORMAT_TIME, dtmfsrc->timestamp),
500       dtmfsrc->clock_rate, GST_SECOND);
501 
502   return TRUE;
503 }
504 
505 
506 static void
gst_rtp_dtmf_src_add_start_event(GstRTPDTMFSrc * dtmfsrc,gint event_number,gint event_volume)507 gst_rtp_dtmf_src_add_start_event (GstRTPDTMFSrc * dtmfsrc, gint event_number,
508     gint event_volume)
509 {
510 
511   GstRTPDTMFSrcEvent *event = g_slice_new0 (GstRTPDTMFSrcEvent);
512   event->event_type = RTP_DTMF_EVENT_TYPE_START;
513 
514   event->payload = g_slice_new0 (GstRTPDTMFPayload);
515   event->payload->event = CLAMP (event_number, MIN_EVENT, MAX_EVENT);
516   event->payload->volume = CLAMP (event_volume, MIN_VOLUME, MAX_VOLUME);
517 
518   g_async_queue_push (dtmfsrc->event_queue, event);
519 }
520 
521 static void
gst_rtp_dtmf_src_add_stop_event(GstRTPDTMFSrc * dtmfsrc)522 gst_rtp_dtmf_src_add_stop_event (GstRTPDTMFSrc * dtmfsrc)
523 {
524 
525   GstRTPDTMFSrcEvent *event = g_slice_new0 (GstRTPDTMFSrcEvent);
526   event->event_type = RTP_DTMF_EVENT_TYPE_STOP;
527 
528   g_async_queue_push (dtmfsrc->event_queue, event);
529 }
530 
531 
532 static void
gst_rtp_dtmf_prepare_rtp_headers(GstRTPDTMFSrc * dtmfsrc,GstRTPBuffer * rtpbuf)533 gst_rtp_dtmf_prepare_rtp_headers (GstRTPDTMFSrc * dtmfsrc,
534     GstRTPBuffer * rtpbuf)
535 {
536   gst_rtp_buffer_set_ssrc (rtpbuf, dtmfsrc->current_ssrc);
537   gst_rtp_buffer_set_payload_type (rtpbuf, dtmfsrc->pt);
538   /* Only the very first packet gets a marker */
539   if (dtmfsrc->first_packet) {
540     gst_rtp_buffer_set_marker (rtpbuf, TRUE);
541   }
542 
543   dtmfsrc->seqnum++;
544   gst_rtp_buffer_set_seq (rtpbuf, dtmfsrc->seqnum);
545 
546   /* timestamp of RTP header */
547   gst_rtp_buffer_set_timestamp (rtpbuf, dtmfsrc->rtp_timestamp);
548 }
549 
550 static GstBuffer *
gst_rtp_dtmf_src_create_next_rtp_packet(GstRTPDTMFSrc * dtmfsrc)551 gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc * dtmfsrc)
552 {
553   GstBuffer *buf;
554   GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
555   GstBitWriter bitwriter;
556   guint8 *payload;
557   guint8 end = dtmfsrc->last_packet ? 0x02 : 0;
558 
559   buf = gst_rtp_buffer_new_allocate (4, 0, 0);
560 
561   gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtpbuffer);
562 
563   gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, &rtpbuffer);
564 
565   /* timestamp and duration of GstBuffer */
566   /* Redundant buffer have no duration ... */
567   if (dtmfsrc->redundancy_count > 1)
568     GST_BUFFER_DURATION (buf) = 0;
569   else
570     GST_BUFFER_DURATION (buf) = dtmfsrc->ptime * GST_MSECOND;
571   GST_BUFFER_PTS (buf) = dtmfsrc->timestamp;
572 
573   payload = gst_rtp_buffer_get_payload (&rtpbuffer);
574 
575   memset (payload, 0, 4);
576   gst_bit_writer_init_with_data (&bitwriter, payload, 4, FALSE);
577   gst_bit_writer_put_bits_uint8 (&bitwriter, dtmfsrc->payload->event, 8);
578   gst_bit_writer_put_bits_uint8 (&bitwriter, end, 2);
579   gst_bit_writer_put_bits_uint8 (&bitwriter, dtmfsrc->payload->volume, 6);
580   gst_bit_writer_put_bits_uint16 (&bitwriter, dtmfsrc->payload->duration, 16);
581 
582   if (dtmfsrc->redundancy_count <= 1 && dtmfsrc->last_packet) {
583     GstClockTime inter_digit_interval = MIN_INTER_DIGIT_INTERVAL;
584 
585     if (inter_digit_interval % dtmfsrc->ptime != 0)
586       inter_digit_interval += dtmfsrc->ptime -
587           (MIN_INTER_DIGIT_INTERVAL % dtmfsrc->ptime);
588 
589     GST_BUFFER_DURATION (buf) += inter_digit_interval * GST_MSECOND;
590   }
591 
592   GST_LOG_OBJECT (dtmfsrc, "Creating new buffer with event %u duration "
593       " gst: %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT "(rtp ts:%u dur:%u)",
594       dtmfsrc->payload->event, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
595       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), dtmfsrc->rtp_timestamp,
596       dtmfsrc->payload->duration);
597 
598   /* duration of DTMF payloadfor the NEXT packet */
599   /* not updated for redundant packets */
600   if (dtmfsrc->redundancy_count <= 1)
601     dtmfsrc->payload->duration += dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
602 
603   if (GST_CLOCK_TIME_IS_VALID (dtmfsrc->timestamp))
604     dtmfsrc->timestamp += GST_BUFFER_DURATION (buf);
605 
606   gst_rtp_buffer_unmap (&rtpbuffer);
607 
608   return buf;
609 }
610 
611 static GstMessage *
gst_dtmf_src_prepare_message(GstRTPDTMFSrc * dtmfsrc,const gchar * message_name,GstRTPDTMFSrcEvent * event)612 gst_dtmf_src_prepare_message (GstRTPDTMFSrc * dtmfsrc,
613     const gchar * message_name, GstRTPDTMFSrcEvent * event)
614 {
615   GstStructure *s;
616 
617   switch (event->event_type) {
618     case RTP_DTMF_EVENT_TYPE_START:
619       s = gst_structure_new (message_name,
620           "type", G_TYPE_INT, 1,
621           "method", G_TYPE_INT, 1,
622           "start", G_TYPE_BOOLEAN, TRUE,
623           "number", G_TYPE_INT, event->payload->event,
624           "volume", G_TYPE_INT, event->payload->volume, NULL);
625       break;
626     case RTP_DTMF_EVENT_TYPE_STOP:
627       s = gst_structure_new (message_name,
628           "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 1,
629           "start", G_TYPE_BOOLEAN, FALSE, NULL);
630       break;
631     case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
632       return NULL;
633     default:
634       return NULL;
635   }
636 
637   return gst_message_new_element (GST_OBJECT (dtmfsrc), s);
638 }
639 
640 static void
gst_dtmf_src_post_message(GstRTPDTMFSrc * dtmfsrc,const gchar * message_name,GstRTPDTMFSrcEvent * event)641 gst_dtmf_src_post_message (GstRTPDTMFSrc * dtmfsrc, const gchar * message_name,
642     GstRTPDTMFSrcEvent * event)
643 {
644   GstMessage *m = gst_dtmf_src_prepare_message (dtmfsrc, message_name, event);
645 
646 
647   if (m)
648     gst_element_post_message (GST_ELEMENT (dtmfsrc), m);
649 }
650 
651 
652 static GstFlowReturn
gst_rtp_dtmf_src_create(GstBaseSrc * basesrc,guint64 offset,guint length,GstBuffer ** buffer)653 gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset,
654     guint length, GstBuffer ** buffer)
655 {
656   GstRTPDTMFSrcEvent *event;
657   GstRTPDTMFSrc *dtmfsrc;
658   GstClock *clock;
659   GstClockID *clockid;
660   GstClockReturn clockret;
661   GstMessage *message;
662   GQueue messages = G_QUEUE_INIT;
663 
664   dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
665 
666   do {
667 
668     if (dtmfsrc->payload == NULL) {
669       GST_DEBUG_OBJECT (dtmfsrc, "popping");
670       event = g_async_queue_pop (dtmfsrc->event_queue);
671 
672       GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type);
673 
674       switch (event->event_type) {
675         case RTP_DTMF_EVENT_TYPE_STOP:
676           GST_WARNING_OBJECT (dtmfsrc,
677               "Received a DTMF stop event when already stopped");
678           gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
679           break;
680 
681         case RTP_DTMF_EVENT_TYPE_START:
682           dtmfsrc->first_packet = TRUE;
683           dtmfsrc->last_packet = FALSE;
684           /* Set the redundancy on the first packet */
685           dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
686           if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc))
687             goto no_clock;
688 
689           g_queue_push_tail (&messages,
690               gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
691                   event));
692           dtmfsrc->payload = event->payload;
693           dtmfsrc->payload->duration =
694               dtmfsrc->ptime * dtmfsrc->clock_rate / 1000;
695           event->payload = NULL;
696           break;
697 
698         case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
699           /*
700            * We're pushing it back because it has to stay in there until
701            * the task is really paused (and the queue will then be flushed
702            */
703           GST_OBJECT_LOCK (dtmfsrc);
704           if (dtmfsrc->paused) {
705             g_async_queue_push (dtmfsrc->event_queue, event);
706             goto paused_locked;
707           }
708           GST_OBJECT_UNLOCK (dtmfsrc);
709           break;
710       }
711 
712       gst_rtp_dtmf_src_event_free (event);
713     } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet &&
714         (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >=
715         MIN_PULSE_DURATION) {
716       GST_DEBUG_OBJECT (dtmfsrc, "try popping");
717       event = g_async_queue_try_pop (dtmfsrc->event_queue);
718 
719 
720       if (event != NULL) {
721         GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type);
722 
723         switch (event->event_type) {
724           case RTP_DTMF_EVENT_TYPE_START:
725             GST_WARNING_OBJECT (dtmfsrc,
726                 "Received two consecutive DTMF start events");
727             gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
728             break;
729 
730           case RTP_DTMF_EVENT_TYPE_STOP:
731             dtmfsrc->first_packet = FALSE;
732             dtmfsrc->last_packet = TRUE;
733             /* Set the redundancy on the last packet */
734             dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
735             g_queue_push_tail (&messages,
736                 gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed",
737                     event));
738             break;
739 
740           case RTP_DTMF_EVENT_TYPE_PAUSE_TASK:
741             /*
742              * We're pushing it back because it has to stay in there until
743              * the task is really paused (and the queue will then be flushed)
744              */
745             GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task...");
746             GST_OBJECT_LOCK (dtmfsrc);
747             if (dtmfsrc->paused) {
748               g_async_queue_push (dtmfsrc->event_queue, event);
749               goto paused_locked;
750             }
751             GST_OBJECT_UNLOCK (dtmfsrc);
752             break;
753         }
754         gst_rtp_dtmf_src_event_free (event);
755       }
756     }
757   } while (dtmfsrc->payload == NULL);
758 
759 
760   GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock");
761 
762   clock = gst_element_get_clock (GST_ELEMENT (basesrc));
763   if (!clock)
764     goto no_clock;
765   clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp +
766       gst_element_get_base_time (GST_ELEMENT (dtmfsrc)));
767   gst_object_unref (clock);
768 
769   GST_OBJECT_LOCK (dtmfsrc);
770   if (!dtmfsrc->paused) {
771     dtmfsrc->clockid = clockid;
772     GST_OBJECT_UNLOCK (dtmfsrc);
773 
774     clockret = gst_clock_id_wait (clockid, NULL);
775 
776     GST_OBJECT_LOCK (dtmfsrc);
777     if (dtmfsrc->paused)
778       clockret = GST_CLOCK_UNSCHEDULED;
779   } else {
780     clockret = GST_CLOCK_UNSCHEDULED;
781   }
782   gst_clock_id_unref (clockid);
783   dtmfsrc->clockid = NULL;
784   GST_OBJECT_UNLOCK (dtmfsrc);
785 
786   while ((message = g_queue_pop_head (&messages)) != NULL)
787     gst_element_post_message (GST_ELEMENT (dtmfsrc), message);
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     g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload);
812     dtmfsrc->payload = NULL;
813 
814     dtmfsrc->last_packet = FALSE;
815   }
816 
817   return GST_FLOW_OK;
818 
819 paused_locked:
820 
821   GST_OBJECT_UNLOCK (dtmfsrc);
822 
823 paused:
824 
825   if (dtmfsrc->payload) {
826     dtmfsrc->first_packet = FALSE;
827     dtmfsrc->last_packet = TRUE;
828     /* Set the redundanc on the last packet */
829     dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy;
830     goto send_last;
831   } else {
832     return GST_FLOW_FLUSHING;
833   }
834 
835 no_clock:
836   GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"),
837       ("No available clock"));
838   gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc));
839   return GST_FLOW_ERROR;
840 }
841 
842 
843 static gboolean
gst_rtp_dtmf_src_negotiate(GstBaseSrc * basesrc)844 gst_rtp_dtmf_src_negotiate (GstBaseSrc * basesrc)
845 {
846   GstCaps *srccaps, *peercaps;
847   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
848   gboolean ret;
849 
850   /* fill in the defaults, there properties cannot be negotiated. */
851   srccaps = gst_caps_new_simple ("application/x-rtp",
852       "media", G_TYPE_STRING, "audio",
853       "encoding-name", G_TYPE_STRING, "TELEPHONE-EVENT", NULL);
854 
855   /* the peer caps can override some of the defaults */
856   peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
857   if (peercaps == NULL) {
858     /* no peer caps, just add the other properties */
859     gst_caps_set_simple (srccaps,
860         "payload", G_TYPE_INT, dtmfsrc->pt,
861         "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc,
862         "timestamp-offset", G_TYPE_UINT, dtmfsrc->ts_base,
863         "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate,
864         "seqnum-offset", G_TYPE_UINT, dtmfsrc->seqnum_base, NULL);
865 
866     GST_DEBUG_OBJECT (dtmfsrc, "no peer caps: %" GST_PTR_FORMAT, srccaps);
867   } else {
868     GstCaps *temp;
869     GstStructure *s;
870     const GValue *value;
871     gint pt;
872     gint clock_rate;
873 
874     /* peer provides caps we can use to fixate, intersect. This always returns a
875      * writable caps. */
876     temp = gst_caps_intersect (srccaps, peercaps);
877     gst_caps_unref (srccaps);
878     gst_caps_unref (peercaps);
879 
880     if (!temp) {
881       GST_DEBUG_OBJECT (dtmfsrc, "Could not get intersection with peer caps");
882       return FALSE;
883     }
884 
885     if (gst_caps_is_empty (temp)) {
886       GST_DEBUG_OBJECT (dtmfsrc, "Intersection with peer caps is empty");
887       gst_caps_unref (temp);
888       return FALSE;
889     }
890 
891     /* now fixate, start by taking the first caps */
892     temp = gst_caps_truncate (temp);
893     temp = gst_caps_make_writable (temp);
894     srccaps = temp;
895 
896     /* get first structure */
897     s = gst_caps_get_structure (srccaps, 0);
898 
899     if (gst_structure_get_int (s, "payload", &pt)) {
900       /* use peer pt */
901       dtmfsrc->pt = pt;
902       GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
903     } else {
904       if (gst_structure_has_field (s, "payload")) {
905         /* can only fixate if there is a field */
906         gst_structure_fixate_field_nearest_int (s, "payload", dtmfsrc->pt);
907         gst_structure_get_int (s, "payload", &pt);
908         GST_LOG_OBJECT (dtmfsrc, "using peer pt %d", pt);
909       } else {
910         /* no pt field, use the internal pt */
911         pt = dtmfsrc->pt;
912         gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
913         GST_LOG_OBJECT (dtmfsrc, "using internal pt %d", pt);
914       }
915     }
916 
917     if (gst_structure_get_int (s, "clock-rate", &clock_rate)) {
918       dtmfsrc->clock_rate = clock_rate;
919       GST_LOG_OBJECT (dtmfsrc, "using clock-rate from caps %d",
920           dtmfsrc->clock_rate);
921     } else {
922       GST_LOG_OBJECT (dtmfsrc, "using existing clock-rate %d",
923           dtmfsrc->clock_rate);
924     }
925     gst_structure_set (s, "clock-rate", G_TYPE_INT, dtmfsrc->clock_rate, NULL);
926 
927 
928     if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
929       value = gst_structure_get_value (s, "ssrc");
930       dtmfsrc->current_ssrc = g_value_get_uint (value);
931       GST_LOG_OBJECT (dtmfsrc, "using peer ssrc %08x", dtmfsrc->current_ssrc);
932     } else {
933       /* FIXME, fixate_nearest_uint would be even better */
934       gst_structure_set (s, "ssrc", G_TYPE_UINT, dtmfsrc->current_ssrc, NULL);
935       GST_LOG_OBJECT (dtmfsrc, "using internal ssrc %08x",
936           dtmfsrc->current_ssrc);
937     }
938 
939     if (gst_structure_has_field_typed (s, "timestamp-offset", G_TYPE_UINT)) {
940       value = gst_structure_get_value (s, "timestamp-offset");
941       dtmfsrc->ts_base = g_value_get_uint (value);
942       GST_LOG_OBJECT (dtmfsrc, "using peer timestamp-offset %u",
943           dtmfsrc->ts_base);
944     } else {
945       /* FIXME, fixate_nearest_uint would be even better */
946       gst_structure_set (s, "timestamp-offset", G_TYPE_UINT, dtmfsrc->ts_base,
947           NULL);
948       GST_LOG_OBJECT (dtmfsrc, "using internal timestamp-offset %u",
949           dtmfsrc->ts_base);
950     }
951     if (gst_structure_has_field_typed (s, "seqnum-offset", G_TYPE_UINT)) {
952       value = gst_structure_get_value (s, "seqnum-offset");
953       dtmfsrc->seqnum_base = g_value_get_uint (value);
954       GST_LOG_OBJECT (dtmfsrc, "using peer seqnum-offset %u",
955           dtmfsrc->seqnum_base);
956     } else {
957       /* FIXME, fixate_nearest_uint would be even better */
958       gst_structure_set (s, "seqnum-offset", G_TYPE_UINT, dtmfsrc->seqnum_base,
959           NULL);
960       GST_LOG_OBJECT (dtmfsrc, "using internal seqnum-offset %u",
961           dtmfsrc->seqnum_base);
962     }
963 
964     if (gst_structure_has_field_typed (s, "ptime", G_TYPE_UINT)) {
965       value = gst_structure_get_value (s, "ptime");
966       dtmfsrc->ptime = g_value_get_uint (value);
967       GST_LOG_OBJECT (dtmfsrc, "using peer ptime %u", dtmfsrc->ptime);
968     } else if (gst_structure_has_field_typed (s, "maxptime", G_TYPE_UINT)) {
969       value = gst_structure_get_value (s, "maxptime");
970       dtmfsrc->ptime = g_value_get_uint (value);
971       GST_LOG_OBJECT (dtmfsrc, "using peer maxptime as ptime %u",
972           dtmfsrc->ptime);
973     } else {
974       /* FIXME, fixate_nearest_uint would be even better */
975       gst_structure_set (s, "ptime", G_TYPE_UINT, dtmfsrc->ptime, NULL);
976       GST_LOG_OBJECT (dtmfsrc, "using internal ptime %u", dtmfsrc->ptime);
977     }
978 
979 
980     GST_DEBUG_OBJECT (dtmfsrc, "with peer caps: %" GST_PTR_FORMAT, srccaps);
981   }
982 
983   ret = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), srccaps);
984   gst_caps_unref (srccaps);
985 
986   dtmfsrc->dirty = FALSE;
987 
988   return ret;
989 
990 }
991 
992 static gboolean
gst_rtp_dtmf_src_query(GstBaseSrc * basesrc,GstQuery * query)993 gst_rtp_dtmf_src_query (GstBaseSrc * basesrc, GstQuery * query)
994 {
995   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (basesrc);
996   gboolean res = FALSE;
997 
998   switch (GST_QUERY_TYPE (query)) {
999     case GST_QUERY_LATENCY:
1000     {
1001       GstClockTime latency;
1002 
1003       latency = dtmfsrc->ptime * GST_MSECOND;
1004       gst_query_set_latency (query, gst_base_src_is_live (basesrc), latency,
1005           GST_CLOCK_TIME_NONE);
1006       GST_DEBUG_OBJECT (dtmfsrc, "Reporting latency of %" GST_TIME_FORMAT,
1007           GST_TIME_ARGS (latency));
1008       res = TRUE;
1009     }
1010       break;
1011     default:
1012       res = GST_BASE_SRC_CLASS (gst_rtp_dtmf_src_parent_class)->query (basesrc,
1013           query);
1014       break;
1015   }
1016 
1017   return res;
1018 }
1019 
1020 static void
gst_rtp_dtmf_src_ready_to_paused(GstRTPDTMFSrc * dtmfsrc)1021 gst_rtp_dtmf_src_ready_to_paused (GstRTPDTMFSrc * dtmfsrc)
1022 {
1023   if (dtmfsrc->ssrc == -1)
1024     dtmfsrc->current_ssrc = g_random_int ();
1025   else
1026     dtmfsrc->current_ssrc = dtmfsrc->ssrc;
1027 
1028   if (dtmfsrc->seqnum_offset == -1)
1029     dtmfsrc->seqnum_base = g_random_int_range (0, G_MAXUINT16);
1030   else
1031     dtmfsrc->seqnum_base = dtmfsrc->seqnum_offset;
1032   dtmfsrc->seqnum = dtmfsrc->seqnum_base;
1033 
1034   if (dtmfsrc->ts_offset == -1)
1035     dtmfsrc->ts_base = g_random_int ();
1036   else
1037     dtmfsrc->ts_base = dtmfsrc->ts_offset;
1038 
1039   dtmfsrc->timestamp = 0;
1040 }
1041 
1042 static GstStateChangeReturn
gst_rtp_dtmf_src_change_state(GstElement * element,GstStateChange transition)1043 gst_rtp_dtmf_src_change_state (GstElement * element, GstStateChange transition)
1044 {
1045   GstRTPDTMFSrc *dtmfsrc;
1046   GstStateChangeReturn result;
1047   gboolean no_preroll = FALSE;
1048   GstRTPDTMFSrcEvent *event = NULL;
1049 
1050   dtmfsrc = GST_RTP_DTMF_SRC (element);
1051 
1052   switch (transition) {
1053     case GST_STATE_CHANGE_READY_TO_PAUSED:
1054       gst_rtp_dtmf_src_ready_to_paused (dtmfsrc);
1055 
1056       /* Flushing the event queue */
1057       while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL) {
1058         gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
1059         gst_rtp_dtmf_src_event_free (event);
1060       }
1061       dtmfsrc->last_event_was_start = FALSE;
1062 
1063       no_preroll = TRUE;
1064       break;
1065     default:
1066       break;
1067   }
1068 
1069   if ((result =
1070           GST_ELEMENT_CLASS (gst_rtp_dtmf_src_parent_class)->change_state
1071           (element, transition)) == GST_STATE_CHANGE_FAILURE)
1072     goto failure;
1073 
1074   switch (transition) {
1075     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1076       no_preroll = TRUE;
1077       break;
1078     case GST_STATE_CHANGE_PAUSED_TO_READY:
1079 
1080       /* Flushing the event queue */
1081       while ((event = g_async_queue_try_pop (dtmfsrc->event_queue)) != NULL) {
1082         gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event);
1083         gst_rtp_dtmf_src_event_free (event);
1084       }
1085       dtmfsrc->last_event_was_start = FALSE;
1086 
1087       /* Indicate that we don't do PRE_ROLL */
1088       break;
1089 
1090     default:
1091       break;
1092   }
1093 
1094   if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
1095     result = GST_STATE_CHANGE_NO_PREROLL;
1096 
1097   return result;
1098 
1099   /* ERRORS */
1100 failure:
1101   {
1102     GST_ERROR_OBJECT (dtmfsrc, "parent failed state change");
1103     return result;
1104   }
1105 }
1106 
1107 
1108 static gboolean
gst_rtp_dtmf_src_unlock(GstBaseSrc * src)1109 gst_rtp_dtmf_src_unlock (GstBaseSrc * src)
1110 {
1111   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
1112   GstRTPDTMFSrcEvent *event = NULL;
1113 
1114   GST_DEBUG_OBJECT (dtmfsrc, "Called unlock");
1115 
1116   GST_OBJECT_LOCK (dtmfsrc);
1117   dtmfsrc->paused = TRUE;
1118   if (dtmfsrc->clockid) {
1119     gst_clock_id_unschedule (dtmfsrc->clockid);
1120   }
1121   GST_OBJECT_UNLOCK (dtmfsrc);
1122 
1123   GST_DEBUG_OBJECT (dtmfsrc, "Pushing the PAUSE_TASK event on unlock request");
1124   event = g_slice_new0 (GstRTPDTMFSrcEvent);
1125   event->event_type = RTP_DTMF_EVENT_TYPE_PAUSE_TASK;
1126   g_async_queue_push (dtmfsrc->event_queue, event);
1127 
1128   return TRUE;
1129 }
1130 
1131 
1132 static gboolean
gst_rtp_dtmf_src_unlock_stop(GstBaseSrc * src)1133 gst_rtp_dtmf_src_unlock_stop (GstBaseSrc * src)
1134 {
1135   GstRTPDTMFSrc *dtmfsrc = GST_RTP_DTMF_SRC (src);
1136 
1137   GST_DEBUG_OBJECT (dtmfsrc, "Unlock stopped");
1138 
1139   GST_OBJECT_LOCK (dtmfsrc);
1140   dtmfsrc->paused = FALSE;
1141   GST_OBJECT_UNLOCK (dtmfsrc);
1142 
1143   return TRUE;
1144 }
1145