netsim: add "allow-reordering" property

Reordering of packets is not very common in networks, and the delay
functions will always introduce reordering if delay > packet-spacing,
so by setting allow-reordering to FALSE you guarantee that the packets
are in order, while at the same time introducing delay/jitter to them.
This commit is contained in:
Havard Graff 2016-11-01 16:03:00 +01:00 committed by Tim-Philipp Müller
parent c9002e3dd5
commit b8b4124c8b
2 changed files with 52 additions and 3 deletions

View file

@ -65,6 +65,7 @@ enum
PROP_DROP_PACKETS, PROP_DROP_PACKETS,
PROP_MAX_KBPS, PROP_MAX_KBPS,
PROP_MAX_BUCKET_SIZE, PROP_MAX_BUCKET_SIZE,
PROP_ALLOW_REORDERING,
}; };
/* these numbers are nothing but wild guesses and dont reflect any reality */ /* these numbers are nothing but wild guesses and dont reflect any reality */
@ -77,6 +78,7 @@ enum
#define DEFAULT_DROP_PACKETS 0 #define DEFAULT_DROP_PACKETS 0
#define DEFAULT_MAX_KBPS -1 #define DEFAULT_MAX_KBPS -1
#define DEFAULT_MAX_BUCKET_SIZE -1 #define DEFAULT_MAX_BUCKET_SIZE -1
#define DEFAULT_ALLOW_REORDERING TRUE
static GstStaticPadTemplate gst_net_sim_sink_template = static GstStaticPadTemplate gst_net_sim_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
@ -92,6 +94,21 @@ GST_STATIC_PAD_TEMPLATE ("src",
G_DEFINE_TYPE (GstNetSim, gst_net_sim, GST_TYPE_ELEMENT); G_DEFINE_TYPE (GstNetSim, gst_net_sim, GST_TYPE_ELEMENT);
static gboolean
gst_net_sim_source_dispatch (GSource * source,
GSourceFunc callback, gpointer user_data)
{
callback (user_data);
return FALSE;
}
GSourceFuncs gst_net_sim_source_funcs = {
NULL, /* prepare */
NULL, /* check */
gst_net_sim_source_dispatch,
NULL /* finalize */
};
static void static void
gst_net_sim_loop (GstNetSim * netsim) gst_net_sim_loop (GstNetSim * netsim)
{ {
@ -309,7 +326,6 @@ get_random_value_gamma (GRand * rand_seed, gint32 low, gint32 high,
return round (x + low); return round (x + low);
} }
static GstFlowReturn static GstFlowReturn
gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf) gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf)
{ {
@ -321,6 +337,7 @@ gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf)
gint delay; gint delay;
PushBufferCtx *ctx; PushBufferCtx *ctx;
GSource *source; GSource *source;
gint64 ready_time;
switch (netsim->delay_distribution) { switch (netsim->delay_distribution) {
case DISTRIBUTION_UNIFORM: case DISTRIBUTION_UNIFORM:
@ -344,9 +361,17 @@ gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf)
delay = 0; delay = 0;
ctx = push_buffer_ctx_new (netsim->srcpad, buf); ctx = push_buffer_ctx_new (netsim->srcpad, buf);
source = g_timeout_source_new (delay);
GST_DEBUG_OBJECT (netsim, "Delaying packet by %d", delay); source = g_source_new (&gst_net_sim_source_funcs, sizeof (GSource));
ready_time = g_get_monotonic_time () + delay * 1000;
if (!netsim->allow_reordering && ready_time < netsim->last_ready_time)
ready_time = netsim->last_ready_time + 1;
GST_DEBUG_OBJECT (netsim, "Delaying packet by %ldms",
(ready_time - netsim->last_ready_time) / 1000);
netsim->last_ready_time = ready_time;
g_source_set_ready_time (source, ready_time);
g_source_set_callback (source, (GSourceFunc) push_buffer_ctx_push, g_source_set_callback (source, (GSourceFunc) push_buffer_ctx_push,
ctx, (GDestroyNotify) push_buffer_ctx_free); ctx, (GDestroyNotify) push_buffer_ctx_free);
g_source_attach (source, g_main_loop_get_context (netsim->main_loop)); g_source_attach (source, g_main_loop_get_context (netsim->main_loop));
@ -518,6 +543,9 @@ gst_net_sim_set_property (GObject * object,
if (netsim->max_bucket_size != -1) if (netsim->max_bucket_size != -1)
netsim->bucket_size = netsim->max_bucket_size * 1000; netsim->bucket_size = netsim->max_bucket_size * 1000;
break; break;
case PROP_ALLOW_REORDERING:
netsim->allow_reordering = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -558,6 +586,9 @@ gst_net_sim_get_property (GObject * object,
case PROP_MAX_BUCKET_SIZE: case PROP_MAX_BUCKET_SIZE:
g_value_set_int (value, netsim->max_bucket_size); g_value_set_int (value, netsim->max_bucket_size);
break; break;
case PROP_ALLOW_REORDERING:
g_value_set_boolean (value, netsim->allow_reordering);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -714,6 +745,22 @@ gst_net_sim_class_init (GstNetSimClass * klass)
"(-1 = unlimited)", -1, G_MAXINT, DEFAULT_MAX_BUCKET_SIZE, "(-1 = unlimited)", -1, G_MAXINT, DEFAULT_MAX_BUCKET_SIZE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
/**
* GstNetSim:allow-reordering:
*
* When delaying packets, are they allowed to be reordered or not. By
* default this is enabled, but in the real world packet reordering is
* fairly uncommon, yet the delay functions will always introduce reordering
* if delay > packet-spacing, This property allows switching that off.
*
* Since: 1.14
*/
g_object_class_install_property (gobject_class, PROP_ALLOW_REORDERING,
g_param_spec_boolean ("allow-reordering", "Allow Reordering",
"When delaying packets, are they allowed to be reordered or not",
DEFAULT_ALLOW_REORDERING,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
GST_DEBUG_CATEGORY_INIT (netsim_debug, "netsim", 0, "Network simulator"); GST_DEBUG_CATEGORY_INIT (netsim_debug, "netsim", 0, "Network simulator");
} }

View file

@ -75,6 +75,7 @@ struct _GstNetSim
gsize bucket_size; gsize bucket_size;
GstClockTime prev_time; GstClockTime prev_time;
NormalDistributionState delay_state; NormalDistributionState delay_state;
gint64 last_ready_time;
/* properties */ /* properties */
gint min_delay; gint min_delay;
@ -86,6 +87,7 @@ struct _GstNetSim
guint drop_packets; guint drop_packets;
gint max_kbps; gint max_kbps;
gint max_bucket_size; gint max_bucket_size;
gboolean allow_reordering;
}; };
struct _GstNetSimClass struct _GstNetSimClass