srtobject: make possible to specify more sockopts in SRT URI

Any socket option that can be passed to libsrt's srt-live-transmit
through SRT URI query string is now recognized.

Also make the code that applies options to SRT sockets more generic.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1842>
This commit is contained in:
Jakub Adam 2020-11-24 22:25:15 +01:00 committed by GStreamer Merge Bot
parent 5687b03438
commit 3c3e89304e

View file

@ -133,6 +133,52 @@ static const struct srt_constant_params srt_params[] = {
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
typedef struct
{
const gchar *name;
SRT_SOCKOPT opt;
GType gtype;
} SrtOption;
SrtOption srt_options[] = {
{"mss", SRTO_MSS, G_TYPE_INT},
{"fc", SRTO_FC, G_TYPE_INT},
{"sndbuf", SRTO_SNDBUF, G_TYPE_INT},
{"rcvbuf", SRTO_RCVBUF, G_TYPE_INT},
{"maxbw", SRTO_MAXBW, G_TYPE_INT64},
{"tsbpdmode", SRTO_TSBPDMODE, G_TYPE_BOOLEAN},
{"latency", SRTO_LATENCY, G_TYPE_INT},
{"inputbw", SRTO_INPUTBW, G_TYPE_INT64},
{"oheadbw", SRTO_OHEADBW, G_TYPE_INT},
{"passphrase", SRTO_PASSPHRASE, G_TYPE_STRING},
{"pbkeylen", SRTO_PBKEYLEN, G_TYPE_INT},
{"ipttl", SRTO_IPTTL, G_TYPE_INT},
{"iptos", SRTO_IPTOS, G_TYPE_INT},
{"tlpktdrop", SRTO_TLPKTDROP, G_TYPE_BOOLEAN},
{"snddropdelay", SRTO_SNDDROPDELAY, G_TYPE_INT},
{"nakreport", SRTO_NAKREPORT, G_TYPE_BOOLEAN},
{"conntimeo", SRTO_CONNTIMEO, G_TYPE_INT},
{"drifttracer", SRTO_DRIFTTRACER, G_TYPE_BOOLEAN},
{"lossmaxttl", SRTO_LOSSMAXTTL, G_TYPE_INT},
{"rcvlatency", SRTO_RCVLATENCY, G_TYPE_INT},
{"peerlatency", SRTO_PEERLATENCY, G_TYPE_INT},
{"minversion", SRTO_MINVERSION, G_TYPE_INT},
{"streamid", SRTO_STREAMID, G_TYPE_STRING},
{"congestion", SRTO_CONGESTION, G_TYPE_STRING},
{"messageapi", SRTO_MESSAGEAPI, G_TYPE_BOOLEAN},
{"payloadsize", SRTO_PAYLOADSIZE, G_TYPE_INT},
{"transtype", SRTO_TRANSTYPE, G_TYPE_INT},
{"kmrefreshrate", SRTO_KMREFRESHRATE, G_TYPE_INT},
{"kmpreannounce", SRTO_KMPREANNOUNCE, G_TYPE_INT},
{"enforcedencryption", SRTO_ENFORCEDENCRYPTION, G_TYPE_BOOLEAN},
{"ipv6only", SRTO_IPV6ONLY, G_TYPE_INT},
{"peeridletimeo", SRTO_PEERIDLETIMEO, G_TYPE_INT},
{"bindtodevice", SRTO_BINDTODEVICE, G_TYPE_STRING},
{"packetfilter", SRTO_PACKETFILTER, G_TYPE_STRING},
{"retransmitalgo", SRTO_RETRANSMITALGO, G_TYPE_INT},
{NULL}
};
static gint srt_init_refcount = 0; static gint srt_init_refcount = 0;
static GSocketAddress * static GSocketAddress *
@ -185,12 +231,69 @@ name_resolve:
} }
} }
static gboolean
gst_srt_object_apply_socket_option (SRTSOCKET sock, SrtOption * option,
const GValue * value, GError ** error)
{
union
{
int32_t i;
int64_t i64;
gboolean b;
const gchar *c;
} u;
const void *optval = &u;
gint optlen;
if (!G_VALUE_HOLDS (value, option->gtype)) {
goto bad_type;
}
switch (option->gtype) {
case G_TYPE_INT:
u.i = g_value_get_int (value);
optlen = sizeof u.i;
break;
case G_TYPE_INT64:
u.i64 = g_value_get_int64 (value);
optlen = sizeof u.i64;
break;
case G_TYPE_BOOLEAN:
u.b = g_value_get_boolean (value);
optlen = sizeof u.b;
break;
case G_TYPE_STRING:
u.c = g_value_get_string (value);
optval = u.c;
optlen = u.c ? strlen (u.c) : 0;
if (optlen == 0) {
return TRUE;
}
break;
default:
goto bad_type;
}
if (srt_setsockopt (sock, 0, option->opt, optval, optlen)) {
g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_SETTINGS,
"failed to set %s (reason: %s)", option->name, srt_getlasterror_str ());
return FALSE;
}
return TRUE;
bad_type:
g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_SETTINGS,
"option %s has unsupported type", option->name);
return FALSE;
}
static gboolean static gboolean
gst_srt_object_set_common_params (SRTSOCKET sock, GstSRTObject * srtobject, gst_srt_object_set_common_params (SRTSOCKET sock, GstSRTObject * srtobject,
GError ** error) GError ** error)
{ {
const struct srt_constant_params *params = srt_params; const struct srt_constant_params *params = srt_params;
const gchar *passphrase; SrtOption *option = srt_options;
GST_OBJECT_LOCK (srtobject->element); GST_OBJECT_LOCK (srtobject->element);
@ -203,51 +306,13 @@ gst_srt_object_set_common_params (SRTSOCKET sock, GstSRTObject * srtobject,
} }
} }
passphrase = gst_structure_get_string (srtobject->parameters, "passphrase"); for (; option->name; ++option) {
if (passphrase != NULL && passphrase[0] != '\0') { const GValue *val;
int32_t pbkeylen;
if (srt_setsockopt (sock, 0, SRTO_PASSPHRASE, passphrase,
strlen (passphrase))) {
g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_SETTINGS,
"failed to set passphrase (reason: %s)", srt_getlasterror_str ());
val = gst_structure_get_value (srtobject->parameters, option->name);
if (val && !gst_srt_object_apply_socket_option (sock, option, val, error)) {
goto err; goto err;
} }
if (!gst_structure_get_int (srtobject->parameters, "pbkeylen", &pbkeylen)) {
pbkeylen = GST_SRT_DEFAULT_PBKEYLEN;
}
if (srt_setsockopt (sock, 0, SRTO_PBKEYLEN, &pbkeylen, sizeof pbkeylen)) {
g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_SETTINGS,
"failed to set pbkeylen (reason: %s)", srt_getlasterror_str ());
goto err;
}
}
{
int32_t latency;
if (!gst_structure_get_int (srtobject->parameters, "latency", &latency))
latency = GST_SRT_DEFAULT_LATENCY;
if (srt_setsockopt (sock, 0, SRTO_LATENCY, &latency, sizeof latency)) {
g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_SETTINGS,
"failed to set latency (reason: %s)", srt_getlasterror_str ());
goto err;
}
}
if (gst_structure_has_field (srtobject->parameters, "streamid")) {
const gchar *streamid;
streamid = gst_structure_get_string (srtobject->parameters, "streamid");
if (streamid != NULL && streamid[0] != '\0') {
if (srt_setsockopt (sock, 0, SRTO_STREAMID, streamid, strlen (streamid))) {
g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_SETTINGS,
"failed to set stream ID (reason: %s)", srt_getlasterror_str ());
}
}
} }
GST_OBJECT_UNLOCK (srtobject->element); GST_OBJECT_UNLOCK (srtobject->element);
@ -339,7 +404,8 @@ gst_srt_object_set_property_helper (GstSRTObject * srtobject,
gst_structure_set_value (srtobject->parameters, "passphrase", value); gst_structure_set_value (srtobject->parameters, "passphrase", value);
break; break;
case PROP_PBKEYLEN: case PROP_PBKEYLEN:
gst_structure_set_value (srtobject->parameters, "pbkeylen", value); gst_structure_set (srtobject->parameters, "pbkeylen", G_TYPE_INT,
g_value_get_enum (value), NULL);
break; break;
case PROP_WAIT_FOR_CONNECTION: case PROP_WAIT_FOR_CONNECTION:
srtobject->wait_for_connection = g_value_get_boolean (value); srtobject->wait_for_connection = g_value_get_boolean (value);
@ -407,8 +473,8 @@ gst_srt_object_get_property_helper (GstSRTObject * srtobject,
GstSRTKeyLength v; GstSRTKeyLength v;
GST_OBJECT_LOCK (srtobject->element); GST_OBJECT_LOCK (srtobject->element);
if (!gst_structure_get_enum (srtobject->parameters, "pbkeylen", if (!gst_structure_get_int (srtobject->parameters, "pbkeylen",
GST_TYPE_SRT_KEY_LENGTH, (gint *) & v)) { (gint *) & v)) {
GST_WARNING_OBJECT (srtobject->element, "Failed to get 'pbkeylen'"); GST_WARNING_OBJECT (srtobject->element, "Failed to get 'pbkeylen'");
v = GST_SRT_KEY_LENGTH_NO_KEY; v = GST_SRT_KEY_LENGTH_NO_KEY;
} }
@ -659,6 +725,65 @@ gst_srt_object_set_int_value (GstStructure * s, const gchar * key,
(gint) g_ascii_strtoll (value, NULL, 10), NULL); (gint) g_ascii_strtoll (value, NULL, 10), NULL);
} }
static void
gst_srt_object_set_int64_value (GstStructure * s, const gchar * key,
const gchar * value)
{
gst_structure_set (s, key, G_TYPE_INT64,
g_ascii_strtoll (value, NULL, 10), NULL);
}
static void
gst_srt_object_set_boolean_value (GstStructure * s, const gchar * key,
const gchar * value)
{
gboolean bool_val;
static const gchar *true_names[] = {
"1", "yes", "on", "true", NULL
};
static const gchar *false_names[] = {
"0", "no", "off", "false", NULL
};
if (g_strv_contains (true_names, value)) {
bool_val = TRUE;
} else if (g_strv_contains (false_names, value)) {
bool_val = FALSE;
} else {
return;
}
gst_structure_set (s, key, G_TYPE_BOOLEAN, bool_val, NULL);
}
static void
gst_srt_object_set_socket_option (GstStructure * s, const gchar * key,
const gchar * value)
{
SrtOption *option = srt_options;
for (; option; ++option) {
if (g_str_equal (key, option->name)) {
switch (option->gtype) {
case G_TYPE_INT:
gst_srt_object_set_int_value (s, key, value);
break;
case G_TYPE_INT64:
gst_srt_object_set_int64_value (s, key, value);
break;
case G_TYPE_STRING:
gst_srt_object_set_string_value (s, key, value);
break;
case G_TYPE_BOOLEAN:
gst_srt_object_set_boolean_value (s, key, value);
break;
}
break;
}
}
}
static void static void
gst_srt_object_validate_parameters (GstStructure * s, GstUri * uri) gst_srt_object_validate_parameters (GstStructure * s, GstUri * uri)
{ {
@ -747,17 +872,10 @@ gst_srt_object_set_uri (GstSRTObject * srtobject, const gchar * uri,
gst_srt_object_set_string_value (srtobject->parameters, key, value); gst_srt_object_set_string_value (srtobject->parameters, key, value);
} else if (!g_strcmp0 ("localport", key)) { } else if (!g_strcmp0 ("localport", key)) {
gst_srt_object_set_uint_value (srtobject->parameters, key, value); gst_srt_object_set_uint_value (srtobject->parameters, key, value);
} else if (!g_strcmp0 ("passphrase", key)) {
gst_srt_object_set_string_value (srtobject->parameters, key, value);
} else if (!g_strcmp0 ("pbkeylen", key)) {
gst_srt_object_set_enum_value (srtobject->parameters,
GST_TYPE_SRT_KEY_LENGTH, key, value);
} else if (!g_strcmp0 ("streamid", key)) {
gst_srt_object_set_string_value (srtobject->parameters, key, value);
} else if (!g_strcmp0 ("latency", key)) {
gst_srt_object_set_int_value (srtobject->parameters, key, value);
} else if (!g_strcmp0 ("poll-timeout", key)) { } else if (!g_strcmp0 ("poll-timeout", key)) {
gst_srt_object_set_int_value (srtobject->parameters, key, value); gst_srt_object_set_int_value (srtobject->parameters, key, value);
} else {
gst_srt_object_set_socket_option (srtobject->parameters, key, value);
} }
} }