diff --git a/gst/netsim/gstnetsim.c b/gst/netsim/gstnetsim.c index 29a2f70444..24ea04a68c 100644 --- a/gst/netsim/gstnetsim.c +++ b/gst/netsim/gstnetsim.c @@ -65,6 +65,7 @@ enum PROP_DROP_PACKETS, PROP_MAX_KBPS, PROP_MAX_BUCKET_SIZE, + PROP_ALLOW_REORDERING, }; /* these numbers are nothing but wild guesses and dont reflect any reality */ @@ -77,6 +78,7 @@ enum #define DEFAULT_DROP_PACKETS 0 #define DEFAULT_MAX_KBPS -1 #define DEFAULT_MAX_BUCKET_SIZE -1 +#define DEFAULT_ALLOW_REORDERING TRUE static GstStaticPadTemplate gst_net_sim_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", @@ -92,6 +94,21 @@ GST_STATIC_PAD_TEMPLATE ("src", 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 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); } - static GstFlowReturn gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf) { @@ -321,6 +337,7 @@ gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf) gint delay; PushBufferCtx *ctx; GSource *source; + gint64 ready_time; switch (netsim->delay_distribution) { case DISTRIBUTION_UNIFORM: @@ -344,9 +361,17 @@ gst_net_sim_delay_buffer (GstNetSim * netsim, GstBuffer * buf) delay = 0; 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, ctx, (GDestroyNotify) push_buffer_ctx_free); 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) netsim->bucket_size = netsim->max_bucket_size * 1000; break; + case PROP_ALLOW_REORDERING: + netsim->allow_reordering = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -558,6 +586,9 @@ gst_net_sim_get_property (GObject * object, case PROP_MAX_BUCKET_SIZE: g_value_set_int (value, netsim->max_bucket_size); break; + case PROP_ALLOW_REORDERING: + g_value_set_boolean (value, netsim->allow_reordering); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -714,6 +745,22 @@ gst_net_sim_class_init (GstNetSimClass * klass) "(-1 = unlimited)", -1, G_MAXINT, DEFAULT_MAX_BUCKET_SIZE, 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"); } diff --git a/gst/netsim/gstnetsim.h b/gst/netsim/gstnetsim.h index c9e32d8fdb..bfbfa3f9f5 100644 --- a/gst/netsim/gstnetsim.h +++ b/gst/netsim/gstnetsim.h @@ -75,6 +75,7 @@ struct _GstNetSim gsize bucket_size; GstClockTime prev_time; NormalDistributionState delay_state; + gint64 last_ready_time; /* properties */ gint min_delay; @@ -86,6 +87,7 @@ struct _GstNetSim guint drop_packets; gint max_kbps; gint max_bucket_size; + gboolean allow_reordering; }; struct _GstNetSimClass