* subsequent packet is dropped, until a new key is set and the stream
* has been updated.
*
+ * If a stream is to be shared between multiple clients the SRTP
+ * rollover counter for a given SSRC must be set in the caps "roc" field
+ * when the request-key signal is emitted by the decoder. The rollover
+ * counters should have been transmitted by a signaling protocol by some
+ * other means. If no rollover counter is provided by the user, 0 is
+ * used by default.
+ *
* <refsect2>
* <title>Example pipelines</title>
* |[
#include "gstsrtpdec.h"
+#include <srtp/srtp_priv.h>
+
GST_DEBUG_CATEGORY_STATIC (gst_srtp_dec_debug);
#define GST_CAT_DEFAULT gst_srtp_dec_debug
{
guint32 ssrc;
+ guint32 roc;
GstBuffer *key;
GstSrtpCipherType rtp_cipher;
GstSrtpAuthType rtp_auth;
stream->rtp_auth != GST_SRTP_AUTH_NULL || \
stream->rtcp_auth != GST_SRTP_AUTH_NULL)
+
/* initialize the srtpdec's class */
static void
gst_srtp_dec_class_init (GstSrtpDecClass * klass)
"A SRTP and SRTCP decoder",
"Gabriel Millaire <millaire.gabriel@collabora.com>");
+ /* Install callbacks */
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_srtp_dec_change_state);
+
klass->clear_streams = GST_DEBUG_FUNCPTR (gst_srtp_dec_clear_streams);
klass->remove_stream = GST_DEBUG_FUNCPTR (gst_srtp_dec_remove_stream);
+ /* Install signals */
/**
* GstSrtpDec::request-key:
* @gstsrtpdec: the element on which the signal is emitted
gst_element_add_pad (GST_ELEMENT (filter), filter->rtcp_srcpad);
filter->first_session = TRUE;
+ filter->roc_changed = FALSE;
}
static void
if (!rtp_cipher || !rtp_auth || !rtcp_cipher || !rtcp_auth)
goto error;
+ gst_structure_get_uint (s, "roc", &stream->roc);
stream->rtp_cipher = enum_value_from_nick (GST_TYPE_SRTP_CIPHER_TYPE,
rtp_cipher);
gst_buffer_unmap (stream->key, &map);
if (ret == err_status_ok) {
+ srtp_stream_t srtp_stream;
+
+ srtp_stream = srtp_get_stream (filter->session, htonl (ssrc));
+ if (srtp_stream) {
+ /* Here, we just set the ROC, but we also need to set the initial
+ * RTP sequence number later, otherwise libsrtp will not be able
+ * to get the right packet index. */
+ rdbx_set_roc (&srtp_stream->rtp_rdbx, stream->roc);
+ filter->roc_changed = TRUE;
+ }
+
filter->first_session = FALSE;
g_hash_table_insert (filter->streams, GUINT_TO_POINTER (stream->ssrc),
stream);
if (caps) {
stream = update_session_stream_from_caps (filter, ssrc, caps);
if (stream)
- GST_DEBUG_OBJECT (filter, "New stream set with SSRC %d", ssrc);
+ GST_DEBUG_OBJECT (filter, "New stream set with SSRC %u", ssrc);
else
- GST_WARNING_OBJECT (filter, "Could not set stream with SSRC %d", ssrc);
+ GST_WARNING_OBJECT (filter, "Could not set stream with SSRC %u", ssrc);
gst_caps_unref (caps);
}
if (is_rtcp)
err = srtp_unprotect_rtcp (filter->session, map.data, &size);
- else
+ else {
+ /* If ROC has changed, we know we need to set the initial RTP
+ * sequence number too. */
+ if (filter->roc_changed) {
+ srtp_stream_t stream;
+
+ stream = srtp_get_stream (filter->session, htonl (ssrc));
+
+ if (stream) {
+ guint16 seqnum = 0;
+ GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuf);
+ seqnum = gst_rtp_buffer_get_seq (&rtpbuf);
+ gst_rtp_buffer_unmap (&rtpbuf);
+
+ /* We finally add the RTP sequence number to the current
+ * rollover counter. */
+ stream->rtp_rdbx.index &= ~0xFFFF;
+ stream->rtp_rdbx.index |= seqnum;
+ }
+
+ filter->roc_changed = FALSE;
+ }
err = srtp_unprotect (filter->session, map.data, &size);
+ }
gst_buffer_unmap (buf, &map);
* subsequent packet is dropped, until a new key is set and the stream
* has been updated.
*
+ * If a stream is to be shared between multiple clients it is also
+ * possible to request the internal SRTP rollover counter for a given
+ * SSRC. The rollover counter should be then transmitted and used by the
+ * clients to authenticate and decrypt the packets. Failing to do that
+ * the clients will start with a rollover counter of 0 which will
+ * probably be incorrect if the stream has been transmitted for a
+ * while to other clients.
*/
#ifdef HAVE_CONFIG_H
#include "gstsrtp.h"
#include "gstsrtp-enumtypes.h"
+#include <srtp/srtp_priv.h>
+
GST_DEBUG_CATEGORY_STATIC (gst_srtp_enc_debug);
#define GST_CAT_DEFAULT gst_srtp_enc_debug
enum
{
SIGNAL_SOFT_LIMIT,
+ SIGNAL_GET_ROLLOVER_COUNTER,
LAST_SIGNAL
};
static void gst_srtp_enc_release_pad (GstElement * element, GstPad * pad);
+
+static guint32
+gst_srtp_enc_get_rollover_counter (GstSrtpEnc * filter, guint32 ssrc)
+{
+ guint32 roc = 0;
+ srtp_stream_t stream;
+
+ GST_OBJECT_LOCK (filter);
+
+ GST_DEBUG_OBJECT (filter, "retrieving SRTP Rollover Counter, ssrc: %u", ssrc);
+
+ if (filter->session) {
+ stream = srtp_get_stream (filter->session, htonl (ssrc));
+ if (stream)
+ roc = stream->rtp_rdbx.index >> 16;
+ }
+
+ GST_OBJECT_UNLOCK (filter);
+
+ return roc;
+}
+
/* initialize the srtpenc's class
*/
static void
gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT] =
g_signal_new ("soft-limit", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+ /**
+ * GstSrtpEnc::get-rollover-counter:
+ * @gstsrtpenc: the element on which the signal is emitted
+ * @ssrc: The unique SSRC of the stream
+ *
+ * Request the SRTP rollover counter for the stream with @ssrc.
+ */
+ gst_srtp_enc_signals[SIGNAL_GET_ROLLOVER_COUNTER] =
+ g_signal_new ("get-rollover-counter", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstSrtpEncClass,
+ get_rollover_counter), NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_UINT, 1, G_TYPE_UINT);
+
+ klass->get_rollover_counter =
+ GST_DEBUG_FUNCPTR (gst_srtp_enc_get_rollover_counter);
}