static void remb_event_manager_update_min (RembEventManager * manager, guint bitrate, guint ssrc) { RembHashValue *last_value, *value; g_mutex_lock (&manager->mutex); last_value = g_hash_table_lookup (manager->remb_hash, GUINT_TO_POINTER (ssrc)); if (last_value != NULL && bitrate == last_value->bitrate) { last_value->ts = kms_utils_get_time_nsecs (); goto end; } value = remb_hash_value_create (bitrate); g_hash_table_insert (manager->remb_hash, GUINT_TO_POINTER (ssrc), value); if (bitrate > manager->remb_min) { remb_event_manager_calc_min (manager); } else { remb_event_manager_set_min (manager, bitrate); } end: GST_TRACE_OBJECT (manager->pad, "remb_min: %" G_GUINT32_FORMAT, manager->remb_min); g_mutex_unlock (&manager->mutex); }
static void remb_event_manager_calc_min (RembEventManager * manager) { guint remb_min = 0; GstClockTime time = kms_utils_get_time_nsecs (); GstClockTime oldest_time = GST_CLOCK_TIME_NONE; GHashTableIter iter; gpointer key, v; g_hash_table_iter_init (&iter, manager->remb_hash); while (g_hash_table_iter_next (&iter, &key, &v)) { guint br = ((RembHashValue *) v)->bitrate; GstClockTime ts = ((RembHashValue *) v)->ts; if (time - ts > REMB_HASH_CLEAR_INTERVAL) { GST_TRACE ("Remove entry %" G_GUINT32_FORMAT, GPOINTER_TO_UINT (key)); g_hash_table_iter_remove (&iter); continue; } if (remb_min == 0) { remb_min = br; } else { remb_min = MIN (remb_min, br); } oldest_time = MIN (oldest_time, ts); } manager->oldest_remb_value = oldest_time; remb_event_manager_set_min (manager, remb_min); }
static void buffer_latency_probe_cb (GstBuffer * buffer, ProbeData * pdata) { BufferLatencyValues *blv = (BufferLatencyValues *) pdata->invoke_data; GstClockTime time; time = kms_utils_get_time_nsecs (); kms_buffer_add_buffer_latency_meta (buffer, time, blv->valid, blv->type); }
static RembHashValue * remb_hash_value_create (guint bitrate) { RembHashValue *value = g_slice_new0 (RembHashValue); value->bitrate = bitrate; value->ts = kms_utils_get_time_nsecs (); return value; }
static void remb_event_manager_update_min (RembEventManager * manager, guint bitrate, guint ssrc) { RembHashValue *last_value; GstClockTime time = kms_utils_get_time_nsecs (); gboolean new_br = TRUE; g_mutex_lock (&manager->mutex); last_value = g_hash_table_lookup (manager->remb_hash, GUINT_TO_POINTER (ssrc)); if (last_value != NULL) { new_br = bitrate != last_value->bitrate; last_value->bitrate = bitrate; last_value->ts = kms_utils_get_time_nsecs (); } else { RembHashValue *value; value = remb_hash_value_create (bitrate); g_hash_table_insert (manager->remb_hash, GUINT_TO_POINTER (ssrc), value); } if (bitrate < manager->remb_min) { remb_event_manager_set_min (manager, bitrate); } else { gboolean calc_min; calc_min = new_br && (bitrate > manager->remb_min); calc_min = calc_min || (time - manager->oldest_remb_time > manager->clear_interval); if (calc_min) { remb_event_manager_calc_min (manager, bitrate); } } GST_TRACE_OBJECT (manager->pad, "remb_min: %" G_GUINT32_FORMAT, manager->remb_min); g_mutex_unlock (&manager->mutex); }
RembEventManager * kms_utils_remb_event_manager_create (GstPad * pad) { RembEventManager *manager = g_slice_new0 (RembEventManager); g_mutex_init (&manager->mutex); manager->remb_hash = g_hash_table_new_full (NULL, NULL, NULL, remb_hash_value_destroy); manager->pad = g_object_ref (pad); manager->probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, remb_probe, manager, NULL); manager->oldest_remb_value = kms_utils_get_time_nsecs (); return manager; }
guint kms_utils_remb_event_manager_get_min (RembEventManager * manager) { GstClockTime time = kms_utils_get_time_nsecs (); guint ret; g_mutex_lock (&manager->mutex); if (time - manager->oldest_remb_value > REMB_HASH_CLEAR_INTERVAL) { remb_event_manager_calc_min (manager); } ret = manager->remb_min; g_mutex_unlock (&manager->mutex); return ret; }
guint kms_utils_remb_event_manager_get_min (RembEventManager * manager) { GstClockTime time = kms_utils_get_time_nsecs (); guint ret; g_mutex_lock (&manager->mutex); if (time - manager->oldest_remb_time > manager->clear_interval) { remb_event_manager_calc_min (manager, 0); } ret = manager->remb_min; g_mutex_unlock (&manager->mutex); return ret; }
static gboolean buffer_for_each_meta_cb (GstBuffer * buffer, GstMeta ** meta, ProbeData * pdata) { BufferLatencyCallback func = (BufferLatencyCallback) pdata->cb; GstPad *pad = GST_PAD (pdata->invoke_data); KmsBufferLatencyMeta *blmeta; GstClockTimeDiff diff; GstClockTime now; if ((*meta)->info->api != KMS_BUFFER_LATENCY_META_API_TYPE) { /* continue iterating */ return TRUE; } blmeta = (KmsBufferLatencyMeta *) * meta; if (!blmeta->valid) { /* Ignore this meta */ return TRUE; } if (func == NULL) { return TRUE; } now = kms_utils_get_time_nsecs (); diff = GST_CLOCK_DIFF (blmeta->ts, now); if (pdata->locked) { KMS_BUFFER_LATENCY_DATA_LOCK (blmeta); } func (pad, blmeta->type, diff, blmeta->data, pdata->user_data); if (pdata->locked) { KMS_BUFFER_LATENCY_DATA_UNLOCK (blmeta); } return TRUE; }
static gboolean get_video_recv_info (KmsRembLocal * rl, guint64 * bitrate, guint * fraction_lost, guint64 * packets_rcv_interval) { GValueArray *arr = NULL; GValue *val; guint i; gboolean ret = FALSE; if (!KMS_REMB_BASE (rl)->rtpsess) { GST_WARNING ("Session object does not exist"); return ret; } g_object_get (KMS_REMB_BASE (rl)->rtpsess, "sources", &arr, NULL); if (arr == NULL) { GST_WARNING ("Sources array not found"); return ret; } for (i = 0; i < arr->n_values; i++) { GObject *source; guint ssrc; GstStructure *s; val = g_value_array_get_nth (arr, i); source = g_value_get_object (val); g_object_get (source, "ssrc", &ssrc, "stats", &s, NULL); GST_TRACE_OBJECT (source, "source ssrc: %u", ssrc); GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "stats: %" GST_PTR_FORMAT, s); if (ssrc == rl->remote_ssrc) { GstClockTime current_time; guint64 octets_received, packets_received; if (!gst_structure_get_uint64 (s, "bitrate", bitrate)) { break; } if (!gst_structure_get_uint64 (s, "octets-received", &octets_received)) { break; } if (!gst_structure_get_uint (s, "sent-rb-fractionlost", fraction_lost)) { break; } if (!gst_structure_get_uint64 (s, "packets-received", &packets_received)) { break; } current_time = kms_utils_get_time_nsecs (); if (rl->last_time != 0) { GstClockTime elapsed = current_time - rl->last_time; guint64 bytes_handled = octets_received - rl->last_octets_received; *bitrate = gst_util_uint64_scale (bytes_handled, 8 * GST_SECOND, elapsed); GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "Elapsed %" G_GUINT64_FORMAT " bytes %" G_GUINT64_FORMAT ", rate %" G_GUINT64_FORMAT, elapsed, bytes_handled, *bitrate); } rl->last_time = current_time; rl->last_octets_received = octets_received; *packets_rcv_interval = packets_received - rl->last_packets_received; rl->last_packets_received = packets_received; ret = TRUE; } gst_structure_free (s); if (ret) { break; } } g_value_array_free (arr); return ret; }