home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / openh323.tar.gz / openh323.tar / openh323 / src / jitter.cxx < prev    next >
C/C++ Source or Header  |  2002-11-25  |  22KB  |  688 lines

  1. /*
  2.  * jitter.cxx
  3.  *
  4.  * Jitter buffer support
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions of this code were written with the assisance of funding from
  25.  * Vovida Networks, Inc. http://www.vovida.com.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: jitter.cxx,v $
  30.  * Revision 1.33  2002/11/26 03:00:06  robertj
  31.  * Added logging to help find logical channel thread stop failures.
  32.  *
  33.  * Revision 1.32  2002/11/05 04:06:48  robertj
  34.  * Better tracing
  35.  *
  36.  * Revision 1.31  2002/10/31 00:46:30  robertj
  37.  * Enhanced jitter buffer system so operates dynamically between minimum and
  38.  *   maximum values. Altered API to assure app writers note the change!
  39.  *
  40.  * Revision 1.30  2002/10/30 05:56:12  craigs
  41.  * Added more bulletproofing thanks to Alex Kovatch
  42.  *
  43.  * Revision 1.29  2002/09/03 07:31:35  robertj
  44.  * Added buffer reset on excess buffer overruns.
  45.  *
  46.  * Revision 1.28  2002/08/05 10:03:47  robertj
  47.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  48.  *
  49.  * Revision 1.27  2002/01/17 07:01:28  robertj
  50.  * Fixed jitter buffer failing to deliver a talk burst shorted than the size of
  51.  *    the buffer, this is particularly noticable with RFC2833.
  52.  *
  53.  * Revision 1.26  2001/09/11 00:21:23  robertj
  54.  * Fixed missing stack sizes in endpoint for cleaner thread and jitter thread.
  55.  *
  56.  * Revision 1.25  2001/09/10 08:18:11  robertj
  57.  * Added define to remove jitter buffer analyser, thanks Nick Hoath.
  58.  *
  59.  * Revision 1.24  2001/07/05 05:55:17  robertj
  60.  * Added thread name.
  61.  *
  62.  * Revision 1.23  2001/04/04 03:13:31  robertj
  63.  * Added PTRACE for when have packets too late.
  64.  *
  65.  * Revision 1.22  2001/02/09 05:13:56  craigs
  66.  * Added pragma implementation to (hopefully) reduce the executable image size
  67.  * under Linux
  68.  *
  69.  * Revision 1.21  2000/12/17 22:45:36  robertj
  70.  * Set media stream threads to highest unprivileged priority.
  71.  *
  72.  * Revision 1.20  2000/09/14 23:03:45  robertj
  73.  * Increased timeout on asserting because of driver lockup
  74.  *
  75.  * Revision 1.19  2000/09/05 22:21:02  robertj
  76.  * Fixed bug in jitter buffer list changes if get out of order packet within jitter time.
  77.  *
  78.  * Revision 1.18  2000/08/25 01:10:28  robertj
  79.  * Added assert if various thrads ever fail to terminate.
  80.  *
  81.  * Revision 1.17  2000/05/30 06:53:04  robertj
  82.  * Fixed bug where jitter buffer needs to be restarted, eg Cisco double use of session.
  83.  *
  84.  * Revision 1.16  2000/05/25 02:26:12  robertj
  85.  * Added ignore of marker bits on broken clients that sets it on every RTP packet.
  86.  *
  87.  * Revision 1.15  2000/05/25 00:35:37  robertj
  88.  * Fixed rare crashing bug in jitter buffer caused by our of order packet.
  89.  *
  90.  * Revision 1.14  2000/05/16 07:37:41  robertj
  91.  * Initialised preBuffering flag just in case sender does not set RTP marker bit.
  92.  *
  93.  * Revision 1.13  2000/05/08 14:05:58  robertj
  94.  * Increased log level of big jitter debug output to level 5.
  95.  *
  96.  * Revision 1.12  2000/05/05 02:54:15  robertj
  97.  * Fixed memory leak just introduced in jitter buffer.
  98.  *
  99.  * Revision 1.11  2000/05/04 11:52:35  robertj
  100.  * Added Packets Too Late statistics, requiring major rearrangement of jitter
  101.  *    buffer code, not also changes semantics of codec Write() function slightly.
  102.  *
  103.  * Revision 1.10  2000/05/02 04:32:27  robertj
  104.  * Fixed copyright notice comment.
  105.  *
  106.  * Revision 1.9  2000/05/01 09:11:04  robertj
  107.  * Fixed removal of analysis code on No Trace version.
  108.  *
  109.  * Revision 1.8  2000/05/01 06:04:33  robertj
  110.  * More jitter buffer debugging.
  111.  *
  112.  * Revision 1.7  2000/04/10 18:55:46  robertj
  113.  * Changed RTP data receive tp be more forgiving, will process packet even if payload type is wrong.
  114.  *
  115.  * Revision 1.6  2000/03/31 20:10:43  robertj
  116.  * Fixed problem with insufficient jitter buffer frames being allocated.
  117.  * Fixed "center in frame" change in previous version.
  118.  *
  119.  * Revision 1.5  2000/03/23 03:08:52  robertj
  120.  * Changed jitter buffer so asumes output double buffering and centers output in time frames.
  121.  *
  122.  * Revision 1.4  2000/03/21 03:06:50  robertj
  123.  * Changes to make RTP TX of exact numbers of frames in some codecs.
  124.  *
  125.  * Revision 1.3  2000/03/20 20:51:47  robertj
  126.  * Fixed possible buffer overrun problem in RTP_DataFrames
  127.  *
  128.  * Revision 1.2  1999/12/29 01:18:07  craigs
  129.  * Fixed problem with codecs other than G.711 not working after reorganisation
  130.  *
  131.  * Revision 1.1  1999/12/23 23:02:36  robertj
  132.  * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
  133.  *
  134.  */
  135.  
  136. #include <ptlib.h>
  137.  
  138. #ifdef __GNUC__
  139. #pragma implementation "jitter.h"
  140. #endif
  141.  
  142. #include "jitter.h"
  143.  
  144.  
  145. /*Number of consecutive attempts to add a packet to the jitter buffer while
  146.   it is full before the system clears the jitter buffer and starts over
  147.   again. */
  148. #define MAX_BUFFER_OVERRUNS 20
  149.  
  150. /**How much time must elapse with consecutive "early" packets before jitter
  151.    buffer size is reduced and the amount that it is reduced by. */
  152. #define EARLY_PACKET_PERIOD    10    // RTP timestamp units (milliseconds)
  153. #define DECREASE_JITTER_PERIOD 16000 // RTP timestamp units (2 seconds)
  154. #define DECREASE_JITTER_AMOUNT 8     // RTP timestamp units (1 millisecond)
  155.  
  156. /**Amount to increase jitter buffer size every time a late packet is
  157.    received. */
  158. #define INCREASE_JITTER_AMOUNT 16    // RTP timestamp units (2 millisecond)
  159.  
  160.  
  161.  
  162. #if PTRACING && !defined(NO_ANALYSER)
  163.  
  164. class RTP_JitterBufferAnalyser : public PObject
  165. {
  166.     PCLASSINFO(RTP_JitterBufferAnalyser, PObject);
  167.   public:
  168.     RTP_JitterBufferAnalyser();
  169.     void In(DWORD time, unsigned depth, const char * extra);
  170.     void Out(DWORD time, unsigned depth, const char * extra);
  171.     void PrintOn(ostream & strm) const;
  172.  
  173.     struct Info {
  174.       Info() { }
  175.       DWORD         time;
  176.       PTimeInterval tick;
  177.       int           depth;
  178.       const char *  extra;
  179.     } in[1000], out[1000];
  180.     PINDEX inPos, outPos;
  181. };
  182.  
  183. #endif
  184.  
  185.  
  186. #define new PNEW
  187.  
  188.  
  189. /////////////////////////////////////////////////////////////////////////////
  190.  
  191. RTP_JitterBuffer::RTP_JitterBuffer(RTP_Session & sess,
  192.                                    unsigned minJitterDelay,
  193.                                    unsigned maxJitterDelay,
  194.                                    PINDEX stackSize)
  195.   : PThread(stackSize, NoAutoDeleteThread, HighestPriority, "RTP Jitter:%x"),
  196.     session(sess)
  197. {
  198.   // Jitter buffer is a queue of frames waiting for playback, a list of
  199.   // free frames, and a couple of place holders for the frame that is
  200.   // currently beeing read from the RTP transport or written to the codec.
  201.  
  202.   oldestFrame = newestFrame = currentWriteFrame = NULL;
  203.  
  204.   // Calculate the maximum amount of timestamp units for the jitter buffer
  205.   minJitterTime = minJitterDelay;
  206.   maxJitterTime = maxJitterDelay;
  207.   currentJitterTime = minJitterDelay + (maxJitterDelay - minJitterDelay)/3;
  208.  
  209.   // Calculate number of frames to allocate, we make the assumption that the
  210.   // smallest packet we can possibly get is 5ms long (assuming audio 8kHz unit).
  211.   bufferSize = maxJitterTime/40+1;
  212.  
  213.   // Nothing in the buffer so far
  214.   currentDepth = 0;
  215.   packetsTooLate = 0;
  216.   bufferOverruns = 0;
  217.   consecutiveBufferOverruns = 0;
  218.   maxConsecutiveMarkerBits = 10;
  219.   consecutiveMarkerBits = 0;
  220.   consecutiveEarlyPacketStartTime = 0;
  221.  
  222.   shuttingDown = FALSE;
  223.   preBuffering = TRUE;
  224.  
  225.   // Allocate the frames and put them all into the free list
  226.   freeFrames = new Entry;
  227.   freeFrames->next = freeFrames->prev = NULL;
  228.  
  229.   for (PINDEX i = 0; i < bufferSize; i++) {
  230.     Entry * frame = new Entry;
  231.     frame->prev = NULL;
  232.     frame->next = freeFrames;
  233.     freeFrames->prev = frame;
  234.     freeFrames = frame;
  235.   }
  236.  
  237.   PTRACE(2, "RTP\tJitter buffer created:"
  238.             " size=" << bufferSize <<
  239.             " delay=" << minJitterTime << '-' << maxJitterTime << '/' << currentJitterTime <<
  240.             " (" << (currentJitterTime/8) << "ms)"
  241.             " obj=" << this);
  242.  
  243. #if PTRACING && !defined(NO_ANALYSER)
  244.   analyser = new RTP_JitterBufferAnalyser;
  245. #else
  246.   analyser = NULL;
  247. #endif
  248.  
  249.   // Start reading data from RTP session
  250.   Resume();
  251. }
  252.  
  253.  
  254. RTP_JitterBuffer::~RTP_JitterBuffer()
  255. {
  256.   PTRACE(3, "RTP\tRemoving jitter buffer " << this << ' ' << GetThreadName());
  257.  
  258.   shuttingDown = TRUE;
  259.   PAssert(WaitForTermination(10000), "Jitter buffer thread did not terminate");
  260.  
  261.   bufferMutex.Wait();
  262.  
  263.   // Free up all the memory allocated
  264.   while (oldestFrame != NULL) {
  265.     Entry * frame = oldestFrame;
  266.     oldestFrame = oldestFrame->next;
  267.     delete frame;
  268.   }
  269.  
  270.   while (freeFrames != NULL) {
  271.     Entry * frame = freeFrames;
  272.     freeFrames = freeFrames->next;
  273.     delete frame;
  274.   }
  275.  
  276.   delete currentWriteFrame;
  277.  
  278.   bufferMutex.Signal();
  279.  
  280. #if PTRACING && !defined(NO_ANALYSER)
  281.   PTRACE(5, "Jitter buffer analysis: size=" << bufferSize
  282.          << " time=" << currentJitterTime << '\n' << *analyser);
  283.   delete analyser;
  284. #endif
  285. }
  286.  
  287.  
  288. void RTP_JitterBuffer::SetDelay(unsigned minJitterDelay, unsigned maxJitterDelay)
  289. {
  290.   if (shuttingDown)
  291.     PAssert(WaitForTermination(10000), "Jitter buffer thread did not terminate");
  292.  
  293.   bufferMutex.Wait();
  294.  
  295.   minJitterTime = minJitterDelay;
  296.   maxJitterTime = maxJitterDelay;
  297.   currentJitterTime = minJitterDelay + (maxJitterDelay - minJitterDelay)/3;
  298.  
  299.   PINDEX newBufferSize = maxJitterTime/40+1;
  300.   while (bufferSize < newBufferSize) {
  301.     Entry * frame = new Entry;
  302.     frame->prev = NULL;
  303.     frame->next = freeFrames;
  304.     freeFrames->prev = frame;
  305.     freeFrames = frame;
  306.     bufferSize++;
  307.   }
  308.  
  309.   if (IsTerminated()) {
  310.     packetsTooLate = 0;
  311.     bufferOverruns = 0;
  312.     consecutiveBufferOverruns = 0;
  313.     consecutiveMarkerBits = 0;
  314.     consecutiveEarlyPacketStartTime = 0;
  315.  
  316.     shuttingDown = FALSE;
  317.     preBuffering = TRUE;
  318.  
  319.     PTRACE(2, "RTP\tJitter buffer restarted:"
  320.               " size=" << bufferSize <<
  321.               " delay=" << minJitterTime << '-' << maxJitterTime << '/' << currentJitterTime <<
  322.               " (" << (currentJitterTime/8) << "ms)");
  323.     Restart();
  324.   }
  325.  
  326.   bufferMutex.Signal();
  327. }
  328.  
  329.  
  330. void RTP_JitterBuffer::Main()
  331. {
  332.   PTRACE(3, "RTP\tJitter RTP receive thread started: " << this);
  333.  
  334.   bufferMutex.Wait();
  335.  
  336.   for (;;) {
  337.  
  338.     // Get the next free frame available for use for reading from the RTP
  339.     // transport. Place it into a parking spot.
  340.     Entry * currentReadFrame;
  341.     if (freeFrames != NULL) {
  342.       // Take the next free frame and make it the current for reading
  343.       currentReadFrame = freeFrames;
  344.       freeFrames = freeFrames->next;
  345.       if (freeFrames != NULL)
  346.         freeFrames->prev = NULL;
  347.       PTRACE_IF(2, consecutiveBufferOverruns > 1,
  348.                 "RTP\tJitter buffer full, threw away "
  349.                 << consecutiveBufferOverruns << " oldest frames");
  350.       consecutiveBufferOverruns = 0;
  351.     }
  352.     else {
  353.       // We have a full jitter buffer, need a new frame so take the oldest one
  354.       currentReadFrame = oldestFrame;
  355.       oldestFrame = oldestFrame->next;
  356.       if (oldestFrame != NULL)
  357.         oldestFrame->prev = NULL;
  358.       currentDepth--;
  359.       bufferOverruns++;
  360.       consecutiveBufferOverruns++;
  361.       if (consecutiveBufferOverruns > MAX_BUFFER_OVERRUNS) {
  362.         PTRACE(2, "RTP\tJitter buffer continuously full, throwing away entire buffer.");
  363.         freeFrames = oldestFrame;
  364.         oldestFrame = newestFrame = NULL;
  365.         preBuffering = TRUE;
  366.       }
  367.       else {
  368.         PTRACE_IF(2, consecutiveBufferOverruns == 1,
  369.                   "RTP\tJitter buffer full, throwing away oldest frame ("
  370.                   << currentReadFrame->GetTimestamp() << ')');
  371.       }
  372.     }
  373.  
  374.     currentReadFrame->next = NULL;
  375.  
  376.     bufferMutex.Signal();
  377.  
  378.     // Keep reading from the RTP transport frames
  379.     if (!session.ReadData(*currentReadFrame)) {
  380.       delete currentReadFrame;  // Destructor won't delete this one, so do it here.
  381.       shuttingDown = TRUE; // Flag to stop the reading side thread
  382.       PTRACE(3, "RTP\tJitter RTP receive thread ended");
  383.       return;
  384.     }
  385.  
  386.     currentReadFrame->tick = PTimer::Tick();
  387.  
  388.     if (currentReadFrame->GetMarker()) {
  389.       // See if remote appears to be setting marker bit on EVERY packet.
  390.       consecutiveMarkerBits++;
  391.       if (consecutiveMarkerBits < maxConsecutiveMarkerBits) {
  392.         PTRACE(3, "RTP\tReceived start of talk burst: " << currentReadFrame->GetTimestamp());
  393.         preBuffering = TRUE;
  394.       }
  395.       if (consecutiveMarkerBits == maxConsecutiveMarkerBits) {
  396.         PTRACE(3, "RTP\tEvery packet has Marker bit, ignoring them from this client!");
  397.       }
  398.     }
  399.     else
  400.       consecutiveMarkerBits = 0;
  401.  
  402. #if PTRACING && !defined(NO_ANALYSER)
  403.     analyser->In(currentReadFrame->GetTimestamp(), currentDepth, preBuffering ? "PreBuf" : "");
  404. #endif
  405.  
  406.     // Queue the frame for playing by the thread at other end of jitter buffer
  407.     bufferMutex.Wait();
  408.  
  409.     // Have been reading a frame, put it into the queue now, at correct position
  410.     if (newestFrame == NULL)
  411.       oldestFrame = newestFrame = currentReadFrame; // Was empty
  412.     else {
  413.       DWORD time = currentReadFrame->GetTimestamp();
  414.  
  415.       if (time > newestFrame->GetTimestamp()) {
  416.         // Is newer than newst, put at that end of queue
  417.         currentReadFrame->prev = newestFrame;
  418.         newestFrame->next = currentReadFrame;
  419.         newestFrame = currentReadFrame;
  420.       }
  421.       else if (time <= oldestFrame->GetTimestamp()) {
  422.         // Is older than the oldest, put at that end of queue
  423.         currentReadFrame->next = oldestFrame;
  424.         oldestFrame->prev = currentReadFrame;
  425.         oldestFrame = currentReadFrame;
  426.       }
  427.       else {
  428.         // Somewhere in between, locate its position
  429.         Entry * frame = newestFrame->prev;
  430.         while (time < frame->GetTimestamp())
  431.           frame = frame->prev;
  432.  
  433.         currentReadFrame->prev = frame;
  434.         currentReadFrame->next = frame->next;
  435.         frame->next->prev = currentReadFrame;
  436.         frame->next = currentReadFrame;
  437.       }
  438.     }
  439.  
  440.     currentDepth++;
  441.   }
  442. }
  443.  
  444.  
  445. BOOL RTP_JitterBuffer::ReadData(DWORD timestamp, RTP_DataFrame & frame)
  446. {
  447.   if (shuttingDown)
  448.     return FALSE;
  449.  
  450.   /*Free the frame just written to codec, putting it back into
  451.     the free list and clearing the parking spot for it.
  452.    */
  453.   if (currentWriteFrame != NULL) {
  454.     bufferMutex.Wait();
  455.  
  456.     // Move frame from current to free list
  457.     currentWriteFrame->next = freeFrames;
  458.     if (freeFrames != NULL)
  459.       freeFrames->prev = currentWriteFrame;
  460.     freeFrames = currentWriteFrame;
  461.  
  462.     currentWriteFrame = NULL;
  463.  
  464.     bufferMutex.Signal();
  465.   }
  466.  
  467.   // Default response is an empty frame, ie silence
  468.   frame.SetPayloadSize(0);
  469.  
  470.   PWaitAndSignal mutex(bufferMutex);
  471.  
  472.   /*Get the next frame to write to the codec. Takes it from the oldest
  473.     position in the queue, if it is time to do so, and parks it in the
  474.     special member so can unlock the mutex while the writer thread has its
  475.     way with the buffer.
  476.    */
  477.   if (oldestFrame == NULL) {
  478.     /*No data to play! We ran the buffer down to empty, restart buffer by
  479.       setting flag that will fill it again before returning any data.
  480.      */
  481.     preBuffering = TRUE;
  482.  
  483. #if PTRACING && !defined(NO_ANALYSER)
  484.     analyser->Out(0, currentDepth, "Empty");
  485. #endif
  486.     return TRUE;
  487.   }
  488.  
  489.   /* See if time for this packet, if our oldest frame is older than the
  490.      required age, then use it. If it is not time yet, make sure that the
  491.      writer thread isn't falling behind (not enough MIPS). If the time
  492.      between the oldest and the newest entries in the jitter buffer is
  493.      greater than the size specified for the buffer, then return the oldest
  494.      entry regardless, making the writer thread catch up.
  495.   */
  496.  
  497.   DWORD oldestTimestamp = oldestFrame->GetTimestamp();
  498.   DWORD newestTimestamp = newestFrame->GetTimestamp();
  499.  
  500.   if (preBuffering) {
  501.     // Check for requesting something that already exceeds the maximum time,
  502.     // or have filled the jitter buffer, not filling if this is so
  503.     if ((timestamp - oldestTimestamp) < currentJitterTime &&
  504.         (newestTimestamp - oldestTimestamp) < currentJitterTime/2) {
  505.       // Are filling the buffer, don't return anything yet
  506. #if PTRACING && !defined(NO_ANALYSER)
  507.       analyser->Out(oldestTimestamp, currentDepth, "PreBuf");
  508. #endif
  509.       return TRUE;
  510.     }
  511.  
  512.     preBuffering = FALSE;
  513.   }
  514.  
  515.   if (timestamp < oldestTimestamp && timestamp > (newestTimestamp - currentJitterTime)) {
  516.     // It is not yet time for something in the buffer
  517. #if PTRACING && !defined(NO_ANALYSER)
  518.     analyser->Out(oldestTimestamp, currentDepth, "Wait");
  519. #endif
  520.     return TRUE;
  521.   }
  522.  
  523.   // Detatch oldest packet from the list, put into parking space
  524.   currentDepth--;
  525. #if PTRACING && !defined(NO_ANALYSER)
  526.   analyser->Out(oldestTimestamp, currentDepth, timestamp >= oldestTimestamp ? "" : "Late");
  527. #endif
  528.   currentWriteFrame = oldestFrame;
  529.   oldestFrame = currentWriteFrame->next;
  530.   currentWriteFrame->next = NULL;
  531.  
  532.   if (oldestFrame == NULL)
  533.     newestFrame = NULL;
  534.   else {
  535.     oldestFrame->prev = NULL;
  536.  
  537.     // See if exceeded maximum jitter buffer time delay, waste them if so
  538.     while ((newestTimestamp - oldestFrame->GetTimestamp()) > currentJitterTime) {
  539.       PTRACE(4, "RTP\tJitter buffer oldest packet ("
  540.              << oldestFrame->GetTimestamp() << " < "
  541.              << (newestTimestamp - maxJitterTime)
  542.              << ") too late, throwing away");
  543.  
  544.       packetsTooLate++;
  545.       consecutiveEarlyPacketStartTime = newestTimestamp;
  546.  
  547.       if (currentJitterTime < maxJitterTime) {
  548.         currentJitterTime += INCREASE_JITTER_AMOUNT;
  549.         PTRACE(3, "RTP\tJitter buffer size increased to "
  550.                << currentJitterTime << " (" << (currentJitterTime/8) << "ms)");
  551.       }
  552.  
  553.       // Throw away the oldest entry
  554.       Entry * wastedFrame = oldestFrame;
  555.       oldestFrame = oldestFrame->next;
  556.       oldestFrame->prev = NULL;
  557.       currentDepth--;
  558.  
  559.       // Put thrown away frame on free list
  560.       wastedFrame->next = freeFrames;
  561.       if (freeFrames != NULL)
  562.         freeFrames->prev = wastedFrame;
  563.       freeFrames = wastedFrame;
  564.     }
  565.   }
  566.  
  567.   PTimeInterval delay = PTimer::Tick() - currentWriteFrame->tick;
  568.   if (consecutiveEarlyPacketStartTime == 0 || delay < EARLY_PACKET_PERIOD)
  569.     consecutiveEarlyPacketStartTime = newestTimestamp;
  570.  
  571.   if (currentJitterTime > minJitterTime &&
  572.         (newestTimestamp - consecutiveEarlyPacketStartTime) > DECREASE_JITTER_PERIOD) {
  573.     consecutiveEarlyPacketStartTime = newestTimestamp;
  574.     currentJitterTime -= DECREASE_JITTER_AMOUNT;
  575.     PTRACE(3, "RTP\tJitter buffer size decreased to "
  576.            << currentJitterTime << " (" << (currentJitterTime/8) << "ms)");
  577.   }
  578.  
  579.   frame = *currentWriteFrame;
  580.   return TRUE;
  581. }
  582.  
  583.  
  584. #if PTRACING && !defined(NO_ANALYSER)
  585.  
  586. RTP_JitterBufferAnalyser::RTP_JitterBufferAnalyser()
  587. {
  588.   inPos = outPos = 1;
  589.   in[0].time = out[0].time = 0;
  590.   in[0].tick = out[0].tick = PTimer::Tick();
  591.   in[0].depth = out[0].depth = 0;
  592. }
  593.  
  594.  
  595. void RTP_JitterBufferAnalyser::In(DWORD time, unsigned depth, const char * extra)
  596. {
  597.   if (inPos < PARRAYSIZE(in)) {
  598.     in[inPos].tick = PTimer::Tick();
  599.     in[inPos].time = time;
  600.     in[inPos].depth = depth;
  601.     in[inPos++].extra = extra;
  602.   }
  603. }
  604.  
  605.  
  606. void RTP_JitterBufferAnalyser::Out(DWORD time, unsigned depth, const char * extra)
  607. {
  608.   if (outPos < PARRAYSIZE(out)) {
  609.     out[outPos].tick = PTimer::Tick();
  610.     if (time == 0 && outPos > 0)
  611.       out[outPos].time = out[outPos-1].time;
  612.     else
  613.       out[outPos].time = time;
  614.     out[outPos].depth = depth;
  615.     out[outPos++].extra = extra;
  616.   }
  617. }
  618.  
  619.  
  620. void RTP_JitterBufferAnalyser::PrintOn(ostream & strm) const
  621. {
  622.   strm << "Input samples: " << inPos << " Output samples: " << outPos << "\n"
  623.           "Dir\tRTPTime\tInDiff\tOutDiff\tInMode\tOutMode\t"
  624.           "InDepth\tOutDep\tInTick\tInDelay\tOutTick\tOutDel\tIODelay\n";
  625.   PINDEX ix = 1;
  626.   PINDEX ox = 1;
  627.   while (ix < inPos || ox < outPos) {
  628.     while (ix < inPos && (ox >= outPos || in[ix].time < out[ox].time)) {
  629.       strm << "In\t"
  630.            << in[ix].time << '\t'
  631.            << (in[ix].time - in[ix-1].time) << "\t"
  632.               "\t"
  633.            << in[ix].extra << "\t"
  634.               "\t"
  635.            << in[ix].depth << "\t"
  636.               "\t"
  637.            << (in[ix].tick - in[0].tick) << '\t'
  638.            << (in[ix].tick - in[ix-1].tick) << "\t"
  639.               "\t"
  640.               "\t"
  641.               "\n";
  642.       ix++;
  643.     }
  644.  
  645.     while (ox < outPos && (ix >= inPos || out[ox].time < in[ix].time)) {
  646.       strm << "Out\t"
  647.            << out[ox].time << "\t"
  648.               "\t"
  649.            << (out[ox].time - out[ox-1].time) << "\t"
  650.               "\t"
  651.            << out[ox].extra << "\t"
  652.               "\t"
  653.            << out[ox].depth << "\t"
  654.               "\t"
  655.               "\t"
  656.            << (out[ox].tick - out[0].tick) << '\t'
  657.            << (out[ox].tick - out[ox-1].tick) << "\t"
  658.               "\n";
  659.       ox++;
  660.     }
  661.  
  662.     while (ix < inPos && ox < outPos && in[ix].time == out[ox].time) {
  663.       strm << "I/O\t"
  664.            << in[ix].time << '\t'
  665.            << (in[ix].time - in[ix-1].time) << '\t'
  666.            << (out[ox].time - out[ox-1].time) << '\t'
  667.            << in[ix].extra << '\t'
  668.            << out[ox].extra << '\t'
  669.            << in[ix].depth << '\t'
  670.            << out[ox].depth << '\t'
  671.            << (in[ix].tick - in[0].tick) << '\t'
  672.            << (in[ix].tick - in[ix-1].tick) << '\t'
  673.            << (out[ox].tick - out[0].tick) << '\t'
  674.            << (out[ox].tick - out[ox-1].tick) << '\t'
  675.            << (out[ox].tick - in[ix].tick)
  676.            << '\n';
  677.       ox++;
  678.       ix++;
  679.     }
  680.   }
  681. }
  682.  
  683.  
  684. #endif
  685.  
  686.  
  687. /////////////////////////////////////////////////////////////////////////////
  688.