4 * Jitter buffer support
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions of this code were written with the assisance of funding from
25 * Vovida Networks, Inc. http://www.vovida.com.
27 * Contributor(s): ______________________________________.
30 * Revision 1.38 2006/01/18 07:46:08 csoutheren
31 * Initial version of RTP aggregation (disabled by default)
33 * Revision 1.37 2005/08/27 06:39:56 csoutheren
34 * Extended scope of mutex to avoid race conditions
35 * Thanks to Anton Antonov
37 * Revision 1.36 2004/04/16 04:00:14 csoutheren
38 * Prevent lots of "all packets have marker bits set" message from cluttering the logs
40 * Revision 1.35 2003/11/08 02:03:46 rjongbloed
41 * Removed warning on no logging build.
43 * Revision 1.34 2003/10/28 22:38:31 dereksmithies
44 * Rework of jitter buffer. Many thanks to Henry Harrison of Alice Street.
46 * Revision 1.33ACC1.0 6th October 2003 henryh
47 * Complete change to adaptive algorithm
49 * Revision 1.33 2002/11/26 03:00:06 robertj
50 * Added logging to help find logical channel thread stop failures.
52 * Revision 1.32 2002/11/05 04:06:48 robertj
55 * Revision 1.31 2002/10/31 00:46:30 robertj
56 * Enhanced jitter buffer system so operates dynamically between minimum and
57 * maximum values. Altered API to assure app writers note the change!
59 * Revision 1.30 2002/10/30 05:56:12 craigs
60 * Added more bulletproofing thanks to Alex Kovatch
62 * Revision 1.29 2002/09/03 07:31:35 robertj
63 * Added buffer reset on excess buffer overruns.
65 * Revision 1.28 2002/08/05 10:03:47 robertj
66 * Cosmetic changes to normalise the usage of pragma interface/implementation.
68 * Revision 1.27 2002/01/17 07:01:28 robertj
69 * Fixed jitter buffer failing to deliver a talk burst shorted than the size of
70 * the buffer, this is particularly noticable with RFC2833.
72 * Revision 1.26 2001/09/11 00:21:23 robertj
73 * Fixed missing stack sizes in endpoint for cleaner thread and jitter thread.
75 * Revision 1.25 2001/09/10 08:18:11 robertj
76 * Added define to remove jitter buffer analyser, thanks Nick Hoath.
78 * Revision 1.24 2001/07/05 05:55:17 robertj
81 * Revision 1.23 2001/04/04 03:13:31 robertj
82 * Added PTRACE for when have packets too late.
84 * Revision 1.22 2001/02/09 05:13:56 craigs
85 * Added pragma implementation to (hopefully) reduce the executable image size
88 * Revision 1.21 2000/12/17 22:45:36 robertj
89 * Set media stream threads to highest unprivileged priority.
91 * Revision 1.20 2000/09/14 23:03:45 robertj
92 * Increased timeout on asserting because of driver lockup
94 * Revision 1.19 2000/09/05 22:21:02 robertj
95 * Fixed bug in jitter buffer list changes if get out of order packet within jitter time.
97 * Revision 1.18 2000/08/25 01:10:28 robertj
98 * Added assert if various thrads ever fail to terminate.
100 * Revision 1.17 2000/05/30 06:53:04 robertj
101 * Fixed bug where jitter buffer needs to be restarted, eg Cisco double use of session.
103 * Revision 1.16 2000/05/25 02:26:12 robertj
104 * Added ignore of marker bits on broken clients that sets it on every RTP packet.
106 * Revision 1.15 2000/05/25 00:35:37 robertj
107 * Fixed rare crashing bug in jitter buffer caused by our of order packet.
109 * Revision 1.14 2000/05/16 07:37:41 robertj
110 * Initialised preBuffering flag just in case sender does not set RTP marker bit.
112 * Revision 1.13 2000/05/08 14:05:58 robertj
113 * Increased log level of big jitter debug output to level 5.
115 * Revision 1.12 2000/05/05 02:54:15 robertj
116 * Fixed memory leak just introduced in jitter buffer.
118 * Revision 1.11 2000/05/04 11:52:35 robertj
119 * Added Packets Too Late statistics, requiring major rearrangement of jitter
120 * buffer code, not also changes semantics of codec Write() function slightly.
122 * Revision 1.10 2000/05/02 04:32:27 robertj
123 * Fixed copyright notice comment.
125 * Revision 1.9 2000/05/01 09:11:04 robertj
126 * Fixed removal of analysis code on No Trace version.
128 * Revision 1.8 2000/05/01 06:04:33 robertj
129 * More jitter buffer debugging.
131 * Revision 1.7 2000/04/10 18:55:46 robertj
132 * Changed RTP data receive tp be more forgiving, will process packet even if payload type is wrong.
134 * Revision 1.6 2000/03/31 20:10:43 robertj
135 * Fixed problem with insufficient jitter buffer frames being allocated.
136 * Fixed "center in frame" change in previous version.
138 * Revision 1.5 2000/03/23 03:08:52 robertj
139 * Changed jitter buffer so asumes output double buffering and centers output in time frames.
141 * Revision 1.4 2000/03/21 03:06:50 robertj
142 * Changes to make RTP TX of exact numbers of frames in some codecs.
144 * Revision 1.3 2000/03/20 20:51:47 robertj
145 * Fixed possible buffer overrun problem in RTP_DataFrames
147 * Revision 1.2 1999/12/29 01:18:07 craigs
148 * Fixed problem with codecs other than G.711 not working after reorganisation
150 * Revision 1.1 1999/12/23 23:02:36 robertj
151 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
158 #pragma implementation "jitter.h"
161 #include "openh323buildopts.h"
165 #if defined(H323_RTP_AGGREGATE) || defined(H323_SIGNAL_AGGREGATE)
166 #include <ptclib/sockagg.h>
169 /*Number of consecutive attempts to add a packet to the jitter buffer while
170 it is full before the system clears the jitter buffer and starts over
172 #define MAX_BUFFER_OVERRUNS 20
174 /**How much time must elapse with lower jitter before jitter
175 buffer size is reduced */
176 #define DECREASE_JITTER_PERIOD 5000 // milliseconds
178 /* Percentage of current jitter buffer size that constitutes a "genuinely" smaller
180 #define LOWER_JITTER_MAX_PCNT 80
182 /* Minimum number of packets that constitute a reliable sample for setting a lower
183 jitter buffer target */
184 #define DECREASE_JITTER_MIN_PACKETS 50
188 #if PTRACING && !defined(NO_ANALYSER)
190 class RTP_JitterBufferAnalyser
: public PObject
192 PCLASSINFO(RTP_JitterBufferAnalyser
, PObject
);
194 RTP_JitterBufferAnalyser();
195 void In(DWORD time
, unsigned depth
, const char * extra
);
196 void Out(DWORD time
, unsigned depth
, const char * extra
);
197 void PrintOn(ostream
& strm
) const;
205 } in
[1000], out
[1000];
206 PINDEX inPos
, outPos
;
211 #ifdef H323_RTP_AGGREGATE
212 class RTP_AggregatedHandle
: public PAggregatedHandle
215 RTP_AggregatedHandle(PHandleAggregator
* _owner
, RTP_JitterBuffer
& _jitterBuffer
)
216 : jitterBuffer(_jitterBuffer
),
217 dataFd(jitterBuffer
.session
.GetDataSocketHandle()),
218 controlFd(jitterBuffer
.session
.GetControlSocketHandle()),
222 ~RTP_AggregatedHandle()
226 PAggregatorFDList_t
GetFDs()
228 PAggregatorFDList_t list
;
229 list
.push_back(&controlFd
);
230 list
.push_back(&dataFd
);
236 return jitterBuffer
.Init(currentReadFrame
, markerWarning
);
241 return jitterBuffer
.PreRead(currentReadFrame
, markerWarning
);
246 return jitterBuffer
.OnRead(currentReadFrame
, markerWarning
, FALSE
);
251 return jitterBuffer
.DeInit(currentReadFrame
, markerWarning
);
254 PTimeInterval
GetTimeout()
255 { return jitterBuffer
.session
.GetReportTimer(); }
258 { return owner
->RemoveHandle(this); }
260 RTP_JitterBuffer
& jitterBuffer
;
261 RTP_JitterBuffer::Entry
* currentReadFrame
;
265 PAggregatorFD dataFd
, controlFd
;
266 PHandleAggregator
* owner
;
272 /////////////////////////////////////////////////////////////////////////////
274 RTP_JitterBuffer::RTP_JitterBuffer(RTP_Session
& sess
,
275 unsigned minJitterDelay
,
276 unsigned maxJitterDelay
,
278 : session(sess
), jitterThread(NULL
), jitterStackSize(stackSize
)
280 // Jitter buffer is a queue of frames waiting for playback, a list of
281 // free frames, and a couple of place holders for the frame that is
282 // currently beeing read from the RTP transport or written to the codec.
284 oldestFrame
= newestFrame
= currentWriteFrame
= NULL
;
286 // Calculate the maximum amount of timestamp units for the jitter buffer
287 minJitterTime
= minJitterDelay
;
288 maxJitterTime
= maxJitterDelay
;
289 currentJitterTime
= minJitterDelay
;
290 targetJitterTime
= currentJitterTime
;
292 // Calculate number of frames to allocate, we make the assumption that the
293 // smallest packet we can possibly get is 5ms long (assuming audio 8kHz unit).
294 bufferSize
= maxJitterTime
/40+1;
296 // Nothing in the buffer so far
300 consecutiveBufferOverruns
= 0;
301 maxConsecutiveMarkerBits
= 10;
302 consecutiveMarkerBits
= 0;
303 consecutiveEarlyPacketStartTime
= 0;
304 doJitterReductionImmediately
= FALSE
;
305 doneFreeTrash
= FALSE
;
307 lastWriteTimestamp
= 0;
310 jitterCalcPacketCount
= 0;
312 shuttingDown
= FALSE
;
314 doneFirstWrite
= FALSE
;
316 // Allocate the frames and put them all into the free list
317 freeFrames
= new Entry
;
318 freeFrames
->next
= freeFrames
->prev
= NULL
;
320 for (PINDEX i
= 0; i
< bufferSize
; i
++) {
321 Entry
* frame
= new Entry
;
323 frame
->next
= freeFrames
;
324 freeFrames
->prev
= frame
;
328 PTRACE(2, "RTP\tJitter buffer created:"
329 " size=" << bufferSize
<<
330 " delay=" << minJitterTime
<< '-' << maxJitterTime
<< '/' << currentJitterTime
<<
331 " (" << (currentJitterTime
/8) << "ms)"
334 #if PTRACING && !defined(NO_ANALYSER)
335 analyser
= new RTP_JitterBufferAnalyser
;
340 #ifdef H323_RTP_AGGREGATE
341 aggregratedHandle
= NULL
;
346 RTP_JitterBuffer::~RTP_JitterBuffer()
350 #ifdef H323_RTP_AGGREGATE
351 if (jitterThread
== NULL
) {
352 aggregratedHandle
->Remove();
353 delete aggregratedHandle
;
354 aggregratedHandle
= NULL
;
358 PTRACE(3, "RTP\tRemoving jitter buffer " << this << ' ' << jitterThread
->GetThreadName());
359 PAssert(jitterThread
->WaitForTermination(10000), "Jitter buffer thread did not terminate");
366 // Free up all the memory allocated
367 while (oldestFrame
!= NULL
) {
368 Entry
* frame
= oldestFrame
;
369 oldestFrame
= oldestFrame
->next
;
373 while (freeFrames
!= NULL
) {
374 Entry
* frame
= freeFrames
;
375 freeFrames
= freeFrames
->next
;
379 delete currentWriteFrame
;
381 bufferMutex
.Signal();
383 #if PTRACING && !defined(NO_ANALYSER)
384 PTRACE(5, "Jitter buffer analysis: size=" << bufferSize
385 << " time=" << currentJitterTime
<< '\n' << *analyser
);
391 void RTP_JitterBuffer::SetDelay(unsigned minJitterDelay
, unsigned maxJitterDelay
)
393 if (shuttingDown
&& jitterThread
!= NULL
) {
394 PAssert(jitterThread
->WaitForTermination(10000), "Jitter buffer thread did not terminate");
399 minJitterTime
= minJitterDelay
;
400 maxJitterTime
= maxJitterDelay
;
401 currentJitterTime
= minJitterDelay
;
402 targetJitterTime
= currentJitterTime
;
404 PINDEX newBufferSize
= maxJitterTime
/40+1;
405 while (bufferSize
< newBufferSize
) {
406 Entry
* frame
= new Entry
;
408 frame
->next
= freeFrames
;
409 freeFrames
->prev
= frame
;
414 if (jitterThread
!= NULL
) {
415 if (jitterThread
->IsTerminated()) {
418 consecutiveBufferOverruns
= 0;
419 consecutiveMarkerBits
= 0;
420 consecutiveEarlyPacketStartTime
= 0;
422 shuttingDown
= FALSE
;
425 PTRACE(2, "RTP\tJitter buffer restarted:"
426 " size=" << bufferSize
<<
427 " delay=" << minJitterTime
<< '-' << maxJitterTime
<< '/' << currentJitterTime
<<
428 " (" << (currentJitterTime
/8) << "ms)");
429 jitterThread
->Restart();
433 bufferMutex
.Signal();
436 void RTP_JitterBuffer::Resume(
437 #ifdef H323_RTP_AGGREGATE
438 PHandleAggregator
* aggregator
442 #ifdef H323_RTP_AGGREGATE
443 // if we are aggregating RTP threads, add the socket to the RTP aggregator
444 if (aggregator
!= NULL
) {
445 aggregratedHandle
= new RTP_AggregatedHandle(aggregator
, *this);
446 aggregator
->AddHandle(aggregratedHandle
);
451 // otherwise create a seperate thread as per the old design
452 jitterThread
= PThread::Create(PCREATE_NOTIFIER(JitterThreadMain
), 0, PThread::NoAutoDeleteThread
, PThread::HighestPriority
, "RTP Jitter:%x", jitterStackSize
);
453 jitterThread
->Resume();
456 void RTP_JitterBuffer::JitterThreadMain(PThread
&, INT
)
458 RTP_JitterBuffer::Entry
* currentReadFrame
;
461 PTRACE(3, "RTP\tJitter RTP receive thread started: " << this);
463 if (Init(currentReadFrame
, markerWarning
)) {
466 if (!PreRead(currentReadFrame
, markerWarning
))
469 if (!OnRead(currentReadFrame
, markerWarning
, TRUE
))
473 DeInit(currentReadFrame
, markerWarning
);
476 PTRACE(3, "RTP\tJitter RTP receive thread finished: " << this);
480 BOOL
RTP_JitterBuffer::Init(Entry
* & /*currentReadFrame*/, BOOL
& markerWarning
)
483 markerWarning
= FALSE
;
487 void RTP_JitterBuffer::DeInit(Entry
* & /*currentReadFrame*/, BOOL
& /*markerWarning*/)
492 BOOL
RTP_JitterBuffer::PreRead(RTP_JitterBuffer::Entry
* & currentReadFrame
, BOOL
& /*markerWarning*/)
494 // Get the next free frame available for use for reading from the RTP
495 // transport. Place it into a parking spot.
496 if (freeFrames
!= NULL
) {
497 // Take the next free frame and make it the current for reading
498 currentReadFrame
= freeFrames
;
499 freeFrames
= freeFrames
->next
;
500 if (freeFrames
!= NULL
)
501 freeFrames
->prev
= NULL
;
502 PTRACE_IF(2, consecutiveBufferOverruns
> 1,
503 "RTP\tJitter buffer full, threw away "
504 << consecutiveBufferOverruns
<< " oldest frames");
505 consecutiveBufferOverruns
= 0;
508 // We have a full jitter buffer, need a new frame so take the oldest one
509 currentReadFrame
= oldestFrame
;
510 oldestFrame
= oldestFrame
->next
;
511 if (oldestFrame
!= NULL
)
512 oldestFrame
->prev
= NULL
;
515 consecutiveBufferOverruns
++;
516 if (consecutiveBufferOverruns
> MAX_BUFFER_OVERRUNS
) {
517 PTRACE(2, "RTP\tJitter buffer continuously full, throwing away entire buffer.");
518 freeFrames
= oldestFrame
;
519 oldestFrame
= newestFrame
= NULL
;
523 PTRACE_IF(2, consecutiveBufferOverruns
== 1,
524 "RTP\tJitter buffer full, throwing away oldest frame ("
525 << currentReadFrame
->GetTimestamp() << ')');
529 currentReadFrame
->next
= NULL
;
531 bufferMutex
.Signal();
536 BOOL
RTP_JitterBuffer::OnRead(RTP_JitterBuffer::Entry
* & currentReadFrame
, BOOL
& markerWarning
, BOOL loop
)
538 // Keep reading from the RTP transport frames
539 if (!session
.ReadData(*currentReadFrame
, loop
)) {
540 delete currentReadFrame
; // Destructor won't delete this one, so do it here.
541 currentReadFrame
= FALSE
;
542 shuttingDown
= TRUE
; // Flag to stop the reading side thread
543 PTRACE(3, "RTP\tJitter RTP receive thread ended");
547 currentReadFrame
->tick
= PTimer::Tick();
549 if (consecutiveMarkerBits
< maxConsecutiveMarkerBits
) {
550 if (currentReadFrame
->GetMarker()) {
551 PTRACE(3, "RTP\tReceived start of talk burst: " << currentReadFrame
->GetTimestamp());
552 //preBuffering = TRUE;
553 consecutiveMarkerBits
++;
556 consecutiveMarkerBits
= 0;
559 if (currentReadFrame
->GetMarker())
560 currentReadFrame
->SetMarker(FALSE
);
561 if (!markerWarning
&& (consecutiveMarkerBits
== maxConsecutiveMarkerBits
)) {
562 markerWarning
= TRUE
;
563 PTRACE(3, "RTP\tEvery packet has Marker bit, ignoring them from this client!");
567 #if PTRACING && !defined(NO_ANALYSER)
568 analyser
->In(currentReadFrame
->GetTimestamp(), currentDepth
, preBuffering
? "PreBuf" : "");
571 // Queue the frame for playing by the thread at other end of jitter buffer
574 // Have been reading a frame, put it into the queue now, at correct position
575 if (newestFrame
== NULL
)
576 oldestFrame
= newestFrame
= currentReadFrame
; // Was empty
578 DWORD time
= currentReadFrame
->GetTimestamp();
580 if (time
> newestFrame
->GetTimestamp()) {
581 // Is newer than newst, put at that end of queue
582 currentReadFrame
->prev
= newestFrame
;
583 newestFrame
->next
= currentReadFrame
;
584 newestFrame
= currentReadFrame
;
586 else if (time
<= oldestFrame
->GetTimestamp()) {
587 // Is older than the oldest, put at that end of queue
588 currentReadFrame
->next
= oldestFrame
;
589 oldestFrame
->prev
= currentReadFrame
;
590 oldestFrame
= currentReadFrame
;
593 // Somewhere in between, locate its position
594 Entry
* frame
= newestFrame
->prev
;
595 while (time
< frame
->GetTimestamp())
598 currentReadFrame
->prev
= frame
;
599 currentReadFrame
->next
= frame
->next
;
600 frame
->next
->prev
= currentReadFrame
;
601 frame
->next
= currentReadFrame
;
611 BOOL
RTP_JitterBuffer::ReadData(DWORD timestamp
, RTP_DataFrame
& frame
)
616 /*Free the frame just written to codec, putting it back into
617 the free list and clearing the parking spot for it.
620 if (currentWriteFrame
!= NULL
) {
622 // Move frame from current to free list
623 currentWriteFrame
->next
= freeFrames
;
624 if (freeFrames
!= NULL
)
625 freeFrames
->prev
= currentWriteFrame
;
626 freeFrames
= currentWriteFrame
;
628 currentWriteFrame
= NULL
;
630 bufferMutex
.Signal();
632 // Default response is an empty frame, ie silence
633 frame
.SetPayloadSize(0);
635 PWaitAndSignal
mutex(bufferMutex
);
637 /*Get the next frame to write to the codec. Takes it from the oldest
638 position in the queue, if it is time to do so, and parks it in the
639 special member so can unlock the mutex while the writer thread has its
642 if (oldestFrame
== NULL
) {
643 /*No data to play! We ran the buffer down to empty, restart buffer by
644 setting flag that will fill it again before returning any data.
647 currentJitterTime
= targetJitterTime
;
650 #if PTRACING && !defined(NO_ANALYSER)
651 analyser
->Out(0, currentDepth
, "Empty");
657 DWORD oldestTimestamp
= oldestFrame
->GetTimestamp();
658 DWORD newestTimestamp
= newestFrame
->GetTimestamp();
660 /* If there is an opportunity (due to silence in the buffer) to implement a desired
661 reduction in the size of the jitter buffer, effect it */
663 if (targetJitterTime
< currentJitterTime
&&
664 (newestTimestamp
- oldestTimestamp
) < currentJitterTime
) {
665 currentJitterTime
= ( targetJitterTime
> (newestTimestamp
- oldestTimestamp
)) ?
666 targetJitterTime
: (newestTimestamp
- oldestTimestamp
);
668 PTRACE(3, "RTP\tJitter buffer size decreased to "
669 << currentJitterTime
<< " (" << (currentJitterTime
/8) << "ms)");
672 /* See if time for this packet, if our oldest frame is older than the
673 required age, then use it. If it is not time yet, make sure that the
674 writer thread isn't falling behind (not enough MIPS). If the time
675 between the oldest and the newest entries in the jitter buffer is
676 greater than the size specified for the buffer, then return the oldest
677 entry regardless, making the writer thread catch up.
681 // Reset jitter baseline (should be handled by GetMarker() condition, but just in case...)
682 lastWriteTimestamp
= 0;
686 // Check for requesting something that already exceeds the maximum time,
687 // or have filled the jitter buffer, not filling if this is so
688 if ((timestamp - oldestTimestamp) < currentJitterTime &&
689 (newestTimestamp - oldestTimestamp) < currentJitterTime/2) {
692 // If oldest frame has not been in the buffer long enough, don't return anything yet
693 if ((PTimer::Tick() - oldestFrame
->tick
).GetInterval() * 8
694 < currentJitterTime
/ 2) {
695 #if PTRACING && !defined(NO_ANALYSER)
696 analyser
->Out(oldestTimestamp
, currentDepth
, "PreBuf");
701 preBuffering
= FALSE
;
705 //Handle short silence bursts in the middle of the buffer
706 // - if we think we're getting marker bit information, use that
707 BOOL shortSilence
= FALSE
;
708 if (consecutiveMarkerBits
< maxConsecutiveMarkerBits
) {
709 if (oldestFrame
->GetMarker() &&
710 (PTimer::Tick() - oldestFrame
->tick
).GetInterval()* 8 < currentJitterTime
/ 2)
713 else if (timestamp
< oldestTimestamp
&& timestamp
> (newestTimestamp
- currentJitterTime
))
717 // It is not yet time for something in the buffer
718 #if PTRACING && !defined(NO_ANALYSER)
719 analyser
->Out(oldestTimestamp
, currentDepth
, "Wait");
721 lastWriteTimestamp
= 0;
726 // Detatch oldest packet from the list, put into parking space
728 #if PTRACING && !defined(NO_ANALYSER)
729 analyser
->Out(oldestTimestamp
, currentDepth
, timestamp
>= oldestTimestamp
? "" : "Late");
731 currentWriteFrame
= oldestFrame
;
732 oldestFrame
= currentWriteFrame
->next
;
733 currentWriteFrame
->next
= NULL
;
735 // Calculate the jitter contribution of this frame
736 // - don't count if start of a talk burst
737 if (currentWriteFrame
->GetMarker()) {
738 lastWriteTimestamp
= 0;
742 if (lastWriteTimestamp
!= 0 && lastWriteTick
!=0) {
745 if (currentWriteFrame
->GetTimestamp() < lastWriteTimestamp
) {
746 //Not too sure how to handle this situation...
749 else if (currentWriteFrame
->tick
< lastWriteTick
) {
750 //Not too sure how to handle this situation either!
754 thisJitter
= (currentWriteFrame
->tick
-
755 lastWriteTick
).GetInterval()*8 +
757 currentWriteFrame
->GetTimestamp();
760 if (thisJitter
< 0) thisJitter
*=(-1);
761 thisJitter
*=2; //currentJitterTime needs to be at least TWICE the maximum jitter
763 if (thisJitter
> (int) currentJitterTime
* LOWER_JITTER_MAX_PCNT
/ 100) {
764 targetJitterTime
= currentJitterTime
;
765 PTRACE(3, "RTP\tJitter buffer target realigned to current jitter buffer");
766 consecutiveEarlyPacketStartTime
= PTimer::Tick();
767 jitterCalcPacketCount
= 0;
771 if (thisJitter
> (int) jitterCalc
)
772 jitterCalc
= thisJitter
;
773 jitterCalcPacketCount
++;
775 //If it's bigger than the target we're currently trying to set, adapt that target.
776 //Note: this will never make targetJitterTime larger than currentJitterTime due to
777 //previous if condition
778 if (thisJitter
> (int) targetJitterTime
* LOWER_JITTER_MAX_PCNT
/ 100) {
779 targetJitterTime
= thisJitter
* 100 / LOWER_JITTER_MAX_PCNT
;
780 PTRACE(3, "RTP\tJitter buffer target size increased to "
781 << targetJitterTime
<< " (" << (targetJitterTime
/8) << "ms)");
787 lastWriteTimestamp
= currentWriteFrame
->GetTimestamp();
788 lastWriteTick
= currentWriteFrame
->tick
;
791 if (oldestFrame
== NULL
)
794 oldestFrame
->prev
= NULL
;
796 // If exceeded current jitter buffer time delay:
797 if ((newestTimestamp
- currentWriteFrame
->GetTimestamp()) > currentJitterTime
) {
798 PTRACE(4, "RTP\tJitter buffer length exceeded");
799 consecutiveEarlyPacketStartTime
= PTimer::Tick();
800 jitterCalcPacketCount
= 0;
802 lastWriteTimestamp
= 0;
805 // If we haven't yet written a frame, we get one free overrun
806 if (!doneFirstWrite
) {
807 PTRACE(4, "RTP\tJitter buffer length exceed was prior to first write. Not increasing buffer size");
808 while ((newestTimestamp
- currentWriteFrame
->GetTimestamp()) > currentJitterTime
) {
809 Entry
* wastedFrame
= currentWriteFrame
;
810 currentWriteFrame
= oldestFrame
;
811 oldestFrame
= oldestFrame
->next
;
814 currentWriteFrame
->next
= NULL
; //currentWriteFrame should never be able to be NULL
816 wastedFrame
->next
= freeFrames
;
817 if (freeFrames
!= NULL
)
818 freeFrames
->prev
= wastedFrame
;
819 freeFrames
= wastedFrame
;
821 if (oldestFrame
== NULL
) {
826 oldestFrame
->prev
= NULL
;
829 doneFirstWrite
= TRUE
;
830 frame
= *currentWriteFrame
;
835 // See if exceeded maximum jitter buffer time delay, waste them if so
836 while ((newestFrame
->GetTimestamp() - currentWriteFrame
->GetTimestamp()) > maxJitterTime
) {
837 PTRACE(4, "RTP\tJitter buffer oldest packet ("
838 << oldestFrame
->GetTimestamp() << " < "
839 << (newestTimestamp
- maxJitterTime
)
840 << ") too late, throwing away");
842 currentJitterTime
= maxJitterTime
;
844 //Throw away the oldest frame and move everything up
845 Entry
* wastedFrame
= currentWriteFrame
;
846 currentWriteFrame
= oldestFrame
;
847 oldestFrame
= oldestFrame
->next
;
850 currentWriteFrame
->next
= NULL
; //currentWriteFrame should never be able to be NULL
852 wastedFrame
->next
= freeFrames
;
853 if (freeFrames
!= NULL
)
854 freeFrames
->prev
= wastedFrame
;
855 freeFrames
= wastedFrame
;
857 if (oldestFrame
== NULL
) {
864 // Now change the jitter time to cope with the new size
865 // unless already set to maxJitterTime
866 if (newestTimestamp
- currentWriteFrame
->GetTimestamp() > currentJitterTime
)
867 currentJitterTime
= newestTimestamp
- currentWriteFrame
->GetTimestamp();
869 targetJitterTime
= currentJitterTime
;
870 PTRACE(3, "RTP\tJitter buffer size increased to "
871 << currentJitterTime
<< " (" << (currentJitterTime
/8) << "ms)");
875 if ((PTimer::Tick() - consecutiveEarlyPacketStartTime
).GetInterval() > DECREASE_JITTER_PERIOD
&&
876 jitterCalcPacketCount
>= DECREASE_JITTER_MIN_PACKETS
){
877 jitterCalc
= jitterCalc
* 100 / LOWER_JITTER_MAX_PCNT
;
878 if (jitterCalc
< targetJitterTime
/ 2) jitterCalc
= targetJitterTime
/ 2;
879 if (jitterCalc
< minJitterTime
) jitterCalc
= minJitterTime
;
880 targetJitterTime
= jitterCalc
;
881 PTRACE(3, "RTP\tJitter buffer target size decreased to "
882 << targetJitterTime
<< " (" << (targetJitterTime
/8) << "ms)");
884 jitterCalcPacketCount
= 0;
885 consecutiveEarlyPacketStartTime
= PTimer::Tick();
888 /* If using immediate jitter reduction (rather than waiting for silence opportunities)
889 then trash oldest frames as necessary to reduce the size of the jitter buffer */
890 if (targetJitterTime
< currentJitterTime
&&
891 doJitterReductionImmediately
&&
892 newestFrame
!= NULL
) {
893 while ((newestFrame
->GetTimestamp() - currentWriteFrame
->GetTimestamp()) > targetJitterTime
){
894 // Throw away the newest entries
895 Entry
* wastedFrame
= newestFrame
;
896 newestFrame
= newestFrame
->prev
;
897 if (newestFrame
!= NULL
)
898 newestFrame
->next
= NULL
;
899 wastedFrame
->prev
= NULL
;
901 // Put thrown away frame on free list
902 wastedFrame
->next
= freeFrames
;
903 if (freeFrames
!= NULL
)
904 freeFrames
->prev
= wastedFrame
;
905 freeFrames
= wastedFrame
;
907 // Reset jitter calculation baseline
908 lastWriteTimestamp
= 0;
912 if (newestFrame
== NULL
)
919 currentJitterTime
= targetJitterTime
;
920 PTRACE(3, "RTP\tJitter buffer size decreased to "
921 << currentJitterTime
<< " (" << (currentJitterTime
/8) << "ms)");
925 doneFirstWrite
= TRUE
;
926 frame
= *currentWriteFrame
;
930 /////////////////////////////////////////////////////////////////////////////////
933 #if PTRACING && !defined(NO_ANALYSER)
935 RTP_JitterBufferAnalyser::RTP_JitterBufferAnalyser()
938 in
[0].time
= out
[0].time
= 0;
939 in
[0].tick
= out
[0].tick
= PTimer::Tick();
940 in
[0].depth
= out
[0].depth
= 0;
944 void RTP_JitterBufferAnalyser::In(DWORD time
, unsigned depth
, const char * extra
)
946 if (inPos
< PARRAYSIZE(in
)) {
947 in
[inPos
].tick
= PTimer::Tick();
948 in
[inPos
].time
= time
;
949 in
[inPos
].depth
= depth
;
950 in
[inPos
++].extra
= extra
;
955 void RTP_JitterBufferAnalyser::Out(DWORD time
, unsigned depth
, const char * extra
)
957 if (outPos
< PARRAYSIZE(out
)) {
958 out
[outPos
].tick
= PTimer::Tick();
959 if (time
== 0 && outPos
> 0)
960 out
[outPos
].time
= out
[outPos
-1].time
;
962 out
[outPos
].time
= time
;
963 out
[outPos
].depth
= depth
;
964 out
[outPos
++].extra
= extra
;
969 void RTP_JitterBufferAnalyser::PrintOn(ostream
& strm
) const
971 strm
<< "Input samples: " << inPos
<< " Output samples: " << outPos
<< "\n"
972 "Dir\tRTPTime\tInDiff\tOutDiff\tInMode\tOutMode\t"
973 "InDepth\tOutDep\tInTick\tInDelay\tOutTick\tOutDel\tIODelay\n";
976 while (ix
< inPos
|| ox
< outPos
) {
977 while (ix
< inPos
&& (ox
>= outPos
|| in
[ix
].time
< out
[ox
].time
)) {
979 << in
[ix
].time
<< '\t'
980 << (in
[ix
].time
- in
[ix
-1].time
) << "\t"
982 << in
[ix
].extra
<< "\t"
984 << in
[ix
].depth
<< "\t"
986 << (in
[ix
].tick
- in
[0].tick
) << '\t'
987 << (in
[ix
].tick
- in
[ix
-1].tick
) << "\t"
994 while (ox
< outPos
&& (ix
>= inPos
|| out
[ox
].time
< in
[ix
].time
)) {
996 << out
[ox
].time
<< "\t"
998 << (out
[ox
].time
- out
[ox
-1].time
) << "\t"
1000 << out
[ox
].extra
<< "\t"
1002 << out
[ox
].depth
<< "\t"
1005 << (out
[ox
].tick
- out
[0].tick
) << '\t'
1006 << (out
[ox
].tick
- out
[ox
-1].tick
) << "\t"
1011 while (ix
< inPos
&& ox
< outPos
&& in
[ix
].time
== out
[ox
].time
) {
1013 << in
[ix
].time
<< '\t'
1014 << (in
[ix
].time
- in
[ix
-1].time
) << '\t'
1015 << (out
[ox
].time
- out
[ox
-1].time
) << '\t'
1016 << in
[ix
].extra
<< '\t'
1017 << out
[ox
].extra
<< '\t'
1018 << in
[ix
].depth
<< '\t'
1019 << out
[ox
].depth
<< '\t'
1020 << (in
[ix
].tick
- in
[0].tick
) << '\t'
1021 << (in
[ix
].tick
- in
[ix
-1].tick
) << '\t'
1022 << (out
[ox
].tick
- out
[0].tick
) << '\t'
1023 << (out
[ox
].tick
- out
[ox
-1].tick
) << '\t'
1024 << (out
[ox
].tick
- in
[ix
].tick
)
1036 /////////////////////////////////////////////////////////////////////////////