rtpsession: Calculate RTCP bandwidth as a fraction of the RTP bandwidth
[platform/upstream/gstreamer.git] / gst / rtpmanager / rtpstats.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "rtpstats.h"
21
22 /**
23  * rtp_stats_init_defaults:
24  * @stats: an #RTPSessionStats struct
25  *
26  * Initialize @stats with its default values.
27  */
28 void
29 rtp_stats_init_defaults (RTPSessionStats * stats)
30 {
31   rtp_stats_set_bandwidths (stats, -1, -1, -1, -1);
32   stats->min_interval = RTP_STATS_MIN_INTERVAL;
33   stats->bye_timeout = RTP_STATS_BYE_TIMEOUT;
34 }
35
36 /**
37  * rtp_stats_set_bandwidths:
38  * @stats: an #RTPSessionStats struct
39  * @rtp_bw: RTP bandwidth
40  * @rtcp_bw: RTCP bandwidth
41  * @rs: sender RTCP bandwidth
42  * @rr: receiver RTCP bandwidth
43  *
44  * Configure the bandwidth parameters in the stats. When an input variable is
45  * set to -1, it will be calculated from the other input variables and from the
46  * defaults.
47  */
48 void
49 rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw,
50     gdouble rtcp_bw, guint rs, guint rr)
51 {
52   GST_DEBUG ("recalc bandwidths: RTP %u, RTCP %u, RS %u, RR %u", rtp_bw,
53       rtcp_bw, rs, rr);
54
55   /* when given, sender and receive bandwidth add up to the total
56    * rtcp bandwidth */
57   if (rs != -1 && rr != -1)
58     rtcp_bw = rs + rr;
59
60   /* If rtcp_bw is between 0 and 1, it is a fraction of rtp_bw */
61   if (rtcp_bw > 0 && rtcp_bw < 1) {
62     if (rtp_bw > 0)
63       rtcp_bw = rtp_bw * rtcp_bw;
64     else
65       rtcp_bw = -1;
66   }
67
68   /* RTCP is 5% of the RTP bandwidth */
69   if (rtp_bw == -1 && rtcp_bw > 0)
70     rtp_bw = rtcp_bw * 20;
71   else if (rtp_bw != -1 && rtcp_bw < 0)
72     rtcp_bw = rtp_bw / 20;
73   else if (rtp_bw == -1 && rtcp_bw < 0) {
74     /* nothing given, take defaults */
75     rtp_bw = RTP_STATS_BANDWIDTH;
76     rtcp_bw = rtp_bw = RTP_STATS_RTCP_FRACTION;
77   }
78
79   stats->bandwidth = rtp_bw;
80   stats->rtcp_bandwidth = rtcp_bw;
81
82   /* now figure out the fractions */
83   if (rs == -1) {
84     /* rs unknown */
85     if (rr == -1) {
86       /* both not given, use defaults */
87       rs = stats->rtcp_bandwidth * RTP_STATS_SENDER_FRACTION;
88       rr = stats->rtcp_bandwidth * RTP_STATS_RECEIVER_FRACTION;
89     } else {
90       /* rr known, calculate rs */
91       if (stats->rtcp_bandwidth > rr)
92         rs = stats->rtcp_bandwidth - rr;
93       else
94         rs = 0;
95     }
96   } else if (rr == -1) {
97     /* rs known, calculate rr */
98     if (stats->rtcp_bandwidth > rs)
99       rr = stats->rtcp_bandwidth - rs;
100     else
101       rr = 0;
102   }
103
104   if (stats->rtcp_bandwidth > 0) {
105     stats->sender_fraction = ((gdouble) rs) / ((gdouble) stats->rtcp_bandwidth);
106     stats->receiver_fraction = 1.0 - stats->sender_fraction;
107   } else {
108     /* no RTCP bandwidth, set dummy values */
109     stats->sender_fraction = 0.0;
110     stats->receiver_fraction = 0.0;
111   }
112   GST_DEBUG ("bandwidths: RTP %u, RTCP %u, RS %f, RR %f", stats->bandwidth,
113       stats->rtcp_bandwidth, stats->sender_fraction, stats->receiver_fraction);
114 }
115
116 /**
117  * rtp_stats_calculate_rtcp_interval:
118  * @stats: an #RTPSessionStats struct
119  * @sender: if we are a sender
120  * @first: if this is the first time
121  *
122  * Calculate the RTCP interval. The result of this function is the amount of
123  * time to wait (in nanoseconds) before sending a new RTCP message.
124  *
125  * Returns: the RTCP interval.
126  */
127 GstClockTime
128 rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
129     gboolean first)
130 {
131   gdouble members, senders, n;
132   gdouble avg_rtcp_size, rtcp_bw;
133   gdouble interval;
134   gdouble rtcp_min_time;
135
136   /* Very first call at application start-up uses half the min
137    * delay for quicker notification while still allowing some time
138    * before reporting for randomization and to learn about other
139    * sources so the report interval will converge to the correct
140    * interval more quickly.
141    */
142   rtcp_min_time = stats->min_interval;
143   if (first)
144     rtcp_min_time /= 2.0;
145
146   /* Dedicate a fraction of the RTCP bandwidth to senders unless
147    * the number of senders is large enough that their share is
148    * more than that fraction.
149    */
150   n = members = stats->active_sources;
151   senders = (gdouble) stats->sender_sources;
152   rtcp_bw = stats->rtcp_bandwidth;
153
154   if (senders <= members * stats->sender_fraction) {
155     if (we_send) {
156       rtcp_bw *= stats->sender_fraction;
157       n = senders;
158     } else {
159       rtcp_bw *= stats->receiver_fraction;
160       n -= senders;
161     }
162   }
163
164   /* no bandwidth for RTCP, return NONE to signal that we don't want to send
165    * RTCP packets */
166   if (rtcp_bw <= 0.00001)
167     return GST_CLOCK_TIME_NONE;
168
169   avg_rtcp_size = stats->avg_rtcp_packet_size / 16.0;
170   /*
171    * The effective number of sites times the average packet size is
172    * the total number of octets sent when each site sends a report.
173    * Dividing this by the effective bandwidth gives the time
174    * interval over which those packets must be sent in order to
175    * meet the bandwidth target, with a minimum enforced.  In that
176    * time interval we send one report so this time is also our
177    * average time between reports.
178    */
179   interval = avg_rtcp_size * n / rtcp_bw;
180   if (interval < rtcp_min_time)
181     interval = rtcp_min_time;
182
183   return interval * GST_SECOND;
184 }
185
186 /**
187  * rtp_stats_add_rtcp_jitter:
188  * @stats: an #RTPSessionStats struct
189  * @interval: an RTCP interval
190  *
191  * Apply a random jitter to the @interval. @interval is typically obtained with
192  * rtp_stats_calculate_rtcp_interval().
193  *
194  * Returns: the new RTCP interval.
195  */
196 GstClockTime
197 rtp_stats_add_rtcp_jitter (RTPSessionStats * stats, GstClockTime interval)
198 {
199   gdouble temp;
200
201   /* see RFC 3550 p 30
202    * To compensate for "unconditional reconsideration" converging to a
203    * value below the intended average.
204    */
205 #define COMPENSATION  (2.71828 - 1.5);
206
207   temp = (interval * g_random_double_range (0.5, 1.5)) / COMPENSATION;
208
209   return (GstClockTime) temp;
210 }
211
212
213 /**
214  * rtp_stats_calculate_bye_interval:
215  * @stats: an #RTPSessionStats struct
216  *
217  * Calculate the BYE interval. The result of this function is the amount of
218  * time to wait (in nanoseconds) before sending a BYE message.
219  *
220  * Returns: the BYE interval.
221  */
222 GstClockTime
223 rtp_stats_calculate_bye_interval (RTPSessionStats * stats)
224 {
225   gdouble members;
226   gdouble avg_rtcp_size, rtcp_bw;
227   gdouble interval;
228   gdouble rtcp_min_time;
229
230   /* no interval when we have less than 50 members */
231   if (stats->active_sources < 50)
232     return 0;
233
234   rtcp_min_time = (stats->min_interval) / 2.0;
235
236   /* Dedicate a fraction of the RTCP bandwidth to senders unless
237    * the number of senders is large enough that their share is
238    * more than that fraction.
239    */
240   members = stats->bye_members;
241   rtcp_bw = stats->rtcp_bandwidth * stats->receiver_fraction;
242
243   /* no bandwidth for RTCP, return NONE to signal that we don't want to send
244    * RTCP packets */
245   if (rtcp_bw <= 0.0001)
246     return GST_CLOCK_TIME_NONE;
247
248   avg_rtcp_size = stats->avg_rtcp_packet_size / 16.0;
249   /*
250    * The effective number of sites times the average packet size is
251    * the total number of octets sent when each site sends a report.
252    * Dividing this by the effective bandwidth gives the time
253    * interval over which those packets must be sent in order to
254    * meet the bandwidth target, with a minimum enforced.  In that
255    * time interval we send one report so this time is also our
256    * average time between reports.
257    */
258   interval = avg_rtcp_size * members / rtcp_bw;
259   if (interval < rtcp_min_time)
260     interval = rtcp_min_time;
261
262   return interval * GST_SECOND;
263 }