• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014, Ericsson AB. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this
11  * list of conditions and the following disclaimer in the documentation and/or other
12  * materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23  * OF SUCH DAMAGE.
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 
30 #include "gstdtlselements.h"
31 #include "gstdtlssrtpenc.h"
32 #include "gstdtlsconnection.h"
33 
34 #include <stdio.h>
35 
36 static GstStaticPadTemplate rtp_sink_template =
37     GST_STATIC_PAD_TEMPLATE ("rtp_sink_%d",
38     GST_PAD_SINK,
39     GST_PAD_REQUEST,
40     GST_STATIC_CAPS ("application/x-rtp;application/x-rtcp")
41     );
42 
43 static GstStaticPadTemplate rtcp_sink_template =
44     GST_STATIC_PAD_TEMPLATE ("rtcp_sink_%d",
45     GST_PAD_SINK,
46     GST_PAD_REQUEST,
47     GST_STATIC_CAPS ("application/x-rtp;application/x-rtcp")
48     );
49 
50 static GstStaticPadTemplate data_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("data_sink",
52     GST_PAD_SINK,
53     GST_PAD_REQUEST,
54     GST_STATIC_CAPS_ANY);
55 
56 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
57     GST_PAD_SRC,
58     GST_PAD_ALWAYS,
59     GST_STATIC_CAPS_ANY);
60 
61 GST_DEBUG_CATEGORY_STATIC (gst_dtls_srtp_enc_debug);
62 #define GST_CAT_DEFAULT gst_dtls_srtp_enc_debug
63 
64 #define gst_dtls_srtp_enc_parent_class parent_class
65 G_DEFINE_TYPE_WITH_CODE (GstDtlsSrtpEnc, gst_dtls_srtp_enc,
66     GST_TYPE_DTLS_SRTP_BIN, GST_DEBUG_CATEGORY_INIT (gst_dtls_srtp_enc_debug,
67         "dtlssrtpenc", 0, "DTLS Decoder"));
68 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (dtlssrtpenc, "dtlssrtpenc",
69     GST_RANK_NONE, GST_TYPE_DTLS_SRTP_ENC, dtls_element_init (plugin));
70 
71 enum
72 {
73   SIGNAL_ON_KEY_SET,
74   NUM_SIGNALS
75 };
76 
77 static guint signals[NUM_SIGNALS];
78 
79 enum
80 {
81   PROP_0,
82   PROP_IS_CLIENT,
83   PROP_CONNECTION_STATE,
84   PROP_RTP_SYNC,
85   NUM_PROPERTIES
86 };
87 
88 static GParamSpec *properties[NUM_PROPERTIES];
89 
90 #define DEFAULT_IS_CLIENT FALSE
91 #define DEFAULT_RTP_SYNC FALSE
92 
93 static gboolean transform_enum (GBinding *, const GValue * source_value,
94     GValue * target_value, GEnumClass *);
95 
96 static void gst_dtls_srtp_enc_set_property (GObject *, guint prop_id,
97     const GValue *, GParamSpec *);
98 static void gst_dtls_srtp_enc_get_property (GObject *, guint prop_id,
99     GValue *, GParamSpec *);
100 
101 static GstPad *add_ghost_pad (GstElement *, const gchar * name, GstPad *,
102     GstPadTemplate *);
103 static GstPad *gst_dtls_srtp_enc_request_new_pad (GstElement *,
104     GstPadTemplate *, const gchar * name, const GstCaps *);
105 
106 static void on_key_received (GObject * encoder, GstDtlsSrtpEnc *);
107 
108 static void gst_dtls_srtp_enc_remove_dtls_element (GstDtlsSrtpBin *);
109 static GstPadProbeReturn remove_dtls_encoder_probe_callback (GstPad *,
110     GstPadProbeInfo *, GstElement *);
111 
112 static void
gst_dtls_srtp_enc_class_init(GstDtlsSrtpEncClass * klass)113 gst_dtls_srtp_enc_class_init (GstDtlsSrtpEncClass * klass)
114 {
115   GObjectClass *gobject_class;
116   GstElementClass *element_class;
117   GstDtlsSrtpBinClass *dtls_srtp_bin_class;
118 
119   gobject_class = (GObjectClass *) klass;
120   element_class = (GstElementClass *) klass;
121   dtls_srtp_bin_class = (GstDtlsSrtpBinClass *) klass;
122 
123   gobject_class->set_property =
124       GST_DEBUG_FUNCPTR (gst_dtls_srtp_enc_set_property);
125   gobject_class->get_property =
126       GST_DEBUG_FUNCPTR (gst_dtls_srtp_enc_get_property);
127 
128   element_class->request_new_pad =
129       GST_DEBUG_FUNCPTR (gst_dtls_srtp_enc_request_new_pad);
130 
131   dtls_srtp_bin_class->remove_dtls_element =
132       GST_DEBUG_FUNCPTR (gst_dtls_srtp_enc_remove_dtls_element);
133 
134   signals[SIGNAL_ON_KEY_SET] =
135       g_signal_new ("on-key-set", G_TYPE_FROM_CLASS (klass),
136       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
137 
138   properties[PROP_IS_CLIENT] =
139       g_param_spec_boolean ("is-client",
140       "Is client",
141       "Set to true if the decoder should act as "
142       "client and initiate the handshake",
143       DEFAULT_IS_CLIENT,
144       GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
145 
146   properties[PROP_CONNECTION_STATE] =
147       g_param_spec_enum ("connection-state",
148       "Connection State",
149       "Current connection state",
150       GST_DTLS_TYPE_CONNECTION_STATE,
151       GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
152 
153 
154   properties[PROP_RTP_SYNC] =
155       g_param_spec_boolean ("rtp-sync", "Synchronize RTP",
156       "Synchronize RTP to the pipeline clock before merging with RTCP",
157       DEFAULT_RTP_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
158 
159   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
160 
161   gst_element_class_add_static_pad_template (element_class, &rtp_sink_template);
162   gst_element_class_add_static_pad_template (element_class,
163       &rtcp_sink_template);
164   gst_element_class_add_static_pad_template (element_class,
165       &data_sink_template);
166   gst_element_class_add_static_pad_template (element_class, &src_template);
167 
168   gst_element_class_set_static_metadata (element_class,
169       "DTLS-SRTP Encoder",
170       "Encoder/Network/DTLS/SRTP",
171       "Encodes SRTP packets with a key received from DTLS",
172       "Patrik Oldsberg patrik.oldsberg@ericsson.com");
173 }
174 
175 static void
on_connection_state_changed(GObject * object,GParamSpec * pspec,gpointer user_data)176 on_connection_state_changed (GObject * object, GParamSpec * pspec,
177     gpointer user_data)
178 {
179   GstDtlsSrtpEnc *self = GST_DTLS_SRTP_ENC (user_data);
180 
181   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONNECTION_STATE]);
182 }
183 
184 static void
gst_dtls_srtp_enc_init(GstDtlsSrtpEnc * self)185 gst_dtls_srtp_enc_init (GstDtlsSrtpEnc * self)
186 {
187   GstElementClass *klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (self));
188   static GEnumClass *cipher_enum_class, *auth_enum_class;
189   gboolean ret;
190 
191 /*
192                  +--------------------+    +--------------+     +-----------------+
193      rtp_sink-R-o|rtp_sink     rtp_src|o-R-o   clocksync  |o-R-o|                 |
194                  |       srtpenc      |    +--------------+     |                 |
195                  |                    |                         |                 |
196     rtcp_sink-R-o|srtcp_sink  rtcp_src|o-----------R-----------o|                 |
197                  +--------------------+                         |     funnel      |o---src
198                                                                 |                 |
199                  +--------------------+                         |                 |
200     data_sink-R-o|       dtlsenc      |o-----------------------o|                 |
201                  +--------------------+                         +-----------------+
202 
203     The clocksync element is tied to the sync property. If sync=true, RTP output will be
204     synchronised to the clock, so it doesn't slow down RTCP traffic by being synched later
205     in the pipeline
206 */
207 
208   self->srtp_enc = gst_element_factory_make ("srtpenc", NULL);
209   if (!self->srtp_enc) {
210     GST_ERROR_OBJECT (self,
211         "failed to create srtp encoder, is the srtp plugin registered?");
212     return;
213   }
214   g_return_if_fail (self->srtp_enc);
215   self->bin.dtls_element = gst_element_factory_make ("dtlsenc", NULL);
216   if (!self->bin.dtls_element) {
217     GST_ERROR_OBJECT (self, "failed to create dtls encoder");
218     return;
219   }
220   self->funnel = gst_element_factory_make ("funnel", NULL);
221   if (!self->funnel) {
222     GST_ERROR_OBJECT (self, "failed to create funnel");
223     return;
224   }
225 
226   gst_bin_add_many (GST_BIN (self), self->bin.dtls_element, self->srtp_enc,
227       self->funnel, NULL);
228 
229   ret = gst_element_link (self->bin.dtls_element, self->funnel);
230   g_return_if_fail (ret);
231 
232   add_ghost_pad (GST_ELEMENT (self), "src",
233       gst_element_get_static_pad (self->funnel, "src"),
234       gst_element_class_get_pad_template (klass, "src"));
235 
236   g_signal_connect (self->bin.dtls_element, "on-key-received",
237       G_CALLBACK (on_key_received), self);
238 
239   if (g_once_init_enter (&cipher_enum_class)) {
240     GType type = g_type_from_name ("GstSrtpCipherType");
241     g_assert (type);
242     g_once_init_leave (&cipher_enum_class, g_type_class_peek (type));
243   }
244   if (g_once_init_enter (&auth_enum_class)) {
245     GType type = g_type_from_name ("GstSrtpAuthType");
246     g_assert (type);
247     g_once_init_leave (&auth_enum_class, g_type_class_peek (type));
248   }
249 
250   g_object_set (self->srtp_enc, "random-key", TRUE, NULL);
251 
252   g_signal_connect (self->bin.dtls_element, "notify::connection-state",
253       G_CALLBACK (on_connection_state_changed), self);
254 
255   g_object_bind_property (G_OBJECT (self), "key", self->srtp_enc, "key",
256       G_BINDING_DEFAULT);
257   g_object_bind_property_full (G_OBJECT (self), "srtp-cipher", self->srtp_enc,
258       "rtp-cipher", G_BINDING_DEFAULT, (GBindingTransformFunc) transform_enum,
259       NULL, cipher_enum_class, NULL);
260   g_object_bind_property_full (G_OBJECT (self), "srtcp-cipher", self->srtp_enc,
261       "rtcp-cipher", G_BINDING_DEFAULT, (GBindingTransformFunc) transform_enum,
262       NULL, cipher_enum_class, NULL);
263   g_object_bind_property_full (G_OBJECT (self), "srtp-auth", self->srtp_enc,
264       "rtp-auth", G_BINDING_DEFAULT, (GBindingTransformFunc) transform_enum,
265       NULL, auth_enum_class, NULL);
266   g_object_bind_property_full (G_OBJECT (self), "srtcp-auth", self->srtp_enc,
267       "rtcp-auth", G_BINDING_DEFAULT, (GBindingTransformFunc) transform_enum,
268       NULL, auth_enum_class, NULL);
269 }
270 
271 #if GLIB_CHECK_VERSION(2,68,0)
272 #define binding_get_source(b) g_binding_dup_source(b)
273 #define unref_source(s) G_STMT_START { if(s) g_object_unref(s); } G_STMT_END
274 #else
275 #define binding_get_source(b) g_binding_get_source(b)
276 #define unref_source(s)         /* no op */
277 #endif
278 
279 static gboolean
transform_enum(GBinding * binding,const GValue * source_value,GValue * target_value,GEnumClass * enum_class)280 transform_enum (GBinding * binding, const GValue * source_value,
281     GValue * target_value, GEnumClass * enum_class)
282 {
283   GEnumValue *enum_value;
284   const gchar *nick;
285   GObject *bind_src;
286 
287   nick = g_value_get_string (source_value);
288   g_return_val_if_fail (nick, FALSE);
289 
290   enum_value = g_enum_get_value_by_nick (enum_class, nick);
291   g_return_val_if_fail (enum_value, FALSE);
292 
293   bind_src = binding_get_source (binding);
294 
295   GST_DEBUG_OBJECT (bind_src,
296       "transforming enum from %s to %d", nick, enum_value->value);
297 
298   unref_source (bind_src);
299 
300   g_value_set_enum (target_value, enum_value->value);
301 
302   return TRUE;
303 }
304 
305 static void
gst_dtls_srtp_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)306 gst_dtls_srtp_enc_set_property (GObject * object,
307     guint prop_id, const GValue * value, GParamSpec * pspec)
308 {
309   GstDtlsSrtpEnc *self = GST_DTLS_SRTP_ENC (object);
310 
311   switch (prop_id) {
312     case PROP_IS_CLIENT:
313       if (self->bin.dtls_element) {
314         g_object_set_property (G_OBJECT (self->bin.dtls_element), "is-client",
315             value);
316       } else {
317         GST_WARNING_OBJECT (self,
318             "tried to set is-client after disabling DTLS");
319       }
320       break;
321     case PROP_RTP_SYNC:
322       self->rtp_sync = g_value_get_boolean (value);
323       break;
324     default:
325       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
326   }
327 }
328 
329 static void
gst_dtls_srtp_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)330 gst_dtls_srtp_enc_get_property (GObject * object,
331     guint prop_id, GValue * value, GParamSpec * pspec)
332 {
333   GstDtlsSrtpEnc *self = GST_DTLS_SRTP_ENC (object);
334 
335   switch (prop_id) {
336     case PROP_IS_CLIENT:
337       if (self->bin.dtls_element) {
338         g_object_get_property (G_OBJECT (self->bin.dtls_element), "is-client",
339             value);
340       } else {
341         GST_WARNING_OBJECT (self,
342             "tried to get is-client after disabling DTLS");
343       }
344       break;
345     case PROP_CONNECTION_STATE:
346       if (self->bin.dtls_element) {
347         g_object_get_property (G_OBJECT (self->bin.dtls_element),
348             "connection-state", value);
349       } else {
350         GST_WARNING_OBJECT (self,
351             "tried to get connection-state after disabling DTLS");
352       }
353       break;
354     case PROP_RTP_SYNC:
355       g_value_set_boolean (value, self->rtp_sync);
356       break;
357     default:
358       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
359   }
360 }
361 
362 static GstPad *
add_ghost_pad(GstElement * element,const gchar * name,GstPad * target,GstPadTemplate * templ)363 add_ghost_pad (GstElement * element,
364     const gchar * name, GstPad * target, GstPadTemplate * templ)
365 {
366   GstPad *pad;
367   gboolean ret;
368 
369   pad = gst_ghost_pad_new_from_template (name, target, templ);
370   gst_object_unref (target);
371   target = NULL;
372 
373   ret = gst_pad_set_active (pad, TRUE);
374   g_warn_if_fail (ret);
375 
376   ret = gst_element_add_pad (element, pad);
377   g_warn_if_fail (ret);
378 
379   return pad;
380 }
381 
382 static GstPad *
gst_dtls_srtp_enc_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * name,const GstCaps * caps)383 gst_dtls_srtp_enc_request_new_pad (GstElement * element,
384     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
385 {
386   GstDtlsSrtpEnc *self = GST_DTLS_SRTP_ENC (element);
387   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
388   GstPad *target_pad;
389   GstPad *ghost_pad = NULL;
390   guint pad_n;
391   gchar *srtp_src_name;
392 
393   GST_DEBUG_OBJECT (element, "pad requested");
394 
395   g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
396   g_return_val_if_fail (self->srtp_enc, NULL);
397 
398   if (templ == gst_element_class_get_pad_template (klass, "rtp_sink_%d")) {
399     gchar *clocksync_name;
400     GstElement *clocksync;
401 
402     sscanf (name, "rtp_sink_%d", &pad_n);
403 
404     clocksync_name = g_strdup_printf ("clocksync_%d", pad_n);
405     clocksync = gst_element_factory_make ("clocksync", clocksync_name);
406     g_free (clocksync_name);
407 
408     if (clocksync == NULL) {
409       goto fail_create;
410     }
411 
412     g_object_bind_property (self, "rtp-sync", clocksync, "sync",
413         G_BINDING_SYNC_CREATE);
414 
415     gst_bin_add (GST_BIN (self), clocksync);
416     gst_element_sync_state_with_parent (clocksync);
417 
418     target_pad = gst_element_request_pad_simple (self->srtp_enc, name);
419     g_return_val_if_fail (target_pad, NULL);
420 
421     srtp_src_name = g_strdup_printf ("rtp_src_%d", pad_n);
422 
423     gst_element_link_pads (self->srtp_enc, srtp_src_name, clocksync, NULL);
424     gst_element_link_pads (clocksync, "src", self->funnel, NULL);
425 
426     g_free (srtp_src_name);
427 
428     ghost_pad = add_ghost_pad (element, name, target_pad, templ);
429 
430     GST_LOG_OBJECT (self, "added rtp sink pad");
431   } else if (templ == gst_element_class_get_pad_template (klass,
432           "rtcp_sink_%d")) {
433     target_pad = gst_element_request_pad_simple (self->srtp_enc, name);
434     g_return_val_if_fail (target_pad, NULL);
435 
436     sscanf (GST_PAD_NAME (target_pad), "rtcp_sink_%d", &pad_n);
437     srtp_src_name = g_strdup_printf ("rtcp_src_%d", pad_n);
438 
439     gst_element_link_pads (self->srtp_enc, srtp_src_name, self->funnel, NULL);
440 
441     g_free (srtp_src_name);
442 
443     ghost_pad = add_ghost_pad (element, name, target_pad, templ);
444 
445     GST_LOG_OBJECT (self, "added rtcp sink pad");
446   } else if (templ == gst_element_class_get_pad_template (klass, "data_sink")) {
447     g_return_val_if_fail (self->bin.dtls_element, NULL);
448     target_pad =
449         gst_element_request_pad_simple (self->bin.dtls_element, "sink");
450 
451     ghost_pad = add_ghost_pad (element, name, target_pad, templ);
452 
453     GST_LOG_OBJECT (self, "added data sink pad");
454   } else {
455     g_warn_if_reached ();
456   }
457 
458   if (caps && ghost_pad) {
459     g_object_set (ghost_pad, "caps", caps, NULL);
460   }
461 
462   return ghost_pad;
463 
464 fail_create:
465   GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, NULL,
466       ("%s", "Failed to create internal clocksync element"));
467   return NULL;
468 }
469 
470 static void
on_key_received(GObject * encoder,GstDtlsSrtpEnc * self)471 on_key_received (GObject * encoder, GstDtlsSrtpEnc * self)
472 {
473   GstDtlsSrtpBin *bin = GST_DTLS_SRTP_BIN (self);
474   GstBuffer *buffer = NULL;
475   guint cipher, auth;
476 
477   if (!(bin->key_is_set || bin->srtp_cipher || bin->srtp_auth
478           || bin->srtcp_cipher || bin->srtcp_auth)) {
479     g_object_get (encoder,
480         "encoder-key", &buffer,
481         "srtp-cipher", &cipher, "srtp-auth", &auth, NULL);
482 
483     g_object_set (self->srtp_enc,
484         "rtp-cipher", cipher,
485         "rtcp-cipher", cipher,
486         "rtp-auth", auth,
487         "rtcp-auth", auth, "key", buffer, "random-key", FALSE, NULL);
488 
489     gst_buffer_unref (buffer);
490 
491     g_signal_emit (self, signals[SIGNAL_ON_KEY_SET], 0);
492   } else {
493     GST_DEBUG_OBJECT (self,
494         "ignoring keys received from DTLS handshake, key struct is set");
495   }
496 }
497 
498 static void
gst_dtls_srtp_enc_remove_dtls_element(GstDtlsSrtpBin * bin)499 gst_dtls_srtp_enc_remove_dtls_element (GstDtlsSrtpBin * bin)
500 {
501   GstDtlsSrtpEnc *self = GST_DTLS_SRTP_ENC (bin);
502   GstPad *dtls_sink_pad, *peer_pad;
503   gulong id;
504   guint rtp_cipher = 1, rtcp_cipher = 1, rtp_auth = 1, rtcp_auth = 1;
505 
506   if (!bin->dtls_element) {
507     return;
508   }
509 
510   g_object_get (self->srtp_enc,
511       "rtp-cipher", &rtp_cipher,
512       "rtcp-cipher", &rtcp_cipher,
513       "rtp-auth", &rtp_auth, "rtcp-auth", &rtcp_auth, NULL);
514 
515   if (!rtp_cipher && !rtcp_cipher && !rtp_auth && !rtcp_auth) {
516     g_object_set (self->srtp_enc, "random-key", FALSE, NULL);
517   }
518 
519   dtls_sink_pad = gst_element_get_static_pad (bin->dtls_element, "sink");
520 
521   if (!dtls_sink_pad) {
522     gst_element_set_state (GST_ELEMENT (bin->dtls_element), GST_STATE_NULL);
523     gst_bin_remove (GST_BIN (self), bin->dtls_element);
524     bin->dtls_element = NULL;
525     return;
526   }
527 
528   peer_pad = gst_pad_get_peer (dtls_sink_pad);
529   g_return_if_fail (peer_pad);
530   gst_object_unref (dtls_sink_pad);
531   dtls_sink_pad = NULL;
532 
533   id = gst_pad_add_probe (peer_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
534       (GstPadProbeCallback) remove_dtls_encoder_probe_callback,
535       bin->dtls_element, NULL);
536   g_return_if_fail (id);
537   bin->dtls_element = NULL;
538 
539   gst_pad_push_event (peer_pad,
540       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
541           gst_structure_new_empty ("dummy")));
542 
543   gst_object_unref (peer_pad);
544 }
545 
546 static GstPadProbeReturn
remove_dtls_encoder_probe_callback(GstPad * pad,GstPadProbeInfo * info,GstElement * element)547 remove_dtls_encoder_probe_callback (GstPad * pad,
548     GstPadProbeInfo * info, GstElement * element)
549 {
550   gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
551 
552   gst_element_set_state (GST_ELEMENT (element), GST_STATE_NULL);
553   gst_bin_remove (GST_BIN (GST_ELEMENT_PARENT (element)), element);
554 
555   return GST_PAD_PROBE_OK;
556 }
557