mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
sdp: add helper fuctions from/to sdp from/to caps
<gstsdpmessage.h> GstCaps* gst_sdp_media_get_caps_from_media (const GstSDPMedia *media, gint pt); GstSDPResult gst_sdp_media_set_media_from_caps (const GstCaps* caps, GstSDPMedia *media); gchar * gst_sdp_make_keymgmt (const gchar *uri, const gchar *base64); GstSDPResult gst_sdp_message_attributes_to_caps (GstSDPMessage *msg, GstCaps *caps); GstSDPResult gst_sdp_media_attributes_to_caps (GstSDPMedia *media, GstCaps *caps); <gstmikey.h> GstMIKEYMessage * gst_mikey_message_new_from_caps (GstCaps *caps); gchar * gst_mikey_message_base64_encode (GstMIKEYMessage* msg); https://bugzilla.gnome.org/show_bug.cgi?id=745880
This commit is contained in:
parent
eb09889176
commit
682b523652
8 changed files with 995 additions and 2 deletions
|
@ -1793,6 +1793,11 @@ gst_sdp_media_insert_attribute
|
||||||
gst_sdp_media_replace_attribute
|
gst_sdp_media_replace_attribute
|
||||||
gst_sdp_media_remove_attribute
|
gst_sdp_media_remove_attribute
|
||||||
gst_sdp_media_add_attribute
|
gst_sdp_media_add_attribute
|
||||||
|
gst_sdp_media_get_caps_from_media
|
||||||
|
gst_sdp_media_set_media_from_caps
|
||||||
|
gst_sdp_make_keymgmt
|
||||||
|
gst_sdp_message_attributes_to_caps
|
||||||
|
gst_sdp_media_attributes_to_caps
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
gst_sdp_message_get_type
|
gst_sdp_message_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
@ -1807,8 +1812,10 @@ GstMIKEYMessage
|
||||||
|
|
||||||
gst_mikey_message_new
|
gst_mikey_message_new
|
||||||
gst_mikey_message_new_from_bytes
|
gst_mikey_message_new_from_bytes
|
||||||
|
gst_mikey_message_new_from_caps
|
||||||
gst_mikey_message_new_from_data
|
gst_mikey_message_new_from_data
|
||||||
gst_mikey_message_to_bytes
|
gst_mikey_message_to_bytes
|
||||||
|
gst_mikey_message_base64_encode
|
||||||
gst_mikey_message_copy
|
gst_mikey_message_copy
|
||||||
gst_mikey_message_ref
|
gst_mikey_message_ref
|
||||||
gst_mikey_message_unref
|
gst_mikey_message_unref
|
||||||
|
|
|
@ -10,7 +10,7 @@ lib_LTLIBRARIES = libgstsdp-@GST_API_VERSION@.la
|
||||||
libgstsdp_@GST_API_VERSION@_la_SOURCES = gstsdpmessage.c gstmikey.c
|
libgstsdp_@GST_API_VERSION@_la_SOURCES = gstsdpmessage.c gstmikey.c
|
||||||
|
|
||||||
libgstsdp_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
|
libgstsdp_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
|
||||||
libgstsdp_@GST_API_VERSION@_la_LIBADD = $(GST_LIBS) $(GIO_LIBS)
|
libgstsdp_@GST_API_VERSION@_la_LIBADD = $(top_builddir)/gst-libs/gst/rtp/libgstrtp-@GST_API_VERSION@.la $(GST_LIBS) $(GIO_LIBS)
|
||||||
libgstsdp_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
|
libgstsdp_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
|
||||||
|
|
||||||
if HAVE_INTROSPECTION
|
if HAVE_INTROSPECTION
|
||||||
|
|
|
@ -2148,3 +2148,170 @@ parse_error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define AES_128_KEY_LEN 16
|
||||||
|
#define AES_256_KEY_LEN 32
|
||||||
|
#define HMAC_32_KEY_LEN 4
|
||||||
|
#define HMAC_80_KEY_LEN 10
|
||||||
|
|
||||||
|
static guint8
|
||||||
|
enc_key_length_from_cipher_name (const gchar * cipher)
|
||||||
|
{
|
||||||
|
if (g_strcmp0 (cipher, "aes-128-icm") == 0)
|
||||||
|
return AES_128_KEY_LEN;
|
||||||
|
else if (g_strcmp0 (cipher, "aes-256-icm") == 0)
|
||||||
|
return AES_256_KEY_LEN;
|
||||||
|
else {
|
||||||
|
GST_ERROR ("encryption algorithm '%s' not supported", cipher);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint8
|
||||||
|
auth_key_length_from_auth_name (const gchar * auth)
|
||||||
|
{
|
||||||
|
if (g_strcmp0 (auth, "hmac-sha1-32") == 0)
|
||||||
|
return HMAC_32_KEY_LEN;
|
||||||
|
else if (g_strcmp0 (auth, "hmac-sha1-80") == 0)
|
||||||
|
return HMAC_80_KEY_LEN;
|
||||||
|
else {
|
||||||
|
GST_ERROR ("authentication algorithm '%s' not supported", auth);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mikey_message_new_from_caps:
|
||||||
|
* @caps: a #GstCaps, including SRTP parameters (srtp/srtcp cipher, authorization, key data)
|
||||||
|
*
|
||||||
|
* Makes mikey message including:
|
||||||
|
* - Security Policy Payload
|
||||||
|
* - Key Data Transport Payload
|
||||||
|
* - Key Data Sub-Payload
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a #GstMIKEYMessage,
|
||||||
|
* or %NULL if there is no srtp information in the caps.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstMIKEYMessage *
|
||||||
|
gst_mikey_message_new_from_caps (GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstMIKEYMessage *msg;
|
||||||
|
GstMIKEYPayload *payload, *pkd;
|
||||||
|
guint8 byte;
|
||||||
|
GstStructure *s;
|
||||||
|
GstMapInfo info;
|
||||||
|
GstBuffer *srtpkey;
|
||||||
|
const GValue *val;
|
||||||
|
const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth;
|
||||||
|
|
||||||
|
g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), NULL);
|
||||||
|
|
||||||
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
g_return_val_if_fail (s != NULL, NULL);
|
||||||
|
|
||||||
|
val = gst_structure_get_value (s, "srtp-key");
|
||||||
|
if (!val)
|
||||||
|
goto no_key;
|
||||||
|
|
||||||
|
srtpkey = gst_value_get_buffer (val);
|
||||||
|
if (!srtpkey || !GST_IS_BUFFER (srtpkey))
|
||||||
|
goto no_key;
|
||||||
|
|
||||||
|
srtpcipher = gst_structure_get_string (s, "srtp-cipher");
|
||||||
|
srtpauth = gst_structure_get_string (s, "srtp-auth");
|
||||||
|
srtcpcipher = gst_structure_get_string (s, "srtcp-cipher");
|
||||||
|
srtcpauth = gst_structure_get_string (s, "srtcp-auth");
|
||||||
|
|
||||||
|
if (srtpcipher == NULL || srtpauth == NULL || srtcpcipher == NULL ||
|
||||||
|
srtcpauth == NULL) {
|
||||||
|
GST_WARNING ("could not find the right SRTP parameters in caps");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = gst_mikey_message_new ();
|
||||||
|
/* unencrypted MIKEY message, we send this over TLS so this is allowed */
|
||||||
|
gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT,
|
||||||
|
FALSE, GST_MIKEY_PRF_MIKEY_1, g_random_int (), GST_MIKEY_MAP_TYPE_SRTP);
|
||||||
|
|
||||||
|
/* timestamp is now */
|
||||||
|
gst_mikey_message_add_t_now_ntp_utc (msg);
|
||||||
|
/* add some random data */
|
||||||
|
gst_mikey_message_add_rand_len (msg, 16);
|
||||||
|
|
||||||
|
/* the policy '0' is SRTP */
|
||||||
|
payload = gst_mikey_payload_new (GST_MIKEY_PT_SP);
|
||||||
|
gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP);
|
||||||
|
|
||||||
|
/* only AES-CM is supported */
|
||||||
|
byte = 1;
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte);
|
||||||
|
/* encryption key length */
|
||||||
|
byte = enc_key_length_from_cipher_name (srtpcipher);
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1,
|
||||||
|
&byte);
|
||||||
|
/* only HMAC-SHA1 */
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1,
|
||||||
|
&byte);
|
||||||
|
/* authentication key length */
|
||||||
|
byte = auth_key_length_from_auth_name (srtpauth);
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1,
|
||||||
|
&byte);
|
||||||
|
/* we enable encryption on RTP and RTCP */
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1,
|
||||||
|
&byte);
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1,
|
||||||
|
&byte);
|
||||||
|
/* we enable authentication on RTP and RTCP */
|
||||||
|
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1,
|
||||||
|
&byte);
|
||||||
|
gst_mikey_message_add_payload (msg, payload);
|
||||||
|
|
||||||
|
/* make unencrypted KEMAC */
|
||||||
|
payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC);
|
||||||
|
gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, GST_MIKEY_MAC_NULL);
|
||||||
|
/* add the key in KEMAC */
|
||||||
|
pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA);
|
||||||
|
gst_buffer_map (srtpkey, &info, GST_MAP_READ);
|
||||||
|
gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size,
|
||||||
|
info.data);
|
||||||
|
gst_buffer_unmap (srtpkey, &info);
|
||||||
|
gst_mikey_payload_kemac_add_sub (payload, pkd);
|
||||||
|
gst_mikey_message_add_payload (msg, payload);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
|
||||||
|
no_key:
|
||||||
|
GST_INFO ("No srtp key");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mikey_message_base64_encode:
|
||||||
|
* @msg: a #GstMIKEYMessage
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a #gchar, base64-encoded data
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
gchar *
|
||||||
|
gst_mikey_message_base64_encode (GstMIKEYMessage * msg)
|
||||||
|
{
|
||||||
|
GBytes *bytes;
|
||||||
|
gchar *base64;
|
||||||
|
const guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
g_return_val_if_fail (msg != NULL, NULL);
|
||||||
|
|
||||||
|
/* serialize mikey message to bytes */
|
||||||
|
bytes = gst_mikey_message_to_bytes (msg, NULL, NULL);
|
||||||
|
|
||||||
|
/* and make it into base64 */
|
||||||
|
data = g_bytes_get_data (bytes, &size);
|
||||||
|
base64 = g_base64_encode (data, size);
|
||||||
|
g_bytes_unref (bytes);
|
||||||
|
|
||||||
|
return base64;
|
||||||
|
}
|
||||||
|
|
|
@ -559,6 +559,9 @@ GstMIKEYMessage * gst_mikey_message_new_from_bytes (GBytes *bytes,
|
||||||
GError **error);
|
GError **error);
|
||||||
GBytes * gst_mikey_message_to_bytes (GstMIKEYMessage *msg, GstMIKEYEncryptInfo *info,
|
GBytes * gst_mikey_message_to_bytes (GstMIKEYMessage *msg, GstMIKEYEncryptInfo *info,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
GstMIKEYMessage * gst_mikey_message_new_from_caps (GstCaps *caps);
|
||||||
|
gchar * gst_mikey_message_base64_encode (GstMIKEYMessage* msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_mikey_message_ref:
|
* gst_mikey_message_ref:
|
||||||
* @message: The message to refcount
|
* @message: The message to refcount
|
||||||
|
|
|
@ -56,12 +56,15 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
#include <gst/rtp/gstrtppayloads.h>
|
||||||
#include "gstsdpmessage.h"
|
#include "gstsdpmessage.h"
|
||||||
|
#include "gstmikey.h"
|
||||||
|
|
||||||
#define FREE_STRING(field) g_free (field); (field) = NULL
|
#define FREE_STRING(field) g_free (field); (field) = NULL
|
||||||
#define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup (val)
|
#define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup (val)
|
||||||
|
@ -2802,7 +2805,7 @@ gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'v':
|
case 'v':
|
||||||
if (buffer[0] != '0')
|
if (buffer[0] != '0')
|
||||||
g_warning ("wrong SDP version");
|
GST_WARNING ("wrong SDP version");
|
||||||
gst_sdp_message_set_version (c->msg, buffer);
|
gst_sdp_message_set_version (c->msg, buffer);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
|
@ -3165,3 +3168,699 @@ gst_sdp_message_dump (const GstSDPMessage * msg)
|
||||||
}
|
}
|
||||||
return GST_SDP_OK;
|
return GST_SDP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
gst_sdp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name,
|
||||||
|
gint pt)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0;; i++) {
|
||||||
|
const gchar *attr;
|
||||||
|
gint val;
|
||||||
|
|
||||||
|
if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (sscanf (attr, "%d ", &val) != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (val == pt)
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PARSE_INT(p, del, res) \
|
||||||
|
G_STMT_START { \
|
||||||
|
gchar *t = p; \
|
||||||
|
p = strstr (p, del); \
|
||||||
|
if (p == NULL) \
|
||||||
|
res = -1; \
|
||||||
|
else { \
|
||||||
|
*p = '\0'; \
|
||||||
|
p++; \
|
||||||
|
res = atoi (t); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define PARSE_STRING(p, del, res) \
|
||||||
|
G_STMT_START { \
|
||||||
|
gchar *t = p; \
|
||||||
|
p = strstr (p, del); \
|
||||||
|
if (p == NULL) { \
|
||||||
|
res = NULL; \
|
||||||
|
p = t; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
*p = '\0'; \
|
||||||
|
p++; \
|
||||||
|
res = t; \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define SKIP_SPACES(p) \
|
||||||
|
while (*p && g_ascii_isspace (*p)) \
|
||||||
|
p++;
|
||||||
|
|
||||||
|
/* rtpmap contains:
|
||||||
|
*
|
||||||
|
* <payload> <encoding_name>/<clock_rate>[/<encoding_params>]
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_sdp_parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name,
|
||||||
|
gint * rate, gchar ** params)
|
||||||
|
{
|
||||||
|
gchar *p, *t;
|
||||||
|
|
||||||
|
p = (gchar *) rtpmap;
|
||||||
|
|
||||||
|
PARSE_INT (p, " ", *payload);
|
||||||
|
if (*payload == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
SKIP_SPACES (p);
|
||||||
|
if (*p == '\0')
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
PARSE_STRING (p, "/", *name);
|
||||||
|
if (*name == NULL) {
|
||||||
|
GST_DEBUG ("no rate, name %s", p);
|
||||||
|
/* no rate, assume -1 then, this is not supposed to happen but RealMedia
|
||||||
|
* streams seem to omit the rate. */
|
||||||
|
*name = p;
|
||||||
|
*rate = -1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = p;
|
||||||
|
p = strstr (p, "/");
|
||||||
|
if (p == NULL) {
|
||||||
|
*rate = atoi (t);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
p++;
|
||||||
|
*rate = atoi (t);
|
||||||
|
|
||||||
|
t = p;
|
||||||
|
if (*p == '\0')
|
||||||
|
return TRUE;
|
||||||
|
*params = t;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_sdp_media_get_caps_from_media:
|
||||||
|
* @media: a #GstSDPMedia
|
||||||
|
* @pt: a payload type
|
||||||
|
*
|
||||||
|
* Mapping of caps from SDP fields:
|
||||||
|
*
|
||||||
|
* a=rtpmap:(payload) (encoding_name)/(clock_rate)[/(encoding_params)]
|
||||||
|
*
|
||||||
|
* a=framesize:(payload) (width)-(height)
|
||||||
|
*
|
||||||
|
* a=fmtp:(payload) (param)[=(value)];...
|
||||||
|
*
|
||||||
|
* Returns: a #GstCaps, or %NULL if an error happened
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstCaps *
|
||||||
|
gst_sdp_media_get_caps_from_media (const GstSDPMedia * media, gint pt)
|
||||||
|
{
|
||||||
|
GstCaps *caps;
|
||||||
|
const gchar *rtpmap;
|
||||||
|
const gchar *fmtp;
|
||||||
|
const gchar *framesize;
|
||||||
|
gchar *name = NULL;
|
||||||
|
gint rate = -1;
|
||||||
|
gchar *params = NULL;
|
||||||
|
gchar *tmp;
|
||||||
|
GstStructure *s;
|
||||||
|
gint payload = 0;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
/* get and parse rtpmap */
|
||||||
|
rtpmap = gst_sdp_get_attribute_for_pt (media, "rtpmap", pt);
|
||||||
|
|
||||||
|
if (rtpmap) {
|
||||||
|
ret = gst_sdp_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms);
|
||||||
|
if (!ret) {
|
||||||
|
GST_ERROR ("error parsing rtpmap, ignoring");
|
||||||
|
rtpmap = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* dynamic payloads need rtpmap or we fail */
|
||||||
|
if (rtpmap == NULL && pt >= 96)
|
||||||
|
goto no_rtpmap;
|
||||||
|
|
||||||
|
/* check if we have a rate, if not, we need to look up the rate from the
|
||||||
|
* default rates based on the payload types. */
|
||||||
|
if (rate == -1) {
|
||||||
|
const GstRTPPayloadInfo *info;
|
||||||
|
|
||||||
|
if (GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) {
|
||||||
|
/* dynamic types, use media and encoding_name */
|
||||||
|
tmp = g_ascii_strdown (media->media, -1);
|
||||||
|
info = gst_rtp_payload_info_for_name (tmp, name);
|
||||||
|
g_free (tmp);
|
||||||
|
} else {
|
||||||
|
/* static types, use payload type */
|
||||||
|
info = gst_rtp_payload_info_for_pt (pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
if ((rate = info->clock_rate) == 0)
|
||||||
|
rate = -1;
|
||||||
|
}
|
||||||
|
/* we fail if we cannot find one */
|
||||||
|
if (rate == -1)
|
||||||
|
goto no_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = g_ascii_strdown (media->media, -1);
|
||||||
|
caps = gst_caps_new_simple ("application/x-unknown",
|
||||||
|
"media", G_TYPE_STRING, tmp, "payload", G_TYPE_INT, pt, NULL);
|
||||||
|
g_free (tmp);
|
||||||
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
gst_structure_set (s, "clock-rate", G_TYPE_INT, rate, NULL);
|
||||||
|
|
||||||
|
/* encoding name must be upper case */
|
||||||
|
if (name != NULL) {
|
||||||
|
tmp = g_ascii_strup (name, -1);
|
||||||
|
gst_structure_set (s, "encoding-name", G_TYPE_STRING, tmp, NULL);
|
||||||
|
g_free (tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* params must be lower case */
|
||||||
|
if (params != NULL) {
|
||||||
|
tmp = g_ascii_strdown (params, -1);
|
||||||
|
gst_structure_set (s, "encoding-params", G_TYPE_STRING, tmp, NULL);
|
||||||
|
g_free (tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse optional fmtp: field */
|
||||||
|
if ((fmtp = gst_sdp_get_attribute_for_pt (media, "fmtp", pt))) {
|
||||||
|
gchar *p;
|
||||||
|
gint payload = 0;
|
||||||
|
|
||||||
|
p = (gchar *) fmtp;
|
||||||
|
|
||||||
|
/* p is now of the format <payload> <param>[=<value>];... */
|
||||||
|
PARSE_INT (p, " ", payload);
|
||||||
|
if (payload != -1 && payload == pt) {
|
||||||
|
gchar **pairs;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* <param>[=<value>] are separated with ';' */
|
||||||
|
pairs = g_strsplit (p, ";", 0);
|
||||||
|
for (i = 0; pairs[i]; i++) {
|
||||||
|
gchar *valpos;
|
||||||
|
const gchar *val, *key;
|
||||||
|
gint j;
|
||||||
|
const gchar *reserved_keys[] =
|
||||||
|
{ "media", "payload", "clock-rate", "encoding-name",
|
||||||
|
"encoding-params"
|
||||||
|
};
|
||||||
|
|
||||||
|
/* the key may not have a '=', the value can have other '='s */
|
||||||
|
valpos = strstr (pairs[i], "=");
|
||||||
|
if (valpos) {
|
||||||
|
/* we have a '=' and thus a value, remove the '=' with \0 */
|
||||||
|
*valpos = '\0';
|
||||||
|
/* value is everything between '=' and ';'. We split the pairs at ;
|
||||||
|
* boundaries so we can take the remainder of the value. Some servers
|
||||||
|
* put spaces around the value which we strip off here. Alternatively
|
||||||
|
* we could strip those spaces in the depayloaders should these spaces
|
||||||
|
* actually carry any meaning in the future. */
|
||||||
|
val = g_strstrip (valpos + 1);
|
||||||
|
} else {
|
||||||
|
/* simple <param>;.. is translated into <param>=1;... */
|
||||||
|
val = "1";
|
||||||
|
}
|
||||||
|
/* strip the key of spaces, convert key to lowercase but not the value. */
|
||||||
|
key = g_strstrip (pairs[i]);
|
||||||
|
|
||||||
|
/* skip keys from the fmtp, which we already use ourselves for the
|
||||||
|
* caps. Some software is adding random things like clock-rate into
|
||||||
|
* the fmtp, and we would otherwise here set a string-typed clock-rate
|
||||||
|
* in the caps... and thus fail to create valid RTP caps
|
||||||
|
*/
|
||||||
|
for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) {
|
||||||
|
if (g_ascii_strcasecmp (reserved_keys[j], key) == 0) {
|
||||||
|
key = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen (key) > 1) {
|
||||||
|
tmp = g_ascii_strdown (key, -1);
|
||||||
|
gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL);
|
||||||
|
g_free (tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_strfreev (pairs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse framesize: field */
|
||||||
|
if ((framesize = gst_sdp_media_get_attribute_val (media, "framesize"))) {
|
||||||
|
gchar *p;
|
||||||
|
|
||||||
|
/* p is now of the format <payload> <width>-<height> */
|
||||||
|
p = (gchar *) framesize;
|
||||||
|
|
||||||
|
PARSE_INT (p, " ", payload);
|
||||||
|
if (payload != -1 && payload == pt) {
|
||||||
|
gst_structure_set (s, "a-framesize", G_TYPE_STRING, p, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
no_rtpmap:
|
||||||
|
{
|
||||||
|
GST_ERROR ("rtpmap type not given for dynamic payload %d", pt);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
no_rate:
|
||||||
|
{
|
||||||
|
GST_ERROR ("rate unknown for payload type %d", pt);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_sdp_media_set_media_from_caps:
|
||||||
|
* @caps: a #GstCaps
|
||||||
|
* @media: a #GstSDPMedia
|
||||||
|
*
|
||||||
|
* Mapping of caps to SDP fields:
|
||||||
|
*
|
||||||
|
* a=rtpmap:(payload) (encoding_name) or (clock_rate)[or (encoding_params)]
|
||||||
|
*
|
||||||
|
* a=framesize:(payload) (width)-(height)
|
||||||
|
*
|
||||||
|
* a=fmtp:(payload) (param)[=(value)];...
|
||||||
|
*
|
||||||
|
* Returns: a #GstSDPResult.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstSDPResult
|
||||||
|
gst_sdp_media_set_media_from_caps (const GstCaps * caps, GstSDPMedia * media)
|
||||||
|
{
|
||||||
|
const gchar *caps_str, *caps_enc, *caps_params;
|
||||||
|
gchar *tmp;
|
||||||
|
gint caps_pt, caps_rate;
|
||||||
|
guint n_fields, j;
|
||||||
|
gboolean first;
|
||||||
|
GString *fmtp;
|
||||||
|
GstStructure *s;
|
||||||
|
|
||||||
|
g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
|
||||||
|
g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
|
||||||
|
|
||||||
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
if (s == NULL) {
|
||||||
|
GST_ERROR ("ignoring stream without media type");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get media type and payload for the m= line */
|
||||||
|
caps_str = gst_structure_get_string (s, "media");
|
||||||
|
gst_sdp_media_set_media (media, caps_str);
|
||||||
|
|
||||||
|
gst_structure_get_int (s, "payload", &caps_pt);
|
||||||
|
tmp = g_strdup_printf ("%d", caps_pt);
|
||||||
|
gst_sdp_media_add_format (media, tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
/* get clock-rate, media type and params for the rtpmap attribute */
|
||||||
|
gst_structure_get_int (s, "clock-rate", &caps_rate);
|
||||||
|
caps_enc = gst_structure_get_string (s, "encoding-name");
|
||||||
|
caps_params = gst_structure_get_string (s, "encoding-params");
|
||||||
|
|
||||||
|
if (caps_enc) {
|
||||||
|
if (caps_params)
|
||||||
|
tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate,
|
||||||
|
caps_params);
|
||||||
|
else
|
||||||
|
tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate);
|
||||||
|
|
||||||
|
gst_sdp_media_add_attribute (media, "rtpmap", tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* collect all other properties and add them to fmtp or attributes */
|
||||||
|
fmtp = g_string_new ("");
|
||||||
|
g_string_append_printf (fmtp, "%d ", caps_pt);
|
||||||
|
first = TRUE;
|
||||||
|
n_fields = gst_structure_n_fields (s);
|
||||||
|
for (j = 0; j < n_fields; j++) {
|
||||||
|
const gchar *fname, *fval;
|
||||||
|
|
||||||
|
fname = gst_structure_nth_field_name (s, j);
|
||||||
|
|
||||||
|
/* filter out standard properties */
|
||||||
|
if (!strcmp (fname, "media"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "payload"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "clock-rate"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "encoding-name"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "encoding-params"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "ssrc"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "timestamp-offset"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (fname, "seqnum-offset"))
|
||||||
|
continue;
|
||||||
|
if (g_str_has_prefix (fname, "srtp-"))
|
||||||
|
continue;
|
||||||
|
if (g_str_has_prefix (fname, "srtcp-"))
|
||||||
|
continue;
|
||||||
|
/* handled later */
|
||||||
|
if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!strcmp (fname, "a-framesize")) {
|
||||||
|
/* a-framesize attribute */
|
||||||
|
if ((fval = gst_structure_get_string (s, fname))) {
|
||||||
|
tmp = g_strdup_printf ("%d %s", caps_pt, fval);
|
||||||
|
gst_sdp_media_add_attribute (media, fname + 2, tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_prefix (fname, "a-")) {
|
||||||
|
/* attribute */
|
||||||
|
if ((fval = gst_structure_get_string (s, fname)))
|
||||||
|
gst_sdp_media_add_attribute (media, fname + 2, fval);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (g_str_has_prefix (fname, "x-")) {
|
||||||
|
/* attribute */
|
||||||
|
if ((fval = gst_structure_get_string (s, fname)))
|
||||||
|
gst_sdp_media_add_attribute (media, fname, fval);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fval = gst_structure_get_string (s, fname))) {
|
||||||
|
g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first) {
|
||||||
|
tmp = g_string_free (fmtp, FALSE);
|
||||||
|
gst_sdp_media_add_attribute (media, "fmtp", tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
} else {
|
||||||
|
g_string_free (fmtp, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_SDP_OK;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
error:
|
||||||
|
{
|
||||||
|
GST_DEBUG ("ignoring stream");
|
||||||
|
return GST_SDP_EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_sdp_make_keymgmt:
|
||||||
|
* @uri: a #gchar URI
|
||||||
|
* @base64: a #gchar base64-encoded key data
|
||||||
|
*
|
||||||
|
* Makes key management data
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a #gchar key-mgmt data,
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
gchar *
|
||||||
|
gst_sdp_make_keymgmt (const gchar * uri, const gchar * base64)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (uri != NULL, NULL);
|
||||||
|
g_return_val_if_fail (base64 != NULL, NULL);
|
||||||
|
|
||||||
|
return g_strdup_printf ("prot=mikey;uri=\"%s\";data=\"%s\"", uri, base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AES_128_KEY_LEN 16
|
||||||
|
#define AES_256_KEY_LEN 32
|
||||||
|
#define HMAC_32_KEY_LEN 4
|
||||||
|
#define HMAC_80_KEY_LEN 10
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_sdp_parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
gsize size;
|
||||||
|
guchar *data;
|
||||||
|
GstMIKEYMessage *msg;
|
||||||
|
const GstMIKEYPayload *payload;
|
||||||
|
const gchar *srtp_cipher;
|
||||||
|
const gchar *srtp_auth;
|
||||||
|
gchar *orig_value;
|
||||||
|
gchar *p, *kmpid;
|
||||||
|
|
||||||
|
p = orig_value = g_strdup (keymgmt);
|
||||||
|
|
||||||
|
SKIP_SPACES (p);
|
||||||
|
if (*p == '\0') {
|
||||||
|
g_free (orig_value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PARSE_STRING (p, " ", kmpid);
|
||||||
|
if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) {
|
||||||
|
g_free (orig_value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
data = g_base64_decode (p, &size);
|
||||||
|
g_free (orig_value); /* Don't need this any more */
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
msg = gst_mikey_message_new_from_data (data, size, NULL, NULL);
|
||||||
|
g_free (data);
|
||||||
|
if (msg == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
srtp_cipher = "aes-128-icm";
|
||||||
|
srtp_auth = "hmac-sha1-80";
|
||||||
|
|
||||||
|
/* check the Security policy if any */
|
||||||
|
if ((payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, 0))) {
|
||||||
|
GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
|
||||||
|
guint len, i;
|
||||||
|
|
||||||
|
if (p->proto != GST_MIKEY_SEC_PROTO_SRTP)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
len = gst_mikey_payload_sp_get_n_params (payload);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
const GstMIKEYPayloadSPParam *param =
|
||||||
|
gst_mikey_payload_sp_get_param (payload, i);
|
||||||
|
|
||||||
|
switch (param->type) {
|
||||||
|
case GST_MIKEY_SP_SRTP_ENC_ALG:
|
||||||
|
switch (param->val[0]) {
|
||||||
|
case 0:
|
||||||
|
srtp_cipher = "null";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 1:
|
||||||
|
srtp_cipher = "aes-128-icm";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
|
||||||
|
switch (param->val[0]) {
|
||||||
|
case AES_128_KEY_LEN:
|
||||||
|
srtp_cipher = "aes-128-icm";
|
||||||
|
break;
|
||||||
|
case AES_256_KEY_LEN:
|
||||||
|
srtp_cipher = "aes-256-icm";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MIKEY_SP_SRTP_AUTH_ALG:
|
||||||
|
switch (param->val[0]) {
|
||||||
|
case 0:
|
||||||
|
srtp_auth = "null";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 1:
|
||||||
|
srtp_auth = "hmac-sha1-80";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
|
||||||
|
switch (param->val[0]) {
|
||||||
|
case HMAC_32_KEY_LEN:
|
||||||
|
srtp_auth = "hmac-sha1-32";
|
||||||
|
break;
|
||||||
|
case HMAC_80_KEY_LEN:
|
||||||
|
srtp_auth = "hmac-sha1-80";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MIKEY_SP_SRTP_SRTP_ENC:
|
||||||
|
break;
|
||||||
|
case GST_MIKEY_SP_SRTP_SRTCP_ENC:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0)))
|
||||||
|
goto done;
|
||||||
|
else {
|
||||||
|
GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
|
||||||
|
const GstMIKEYPayload *sub;
|
||||||
|
GstMIKEYPayloadKeyData *pkd;
|
||||||
|
GstBuffer *buf;
|
||||||
|
|
||||||
|
if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0)))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (sub->type != GST_MIKEY_PT_KEY_DATA)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pkd = (GstMIKEYPayloadKeyData *) sub;
|
||||||
|
buf =
|
||||||
|
gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
|
||||||
|
pkd->key_len);
|
||||||
|
gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_caps_set_simple (caps,
|
||||||
|
"srtp-cipher", G_TYPE_STRING, srtp_cipher,
|
||||||
|
"srtp-auth", G_TYPE_STRING, srtp_auth,
|
||||||
|
"srtcp-cipher", G_TYPE_STRING, srtp_cipher,
|
||||||
|
"srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
|
||||||
|
|
||||||
|
res = TRUE;
|
||||||
|
done:
|
||||||
|
gst_mikey_message_unref (msg);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstSDPResult
|
||||||
|
sdp_addtributes_to_caps (GArray * attributes, GstCaps * caps)
|
||||||
|
{
|
||||||
|
if (attributes->len > 0) {
|
||||||
|
GstStructure *s;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
for (i = 0; i < attributes->len; i++) {
|
||||||
|
GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i);
|
||||||
|
gchar *tofree, *key;
|
||||||
|
|
||||||
|
key = attr->key;
|
||||||
|
|
||||||
|
/* skip some of the attribute we already handle */
|
||||||
|
if (!strcmp (key, "fmtp"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (key, "rtpmap"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (key, "control"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (key, "range"))
|
||||||
|
continue;
|
||||||
|
if (!strcmp (key, "framesize"))
|
||||||
|
continue;
|
||||||
|
if (g_str_equal (key, "key-mgmt")) {
|
||||||
|
gst_sdp_parse_keymgmt (attr->value, caps);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string must be valid UTF8 */
|
||||||
|
if (!g_utf8_validate (attr->value, -1, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!g_str_has_prefix (key, "x-"))
|
||||||
|
tofree = key = g_strdup_printf ("a-%s", key);
|
||||||
|
else
|
||||||
|
tofree = NULL;
|
||||||
|
|
||||||
|
GST_DEBUG ("adding caps: %s=%s", key, attr->value);
|
||||||
|
gst_structure_set (s, key, G_TYPE_STRING, attr->value, NULL);
|
||||||
|
g_free (tofree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_SDP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_sdp_message_attributes_to_caps:
|
||||||
|
* @msg: a #GstSDPMessage
|
||||||
|
* @caps: a #GstCaps
|
||||||
|
*
|
||||||
|
* Mapping of attributes of #GstSDPMessage to #GstCaps
|
||||||
|
*
|
||||||
|
* Returns: a #GstSDPResult.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstSDPResult
|
||||||
|
gst_sdp_message_attributes_to_caps (const GstSDPMessage * msg, GstCaps * caps)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
|
||||||
|
g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
|
||||||
|
|
||||||
|
return sdp_addtributes_to_caps (msg->attributes, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_sdp_media_attributes_to_caps:
|
||||||
|
* @media: a #GstSDPMedia
|
||||||
|
* @caps: a #GstCaps
|
||||||
|
*
|
||||||
|
* Mapping of attributes of #GstSDPMedia to #GstCaps
|
||||||
|
*
|
||||||
|
* Returns: a #GstSDPResult.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstSDPResult
|
||||||
|
gst_sdp_media_attributes_to_caps (const GstSDPMedia * media, GstCaps * caps)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
|
||||||
|
g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
|
||||||
|
|
||||||
|
return sdp_addtributes_to_caps (media->attributes, caps);
|
||||||
|
}
|
||||||
|
|
|
@ -501,6 +501,11 @@ GstSDPResult gst_sdp_media_replace_attribute (GstSDPMedia *media,
|
||||||
GstSDPResult gst_sdp_media_remove_attribute (GstSDPMedia *media, guint idx);
|
GstSDPResult gst_sdp_media_remove_attribute (GstSDPMedia *media, guint idx);
|
||||||
GstSDPResult gst_sdp_media_add_attribute (GstSDPMedia *media, const gchar *key,
|
GstSDPResult gst_sdp_media_add_attribute (GstSDPMedia *media, const gchar *key,
|
||||||
const gchar *value);
|
const gchar *value);
|
||||||
|
GstCaps* gst_sdp_media_get_caps_from_media (const GstSDPMedia *media, gint pt);
|
||||||
|
GstSDPResult gst_sdp_media_set_media_from_caps (const GstCaps* caps, GstSDPMedia *media);
|
||||||
|
gchar * gst_sdp_make_keymgmt (const gchar *uri, const gchar *base64);
|
||||||
|
GstSDPResult gst_sdp_message_attributes_to_caps (const GstSDPMessage *msg, GstCaps *caps);
|
||||||
|
GstSDPResult gst_sdp_media_attributes_to_caps (const GstSDPMedia *media, GstCaps *caps);
|
||||||
|
|
||||||
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
|
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstSDPMessage, gst_sdp_message_free)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstSDPMessage, gst_sdp_message_free)
|
||||||
|
|
|
@ -62,6 +62,18 @@ static const gchar *sdp = "v=0\r\n"
|
||||||
"a=sendrecv\r\n" "m=audio 4545 RTP/AVP 14\r\n" "a=sendrecv\r\n"
|
"a=sendrecv\r\n" "m=audio 4545 RTP/AVP 14\r\n" "a=sendrecv\r\n"
|
||||||
"m=audio 1010 TCP 14\r\n";
|
"m=audio 1010 TCP 14\r\n";
|
||||||
|
|
||||||
|
static const gchar caps_video_string1[] =
|
||||||
|
"application/x-unknown, media=(string)video, payload=(int)96, "
|
||||||
|
"clock-rate=(int)90000, encoding-name=(string)MP4V-ES";
|
||||||
|
|
||||||
|
static const gchar caps_video_string2[] =
|
||||||
|
"application/x-unknown, media=(string)video, payload=(int)97, "
|
||||||
|
"clock-rate=(int)90000, encoding-name=(string)H263-1998";
|
||||||
|
|
||||||
|
static const gchar caps_audio_string[] =
|
||||||
|
"application/x-unknown, media=(string)audio, payload=(int)14, "
|
||||||
|
"clock-rate=(int)90000";
|
||||||
|
|
||||||
GST_START_TEST (boxed)
|
GST_START_TEST (boxed)
|
||||||
{
|
{
|
||||||
GValue value = G_VALUE_INIT;
|
GValue value = G_VALUE_INIT;
|
||||||
|
@ -193,6 +205,97 @@ GST_START_TEST (modify)
|
||||||
gst_sdp_message_free (message);
|
gst_sdp_message_free (message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_END_TEST
|
||||||
|
GST_START_TEST (caps_from_media)
|
||||||
|
{
|
||||||
|
GstSDPMessage *message;
|
||||||
|
glong length = -1;
|
||||||
|
const GstSDPMedia *media1, *media2, *media3;
|
||||||
|
GstCaps *caps_video1, *caps_video2, *caps_audio;
|
||||||
|
GstCaps *result_video1, *result_video2, *result_audio;
|
||||||
|
|
||||||
|
gst_sdp_message_new (&message);
|
||||||
|
gst_sdp_message_parse_buffer ((guint8 *) sdp, length, message);
|
||||||
|
|
||||||
|
media1 = gst_sdp_message_get_media (message, 0);
|
||||||
|
fail_unless (media1 != NULL);
|
||||||
|
|
||||||
|
media2 = gst_sdp_message_get_media (message, 1);
|
||||||
|
fail_unless (media2 != NULL);
|
||||||
|
|
||||||
|
media3 = gst_sdp_message_get_media (message, 2);
|
||||||
|
fail_unless (media2 != NULL);
|
||||||
|
|
||||||
|
caps_video1 = gst_sdp_media_get_caps_from_media (media1, 96);
|
||||||
|
caps_video2 = gst_sdp_media_get_caps_from_media (media1, 97);
|
||||||
|
caps_audio = gst_sdp_media_get_caps_from_media (media3, 14);
|
||||||
|
|
||||||
|
result_video1 = gst_caps_from_string (caps_video_string1);
|
||||||
|
fail_unless (gst_caps_is_strictly_equal (caps_video1, result_video1));
|
||||||
|
gst_caps_unref (result_video1);
|
||||||
|
gst_caps_unref (caps_video1);
|
||||||
|
|
||||||
|
result_video2 = gst_caps_from_string (caps_video_string2);
|
||||||
|
fail_unless (gst_caps_is_strictly_equal (caps_video2, result_video2));
|
||||||
|
gst_caps_unref (result_video2);
|
||||||
|
gst_caps_unref (caps_video2);
|
||||||
|
|
||||||
|
result_audio = gst_caps_from_string (caps_audio_string);
|
||||||
|
fail_unless (gst_caps_is_strictly_equal (caps_audio, result_audio));
|
||||||
|
gst_caps_unref (result_audio);
|
||||||
|
gst_caps_unref (caps_audio);
|
||||||
|
|
||||||
|
gst_sdp_message_free (message);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST
|
||||||
|
GST_START_TEST (media_from_caps)
|
||||||
|
{
|
||||||
|
GstSDPResult ret = GST_SDP_OK;
|
||||||
|
GstSDPMessage *message;
|
||||||
|
glong length = -1;
|
||||||
|
GstSDPMedia *media_video, *media_audio;
|
||||||
|
const GstSDPMedia *result_video, *result_audio;
|
||||||
|
GstCaps *caps_video, *caps_audio;
|
||||||
|
const gchar *media1_text, *media2_text, *media3_text, *media4_text;
|
||||||
|
|
||||||
|
caps_video = gst_caps_from_string (caps_video_string1);
|
||||||
|
caps_audio = gst_caps_from_string (caps_audio_string);
|
||||||
|
|
||||||
|
gst_sdp_media_new (&media_video);
|
||||||
|
fail_unless (media_video != NULL);
|
||||||
|
gst_sdp_media_new (&media_audio);
|
||||||
|
fail_unless (media_audio != NULL);
|
||||||
|
|
||||||
|
ret = gst_sdp_media_set_media_from_caps (caps_video, media_video);
|
||||||
|
fail_unless (ret == GST_SDP_OK);
|
||||||
|
gst_caps_unref (caps_video);
|
||||||
|
ret = gst_sdp_media_set_media_from_caps (caps_audio, media_audio);
|
||||||
|
fail_unless (ret == GST_SDP_OK);
|
||||||
|
gst_caps_unref (caps_audio);
|
||||||
|
|
||||||
|
gst_sdp_message_new (&message);
|
||||||
|
gst_sdp_message_parse_buffer ((guint8 *) sdp, length, message);
|
||||||
|
|
||||||
|
result_video = gst_sdp_message_get_media (message, 0);
|
||||||
|
fail_unless (result_video != NULL);
|
||||||
|
|
||||||
|
result_audio = gst_sdp_message_get_media (message, 2);
|
||||||
|
fail_unless (result_audio != NULL);
|
||||||
|
|
||||||
|
media1_text = gst_sdp_media_get_attribute_val (media_video, "rtpmap");
|
||||||
|
media2_text = gst_sdp_media_get_attribute_val (result_video, "rtpmap");
|
||||||
|
media3_text = gst_sdp_media_get_format (media_audio, 0);
|
||||||
|
media4_text = gst_sdp_media_get_format (result_audio, 0);
|
||||||
|
|
||||||
|
fail_if (g_strcmp0 (media1_text, media2_text) != 0);
|
||||||
|
fail_if (g_strcmp0 (media3_text, media4_text) != 0);
|
||||||
|
|
||||||
|
gst_sdp_media_free (media_video);
|
||||||
|
gst_sdp_media_free (media_audio);
|
||||||
|
gst_sdp_message_free (message);
|
||||||
|
}
|
||||||
|
|
||||||
GST_END_TEST
|
GST_END_TEST
|
||||||
/*
|
/*
|
||||||
* End of test cases
|
* End of test cases
|
||||||
|
@ -207,6 +310,8 @@ sdp_suite (void)
|
||||||
tcase_add_test (tc_chain, copy);
|
tcase_add_test (tc_chain, copy);
|
||||||
tcase_add_test (tc_chain, boxed);
|
tcase_add_test (tc_chain, boxed);
|
||||||
tcase_add_test (tc_chain, modify);
|
tcase_add_test (tc_chain, modify);
|
||||||
|
tcase_add_test (tc_chain, caps_from_media);
|
||||||
|
tcase_add_test (tc_chain, media_from_caps);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ EXPORTS
|
||||||
gst_mikey_message_add_rand_len
|
gst_mikey_message_add_rand_len
|
||||||
gst_mikey_message_add_t
|
gst_mikey_message_add_t
|
||||||
gst_mikey_message_add_t_now_ntp_utc
|
gst_mikey_message_add_t_now_ntp_utc
|
||||||
|
gst_mikey_message_base64_encode
|
||||||
gst_mikey_message_find_payload
|
gst_mikey_message_find_payload
|
||||||
gst_mikey_message_get_cs_srtp
|
gst_mikey_message_get_cs_srtp
|
||||||
gst_mikey_message_get_n_cs
|
gst_mikey_message_get_n_cs
|
||||||
|
@ -16,6 +17,7 @@ EXPORTS
|
||||||
gst_mikey_message_insert_payload
|
gst_mikey_message_insert_payload
|
||||||
gst_mikey_message_new
|
gst_mikey_message_new
|
||||||
gst_mikey_message_new_from_bytes
|
gst_mikey_message_new_from_bytes
|
||||||
|
gst_mikey_message_new_from_caps
|
||||||
gst_mikey_message_new_from_data
|
gst_mikey_message_new_from_data
|
||||||
gst_mikey_message_remove_cs_srtp
|
gst_mikey_message_remove_cs_srtp
|
||||||
gst_mikey_message_remove_payload
|
gst_mikey_message_remove_payload
|
||||||
|
@ -49,12 +51,14 @@ EXPORTS
|
||||||
gst_sdp_bandwidth_set
|
gst_sdp_bandwidth_set
|
||||||
gst_sdp_connection_clear
|
gst_sdp_connection_clear
|
||||||
gst_sdp_connection_set
|
gst_sdp_connection_set
|
||||||
|
gst_sdp_make_keymgmt
|
||||||
gst_sdp_media_add_attribute
|
gst_sdp_media_add_attribute
|
||||||
gst_sdp_media_add_bandwidth
|
gst_sdp_media_add_bandwidth
|
||||||
gst_sdp_media_add_connection
|
gst_sdp_media_add_connection
|
||||||
gst_sdp_media_add_format
|
gst_sdp_media_add_format
|
||||||
gst_sdp_media_as_text
|
gst_sdp_media_as_text
|
||||||
gst_sdp_media_attributes_len
|
gst_sdp_media_attributes_len
|
||||||
|
gst_sdp_media_attributes_to_caps
|
||||||
gst_sdp_media_bandwidths_len
|
gst_sdp_media_bandwidths_len
|
||||||
gst_sdp_media_connections_len
|
gst_sdp_media_connections_len
|
||||||
gst_sdp_media_copy
|
gst_sdp_media_copy
|
||||||
|
@ -64,6 +68,7 @@ EXPORTS
|
||||||
gst_sdp_media_get_attribute_val
|
gst_sdp_media_get_attribute_val
|
||||||
gst_sdp_media_get_attribute_val_n
|
gst_sdp_media_get_attribute_val_n
|
||||||
gst_sdp_media_get_bandwidth
|
gst_sdp_media_get_bandwidth
|
||||||
|
gst_sdp_media_get_caps_from_media
|
||||||
gst_sdp_media_get_connection
|
gst_sdp_media_get_connection
|
||||||
gst_sdp_media_get_format
|
gst_sdp_media_get_format
|
||||||
gst_sdp_media_get_information
|
gst_sdp_media_get_information
|
||||||
|
@ -89,6 +94,7 @@ EXPORTS
|
||||||
gst_sdp_media_set_information
|
gst_sdp_media_set_information
|
||||||
gst_sdp_media_set_key
|
gst_sdp_media_set_key
|
||||||
gst_sdp_media_set_media
|
gst_sdp_media_set_media
|
||||||
|
gst_sdp_media_set_media_from_caps
|
||||||
gst_sdp_media_set_port_info
|
gst_sdp_media_set_port_info
|
||||||
gst_sdp_media_set_proto
|
gst_sdp_media_set_proto
|
||||||
gst_sdp_media_uninit
|
gst_sdp_media_uninit
|
||||||
|
@ -102,6 +108,7 @@ EXPORTS
|
||||||
gst_sdp_message_as_text
|
gst_sdp_message_as_text
|
||||||
gst_sdp_message_as_uri
|
gst_sdp_message_as_uri
|
||||||
gst_sdp_message_attributes_len
|
gst_sdp_message_attributes_len
|
||||||
|
gst_sdp_message_attributes_to_caps
|
||||||
gst_sdp_message_bandwidths_len
|
gst_sdp_message_bandwidths_len
|
||||||
gst_sdp_message_copy
|
gst_sdp_message_copy
|
||||||
gst_sdp_message_dump
|
gst_sdp_message_dump
|
||||||
|
|
Loading…
Reference in a new issue