SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
rtcpscheduler.cpp
Go to the documentation of this file.
1 /*
2 
3  This file is a part of JRTPLIB
4  Copyright (c) 1999-2017 Jori Liesenborgs
5 
6  Contact: jori.liesenborgs@gmail.com
7 
8  This library was developed at the Expertise Centre for Digital Media
9  (http://www.edm.uhasselt.be), a research center of the Hasselt University
10  (http://www.uhasselt.be). The library is based upon work done for
11  my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
12 
13  Permission is hereby granted, free of charge, to any person obtaining a
14  copy of this software and associated documentation files (the "Software"),
15  to deal in the Software without restriction, including without limitation
16  the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  and/or sell copies of the Software, and to permit persons to whom the
18  Software is furnished to do so, subject to the following conditions:
19 
20  The above copyright notice and this permission notice shall be included
21  in all copies or substantial portions of the Software.
22 
23  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29  IN THE SOFTWARE.
30 
31  */
32 
33 #include "rtcpscheduler.h"
34 #include "rtpsources.h"
35 #include "rtpdefines.h"
36 #include "rtcppacket.h"
37 #include "rtppacket.h"
38 #include "rtcpcompoundpacket.h"
39 #include "rtpsourcedata.h"
40 
41 #define RTCPSCHED_MININTERVAL 1.0
42 
43 namespace qrtplib
44 {
45 
47  mininterval(RTCP_DEFAULTMININTERVAL)
48 {
49  bandwidth = 1000; // TODO What is a good value here?
53  timeinit.Dummy();
54 }
55 
57 {
58 }
59 
61 {
62  if (bw < 0.0)
64  bandwidth = bw;
65  return 0;
66 }
67 
69 {
70  if (fraction < 0.0 || fraction > 1.0)
72  senderfraction = fraction;
73  return 0;
74 }
75 
77 {
78  double t2 = t.GetDouble();
79 
80  if (t2 < RTCPSCHED_MININTERVAL)
82 
83  mininterval = t;
84  return 0;
85 }
86 
88  sources(s), nextrtcptime(0, 0), prevrtcptime(0, 0), rtprand(r)
89 {
90  pmembers = 0;
91  byemembers = 0;
92  pbyemembers = 0;
93  avgbyepacketsize = 0;
94 
95  Reset();
96 
97  //std::cout << (void *)(&rtprand) << std::endl;
98 }
99 
101 {
102 }
103 
105 {
106  headeroverhead = 0; // user has to set this to an appropriate value
107  hassentrtcp = false;
108  firstcall = true;
109  avgrtcppacksize = 1000; // TODO: what is a good value for this?
110  byescheduled = false;
111  sendbyenow = false;
112 }
113 
115 {
116  bool isbye = false;
117  RTCPPacket *p;
118 
119  rtcpcomppack.GotoFirstPacket();
120  while (!isbye && ((p = rtcpcomppack.GetNextPacket()) != 0))
121  {
122  if (p->GetPacketType() == RTCPPacket::BYE)
123  isbye = true;
124  }
125 
126  if (!isbye)
127  {
128  std::size_t packsize = headeroverhead + rtcpcomppack.GetCompoundPacketLength();
129  avgrtcppacksize = (std::size_t)((1.0 / 16.0) * ((double) packsize) + (15.0 / 16.0) * ((double) avgrtcppacksize));
130  }
131  else
132  {
133  if (byescheduled)
134  {
135  std::size_t packsize = headeroverhead + rtcpcomppack.GetCompoundPacketLength();
136  avgbyepacketsize = (std::size_t)((1.0 / 16.0) * ((double) packsize) + (15.0 / 16.0) * ((double) avgbyepacketsize));
137  byemembers++;
138  }
139  }
140 }
141 
143 {
144  bool isbye = false;
145  RTCPPacket *p;
146 
147  rtcpcomppack.GotoFirstPacket();
148  while (!isbye && ((p = rtcpcomppack.GetNextPacket()) != 0))
149  {
150  if (p->GetPacketType() == RTCPPacket::BYE)
151  isbye = true;
152  }
153 
154  if (!isbye)
155  {
156  std::size_t packsize = headeroverhead + rtcpcomppack.GetCompoundPacketLength();
157  avgrtcppacksize = (std::size_t)((1.0 / 16.0) * ((double) packsize) + (15.0 / 16.0) * ((double) avgrtcppacksize));
158  }
159 
160  hassentrtcp = true;
161 }
162 
164 {
165  if (firstcall)
166  {
167  firstcall = false;
171  }
172 
173  RTPTime curtime = RTPTime::CurrentTime();
174 
175  if (curtime > nextrtcptime) // packet should be sent
176  return RTPTime(0, 0);
177 
178  RTPTime diff = nextrtcptime;
179  diff -= curtime;
180 
181  return diff;
182 }
183 
185 {
186  if (firstcall)
187  {
188  firstcall = false;
192  return false;
193  }
194 
195  RTPTime currenttime = RTPTime::CurrentTime();
196 
197 // // TODO: for debugging
198 // double diff = nextrtcptime.GetDouble() - currenttime.GetDouble();
199 //
200 // std::cout << "Delay till next RTCP interval: " << diff << std::endl;
201 
202  if (currenttime < nextrtcptime) // timer has not yet expired
203  return false;
204 
205  RTPTime checktime(0, 0);
206 
207  if (!byescheduled)
208  {
209  bool aresender = false;
210  RTPSourceData *srcdat;
211 
212  if ((srcdat = sources.GetOwnSourceInfo()) != 0)
213  aresender = srcdat->IsSender();
214 
215  checktime = CalculateTransmissionInterval(aresender);
216  }
217  else
218  checktime = CalculateBYETransmissionInterval();
219 
220 // std::cout << "Calculated checktime: " << checktime.GetDouble() << std::endl;
221 
222  checktime += prevrtcptime;
223 
224  if (checktime <= currenttime) // Okay
225  {
226  byescheduled = false;
227  prevrtcptime = currenttime;
230  return true;
231  }
232 
233 // std::cout << "New delay: " << nextrtcptime.GetDouble() - currenttime.GetDouble() << std::endl;
234 
235  nextrtcptime = checktime;
237 
238  return false;
239 }
240 
242 {
243  bool aresender = false;
244  RTPSourceData *srcdat;
245 
246  if ((srcdat = sources.GetOwnSourceInfo()) != 0)
247  aresender = srcdat->IsSender();
248 
251 }
252 
254 {
255  int numsenders = sources.GetSenderCount();
256  int numtotal = sources.GetActiveMemberCount();
257 
258 // std::cout << "CalculateDeterministicInterval" << std::endl;
259 // std::cout << " numsenders: " << numsenders << std::endl;
260 // std::cout << " numtotal: " << numtotal << std::endl;
261 
262  // Try to avoid division by zero:
263  if (numtotal == 0)
264  numtotal++;
265 
266  double sfraction = ((double) numsenders) / ((double) numtotal);
267  double C, n;
268 
269  if (sfraction <= schedparams.GetSenderBandwidthFraction())
270  {
271  if (sender)
272  {
274  n = (double) numsenders;
275  }
276  else
277  {
279  n = (double) (numtotal - numsenders);
280  }
281  }
282  else
283  {
284  C = ((double) avgrtcppacksize) / schedparams.GetRTCPBandwidth();
285  n = (double) numtotal;
286  }
287 
289  double tmin = Tmin.GetDouble();
290 
292  tmin /= 2.0;
293 
294  double ntimesC = n * C;
295  double Td = (tmin > ntimesC) ? tmin : ntimesC;
296 
297  // TODO: for debugging
298 // std::cout << " Td: " << Td << std::endl;
299 
300  return RTPTime(Td);
301 }
302 
304 {
306  double td, mul, T;
307 
308 // std::cout << "CalculateTransmissionInterval" << std::endl;
309 
310  td = Td.GetDouble();
311  mul = rtprand.GetRandomDouble() + 0.5; // gives random value between 0.5 and 1.5
312  T = (td * mul) / 1.21828; // see RFC 3550 p 30
313 
314 // std::cout << " Td: " << td << std::endl;
315 // std::cout << " mul: " << mul << std::endl;
316 // std::cout << " T: " << T << std::endl;
317 
318  return RTPTime(T);
319 }
320 
322 {
323  if (firstcall)
324  return;
325 
326  double diff1, diff2;
327  int members = sources.GetActiveMemberCount();
328 
330  RTPTime tn_min_tc = nextrtcptime;
331 
332  if (tn_min_tc > tc)
333  tn_min_tc -= tc;
334  else
335  tn_min_tc = RTPTime(0, 0);
336 
337 // std::cout << "+tn_min_tc0 " << nextrtcptime.GetDouble()-tc.GetDouble() << std::endl;
338 // std::cout << "-tn_min_tc0 " << -nextrtcptime.GetDouble()+tc.GetDouble() << std::endl;
339 // std::cout << "tn_min_tc " << tn_min_tc.GetDouble() << std::endl;
340 
341  RTPTime tc_min_tp = tc;
342 
343  if (tc_min_tp > prevrtcptime)
344  tc_min_tp -= prevrtcptime;
345  else
346  tc_min_tp = 0;
347 
348  if (pmembers == 0) // avoid division by zero
349  pmembers++;
350 
351  diff1 = (((double) members) / ((double) pmembers)) * tn_min_tc.GetDouble();
352  diff2 = (((double) members) / ((double) pmembers)) * tc_min_tp.GetDouble();
353 
354  nextrtcptime = tc;
355  prevrtcptime = tc;
356  nextrtcptime += RTPTime(diff1);
357  prevrtcptime -= RTPTime(diff2);
358 
359  pmembers = members;
360 }
361 
362 void RTCPScheduler::ScheduleBYEPacket(std::size_t packetsize)
363 {
364  if (byescheduled)
365  return;
366 
367  if (firstcall)
368  {
369  firstcall = false;
371  }
372 
373  byescheduled = true;
374  avgbyepacketsize = packetsize + headeroverhead;
375 
376  // For now, we will always use the BYE backoff algorithm as described in rfc 3550 p 33
377 
378  byemembers = 1;
379  pbyemembers = 1;
380 
381  if (schedparams.GetRequestImmediateBYE() && sources.GetActiveMemberCount() < 50) // p 34 (top)
382  sendbyenow = true;
383  else
384  sendbyenow = false;
385 
389 }
390 
392 {
395 }
396 
398 {
399  if (!byescheduled)
400  return RTPTime(0, 0);
401 
402  if (sendbyenow)
403  return RTPTime(0, 0);
404 
405  double C, n;
406 
408  n = (double) byemembers;
409 
411  double tmin = Tmin.GetDouble();
412 
414  tmin /= 2.0;
415 
416  double ntimesC = n * C;
417  double Td = (tmin > ntimesC) ? tmin : ntimesC;
418 
419  double mul = rtprand.GetRandomDouble() + 0.5; // gives random value between 0.5 and 1.5
420  double T = (Td * mul) / 1.21828; // see RFC 3550 p 30
421 
422  return RTPTime(T);
423 }
424 
425 } // end namespace
426 
int SetSenderBandwidthFraction(double fraction)
virtual double GetRandomDouble()=0
int GetSenderCount() const
Definition: rtpsources.h:275
RTPSourceData * GetOwnSourceInfo()
Definition: rtpsources.h:243
double GetDouble() const
RTPTimeInitializerObject timeinit
std::size_t avgbyepacketsize
int SetMinimumTransmissionInterval(const RTPTime &t)
RTPTime CalculateBYETransmissionInterval()
#define RTCP_DEFAULTIMMEDIATEBYE
Definition: rtpdefines.h:72
double GetRTCPBandwidth() const
Definition: rtcpscheduler.h:66
RTCPScheduler(RTPSources &sources, RTPRandom &rtprand)
std::size_t headeroverhead
void ScheduleBYEPacket(std::size_t packetsize)
RTPTime GetMinimumTransmissionInterval() const
Definition: rtcpscheduler.h:84
int GetActiveMemberCount() const
Definition: rtpsources.h:287
#define RTCPSCHED_MININTERVAL
#define ERR_RTP_SCHEDPARAMS_INVALIDBANDWIDTH
Definition: rtperrors.h:106
void AnalyseIncoming(RTCPCompoundPacket &rtcpcomppack)
RTCPSchedulerParams schedparams
#define ERR_RTP_SCHEDPARAMS_BADFRACTION
Definition: rtperrors.h:104
#define RTCP_DEFAULTMININTERVAL
Definition: rtpdefines.h:68
std::size_t avgrtcppacksize
RTPTime CalculateTransmissionInterval(bool sender)
static RTPTime CurrentTime()
PacketType GetPacketType() const
Definition: rtcppacket.h:82
void AnalyseOutgoing(RTCPCompoundPacket &rtcpcomppack)
#define RTCP_DEFAULTSENDERFRACTION
Definition: rtpdefines.h:70
#define RTCP_DEFAULTHALFATSTARTUP
Definition: rtpdefines.h:71
double GetSenderBandwidthFraction() const
Definition: rtcpscheduler.h:75
#define ERR_RTP_SCHEDPARAMS_BADMINIMUMINTERVAL
Definition: rtperrors.h:105
RTPTime CalculateDeterministicInterval(bool sender=false)