rtpstats: make bandwidths more configurable
[platform/upstream/gst-plugins-good.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, guint rtcp_bw,
50     guint rs, guint rr)
51 {
52   /* when given, sender and receive bandwidth add up to the total
53    * rtcp bandwidth */
54   if (rs != -1 && rr != -1)
55     rtcp_bw = rs + rr;
56
57   /* RTCP is 5% of the RTP bandwidth */
58   if (rtp_bw == -1 && rtcp_bw != -1)
59     rtp_bw = rtcp_bw * 20;
60   else if (rtp_bw != -1 && rtcp_bw == -1)
61     rtcp_bw = rtp_bw / 20;
62   else if (rtp_bw == -1 && rtcp_bw == -1) {
63     /* nothing given, take defaults */
64     rtp_bw = RTP_STATS_BANDWIDTH;
65     rtcp_bw = RTP_STATS_RTCP_BANDWIDTH;
66   }
67   stats->bandwidth = rtp_bw;
68   stats->rtcp_bandwidth = rtcp_bw;
69
70   /* now figure out the fractions */
71   if (rs == -1) {
72     /* rs unknown */
73     if (rr == -1) {
74       /* both not given, use defaults */
75       rs = stats->rtcp_bandwidth * RTP_STATS_SENDER_FRACTION;
76       rr = stats->rtcp_bandwidth * RTP_STATS_RECEIVER_FRACTION;
77     } else {
78       /* rr known, calculate rs */
79       if (stats->rtcp_bandwidth > rr)
80         rs = stats->rtcp_bandwidth - rr;
81       else
82         rs = 0;
83     }
84   } else if (rr == -1) {
85     /* rs known, calculate rr */
86     if (stats->rtcp_bandwidth > rs)
87       rr = stats->rtcp_bandwidth - rs;
88     else
89       rr = 0;
90   }
91
92   if (stats->rtcp_bandwidth > 0) {
93     stats->sender_fraction = ((gdouble) rs) / ((gdouble) stats->rtcp_bandwidth);
94     stats->receiver_fraction = 1.0 - stats->sender_fraction;
95   } else {
96     /* no RTCP bandwidth, set dummy values */
97     stats->sender_fraction = 0.0;
98     stats->receiver_fraction = 0.0;
99   }
100   GST_DEBUG ("bandwidths: RTP %u, RTCP %u, RS %f, RR %f", stats->bandwidth,
101       stats->rtcp_bandwidth, stats->sender_fraction, stats->receiver_fraction);
102 }
103
104 /**
105  * rtp_stats_calculate_rtcp_interval:
106  * @stats: an #RTPSessionStats struct
107  * @sender: if we are a sender
108  * @first: if this is the first time
109  *
110  * Calculate the RTCP interval. The result of this function is the amount of
111  * time to wait (in nanoseconds) before sending a new RTCP message.
112  *
113  * Returns: the RTCP interval.
114  */
115 GstClockTime
116 rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
117     gboolean first)
118 {
119   gdouble members, senders, n;
120   gdouble avg_rtcp_size, rtcp_bw;
121   gdouble interval;
122   gdouble rtcp_min_time;
123
124   /* Very first call at application start-up uses half the min
125    * delay for quicker notification while still allowing some time
126    * before reporting for randomization and to learn about other
127    * sources so the report interval will converge to the correct
128    * interval more quickly.
129    */
130   rtcp_min_time = stats->min_interval;
131   if (first)
132     rtcp_min_time /= 2.0;
133
134   /* Dedicate a fraction of the RTCP bandwidth to senders unless
135    * the number of senders is large enough that their share is
136    * more than that fraction.
137    */
138   n = members = stats->active_sources;
139   senders = (gdouble) stats->sender_sources;
140   rtcp_bw = stats->rtcp_bandwidth;
141
142   if (senders <= members * stats->sender_fraction) {
143     if (we_send) {
144       rtcp_bw *= stats->sender_fraction;
145       n = senders;
146     } else {
147       rtcp_bw *= stats->receiver_fraction;
148       n -= senders;
149     }
150   }
151
152   /* no bandwidth for RTCP, return NONE to signal that we don't want to send
153    * RTCP packets */
154   if (rtcp_bw <= 0.00001)
155     return GST_CLOCK_TIME_NONE;
156
157   avg_rtcp_size = stats->avg_rtcp_packet_size / 16.0;
158   /*
159    * The effective number of sites times the average packet size is
160    * the total number of octets sent when each site sends a report.
161    * Dividing this by the effective bandwidth gives the time
162    * interval over which those packets must be sent in order to
163    * meet the bandwidth target, with a minimum enforced.  In that
164    * time interval we send one report so this time is also our
165    * average time between reports.
166    */
167   interval = avg_rtcp_size * n / rtcp_bw;
168   if (interval < rtcp_min_time)
169     interval = rtcp_min_time;
170
171   return interval * GST_SECOND;
172 }
173
174 /**
175  * rtp_stats_add_rtcp_jitter:
176  * @stats: an #RTPSessionStats struct
177  * @interval: an RTCP interval
178  *
179  * Apply a random jitter to the @interval. @interval is typically obtained with
180  * rtp_stats_calculate_rtcp_interval().
181  *
182  * Returns: the new RTCP interval.
183  */
184 GstClockTime
185 rtp_stats_add_rtcp_jitter (RTPSessionStats * stats, GstClockTime interval)
186 {
187   gdouble temp;
188
189   /* see RFC 3550 p 30
190    * To compensate for "unconditional reconsideration" converging to a
191    * value below the intended average.
192    */
193 #define COMPENSATION  (2.71828 - 1.5);
194
195   temp = (interval * g_random_double_range (0.5, 1.5)) / COMPENSATION;
196
197   return (GstClockTime) temp;
198 }
199
200
201 /**
202  * rtp_stats_calculate_bye_interval:
203  * @stats: an #RTPSessionStats struct
204  *
205  * Calculate the BYE interval. The result of this function is the amount of
206  * time to wait (in nanoseconds) before sending a BYE message.
207  *
208  * Returns: the BYE interval.
209  */
210 GstClockTime
211 rtp_stats_calculate_bye_interval (RTPSessionStats * stats)
212 {
213   gdouble members;
214   gdouble avg_rtcp_size, rtcp_bw;
215   gdouble interval;
216   gdouble rtcp_min_time;
217
218   /* no interval when we have less than 50 members */
219   if (stats->active_sources < 50)
220     return 0;
221
222   rtcp_min_time = (stats->min_interval) / 2.0;
223
224   /* Dedicate a fraction of the RTCP bandwidth to senders unless
225    * the number of senders is large enough that their share is
226    * more than that fraction.
227    */
228   members = stats->bye_members;
229   rtcp_bw = stats->rtcp_bandwidth * stats->receiver_fraction;
230
231   /* no bandwidth for RTCP, return NONE to signal that we don't want to send
232    * RTCP packets */
233   if (rtcp_bw <= 0.0001)
234     return GST_CLOCK_TIME_NONE;
235
236   avg_rtcp_size = stats->avg_rtcp_packet_size / 16.0;
237   /*
238    * The effective number of sites times the average packet size is
239    * the total number of octets sent when each site sends a report.
240    * Dividing this by the effective bandwidth gives the time
241    * interval over which those packets must be sent in order to
242    * meet the bandwidth target, with a minimum enforced.  In that
243    * time interval we send one report so this time is also our
244    * average time between reports.
245    */
246   interval = avg_rtcp_size * members / rtcp_bw;
247   if (interval < rtcp_min_time)
248     interval = rtcp_min_time;
249
250   return interval * GST_SECOND;
251 }