rtpsession: Use bandwidth calculation by default instead of some arbitrary hardcoded...
[platform/upstream/gst-plugins-good.git] / gst / rtpmanager / rtpsession.c
index 85c9ca2..a260186 100644 (file)
@@ -55,8 +55,8 @@ enum
 };
 
 #define DEFAULT_INTERNAL_SOURCE      NULL
-#define DEFAULT_BANDWIDTH            RTP_STATS_BANDWIDTH
-#define DEFAULT_RTCP_FRACTION        (RTP_STATS_RTCP_FRACTION * RTP_STATS_BANDWIDTH)
+#define DEFAULT_BANDWIDTH            0.0
+#define DEFAULT_RTCP_FRACTION        RTP_STATS_RTCP_FRACTION
 #define DEFAULT_RTCP_RR_BANDWIDTH    -1
 #define DEFAULT_RTCP_RS_BANDWIDTH    -1
 #define DEFAULT_RTCP_MTU             1400
@@ -88,8 +88,7 @@ enum
   PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
   PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
   PROP_PROBATION,
-  PROP_STATS,
-  PROP_LAST
+  PROP_STATS
 };
 
 /* update average packet size */
@@ -505,13 +504,23 @@ rtp_session_class_init (RTPSessionClass * klass)
 static void
 rtp_session_init (RTPSession * sess)
 {
+  gint i;
   gchar *str;
 
   g_mutex_init (&sess->lock);
   sess->key = g_random_int ();
+  sess->mask_idx = 0;
+  sess->mask = 0;
 
-  sess->ssrcs = g_hash_table_new_full (NULL, NULL, NULL,
-      (GDestroyNotify) g_object_unref);
+  /* TODO: We currently only use the first hash table but this is the
+   * beginning of an implementation for RFC2762
+   for (i = 0; i < 32; i++) {
+   */
+  for (i = 0; i < 1; i++) {
+    sess->ssrcs[i] =
+        g_hash_table_new_full (NULL, NULL, NULL,
+        (GDestroyNotify) g_object_unref);
+  }
 
   rtp_stats_init_defaults (&sess->stats);
   INIT_AVG (sess->stats.avg_rtcp_packet_size, 100);
@@ -569,6 +578,7 @@ static void
 rtp_session_finalize (GObject * object)
 {
   RTPSession *sess;
+  gint i;
 
   sess = RTP_SESSION_CAST (object);
 
@@ -577,7 +587,11 @@ rtp_session_finalize (GObject * object)
   g_list_free_full (sess->conflicting_addresses,
       (GDestroyNotify) rtp_conflicting_address_free);
 
-  g_hash_table_destroy (sess->ssrcs);
+  /* TODO: Change this again when implementing RFC 2762
+   * for (i = 0; i < 32; i++)
+   */
+  for (i = 0; i < 1; i++)
+    g_hash_table_destroy (sess->ssrcs[i]);
 
   g_mutex_clear (&sess->lock);
 
@@ -603,12 +617,12 @@ rtp_session_create_sources (RTPSession * sess)
 
   RTP_SESSION_LOCK (sess);
   /* get number of elements in the table */
-  size = g_hash_table_size (sess->ssrcs);
+  size = g_hash_table_size (sess->ssrcs[sess->mask_idx]);
   /* create the result value array */
   res = g_value_array_new (size);
 
   /* and copy all values into the array */
-  g_hash_table_foreach (sess->ssrcs, (GHFunc) copy_source, res);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx], (GHFunc) copy_source, res);
   RTP_SESSION_UNLOCK (sess);
 
   return res;
@@ -1452,14 +1466,14 @@ session_update_ptp (RTPSession * sess)
    */
   data.is_doing_ptp = TRUE;
   data.new_addr = NULL;
-  g_hash_table_foreach (sess->ssrcs,
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
       (GHFunc) compare_rtp_source_addr, (gpointer) & data);
   is_doing_rtp_ptp = data.is_doing_ptp;
 
   /* same but about rtcp */
   data.is_doing_ptp = TRUE;
   data.new_addr = NULL;
-  g_hash_table_foreach (sess->ssrcs,
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
       (GHFunc) compare_rtcp_source_addr, (gpointer) & data);
   is_doing_rtcp_ptp = data.is_doing_ptp;
 
@@ -1473,7 +1487,8 @@ session_update_ptp (RTPSession * sess)
 static void
 add_source (RTPSession * sess, RTPSource * src)
 {
-  g_hash_table_insert (sess->ssrcs, GINT_TO_POINTER (src->ssrc), src);
+  g_hash_table_insert (sess->ssrcs[sess->mask_idx],
+      GINT_TO_POINTER (src->ssrc), src);
   /* report the new source ASAP */
   src->generation = sess->generation;
   /* we have one more source now */
@@ -1494,7 +1509,8 @@ add_source (RTPSession * sess, RTPSource * src)
 static RTPSource *
 find_source (RTPSession * sess, guint32 ssrc)
 {
-  return g_hash_table_lookup (sess->ssrcs, GINT_TO_POINTER (ssrc));
+  return g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
+      GINT_TO_POINTER (ssrc));
 }
 
 /* must be called with the session lock, the returned source needs to be
@@ -2341,7 +2357,7 @@ rtp_session_request_local_key_unit (RTPSession * sess, RTPSource * src,
           "RTT (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
           fir ? "FIR" : "PLI",
           GST_TIME_ARGS (current_time - sess->last_keyframe_request),
-          GST_TIME_ARGS (round_trip_in_ns));;
+          GST_TIME_ARGS (round_trip_in_ns));
       return FALSE;
     }
   }
@@ -2374,6 +2390,8 @@ rtp_session_process_pli (RTPSession * sess, guint32 sender_ssrc,
     return;
 
   rtp_session_request_local_key_unit (sess, src, FALSE, current_time);
+
+  src->stats.recv_pli_count++;
 }
 
 static void
@@ -2401,7 +2419,7 @@ rtp_session_process_fir (RTPSession * sess, guint32 sender_ssrc,
     if (sess->stats.sender_sources > sess->stats.internal_sender_sources + 1)
       return;
 
-    g_hash_table_iter_init (&iter, sess->ssrcs);
+    g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]);
     while (g_hash_table_iter_next (&iter, NULL, (gpointer *) & src)) {
       if (!src->internal && rtp_source_is_sender (src))
         break;
@@ -2430,6 +2448,7 @@ rtp_session_process_fir (RTPSession * sess, guint32 sender_ssrc,
     return;
 
   rtp_session_request_local_key_unit (sess, src, TRUE, current_time);
+  src->stats.recv_fir_count++;
 }
 
 static void
@@ -2681,6 +2700,15 @@ rtp_session_update_send_caps (RTPSession * sess, GstCaps * caps)
       rtp_source_update_caps (source, caps);
       g_object_unref (source);
     }
+
+    if (gst_structure_get_uint (s, "rtx-ssrc", &ssrc)) {
+      source =
+          obtain_internal_source (sess, ssrc, &created, GST_CLOCK_TIME_NONE);
+      if (source) {
+        rtp_source_update_caps (source, caps);
+        g_object_unref (source);
+      }
+    }
     RTP_SESSION_UNLOCK (sess);
   }
 }
@@ -2771,10 +2799,10 @@ calculate_rtcp_interval (RTPSession * sess, gboolean deterministic,
       /* If it is <= 0, then try to estimate the actual bandwidth */
       bandwidth = 0;
 
-      g_hash_table_foreach (sess->ssrcs, (GHFunc) add_bitrates, &bandwidth);
-      bandwidth /= 8.0;
+      g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+          (GHFunc) add_bitrates, &bandwidth);
     }
-    if (bandwidth < 8000)
+    if (bandwidth < RTP_STATS_BANDWIDTH)
       bandwidth = RTP_STATS_BANDWIDTH;
 
     rtp_stats_set_bandwidths (&sess->stats, bandwidth,
@@ -2823,7 +2851,7 @@ rtp_session_mark_all_bye (RTPSession * sess, const gchar * reason)
   g_return_if_fail (RTP_IS_SESSION (sess));
 
   RTP_SESSION_LOCK (sess);
-  g_hash_table_foreach (sess->ssrcs,
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
       (GHFunc) source_mark_bye, (gpointer) reason);
   RTP_SESSION_UNLOCK (sess);
 }
@@ -3123,6 +3151,7 @@ session_add_fir (const gchar * key, RTPSource * source, ReportData * data)
   fci_data[1] = fci_data[2] = fci_data[3] = 0;
 
   source->send_fir = FALSE;
+  source->stats.sent_fir_count++;
 }
 
 static void
@@ -3138,7 +3167,8 @@ session_fir (RTPSession * sess, ReportData * data)
   gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
   gst_rtcp_packet_fb_set_media_ssrc (packet, 0);
 
-  g_hash_table_foreach (sess->ssrcs, (GHFunc) session_add_fir, data);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) session_add_fir, data);
 
   if (gst_rtcp_packet_fb_get_fci_length (packet) == 0)
     gst_rtcp_packet_remove (packet);
@@ -3190,6 +3220,8 @@ session_pli (const gchar * key, RTPSource * source, ReportData * data)
 
   source->send_pli = FALSE;
   data->may_suppress = FALSE;
+
+  source->stats.sent_pli_count++;
 }
 
 /* construct NACK */
@@ -3603,7 +3635,8 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
   } else if (!data->is_early) {
     /* loop over all known sources and add report blocks. If we are early, we
      * just make a minimal RTCP packet and skip this step */
-    g_hash_table_foreach (sess->ssrcs, (GHFunc) session_report_blocks, data);
+    g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+        (GHFunc) session_report_blocks, data);
   }
   if (!data->has_sdes)
     session_sdes (sess, data);
@@ -3612,10 +3645,12 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
     session_fir (sess, data);
 
   if (data->have_pli)
-    g_hash_table_foreach (sess->ssrcs, (GHFunc) session_pli, data);
+    g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+        (GHFunc) session_pli, data);
 
   if (data->have_nack)
-    g_hash_table_foreach (sess->ssrcs, (GHFunc) session_nack, data);
+    g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+        (GHFunc) session_nack, data);
 
   gst_rtcp_buffer_unmap (&data->rtcpbuf);
 
@@ -3714,7 +3749,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
    * cleanup stage below releases the session lock. */
   table_copy = g_hash_table_new_full (NULL, NULL, NULL,
       (GDestroyNotify) g_object_unref);
-  g_hash_table_foreach (sess->ssrcs,
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
       (GHFunc) clone_ssrcs_hashtable, table_copy);
 
   /* Clean up the session, mark the source for removing, this might release the
@@ -3723,7 +3758,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
   g_hash_table_destroy (table_copy);
 
   /* Now remove the marked sources */
-  g_hash_table_foreach_remove (sess->ssrcs,
+  g_hash_table_foreach_remove (sess->ssrcs[sess->mask_idx],
       (GHRFunc) remove_closing_sources, &data);
 
   /* update point-to-point status */
@@ -3737,10 +3772,12 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
       sess->generation, data.num_to_report, data.is_early);
 
   /* generate RTCP for all internal sources */
-  g_hash_table_foreach (sess->ssrcs, (GHFunc) generate_rtcp, &data);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) generate_rtcp, &data);
 
   /* update the generation for all the sources that have been reported */
-  g_hash_table_foreach (sess->ssrcs, (GHFunc) update_generation, &data);
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) update_generation, &data);
 
   /* we keep track of the last report time in order to timeout inactive
    * receivers or senders */
@@ -3844,6 +3881,11 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
           GST_TIME_ARGS (sess->next_rtcp_check_time));
       ret = TRUE;
     } else {
+      GST_LOG_OBJECT (sess,
+          "can't allow early feedback, next scheduled time is too late %"
+          GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
+          GST_TIME_ARGS (sess->next_rtcp_check_time));
       ret = FALSE;
     }
     goto end;
@@ -3866,8 +3908,12 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
 
   /*  RFC 4585 section 3.5.2 step 3 */
   if (current_time + T_dither_max > sess->next_rtcp_check_time) {
-    GST_LOG_OBJECT (sess, "don't send because of dither");
-    ret = FALSE;
+    GST_LOG_OBJECT (sess,
+        "don't send because of dither, next scheduled time is soon %"
+        GST_TIME_FORMAT " + %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (current_time), GST_TIME_ARGS (T_dither_max),
+        GST_TIME_ARGS (sess->next_rtcp_check_time));
+    ret = TRUE;
     goto end;
   }
 
@@ -3882,7 +3928,11 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
           GST_TIME_ARGS (sess->next_rtcp_check_time));
       ret = TRUE;
     } else {
-      GST_LOG_OBJECT (sess, "can't allow early feedback");
+      GST_LOG_OBJECT (sess,
+          "can't allow early feedback, next scheduled time is too late %"
+          GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
+          GST_TIME_ARGS (sess->next_rtcp_check_time));
       ret = FALSE;
     }
     goto end;
@@ -3906,8 +3956,10 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
   sess->next_rtcp_check_time = sess->last_rtcp_send_time + 2 * T_rr;
   sess->last_rtcp_send_time += T_rr;
 
-  GST_LOG_OBJECT (sess, "next early RTCP time %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (sess->next_early_rtcp_time));
+  GST_LOG_OBJECT (sess, "next early RTCP time %" GST_TIME_FORMAT
+      ", next regular RTCP time %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (sess->next_early_rtcp_time),
+      GST_TIME_ARGS (sess->next_rtcp_check_time));
   RTP_SESSION_UNLOCK (sess);
 
   /* notify app of need to send packet early