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