Skip to content
Snippets Groups Projects
MediaStreamStatsImpl.java 34.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
     *
     * Distributable under LGPL license.
     * See terms of license at gnu.org.
     */
    package org.jitsi.impl.neomedia;
    
    import java.awt.*;
    import java.net.*;
    
    import java.util.List;
    
    import javax.media.rtp.*;
    
    import net.sf.fmj.media.rtp.*;
    
    
    import org.jitsi.impl.neomedia.device.*;
    
    import org.jitsi.impl.neomedia.rtp.*;
    
    import org.jitsi.service.neomedia.control.*;
    
    import org.jitsi.service.neomedia.rtp.*;
    
    import org.jitsi.util.*;
    
    /**
     * Class used to compute stats concerning a MediaStream.
     *
     * @author Vincent Lucas
    
     * @author Lyubomir Marinov
    
     */
    public class MediaStreamStatsImpl
        implements MediaStreamStats
    {
    
        /**
         * Enumeration of the direction (DOWNLOAD or UPLOAD) used for the stats.
         */
        private enum StreamDirection
        {
            DOWNLOAD,
            UPLOAD
        }
    
    
        /**
         * The <tt>Logger</tt> used by the <tt>MediaStreamImpl</tt> class and its
         * instances for logging output.
         */
        private static final Logger logger
            = Logger.getLogger(MediaStreamStatsImpl.class);
    
         * Computes an Exponentially Weighted Moving Average (EWMA). Thus, the most
         * recent history has a more preponderant importance in the average
         * computed.
         *
         * @param nbStepSinceLastUpdate The number of step which has not been
         * computed since last update. In our case the number of packets received
         * since the last computation.
         * @param lastValue The value computed during the last update.
         * @param newValue The value newly computed.
         *
         * @return The EWMA average computed.
    
        private static double computeEWMA(
                long nbStepSinceLastUpdate,
                double lastValue,
                double newValue)
    
            // For each new packet received the EWMA moves by a 0.1 coefficient.
            double EWMACoeff = 0.01 * nbStepSinceLastUpdate;
            // EWMA must be <= 1.
            if(EWMACoeff > 1)
                EWMACoeff = 1.0;
            return lastValue * (1.0 - EWMACoeff) + newValue * EWMACoeff;
    
         * Computes the loss rate.
         *
         * @param nbLostAndRecv The number of lost and received packets.
         * @param nbLost The number of lost packets.
         *
         * @return The loss rate in percent.
    
        private static double computePercentLoss(long nbLostAndRecv, long nbLost)
        {
            return
                (nbLostAndRecv == 0)
                    ? 0
                    : (((double) 100 * nbLost) / nbLostAndRecv);
        }
    
         * Computes the bandwidth usage in Kilo bits per seconds.
         *
         * @param nbByteRecv The number of Byte received.
         * @param callNbTimeMsSpent The time spent since the mediaStreamImpl is
         * connected to the endpoint.
         *
         * @return the bandwidth rate computed in Kilo bits per seconds.
    
        private static double computeRateKiloBitPerSec(
                long nbByteRecv,
                long callNbTimeMsSpent)
        {
            return
                (nbByteRecv == 0)
                    ? 0
                    : ((nbByteRecv * 8.0 / 1000.0) / (callNbTimeMsSpent / 1000.0));
        }
    
         * Gets the <tt>JitterBufferControl</tt> of a <tt>ReceiveStream</tt>.
         *
         * @param receiveStream the <tt>ReceiveStream</tt> to get the
         * <tt>JitterBufferControl</tt> of
         * @return the <tt>JitterBufferControl</tt> of <tt>receiveStream</tt>.
    
        public static JitterBufferControl getJitterBufferControl(
                ReceiveStream receiveStream)
        {
            DataSource ds = receiveStream.getDataSource();
    
            if (ds instanceof PushBufferDataSource)
            {
                for (PushBufferStream pbs
                        : ((PushBufferDataSource) ds).getStreams())
                {
                    JitterBufferControl pqc
                        = (JitterBufferControl)
                            pbs.getControl(JitterBufferControl.class.getName());
    
                    if (pqc != null)
                        return pqc;
                }
            }
            return null;
        }
    
         * The last jitter received/sent in a RTCP feedback (in RTP timestamp
         * units).
    
        private double[] jitterRTPTimestampUnits = {0, 0};
    
         * The source data stream to analyze in order to compute the stats.
    
        private final MediaStreamImpl mediaStreamImpl;
    
        /**
         * The last number of received/sent Bytes.
         */
        private long[] nbByte = {0, 0};
    
        /**
         * The total number of discarded packets
         */
        private long nbDiscarded = 0;
    
    
        /**
         * The number of packets for which FEC data was decoded. This is only
         */
        private long nbFec = 0;
    
    
         * The last number of download/upload lost packets.
    
        private long[] nbLost = {0, 0};
    
         * The last number of received/sent packets.
    
        private long[] nbPackets = {0, 0};
    
        /**
         * The last percent of discarded packets
         */
        private double percentDiscarded = 0;
    
    
        /**
         * The last download/upload loss rate computed (in %).
         */
        private double[] percentLoss = {0, 0};
    
    
        /**
         * The last used bandwidth computed in download/upload (in Kbit/s).
         */
        private double[] rateKiloBitPerSec = {0, 0};
    
        /**
    
         * The <tt>RTCPReportListener</tt> which listens to {@link #rtcpReports}
         * about the sending and the receiving of RTCP sender/receiver reports and
         * updates this <tt>MediaStreamStats</tt> with their feedback reports.
    
        private final RTCPReportListener rtcpReportListener
            = new RTCPReportAdapter()
            {
                /**
                 * {@inheritDoc}
                 *
                 * Updates this <tt>MediaStreamStats</tt> with the received feedback
                 * (report).
                 */
                @Override
                public void rtcpReportReceived(RTCPReport report)
                {
                    List<?> feedbackReports = report.getFeedbackReports();
    
                    if (!feedbackReports.isEmpty())
                    {
                        updateNewReceivedFeedback(
                                (RTCPFeedback) feedbackReports.get(0));
                    }
                }
    
                /**
                 * {@inheritDoc}
                 *
                 * Updates this <tt>MediaStreamStats</tt> with the sent feedback
                 * (report).
                 */
                @Override
                public void rtcpReportSent(RTCPReport report)
                {
                    List<?> feedbackReports = report.getFeedbackReports();
    
                    if (!feedbackReports.isEmpty())
                    {
                        updateNewSentFeedback(
                                (RTCPFeedback) feedbackReports.get(0));
                    }
                }
            };
    
        /**
         * The detailed statistics about the RTCP reports sent and received by the
         * associated local peer.
         */
        private final RTCPReports rtcpReports = new RTCPReports();
    
        /**
         * The RTT computed with the RTCP feedback (cf. RFC3550, section 6.4.1,
         * subsection "delay since last SR (DLSR): 32 bits").
         * -1 if the RTT has not been computed yet. Otherwise the RTT in ms.
         */
        private long rttMs = -1;
    
    
        /**
         * The last time these stats have been updated.
         */
        private long updateTimeMs;
    
        /**
         * The last number of sent packets when the last feedback has been received.
         * This counter is used to compute the upload loss rate.
         */
        private long uploadFeedbackNbPackets = 0;
    
    
        /**
         * Creates a new instance of stats concerning a MediaStream.
         *
         * @param mediaStreamImpl The MediaStreamImpl used to compute the stats.
         */
        public MediaStreamStatsImpl(MediaStreamImpl mediaStreamImpl)
        {
            this.mediaStreamImpl = mediaStreamImpl;
    
    
            getRTCPReports().addRTCPReportListener(rtcpReportListener);
    
            updateTimeMs = System.currentTimeMillis();
    
         * Computes the RTT with the data (LSR and DLSR) contained in the last
         * RTCP Sender Report (RTCP feedback). This RTT computation is based on
         * RFC3550, section 6.4.1, subsection "delay since last SR (DLSR): 32
         * bits".
    
         * @param feedback The last RTCP feedback received by the MediaStream.
         *
         * @return The RTT in milliseconds, or -1 if the RTT is not computable.
    
        private long computeRTTInMs(RTCPFeedback feedback)
    
            long now = System.currentTimeMillis();
            long lsr = feedback.getLSR();
            long dlsr = feedback.getDLSR();
            int rtt = RecvSSRCInfo.getRoundTripDelay(now, lsr, dlsr);
    
            /*
             * If the RTT is greater than a minute, it may signal a bug in the
             * computation. Log such occurrences in order to debug them.
             */
            if ((rtt >= 65536) && logger.isInfoEnabled())
    
                logger.info(
                        "Stream: " + mediaStreamImpl.getName()
                            + ", RTT computation may be wrong (" + rtt
                            + ">= 65536 milliseconds): now " + now + ", lsr " + lsr
                            + ", dlsr " + dlsr);
    
            return rtt;
    
         * Returns the jitter average of this download stream.
    
         * @return the last jitter average computed (in ms).
    
        public double getDownloadJitterMs()
    
            return getJitterMs(StreamDirection.DOWNLOAD);
    
         * Returns the number of Protocol Data Units (PDU) lost in download since
         * the beginning of the session.
    
         * @return the number of packets lost for this stream.
    
        private long getDownloadNbPDULost()
    
            MediaDeviceSession devSession = mediaStreamImpl.getDeviceSession();
            int nbLost = 0;
    
            if (devSession != null)
            {
                for(ReceiveStream receiveStream : devSession.getReceiveStreams())
                    nbLost += receiveStream.getSourceReceptionStats().getPDUlost();
            }
            return nbLost;
    
         * Returns the percent loss of the download stream.
    
         * @return the last loss rate computed (in %).
    
        public double getDownloadPercentLoss()
    
            return percentLoss[StreamDirection.DOWNLOAD.ordinal()];
    
         * Returns the bandwidth used by this download stream.
    
         * @return the last used download bandwidth computed (in Kbit/s).
    
        public double getDownloadRateKiloBitPerSec()
    
            return rateKiloBitPerSec[StreamDirection.DOWNLOAD.ordinal()];
    
        }
    
        /**
         * Returns the download video format if this stream downloads a video, or
         * null if not.
         *
         * @return the download video format if this stream downloads a video, or
         * null if not.
         */
        private VideoFormat getDownloadVideoFormat()
        {
    
            MediaDeviceSession deviceSession = mediaStreamImpl.getDeviceSession();
    
                (deviceSession instanceof VideoMediaDeviceSession)
                    ? ((VideoMediaDeviceSession) deviceSession)
    
        }
    
        /**
         * Returns the download video size if this stream downloads a video, or
         * null if not.
         *
         * @return the download video size if this stream downloads a video, or null
         * if not.
         */
        public Dimension getDownloadVideoSize()
        {
    
            VideoFormat format = getDownloadVideoFormat();
    
            return (format == null) ? null : format.getSize();
    
         * Returns the MediaStream enconding.
    
         * @return the encoding used by the stream.
    
        public String getEncoding()
    
            MediaFormat format = mediaStreamImpl.getFormat();
    
            return (format == null) ? null : format.getEncoding();
    
         * Returns the MediaStream enconding rate (in Hz)..
    
         * @return the encoding rate used by the stream.
    
        public String getEncodingClockRate()
    
            MediaFormat format = mediaStreamImpl.getFormat();
    
            return (format == null) ? null : format.getRealUsedClockRateString();
    
         * Returns the delay in milliseconds introduced by the jitter buffer.
         * Since there might be multiple <tt>ReceiveStreams</tt>, returns the
         * biggest delay found in any of them.
    
         * @return the delay in milliseconds introduces by the jitter buffer
    
        public int getJitterBufferDelayMs()
    
            int delay = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
              if(pqc.getCurrentDelayMs() > delay)
                  delay = pqc.getCurrentDelayMs();
            return delay;
    
         * Returns the delay in number of packets introduced by the jitter buffer.
         * Since there might be multiple <tt>ReceiveStreams</tt>, returns the
         * biggest delay found in any of them.
    
         * @return the delay in number of packets introduced by the jitter buffer
    
        public int getJitterBufferDelayPackets()
    
            int delay = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
                if(pqc.getCurrentDelayPackets() > delay)
                    delay = pqc.getCurrentDelayPackets();
            return delay;
    
        }
    
        /**
         * Returns the jitter average of this upload/download stream.
         *
         * @param streamDirection The stream direction (DOWNLOAD or UPLOAD) of the
         * stream from which this function retrieve the jitter.
         *
         * @return the last jitter average computed (in ms).
         */
        private double getJitterMs(StreamDirection streamDirection)
        {
    
            MediaFormat format = mediaStreamImpl.getFormat();
            double clockRate;
    
            if (format == null)
            {
                MediaType mediaType = mediaStreamImpl.getMediaType();
    
    
                clockRate = MediaType.VIDEO.equals(mediaType) ? 90000 : -1;
    
            }
            else
                clockRate = format.getClockRate();
    
            if (clockRate <= 0)
                return -1;
    
    
            // RFC3550 says that concerning the RTP timestamp unit (cf. section 5.1
            // RTP Fixed Header Fields, subsection timestamp: 32 bits):
            // As an example, for fixed-rate audio the timestamp clock would likely
            // increment by one for each sampling period.
            //
    
            // Thus we take the jitter in RTP timestamp units, convert it to seconds
            // (/ clockRate) and finally converts it to milliseconds  (* 1000).
    
            return
                (jitterRTPTimestampUnits[streamDirection.ordinal()] / clockRate)
                    * 1000.0;
    
         * Returns the local IP address of the MediaStream.
    
         * @return the local IP address of the stream.
    
        public String getLocalIPAddress()
    
            InetSocketAddress mediaStreamLocalDataAddress
                = mediaStreamImpl.getLocalDataAddress();
    
            return
                (mediaStreamLocalDataAddress == null)
                    ? null
                    : mediaStreamLocalDataAddress.getAddress().getHostAddress();
    
         * Returns the local port of the MediaStream.
    
         * @return the local port of the stream.
    
        public int getLocalPort()
    
            InetSocketAddress mediaStreamLocalDataAddress
                = mediaStreamImpl.getLocalDataAddress();
    
            return
                (mediaStreamLocalDataAddress == null)
                    ? -1
                    : mediaStreamLocalDataAddress.getPort();
    
         * Returns the number of sent/received bytes since the beginning of the
         * session.
    
         * @param streamDirection The stream direction (DOWNLOAD or UPLOAD) of the
         * stream from which this function retrieve the number of sent/received
         * bytes.
         *
         * @return the number of sent/received bytes for this stream.
    
        private long getNbBytes(StreamDirection streamDirection)
    
            StreamRTPManager rtpManager = mediaStreamImpl.queryRTPManager();
            long nbBytes = 0;
    
            if(rtpManager != null)
            {
                switch(streamDirection)
                {
                case DOWNLOAD:
                    nbBytes = rtpManager.getGlobalReceptionStats().getBytesRecd();
                    break;
                case UPLOAD:
                    nbBytes
                        = rtpManager.getGlobalTransmissionStats().getBytesSent();
                    break;
                }
            }
            return nbBytes;
    
         * Returns the total number of Protocol Data Units (PDU) discarded by the
         * FMJ packet queue since the beginning of the session. It's the sum over
         * all <tt>ReceiveStream</tt>s of the <tt>MediaStream</tt>
    
         * @return the number of discarded packets.
    
        public long getNbDiscarded()
    
            int nbDiscarded = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
                nbDiscarded =+ pqc.getDiscarded();
            return nbDiscarded;
    
         * Returns the number of Protocol Data Units (PDU) discarded by the
         * FMJ packet queue since the beginning of the session because it was full.
         * It's the sum over all <tt>ReceiveStream</tt>s of the <tt>MediaStream</tt>
    
         * @return the number of discarded packets because it was full.
    
        public int getNbDiscardedFull()
    
            int nbDiscardedFull = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
                nbDiscardedFull =+ pqc.getDiscardedFull();
            return nbDiscardedFull;
    
         * Returns the number of Protocol Data Units (PDU) discarded by the
         * FMJ packet queue since the beginning of the session because they were late.
         * It's the sum over all <tt>ReceiveStream</tt>s of the <tt>MediaStream</tt>
    
         * @return the number of discarded packets because they were late.
    
        public int getNbDiscardedLate()
    
            int nbDiscardedLate = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
                nbDiscardedLate =+ pqc.getDiscardedLate();
            return nbDiscardedLate;
    
         * Returns the number of Protocol Data Units (PDU) discarded by the
         * FMJ packet queue since the beginning of the session during resets.
         * It's the sum over all <tt>ReceiveStream</tt>s of the <tt>MediaStream</tt>
    
         * @return the number of discarded packets during resets.
         */
        public int getNbDiscardedReset()
        {
            int nbDiscardedReset = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
                nbDiscardedReset =+ pqc.getDiscardedReset();
            return nbDiscardedReset;
        }
    
        /**
         * Returns the number of Protocol Data Units (PDU) discarded by the
         * FMJ packet queue since the beginning of the session due to shrinking.
         * It's the sum over all <tt>ReceiveStream</tt>s of the <tt>MediaStream</tt>
    
         * @return the number of discarded packets due to shrinking.
    
        public int getNbDiscardedShrink()
    
            int nbDiscardedShrink = 0;
            for(JitterBufferControl pqc : getJitterBufferControls())
                nbDiscardedShrink =+ pqc.getDiscardedShrink();
            return nbDiscardedShrink;
        }
    
        /**
         * Returns the number of packets for which FEC data was decoded. Currently
         * this is cumulative over all <tt>ReceiveStream</tt>s.
         *
         * @return the number of packets for which FEC data was decoded. Currently
         * this is cumulative over all <tt>ReceiveStream</tt>s.
         *
         * @see org.jitsi.impl.neomedia.MediaStreamStatsImpl#updateNbFec()
         */
        public long getNbFec()
        {
            return nbFec;
    
        }
    
        /**
         * Returns the number of Protocol Data Units (PDU) sent/received since the
         * beginning of the session.
         *
         * @param streamDirection The stream direction (DOWNLOAD or UPLOAD) of the
         * stream from which this function retrieve the number of sent/received
         * packets.
         *
         * @return the number of packets sent/received for this stream.
         */
        private long getNbPDU(StreamDirection streamDirection)
        {
    
            StreamRTPManager rtpManager = mediaStreamImpl.queryRTPManager();
    
            long nbPDU = 0;
    
            if(rtpManager != null)
            {
                switch(streamDirection)
                {
    
                case UPLOAD:
                    nbPDU = rtpManager.getGlobalTransmissionStats().getRTPSent();
                    break;
    
                case DOWNLOAD:
                    GlobalReceptionStats globalReceptionStats
                        = rtpManager.getGlobalReceptionStats();
    
                    nbPDU
                        = globalReceptionStats.getPacketsRecd()
    
                            - globalReceptionStats.getRTCPRecd();
    
        /**
         * Returns the total number of packets that are send or receive for this
         * stream since the stream is created.
         * @return the total number of packets.
         */
        public long getNbPackets()
        {
            return getNbPDU(StreamDirection.DOWNLOAD)
                + nbLost[StreamDirection.DOWNLOAD.ordinal()]
                + uploadFeedbackNbPackets;
        }
    
        /**
         * Returns the number of lost packets for that stream.
         * @return the number of lost packets.
         */
        public long getNbPacketsLost()
        {
            return nbLost[StreamDirection.DOWNLOAD.ordinal()]
                + nbLost[StreamDirection.UPLOAD.ordinal()];
        }
    
    
         * Returns the set of <tt>PacketQueueControls</tt> found for all the
         * <tt>DataSource</tt>s of all the <tt>ReceiveStream</tt>s. The set contains
         * only non-null elements.
    
         * @return the set of <tt>PacketQueueControls</tt> found for all the
         * <tt>DataSource</tt>s of all the <tt>ReceiveStream</tt>s. The set contains
         * only non-null elements.
    
        private Set<JitterBufferControl> getJitterBufferControls()
    
            Set<JitterBufferControl> set = new HashSet<JitterBufferControl>();
    
            if (mediaStreamImpl.isStarted())
    
                MediaDeviceSession devSession = mediaStreamImpl.getDeviceSession();
    
                if (devSession != null)
                {
                    for(ReceiveStream receiveStream
                            : devSession.getReceiveStreams())
                    {
                        JitterBufferControl pqc
                            = getJitterBufferControl(receiveStream);
    
                        if(pqc != null)
                            set.add(pqc);
                    }
                }
    
            return set;
    
         * Returns the number of packets in the first <tt>JitterBufferControl</tt>
         * found via <tt>getJitterBufferControls</tt>.
    
         * @return the number of packets in the first <tt>JitterBufferControl</tt>
         * found via <tt>getJitterBufferControls</tt>.
    
        public int getPacketQueueCountPackets()
    
            for(JitterBufferControl pqc : getJitterBufferControls())
                return pqc.getCurrentPacketCount();
            return 0;
    
         * Returns the size of the first <tt>JitterBufferControl</tt> found via
         * <tt>getJitterBufferControls</tt>.
    
         * @return the size of the first <tt>JitterBufferControl</tt> found via
         * <tt>getJitterBufferControls</tt>.
    
        public int getPacketQueueSize()
    
            for(JitterBufferControl pqc : getJitterBufferControls())
                return pqc.getCurrentSizePackets();
            return 0;
    
         * Returns the percent of discarded packets
    
         * @return the percent of discarded packets
    
        public double getPercentDiscarded()
    
            return percentDiscarded;
    
         * Returns the remote IP address of the MediaStream.
    
         * @return the remote IP address of the stream.
    
        public String getRemoteIPAddress()
    
            MediaStreamTarget mediaStreamTarget = mediaStreamImpl.getTarget();
    
            // Gets this stream IP address endpoint. Stops if the endpoint is
            // disconnected.
            return
                (mediaStreamTarget == null)
                    ? null
                    : mediaStreamTarget.getDataAddress().getAddress()
                            .getHostAddress();
    
         * Returns the remote port of the MediaStream.
    
         * @return the remote port of the stream.
    
        public int getRemotePort()
    
            MediaStreamTarget mediaStreamTarget = mediaStreamImpl.getTarget();
    
            // Gets this stream port endpoint. Stops if the endpoint is
            // disconnected.
            return
                (mediaStreamTarget == null)
                    ? -1
                    : mediaStreamTarget.getDataAddress().getPort();
    
         * {@inheritDoc}
         */
        @Override
        public RTCPReports getRTCPReports()
        {
            return rtcpReports;
        }
    
        /**
         * Returns the RTT computed with the RTCP feedback (cf. RFC3550, section
         * 6.4.1, subsection "delay since last SR (DLSR): 32 bits").
    
         * @return The RTT computed with the RTCP feedback. Returns -1 if the RTT
         * has not been computed yet. Otherwise the RTT in ms.
    
        public long getRttMs()
    
            return rttMs;
        }
    
        /**
         * Returns the jitter average of this upload stream.
         *
         * @return the last jitter average computed (in ms).
         */
        public double getUploadJitterMs()
        {
            return getJitterMs(StreamDirection.UPLOAD);
    
         * Returns the percent loss of the upload stream.
    
         * @return the last loss rate computed (in %).
         */
        public double getUploadPercentLoss()
        {
            return percentLoss[StreamDirection.UPLOAD.ordinal()];
        }
    
        /**
         * Returns the bandwidth used by this download stream.
    
         * @return the last used upload bandwidth computed (in Kbit/s).
    
        public double getUploadRateKiloBitPerSec()
    
            return rateKiloBitPerSec[StreamDirection.UPLOAD.ordinal()];
        }
    
        /**
         * Returns the upload video format if this stream uploads a video, or null
         * if not.
         *
         * @return the upload video format if this stream uploads a video, or null
         * if not.
         */
        private VideoFormat getUploadVideoFormat()
        {
            MediaDeviceSession deviceSession = mediaStreamImpl.getDeviceSession();
    
            return
                (deviceSession instanceof VideoMediaDeviceSession)
                    ? ((VideoMediaDeviceSession) deviceSession)
                        .getSentVideoFormat()
                    : null;
        }
    
        /**
         * Returns the upload video size if this stream uploads a video, or null if
         * not.
         *
         * @return the upload video size if this stream uploads a video, or null if
         * not.
         */
        public Dimension getUploadVideoSize()
        {
            VideoFormat format = getUploadVideoFormat();
    
            return (format == null) ? null : format.getSize();
        }
    
        public boolean isAdaptiveBufferEnabled()
        {
            for(JitterBufferControl pcq : getJitterBufferControls())
                if(pcq.isAdaptiveBufferEnabled())
                    return true;
            return false;
    
         * Updates the jitter stream stats with the new feedback sent.
    
         * @param feedback The last RTCP feedback sent by the MediaStream.
         * @param streamDirection The stream direction (DOWNLOAD or UPLOAD) of the
         * stream from which this function retrieve the jitter.
    
        private void updateJitterRTPTimestampUnits(
                RTCPFeedback feedback,
                StreamDirection streamDirection)
    
            // Updates the download jitter in RTP timestamp units. There is no need
            // to compute a jitter average, since (cf. RFC3550, section 6.4.1 SR:
            // Sender Report RTCP Packet, subsection interarrival jitter: 32 bits)
            // the value contained in the RTCP sender report packet contains a mean
            // deviation of the jitter.
            jitterRTPTimestampUnits[streamDirection.ordinal()]
                = feedback.getJitter();
    
         * Updates the number of discarded packets.
    
         * @param newNbDiscarded The last update of the number of lost.
         * @param nbSteps The number of elapsed steps since the last number of loss
         * update.
    
        private void updateNbDiscarded(
                long newNbDiscarded,
                long nbSteps)
    
            double newPercentDiscarded
                = MediaStreamStatsImpl.computePercentLoss(nbSteps, newNbDiscarded);
    
            percentDiscarded
                = MediaStreamStatsImpl.computeEWMA(
                        nbSteps,
                        percentDiscarded,
                        newPercentDiscarded);
            // Saves the last update number download lost value.
            nbDiscarded += newNbDiscarded;
    
        }
    
        /**
         * Updates the <tt>nbFec</tt> field with the sum of FEC-decoded packets
         * over the different <tt>ReceiveStream</tt>s
         */
        private void updateNbFec()
        {
    
            MediaDeviceSession devSession = mediaStreamImpl.getDeviceSession();
    
                for(ReceiveStream receiveStream : devSession.getReceiveStreams())
    
                            : devSession.getDecoderControls(
                                    receiveStream,
    
                        nbFec += fecDecoderControl.fecPacketsDecoded();
    
         * Updates the number of loss for a given stream.
    
         * @param streamDirection The stream direction (DOWNLOAD or UPLOAD) of the
         * stream from which this function updates the stats.
         * @param newNbLost The last update of the number of lost.
    
         * @param nbSteps The number of elapsed steps since the last number of loss
         * update.
         */
    
        private void updateNbLoss(
                StreamDirection streamDirection,
                long newNbLost,
    
            int streamDirectionIndex = streamDirection.ordinal();
            double newPercentLoss
                = MediaStreamStatsImpl.computePercentLoss(nbSteps, newNbLost);
    
            percentLoss[streamDirectionIndex]
                = MediaStreamStatsImpl.computeEWMA(
                        nbSteps,
                        percentLoss[streamDirectionIndex],
                        newPercentLoss);
    
            // Saves the last update number download lost value.
    
            nbLost[streamDirectionIndex] += newNbLost;
    
         * Updates this stream stats with the new feedback received.
    
         * @param feedback The last RTCP feedback received by the MediaStream.
    
        private void updateNewReceivedFeedback(RTCPFeedback feedback)
    
            StreamDirection streamDirection = StreamDirection.UPLOAD;
    
            updateJitterRTPTimestampUnits(feedback, streamDirection);
    
            // Updates the loss rate with the RTCP sender report feedback, since