ae6b450ab541a89cdd12f091b544080b79e0a026
[platform/upstream/gstreamer.git] / ext / srtp / gstsrtpenc.c
1 /*
2  * GStreamer - GStreamer SRTP encoder
3  *
4  * Copyright 2009-2011 Collabora Ltd.
5  *  @author: Gabriel Millaire <gabriel.millaire@collabora.com>
6  *  @author: Olivier Crete <olivier.crete@collabora.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Alternatively, the contents of this file may be used under the
27  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28  * which case the following provisions apply instead of the ones
29  * mentioned above:
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of the GNU Library General Public
33  * License as published by the Free Software Foundation; either
34  * version 2 of the License, or (at your option) any later version.
35  *
36  * This library is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39  * Library General Public License for more details.
40  *
41  * You should have received a copy of the GNU Library General Public
42  * License along with this library; if not, write to the
43  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44  * Boston, MA 02111-1307, USA.
45  */
46
47 /**
48  * SECTION:element-srtpenc
49  * @title: srtpenc
50  * @see_also: srtpdec
51  *
52  * gstrtpenc acts as an encoder that adds security to RTP and RTCP
53  * packets in the form of encryption and authentication. It outs SRTP
54  * and SRTCP.
55  *
56  * An application can request multiple RTP and RTCP pads to protect,
57  * but every sink pad requested must receive packets from the same
58  * source (identical SSRC). If a packet received contains a different
59  * SSRC, a warning is emited and the valid SSRC is forced on the packet.
60  *
61  * This element uses libsrtp library. When receiving the first packet,
62  * the library is initialized with a new stream (based on the SSRC). It
63  * uses the default RTP and RTCP encryption and authentication mechanisms,
64  * unless the user has set the relevant properties first. It also uses
65  * a master key that MUST be set by property (key) at the beginning. The
66  * master key must be of a maximum length of 46 characters (14 characters
67  * for the salt plus the key). The encryption and authentication mechanisms
68  * available are :
69  *
70  * Encryption (properties rtp-cipher and rtcp-cipher)
71  * - AES_ICM 256 bits (maximum security)
72  * - AES_ICM 128 bits (default)
73  * - NULL
74  *
75  * Authentication (properties rtp-auth and rtcp-auth)
76  * - HMAC_SHA1 80 bits (default, maximum protection)
77  * - HMAC_SHA1 32 bits
78  * - NULL
79  *
80  * Note that for SRTP protection, authentication is mandatory (non-null)
81  * if encryption is used (non-null).
82  *
83  * When requested to create a sink pad, a linked source pad is created.
84  * Each packet received is first analysed (checked for valid SSRC) then
85  * its buffer is protected with libsrtp, then pushed on the source pad.
86  * If protection failed or the stream could not be created, the buffer
87  * is dropped and a warning is emitted. The packets pushed on the source
88  * pad are of type 'application/x-srtp' or 'application/x-srtcp'.
89  *
90  * When the maximum usage of the master key is reached, a soft-limit
91  * signal is sent to the user. The user must then set a new master key
92  * by property. If the hard limit is reached, a flag is set and every
93  * subsequent packet is dropped, until a new key is set and the stream
94  * has been updated.
95  *
96  * If a stream is to be shared between multiple clients it is also
97  * possible to request the internal SRTP rollover counter for a given
98  * SSRC. The rollover counter should be then transmitted and used by the
99  * clients to authenticate and decrypt the packets. Failing to do that
100  * the clients will start with a rollover counter of 0 which will
101  * probably be incorrect if the stream has been transmitted for a
102  * while to other clients.
103  *
104  * This element supports sending with a single Master Key, it is possible to set the
105  * Master Key Identifier (MKI) using the "mki" property. If this property is set, the MKI
106  * will be added to every buffer.
107  */
108
109 #include "gstsrtpenc.h"
110
111 #include <gst/rtp/gstrtpbuffer.h>
112 #include <gst/rtp/gstrtcpbuffer.h>
113 #include <string.h>
114 #include <stdio.h>
115
116 GST_DEBUG_CATEGORY_STATIC (gst_srtp_enc_debug);
117 #define GST_CAT_DEFAULT gst_srtp_enc_debug
118
119 /* 128 bit key size: 14 (salt) + 16 */
120 #define MASTER_128_KEY_SIZE 30
121
122 /* 256 bit key size: 14 (salt) + 16 + 16 */
123 #define MASTER_256_KEY_SIZE 46
124
125 /* Properties default values */
126 #define DEFAULT_MASTER_KEY      NULL
127 #define DEFAULT_RTP_CIPHER      GST_SRTP_CIPHER_AES_128_ICM
128 #define DEFAULT_RTP_AUTH        GST_SRTP_AUTH_HMAC_SHA1_80
129 #define DEFAULT_RTCP_CIPHER     DEFAULT_RTP_CIPHER
130 #define DEFAULT_RTCP_AUTH       DEFAULT_RTP_AUTH
131 #define DEFAULT_RANDOM_KEY      FALSE
132 #define DEFAULT_REPLAY_WINDOW_SIZE 128
133 #define DEFAULT_ALLOW_REPEAT_TX FALSE
134
135 #define HAS_CRYPTO(filter) (filter->rtp_cipher != GST_SRTP_CIPHER_NULL || \
136       filter->rtcp_cipher != GST_SRTP_CIPHER_NULL ||                      \
137       filter->rtp_auth != GST_SRTP_AUTH_NULL ||                           \
138       filter->rtcp_auth != GST_SRTP_AUTH_NULL)
139
140 /* Filter signals and args */
141 enum
142 {
143   SIGNAL_SOFT_LIMIT,
144   SIGNAL_GET_ROLLOVER_COUNTER,
145   LAST_SIGNAL
146 };
147
148 enum
149 {
150   PROP_0,
151   PROP_MKEY,
152   PROP_RTP_CIPHER,
153   PROP_RTP_AUTH,
154   PROP_RTCP_CIPHER,
155   PROP_RTCP_AUTH,
156   PROP_RANDOM_KEY,
157   PROP_REPLAY_WINDOW_SIZE,
158   PROP_ALLOW_REPEAT_TX,
159   PROP_STATS,
160   PROP_MKI
161 };
162
163 typedef struct ProcessBufferItData
164 {
165   GstSrtpEnc *filter;
166   GstPad *pad;
167   GstBufferList *out_list;
168   GstFlowReturn flowret;
169   gboolean is_rtcp;
170 } ProcessBufferItData;
171
172 /* the capabilities of the inputs and outputs.
173  *
174  * describe the real formats here.
175  */
176 static GstStaticPadTemplate rtp_sink_template =
177 GST_STATIC_PAD_TEMPLATE ("rtp_sink_%u",
178     GST_PAD_SINK,
179     GST_PAD_REQUEST,
180     GST_STATIC_CAPS ("application/x-rtp")
181     );
182
183 static GstStaticPadTemplate rtp_src_template =
184 GST_STATIC_PAD_TEMPLATE ("rtp_src_%u",
185     GST_PAD_SRC,
186     GST_PAD_SOMETIMES,
187     GST_STATIC_CAPS ("application/x-srtp")
188     );
189
190 static GstStaticPadTemplate rtcp_sink_template =
191 GST_STATIC_PAD_TEMPLATE ("rtcp_sink_%u",
192     GST_PAD_SINK,
193     GST_PAD_REQUEST,
194     GST_STATIC_CAPS ("application/x-rtcp")
195     );
196
197 static GstStaticPadTemplate rtcp_src_template =
198 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
199     GST_PAD_SRC,
200     GST_PAD_SOMETIMES,
201     GST_STATIC_CAPS ("application/x-srtcp")
202     );
203
204 G_DEFINE_TYPE (GstSrtpEnc, gst_srtp_enc, GST_TYPE_ELEMENT);
205
206 static guint gst_srtp_enc_signals[LAST_SIGNAL] = { 0 };
207
208 static void gst_srtp_enc_dispose (GObject * object);
209
210 static void gst_srtp_enc_set_property (GObject * object, guint prop_id,
211     const GValue * value, GParamSpec * pspec);
212 static void gst_srtp_enc_get_property (GObject * object, guint prop_id,
213     GValue * value, GParamSpec * pspec);
214
215 static gboolean gst_srtp_enc_sink_query_rtp (GstPad * pad, GstObject * parent,
216     GstQuery * query);
217 static gboolean gst_srtp_enc_sink_query_rtcp (GstPad * pad, GstObject * parent,
218     GstQuery * query);
219
220 static GstIterator *gst_srtp_enc_iterate_internal_links_rtp (GstPad * pad,
221     GstObject * parent);
222 static GstIterator *gst_srtp_enc_iterate_internal_links_rtcp (GstPad * pad,
223     GstObject * parent);
224
225 static GstFlowReturn gst_srtp_enc_chain_rtp (GstPad * pad, GstObject * parent,
226     GstBuffer * buf);
227 static GstFlowReturn gst_srtp_enc_chain_rtcp (GstPad * pad, GstObject * parent,
228     GstBuffer * buf);
229 static GstFlowReturn gst_srtp_enc_chain_list_rtp (GstPad * pad,
230     GstObject * parent, GstBufferList * buf);
231 static GstFlowReturn gst_srtp_enc_chain_list_rtcp (GstPad * pad,
232     GstObject * parent, GstBufferList * buf);
233
234 static gboolean gst_srtp_enc_sink_event_rtp (GstPad * pad, GstObject * parent,
235     GstEvent * event);
236 static gboolean gst_srtp_enc_sink_event_rtcp (GstPad * pad, GstObject * parent,
237     GstEvent * event);
238
239 static GstStateChangeReturn gst_srtp_enc_change_state (GstElement * element,
240     GstStateChange transition);
241
242 static GstPad *gst_srtp_enc_request_new_pad (GstElement * element,
243     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
244
245 static void gst_srtp_enc_release_pad (GstElement * element, GstPad * pad);
246
247
248 /* initialize the srtpenc's class
249  */
250 static void
251 gst_srtp_enc_class_init (GstSrtpEncClass * klass)
252 {
253   GObjectClass *gobject_class;
254   GstElementClass *gstelement_class;
255
256   gobject_class = (GObjectClass *) klass;
257   gstelement_class = (GstElementClass *) klass;
258
259   gst_element_class_add_static_pad_template (gstelement_class,
260       &rtp_src_template);
261   gst_element_class_add_static_pad_template (gstelement_class,
262       &rtp_sink_template);
263   gst_element_class_add_static_pad_template (gstelement_class,
264       &rtcp_src_template);
265   gst_element_class_add_static_pad_template (gstelement_class,
266       &rtcp_sink_template);
267
268   gst_element_class_set_static_metadata (gstelement_class, "SRTP encoder",
269       "Filter/Network/SRTP",
270       "A SRTP and SRTCP encoder",
271       "Gabriel Millaire <millaire.gabriel@collabora.com>");
272
273
274   /* Install callbacks */
275   gobject_class->set_property = gst_srtp_enc_set_property;
276   gobject_class->get_property = gst_srtp_enc_get_property;
277   gobject_class->dispose = gst_srtp_enc_dispose;
278   gstelement_class->request_new_pad =
279       GST_DEBUG_FUNCPTR (gst_srtp_enc_request_new_pad);
280   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_srtp_enc_release_pad);
281   gstelement_class->change_state =
282       GST_DEBUG_FUNCPTR (gst_srtp_enc_change_state);
283
284   /* Install properties */
285   g_object_class_install_property (gobject_class, PROP_MKEY,
286       g_param_spec_boxed ("key", "Key", "Master key (minimum of "
287           G_STRINGIFY (MASTER_128_KEY_SIZE) " and maximum of "
288           G_STRINGIFY (MASTER_256_KEY_SIZE) " bytes)",
289           GST_TYPE_BUFFER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
290           GST_PARAM_MUTABLE_PLAYING));
291   g_object_class_install_property (gobject_class, PROP_RTP_CIPHER,
292       g_param_spec_enum ("rtp-cipher", "RTP Cipher", "RTP Cipher",
293           GST_TYPE_SRTP_CIPHER_TYPE, DEFAULT_RTP_CIPHER,
294           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295   g_object_class_install_property (gobject_class, PROP_RTP_AUTH,
296       g_param_spec_enum ("rtp-auth", "RTP Authentication",
297           "RTP Authentication", GST_TYPE_SRTP_AUTH_TYPE, DEFAULT_RTP_AUTH,
298           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299   g_object_class_install_property (gobject_class, PROP_RTCP_CIPHER,
300       g_param_spec_enum ("rtcp-cipher", "RTCP Cipher",
301           "RTCP Cipher", GST_TYPE_SRTP_CIPHER_TYPE, DEFAULT_RTCP_CIPHER,
302           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
303   g_object_class_install_property (gobject_class, PROP_RTCP_AUTH,
304       g_param_spec_enum ("rtcp-auth", "RTCP Authentication",
305           "RTCP Authentication", GST_TYPE_SRTP_AUTH_TYPE, DEFAULT_RTCP_AUTH,
306           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
307   g_object_class_install_property (gobject_class, PROP_RANDOM_KEY,
308       g_param_spec_boolean ("random-key", "Generate random key",
309           "Generate a random key if TRUE",
310           DEFAULT_RANDOM_KEY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
311   g_object_class_install_property (gobject_class, PROP_REPLAY_WINDOW_SIZE,
312       g_param_spec_uint ("replay-window-size", "Replay window size",
313           "Size of the replay protection window",
314           64, 0x8000, DEFAULT_REPLAY_WINDOW_SIZE,
315           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
316   g_object_class_install_property (gobject_class, PROP_ALLOW_REPEAT_TX,
317       g_param_spec_boolean ("allow-repeat-tx",
318           "Allow repeat packets transmission",
319           "Whether retransmissions of packets with the same sequence number are allowed"
320           "(Note that such repeated transmissions must have the same RTP payload, "
321           "or a severe security weakness is introduced!)",
322           DEFAULT_ALLOW_REPEAT_TX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
323   g_object_class_install_property (gobject_class, PROP_STATS,
324       g_param_spec_boxed ("stats", "Statistics", "Various statistics",
325           GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
326 #ifdef HAVE_SRTP2
327   g_object_class_install_property (gobject_class, PROP_MKI,
328       g_param_spec_boxed ("mki", "MKI",
329           "Master key Identifier (NULL means no MKI)", GST_TYPE_BUFFER,
330           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
331           GST_PARAM_MUTABLE_PLAYING));
332 #endif
333
334   /**
335    * GstSrtpEnc::soft-limit:
336    * @gstsrtpenc: the element on which the signal is emitted
337    *
338    * Signal emited when the stream with @ssrc has reached the soft
339    * limit of utilisation of it's master encryption key. User should
340    * provide a new key by setting the #GstSrtpEnc:key property.
341    */
342   gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT] =
343       g_signal_new ("soft-limit", G_TYPE_FROM_CLASS (klass),
344       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
345 }
346
347
348 /* initialize the new element
349  */
350 static void
351 gst_srtp_enc_init (GstSrtpEnc * filter)
352 {
353   filter->key_changed = TRUE;
354   filter->first_session = TRUE;
355   filter->key = DEFAULT_MASTER_KEY;
356   filter->rtp_cipher = DEFAULT_RTP_CIPHER;
357   filter->rtp_auth = DEFAULT_RTP_AUTH;
358   filter->rtcp_cipher = DEFAULT_RTCP_CIPHER;
359   filter->rtcp_auth = DEFAULT_RTCP_AUTH;
360   filter->replay_window_size = DEFAULT_REPLAY_WINDOW_SIZE;
361   filter->allow_repeat_tx = DEFAULT_ALLOW_REPEAT_TX;
362   filter->ssrcs_set = g_hash_table_new (g_direct_hash, g_direct_equal);
363 }
364
365 static guint
366 max_cipher_key_size (GstSrtpEnc * filter)
367 {
368   guint rtp_size, rtcp_size;
369
370   rtp_size = cipher_key_size (filter->rtp_cipher);
371   rtcp_size = cipher_key_size (filter->rtcp_cipher);
372
373   return (rtp_size > rtcp_size) ? rtp_size : rtcp_size;
374 }
375
376 /* Create stream
377  *
378  * Should be called with the filter locked
379  */
380 static srtp_err_status_t
381 gst_srtp_enc_create_session (GstSrtpEnc * filter)
382 {
383   srtp_err_status_t ret;
384   srtp_policy_t policy;
385   GstMapInfo map;
386   guchar tmp[1];
387 #ifdef HAVE_SRTP2
388   srtp_master_key_t mkey;
389   srtp_master_key_t *mkey_ptr = &mkey;
390   gboolean has_mki = FALSE;
391   GstMapInfo mki_map;
392 #endif
393
394   memset (&policy, 0, sizeof (srtp_policy_t));
395
396   if (HAS_CRYPTO (filter)) {
397     guint expected;
398     gsize keysize;
399
400     if (filter->key == NULL) {
401       GST_OBJECT_UNLOCK (filter);
402       GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS,
403           ("Cipher is not NULL, key must be set"),
404           ("Cipher is not NULL, key must be set"));
405       GST_OBJECT_LOCK (filter);
406       return srtp_err_status_fail;
407     }
408
409     expected = max_cipher_key_size (filter);
410     keysize = gst_buffer_get_size (filter->key);
411
412     if (expected != keysize) {
413       GST_OBJECT_UNLOCK (filter);
414       GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS,
415           ("Master key size is wrong"),
416           ("Expected master key of %d bytes, but received %" G_GSIZE_FORMAT
417               " bytes", expected, keysize));
418       GST_OBJECT_LOCK (filter);
419       return srtp_err_status_fail;
420     }
421   }
422
423   GST_DEBUG_OBJECT (filter, "Setting RTP/RTCP policy to %d / %d",
424       filter->rtp_cipher, filter->rtcp_cipher);
425   set_crypto_policy_cipher_auth (filter->rtp_cipher, filter->rtp_auth,
426       &policy.rtp);
427   set_crypto_policy_cipher_auth (filter->rtcp_cipher, filter->rtcp_auth,
428       &policy.rtcp);
429
430   if (HAS_CRYPTO (filter)) {
431     gst_buffer_map (filter->key, &map, GST_MAP_READ);
432     policy.key = (guchar *) map.data;
433   } else {
434     policy.key = tmp;
435   }
436
437 #ifdef HAVE_SRTP2
438   if (filter->mki) {
439     if (!gst_buffer_map (filter->mki, &mki_map, GST_MAP_READ)) {
440       GST_OBJECT_UNLOCK (filter);
441       GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS, ("Could not map MKI"),
442           (NULL));
443       GST_OBJECT_LOCK (filter);
444
445       ret = srtp_err_status_fail;
446       goto done;
447     }
448     has_mki = TRUE;
449
450     policy.num_master_keys = 1;
451     policy.keys = &mkey_ptr;
452     mkey.key = policy.key;
453     policy.key = NULL;
454
455     mkey.mki_id = (guchar *) mki_map.data;
456     mkey.mki_size = mki_map.size;
457   }
458 #endif
459
460   policy.ssrc.value = 0;
461   policy.ssrc.type = ssrc_any_outbound;
462   policy.next = NULL;
463
464   policy.window_size = filter->replay_window_size;
465   policy.allow_repeat_tx = filter->allow_repeat_tx;
466
467   /* If it is the first stream, create the session
468    * If not, add the stream to the session
469    */
470   ret = srtp_create (&filter->session, &policy);
471   filter->first_session = FALSE;
472
473 #ifdef HAVE_SRTP2
474 done:
475
476   if (has_mki)
477     gst_buffer_unmap (filter->mki, &mki_map);
478 #endif
479
480   if (HAS_CRYPTO (filter))
481     gst_buffer_unmap (filter->key, &map);
482
483
484   return ret;
485 }
486
487 /* Release ressources and set default values
488  */
489 static void
490 gst_srtp_enc_reset_no_lock (GstSrtpEnc * filter)
491 {
492   if (!filter->first_session) {
493     if (filter->session) {
494       srtp_dealloc (filter->session);
495       filter->session = NULL;
496     }
497
498     g_hash_table_remove_all (filter->ssrcs_set);
499   }
500
501   filter->first_session = TRUE;
502   filter->key_changed = FALSE;
503 }
504
505 static void
506 gst_srtp_enc_reset (GstSrtpEnc * filter)
507 {
508   GST_OBJECT_LOCK (filter);
509   gst_srtp_enc_reset_no_lock (filter);
510   GST_OBJECT_UNLOCK (filter);
511 }
512
513 /* Create sinkpad to receive RTP packets from encers
514  * and a srcpad for the RTP packets
515  */
516 static GstPad *
517 create_rtp_sink (GstSrtpEnc * filter, const gchar * name)
518 {
519   GstPad *sinkpad, *srcpad;
520   gchar *sinkpadname, *srcpadname;
521   guint nb = 0;
522
523   GST_DEBUG_OBJECT (filter, "creating RTP sink pad");
524   sinkpad = gst_pad_new_from_static_template (&rtp_sink_template, name);
525
526   sinkpadname = gst_pad_get_name (sinkpad);
527   sscanf (sinkpadname, "rtp_sink_%u", &nb);
528   srcpadname = g_strdup_printf ("rtp_src_%u", nb);
529
530   GST_DEBUG_OBJECT (filter, "creating RTP source pad");
531   srcpad = gst_pad_new_from_static_template (&rtp_src_template, srcpadname);
532   g_free (srcpadname);
533   g_free (sinkpadname);
534
535   gst_pad_set_element_private (sinkpad, srcpad);
536   gst_pad_set_element_private (srcpad, sinkpad);
537
538   gst_pad_set_query_function (sinkpad,
539       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_query_rtp));
540   gst_pad_set_iterate_internal_links_function (sinkpad,
541       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtp));
542   gst_pad_set_chain_function (sinkpad,
543       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_rtp));
544   gst_pad_set_chain_list_function (sinkpad,
545       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_list_rtp));
546   gst_pad_set_event_function (sinkpad,
547       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_event_rtp));
548   gst_pad_set_active (sinkpad, TRUE);
549   gst_element_add_pad (GST_ELEMENT_CAST (filter), sinkpad);
550
551   gst_pad_set_iterate_internal_links_function (srcpad,
552       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtp));
553   gst_pad_set_active (srcpad, TRUE);
554   gst_element_add_pad (GST_ELEMENT_CAST (filter), srcpad);
555
556   return sinkpad;
557 }
558
559 /* Create sinkpad to receive RTCP packets from encers
560  * and a srcpad for the RTCP packets
561  */
562 static GstPad *
563 create_rtcp_sink (GstSrtpEnc * filter, const gchar * name)
564 {
565   GstPad *srcpad, *sinkpad;
566   gchar *sinkpadname, *srcpadname;
567   guint nb = 0;
568
569   GST_DEBUG_OBJECT (filter, "creating RTCP sink pad");
570   sinkpad = gst_pad_new_from_static_template (&rtcp_sink_template, name);
571
572   sinkpadname = gst_pad_get_name (sinkpad);
573   sscanf (sinkpadname, "rtcp_sink_%u", &nb);
574   srcpadname = g_strdup_printf ("rtcp_src_%u", nb);
575
576   GST_DEBUG_OBJECT (filter, "creating RTCP source pad");
577   srcpad = gst_pad_new_from_static_template (&rtcp_src_template, srcpadname);
578   g_free (srcpadname);
579   g_free (sinkpadname);
580
581   gst_pad_set_element_private (sinkpad, srcpad);
582   gst_pad_set_element_private (srcpad, sinkpad);
583
584   gst_pad_set_query_function (sinkpad,
585       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_query_rtcp));
586   gst_pad_set_iterate_internal_links_function (sinkpad,
587       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtcp));
588   gst_pad_set_chain_function (sinkpad,
589       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_rtcp));
590   gst_pad_set_chain_list_function (sinkpad,
591       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_list_rtcp));
592   gst_pad_set_event_function (sinkpad,
593       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_event_rtcp));
594   gst_pad_set_active (sinkpad, TRUE);
595   gst_element_add_pad (GST_ELEMENT_CAST (filter), sinkpad);
596
597   gst_pad_set_iterate_internal_links_function (srcpad,
598       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtcp));
599   gst_pad_set_active (srcpad, TRUE);
600   gst_element_add_pad (GST_ELEMENT_CAST (filter), srcpad);
601
602   return sinkpad;
603 }
604
605 /* Handling new pad request
606  */
607 static GstPad *
608 gst_srtp_enc_request_new_pad (GstElement * element,
609     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
610 {
611   GstElementClass *klass;
612   GstSrtpEnc *filter;
613
614   filter = GST_SRTP_ENC (element);
615   klass = GST_ELEMENT_GET_CLASS (element);
616
617   GST_INFO_OBJECT (element, "New pad requested");
618
619   if (templ == gst_element_class_get_pad_template (klass, "rtp_sink_%u"))
620     return create_rtp_sink (filter, name);
621
622   if (templ == gst_element_class_get_pad_template (klass, "rtcp_sink_%u"))
623     return create_rtcp_sink (filter, name);
624
625   GST_ERROR_OBJECT (element, "Could not find specified template");
626   return NULL;
627 }
628
629 /* Dispose
630  */
631 static void
632 gst_srtp_enc_dispose (GObject * object)
633 {
634   GstSrtpEnc *filter = GST_SRTP_ENC (object);
635   GstIterator *it;
636   GValue val = { 0 };
637
638   GST_DEBUG_OBJECT (object, "Dispose...");
639
640   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (object));
641   while (gst_iterator_next (it, &val) == GST_ITERATOR_OK) {
642     gst_srtp_enc_release_pad (GST_ELEMENT_CAST (object),
643         g_value_get_object (&val));
644     g_value_unset (&val);
645     gst_iterator_resync (it);
646   }
647   gst_iterator_free (it);
648
649   gst_buffer_replace (&filter->key, NULL);
650   gst_buffer_replace (&filter->mki, NULL);
651
652   if (filter->ssrcs_set)
653     g_hash_table_unref (filter->ssrcs_set);
654   filter->ssrcs_set = NULL;
655
656   G_OBJECT_CLASS (gst_srtp_enc_parent_class)->dispose (object);
657 }
658
659 static GstStructure *
660 gst_srtp_enc_create_stats (GstSrtpEnc * filter)
661 {
662   GstStructure *s;
663   GValue va = G_VALUE_INIT;
664   GValue v = G_VALUE_INIT;
665
666   s = gst_structure_new_empty ("application/x-srtp-encoder-stats");
667
668   g_value_init (&va, GST_TYPE_ARRAY);
669   g_value_init (&v, GST_TYPE_STRUCTURE);
670
671   if (filter->session) {
672     GHashTableIter iter;
673     gpointer key;
674
675     g_hash_table_iter_init (&iter, filter->ssrcs_set);
676     while (g_hash_table_iter_next (&iter, &key, NULL)) {
677       GstStructure *ss;
678       guint32 ssrc = GPOINTER_TO_UINT (key);
679       srtp_err_status_t status;
680       guint32 roc;
681
682       status = srtp_get_stream_roc (filter->session, ssrc, &roc);
683       if (status != srtp_err_status_ok) {
684         continue;
685       }
686
687       ss = gst_structure_new ("application/x-srtp-stream",
688           "ssrc", G_TYPE_UINT, ssrc, "roc", G_TYPE_UINT, roc, NULL);
689
690       g_value_take_boxed (&v, ss);
691       gst_value_array_append_value (&va, &v);
692     }
693   }
694
695   gst_structure_take_value (s, "streams", &va);
696   g_value_unset (&v);
697
698   return s;
699 }
700
701 static void
702 gst_srtp_enc_set_property (GObject * object, guint prop_id,
703     const GValue * value, GParamSpec * pspec)
704 {
705   GstSrtpEnc *filter = GST_SRTP_ENC (object);
706
707   GST_OBJECT_LOCK (filter);
708
709   switch (prop_id) {
710     case PROP_MKEY:
711       gst_clear_buffer (&filter->key);
712       filter->key = g_value_dup_boxed (value);
713       filter->key_changed = TRUE;
714       GST_INFO_OBJECT (object, "Set property: key=[%p]", filter->key);
715       break;
716
717     case PROP_RTP_CIPHER:
718       filter->rtp_cipher = g_value_get_enum (value);
719       GST_INFO_OBJECT (object, "Set property: rtp cipher=%d",
720           filter->rtp_cipher);
721       break;
722     case PROP_RTP_AUTH:
723       filter->rtp_auth = g_value_get_enum (value);
724       GST_INFO_OBJECT (object, "Set property: rtp auth=%d", filter->rtp_auth);
725       break;
726
727     case PROP_RTCP_CIPHER:
728       filter->rtcp_cipher = g_value_get_enum (value);
729       GST_INFO_OBJECT (object, "Set property: rtcp cipher=%d",
730           filter->rtcp_cipher);
731       break;
732
733     case PROP_RTCP_AUTH:
734       filter->rtcp_auth = g_value_get_enum (value);
735       GST_INFO_OBJECT (object, "Set property: rtcp auth=%d", filter->rtcp_auth);
736       break;
737
738     case PROP_RANDOM_KEY:
739       filter->random_key = g_value_get_boolean (value);
740       break;
741
742     case PROP_REPLAY_WINDOW_SIZE:
743       filter->replay_window_size = g_value_get_uint (value);
744       break;
745
746     case PROP_ALLOW_REPEAT_TX:
747       filter->allow_repeat_tx = g_value_get_boolean (value);
748       break;
749 #ifdef HAVE_SRTP2
750     case PROP_MKI:
751       gst_clear_buffer (&filter->mki);
752       filter->mki = g_value_dup_boxed (value);
753       filter->key_changed = TRUE;
754       GST_INFO_OBJECT (object, "Set property: mki=[%p]", filter->mki);
755       break;
756 #endif
757     default:
758       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
759       break;
760   }
761
762   GST_OBJECT_UNLOCK (filter);
763 }
764
765 static void
766 gst_srtp_enc_get_property (GObject * object, guint prop_id,
767     GValue * value, GParamSpec * pspec)
768 {
769   GstSrtpEnc *filter = GST_SRTP_ENC (object);
770   GST_OBJECT_LOCK (filter);
771
772   switch (prop_id) {
773     case PROP_MKEY:
774       if (filter->key)
775         g_value_set_boxed (value, filter->key);
776       break;
777     case PROP_RTP_CIPHER:
778       g_value_set_enum (value, filter->rtp_cipher);
779       break;
780     case PROP_RTCP_CIPHER:
781       g_value_set_enum (value, filter->rtcp_cipher);
782       break;
783     case PROP_RTP_AUTH:
784       g_value_set_enum (value, filter->rtp_auth);
785       break;
786     case PROP_RTCP_AUTH:
787       g_value_set_enum (value, filter->rtcp_auth);
788       break;
789     case PROP_RANDOM_KEY:
790       g_value_set_boolean (value, filter->random_key);
791       break;
792     case PROP_REPLAY_WINDOW_SIZE:
793       g_value_set_uint (value, filter->replay_window_size);
794       break;
795     case PROP_ALLOW_REPEAT_TX:
796       g_value_set_boolean (value, filter->allow_repeat_tx);
797       break;
798     case PROP_STATS:
799       g_value_take_boxed (value, gst_srtp_enc_create_stats (filter));
800       break;
801 #ifdef HAVE_SRTP2
802     case PROP_MKI:
803       if (filter->mki)
804         g_value_set_boxed (value, filter->mki);
805       break;
806 #endif
807     default:
808       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
809       break;
810   }
811
812   GST_OBJECT_UNLOCK (filter);
813 }
814
815 /* Returns the source pad linked with the sink pad
816  */
817 static GstPad *
818 get_rtp_other_pad (GstPad * pad)
819 {
820   return GST_PAD (gst_pad_get_element_private (pad));
821 }
822
823 static void
824 gst_srtp_enc_add_ssrc (GstSrtpEnc * filter, guint ssrc)
825 {
826   gboolean is_added =
827       g_hash_table_add (filter->ssrcs_set, GUINT_TO_POINTER (ssrc));
828   if (is_added) {
829     GST_DEBUG_OBJECT (filter, "Added ssrc %u", ssrc);
830   }
831 }
832
833 /* Release a sink pad and it's linked source pad
834  */
835 static void
836 gst_srtp_enc_release_pad (GstElement * element, GstPad * sinkpad)
837 {
838   GstPad *srcpad;
839
840   GST_INFO_OBJECT (element, "Releasing pad %s:%s",
841       GST_DEBUG_PAD_NAME (sinkpad));
842
843   srcpad = GST_PAD (gst_pad_get_element_private (sinkpad));
844   gst_pad_set_element_private (sinkpad, NULL);
845   gst_pad_set_element_private (srcpad, NULL);
846
847   /* deactivate from source to sink */
848   gst_pad_set_active (srcpad, FALSE);
849   gst_pad_set_active (sinkpad, FALSE);
850
851   /* remove pads */
852   gst_element_remove_pad (element, srcpad);
853   gst_element_remove_pad (element, sinkpad);
854 }
855
856 /* Common setcaps function
857  * Handles the link with other elements
858  */
859 static gboolean
860 gst_srtp_enc_sink_setcaps (GstPad * pad, GstSrtpEnc * filter,
861     GstCaps * caps, gboolean is_rtcp)
862 {
863   GstPad *otherpad = NULL;
864   GstStructure *ps = NULL;
865   gboolean ret = FALSE;
866
867   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
868
869   caps = gst_caps_copy (caps);
870
871   ps = gst_caps_get_structure (caps, 0);
872
873   GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
874
875   if (is_rtcp)
876     gst_structure_set_name (ps, "application/x-srtcp");
877   else
878     gst_structure_set_name (ps, "application/x-srtp");
879
880   GST_OBJECT_LOCK (filter);
881
882   if (gst_structure_has_field_typed (ps, "ssrc", G_TYPE_UINT)) {
883     guint ssrc;
884     gst_structure_get_uint (ps, "ssrc", &ssrc);
885     gst_srtp_enc_add_ssrc (filter, ssrc);
886   }
887
888   if (HAS_CRYPTO (filter))
889     gst_structure_set (ps, "srtp-key", GST_TYPE_BUFFER, filter->key, NULL);
890
891 #ifdef HAVE_SRTP2
892   if (filter->mki)
893     gst_structure_set (ps, "mki", GST_TYPE_BUFFER, filter->mki, NULL);
894 #endif
895
896   /* Add srtp-specific params to source caps */
897   gst_structure_set (ps,
898       "srtp-cipher", G_TYPE_STRING,
899       enum_nick_from_value (GST_TYPE_SRTP_CIPHER_TYPE, filter->rtp_cipher),
900       "srtp-auth", G_TYPE_STRING,
901       enum_nick_from_value (GST_TYPE_SRTP_AUTH_TYPE, filter->rtp_auth),
902       "srtcp-cipher", G_TYPE_STRING,
903       enum_nick_from_value (GST_TYPE_SRTP_CIPHER_TYPE, filter->rtcp_cipher),
904       "srtcp-auth", G_TYPE_STRING,
905       enum_nick_from_value (GST_TYPE_SRTP_AUTH_TYPE, filter->rtcp_auth), NULL);
906
907   GST_OBJECT_UNLOCK (filter);
908
909   GST_DEBUG_OBJECT (pad, "Source caps: %" GST_PTR_FORMAT, caps);
910
911   /* Set caps on source pad */
912   otherpad = get_rtp_other_pad (pad);
913
914   ret = gst_pad_set_caps (otherpad, caps);
915
916   gst_caps_unref (caps);
917
918   return ret;
919 }
920
921 static gboolean
922 gst_srtp_enc_sink_query (GstPad * pad, GstObject * parent, GstQuery * query,
923     gboolean is_rtcp)
924 {
925   switch (GST_QUERY_TYPE (query)) {
926     case GST_QUERY_CAPS:
927     {
928       GstCaps *filter = NULL;
929       GstCaps *other_filter = NULL;
930       GstPad *otherpad;
931       GstCaps *other_caps;
932       GstCaps *ret;
933       GstCaps *template_caps;
934       int i;
935
936       otherpad = get_rtp_other_pad (pad);
937
938       gst_query_parse_caps (query, &filter);
939       if (filter) {
940         other_filter = gst_caps_copy (filter);
941
942         for (i = 0; i < gst_caps_get_size (other_filter); i++) {
943           GstStructure *ps = gst_caps_get_structure (other_filter, i);
944           if (is_rtcp)
945             gst_structure_set_name (ps, "application/x-srtcp");
946           else
947             gst_structure_set_name (ps, "application/x-srtp");
948         }
949       }
950
951       other_caps = gst_pad_peer_query_caps (otherpad, other_filter);
952
953       if (other_filter)
954         gst_caps_unref (other_filter);
955
956       if (!other_caps)
957         goto return_template;
958
959       template_caps = gst_pad_get_pad_template_caps (otherpad);
960       ret = gst_caps_intersect_full (other_caps, template_caps,
961           GST_CAPS_INTERSECT_FIRST);
962       gst_caps_unref (other_caps);
963       gst_caps_unref (template_caps);
964
965       ret = gst_caps_make_writable (ret);
966
967       for (i = 0; i < gst_caps_get_size (ret); i++) {
968         GstStructure *ps = gst_caps_get_structure (ret, i);
969         if (is_rtcp)
970           gst_structure_set_name (ps, "application/x-rtcp");
971         else
972           gst_structure_set_name (ps, "application/x-rtp");
973         gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher", "srtp-auth",
974             "srtcp-cipher", "srtcp-auth", "mki", NULL);
975       }
976
977       gst_query_set_caps_result (query, ret);
978       gst_caps_unref (ret);
979       return TRUE;
980     return_template:
981
982       ret = gst_pad_get_pad_template_caps (pad);
983       gst_query_set_caps_result (query, ret);
984       gst_caps_unref (ret);
985
986       return TRUE;
987     }
988     default:
989       return gst_pad_query_default (pad, parent, query);
990   }
991 }
992
993 static gboolean
994 gst_srtp_enc_sink_query_rtp (GstPad * pad, GstObject * parent, GstQuery * query)
995 {
996   return gst_srtp_enc_sink_query (pad, parent, query, FALSE);
997 }
998
999 static gboolean
1000 gst_srtp_enc_sink_query_rtcp (GstPad * pad, GstObject * parent,
1001     GstQuery * query)
1002 {
1003   return gst_srtp_enc_sink_query (pad, parent, query, TRUE);
1004 }
1005
1006 static GstIterator *
1007 gst_srtp_enc_iterate_internal_links (GstPad * pad, GstObject * parent,
1008     gboolean is_rtcp)
1009 {
1010   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1011   GstPad *otherpad = NULL;
1012   GstIterator *it = NULL;
1013
1014   otherpad = get_rtp_other_pad (pad);
1015
1016   if (otherpad) {
1017     GValue val = { 0 };
1018
1019     g_value_init (&val, GST_TYPE_PAD);
1020     g_value_set_object (&val, otherpad);
1021     it = gst_iterator_new_single (GST_TYPE_PAD, &val);
1022     g_value_unset (&val);
1023   } else {
1024     GST_ELEMENT_ERROR (GST_ELEMENT_CAST (filter), CORE, PAD, (NULL),
1025         ("Unable to get linked pad"));
1026   }
1027
1028   return it;
1029 }
1030
1031 static GstIterator *
1032 gst_srtp_enc_iterate_internal_links_rtp (GstPad * pad, GstObject * parent)
1033 {
1034   return gst_srtp_enc_iterate_internal_links (pad, parent, FALSE);
1035 }
1036
1037 static GstIterator *
1038 gst_srtp_enc_iterate_internal_links_rtcp (GstPad * pad, GstObject * parent)
1039 {
1040   return gst_srtp_enc_iterate_internal_links (pad, parent, TRUE);
1041 }
1042
1043
1044 static void
1045 gst_srtp_enc_replace_random_key (GstSrtpEnc * filter)
1046 {
1047   guint i;
1048   guint key_size;
1049   GstMapInfo map;
1050
1051   GST_DEBUG_OBJECT (filter, "Generating random key");
1052
1053   if (filter->key)
1054     gst_buffer_unref (filter->key);
1055
1056   key_size = max_cipher_key_size (filter);
1057
1058   filter->key = gst_buffer_new_allocate (NULL, key_size, NULL);
1059
1060   gst_buffer_map (filter->key, &map, GST_MAP_WRITE);
1061   for (i = 0; i < map.size; i += 4)
1062     GST_WRITE_UINT32_BE (map.data + i, g_random_int ());
1063   gst_buffer_unmap (filter->key, &map);
1064
1065   filter->key_changed = TRUE;
1066 }
1067
1068 static GstFlowReturn
1069 gst_srtp_enc_check_set_caps (GstSrtpEnc * filter, GstPad * pad,
1070     gboolean is_rtcp)
1071 {
1072   gboolean do_setcaps = FALSE;
1073
1074   GST_OBJECT_LOCK (filter);
1075
1076   if (filter->key_changed) {
1077     gst_srtp_enc_reset_no_lock (filter);
1078     do_setcaps = TRUE;
1079   }
1080
1081   if (filter->first_session) {
1082     srtp_err_status_t status = gst_srtp_enc_create_session (filter);
1083
1084     if (status != srtp_err_status_ok) {
1085       GST_OBJECT_UNLOCK (filter);
1086       GST_ELEMENT_ERROR (filter, LIBRARY, INIT,
1087           ("Could not initialize SRTP encoder"),
1088           ("Failed to add stream to SRTP encoder (err: %d)", status));
1089       return GST_FLOW_ERROR;
1090     }
1091   }
1092
1093   GST_OBJECT_UNLOCK (filter);
1094
1095   /* Update source caps if asked */
1096   if (do_setcaps) {
1097     GstCaps *caps;
1098
1099     caps = gst_pad_get_current_caps (pad);
1100     if (!gst_srtp_enc_sink_setcaps (pad, filter, caps, is_rtcp)) {
1101       gst_caps_unref (caps);
1102       return GST_FLOW_NOT_NEGOTIATED;
1103     }
1104     gst_caps_unref (caps);
1105   }
1106
1107   return GST_FLOW_OK;
1108 }
1109
1110 static void
1111 gst_srtp_enc_ensure_ssrc (GstSrtpEnc * filter, GstBuffer * buf)
1112 {
1113   GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
1114   if (gst_rtp_buffer_map (buf,
1115           GST_MAP_READ | GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING, &rtpbuf)) {
1116     guint32 ssrc = gst_rtp_buffer_get_ssrc (&rtpbuf);
1117     gst_srtp_enc_add_ssrc (filter, ssrc);
1118     gst_rtp_buffer_unmap (&rtpbuf);
1119   }
1120 }
1121
1122 static GstFlowReturn
1123 gst_srtp_enc_process_buffer (GstSrtpEnc * filter, GstPad * pad,
1124     GstBuffer * buf, gboolean is_rtcp, GstBuffer ** outbuf_ptr)
1125 {
1126   GstFlowReturn ret = GST_FLOW_OK;
1127   gint size_max, size;
1128   GstBuffer *bufout = NULL;
1129   GstMapInfo mapout;
1130   srtp_err_status_t err;
1131
1132   /* Create a bigger buffer to add protection */
1133   size = gst_buffer_get_size (buf);
1134   size_max = size + SRTP_MAX_TRAILER_LEN + 10;
1135   bufout = gst_buffer_new_allocate (NULL, size_max, NULL);
1136
1137   gst_buffer_map (bufout, &mapout, GST_MAP_READWRITE);
1138
1139   gst_buffer_extract (buf, 0, mapout.data, size);
1140
1141   GST_OBJECT_LOCK (filter);
1142
1143   gst_srtp_init_event_reporter ();
1144
1145   if (filter->session == NULL) {
1146     /* The rtcp session disappeared (element shutting down) */
1147     GST_OBJECT_UNLOCK (filter);
1148     ret = GST_FLOW_FLUSHING;
1149     goto fail;
1150   }
1151
1152   gst_srtp_enc_ensure_ssrc (filter, buf);
1153
1154 #ifdef HAVE_SRTP2
1155   if (is_rtcp)
1156     err = srtp_protect_rtcp_mki (filter->session, mapout.data, &size,
1157         (filter->mki != NULL), 0);
1158   else
1159     err = srtp_protect_mki (filter->session, mapout.data, &size,
1160         (filter->mki != NULL), 0);
1161 #else
1162   if (is_rtcp)
1163     err = srtp_protect_rtcp (filter->session, mapout.data, &size);
1164   else
1165     err = srtp_protect (filter->session, mapout.data, &size);
1166 #endif
1167
1168   GST_OBJECT_UNLOCK (filter);
1169
1170   gst_buffer_unmap (bufout, &mapout);
1171
1172   if (err == srtp_err_status_ok) {
1173     /* Buffer protected */
1174     gst_buffer_set_size (bufout, size);
1175     gst_buffer_copy_into (bufout, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1176
1177     GST_LOG_OBJECT (pad, "Encoding %s buffer of size %d",
1178         is_rtcp ? "RTCP" : "RTP", size);
1179
1180   } else if (err == srtp_err_status_key_expired) {
1181
1182     GST_ELEMENT_ERROR (GST_ELEMENT_CAST (filter), STREAM, ENCODE,
1183         ("Key usage limit has been reached"),
1184         ("Unable to protect buffer (hard key usage limit reached)"));
1185     ret = GST_FLOW_ERROR;
1186     goto fail;
1187
1188   } else {
1189     /* srtp_protect failed */
1190     GST_ELEMENT_ERROR (filter, LIBRARY, FAILED, (NULL),
1191         ("Unable to protect buffer (protect failed) code %d", err));
1192     ret = GST_FLOW_ERROR;
1193     goto fail;
1194   }
1195
1196   *outbuf_ptr = bufout;
1197   return ret;
1198
1199 fail:
1200   gst_buffer_unref (bufout);
1201   return ret;
1202 }
1203
1204 static GstFlowReturn
1205 gst_srtp_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf,
1206     gboolean is_rtcp)
1207 {
1208   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1209   GstFlowReturn ret = GST_FLOW_OK;
1210   GstPad *otherpad;
1211   GstBuffer *bufout = NULL;
1212
1213   if ((ret = gst_srtp_enc_check_set_caps (filter, pad, is_rtcp)) != GST_FLOW_OK) {
1214     goto out;
1215   }
1216
1217   GST_OBJECT_LOCK (filter);
1218
1219   if (!HAS_CRYPTO (filter)) {
1220     GST_OBJECT_UNLOCK (filter);
1221     otherpad = get_rtp_other_pad (pad);
1222     return gst_pad_push (otherpad, buf);
1223   }
1224
1225   GST_OBJECT_UNLOCK (filter);
1226
1227   ret = gst_srtp_enc_process_buffer (filter, pad, buf, is_rtcp, &bufout);
1228   if (ret != GST_FLOW_OK)
1229     goto out;
1230
1231   /* Push buffer to source pad */
1232   otherpad = get_rtp_other_pad (pad);
1233   ret = gst_pad_push (otherpad, bufout);
1234   bufout = NULL;
1235
1236   if (ret != GST_FLOW_OK)
1237     goto out;
1238
1239   GST_OBJECT_LOCK (filter);
1240
1241   if (gst_srtp_get_soft_limit_reached ()) {
1242     GST_OBJECT_UNLOCK (filter);
1243     g_signal_emit (filter, gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT], 0);
1244     GST_OBJECT_LOCK (filter);
1245     if (filter->random_key && !filter->key_changed)
1246       gst_srtp_enc_replace_random_key (filter);
1247   }
1248
1249   GST_OBJECT_UNLOCK (filter);
1250
1251 out:
1252   gst_buffer_unref (buf);
1253   return ret;
1254 }
1255
1256 static gboolean
1257 process_buffer_it (GstBuffer ** buffer, guint index, gpointer user_data)
1258 {
1259   ProcessBufferItData *data = user_data;
1260   GstBuffer *bufout;
1261   GstFlowReturn ret;
1262
1263   ret = gst_srtp_enc_process_buffer (data->filter, data->pad, *buffer,
1264       data->is_rtcp, &bufout);
1265   if (ret != GST_FLOW_OK) {
1266     data->flowret = ret;
1267     return FALSE;
1268   }
1269
1270   gst_buffer_list_add (data->out_list, bufout);
1271
1272   return TRUE;
1273 }
1274
1275 static GstFlowReturn
1276 gst_srtp_enc_chain_list (GstPad * pad, GstObject * parent,
1277     GstBufferList * buf_list, gboolean is_rtcp)
1278 {
1279   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1280   GstFlowReturn ret = GST_FLOW_OK;
1281   GstPad *otherpad;
1282   GstBufferList *out_list = NULL;
1283   ProcessBufferItData process_data;
1284
1285   GST_LOG_OBJECT (pad, "Buffer chain with list of %d",
1286       gst_buffer_list_length (buf_list));
1287
1288   if (!gst_buffer_list_length (buf_list))
1289     goto out;
1290
1291   if ((ret = gst_srtp_enc_check_set_caps (filter, pad, is_rtcp)) != GST_FLOW_OK)
1292     goto out;
1293
1294   GST_OBJECT_LOCK (filter);
1295
1296   if (!HAS_CRYPTO (filter)) {
1297     GST_OBJECT_UNLOCK (filter);
1298     otherpad = get_rtp_other_pad (pad);
1299     return gst_pad_push_list (otherpad, buf_list);
1300   }
1301
1302   GST_OBJECT_UNLOCK (filter);
1303
1304   out_list = gst_buffer_list_new ();
1305
1306   process_data.filter = filter;
1307   process_data.pad = pad;
1308   process_data.is_rtcp = is_rtcp;
1309   process_data.out_list = out_list;
1310   process_data.flowret = GST_FLOW_OK;
1311
1312   if (!gst_buffer_list_foreach (buf_list, process_buffer_it, &process_data)) {
1313     ret = process_data.flowret;
1314     goto out;
1315   }
1316
1317   if (!gst_buffer_list_length (out_list)) {
1318     gst_buffer_list_unref (out_list);
1319     ret = GST_FLOW_OK;
1320     goto out;
1321   }
1322
1323   /* Push buffer to source pad */
1324   otherpad = get_rtp_other_pad (pad);
1325   GST_LOG_OBJECT (pad, "Pushing buffer chain of %d",
1326       gst_buffer_list_length (buf_list));
1327   ret = gst_pad_push_list (otherpad, out_list);
1328
1329   if (ret != GST_FLOW_OK) {
1330     goto out;
1331   }
1332
1333   GST_OBJECT_LOCK (filter);
1334
1335   if (gst_srtp_get_soft_limit_reached ()) {
1336     GST_OBJECT_UNLOCK (filter);
1337     g_signal_emit (filter, gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT], 0);
1338     GST_OBJECT_LOCK (filter);
1339     if (filter->random_key && !filter->key_changed)
1340       gst_srtp_enc_replace_random_key (filter);
1341   }
1342
1343   GST_OBJECT_UNLOCK (filter);
1344
1345 out:
1346
1347   gst_buffer_list_unref (buf_list);
1348
1349   return ret;
1350 }
1351
1352 static GstFlowReturn
1353 gst_srtp_enc_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buf)
1354 {
1355   return gst_srtp_enc_chain (pad, parent, buf, FALSE);
1356 }
1357
1358 static GstFlowReturn
1359 gst_srtp_enc_chain_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buf)
1360 {
1361   return gst_srtp_enc_chain (pad, parent, buf, TRUE);
1362 }
1363
1364 static GstFlowReturn
1365 gst_srtp_enc_chain_list_rtp (GstPad * pad, GstObject * parent,
1366     GstBufferList * buf_list)
1367 {
1368   return gst_srtp_enc_chain_list (pad, parent, buf_list, FALSE);
1369 }
1370
1371 static GstFlowReturn
1372 gst_srtp_enc_chain_list_rtcp (GstPad * pad, GstObject * parent,
1373     GstBufferList * buf_list)
1374 {
1375   return gst_srtp_enc_chain_list (pad, parent, buf_list, TRUE);
1376 }
1377
1378
1379 /* Change state
1380  */
1381 static GstStateChangeReturn
1382 gst_srtp_enc_change_state (GstElement * element, GstStateChange transition)
1383 {
1384   GstStateChangeReturn res;
1385   GstSrtpEnc *filter;
1386
1387   filter = GST_SRTP_ENC (element);
1388
1389   switch (transition) {
1390     case GST_STATE_CHANGE_NULL_TO_READY:
1391       if (filter->rtp_cipher != GST_SRTP_CIPHER_NULL ||
1392           filter->rtcp_cipher != GST_SRTP_CIPHER_NULL ||
1393           filter->rtp_auth != GST_SRTP_AUTH_NULL ||
1394           filter->rtcp_auth != GST_SRTP_AUTH_NULL) {
1395         if (!filter->key) {
1396           if (filter->random_key) {
1397             gst_srtp_enc_replace_random_key (filter);
1398           } else {
1399             GST_ERROR_OBJECT (element, "Need a key to get to READY");
1400             return GST_STATE_CHANGE_FAILURE;
1401           }
1402         }
1403       }
1404
1405       /* RFC 3711 says in "3. SRTP Framework" that SRTCP message authentication
1406        * is MANDATORY. In case of GCM let the pipeline handle any errors.
1407        */
1408       if (filter->rtcp_cipher != GST_SRTP_CIPHER_AES_128_GCM
1409           && filter->rtcp_cipher != GST_SRTP_CIPHER_AES_256_GCM
1410           && filter->rtcp_cipher != GST_SRTP_CIPHER_NULL
1411           && filter->rtcp_auth == GST_SRTP_AUTH_NULL) {
1412         GST_ERROR_OBJECT (filter,
1413             "RTCP authentication can't be NULL if encryption is not NULL.");
1414         return GST_STATE_CHANGE_FAILURE;
1415       }
1416       GST_OBJECT_LOCK (filter);
1417       if (!filter->first_session)
1418         gst_srtp_enc_reset_no_lock (filter);
1419       GST_OBJECT_UNLOCK (filter);
1420       break;
1421     case GST_STATE_CHANGE_READY_TO_PAUSED:
1422       break;
1423     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1424       break;
1425     default:
1426       break;
1427   }
1428
1429   res = GST_ELEMENT_CLASS (gst_srtp_enc_parent_class)->change_state (element,
1430       transition);
1431
1432   switch (transition) {
1433     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1434       break;
1435     case GST_STATE_CHANGE_PAUSED_TO_READY:
1436       gst_srtp_enc_reset (filter);
1437       break;
1438     case GST_STATE_CHANGE_READY_TO_NULL:
1439       break;
1440     default:
1441       break;
1442   }
1443
1444   return res;
1445 }
1446
1447 static gboolean
1448 gst_srtp_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event,
1449     gboolean is_rtcp)
1450 {
1451   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1452   gboolean ret;
1453   GstPad *otherpad;
1454
1455   otherpad = get_rtp_other_pad (pad);
1456
1457   switch (GST_EVENT_TYPE (event)) {
1458     case GST_EVENT_FLUSH_STOP:
1459       GST_DEBUG_OBJECT (pad, "Encing event Flush stop (%d)",
1460           GST_EVENT_TYPE (event));
1461       gst_srtp_enc_reset (filter);
1462       ret = gst_pad_push_event (otherpad, event);
1463       break;
1464     case GST_EVENT_CAPS:
1465     {
1466       GstCaps *caps;
1467
1468       gst_event_parse_caps (event, &caps);
1469       ret = gst_srtp_enc_sink_setcaps (pad, filter, caps, is_rtcp);
1470       gst_event_unref (event);
1471       break;
1472     }
1473     default:
1474       GST_DEBUG_OBJECT (pad, "Encing event default (%d)",
1475           GST_EVENT_TYPE (event));
1476       ret = gst_pad_event_default (pad, parent, event);
1477       break;
1478   }
1479
1480   return ret;
1481 }
1482
1483 static gboolean
1484 gst_srtp_enc_sink_event_rtp (GstPad * pad, GstObject * parent, GstEvent * event)
1485 {
1486   return gst_srtp_enc_sink_event (pad, parent, event, FALSE);
1487 }
1488
1489 static gboolean
1490 gst_srtp_enc_sink_event_rtcp (GstPad * pad, GstObject * parent,
1491     GstEvent * event)
1492 {
1493   return gst_srtp_enc_sink_event (pad, parent, event, TRUE);
1494 }
1495
1496 /* entry point to initialize the plug-in
1497  * initialize the plug-in itself
1498  * register the element factories and other features
1499  */
1500 gboolean
1501 gst_srtp_enc_plugin_init (GstPlugin * srtpenc)
1502 {
1503   GST_DEBUG_CATEGORY_INIT (gst_srtp_enc_debug, "srtpenc", 0, "SRTP Enc");
1504
1505   return gst_element_register (srtpenc, "srtpenc", GST_RANK_NONE,
1506       GST_TYPE_SRTP_ENC);
1507 }