Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / jitter.cxx
bloba20a4c9ec2e2047269701aea692e78fddc3f5350
1 /*
2 * jitter.cxx
4 * Jitter buffer support
6 * Open H323 Library
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
18 * under the License.
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): ______________________________________.
29 * $Log$
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
53 * Better tracing
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
79 * Added thread name.
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
86 * under Linux
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.
155 #include <ptlib.h>
157 #ifdef __GNUC__
158 #pragma implementation "jitter.h"
159 #endif
161 #include "openh323buildopts.h"
163 #include "jitter.h"
165 #if defined(H323_RTP_AGGREGATE) || defined(H323_SIGNAL_AGGREGATE)
166 #include <ptclib/sockagg.h>
167 #endif
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
171 again. */
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
179 jitter */
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);
193 public:
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;
199 struct Info {
200 Info() { }
201 DWORD time;
202 PTimeInterval tick;
203 int depth;
204 const char * extra;
205 } in[1000], out[1000];
206 PINDEX inPos, outPos;
209 #endif
211 #ifdef H323_RTP_AGGREGATE
212 class RTP_AggregatedHandle : public PAggregatedHandle
214 public:
215 RTP_AggregatedHandle(PHandleAggregator * _owner, RTP_JitterBuffer & _jitterBuffer)
216 : jitterBuffer(_jitterBuffer),
217 dataFd(jitterBuffer.session.GetDataSocketHandle()),
218 controlFd(jitterBuffer.session.GetControlSocketHandle()),
219 owner(_owner)
222 ~RTP_AggregatedHandle()
226 PAggregatorFDList_t GetFDs()
228 PAggregatorFDList_t list;
229 list.push_back(&controlFd);
230 list.push_back(&dataFd);
231 return list;
234 BOOL Init()
236 return jitterBuffer.Init(currentReadFrame, markerWarning);
239 BOOL PreRead()
241 return jitterBuffer.PreRead(currentReadFrame, markerWarning);
244 BOOL OnRead()
246 return jitterBuffer.OnRead(currentReadFrame, markerWarning, FALSE);
249 void DeInit()
251 return jitterBuffer.DeInit(currentReadFrame, markerWarning);
254 PTimeInterval GetTimeout()
255 { return jitterBuffer.session.GetReportTimer(); }
257 BOOL Remove()
258 { return owner->RemoveHandle(this); }
260 RTP_JitterBuffer & jitterBuffer;
261 RTP_JitterBuffer::Entry * currentReadFrame;
262 BOOL markerWarning;
264 protected:
265 PAggregatorFD dataFd, controlFd;
266 PHandleAggregator * owner;
268 #endif
270 #define new PNEW
272 /////////////////////////////////////////////////////////////////////////////
274 RTP_JitterBuffer::RTP_JitterBuffer(RTP_Session & sess,
275 unsigned minJitterDelay,
276 unsigned maxJitterDelay,
277 PINDEX stackSize)
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
297 currentDepth = 0;
298 packetsTooLate = 0;
299 bufferOverruns = 0;
300 consecutiveBufferOverruns = 0;
301 maxConsecutiveMarkerBits = 10;
302 consecutiveMarkerBits = 0;
303 consecutiveEarlyPacketStartTime = 0;
304 doJitterReductionImmediately = FALSE;
305 doneFreeTrash = FALSE;
307 lastWriteTimestamp = 0;
308 lastWriteTick = 0;
309 jitterCalc = 0;
310 jitterCalcPacketCount = 0;
312 shuttingDown = FALSE;
313 preBuffering = TRUE;
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;
322 frame->prev = NULL;
323 frame->next = freeFrames;
324 freeFrames->prev = frame;
325 freeFrames = frame;
328 PTRACE(2, "RTP\tJitter buffer created:"
329 " size=" << bufferSize <<
330 " delay=" << minJitterTime << '-' << maxJitterTime << '/' << currentJitterTime <<
331 " (" << (currentJitterTime/8) << "ms)"
332 " obj=" << this);
334 #if PTRACING && !defined(NO_ANALYSER)
335 analyser = new RTP_JitterBufferAnalyser;
336 #else
337 analyser = NULL;
338 #endif
340 #ifdef H323_RTP_AGGREGATE
341 aggregratedHandle = NULL;
342 #endif
346 RTP_JitterBuffer::~RTP_JitterBuffer()
348 shuttingDown = TRUE;
350 #ifdef H323_RTP_AGGREGATE
351 if (jitterThread == NULL) {
352 aggregratedHandle->Remove();
353 delete aggregratedHandle;
354 aggregratedHandle = NULL;
355 } else
356 #endif
358 PTRACE(3, "RTP\tRemoving jitter buffer " << this << ' ' << jitterThread->GetThreadName());
359 PAssert(jitterThread->WaitForTermination(10000), "Jitter buffer thread did not terminate");
360 delete jitterThread;
361 jitterThread = NULL;
364 bufferMutex.Wait();
366 // Free up all the memory allocated
367 while (oldestFrame != NULL) {
368 Entry * frame = oldestFrame;
369 oldestFrame = oldestFrame->next;
370 delete frame;
373 while (freeFrames != NULL) {
374 Entry * frame = freeFrames;
375 freeFrames = freeFrames->next;
376 delete frame;
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);
386 delete analyser;
387 #endif
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");
397 bufferMutex.Wait();
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;
407 frame->prev = NULL;
408 frame->next = freeFrames;
409 freeFrames->prev = frame;
410 freeFrames = frame;
411 bufferSize++;
414 if (jitterThread != NULL) {
415 if (jitterThread->IsTerminated()) {
416 packetsTooLate = 0;
417 bufferOverruns = 0;
418 consecutiveBufferOverruns = 0;
419 consecutiveMarkerBits = 0;
420 consecutiveEarlyPacketStartTime = 0;
422 shuttingDown = FALSE;
423 preBuffering = TRUE;
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
439 #endif
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);
447 return;
449 #endif
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;
459 BOOL markerWarning;
461 PTRACE(3, "RTP\tJitter RTP receive thread started: " << this);
463 if (Init(currentReadFrame, markerWarning)) {
465 for (;;) {
466 if (!PreRead(currentReadFrame, markerWarning))
467 break;
469 if (!OnRead(currentReadFrame, markerWarning, TRUE))
470 break;
473 DeInit(currentReadFrame, markerWarning);
476 PTRACE(3, "RTP\tJitter RTP receive thread finished: " << this);
480 BOOL RTP_JitterBuffer::Init(Entry * & /*currentReadFrame*/, BOOL & markerWarning)
482 bufferMutex.Wait();
483 markerWarning = FALSE;
484 return TRUE;
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;
507 else {
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;
513 currentDepth--;
514 bufferOverruns++;
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;
520 preBuffering = TRUE;
522 else {
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();
533 return TRUE;
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");
544 return FALSE;
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++;
555 else
556 consecutiveMarkerBits = 0;
558 else {
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" : "");
569 #endif
571 // Queue the frame for playing by the thread at other end of jitter buffer
572 bufferMutex.Wait();
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
577 else {
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;
592 else {
593 // Somewhere in between, locate its position
594 Entry * frame = newestFrame->prev;
595 while (time < frame->GetTimestamp())
596 frame = frame->prev;
598 currentReadFrame->prev = frame;
599 currentReadFrame->next = frame->next;
600 frame->next->prev = currentReadFrame;
601 frame->next = currentReadFrame;
605 currentDepth++;
607 return TRUE;
611 BOOL RTP_JitterBuffer::ReadData(DWORD timestamp, RTP_DataFrame & frame)
613 if (shuttingDown)
614 return FALSE;
616 /*Free the frame just written to codec, putting it back into
617 the free list and clearing the parking spot for it.
619 bufferMutex.Wait();
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
640 way with the buffer.
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.
646 preBuffering = TRUE;
647 currentJitterTime = targetJitterTime;
650 #if PTRACING && !defined(NO_ANALYSER)
651 analyser->Out(0, currentDepth, "Empty");
652 #endif
653 return TRUE;
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.
680 if (preBuffering) {
681 // Reset jitter baseline (should be handled by GetMarker() condition, but just in case...)
682 lastWriteTimestamp = 0;
683 lastWriteTick = 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");
697 #endif
698 return TRUE;
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)
711 shortSilence = TRUE;
713 else if (timestamp < oldestTimestamp && timestamp > (newestTimestamp - currentJitterTime))
714 shortSilence = TRUE;
716 if (shortSilence) {
717 // It is not yet time for something in the buffer
718 #if PTRACING && !defined(NO_ANALYSER)
719 analyser->Out(oldestTimestamp, currentDepth, "Wait");
720 #endif
721 lastWriteTimestamp = 0;
722 lastWriteTick = 0;
723 return TRUE;
726 // Detatch oldest packet from the list, put into parking space
727 currentDepth--;
728 #if PTRACING && !defined(NO_ANALYSER)
729 analyser->Out(oldestTimestamp, currentDepth, timestamp >= oldestTimestamp ? "" : "Late");
730 #endif
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;
739 lastWriteTick = 0;
742 if (lastWriteTimestamp != 0 && lastWriteTick !=0) {
743 int thisJitter = 0;
745 if (currentWriteFrame->GetTimestamp() < lastWriteTimestamp) {
746 //Not too sure how to handle this situation...
747 thisJitter = 0;
749 else if (currentWriteFrame->tick < lastWriteTick) {
750 //Not too sure how to handle this situation either!
751 thisJitter = 0;
753 else {
754 thisJitter = (currentWriteFrame->tick -
755 lastWriteTick).GetInterval()*8 +
756 lastWriteTimestamp -
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;
768 jitterCalc = 0;
770 else {
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)
792 newestFrame = NULL;
793 else {
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;
801 jitterCalc = 0;
802 lastWriteTimestamp = 0;
803 lastWriteTick = 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;
812 currentDepth--;
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) {
822 newestFrame = NULL;
823 break;
826 oldestFrame->prev = NULL;
829 doneFirstWrite = TRUE;
830 frame = *currentWriteFrame;
831 return TRUE;
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;
848 currentDepth--;
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) {
858 newestFrame = NULL;
859 break;
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)");
883 jitterCalc = 0;
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;
909 lastWriteTick = 0;
911 currentDepth--;
912 if (newestFrame == NULL)
914 oldestFrame = NULL;
915 break;
919 currentJitterTime = targetJitterTime;
920 PTRACE(3, "RTP\tJitter buffer size decreased to "
921 << currentJitterTime << " (" << (currentJitterTime/8) << "ms)");
925 doneFirstWrite = TRUE;
926 frame = *currentWriteFrame;
927 return TRUE;
930 /////////////////////////////////////////////////////////////////////////////////
933 #if PTRACING && !defined(NO_ANALYSER)
935 RTP_JitterBufferAnalyser::RTP_JitterBufferAnalyser()
937 inPos = outPos = 1;
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;
961 else
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";
974 PINDEX ix = 1;
975 PINDEX ox = 1;
976 while (ix < inPos || ox < outPos) {
977 while (ix < inPos && (ox >= outPos || in[ix].time < out[ox].time)) {
978 strm << "In\t"
979 << in[ix].time << '\t'
980 << (in[ix].time - in[ix-1].time) << "\t"
981 "\t"
982 << in[ix].extra << "\t"
983 "\t"
984 << in[ix].depth << "\t"
985 "\t"
986 << (in[ix].tick - in[0].tick) << '\t'
987 << (in[ix].tick - in[ix-1].tick) << "\t"
988 "\t"
989 "\t"
990 "\n";
991 ix++;
994 while (ox < outPos && (ix >= inPos || out[ox].time < in[ix].time)) {
995 strm << "Out\t"
996 << out[ox].time << "\t"
997 "\t"
998 << (out[ox].time - out[ox-1].time) << "\t"
999 "\t"
1000 << out[ox].extra << "\t"
1001 "\t"
1002 << out[ox].depth << "\t"
1003 "\t"
1004 "\t"
1005 << (out[ox].tick - out[0].tick) << '\t'
1006 << (out[ox].tick - out[ox-1].tick) << "\t"
1007 "\n";
1008 ox++;
1011 while (ix < inPos && ox < outPos && in[ix].time == out[ox].time) {
1012 strm << "I/O\t"
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)
1025 << '\n';
1026 ox++;
1027 ix++;
1033 #endif
1036 /////////////////////////////////////////////////////////////////////////////